Compare commits
	
		
			17 Commits
		
	
	
		
			3.17.92
			...
			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