Merge branch 'wip/775956-dbus-activation' into 'mainline'
Support DBus activation See merge request GNOME/geary!204
This commit is contained in:
commit
ef71e4c4c2
22 changed files with 467 additions and 355 deletions
|
|
@ -7,7 +7,7 @@ Keywords=Email;E-mail;Mail;
|
|||
# Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
Icon=org.gnome.Geary
|
||||
TryExec=geary
|
||||
Exec=geary --hidden
|
||||
Exec=geary --gapplication-service
|
||||
Type=Application
|
||||
Terminal=false
|
||||
Categories=GNOME;GTK;Network;Email;
|
||||
|
|
|
|||
|
|
@ -87,3 +87,18 @@ geary_compiled_schema = gnome.compile_schemas(
|
|||
install_data('org.gnome.Geary.gschema.xml',
|
||||
install_dir: join_paths(datadir, 'glib-2.0', 'schemas'),
|
||||
)
|
||||
|
||||
#
|
||||
# DBus services
|
||||
#
|
||||
|
||||
service_conf = configuration_data()
|
||||
service_conf.set('bindir', bindir)
|
||||
|
||||
configure_file(
|
||||
input: 'org.gnome.Geary.service.in',
|
||||
output: 'org.gnome.Geary.service',
|
||||
configuration: service_conf,
|
||||
install: true,
|
||||
install_dir: dbus_services_dir
|
||||
)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ Terminal=false
|
|||
Categories=GNOME;GTK;Network;Email;
|
||||
MimeType=x-scheme-handler/mailto;
|
||||
StartupNotify=true
|
||||
DBusActivatable=true
|
||||
X-GNOME-UsesNotifications=true
|
||||
Actions=Compose;
|
||||
|
||||
|
|
|
|||
3
desktop/org.gnome.Geary.service.in
Normal file
3
desktop/org.gnome.Geary.service.in
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[D-BUS Service]
|
||||
Name=org.gnome.Geary
|
||||
Exec=@bindir@/geary" --gapplication-service
|
||||
|
|
@ -27,6 +27,7 @@ locale_dir = join_paths(geary_prefix, get_option('localedir'))
|
|||
po_dir = join_paths(meson.source_root(), 'po')
|
||||
vapi_dir = join_paths(meson.source_root(), 'bindings', 'vapi')
|
||||
metadata_dir = join_paths(meson.source_root(), 'bindings', 'metadata')
|
||||
dbus_services_dir = join_paths(datadir, 'dbus-1', 'services')
|
||||
web_extensions_dir = join_paths(libdir, 'geary', 'web-extensions')
|
||||
|
||||
# Make sure Meson can find our custom VAPI's
|
||||
|
|
|
|||
|
|
@ -20,9 +20,8 @@ src/client/application/application-certificate-manager.vala
|
|||
src/client/application/application-command.vala
|
||||
src/client/application/application-contact-store.vala
|
||||
src/client/application/application-contact.vala
|
||||
src/client/application/autostart-manager.vala
|
||||
src/client/application/application-startup-manager.vala
|
||||
src/client/application/geary-application.vala
|
||||
src/client/application/geary-args.vala
|
||||
src/client/application/geary-controller.vala
|
||||
src/client/application/goa-mediator.vala
|
||||
src/client/application/main.vala
|
||||
|
|
|
|||
110
src/client/application/application-startup-manager.vala
Normal file
110
src/client/application/application-startup-manager.vala
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright 2016 Software Freedom Conservancy Inc.
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Manages desktop files in the autostart.
|
||||
*/
|
||||
public class Application.StartupManager : GLib.Object {
|
||||
|
||||
private const string AUTOSTART_FOLDER = "autostart";
|
||||
private const string AUTOSTART_DESKTOP_FILE = "geary-autostart.desktop";
|
||||
|
||||
private Configuration config;
|
||||
private GLib.File? install_dir;
|
||||
private GLib.File startup_file; // Startup '.desktop' file
|
||||
|
||||
public StartupManager(Configuration config, GLib.File? install_dir) {
|
||||
this.config = config;
|
||||
this.install_dir = install_dir;
|
||||
this.startup_file = GLib.File.new_for_path(
|
||||
GLib.Environment.get_user_config_dir()
|
||||
).get_child(AUTOSTART_FOLDER)
|
||||
.get_child(AUTOSTART_DESKTOP_FILE);
|
||||
|
||||
// Connect startup-notifications option callback
|
||||
config.settings.changed[Configuration.STARTUP_NOTIFICATIONS_KEY].connect(
|
||||
on_startup_notification_change
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the system-wide autostart desktop file
|
||||
*/
|
||||
public GLib.File? get_autostart_desktop_file() {
|
||||
GLib.File? parent = null;
|
||||
if (this.install_dir != null) {
|
||||
// Running from the installation directory
|
||||
parent = (
|
||||
this.install_dir
|
||||
.get_child("share")
|
||||
.get_child("applications")
|
||||
);
|
||||
} else {
|
||||
// Running from the source build directory
|
||||
parent = (
|
||||
GLib.File.new_for_path(GearyApplication.SOURCE_ROOT_DIR)
|
||||
.get_child("build")
|
||||
.get_child("desktop")
|
||||
);
|
||||
}
|
||||
|
||||
GLib.File desktop_file = parent.get_child(AUTOSTART_DESKTOP_FILE);
|
||||
return desktop_file.query_exists() ? desktop_file : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the autostart desktop file to the autostart directory.
|
||||
*/
|
||||
public void install_startup_file() throws GLib.Error {
|
||||
if (!this.startup_file.query_exists()) {
|
||||
GLib.File autostart_dir = this.startup_file.get_parent();
|
||||
if (!autostart_dir.query_exists()) {
|
||||
autostart_dir.make_directory_with_parents();
|
||||
}
|
||||
GLib.File? autostart = get_autostart_desktop_file();
|
||||
if (autostart == null) {
|
||||
warning("Autostart file is not installed!");
|
||||
} else {
|
||||
autostart.copy(this.startup_file, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the desktop file from autostart directory.
|
||||
*/
|
||||
public void delete_startup_file() throws GLib.Error {
|
||||
try {
|
||||
this.startup_file.delete();
|
||||
} catch (GLib.IOError.NOT_FOUND err) {
|
||||
// All good
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Synchronises the config with the actual state of the autostart file.
|
||||
*
|
||||
* Ensures it's not misleading (i.e. the option is checked while
|
||||
* the file doesn't exist).
|
||||
*/
|
||||
public void sync_with_config() {
|
||||
this.config.startup_notifications = this.startup_file.query_exists();
|
||||
}
|
||||
|
||||
private void on_startup_notification_change() {
|
||||
try {
|
||||
if (this.config.startup_notifications) {
|
||||
install_startup_file();
|
||||
} else {
|
||||
delete_startup_file();
|
||||
}
|
||||
} catch (GLib.Error err) {
|
||||
warning("Failed to update autostart desktop file: %s", err.message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
/* Copyright 2016 Software Freedom Conservancy Inc.
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A simple class for manipulating autostarting Geary as a hidden application through a simple
|
||||
* desktop file at $HOME/.config/autostart/geary.desktop
|
||||
*/
|
||||
public class AutostartManager : Object {
|
||||
|
||||
private const string AUTOSTART_FOLDER = "autostart";
|
||||
private const string AUTOSTART_DESKTOP_FILE = "geary-autostart.desktop";
|
||||
|
||||
private GearyApplication instance;
|
||||
private File startup_file; // Startup '.desktop' file
|
||||
|
||||
public AutostartManager(GearyApplication instance) {
|
||||
this.instance = instance;
|
||||
this.startup_file = File.new_for_path(Environment.get_user_config_dir()).get_child(AUTOSTART_FOLDER)
|
||||
.get_child(AUTOSTART_DESKTOP_FILE);
|
||||
|
||||
// Connect startup-notifications option callback
|
||||
this.instance.config.settings.changed[Configuration.STARTUP_NOTIFICATIONS_KEY].connect(
|
||||
on_startup_notification_change);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the system-wide autostart desktop file
|
||||
*/
|
||||
public File? get_autostart_desktop_file() {
|
||||
File? install_dir = this.instance.get_install_dir();
|
||||
File desktop_file = (install_dir != null)
|
||||
? install_dir.get_child("share").get_child("applications").get_child(AUTOSTART_DESKTOP_FILE)
|
||||
: File.new_for_path(GearyApplication.SOURCE_ROOT_DIR).get_child("build").get_child("desktop").get_child(AUTOSTART_DESKTOP_FILE);
|
||||
|
||||
return desktop_file.query_exists() ? desktop_file : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the desktop file from autostart directory.
|
||||
*/
|
||||
public void delete_startup_file() {
|
||||
if (this.startup_file.query_exists()) {
|
||||
try {
|
||||
this.startup_file.delete();
|
||||
} catch (Error err) {
|
||||
message("Failed to delete startup file: %s", err.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates .desktop file in autostart directory (usually '$HOME/.config/autostart/') if no one exists.
|
||||
*/
|
||||
public void create_startup_file() {
|
||||
if (this.startup_file.query_exists())
|
||||
return;
|
||||
|
||||
try {
|
||||
File autostart_dir = this.startup_file.get_parent();
|
||||
if (!autostart_dir.query_exists())
|
||||
autostart_dir.make_directory_with_parents();
|
||||
File? autostart = get_autostart_desktop_file();
|
||||
if (autostart == null) {
|
||||
message("Autostart file is not installed!");
|
||||
} else {
|
||||
autostart.copy(this.startup_file, 0);
|
||||
}
|
||||
} catch (Error err) {
|
||||
message("Failed to create startup file: %s", err.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for startup notification option changes.
|
||||
*/
|
||||
public void on_startup_notification_change() {
|
||||
if (this.instance.config.startup_notifications)
|
||||
create_startup_file();
|
||||
else
|
||||
delete_startup_file();
|
||||
}
|
||||
|
||||
/*
|
||||
* A convenience method. The purpose of this method is to synchronize the state of startup notifications setting
|
||||
* with the actual state of the file, so it's not misleading for the user (the option is checked while the file doesn't exist)
|
||||
*/
|
||||
public void sync_with_config() {
|
||||
this.instance.config.startup_notifications = this.startup_file.query_exists();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
/* Copyright 2016 Software Freedom Conservancy Inc.
|
||||
/*
|
||||
* Copyright 2016 Software Freedom Conservancy Inc.
|
||||
* Copyright 2019 Michael Gratton <mike@vee.net>
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
// Defined by CMake build script.
|
||||
|
|
@ -18,7 +20,6 @@ extern const string GETTEXT_PACKAGE;
|
|||
public class GearyApplication : Gtk.Application {
|
||||
|
||||
public const string NAME = "Geary";
|
||||
public const string PRGNAME = "geary";
|
||||
public const string APP_ID = "org.gnome.Geary";
|
||||
public const string DESCRIPTION = _("Send and receive email");
|
||||
public const string COPYRIGHT_1 = _("Copyright 2016 Software Freedom Conservancy Inc.");
|
||||
|
|
@ -52,16 +53,34 @@ public class GearyApplication : Gtk.Application {
|
|||
public const string ACTION_UNDO = "undo";
|
||||
|
||||
// App-wide actions
|
||||
private const string ACTION_ABOUT = "about";
|
||||
private const string ACTION_ACCOUNTS = "accounts";
|
||||
private const string ACTION_COMPOSE = "compose";
|
||||
private const string ACTION_INSPECT = "inspect";
|
||||
private const string ACTION_HELP = "help";
|
||||
private const string ACTION_MAILTO = "mailto";
|
||||
private const string ACTION_PREFERENCES = "preferences";
|
||||
private const string ACTION_QUIT = "quit";
|
||||
public const string ACTION_ABOUT = "about";
|
||||
public const string ACTION_ACCOUNTS = "accounts";
|
||||
public const string ACTION_COMPOSE = "compose";
|
||||
public const string ACTION_INSPECT = "inspect";
|
||||
public const string ACTION_HELP = "help";
|
||||
public const string ACTION_MAILTO = "mailto";
|
||||
public const string ACTION_PREFERENCES = "preferences";
|
||||
public const string ACTION_QUIT = "quit";
|
||||
|
||||
private const ActionEntry[] action_entries = {
|
||||
// Local-only command line options
|
||||
private const string OPTION_VERSION = "version";
|
||||
|
||||
// Local command line options
|
||||
private const string OPTION_DEBUG = "debug";
|
||||
private const string OPTION_INSPECTOR = "inspector";
|
||||
private const string OPTION_LOG_CONVERSATIONS = "log-conversations";
|
||||
private const string OPTION_LOG_DESERIALIZER = "log-deserializer";
|
||||
private const string OPTION_LOG_FOLDER_NORM = "log-folder-normalization";
|
||||
private const string OPTION_LOG_NETWORK = "log-network";
|
||||
private const string OPTION_LOG_PERIODIC = "log-periodic";
|
||||
private const string OPTION_LOG_REPLAY_QUEUE = "log-replay-queue";
|
||||
private const string OPTION_LOG_SERIALIZER = "log-serializer";
|
||||
private const string OPTION_LOG_SQL = "log-sql";
|
||||
private const string OPTION_HIDDEN = "hidden";
|
||||
private const string OPTION_QUIT = "quit";
|
||||
private const string OPTION_REVOKE_CERTS = "revoke-certs";
|
||||
|
||||
private const ActionEntry[] ACTION_ENTRIES = {
|
||||
{ACTION_ABOUT, on_activate_about},
|
||||
{ACTION_ACCOUNTS, on_activate_accounts},
|
||||
{ACTION_COMPOSE, on_activate_compose},
|
||||
|
|
@ -72,6 +91,62 @@ public class GearyApplication : Gtk.Application {
|
|||
{ACTION_QUIT, on_activate_quit},
|
||||
};
|
||||
|
||||
// This is also the order in which they are presented to the user,
|
||||
// so it's probably best to keep them alphabetical
|
||||
private const GLib.OptionEntry[] OPTION_ENTRIES = {
|
||||
{ OPTION_DEBUG, 'd', 0, GLib.OptionArg.NONE, null,
|
||||
/// Command line option
|
||||
N_("Print debug logging"), null },
|
||||
{ OPTION_HIDDEN, 0, 0, GLib.OptionArg.NONE, null,
|
||||
/// Command line option
|
||||
N_("Start with the main window hidden (deprecated)"), null },
|
||||
{ OPTION_INSPECTOR, 'i', 0, GLib.OptionArg.NONE, null,
|
||||
/// Command line option
|
||||
N_("Enable WebKitGTK Inspector in web views"), null },
|
||||
{ OPTION_LOG_CONVERSATIONS, 0, 0, GLib.OptionArg.NONE, null,
|
||||
/// Command line option
|
||||
N_("Log conversation monitoring"), null },
|
||||
{ OPTION_LOG_DESERIALIZER, 0, 0, GLib.OptionArg.NONE, null,
|
||||
/// Command line option
|
||||
N_("Log IMAP network deserialization"), null },
|
||||
{ OPTION_LOG_FOLDER_NORM, 0, 0, GLib.OptionArg.NONE, null,
|
||||
/// Command line option. "Normalization" can also be called
|
||||
/// "synchronization".
|
||||
N_("Log folder normalization"), null },
|
||||
{ OPTION_LOG_NETWORK, 0, 0, GLib.OptionArg.NONE, null,
|
||||
/// Command line option
|
||||
N_("Log network activity"), null },
|
||||
{ OPTION_LOG_PERIODIC, 0, 0, GLib.OptionArg.NONE, null,
|
||||
/// Command line option
|
||||
N_("Log periodic activity"), null },
|
||||
{ OPTION_LOG_REPLAY_QUEUE, 0, 0, GLib.OptionArg.NONE, null,
|
||||
/// Command line option. The IMAP replay queue is how changes
|
||||
/// on the server are replicated on the client. It could
|
||||
/// also be called the IMAP events queue.
|
||||
N_("Log IMAP replay queue"), null },
|
||||
{ OPTION_LOG_SERIALIZER, 0, 0, GLib.OptionArg.NONE, null,
|
||||
/// Command line option. Serialization is how commands and
|
||||
/// responses are converted into a stream of bytes for
|
||||
/// network transmission
|
||||
N_("Log IMAP network serialization"), null },
|
||||
{ OPTION_LOG_SQL, 0, 0, GLib.OptionArg.NONE, null,
|
||||
/// Command line option
|
||||
N_("Log database queries (generates lots of messages)"), null },
|
||||
{ OPTION_QUIT, 'q', 0, GLib.OptionArg.NONE, null,
|
||||
/// Command line option
|
||||
N_("Perform a graceful quit"), null },
|
||||
{ OPTION_REVOKE_CERTS, 0, 0, GLib.OptionArg.NONE, null,
|
||||
/// Command line option
|
||||
N_("Revoke all pinned TLS server certificates"), null },
|
||||
{ OPTION_VERSION, 'v', 0, GLib.OptionArg.NONE, null,
|
||||
/// Command line option
|
||||
N_("Display program version"), null },
|
||||
// Use this to specify arguments in the help section
|
||||
{ GLib.OPTION_REMAINING, 0, 0, GLib.OptionArg.STRING_ARRAY, null, null,
|
||||
"[mailto:[...]]" },
|
||||
{ null }
|
||||
};
|
||||
|
||||
private const int64 USEC_PER_SEC = 1000000;
|
||||
private const int64 FORCE_SHUTDOWN_USEC = 5 * USEC_PER_SEC;
|
||||
|
||||
|
|
@ -118,23 +193,44 @@ public class GearyApplication : Gtk.Application {
|
|||
}
|
||||
|
||||
/**
|
||||
* The user's desktop-wide settings for the application.
|
||||
* The user's desktop settings for the application.
|
||||
*
|
||||
* This will be null until {@link startup} has been called, and
|
||||
* hence will only ever become non-null for the primary instance.
|
||||
*/
|
||||
public Configuration config { get; private set; }
|
||||
public Configuration? config {
|
||||
get; private set; default = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages the autostart desktop file.
|
||||
*
|
||||
* This will be null until {@link startup} has been called, and
|
||||
* hence will only ever become non-null for the primary instance.
|
||||
*/
|
||||
public Application.StartupManager? autostart {
|
||||
get; private set; default = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if Geary configured to run as as a background service.
|
||||
*
|
||||
* If this returns `true`, then the primary application instance
|
||||
* will continue to run in the background after the last window is
|
||||
* closed, instead of existing as usual.
|
||||
* closed, instead of exiting as usual.
|
||||
*/
|
||||
public bool is_background_service {
|
||||
get { return Args.hidden_startup || this.config.startup_notifications; }
|
||||
get {
|
||||
return (
|
||||
(this.flags & ApplicationFlags.IS_SERVICE) != 0 ||
|
||||
this.start_hidden
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private string bin;
|
||||
private string binary;
|
||||
private File exec_dir;
|
||||
private bool start_hidden = false;
|
||||
private bool exiting_fired = false;
|
||||
private int exitcode = 0;
|
||||
private bool is_destroyed = false;
|
||||
|
|
@ -238,57 +334,40 @@ public class GearyApplication : Gtk.Application {
|
|||
|
||||
public GearyApplication() {
|
||||
Object(
|
||||
application_id: APP_ID
|
||||
application_id: APP_ID,
|
||||
flags: GLib.ApplicationFlags.HANDLES_COMMAND_LINE
|
||||
);
|
||||
this.add_main_option_entries(OPTION_ENTRIES);
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
// Application.run() calls this as an entry point.
|
||||
public override bool local_command_line(ref unowned string[] args, out int exit_status) {
|
||||
bin = args[0];
|
||||
exec_dir = (File.new_for_path(Posix.realpath(Environment.find_program_in_path(bin)))).get_parent();
|
||||
public override bool local_command_line(ref unowned string[] args,
|
||||
out int exit_status) {
|
||||
this.binary = args[0];
|
||||
string current_path = Posix.realpath(
|
||||
GLib.Environment.find_program_in_path(this.binary)
|
||||
);
|
||||
this.exec_dir = GLib.File.new_for_path(current_path).get_parent();
|
||||
|
||||
try {
|
||||
register();
|
||||
} catch (Error e) {
|
||||
error("Error registering GearyApplication: %s", e.message);
|
||||
return base.local_command_line(ref args, out exit_status);
|
||||
}
|
||||
|
||||
public override int handle_local_options(GLib.VariantDict options) {
|
||||
if (options.contains(OPTION_VERSION)) {
|
||||
GLib.stdout.printf(
|
||||
"%s: %s\n", this.binary, GearyApplication.VERSION
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!Args.parse(args)) {
|
||||
exit_status = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Args.quit) {
|
||||
// Normal application startup or activation
|
||||
activate();
|
||||
foreach (unowned string arg in args) {
|
||||
if (arg != null) {
|
||||
if (arg == Geary.ComposedEmail.MAILTO_SCHEME)
|
||||
activate_action(ACTION_COMPOSE, null);
|
||||
else if (arg.has_prefix(Geary.ComposedEmail.MAILTO_SCHEME))
|
||||
activate_action(ACTION_MAILTO, new Variant.string(arg));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// User requested quit, only try to if we aren't running
|
||||
// already.
|
||||
if (this.is_remote) {
|
||||
activate_action(ACTION_QUIT, null);
|
||||
}
|
||||
}
|
||||
|
||||
exit_status = 0;
|
||||
return true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public override void startup() {
|
||||
Configuration.init(is_installed(), GSETTINGS_DIR);
|
||||
|
||||
Environment.set_application_name(NAME);
|
||||
Environment.set_prgname(PRGNAME);
|
||||
International.init(GETTEXT_PACKAGE, bin);
|
||||
International.init(GETTEXT_PACKAGE, this.binary);
|
||||
|
||||
Configuration.init(is_installed(), GSETTINGS_DIR);
|
||||
Geary.Logging.init();
|
||||
Geary.Logging.log_to(stderr);
|
||||
GLib.Log.set_default_handler(Geary.Logging.default_handler);
|
||||
|
|
@ -301,7 +380,30 @@ public class GearyApplication : Gtk.Application {
|
|||
// Ensure all geary windows have an icon
|
||||
Gtk.Window.set_default_icon_name(APP_ID);
|
||||
|
||||
add_action_entries(action_entries, this);
|
||||
this.config = new Configuration(APP_ID);
|
||||
this.autostart = new Application.StartupManager(
|
||||
this.config, get_install_dir()
|
||||
);
|
||||
|
||||
add_action_entries(ACTION_ENTRIES, this);
|
||||
|
||||
if (this.is_background_service) {
|
||||
// Since command_line won't be called below if running as
|
||||
// a DBus service, disable logging spew and start the
|
||||
// controller running.
|
||||
Geary.Logging.log_to(null);
|
||||
this.create_async.begin();
|
||||
}
|
||||
}
|
||||
|
||||
public override int command_line(GLib.ApplicationCommandLine command_line) {
|
||||
int exit_value = handle_general_options(command_line);
|
||||
if (exit_value != -1)
|
||||
return exit_value;
|
||||
|
||||
activate();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public override void activate() {
|
||||
|
|
@ -340,8 +442,6 @@ public class GearyApplication : Gtk.Application {
|
|||
message("%s %s prefix=%s exec_dir=%s is_installed=%s", NAME, VERSION, INSTALL_PREFIX,
|
||||
exec_dir.get_path(), is_installed().to_string());
|
||||
|
||||
config = new Configuration(APP_ID);
|
||||
|
||||
// Application accels
|
||||
add_app_accelerators(ACTION_COMPOSE, { "<Ctrl>N" });
|
||||
add_app_accelerators(ACTION_HELP, { "F1" });
|
||||
|
|
@ -358,7 +458,7 @@ public class GearyApplication : Gtk.Application {
|
|||
ComposerWidget.add_window_accelerators(this);
|
||||
Components.Inspector.add_window_accelerators(this);
|
||||
|
||||
yield controller.open_async(null);
|
||||
yield this.controller.open_async(null);
|
||||
|
||||
release();
|
||||
}
|
||||
|
|
@ -367,11 +467,12 @@ public class GearyApplication : Gtk.Application {
|
|||
// see create_async() for reasoning hold/release is used
|
||||
hold();
|
||||
|
||||
yield controller.close_async();
|
||||
if (this.controller != null && this.controller.is_open) {
|
||||
yield this.controller.close_async();
|
||||
}
|
||||
|
||||
release();
|
||||
|
||||
is_destroyed = true;
|
||||
this.is_destroyed = true;
|
||||
}
|
||||
|
||||
public void add_window_accelerators(string action,
|
||||
|
|
@ -479,7 +580,7 @@ public class GearyApplication : Gtk.Application {
|
|||
|
||||
// This call will fire "exiting" only if it's not already been fired.
|
||||
public void exit(int exitcode = 0) {
|
||||
if (exiting_fired)
|
||||
if (this.exiting_fired)
|
||||
return;
|
||||
|
||||
this.exitcode = exitcode;
|
||||
|
|
@ -537,6 +638,95 @@ public class GearyApplication : Gtk.Application {
|
|||
set_accels_for_action("app." + action, accelerators);
|
||||
}
|
||||
|
||||
public int handle_general_options(GLib.ApplicationCommandLine command_line) {
|
||||
GLib.VariantDict options = command_line.get_options_dict();
|
||||
if (options.contains(OPTION_QUIT)) {
|
||||
exit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool enable_debug = options.contains(OPTION_DEBUG);
|
||||
// Will be logging to stderr until this point
|
||||
if (enable_debug) {
|
||||
Geary.Logging.log_to(GLib.stdout);
|
||||
} else {
|
||||
Geary.Logging.log_to(null);
|
||||
}
|
||||
|
||||
// Logging flags
|
||||
if (options.contains(OPTION_LOG_NETWORK))
|
||||
Geary.Logging.enable_flags(Geary.Logging.Flag.NETWORK);
|
||||
if (options.contains(OPTION_LOG_SERIALIZER))
|
||||
Geary.Logging.enable_flags(Geary.Logging.Flag.SERIALIZER);
|
||||
if (options.contains(OPTION_LOG_REPLAY_QUEUE))
|
||||
Geary.Logging.enable_flags(Geary.Logging.Flag.REPLAY);
|
||||
if (options.contains(OPTION_LOG_CONVERSATIONS))
|
||||
Geary.Logging.enable_flags(Geary.Logging.Flag.CONVERSATIONS);
|
||||
if (options.contains(OPTION_LOG_PERIODIC))
|
||||
Geary.Logging.enable_flags(Geary.Logging.Flag.PERIODIC);
|
||||
if (options.contains(OPTION_LOG_SQL))
|
||||
Geary.Logging.enable_flags(Geary.Logging.Flag.SQL);
|
||||
if (options.contains(OPTION_LOG_FOLDER_NORM))
|
||||
Geary.Logging.enable_flags(Geary.Logging.Flag.FOLDER_NORMALIZATION);
|
||||
if (options.contains(OPTION_LOG_DESERIALIZER))
|
||||
Geary.Logging.enable_flags(Geary.Logging.Flag.DESERIALIZER);
|
||||
if (options.contains(OPTION_HIDDEN)) {
|
||||
warning(
|
||||
/// Warning printed to the console when a deprecated
|
||||
/// command line option is used.
|
||||
_("The `--hidden` option is deprecated and will be removed in the future.")
|
||||
);
|
||||
this.start_hidden = true;
|
||||
// Update the autostart file so that it stops using the
|
||||
// --hidden option.
|
||||
this.update_autostart_file.begin();
|
||||
}
|
||||
if (options.contains(GLib.OPTION_REMAINING)) {
|
||||
string[] args = options.lookup_value(
|
||||
GLib.OPTION_REMAINING,
|
||||
GLib.VariantType.STRING_ARRAY
|
||||
).get_strv();
|
||||
foreach (string arg in args) {
|
||||
// the only acceptable arguments are mailto:'s
|
||||
if (arg == Geary.ComposedEmail.MAILTO_SCHEME) {
|
||||
activate_action(GearyApplication.ACTION_COMPOSE, null);
|
||||
} else if (arg.has_prefix(Geary.ComposedEmail.MAILTO_SCHEME)) {
|
||||
activate_action(
|
||||
GearyApplication.ACTION_MAILTO,
|
||||
new GLib.Variant.string(arg)
|
||||
);
|
||||
} else {
|
||||
command_line.printerr("%s: ", this.binary);
|
||||
command_line.printerr(
|
||||
/// Command line warning, string substitution
|
||||
/// is the given argument
|
||||
_("Unrecognised program argument: “%s”"), arg
|
||||
);
|
||||
command_line.printerr("\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.config.enable_debug = enable_debug;
|
||||
this.config.enable_inspector = options.contains(OPTION_INSPECTOR);
|
||||
this.config.revoke_certs = options.contains(OPTION_REVOKE_CERTS);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Removes and re-adds the austostart file if needed. */
|
||||
private async void update_autostart_file() {
|
||||
try {
|
||||
this.autostart.delete_startup_file();
|
||||
if (this.config.startup_notifications) {
|
||||
this.autostart.install_startup_file();
|
||||
}
|
||||
} catch (GLib.Error err) {
|
||||
warning("Could not update autostart file");
|
||||
}
|
||||
}
|
||||
|
||||
private void on_activate_about() {
|
||||
Gtk.show_about_dialog(get_active_window(),
|
||||
"program-name", NAME,
|
||||
|
|
@ -580,7 +770,7 @@ public class GearyApplication : Gtk.Application {
|
|||
|
||||
private void on_activate_mailto(SimpleAction action, Variant? param) {
|
||||
if (this.controller != null && param != null) {
|
||||
this.controller.compose_mailto(param.get_string());
|
||||
this.controller.compose(param.get_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,122 +0,0 @@
|
|||
/* Copyright 2016 Software Freedom Conservancy Inc.
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
namespace Args {
|
||||
|
||||
private const OptionEntry[] options = {
|
||||
{ "hidden", 0, 0, OptionArg.NONE, ref hidden_startup, N_("Start Geary with hidden main window"), null },
|
||||
{ "debug", 'd', 0, OptionArg.NONE, ref log_debug, N_("Output debugging information"), null },
|
||||
{ "log-conversations", 0, 0, OptionArg.NONE, ref log_conversations, N_("Log conversation monitoring"), null },
|
||||
{ "log-deserializer", 0, 0, OptionArg.NONE, ref log_deserializer, N_("Log network deserialization"), null },
|
||||
{ "log-network", 0, 0, OptionArg.NONE, ref log_network, N_("Log network activity"), null },
|
||||
/// The IMAP replay queue is how changes on the server are replicated on the client.
|
||||
/// It could also be called the IMAP events queue.
|
||||
{ "log-replay-queue", 0, 0, OptionArg.NONE, ref log_replay_queue, N_("Log IMAP replay queue"), null },
|
||||
/// Serialization is how commands and responses are converted into a stream of bytes for
|
||||
/// network transmission
|
||||
{ "log-serializer", 0, 0, OptionArg.NONE, ref log_serializer, N_("Log network serialization"), null },
|
||||
{ "log-periodic", 0, 0, OptionArg.NONE, ref log_periodic, N_("Log periodic activity"), null },
|
||||
{ "log-sql", 0, 0, OptionArg.NONE, ref log_sql, N_("Log database queries (generates lots of messages)"), null },
|
||||
/// "Normalization" can also be called "synchronization"
|
||||
{ "log-folder-normalization", 0, 0, OptionArg.NONE, ref log_folder_normalization, N_("Log folder normalization"), null },
|
||||
{ "inspector", 'i', 0, OptionArg.NONE, ref inspector, N_("Allow inspection of WebView"), null },
|
||||
{ "revoke-certs", 0, 0, OptionArg.NONE, ref revoke_certs, N_("Revoke all server certificates with TLS warnings"), null },
|
||||
{ "quit", 'q', 0, OptionArg.NONE, ref quit, N_("Perform a graceful quit"), null },
|
||||
{ "version", 'V', 0, OptionArg.NONE, ref version, N_("Display program version"), null },
|
||||
{ null }
|
||||
};
|
||||
|
||||
public bool hidden_startup = false;
|
||||
public bool log_debug = false;
|
||||
public bool log_network = false;
|
||||
public bool log_serializer = false;
|
||||
public bool log_deserializer = false;
|
||||
public bool log_replay_queue = false;
|
||||
public bool log_conversations = false;
|
||||
public bool log_periodic = false;
|
||||
public bool log_sql = false;
|
||||
public bool log_folder_normalization = false;
|
||||
public bool inspector = false;
|
||||
public bool quit = false;
|
||||
public bool revoke_certs = false;
|
||||
public bool version = false;
|
||||
|
||||
public bool parse(string[] args) {
|
||||
var context = new OptionContext("[%s...]".printf(Geary.ComposedEmail.MAILTO_SCHEME));
|
||||
context.set_help_enabled(true);
|
||||
context.add_main_entries(options, null);
|
||||
context.set_description("%s\n\n%s\n%s\n\n%s\n\t%s\n".printf(
|
||||
// This gives a command-line hint on how to open new composer windows with mailto:
|
||||
_("Use %s to open a new composer window").printf(Geary.ComposedEmail.MAILTO_SCHEME),
|
||||
GearyApplication.COPYRIGHT_1,
|
||||
GearyApplication.COPYRIGHT_2,
|
||||
_("Please report comments, suggestions and bugs to:"),
|
||||
GearyApplication.BUGREPORT));
|
||||
|
||||
try {
|
||||
context.parse(ref args);
|
||||
} catch (OptionError error) {
|
||||
// i18n: Command line arguments are invalid
|
||||
stdout.printf (_("Failed to parse command line options: %s\n"), error.message);
|
||||
stdout.printf("\n%s", context.get_help(true, null));
|
||||
return false;
|
||||
}
|
||||
|
||||
// other than the OptionEntry command-line arguments, the only acceptable arguments are
|
||||
// mailto:'s
|
||||
for (int ctr = 1; ctr < args.length; ctr++) {
|
||||
string arg = args[ctr];
|
||||
|
||||
if (!arg.has_prefix(Geary.ComposedEmail.MAILTO_SCHEME)) {
|
||||
stdout.printf(_("Unrecognized command line option “%s”\n").printf(arg));
|
||||
stdout.printf("\n%s", context.get_help(true, null));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (version) {
|
||||
stdout.printf("%s %s\n", GearyApplication.PRGNAME, GearyApplication.VERSION);
|
||||
Process.exit(0);
|
||||
}
|
||||
|
||||
if (log_network)
|
||||
Geary.Logging.enable_flags(Geary.Logging.Flag.NETWORK);
|
||||
|
||||
if (log_serializer)
|
||||
Geary.Logging.enable_flags(Geary.Logging.Flag.SERIALIZER);
|
||||
|
||||
if (log_replay_queue)
|
||||
Geary.Logging.enable_flags(Geary.Logging.Flag.REPLAY);
|
||||
|
||||
if (log_conversations)
|
||||
Geary.Logging.enable_flags(Geary.Logging.Flag.CONVERSATIONS);
|
||||
|
||||
if (log_periodic)
|
||||
Geary.Logging.enable_flags(Geary.Logging.Flag.PERIODIC);
|
||||
|
||||
if (log_sql)
|
||||
Geary.Logging.enable_flags(Geary.Logging.Flag.SQL);
|
||||
|
||||
if (log_folder_normalization)
|
||||
Geary.Logging.enable_flags(Geary.Logging.Flag.FOLDER_NORMALIZATION);
|
||||
|
||||
if (log_deserializer)
|
||||
Geary.Logging.enable_flags(Geary.Logging.Flag.DESERIALIZER);
|
||||
|
||||
if (log_debug) {
|
||||
Geary.Logging.log_to(stdout);
|
||||
} else {
|
||||
// We'll be logging to stderror until this point, so stop
|
||||
// that.
|
||||
Geary.Logging.log_to(null);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -52,6 +52,15 @@ public class Configuration {
|
|||
public Settings settings { get; private set; }
|
||||
public Settings gnome_interface { get; private set; }
|
||||
|
||||
// Can be set as an arguments
|
||||
public bool enable_debug { get; set; default = false; }
|
||||
|
||||
// Can be set as an arguments
|
||||
public bool enable_inspector { get; set; default = false; }
|
||||
|
||||
// Can be set as an arguments
|
||||
public bool revoke_certs { get; set; default = false; }
|
||||
|
||||
public DesktopEnvironment desktop_environment {
|
||||
get {
|
||||
string? xdg_current_desktop = Environment.get_variable("XDG_CURRENT_DESKTOP");
|
||||
|
|
|
|||
|
|
@ -109,6 +109,13 @@ public class GearyController : Geary.BaseObject {
|
|||
}
|
||||
|
||||
|
||||
/** Determines if the controller is opening or is open. */
|
||||
public bool is_open {
|
||||
get {
|
||||
return (this.open_cancellable != null);
|
||||
}
|
||||
}
|
||||
|
||||
public weak GearyApplication application { get; private set; } // circular ref
|
||||
|
||||
public Accounts.Manager? account_manager { get; private set; default = null; }
|
||||
|
|
@ -122,8 +129,6 @@ public class GearyController : Geary.BaseObject {
|
|||
|
||||
public Geary.App.ConversationMonitor? current_conversations { get; private set; default = null; }
|
||||
|
||||
public AutostartManager? autostart_manager { get; private set; default = null; }
|
||||
|
||||
public Application.AvatarStore? avatars {
|
||||
get; private set; default = new Application.AvatarStore();
|
||||
}
|
||||
|
|
@ -158,7 +163,7 @@ public class GearyController : Geary.BaseObject {
|
|||
private Geary.Nonblocking.Mutex select_folder_mutex = new Geary.Nonblocking.Mutex();
|
||||
private Geary.Folder? previous_non_search_folder = null;
|
||||
private UpgradeDialog upgrade_dialog;
|
||||
private Gee.List<string> pending_mailtos = new Gee.ArrayList<string>();
|
||||
private Gee.List<string?> pending_mailtos = new Gee.ArrayList<string>();
|
||||
|
||||
private uint operation_count = 0;
|
||||
private Geary.Revokable? revokable = null;
|
||||
|
|
@ -254,8 +259,7 @@ public class GearyController : Geary.BaseObject {
|
|||
ClientWebView.init_web_context(
|
||||
this.application.config,
|
||||
this.application.get_web_extensions_dir(),
|
||||
this.application.get_user_cache_directory().get_child("web-resources"),
|
||||
Args.log_debug
|
||||
this.application.get_user_cache_directory().get_child("web-resources")
|
||||
);
|
||||
try {
|
||||
ClientWebView.load_resources(
|
||||
|
|
@ -329,9 +333,6 @@ public class GearyController : Geary.BaseObject {
|
|||
|
||||
this.main_window.conversation_list_view.grab_focus();
|
||||
|
||||
// instantiate here to ensure that Config is initialized and ready
|
||||
this.autostart_manager = new AutostartManager(this.application);
|
||||
|
||||
// initialize revokable
|
||||
save_revokable(null, null);
|
||||
|
||||
|
|
@ -414,29 +415,32 @@ public class GearyController : Geary.BaseObject {
|
|||
this.open_cancellable.cancel();
|
||||
this.open_cancellable = null;
|
||||
|
||||
Geary.Engine.instance.account_available.disconnect(on_account_available);
|
||||
this.application.engine.account_available.disconnect(on_account_available);
|
||||
|
||||
// Release folder and conversations in the main window
|
||||
on_conversations_selected(new Gee.HashSet<Geary.App.Conversation>());
|
||||
on_folder_selected(null);
|
||||
if (this.main_window != null) {
|
||||
// Release folder and conversations in the main window
|
||||
on_conversations_selected(new Gee.HashSet<Geary.App.Conversation>());
|
||||
on_folder_selected(null);
|
||||
|
||||
// Disconnect from various UI signals.
|
||||
main_window.conversation_list_view.conversations_selected.disconnect(on_conversations_selected);
|
||||
main_window.conversation_list_view.conversation_activated.disconnect(on_conversation_activated);
|
||||
main_window.conversation_list_view.load_more.disconnect(on_load_more);
|
||||
main_window.conversation_list_view.mark_conversations.disconnect(on_mark_conversations);
|
||||
main_window.conversation_list_view.visible_conversations_changed.disconnect(on_visible_conversations_changed);
|
||||
main_window.folder_list.folder_selected.disconnect(on_folder_selected);
|
||||
main_window.folder_list.copy_conversation.disconnect(on_copy_conversation);
|
||||
main_window.folder_list.move_conversation.disconnect(on_move_conversation);
|
||||
main_window.main_toolbar.copy_folder_menu.folder_selected.disconnect(on_copy_conversation);
|
||||
main_window.main_toolbar.move_folder_menu.folder_selected.disconnect(on_move_conversation);
|
||||
main_window.conversation_viewer.conversation_added.disconnect(
|
||||
on_conversation_view_added
|
||||
);
|
||||
// Disconnect from various UI signals.
|
||||
this.main_window.conversation_list_view.conversations_selected.disconnect(on_conversations_selected);
|
||||
this.main_window.conversation_list_view.conversation_activated.disconnect(on_conversation_activated);
|
||||
this.main_window.conversation_list_view.load_more.disconnect(on_load_more);
|
||||
this.main_window.conversation_list_view.mark_conversations.disconnect(on_mark_conversations);
|
||||
this.main_window.conversation_list_view.visible_conversations_changed.disconnect(on_visible_conversations_changed);
|
||||
this.main_window.folder_list.folder_selected.disconnect(on_folder_selected);
|
||||
this.main_window.folder_list.copy_conversation.disconnect(on_copy_conversation);
|
||||
this.main_window.folder_list.move_conversation.disconnect(on_move_conversation);
|
||||
this.main_window.main_toolbar.copy_folder_menu.folder_selected.disconnect(on_copy_conversation);
|
||||
this.main_window.main_toolbar.move_folder_menu.folder_selected.disconnect(on_move_conversation);
|
||||
this.main_window.conversation_viewer.conversation_added.disconnect(
|
||||
on_conversation_view_added
|
||||
);
|
||||
|
||||
// hide window while shutting down, as this can take a few seconds under certain conditions
|
||||
main_window.hide();
|
||||
// hide window while shutting down, as this can take a few
|
||||
// seconds under certain conditions
|
||||
this.main_window.hide();
|
||||
}
|
||||
|
||||
// Release monitoring early so held resources can be freed up
|
||||
this.libnotify = null;
|
||||
|
|
@ -533,9 +537,11 @@ public class GearyController : Geary.BaseObject {
|
|||
);
|
||||
this.account_manager = null;
|
||||
|
||||
this.application.remove_window(this.main_window);
|
||||
this.main_window.destroy();
|
||||
this.main_window = null;
|
||||
if (this.main_window != null) {
|
||||
this.application.remove_window(this.main_window);
|
||||
this.main_window.destroy();
|
||||
this.main_window = null;
|
||||
}
|
||||
|
||||
this.upgrade_dialog = null;
|
||||
|
||||
|
|
@ -551,8 +557,6 @@ public class GearyController : Geary.BaseObject {
|
|||
this.composer_widgets.clear();
|
||||
this.waiting_to_close.clear();
|
||||
|
||||
this.autostart_manager = null;
|
||||
|
||||
this.avatars.close();
|
||||
this.avatars = null;
|
||||
|
||||
|
|
@ -560,17 +564,10 @@ public class GearyController : Geary.BaseObject {
|
|||
debug("Closed GearyController");
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new, blank composer.
|
||||
*/
|
||||
public void compose() {
|
||||
create_compose_widget(ComposerWidget.ComposeType.NEW_MESSAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens or queues a new composer addressed to a specific email address.
|
||||
*/
|
||||
public void compose_mailto(string mailto) {
|
||||
public void compose(string? mailto = null) {
|
||||
if (current_account == null) {
|
||||
// Schedule the send for after we have an account open.
|
||||
pending_mailtos.add(mailto);
|
||||
|
|
@ -861,7 +858,7 @@ public class GearyController : Geary.BaseObject {
|
|||
Geary.ServiceInformation service,
|
||||
Geary.Endpoint endpoint,
|
||||
GLib.TlsConnection cx) {
|
||||
if (Args.revoke_certs) {
|
||||
if (this.application.config.revoke_certs) {
|
||||
// XXX
|
||||
}
|
||||
|
||||
|
|
@ -1063,7 +1060,7 @@ public class GearyController : Geary.BaseObject {
|
|||
if (did_attempt_open_all_accounts() &&
|
||||
!upgrade_dialog.visible &&
|
||||
!cancellable_open_account.is_cancelled() &&
|
||||
!Args.hidden_startup)
|
||||
!this.application.is_background_service)
|
||||
main_window.show();
|
||||
}
|
||||
|
||||
|
|
@ -1184,8 +1181,8 @@ public class GearyController : Geary.BaseObject {
|
|||
|
||||
// If we were waiting for an account to be selected before issuing mailtos, do that now.
|
||||
if (pending_mailtos.size > 0) {
|
||||
foreach(string mailto in pending_mailtos)
|
||||
compose_mailto(mailto);
|
||||
foreach(string? mailto in pending_mailtos)
|
||||
compose(mailto);
|
||||
|
||||
pending_mailtos.clear();
|
||||
}
|
||||
|
|
@ -2284,7 +2281,7 @@ public class GearyController : Geary.BaseObject {
|
|||
}
|
||||
|
||||
private void on_close() {
|
||||
this.application.exit();
|
||||
this.main_window.close();
|
||||
}
|
||||
|
||||
private void on_reply_to_message(ConversationEmail target_view) {
|
||||
|
|
@ -2530,12 +2527,14 @@ public class GearyController : Geary.BaseObject {
|
|||
revokable.committed.connect(on_revokable_committed);
|
||||
}
|
||||
|
||||
if (revokable != null && description != null)
|
||||
this.main_window.main_toolbar.undo_tooltip = description;
|
||||
else
|
||||
this.main_window.main_toolbar.undo_tooltip = _("Undo (Ctrl+Z)");
|
||||
if (this.main_window != null) {
|
||||
if (revokable != null && description != null)
|
||||
this.main_window.main_toolbar.undo_tooltip = description;
|
||||
else
|
||||
this.main_window.main_toolbar.undo_tooltip = _("Undo (Ctrl+Z)");
|
||||
|
||||
update_revokable_action();
|
||||
update_revokable_action();
|
||||
}
|
||||
}
|
||||
|
||||
private void update_revokable_action() {
|
||||
|
|
@ -3029,7 +3028,9 @@ public class GearyController : Geary.BaseObject {
|
|||
private void on_scan_completed(Geary.App.ConversationMonitor monitor) {
|
||||
// Done scanning. Check if we have enough messages to fill
|
||||
// the conversation list; if not, trigger a load_more();
|
||||
if (!main_window.conversation_list_has_scrollbar() &&
|
||||
if (this.main_window != null &&
|
||||
this.main_window.is_visible() &&
|
||||
!this.main_window.conversation_list_has_scrollbar() &&
|
||||
monitor == this.current_conversations &&
|
||||
monitor.can_load_more) {
|
||||
debug("Not enough messages, loading more for folder %s",
|
||||
|
|
@ -3074,7 +3075,7 @@ public class GearyController : Geary.BaseObject {
|
|||
|
||||
private void on_link_activated(string uri) {
|
||||
if (uri.down().has_prefix(Geary.ComposedEmail.MAILTO_SCHEME)) {
|
||||
compose_mailto(uri);
|
||||
compose(uri);
|
||||
} else {
|
||||
open_uri(uri);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,8 +73,7 @@ public abstract class ClientWebView : WebKit.WebView, Geary.BaseInterface {
|
|||
*/
|
||||
public static void init_web_context(Configuration config,
|
||||
File web_extension_dir,
|
||||
File cache_dir,
|
||||
bool enable_logging) {
|
||||
File cache_dir) {
|
||||
WebsiteDataManager data_manager = new WebsiteDataManager(cache_dir.get_path());
|
||||
WebKit.WebContext context = new WebKit.WebContext.with_website_data_manager(data_manager);
|
||||
// Use a shared process so we don't spawn N WebProcess instances
|
||||
|
|
@ -101,7 +100,7 @@ public abstract class ClientWebView : WebKit.WebView, Geary.BaseInterface {
|
|||
web_extension_dir.get_path()
|
||||
);
|
||||
context.set_web_extensions_initialization_user_data(
|
||||
new Variant.boolean(enable_logging)
|
||||
new Variant.boolean(config.enable_debug)
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -300,7 +299,7 @@ public abstract class ClientWebView : WebKit.WebView, Geary.BaseInterface {
|
|||
WebKit.Settings setts = new WebKit.Settings();
|
||||
setts.allow_modal_dialogs = false;
|
||||
setts.default_charset = "UTF-8";
|
||||
setts.enable_developer_extras = Args.inspector;
|
||||
setts.enable_developer_extras = config.enable_inspector;
|
||||
setts.enable_fullscreen = false;
|
||||
setts.enable_html5_database = false;
|
||||
setts.enable_html5_local_storage = false;
|
||||
|
|
|
|||
|
|
@ -637,7 +637,7 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
|
|||
|
||||
[GtkCallback]
|
||||
private bool on_delete_event() {
|
||||
if (this.application.is_background_service) {
|
||||
if (this.application.config.startup_notifications) {
|
||||
if (this.application.controller.close_composition_windows(true)) {
|
||||
hide();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -998,7 +998,7 @@ public class ComposerWidget : Gtk.EventBox, Geary.BaseInterface {
|
|||
}
|
||||
|
||||
// User-Agent
|
||||
email.mailer = GearyApplication.PRGNAME + "/" + GearyApplication.VERSION;
|
||||
email.mailer = Environment.get_prgname() + "/" + GearyApplication.VERSION;
|
||||
|
||||
return email;
|
||||
}
|
||||
|
|
@ -1968,7 +1968,7 @@ public class ComposerWidget : Gtk.EventBox, Geary.BaseInterface {
|
|||
if (!this.editor.is_rich_text)
|
||||
append_menu_section(context_menu, section);
|
||||
} else if (section == this.context_menu_inspector) {
|
||||
if (Args.inspector)
|
||||
if (this.config.enable_inspector)
|
||||
append_menu_section(context_menu, section);
|
||||
} else {
|
||||
append_menu_section(context_menu, section);
|
||||
|
|
|
|||
|
|
@ -141,7 +141,8 @@ public class ConversationListView : Gtk.TreeView, Geary.BaseInterface {
|
|||
Gtk.Adjustment adjustment = ((Gtk.Scrollable) this).get_vadjustment();
|
||||
double upper = adjustment.get_upper();
|
||||
double threshold = upper - adjustment.page_size - LOAD_MORE_HEIGHT;
|
||||
if (this.conversation_monitor.can_load_more &&
|
||||
if (this.is_visible() &&
|
||||
this.conversation_monitor.can_load_more &&
|
||||
adjustment.get_value() >= threshold) {
|
||||
load_more();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -408,7 +408,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
|
|||
add_action(ACTION_COPY_SELECTION, false).activate.connect(() => {
|
||||
web_view.copy_clipboard();
|
||||
});
|
||||
add_action(ACTION_OPEN_INSPECTOR, Args.inspector).activate.connect(() => {
|
||||
add_action(ACTION_OPEN_INSPECTOR, config.enable_inspector).activate.connect(() => {
|
||||
this.web_view.get_inspector().show();
|
||||
});
|
||||
add_action(ACTION_OPEN_LINK, true, VariantType.STRING)
|
||||
|
|
@ -429,7 +429,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
|
|||
context_menu_email = (MenuModel) builder.get_object("context_menu_email");
|
||||
context_menu_image = (MenuModel) builder.get_object("context_menu_image");
|
||||
context_menu_main = (MenuModel) builder.get_object("context_menu_main");
|
||||
if (Args.inspector) {
|
||||
if (config.enable_inspector) {
|
||||
context_menu_inspector =
|
||||
(MenuModel) builder.get_object("context_menu_inspector");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ public class PreferencesDialog : Gtk.Dialog {
|
|||
|
||||
public new void run() {
|
||||
// Sync startup notification option with file state
|
||||
this.app.controller.autostart_manager.sync_with_config();
|
||||
this.app.autostart.sync_with_config();
|
||||
|
||||
base.run();
|
||||
destroy();
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@ geary_client_vala_sources = files(
|
|||
'application/application-command.vala',
|
||||
'application/application-contact-store.vala',
|
||||
'application/application-contact.vala',
|
||||
'application/autostart-manager.vala',
|
||||
'application/application-startup-manager.vala',
|
||||
'application/geary-application.vala',
|
||||
'application/geary-args.vala',
|
||||
'application/geary-config.vala',
|
||||
'application/geary-controller.vala',
|
||||
'application/goa-mediator.vala',
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ public class Libnotify : Geary.BaseObject {
|
|||
monitor.add_required_fields(REQUIRED_FIELDS);
|
||||
|
||||
if (!Notify.is_initted()) {
|
||||
if (!Notify.init(GearyApplication.PRGNAME))
|
||||
if (!Notify.init(Environment.get_prgname()))
|
||||
message("Failed to initialize libnotify.");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@ public abstract class ClientWebViewTestCase<V> : TestCase {
|
|||
protected ClientWebViewTestCase(string name) {
|
||||
base(name);
|
||||
this.config = new Configuration(GearyApplication.APP_ID);
|
||||
this.config.enable_debug = true;
|
||||
ClientWebView.init_web_context(
|
||||
this.config,
|
||||
File.new_for_path(_BUILD_ROOT_DIR).get_child("src"),
|
||||
File.new_for_path("/tmp"), // XXX use something better here
|
||||
true
|
||||
File.new_for_path("/tmp") // XXX use something better here
|
||||
);
|
||||
try {
|
||||
ClientWebView.load_resources(GLib.File.new_for_path("/tmp"));
|
||||
|
|
|
|||
|
|
@ -15,11 +15,11 @@ public class ClientWebViewTest : TestCase {
|
|||
|
||||
public void init_web_context() throws Error {
|
||||
Configuration config = new Configuration(GearyApplication.APP_ID);
|
||||
config.enable_debug = true;
|
||||
ClientWebView.init_web_context(
|
||||
config,
|
||||
File.new_for_path(_BUILD_ROOT_DIR).get_child("src"),
|
||||
File.new_for_path("/tmp"), // XXX use something better here
|
||||
true
|
||||
File.new_for_path("/tmp") // XXX use something better here
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue