Compare commits
	
		
			17 Commits
		
	
	
		
			gnome-3-34
			...
			wip/notif-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					50395cded8 | ||
| 
						 | 
					e8ae8f75a0 | ||
| 
						 | 
					2b93bcf921 | ||
| 
						 | 
					a80b8f7791 | ||
| 
						 | 
					62c6563a3a | ||
| 
						 | 
					c22068d288 | ||
| 
						 | 
					d519a0a181 | ||
| 
						 | 
					ef1ab043a3 | ||
| 
						 | 
					fa350bf41e | ||
| 
						 | 
					ae74dbd1bb | ||
| 
						 | 
					afa5a871b3 | ||
| 
						 | 
					e13c0ca9e8 | ||
| 
						 | 
					f29d1beb3e | ||
| 
						 | 
					751a1b5bbe | ||
| 
						 | 
					00a32f53f5 | ||
| 
						 | 
					94688d354f | ||
| 
						 | 
					7f17acd0ea | 
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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',
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2253
									
								
								js/ui/messageTray.js
									
									
									
									
									
								
							
							
						
						
									
										2253
									
								
								js/ui/messageTray.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -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() {
 | 
			
		||||
 
 | 
			
		||||
@@ -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];
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
        });
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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__ */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user