1
by Jonas Kuemmerlin
initial commit |
1 |
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2 |
// Copyright (C) 2011 Giovanni Campagna
|
|
3 |
// Copyright (C) 2013 Jonas Kuemmerlin <rgcjonas@gmail.com>
|
|
4 |
//
|
|
5 |
// This program is free software; you can redistribute it and/or
|
|
6 |
// modify it under the terms of the GNU General Public License
|
|
7 |
// as published by the Free Software Foundation; either version 2
|
|
8 |
// of the License, or (at your option) any later version.
|
|
47
by Jonas Kümmerlin
Internal reorganization, mostly in the settings dialog. |
9 |
//
|
1
by Jonas Kuemmerlin
initial commit |
10 |
// This program is distributed in the hope that it will be useful,
|
11 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13 |
// GNU General Public License for more details.
|
|
14 |
//
|
|
15 |
// You should have received a copy of the GNU General Public License
|
|
16 |
// along with this program; if not, write to the Free Software
|
|
17 |
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
18 |
||
19 |
const Gio = imports.gi.Gio; |
|
20 |
const Gtk = imports.gi.Gtk; |
|
21 |
const Lang = imports.lang; |
|
22 |
const Mainloop = imports.mainloop; |
|
23 |
const Signals = imports.signals; |
|
24 |
const GLib = imports.gi.GLib; |
|
25 |
||
26 |
const Extension = imports.misc.extensionUtils.getCurrentExtension(); |
|
27 |
const AppIndicator = Extension.imports.appIndicator; |
|
28 |
const StatusNotifierDispatcher = Extension.imports.statusNotifierDispatcher; |
|
47
by Jonas Kümmerlin
Internal reorganization, mostly in the settings dialog. |
29 |
const Interfaces = Extension.imports.interfaces; |
30 |
||
31 |
const Config = Extension.imports.config; |
|
32 |
const ShellConfig = imports.misc.config; |
|
1
by Jonas Kuemmerlin
initial commit |
33 |
|
34 |
// TODO: replace with org.freedesktop and /org/freedesktop when approved
|
|
35 |
const KDE_PREFIX = 'org.kde'; |
|
36 |
const AYATANA_PREFIX = 'org.ayatana'; |
|
37 |
const AYATANA_PATH_PREFIX = '/org/ayatana'; |
|
38 |
||
39 |
const WATCHER_BUS_NAME = KDE_PREFIX + '.StatusNotifierWatcher'; |
|
40 |
const WATCHER_INTERFACE = WATCHER_BUS_NAME; |
|
41 |
const WATCHER_OBJECT = '/StatusNotifierWatcher'; |
|
42 |
||
43 |
const ITEM_OBJECT = '/StatusNotifierItem'; |
|
44 |
||
40
by Jonas Kuemmerlin
Inline documentation updates everywhere |
45 |
/*
|
46 |
* The StatusNotifierWatcher class implements the StatusNotifierWatcher dbus object
|
|
47 |
*/
|
|
48 |
const StatusNotifierWatcher = new Lang.Class({ |
|
49 |
Name: 'StatusNotifierWatcher', |
|
47
by Jonas Kümmerlin
Internal reorganization, mostly in the settings dialog. |
50 |
|
1
by Jonas Kuemmerlin
initial commit |
51 |
_init: function() { |
47
by Jonas Kümmerlin
Internal reorganization, mostly in the settings dialog. |
52 |
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(Interfaces.StatusNotifierWatcher, this); |
1
by Jonas Kuemmerlin
initial commit |
53 |
this._dbusImpl.export(Gio.DBus.session, WATCHER_OBJECT); |
54 |
this._everAcquiredName = false; |
|
3
by Jonas Kuemmerlin
call g_bus_unown_name on disable |
55 |
this._ownName = Gio.DBus.session.own_name(WATCHER_BUS_NAME, |
1
by Jonas Kuemmerlin
initial commit |
56 |
Gio.BusNameOwnerFlags.NONE, |
57 |
Lang.bind(this, this._acquiredName), |
|
58 |
Lang.bind(this, this._lostName)); |
|
59 |
this._items = { }; |
|
60 |
this._nameWatcher = { }; |
|
61 |
},
|
|
62 |
||
63 |
_acquiredName: function() { |
|
64 |
this._everAcquiredName = true; |
|
65 |
},
|
|
66 |
||
67 |
_lostName: function() { |
|
68 |
if (this._everAcquiredName) |
|
13
by Jonas Kuemmerlin
debounce enable/disable operations. fixes #2 |
69 |
log('appindicator: Lost name' + WATCHER_BUS_NAME); |
1
by Jonas Kuemmerlin
initial commit |
70 |
else { |
13
by Jonas Kuemmerlin
debounce enable/disable operations. fixes #2 |
71 |
log('appindicator: Failed to acquire ' + WATCHER_BUS_NAME); |
1
by Jonas Kuemmerlin
initial commit |
72 |
}
|
73 |
},
|
|
47
by Jonas Kümmerlin
Internal reorganization, mostly in the settings dialog. |
74 |
|
75 |
||
40
by Jonas Kuemmerlin
Inline documentation updates everywhere |
76 |
// create a unique index for the _items dictionary
|
1
by Jonas Kuemmerlin
initial commit |
77 |
_getItemId: function(bus_name, obj_path) { |
47
by Jonas Kümmerlin
Internal reorganization, mostly in the settings dialog. |
78 |
return bus_name + obj_path; |
1
by Jonas Kuemmerlin
initial commit |
79 |
},
|
80 |
||
81 |
RegisterStatusNotifierItemAsync: function(params, invocation) { |
|
82 |
// it would be too easy if all application behaved the same
|
|
83 |
// instead, ayatana patched gnome apps to send a path
|
|
84 |
// while kde apps send a bus name
|
|
85 |
let service = params[0]; |
|
86 |
let bus_name, obj_path; |
|
40
by Jonas Kuemmerlin
Inline documentation updates everywhere |
87 |
if (service.charAt(0) == '/') { // looks like a path |
1
by Jonas Kuemmerlin
initial commit |
88 |
bus_name = invocation.get_sender(); |
89 |
obj_path = service; |
|
90 |
} else { // we hope it is a bus name |
|
91 |
bus_name = service; |
|
92 |
obj_path = ITEM_OBJECT; |
|
93 |
}
|
|
94 |
||
95 |
let id = this._getItemId(bus_name, obj_path); |
|
47
by Jonas Kümmerlin
Internal reorganization, mostly in the settings dialog. |
96 |
|
1
by Jonas Kuemmerlin
initial commit |
97 |
if(this._items[id]) { |
98 |
//delete the old one and add the new indicator
|
|
99 |
log("WARNING: Attempting to re-register "+id+"; resetting instead"); |
|
100 |
this._items[id].reset(); |
|
101 |
} else { |
|
102 |
log("registering "+id+" for the first time."); |
|
103 |
this._items[id] = new AppIndicator.AppIndicator(bus_name, obj_path); |
|
24
by Jonas Kuemmerlin
changed GVariant type from 's' to '(s)' when emitting DBus signals on StatusNotifierWatcher. Fixes annoying 'assertion failed' warnings. |
104 |
this._dbusImpl.emit_signal('ServiceRegistered', GLib.Variant.new('(s)', service)); |
1
by Jonas Kuemmerlin
initial commit |
105 |
this._nameWatcher[id] = Gio.DBus.session.watch_name(bus_name, Gio.BusNameWatcherFlags.NONE, null, |
106 |
Lang.bind(this, this._itemVanished)); |
|
107 |
StatusNotifierDispatcher.IndicatorDispatcher.instance.dispatch(this._items[id]); |
|
108 |
this._dbusImpl.emit_property_changed('RegisteredStatusNotifierItems', null); //FIXME: null is incorrect |
|
109 |
}
|
|
110 |
invocation.return_value(null); |
|
111 |
},
|
|
112 |
||
113 |
_itemVanished: function(proxy, bus_name) { |
|
114 |
// FIXME: this is useless if the path name disappears while the bus stays alive (not unheard of)
|
|
115 |
for (var i in this._items) { |
|
116 |
if (i.indexOf(bus_name) == 0) { |
|
117 |
this._remove(i); |
|
118 |
}
|
|
119 |
}
|
|
120 |
},
|
|
47
by Jonas Kümmerlin
Internal reorganization, mostly in the settings dialog. |
121 |
|
1
by Jonas Kuemmerlin
initial commit |
122 |
_remove: function(id) { |
29
by Jonas Kuemmerlin
replacing all tabs with 4 spaces |
123 |
this._items[id].destroy(); |
1
by Jonas Kuemmerlin
initial commit |
124 |
delete this._items[id]; |
125 |
Gio.DBus.session.unwatch_name(this._nameWatcher[id]); |
|
126 |
delete this._nameWatcher[id]; |
|
24
by Jonas Kuemmerlin
changed GVariant type from 's' to '(s)' when emitting DBus signals on StatusNotifierWatcher. Fixes annoying 'assertion failed' warnings. |
127 |
this._dbusImpl.emit_signal('ServiceUnregistered', GLib.Variant.new('(s)', id)); |
1
by Jonas Kuemmerlin
initial commit |
128 |
this._dbusImpl.emit_property_changed('RegisteredStatusNotifierItems', null); |
129 |
},
|
|
47
by Jonas Kümmerlin
Internal reorganization, mostly in the settings dialog. |
130 |
|
1
by Jonas Kuemmerlin
initial commit |
131 |
RegisterNotificationHost: function(service) { |
132 |
throw new Gio.DBusError('org.gnome.Shell.UnsupportedMethod', |
|
133 |
'Registering additional notification hosts is not supported'); |
|
134 |
},
|
|
135 |
||
136 |
IsNotificationHostRegistered: function() { |
|
137 |
return true; |
|
138 |
},
|
|
139 |
||
140 |
ProtocolVersion: function() { |
|
141 |
// "The version of the protocol the StatusNotifierWatcher instance implements." [sic]
|
|
142 |
// in what syntax?
|
|
47
by Jonas Kümmerlin
Internal reorganization, mostly in the settings dialog. |
143 |
return "%s/%s (KDE; compatible; mostly) GNOME Shell/%s".format(Config.id, Config.version, ShellConfig.PACKAGE_VERSION); |
1
by Jonas Kuemmerlin
initial commit |
144 |
},
|
145 |
||
146 |
get RegisteredStatusNotifierItems() { |
|
147 |
return Object.keys(this._items); |
|
148 |
},
|
|
47
by Jonas Kümmerlin
Internal reorganization, mostly in the settings dialog. |
149 |
|
1
by Jonas Kuemmerlin
initial commit |
150 |
get IsStatusNotifierHostRegistered() { |
151 |
return true; |
|
152 |
},
|
|
47
by Jonas Kümmerlin
Internal reorganization, mostly in the settings dialog. |
153 |
|
1
by Jonas Kuemmerlin
initial commit |
154 |
destroy: function() { |
29
by Jonas Kuemmerlin
replacing all tabs with 4 spaces |
155 |
if (!this._isDestroyed) { |
40
by Jonas Kuemmerlin
Inline documentation updates everywhere |
156 |
// this doesn't do any sync operation and doesn't allow us to hook up the event of being finished
|
157 |
// which results in our unholy debounce hack (see extension.js)
|
|
29
by Jonas Kuemmerlin
replacing all tabs with 4 spaces |
158 |
Gio.DBus.session.unown_name(this._ownName); |
159 |
this._dbusImpl.unexport(); |
|
160 |
for (var i in this._nameWatcher) { |
|
161 |
Gio.DBus.session.unwatch_name(this._nameWatcher[i]); |
|
162 |
}
|
|
163 |
delete this._nameWatcher; |
|
164 |
for (var i in this._items) { |
|
165 |
this._items[i].destroy(); |
|
166 |
}
|
|
167 |
delete this._items; |
|
168 |
this._isDestroyed = true; |
|
169 |
}
|
|
1
by Jonas Kuemmerlin
initial commit |
170 |
}
|
40
by Jonas Kuemmerlin
Inline documentation updates everywhere |
171 |
});
|