Support Ubuntu messaging menu: Closes #5648
libindicate is supported in this patch (with some framework in place to support others, such as libmessagingmenu if/when it comes down the pipe). libindicate support must be configured with a ./configure switch (which is one-half of #5607) and is off by default. Note that this patch does not fully implement our design spec for how new messages are cleared due to user interaction. That is covered by #5669.
This commit is contained in:
parent
c104f1e45e
commit
6da84dfc79
8 changed files with 225 additions and 22 deletions
7
configure
vendored
7
configure
vendored
|
|
@ -29,6 +29,9 @@ configure_help() {
|
|||
printf "\t--disable-icon-update\n"
|
||||
printf "\t\t\t\tDisable icon cache update.\n"
|
||||
|
||||
printf "\t--enable-libindicate\n"
|
||||
printf "\t\t\t\tEnable libindicate messaging menu support.\n"
|
||||
|
||||
printf "\n"
|
||||
}
|
||||
|
||||
|
|
@ -72,6 +75,10 @@ do
|
|||
CMDLINE="${CMDLINE} -DDESKTOP_UPDATE=OFF"
|
||||
;;
|
||||
|
||||
--enable-libindicate)
|
||||
CMDLINE="${CMDLINE} -DENABLE_LIBINDICATE=ON"
|
||||
;;
|
||||
|
||||
*) abort $option
|
||||
;;
|
||||
esac
|
||||
|
|
|
|||
|
|
@ -196,6 +196,11 @@ client/geary-config.vala
|
|||
client/geary-controller.vala
|
||||
client/main.vala
|
||||
|
||||
client/notification/libindicate.vala
|
||||
client/notification/new-messages-indicator.vala
|
||||
client/notification/notification-bubble.vala
|
||||
client/notification/null-indicator.vala
|
||||
|
||||
client/ui/composer-window.vala
|
||||
client/ui/geary-login.vala
|
||||
client/ui/email-entry.vala
|
||||
|
|
@ -212,7 +217,6 @@ client/ui/message-web-view.vala
|
|||
client/ui/password-dialog.vala
|
||||
client/ui/preferences-dialog.vala
|
||||
client/ui/webview-edit-fixer.vala
|
||||
client/ui/notification-bubble.vala
|
||||
|
||||
client/ui/sidebar/sidebar-branch.vala
|
||||
client/ui/sidebar/sidebar-common.vala
|
||||
|
|
@ -249,6 +253,20 @@ include(ValaVersion)
|
|||
ensure_vala_version("0.17.4" MINIMUM)
|
||||
include(ValaPrecompile)
|
||||
|
||||
option(ENABLE_LIBINDICATE "Enable libindicate messaging menu support." OFF)
|
||||
if (ENABLE_LIBINDICATE STREQUAL "ON")
|
||||
message(STATUS "Building with messaging menu support.")
|
||||
set(EXTRA_CLIENT_PKG_CONFIG
|
||||
indicate-0.7>=0.6.1
|
||||
)
|
||||
set(EXTRA_CLIENT_PACKAGES
|
||||
Dbusmenu-0.4 Indicate-0.7
|
||||
)
|
||||
set(EXTRA_VALA_OPTIONS
|
||||
-D HAVE_LIBINDICATE
|
||||
)
|
||||
endif ()
|
||||
|
||||
# Packages
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(DEPS REQUIRED
|
||||
|
|
@ -264,6 +282,7 @@ pkg_check_modules(DEPS REQUIRED
|
|||
gmime-2.6>=2.6.0
|
||||
gnome-keyring-1>=3.2.2
|
||||
webkitgtk-3.0>=1.8.0
|
||||
${EXTRA_CLIENT_PKG_CONFIG}
|
||||
)
|
||||
|
||||
set(ENGINE_PACKAGES
|
||||
|
|
@ -271,7 +290,7 @@ set(ENGINE_PACKAGES
|
|||
)
|
||||
|
||||
set(CLIENT_PACKAGES
|
||||
gtk+-3.0 gnome-keyring-1 webkitgtk-3.0 libnotify libcanberra
|
||||
gtk+-3.0 gnome-keyring-1 webkitgtk-3.0 libnotify libcanberra ${EXTRA_CLIENT_PACKAGES}
|
||||
)
|
||||
|
||||
set(CONSOLE_PACKAGES
|
||||
|
|
@ -306,6 +325,7 @@ set(VALAC_OPTIONS
|
|||
--enable-checking
|
||||
--debug
|
||||
--fatal-warnings
|
||||
${EXTRA_VALA_OPTIONS}
|
||||
)
|
||||
|
||||
# Engine (conceptually a library, but not built as a separate library)
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
public override void activate(string[] args) {
|
||||
// If Geary is already running, show the main window and return.
|
||||
if (controller != null && controller.main_window != null) {
|
||||
controller.main_window.present();
|
||||
controller.main_window.present_with_time((uint32) TimeVal().tv_sec);
|
||||
handle_args(args);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ public class GearyController {
|
|||
|
||||
public MainWindow main_window { get; private set; }
|
||||
|
||||
private Geary.EngineAccount? account = null;
|
||||
private Cancellable cancellable_folder = new Cancellable();
|
||||
private Cancellable cancellable_inbox = new Cancellable();
|
||||
private Cancellable cancellable_message = new Cancellable();
|
||||
|
|
@ -79,8 +80,7 @@ public class GearyController {
|
|||
private Geary.Conversation? last_deleted_conversation = null;
|
||||
private Gee.LinkedList<ComposerWindow> composer_windows = new Gee.LinkedList<ComposerWindow>();
|
||||
private File? last_save_directory = null;
|
||||
|
||||
private Geary.EngineAccount? account { get; private set; }
|
||||
private NewMessagesIndicator new_messages_indicator;
|
||||
|
||||
public GearyController() {
|
||||
// Setup actions.
|
||||
|
|
@ -92,6 +92,12 @@ public class GearyController {
|
|||
// Listen for attempts to close the application.
|
||||
GearyApplication.instance.exiting.connect(on_application_exiting);
|
||||
|
||||
// New messages indicator (Ubuntuism)
|
||||
new_messages_indicator = NewMessagesIndicator.create();
|
||||
new_messages_indicator.application_activated.connect(on_indicator_activated_application);
|
||||
new_messages_indicator.composer_activated.connect(on_indicator_activated_composer);
|
||||
new_messages_indicator.inbox_activated.connect(on_indicator_activated_inbox);
|
||||
|
||||
// Create the main window (must be done after creating actions.)
|
||||
main_window = new MainWindow();
|
||||
|
||||
|
|
@ -267,6 +273,7 @@ public class GearyController {
|
|||
}
|
||||
|
||||
inbox_folder.email_locally_appended.disconnect(on_inbox_new_email);
|
||||
inbox_folder.email_flags_changed.disconnect(on_inbox_email_flags_changed);
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -435,7 +442,14 @@ public class GearyController {
|
|||
do_notify_new_email.begin(email_ids);
|
||||
}
|
||||
|
||||
public async void do_notify_new_email(Gee.Collection<Geary.EmailIdentifier> email_ids) {
|
||||
private void on_inbox_email_flags_changed(Gee.Map<Geary.EmailIdentifier, Geary.EmailFlags> ids) {
|
||||
foreach(Geary.EmailIdentifier id in ids.keys) {
|
||||
if (!ids[id].is_unread())
|
||||
new_messages_indicator.not_new_message(id);
|
||||
}
|
||||
}
|
||||
|
||||
private async void do_notify_new_email(Gee.Collection<Geary.EmailIdentifier> email_ids) {
|
||||
try {
|
||||
Gee.List<Geary.Email>? list = yield inbox_folder.list_email_by_sparse_id_async(email_ids,
|
||||
NotificationBubble.REQUIRED_FIELDS | Geary.Email.Field.FLAGS, Geary.Folder.ListFlags.NONE,
|
||||
|
|
@ -446,38 +460,57 @@ public class GearyController {
|
|||
return;
|
||||
}
|
||||
|
||||
int unread = 0;
|
||||
Geary.Email? last_unread = null;
|
||||
foreach (Geary.Email email in list) {
|
||||
if (email.email_flags.is_unread()) {
|
||||
unread++;
|
||||
last_unread = email;
|
||||
// notify via new messages indicator (i.e. libindicate, libmessagingmenu when available)
|
||||
new_messages_indicator.new_message(email.id);
|
||||
}
|
||||
}
|
||||
|
||||
debug("do_notify_new_email: %d messages listed, %d unread", list.size, unread);
|
||||
debug("do_notify_new_email: %d messages listed, %d unread", list.size, new_messages_indicator.count);
|
||||
|
||||
// notify via notification bubble (i.e. libnotify)
|
||||
NotificationBubble notification = new NotificationBubble();
|
||||
notification.invoked.connect(on_notification_bubble_invoked);
|
||||
if (unread == 1 && last_unread != null)
|
||||
if (new_messages_indicator.count == 1 && last_unread != null)
|
||||
yield notification.notify_one_message_async(last_unread, cancellable_inbox);
|
||||
else if (unread > 0)
|
||||
notification.notify_new_mail(unread);
|
||||
else if (new_messages_indicator.count > 0)
|
||||
notification.notify_new_mail(new_messages_indicator.count);
|
||||
} catch (Error err) {
|
||||
debug("Unable to notify of new email: %s", err.message);
|
||||
}
|
||||
}
|
||||
|
||||
private void on_notification_bubble_invoked(Geary.Email? email) {
|
||||
if(inbox_folder != null) {
|
||||
if (email == null || inbox_folder == null)
|
||||
return;
|
||||
|
||||
main_window.folder_list.select_path(inbox_folder.get_path());
|
||||
Geary.Conversation? conversation = current_conversations.get_conversation_for_email(email.id);
|
||||
if (conversation != null)
|
||||
main_window.message_list_view.select_conversation(conversation);
|
||||
}
|
||||
|
||||
private void on_indicator_activated_application(uint32 timestamp) {
|
||||
main_window.present_with_time(timestamp);
|
||||
}
|
||||
|
||||
private void on_indicator_activated_composer(uint32 timestamp) {
|
||||
main_window.present_with_time(timestamp);
|
||||
on_new_message();
|
||||
}
|
||||
|
||||
private void on_indicator_activated_inbox(uint32 timestamp) {
|
||||
main_window.present_with_time(timestamp);
|
||||
|
||||
// reset new messages
|
||||
new_messages_indicator.clear_new_messages();
|
||||
|
||||
// attempt to select Inbox
|
||||
if (inbox_folder != null)
|
||||
main_window.folder_list.select_path(inbox_folder.get_path());
|
||||
if(email != null) {
|
||||
Geary.Conversation? conversation = current_conversations.get_conversation_for_email(email.id);
|
||||
if(conversation != null) {
|
||||
main_window.message_list_view.select_conversation(conversation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void on_conversation_appended(Geary.Conversation conversation,
|
||||
|
|
@ -631,10 +664,14 @@ public class GearyController {
|
|||
if (folder.get_special_folder_type() == Geary.SpecialFolderType.INBOX && inbox_folder == null) {
|
||||
inbox_folder = folder;
|
||||
inbox_folder.email_locally_appended.connect(on_inbox_new_email);
|
||||
inbox_folder.email_flags_changed.connect(on_inbox_email_flags_changed);
|
||||
|
||||
// select the inbox and get the show started
|
||||
main_window.folder_list.select_path(folder.get_path());
|
||||
inbox_folder.open_async.begin(false, cancellable_inbox);
|
||||
|
||||
// reset new messages indicator
|
||||
new_messages_indicator.clear_new_messages();
|
||||
}
|
||||
|
||||
folder.special_folder_type_changed.connect(on_special_folder_type_changed);
|
||||
|
|
|
|||
68
src/client/notification/libindicate.vala
Normal file
68
src/client/notification/libindicate.vala
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/* Copyright 2011-2012 Yorba Foundation
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
public class Libindicate : NewMessagesIndicator {
|
||||
#if HAVE_LIBINDICATE
|
||||
private Indicate.Server indicator;
|
||||
private Indicate.Indicator compose;
|
||||
private Indicate.Indicator inbox;
|
||||
|
||||
public Libindicate() {
|
||||
debug("Using libindicate for messaging menu support");
|
||||
|
||||
indicator = Indicate.Server.ref_default();
|
||||
indicator.set_type("message.email");
|
||||
|
||||
// Find the desktop file this app instance is using (running from build dir vs. install dir)
|
||||
File desktop_file = GearyApplication.instance.get_resource_directory().get_child("geary.desktop");
|
||||
if (!desktop_file.query_exists())
|
||||
desktop_file = File.new_for_path("/usr/share/applications/geary.desktop");
|
||||
|
||||
indicator.set_desktop_file(desktop_file.get_path());
|
||||
indicator.server_display.connect(on_display_server);
|
||||
|
||||
// Create "Compose Message" option and always display it
|
||||
compose = new Indicate.Indicator.with_server(indicator);
|
||||
compose.set_property_variant("name", _("Compose Message"));
|
||||
compose.user_display.connect(on_activate_composer);
|
||||
compose.show();
|
||||
|
||||
// Create "New Messages" option which is only displayed if new messages are available
|
||||
inbox = new Indicate.Indicator.with_server(indicator);
|
||||
inbox.set_property_variant("name", _("New Messages"));
|
||||
inbox.user_display.connect(on_activate_inbox);
|
||||
|
||||
notify["count"].connect(on_new_messages_changed);
|
||||
|
||||
indicator.show();
|
||||
}
|
||||
|
||||
private void on_new_messages_changed() {
|
||||
if (count > 0) {
|
||||
// count is in fact a string property
|
||||
inbox.set_property_variant("count", count.to_string());
|
||||
inbox.set_property_bool("draw-attention", true);
|
||||
|
||||
inbox.show();
|
||||
} else {
|
||||
inbox.hide();
|
||||
}
|
||||
}
|
||||
|
||||
private void on_display_server(uint timestamp) {
|
||||
application_activated(timestamp);
|
||||
}
|
||||
|
||||
private void on_activate_composer(uint timestamp) {
|
||||
composer_activated(timestamp);
|
||||
}
|
||||
|
||||
private void on_activate_inbox(uint timestamp) {
|
||||
inbox_activated(timestamp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
58
src/client/notification/new-messages-indicator.vala
Normal file
58
src/client/notification/new-messages-indicator.vala
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/* Copyright 2012 Yorba Foundation
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
// This is coded this way to allow for libindicate and libmessagingmenu to coexist in code (if not
|
||||
// compiled at same time) and minimize the exposure of differences to the rest of the application.
|
||||
// Subclasses should trap the "notify::count" signal and use that to perform whatever magic
|
||||
// they need for their implementation.
|
||||
|
||||
public abstract class NewMessagesIndicator : Object {
|
||||
public int count { get; private set; default = 0; }
|
||||
|
||||
private Gee.HashSet<Geary.EmailIdentifier> new_ids = new Gee.HashSet<Geary.EmailIdentifier>(
|
||||
Geary.Hashable.hash_func, Geary.Equalable.equal_func);
|
||||
|
||||
public signal void application_activated(uint32 timestamp);
|
||||
|
||||
public signal void inbox_activated(uint32 timestamp);
|
||||
|
||||
public signal void composer_activated(uint32 timestamp);
|
||||
|
||||
protected NewMessagesIndicator() {
|
||||
}
|
||||
|
||||
public void new_message(Geary.EmailIdentifier email_id) {
|
||||
new_ids.add(email_id);
|
||||
update_count();
|
||||
}
|
||||
|
||||
public void not_new_message(Geary.EmailIdentifier email_id) {
|
||||
new_ids.remove(email_id);
|
||||
update_count();
|
||||
}
|
||||
|
||||
public void clear_new_messages() {
|
||||
new_ids.clear();
|
||||
update_count();
|
||||
}
|
||||
|
||||
private void update_count() {
|
||||
// Documentation for "notify" signal seems to suggest that it's possible for the signal to
|
||||
// fire even if the value of the property doesn't change. Since this signal can trigger
|
||||
// big events, want to avoid firing it unless necessary
|
||||
if (count != new_ids.size)
|
||||
count = new_ids.size;
|
||||
}
|
||||
|
||||
public static NewMessagesIndicator create() {
|
||||
#if HAVE_LIBINDICATE
|
||||
return new Libindicate();
|
||||
#else
|
||||
return new NullIndicator();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ public class NotificationBubble : GLib.Object {
|
|||
invoked(email);
|
||||
GearyApplication.instance.activate(new string[0]);
|
||||
}
|
||||
|
||||
|
||||
public void notify_new_mail(int count) throws GLib.Error {
|
||||
// don't pass email if invoked
|
||||
email = null;
|
||||
|
|
@ -113,7 +113,6 @@ public class NotificationBubble : GLib.Object {
|
|||
notification.set_hint_string("sound-name", sound);
|
||||
else
|
||||
play_sound(sound);
|
||||
|
||||
}
|
||||
|
||||
public static void play_sound(string sound) {
|
||||
14
src/client/notification/null-indicator.vala
Normal file
14
src/client/notification/null-indicator.vala
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/* Copyright 2012 Yorba Foundation
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
// Do-nothing NewMessagesIndicator, used on non-Ubuntu compiles.
|
||||
|
||||
public class NullIndicator : NewMessagesIndicator {
|
||||
public NullIndicator() {
|
||||
debug("No messaging menu support in this build");
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue