Compare commits

...

17 Commits

Author SHA1 Message Date
Jasper St. Pierre
50395cded8 preview 2014-06-13 14:23:24 -04:00
Jasper St. Pierre
e8ae8f75a0 dateMenu: Fix style 2014-06-13 13:24:10 -04:00
Jasper St. Pierre
2b93bcf921 kill tray 2 2014-06-13 12:29:27 -04:00
Jasper St. Pierre
a80b8f7791 kill tray 2014-06-13 12:21:39 -04:00
Jasper St. Pierre
62c6563a3a always expanded 2014-06-13 12:21:39 -04:00
Jasper St. Pierre
c22068d288 layout: Remove the tray pressure barrier
Since we don't have a tray at the bottom of the screen anymore, it isn't
needed for triggering.
2014-06-13 12:21:36 -04:00
Jasper St. Pierre
d519a0a181 messageTray: Remove support for transient notifications
Transient notifications have used for lots of different "system status"
notifications, like network, low power, low disk space, etc. However, a
majority of these notifications should really also be persistent
instead of going away after they appear.

Users have reported getting confused after seeing a notification appear
up in the corner of their eye, and then have no record of what it was
since the tray was empty.

To simplify the code, set the users more at ease, and also make things
like low power and low disk space more noticeable and urgent after they
go away.

Applications can and should explicitly close any notification it wants
to when state changes, so these notifications shouldn't linger if the
user e.g. plugs in his power cable, or clears up some disk space.
2014-06-13 10:30:34 -04:00
Jasper St. Pierre
ef1ab043a3 messageTray: Add notification close button inside notification
And remove the old close button outside it.
2014-06-12 13:58:16 -04:00
Jasper St. Pierre
fa350bf41e messageTray: Implement new notification designs
Rather than use an StTable, a custom ShellGenericContainer, and plenty
of hacky style classes, replace them all with standard BoxLayouts and
Bins.

Remove the customContent parameter in favor of subclasses setting the
child of this._bodyBin instead.

With this comes a whole new notification implementation to implement
the new notification designs.

We lose a few of the fancy features like showing the first part of
the body, ellipsized, next the banner when it will fit, and some other
layout logic. But since the design of notifications is changing
substantially anyways, I don't feel too bad...
2014-06-12 13:58:15 -04:00
Jasper St. Pierre
ae74dbd1bb messageTray: Glue the notification to the bottom of the screen, always
We'll animate notifications popping up with another system soon enough,
instead. The idea here is that instead of carefully animating the Y
position of the notificationWidget when a notification updates, we
simply animate the height of the new actor inside the notification.
This will fix some of the awkward updates where instead of the
notification content expanding, we see the buttons or action area
pushed off the edge of the screen...

Animations that happen as a result of adding something new to the
notification or expanding it should be done by tweeing the new actors
in inside the notification.
2014-06-12 13:58:15 -04:00
Jasper St. Pierre
afa5a871b3 messageTray: Remove addBody as a public API
As it's unused.
2014-06-12 13:58:15 -04:00
Jasper St. Pierre
e13c0ca9e8 messageTray: Remove support for notifications with images
This sufficiently complicates the code, and won't fit in the
new design.
2014-06-12 13:58:15 -04:00
Jasper St. Pierre
f29d1beb3e messageTray: Remove support for resident notifications
Now the only resident notification is a chat notification. The convenient
thing about this special-case behavior is that there's already special-case
code for it and the shell, and we always know that a chat notification will
always be 1:1 with its chat source.
2014-06-12 13:58:14 -04:00
Jasper St. Pierre
751a1b5bbe notificationDaemon: Remove support for resident notifications
They're not really an API that has caught on, and not really one
we want to support, either.
2014-06-12 13:58:14 -04:00
Jasper St. Pierre
00a32f53f5 notificationDaemon: Remove the special-case hack for system tray icons
Nothing in the system actually has a standard system tray icon anymore,
so this hack isn't necessary.
2014-06-12 13:58:14 -04:00
Jasper St. Pierre
94688d354f telepathyClient: Remove all the fancy features
This can be done with another app, like Empathy or Chat.
2014-06-12 13:58:14 -04:00
Jasper St. Pierre
7f17acd0ea autorunManager: Remove the resident "Removable Devices" notification
Users aren't usually the best at obeying the rules, and systems can
deal with hotplug without ejecting first.

https://bugzilla.gnome.org/show_bug.cgi?id=719857
2014-06-12 13:58:13 -04:00
14 changed files with 318 additions and 3100 deletions

View File

@ -414,10 +414,7 @@ StScrollBar StButton#vhandle:active {
/* Buttons */
.candidate-page-button,
.notification-button,
.notification-icon-button,
.hotplug-notification-item,
.hotplug-resident-eject-button,
.modal-dialog-button,
.app-view-control {
border: 1px solid #8b8b8b;
@ -431,17 +428,12 @@ StScrollBar StButton#vhandle:active {
}
.candidate-page-button:hover,
.notification-button:hover,
.notification-icon-button:hover,
.hotplug-notification-item:hover,
.hotplug-resident-eject-button:hover,
.modal-dialog-button:hover {
background-gradient-start: rgba(255, 255, 255, 0.3);
background-gradient-end: rgba(255, 255, 255, 0.1);
}
.notification-button:focus,
.notification-icon-button:focus,
.hotplug-notification-item:focus,
.modal-dialog-button:focus,
.app-view-control:focus {
@ -455,10 +447,7 @@ StScrollBar StButton#vhandle:active {
.candidate-page-button:active,
.candidate-page-button:pressed,
.notification-button:active,
.notification-icon-button:active,
.hotplug-notification-item:active,
.hotplug-resident-eject-button:active,
.modal-dialog-button:active,
.modal-dialog-button:pressed,
.app-view-control:checked {
@ -467,8 +456,6 @@ StScrollBar StButton#vhandle:active {
}
.candidate-page-button:insensitive,
.notification-button:insensitive,
.notification-icon-button:insensitive,
.modal-dialog-button:insensitive {
border-color: #666666;
color: #9f9f9f;
@ -480,7 +467,6 @@ StScrollBar StButton#vhandle:active {
#searchEntry,
.modal-dialog-button,
.notification-button,
.hotplug-notification-item,
.app-view-controls,
#screenShieldNotifications {
@ -1511,99 +1497,65 @@ StScrollBar StButton#vhandle:active {
height: 72px;
}
.message-tray-summary {
height: 72px;
}
.message-tray-menu-button StIcon {
padding: 0 20px;
color: #aaaaaa;
icon-size: 24px;
}
.message-tray-menu-button:hover StIcon,
.message-tray-menu-button:active StIcon,
.message-tray-menu-button:focus StIcon {
color: #eeeeee;
}
.url-highlighter {
link-color: #ccccff;
}
.no-messages-label {
color: #999999;
}
.notification {
border-radius: 10px 10px 0px 0px;
background: rgba(0,0,0,0.9);
padding: 8px 8px 4px 8px;
spacing-rows: 4px;
spacing-columns: 10px;
}
.notification, #notification-container {
font-size: 11pt;
width: 34em;
}
.notification.multi-line-notification {
padding-bottom: 8px;
.notification-main-button,
.notification-button {
background: rgba(0,0,0,0.9);
}
.notification-unexpanded {
/* We want to force the actor at a specific size, irrespective
of its minimum and preferred size, so we override both */
min-height: 36px;
height: 36px;
.notification-main-button {
border-radius: 10px 10px 0px 0px;
}
/* We use row-span = 2 for the image cell, which prevents its height preferences to be
taken into account during allocation, so its height ends up being limited by the height
of the content in the other rows. To avoid showing a stretched image, we set the minimum
height of the table to be ICON_SIZE + IMAGE_SIZE + spacing-rows = 24 + 125 + 10 = 159 */
.notification-with-image {
min-height: 159px;
.notification-main-content {
padding: 8px;
spacing: 8px;
}
.summary-boxpointer {
-arrow-border-radius: 15px;
-arrow-background-color: rgba(0,0,0,0.9);
-arrow-base: 36px;
-arrow-rise: 18px;
color: white;
-boxpointer-gap: 4px;
.notification-close-button {
padding: 8px;
border-radius: 4px;
}
.summary-boxpointer .notification {
border-radius: 9px;
background: rgba(0,0,0,0) !important;
padding-bottom: 12px;
.notification-action-area {
padding: 8px;
}
.summary-boxpointer #summary-right-click-menu {
padding-top: 12px;
padding-bottom: 12px;
.notification-action-area,
.notification-button {
border-top: 1px solid #666;
}
.summary-notification-stack-scrollview {
max-height: 18em;
padding-top: 8px;
padding-bottom: 8px;
.notification-button {
padding: 8px 0px;
border-right: 1px solid #666;
}
.summary-notification-stack-scrollview:ltr {
padding-right: 8px;
.notification-main-button:hover,
.notification-button:hover,
.notification-close-button:hover {
background: rgba(100,100,100,0.9);
}
.summary-notification-stack-scrollview:rtl {
padding-left: 8px;
.notification-main-button:active,
.notification-button:active {
background: rgba(255,255,255,0.1);
}
.notification-scrollview {
max-height: 10em;
-st-vfade-offset: 24px;
.notification-button:last-child {
border-right-width: 0px;
}
.notification-title-box {
spacing: 8px;
}
.notification-scrollview:ltr > StScrollBar {
@ -1614,37 +1566,9 @@ StScrollBar StButton#vhandle:active {
padding-right: 6px;
}
.notification-body {
spacing: 5px;
}
.notification-actions {
padding-top: 18px;
spacing: 10px;
}
.notification-button {
-st-natural-width: 140px;
padding: 4px 4px 5px;
}
.notification-button:focus {
-st-natural-width: 138px;
padding: 3px 4px 4px;
}
.notification-icon-button {
border-radius: 5px;
padding: 5px;
}
.notification-icon-button:focus {
padding: 4px;
}
.notification-icon-button > StIcon {
icon-size: 16px;
padding: 8px;
.notification-scrollview {
max-height: 10em;
-st-vfade-offset: 24px;
}
.secondary-icon {
@ -1669,45 +1593,6 @@ StScrollBar StButton#vhandle:active {
padding: 2px 5px;
}
.hotplug-resident-box {
spacing: 8px;
}
.hotplug-resident-mount {
spacing: 8px;
border-radius: 4px;
color: #ccc;
}
.hotplug-resident-mount:hover {
background-gradient-direction: horizontal;
background-gradient-start: rgba(255, 255, 255, 0.1);
background-gradient-end: rgba(255, 255, 255, 0);
color: #fff;
}
.hotplug-resident-mount-label {
color: inherit;
padding-left: 6px;
}
.hotplug-resident-mount-icon {
icon-size: 24px;
padding-left: 6px;
}
.hotplug-resident-eject-icon {
icon-size: 16px;
}
.hotplug-resident-eject-button {
padding: 7px;
border-radius: 5px;
color: #ccc;
}
.chat-log-message {
color: #888888;
}
@ -1747,7 +1632,11 @@ StScrollBar StButton#vhandle:active {
padding-right: 4px;
}
.chat-notification-scrollview{
.chat-notification-body-box {
spacing: 5px;
}
.chat-notification-scrollview {
max-height: 22em;
}
@ -2666,8 +2555,7 @@ StScrollBar StButton#vhandle:active {
padding-bottom: 0px;
}
#screenShieldNotifications .notification-button,
#screenShieldNotifications .notification-icon-button {
#screenShieldNotifications .notification-button {
border: 1px rgba(255,255,255,0.5);
}
@ -2703,3 +2591,7 @@ StScrollBar StButton#vhandle:active {
-boxpointer-gap: 4px;
-arrow-rise: 0px;
}
.top-bar-notification-preview {
font-weight: normal;
}

View File

@ -170,17 +170,6 @@ const AutorunManager = new Lang.Class({
this._transDispatcher = new AutorunTransientDispatcher(this);
},
_ensureResidentSource: function() {
if (this._residentSource)
return;
this._residentSource = new AutorunResidentSource(this);
let destroyId = this._residentSource.connect('destroy', Lang.bind(this, function() {
this._residentSource.disconnect(destroyId);
this._residentSource = null;
}));
},
enable: function() {
this._scanMounts();
@ -189,17 +178,12 @@ const AutorunManager = new Lang.Class({
},
disable: function() {
if (this._residentSource)
this._residentSource.destroy();
this._volumeMonitor.disconnect(this._mountAddedId);
this._volumeMonitor.disconnect(this._mountRemovedId);
},
_processMount: function(mount, hotplug) {
let discoverer = new ContentTypeDiscoverer(Lang.bind(this, function(mount, apps, contentTypes) {
this._ensureResidentSource();
this._residentSource.addMount(mount, apps);
if (hotplug)
this._transDispatcher.addMount(mount, apps, contentTypes);
}));
@ -224,8 +208,6 @@ const AutorunManager = new Lang.Class({
_onMountRemoved: function(monitor, mount) {
this._transDispatcher.removeMount(mount);
if (this._residentSource)
this._residentSource.removeMount(mount);
},
ejectMount: function(mount) {
@ -288,153 +270,6 @@ const AutorunManager = new Lang.Class({
},
});
const AutorunResidentSource = new Lang.Class({
Name: 'AutorunResidentSource',
Extends: MessageTray.Source,
_init: function(manager) {
this.parent(_("Removable Devices"), 'media-removable');
this.resident = true;
this._mounts = [];
this._manager = manager;
this._notification = new AutorunResidentNotification(this._manager, this);
},
_createPolicy: function() {
return new MessageTray.NotificationPolicy({ showInLockScreen: false });
},
buildRightClickMenu: function() {
return null;
},
addMount: function(mount, apps) {
if (!shouldAutorunMount(mount, false))
return;
let filtered = this._mounts.filter(function (element) {
return (element.mount == mount);
});
if (filtered.length != 0)
return;
let element = { mount: mount, apps: apps };
this._mounts.push(element);
this._redisplay();
},
removeMount: function(mount) {
this._mounts =
this._mounts.filter(function (element) {
return (element.mount != mount);
});
this._redisplay();
},
_redisplay: function() {
if (this._mounts.length == 0) {
this._notification.destroy();
this.destroy();
return;
}
this._notification.updateForMounts(this._mounts);
// add ourselves as a source, and push the notification
if (!Main.messageTray.contains(this)) {
Main.messageTray.add(this);
this.pushNotification(this._notification);
}
}
});
const AutorunResidentNotification = new Lang.Class({
Name: 'AutorunResidentNotification',
Extends: MessageTray.Notification,
_init: function(manager, source) {
this.parent(source, source.title, null, { customContent: true });
// set the notification as resident
this.setResident(true);
this._layout = new St.BoxLayout ({ style_class: 'hotplug-resident-box',
vertical: true });
this._manager = manager;
this.addActor(this._layout,
{ x_expand: true,
x_fill: true });
},
updateForMounts: function(mounts) {
// remove all the layout content
this._layout.destroy_all_children();
for (let idx = 0; idx < mounts.length; idx++) {
let element = mounts[idx];
let actor = this._itemForMount(element.mount, element.apps);
this._layout.add(actor, { x_fill: true,
expand: true });
}
},
_itemForMount: function(mount, apps) {
let item = new St.BoxLayout();
// prepare the mount button content
let mountLayout = new St.BoxLayout();
let mountIcon = new St.Icon({ gicon: mount.get_icon(),
style_class: 'hotplug-resident-mount-icon' });
mountLayout.add_actor(mountIcon);
let labelBin = new St.Bin({ y_align: St.Align.MIDDLE });
let mountLabel =
new St.Label({ text: mount.get_name(),
style_class: 'hotplug-resident-mount-label',
track_hover: true,
reactive: true });
labelBin.add_actor(mountLabel);
mountLayout.add_actor(labelBin);
let mountButton = new St.Button({ child: mountLayout,
x_align: St.Align.START,
x_fill: true,
style_class: 'hotplug-resident-mount',
button_mask: St.ButtonMask.ONE });
item.add(mountButton, { x_align: St.Align.START,
expand: true });
let ejectIcon =
new St.Icon({ icon_name: 'media-eject-symbolic',
style_class: 'hotplug-resident-eject-icon' });
let ejectButton =
new St.Button({ style_class: 'hotplug-resident-eject-button',
button_mask: St.ButtonMask.ONE,
child: ejectIcon });
item.add(ejectButton, { x_align: St.Align.END });
// now connect signals
mountButton.connect('clicked', Lang.bind(this, function(actor, event) {
startAppForMount(apps[0], mount);
}));
ejectButton.connect('clicked', Lang.bind(this, function() {
this._manager.ejectMount(mount);
}));
return item;
},
});
const AutorunTransientDispatcher = new Lang.Class({
Name: 'AutorunTransientDispatcher',
@ -559,12 +394,12 @@ const AutorunTransientNotification = new Lang.Class({
Extends: MessageTray.Notification,
_init: function(manager, source) {
this.parent(source, source.title, null, { customContent: true });
this.parent(source, source.title);
this._manager = manager;
this._box = new St.BoxLayout({ style_class: 'hotplug-transient-box',
vertical: true });
this.addActor(this._box);
this._bodyBin.child = this._box;
this._mount = source.mount;
@ -581,7 +416,6 @@ const AutorunTransientNotification = new Lang.Class({
// set the notification to transient and urgent, so that it
// expands out
this.setTransient(true);
this.setUrgency(MessageTray.Urgency.CRITICAL);
},

View File

@ -102,15 +102,6 @@ const TelepathyClient = new Lang.Class({
this._tpClient.set_handle_channels_func(
Lang.bind(this, this._handleChannels));
// Watch subscription requests and connection errors
this._subscriptionSource = null;
this._accountSource = null;
// Workaround for gjs not supporting GPtrArray in signals.
// See BGO bug #653941 for context.
this._tpClient.set_contact_list_changed_func(
Lang.bind(this, this._contactListChanged));
// Allow other clients (such as Empathy) to pre-empt our channels if
// needed
this._tpClient.set_delegated_channels_callback(
@ -124,17 +115,12 @@ const TelepathyClient = new Lang.Class({
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
}
this._accountManagerValidityChangedId = this._accountManager.connect('account-validity-changed',
Lang.bind(this, this._accountValidityChanged));
if (!this._accountManager.is_prepared(Tp.AccountManager.get_feature_quark_core()))
this._accountManager.prepare_async(null, Lang.bind(this, this._accountManagerPrepared));
},
disable: function() {
this._tpClient.unregister();
this._accountManager.disconnect(this._accountManagerValidityChangedId);
this._accountManagerValidityChangedId = 0;
},
_observeChannels: function(observer, account, conn, channels,
@ -219,33 +205,6 @@ const TelepathyClient = new Lang.Class({
}
},
_displayRoomInvitation: function(conn, channel, dispatchOp, context) {
// We can only approve the rooms if we have been invited to it
let selfContact = channel.group_get_self_contact();
if (selfContact == null) {
context.fail(new Tp.Error({ code: Tp.Error.INVALID_ARGUMENT,
message: 'Not invited to the room' }));
return;
}
let [invited, inviter, reason, msg] = channel.group_get_local_pending_contact_info(selfContact);
if (!invited) {
context.fail(new Tp.Error({ code: Tp.Error.INVALID_ARGUMENT,
message: 'Not invited to the room' }));
return;
}
// FIXME: We don't have a 'chat room' icon (bgo #653737) use
// system-users for now as Empathy does.
let source = new ApproverSource(dispatchOp, _("Invitation"),
Gio.icon_new_for_string('system-users'));
Main.messageTray.add(source);
let notif = new RoomInviteNotification(source, dispatchOp, channel, inviter);
source.notify(notif);
context.accept();
},
_approveChannels: function(approver, account, conn, channels,
dispatchOp, context) {
let channel = channels[0];
@ -259,10 +218,6 @@ const TelepathyClient = new Lang.Class({
if (chanType == Tp.IFACE_CHANNEL_TYPE_TEXT)
this._approveTextChannel(account, conn, channel, dispatchOp, context);
else if (chanType == Tp.IFACE_CHANNEL_TYPE_CALL)
this._approveCall(account, conn, channel, dispatchOp, context);
else if (chanType == Tp.IFACE_CHANNEL_TYPE_FILE_TRANSFER)
this._approveFileTransfer(account, conn, channel, dispatchOp, context);
else
context.fail(new Tp.Error({ code: Tp.Error.INVALID_ARGUMENT,
message: 'Unsupported channel type' }));
@ -283,45 +238,9 @@ const TelepathyClient = new Lang.Class({
}}));
context.accept();
} else {
this._displayRoomInvitation(conn, channel, dispatchOp, context);
}
},
_approveCall: function(account, conn, channel, dispatchOp, context) {
let isVideo = false;
let props = channel.borrow_immutable_properties();
if (props[Tp.PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO])
isVideo = true;
// We got the TpContact
let source = new ApproverSource(dispatchOp, _("Call"), isVideo ?
Gio.icon_new_for_string('camera-web') :
Gio.icon_new_for_string('audio-input-microphone'));
Main.messageTray.add(source);
let notif = new AudioVideoNotification(source, dispatchOp, channel,
channel.get_target_contact(), isVideo);
source.notify(notif);
context.accept();
},
_approveFileTransfer: function(account, conn, channel, dispatchOp, context) {
// Use the icon of the file being transferred
let gicon = Gio.content_type_get_icon(channel.get_mime_type());
// We got the TpContact
let source = new ApproverSource(dispatchOp, _("File Transfer"), gicon);
Main.messageTray.add(source);
let notif = new FileTransferNotification(source, dispatchOp, channel,
channel.get_target_contact());
source.notify(notif);
context.accept();
},
_delegatedChannelsCb: function(client, channels) {
// Nothing to do as we don't make a distinction between observed and
// handled channels.
@ -329,105 +248,7 @@ const TelepathyClient = new Lang.Class({
_accountManagerPrepared: function(am, result) {
am.prepare_finish(result);
let accounts = am.get_valid_accounts();
for (let i = 0; i < accounts.length; i++) {
this._accountValidityChanged(am, accounts[i], true);
}
},
_accountValidityChanged: function(am, account, valid) {
if (!valid)
return;
// It would be better to connect to "status-changed" but we cannot.
// See discussion in https://bugzilla.gnome.org/show_bug.cgi?id=654159
account.connect("notify::connection-status",
Lang.bind(this, this._accountConnectionStatusNotifyCb));
account.connect('notify::connection',
Lang.bind(this, this._connectionChanged));
this._connectionChanged(account);
},
_connectionChanged: function(account) {
let conn = account.get_connection();
if (conn == null)
return;
this._tpClient.grab_contact_list_changed(conn);
if (conn.get_contact_list_state() == Tp.ContactListState.SUCCESS) {
this._contactListChanged(conn, conn.dup_contact_list(), []);
}
},
_contactListChanged: function(conn, added, removed) {
for (let i = 0; i < added.length; i++) {
let contact = added[i];
contact.connect('subscription-states-changed',
Lang.bind(this, this._subscriptionStateChanged));
this._subscriptionStateChanged(contact);
}
},
_subscriptionStateChanged: function(contact) {
if (contact.get_publish_state() != Tp.SubscriptionState.ASK)
return;
/* Implicitly accept publish requests if contact is already subscribed */
if (contact.get_subscribe_state() == Tp.SubscriptionState.YES ||
contact.get_subscribe_state() == Tp.SubscriptionState.ASK) {
contact.authorize_publication_async(function(src, result) {
src.authorize_publication_finish(result)});
return;
}
/* Display notification to ask user to accept/reject request */
let source = this._ensureAppSource();
let notif = new SubscriptionRequestNotification(source, contact);
source.notify(notif);
},
_accountConnectionStatusNotifyCb: function(account) {
let connectionError = account.connection_error;
if (account.connection_status != Tp.ConnectionStatus.DISCONNECTED ||
connectionError == Tp.error_get_dbus_name(Tp.Error.CANCELLED)) {
return;
}
let notif = this._accountNotifications[account.get_object_path()];
if (notif)
return;
/* Display notification that account failed to connect */
let source = this._ensureAppSource();
notif = new AccountNotification(source, account, connectionError);
this._accountNotifications[account.get_object_path()] = notif;
notif.connect('destroy', Lang.bind(this, function() {
delete this._accountNotifications[account.get_object_path()];
}));
source.notify(notif);
},
_ensureAppSource: function() {
if (this._appSource == null) {
this._appSource = new MessageTray.Source(_("Chat"), 'empathy');
this._appSource.policy = new MessageTray.NotificationApplicationPolicy('empathy');
Main.messageTray.add(this._appSource);
this._appSource.connect('destroy', Lang.bind(this, function () {
this._appSource = null;
}));
}
return this._appSource;
}
});
const ChatSource = new Lang.Class({
@ -545,7 +366,7 @@ const ChatSource = new Lang.Class({
_updateAvatarIcon: function() {
this.iconUpdated();
this._notification.update(this._notification.title, null, { customContent: true });
this._notification.update(this._notification.title);
},
open: function() {
@ -737,7 +558,7 @@ const ChatSource = new Lang.Class({
title = GLib.markup_escape_text(this.title, -1);
this._notification.update(this._notification.title, null, { customContent: true, secondaryGIcon: this.getSecondaryIcon() });
this._notification.update(this._notification.title, null, { secondaryGIcon: this.getSecondaryIcon() });
if (message)
msg += ' <i>(' + GLib.markup_escape_text(message, -1) + ')</i>';
@ -764,8 +585,7 @@ const ChatNotification = new Lang.Class({
Extends: MessageTray.Notification,
_init: function(source) {
this.parent(source, source.title, null, { customContent: true, secondaryGIcon: source.getSecondaryIcon() });
this.setResident(true);
this.parent(source, source.title, null, { secondaryGIcon: source.getSecondaryIcon() });
this._responseEntry = new St.Entry({ style_class: 'chat-response',
can_focus: true });
@ -781,15 +601,17 @@ const ChatNotification = new Lang.Class({
this.emit('unfocused');
}));
this._createScrollArea();
this._lastGroup = null;
this._bodyBox = new St.BoxLayout({ style_class: 'chat-notification-body-box' });
this._bodyBin.child = this._bodyBox;
// Keep track of the bottom position for the current adjustment and
// force a scroll to the bottom if things change while we were at the
// bottom
this._oldMaxScrollValue = this._scrollArea.vscroll.adjustment.value;
this._scrollArea.add_style_class_name('chat-notification-scrollview');
this._scrollArea.vscroll.adjustment.connect('changed', Lang.bind(this, function(adjustment) {
this._oldMaxScrollValue = this._bodyScrollArea.vscroll.adjustment.value;
this._bodyScrollArea.add_style_class_name('chat-notification-scrollview');
this._bodyScrollArea.vscroll.adjustment.connect('changed', Lang.bind(this, function(adjustment) {
if (adjustment.value == this._oldMaxScrollValue)
this.scrollTo(St.Side.BOTTOM);
this._oldMaxScrollValue = Math.max(adjustment.lower, adjustment.upper - adjustment.page_size);
@ -826,8 +648,7 @@ const ChatNotification = new Lang.Class({
}
if (message.direction == NotificationDirection.RECEIVED) {
this.update(this.source.title, messageBody, { customContent: true,
bannerMarkup: true });
this.update(this.source.title, messageBody, { bannerMarkup: true });
}
let group = (message.direction == NotificationDirection.RECEIVED ?
@ -864,7 +685,7 @@ const ChatNotification = new Lang.Class({
expired[i].actor.destroy();
}
let groups = this._contentArea.get_children();
let groups = this._bodyBox.get_children();
for (let i = 0; i < groups.length; i++) {
let group = groups[i];
if (group.get_n_children() == 0)
@ -896,9 +717,9 @@ const ChatNotification = new Lang.Class({
if (this._timestampTimeoutId)
Mainloop.source_remove(this._timestampTimeoutId);
let highlighter = new MessageTray.URLHighlighter(props.body,
true, // line wrap?
true); // allow markup?
let highlighter = new MessageTray.URLHighlighter();
highlighter.actor.clutter_text.line_wrap = true;
highlighter.setMarkup(props.body, true);
let body = highlighter.actor;
@ -910,14 +731,12 @@ const ChatNotification = new Lang.Class({
if (group != this._lastGroup) {
this._lastGroup = group;
let emptyLine = new St.Label({ style_class: 'chat-empty-line' });
this.addActor(emptyLine);
this._bodyBox.add_child(emptyLine);
}
this._lastMessageBox = new St.BoxLayout({ vertical: false });
this._lastMessageBox.add(body, props.childProps);
this.addActor(this._lastMessageBox);
this.updated();
this._bodyBox.add_child(this._lastMessageBox);
let timestamp = props.timestamp;
this._history.unshift({ actor: body, time: timestamp,
@ -1052,7 +871,7 @@ const ChatNotification = new Lang.Class({
group: 'meta',
styles: ['chat-meta-message'] });
this.update(newAlias, null, { customContent: true });
this.update(newAlias);
this._filterMessages();
},
@ -1105,359 +924,4 @@ const ChatNotification = new Lang.Class({
}
});
const ApproverSource = new Lang.Class({
Name: 'ApproverSource',
Extends: MessageTray.Source,
_init: function(dispatchOp, text, gicon) {
this._gicon = gicon;
this.parent(text);
this._dispatchOp = dispatchOp;
// Destroy the source if the channel dispatch operation is invalidated
// as we can't approve any more.
this._invalidId = dispatchOp.connect('invalidated',
Lang.bind(this, function(domain, code, msg) {
this.destroy();
}));
},
_createPolicy: function() {
return new MessageTray.NotificationApplicationPolicy('empathy');
},
destroy: function() {
if (this._invalidId != 0) {
this._dispatchOp.disconnect(this._invalidId);
this._invalidId = 0;
}
this.parent();
},
getIcon: function() {
return this._gicon;
}
});
const RoomInviteNotification = new Lang.Class({
Name: 'RoomInviteNotification',
Extends: MessageTray.Notification,
_init: function(source, dispatchOp, channel, inviter) {
this.parent(source,
/* translators: argument is a room name like
* room@jabber.org for example. */
_("Invitation to %s").format(channel.get_identifier()),
null,
{ customContent: true });
this.setResident(true);
/* translators: first argument is the name of a contact and the second
* one the name of a room. "Alice is inviting you to join room@jabber.org
* for example. */
this.addBody(_("%s is inviting you to join %s").format(inviter.get_alias(), channel.get_identifier()));
this.addAction(_("Decline"), Lang.bind(this, function() {
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, '', function(src, result) {
src.leave_channels_finish(result);
});
this.destroy();
}));
this.addAction(_("Accept"), Lang.bind(this, function() {
dispatchOp.handle_with_time_async('', global.get_current_time(), function(src, result) {
src.handle_with_time_finish(result);
});
this.destroy();
}));
}
});
// Audio Video
const AudioVideoNotification = new Lang.Class({
Name: 'AudioVideoNotification',
Extends: MessageTray.Notification,
_init: function(source, dispatchOp, channel, contact, isVideo) {
let title = '';
if (isVideo)
/* translators: argument is a contact name like Alice for example. */
title = _("Video call from %s").format(contact.get_alias());
else
/* translators: argument is a contact name like Alice for example. */
title = _("Call from %s").format(contact.get_alias());
this.parent(source, title, null, { customContent: true });
this.setResident(true);
this.setUrgency(MessageTray.Urgency.CRITICAL);
this.addAction(_("Decline"), Lang.bind(this, function() {
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, '', function(src, result) {
src.leave_channels_finish(result);
});
this.destroy();
}));
/* translators: this is a button label (verb), not a noun */
this.addAction(_("Answer"), Lang.bind(this, function() {
dispatchOp.handle_with_time_async('', global.get_current_time(), function(src, result) {
src.handle_with_time_finish(result);
});
this.destroy();
}));
}
});
// File Transfer
const FileTransferNotification = new Lang.Class({
Name: 'FileTransferNotification',
Extends: MessageTray.Notification,
_init: function(source, dispatchOp, channel, contact) {
this.parent(source,
/* To translators: The first parameter is
* the contact's alias and the second one is the
* file name. The string will be something
* like: "Alice is sending you test.ogg"
*/
_("%s is sending you %s").format(contact.get_alias(),
channel.get_filename()),
null,
{ customContent: true });
this.setResident(true);
this.addAction(_("Decline"), Lang.bind(this, function() {
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, '', function(src, result) {
src.leave_channels_finish(result);
});
this.destroy();
}));
this.addAction(_("Accept"), Lang.bind(this, function() {
dispatchOp.handle_with_time_async('', global.get_current_time(), function(src, result) {
src.handle_with_time_finish(result);
});
this.destroy();
}));
}
});
// Subscription request
const SubscriptionRequestNotification = new Lang.Class({
Name: 'SubscriptionRequestNotification',
Extends: MessageTray.Notification,
_init: function(source, contact) {
this.parent(source,
/* To translators: The parameter is the contact's alias */
_("%s would like permission to see when you are online").format(contact.get_alias()),
null, { customContent: true });
this._contact = contact;
this._connection = contact.get_connection();
let layout = new St.BoxLayout({ vertical: false });
// Display avatar
let iconBox = new St.Bin({ style_class: 'avatar-box' });
iconBox._size = 48;
let textureCache = St.TextureCache.get_default();
let file = contact.get_avatar_file();
if (file) {
let uri = file.get_uri();
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
iconBox.child = textureCache.load_uri_async(uri, iconBox._size, iconBox._size, scaleFactor);
}
else {
iconBox.child = new St.Icon({ icon_name: 'avatar-default',
icon_size: iconBox._size });
}
layout.add(iconBox);
// subscription request message
let label = new St.Label({ style_class: 'subscription-message',
text: contact.get_publish_request() });
layout.add(label);
this.addActor(layout);
this.addAction(_("Decline"), Lang.bind(this, function() {
contact.remove_async(function(src, result) {
src.remove_finish(result);
});
}));
this.addAction(_("Accept"), Lang.bind(this, function() {
// Authorize the contact and request to see his status as well
contact.authorize_publication_async(function(src, result) {
src.authorize_publication_finish(result);
});
contact.request_subscription_async('', function(src, result) {
src.request_subscription_finish(result);
});
}));
this._changedId = contact.connect('subscription-states-changed',
Lang.bind(this, this._subscriptionStatesChangedCb));
this._invalidatedId = this._connection.connect('invalidated',
Lang.bind(this, this.destroy));
},
destroy: function() {
if (this._changedId != 0) {
this._contact.disconnect(this._changedId);
this._changedId = 0;
}
if (this._invalidatedId != 0) {
this._connection.disconnect(this._invalidatedId);
this._invalidatedId = 0;
}
this.parent();
},
_subscriptionStatesChangedCb: function(contact, subscribe, publish, msg) {
// Destroy the notification if the subscription request has been
// answered
if (publish != Tp.SubscriptionState.ASK)
this.destroy();
}
});
// Messages from empathy/libempathy/empathy-utils.c
// create_errors_to_message_hash()
/* Translator note: these should be the same messages that are
* used in Empathy, so just copy and paste from there. */
let _connectionErrorMessages = {};
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.NETWORK_ERROR)]
= _("Network error");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.AUTHENTICATION_FAILED)]
= _("Authentication failed");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.ENCRYPTION_ERROR)]
= _("Encryption error");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_NOT_PROVIDED)]
= _("Certificate not provided");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_UNTRUSTED)]
= _("Certificate untrusted");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_EXPIRED)]
= _("Certificate expired");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_NOT_ACTIVATED)]
= _("Certificate not activated");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_HOSTNAME_MISMATCH)]
= _("Certificate hostname mismatch");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_FINGERPRINT_MISMATCH)]
= _("Certificate fingerprint mismatch");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_SELF_SIGNED)]
= _("Certificate self-signed");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CANCELLED)]
= _("Status is set to offline");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.ENCRYPTION_NOT_AVAILABLE)]
= _("Encryption is not available");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_INVALID)]
= _("Certificate is invalid");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_REFUSED)]
= _("Connection has been refused");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_FAILED)]
= _("Connection can't be established");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_LOST)]
= _("Connection has been lost");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.ALREADY_CONNECTED)]
= _("This account is already connected to the server");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_REPLACED)]
= _("Connection has been replaced by a new connection using the same resource");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.REGISTRATION_EXISTS)]
= _("The account already exists on the server");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.SERVICE_BUSY)]
= _("Server is currently too busy to handle the connection");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_REVOKED)]
= _("Certificate has been revoked");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_INSECURE)]
= _("Certificate uses an insecure cipher algorithm or is cryptographically weak");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_LIMIT_EXCEEDED)]
= _("The length of the server certificate, or the depth of the server certificate chain, exceed the limits imposed by the cryptography library");
_connectionErrorMessages['org.freedesktop.DBus.Error.NoReply']
= _("Internal error");
const AccountNotification = new Lang.Class({
Name: 'AccountNotification',
Extends: MessageTray.Notification,
_init: function(source, account, connectionError) {
this.parent(source,
/* translators: argument is the account name, like
* name@jabber.org for example. */
_("Unable to connect to %s").format(account.get_display_name()),
this._getMessage(connectionError));
this._account = account;
this.addAction(_("View account"), Lang.bind(this, function() {
let cmd = 'empathy-accounts --select-account=' +
account.get_path_suffix();
let app_info = Gio.app_info_create_from_commandline(cmd, null, 0);
app_info.launch([], global.create_app_launch_context(0, -1));
}));
this._enabledId = account.connect('notify::enabled',
Lang.bind(this, function() {
if (!account.is_enabled())
this.destroy();
}));
this._invalidatedId = account.connect('invalidated',
Lang.bind(this, this.destroy));
this._connectionStatusId = account.connect('notify::connection-status',
Lang.bind(this, function() {
let status = account.connection_status;
if (status == Tp.ConnectionStatus.CONNECTED) {
this.destroy();
} else if (status == Tp.ConnectionStatus.DISCONNECTED) {
let connectionError = account.connection_error;
if (connectionError == Tp.error_get_dbus_name(Tp.Error.CANCELLED))
this.destroy();
else
this.update(this.title, this._getMessage(connectionError));
}
}));
},
_getMessage: function(connectionError) {
let message;
if (connectionError in _connectionErrorMessages) {
message = _connectionErrorMessages[connectionError];
} else {
message = _("Unknown reason");
}
return message;
},
destroy: function() {
if (this._enabledId != 0) {
this._account.disconnect(this._enabledId);
this._enabledId = 0;
}
if (this._invalidatedId != 0) {
this._account.disconnect(this._invalidatedId);
this._invalidatedId = 0;
}
if (this._connectionStatusId != 0) {
this._account.disconnect(this._connectionStatusId);
this._connectionStatusId = 0;
}
this.parent();
}
});
const Component = TelepathyClient;

View File

@ -18,8 +18,7 @@ const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Calendar = imports.ui.calendar;
function _onVertSepRepaint (area)
{
function _onVertSepRepaint(area) {
let cr = area.get_context();
let themeNode = area.get_theme_node();
let [width, height] = area.get_surface_size();
@ -33,7 +32,7 @@ function _onVertSepRepaint (area)
cr.setLineWidth(stippleWidth);
cr.stroke();
cr.$dispose();
};
}
const DateMenuButton = new Lang.Class({
Name: 'DateMenuButton',

View File

@ -150,7 +150,6 @@ const LayoutManager = new Lang.Class({
this._keyboardIndex = -1;
this._rightPanelBarrier = null;
this._trayBarrier = null;
this._inOverview = false;
this._updateRegionIdle = 0;
@ -210,7 +209,6 @@ const LayoutManager = new Lang.Class({
this.trayBox = new St.Widget({ name: 'trayBox',
layout_manager: new Clutter.BinLayout() });
this.addChrome(this.trayBox);
this._setupTrayPressure();
this.modalDialogGroup = new St.Widget({ name: 'modalDialogGroup',
layout_manager: new Clutter.BinLayout() });
@ -449,50 +447,9 @@ const LayoutManager = new Lang.Class({
}
},
_setupTrayPressure: function() {
this._trayPressure = new PressureBarrier(MESSAGE_TRAY_PRESSURE_THRESHOLD,
MESSAGE_TRAY_PRESSURE_TIMEOUT,
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW);
this._trayPressure.setEventFilter(this._trayBarrierEventFilter);
this._trayPressure.connect('trigger', function(barrier) {
if (Main.layoutManager.bottomMonitor.inFullscreen)
return;
Main.messageTray.openTray();
});
},
_updateTrayBarrier: function() {
let monitor = this.bottomMonitor;
if (this._trayBarrier) {
this._trayPressure.removeBarrier(this._trayBarrier);
this._trayBarrier.destroy();
this._trayBarrier = null;
}
this._trayBarrier = new Meta.Barrier({ display: global.display,
x1: monitor.x, x2: monitor.x + monitor.width,
y1: monitor.y + monitor.height, y2: monitor.y + monitor.height,
directions: Meta.BarrierDirection.NEGATIVE_Y });
this._trayPressure.addBarrier(this._trayBarrier);
},
_trayBarrierEventFilter: function(event) {
// Throw out all events where the pointer was grabbed by another
// client, as the client that grabbed the pointer expects to have
// complete control over it
if (event.grabbed && Main.modalCount == 0)
return true;
return false;
},
_monitorsChanged: function() {
this._updateMonitors();
this._updateBoxes();
this._updateTrayBarrier();
this._updateHotCorners();
this._updateBackgrounds();
this._updateFullscreen();

View File

@ -150,8 +150,8 @@ function _initializeUI() {
if (LoginManager.canLock())
screenShield = new ScreenShield.ScreenShield();
panel = new Panel.Panel();
messageTray = new MessageTray.MessageTray();
panel = new Panel.Panel();
keyboard = new Keyboard.Keyboard();
notificationDaemon = new NotificationDaemon.NotificationDaemon();
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
@ -281,7 +281,6 @@ function notify(msg, details) {
let source = new MessageTray.SystemNotificationSource();
messageTray.add(source);
let notification = new MessageTray.Notification(source, msg, details);
notification.setTransient(true);
source.notify(notification);
}

File diff suppressed because it is too large Load Diff

View File

@ -91,21 +91,6 @@ const rewriteRules = {
]
};
const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
'bluetooth-applet': 'bluetooth',
'gnome-volume-control-applet': 'volume', // renamed to gnome-sound-applet
// when moved to control center
'gnome-sound-applet': 'volume',
'nm-applet': 'network',
'gnome-power-manager': 'battery',
'keyboard': 'keyboard',
'a11y-keyboard': 'a11y',
'kbd-scrolllock': 'keyboard',
'kbd-numlock': 'keyboard',
'kbd-capslock': 'keyboard',
'ibus-ui-gtk': 'keyboard'
};
const FdoNotificationDaemon = new Lang.Class({
Name: 'FdoNotificationDaemon',
@ -129,7 +114,7 @@ const FdoNotificationDaemon = new Lang.Class({
Main.overview.connect('hidden',
Lang.bind(this, this._onFocusAppChanged));
this._trayManager.manage_screen(global.screen, Main.messageTray.actor);
// this._trayManager.manage_screen(global.screen, Main.messageTray.actor);
},
_imageForNotificationData: function(hints) {
@ -195,10 +180,6 @@ const FdoNotificationDaemon = new Lang.Class({
if (!pid && !(ndata && ndata.notification))
return null;
// We use notification's source for the notifications we still have
// around that are getting replaced because we don't keep sources
// for transient notifications in this._sources, but we still want
// the notification associated with them to get replaced correctly.
if (ndata && ndata.notification)
return ndata.notification.source;
@ -334,13 +315,14 @@ const FdoNotificationDaemon = new Lang.Class({
},
_makeButton: function(id, label, useActionIcons) {
let button = new St.Button({ can_focus: true });
let button = new St.Button({ can_focus: true,
x_expand: true,
style_class: 'notification-button' });
let iconName = id.endsWith('-symbolic') ? id : id + '-symbolic';
if (useActionIcons && Gtk.IconTheme.get_default().has_icon(iconName)) {
button.add_style_class_name('notification-icon-button');
button.child = new St.Icon({ icon_name: iconName });
button.child = new St.Icon({ icon_name: iconName, icon_size: 16 });
} else {
button.add_style_class_name('notification-button');
button.label = label;
}
return button;
@ -379,8 +361,6 @@ const FdoNotificationDaemon = new Lang.Class({
let gicon = this._iconForNotificationData(icon, hints);
let gimage = this._imageForNotificationData(hints);
let image = null;
// If an icon is not specified, we use 'image-data' or 'image-path' hint for an icon
// and don't show a large image. There are currently many applications that use
// notify_notification_set_icon_from_pixbuf() from libnotify, which in turn sets
@ -389,10 +369,7 @@ const FdoNotificationDaemon = new Lang.Class({
// So the logic here does the right thing for this case. If both an icon and either
// one of 'image-data' or 'image-path' are specified, we show both an icon and
// a large image.
if (gicon && gimage)
image = new St.Icon({ gicon: gimage,
icon_size: notification.IMAGE_SIZE });
else if (!gicon && gimage)
if (!gicon && gimage)
gicon = gimage;
else if (!gicon)
gicon = this._fallbackIconForNotificationData(hints);
@ -402,7 +379,6 @@ const FdoNotificationDaemon = new Lang.Class({
clear: true,
soundFile: hints['sound-file'],
soundName: hints['sound-name'] });
notification.setImage(image);
let hasDefaultAction = false;
@ -442,10 +418,6 @@ const FdoNotificationDaemon = new Lang.Class({
notification.setUrgency(MessageTray.Urgency.CRITICAL);
break;
}
notification.setResident(hints.resident == true);
// 'transient' is a reserved keyword in JS, so we have to retrieve the value
// of the 'transient' hint with hints['transient'] rather than hints.transient
notification.setTransient(hints['transient'] == true);
let sourceGIcon = source.useNotificationIcon ? gicon : null;
source.processNotification(notification, sourceGIcon);
@ -470,7 +442,6 @@ const FdoNotificationDaemon = new Lang.Class({
'body-markup',
// 'icon-multi',
'icon-static',
'persistence',
'sound',
];
},
@ -492,7 +463,7 @@ const FdoNotificationDaemon = new Lang.Class({
for (let i = 0; i < this._sources.length; i++) {
let source = this._sources[i];
if (source.app == tracker.focus_app) {
source.destroyNonResidentNotifications();
source.destroyNotifications();
return;
}
}
@ -509,10 +480,6 @@ const FdoNotificationDaemon = new Lang.Class({
},
_onTrayIconAdded: function(o, icon) {
let wmClass = icon.wm_class ? icon.wm_class.toLowerCase() : '';
if (STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass] !== undefined)
return;
let source = this._getSource(icon.title || icon.wm_class || C_("program", "Unknown"), icon.pid, null, null, icon);
},
@ -584,7 +551,7 @@ const FdoNotificationDaemonSource = new Lang.Class({
this.iconUpdated();
let tracker = Shell.WindowTracker.get_default();
if (notification.resident && this.app && tracker.focus_app == this.app)
if (this.app && tracker.focus_app == this.app)
this.pushNotification(notification);
else
this.notify(notification);
@ -651,7 +618,7 @@ const FdoNotificationDaemonSource = new Lang.Class({
open: function() {
this.openApp();
this.destroyNonResidentNotifications();
this.destroyNotifications();
},
_lastNotificationRemoved: function() {

View File

@ -72,7 +72,6 @@ const ShellInfo = new Lang.Class({
let notification = null;
if (this._source.notifications.length == 0) {
notification = new MessageTray.Notification(this._source, text, null);
notification.setTransient(true);
notification.setForFeedback(forFeedback);
} else {
notification = this._source.notifications[0];

View File

@ -862,11 +862,56 @@ const AggregateMenu = new Lang.Class({
},
});
const DateMenuButton2 = new Lang.Class({
Name: 'DateMenuButton2',
_init: function() {
this.container = new St.Widget({ layout_manager: new Clutter.BinLayout() });
this._notificationPreview = Main.messageTray.notificationPreview;
this.container.add_child(this._notificationPreview.actor);
this._notificationPreview.actor.x_expand = true;
this._notificationPreview.actor.x_align = Clutter.ActorAlign.CENTER;
this._notificationPreview.connect('updated', Lang.bind(this, this._sync));
let dateMenu = new imports.ui.dateMenu.DateMenuButton();
this._clock = dateMenu.container;
this._clock.x_expand = true;
this._clock.x_align = Clutter.ActorAlign.CENTER;
this.container.add_child(this._clock);
this._currentlyShowing = 'clock';
this._sync();
},
_show: function(which, animate) {
if (this._currentlyShowing == which)
return;
this._currentlyShowing = which;
if (this._currentlyShowing == 'clock') {
this._notificationPreview.actor.visible = false;
this._clock.visible = true;
} else if (this._currentlyShowing == 'notification') {
this._notificationPreview.actor.visible = true;
this._clock.visible = false;
}
},
_sync: function() {
if (this._currentlyShowing == 'clock' && this._notificationPreview.hasNotification)
this._show('notification', true);
else if (this._currentlyShowing == 'notification' && !this._notificationPreview.hasNotification)
this._show('clock', false);
},
});
Signals.addSignalMethods(DateMenuButton2.prototype);
const PANEL_ITEM_IMPLEMENTATIONS = {
'activities': ActivitiesButton,
'aggregateMenu': AggregateMenu,
'appMenu': AppMenuButton,
'dateMenu': imports.ui.dateMenu.DateMenuButton,
'dateMenu': DateMenuButton2,
'a11y': imports.ui.status.accessibility.ATIndicator,
'a11yGreeter': imports.ui.status.accessibility.ATGreeterIndicator,
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,

View File

@ -253,7 +253,6 @@ const ShellUnmountNotifier = new Lang.Class({
if (!this._notification) {
this._notification = new MessageTray.Notification(this, header, text);
this._notification.setTransient(true);
this._notification.setUrgency(MessageTray.Urgency.CRITICAL);
} else {
this._notification.update(header, text);
@ -270,7 +269,6 @@ const ShellUnmountNotifier = new Lang.Class({
if (message) {
let notification = new MessageTray.Notification(this, message, null);
notification.setTransient(true);
this.notify(notification);
}

View File

@ -1632,7 +1632,6 @@ const NMApplet = new Lang.Class({
let gicon = new Gio.ThemedIcon({ name: iconName });
this._notification = new MessageTray.Notification(this._source, title, text, { gicon: gicon });
this._notification.setUrgency(urgency);
this._notification.setTransient(true);
this._notification.connect('destroy', function() {
this._notification = null;
});

View File

@ -21,10 +21,6 @@ struct _ShellTpClientPrivate
ShellTpClientHandleChannelsImpl handle_channels_impl;
gpointer user_data_handle_channels;
GDestroyNotify destroy_handle_channels;
ShellTpClientContactListChangedImpl contact_list_changed_impl;
gpointer user_data_contact_list_changed;
GDestroyNotify destroy_contact_list_changed;
};
/**
@ -83,16 +79,6 @@ struct _ShellTpClientPrivate
* Signature of the implementation of the HandleChannels method.
*/
/**
* ShellTpClientContactListChangedImpl:
* @connection: a #TpConnection having %TP_CONNECTION_FEATURE_CORE prepared
* if possible
* @added: (element-type TelepathyGLib.Contact): a #GPtrArray of added #TpContact
* @removed: (element-type TelepathyGLib.Contact): a #GPtrArray of removed #TpContact
*
* Signature of the implementation of the ContactListChanged method.
*/
static void
shell_tp_client_init (ShellTpClient *self)
{
@ -226,13 +212,6 @@ shell_tp_client_dispose (GObject *object)
self->priv->user_data_handle_channels = NULL;
}
if (self->priv->destroy_contact_list_changed != NULL)
{
self->priv->destroy_contact_list_changed (self->priv->user_data_contact_list_changed);
self->priv->destroy_contact_list_changed = NULL;
self->priv->user_data_contact_list_changed = NULL;
}
if (dispose != NULL)
dispose (object);
}
@ -290,40 +269,3 @@ shell_tp_client_set_handle_channels_func (ShellTpClient *self,
self->priv->user_data_handle_channels = user_data;
self->priv->destroy_handle_channels = destroy;
}
void
shell_tp_client_set_contact_list_changed_func (ShellTpClient *self,
ShellTpClientContactListChangedImpl contact_list_changed_impl,
gpointer user_data,
GDestroyNotify destroy)
{
g_assert (self->priv->contact_list_changed_impl == NULL);
self->priv->contact_list_changed_impl = contact_list_changed_impl;
self->priv->user_data_handle_channels = user_data;
self->priv->destroy_handle_channels = destroy;
}
static void
on_contact_list_changed (TpConnection *conn,
GPtrArray *added,
GPtrArray *removed,
gpointer user_data)
{
ShellTpClient *self = (ShellTpClient *) user_data;
g_assert (self->priv->contact_list_changed_impl != NULL);
self->priv->contact_list_changed_impl (conn,
added, removed,
self->priv->user_data_contact_list_changed);
}
void
shell_tp_client_grab_contact_list_changed (ShellTpClient *self,
TpConnection *conn)
{
g_signal_connect (conn, "contact-list-changed",
G_CALLBACK (on_contact_list_changed),
self);
}

View File

@ -86,19 +86,5 @@ void shell_tp_client_set_handle_channels_func (ShellTpClient *self,
gpointer user_data,
GDestroyNotify destroy);
typedef void (*ShellTpClientContactListChangedImpl) (
TpConnection *connection,
GPtrArray *added,
GPtrArray *removed,
gpointer user_data);
void shell_tp_client_set_contact_list_changed_func (ShellTpClient *self,
ShellTpClientContactListChangedImpl contact_list_changed_impl,
gpointer user_data,
GDestroyNotify destroy);
void shell_tp_client_grab_contact_list_changed (ShellTpClient *self,
TpConnection *conn);
G_END_DECLS
#endif /* __SHELL_TP_CLIENT_H__ */