notificationDaemon, magnifierDBus: port to GDBus

Move /org/freedesktop/Notifications and /org/gnome/Magnifier to the
GDBus connection, so they're matched with the appropriate DBus name.

https://bugzilla.gnome.org/show_bug.cgi?id=648651
This commit is contained in:
Giovanni Campagna 2011-08-16 14:26:49 +02:00 committed by Colin Walters
parent adc187c32e
commit 827bf506a7
2 changed files with 190 additions and 139 deletions

View File

@ -1,6 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const DBus = imports.dbus; const Gio = imports.gi.Gio;
const Main = imports.ui.main; const Main = imports.ui.main;
const MAG_SERVICE_NAME = 'org.gnome.Magnifier'; const MAG_SERVICE_NAME = 'org.gnome.Magnifier';
@ -10,47 +10,85 @@ const ZOOM_SERVICE_PATH = '/org/gnome/Magnifier/ZoomRegion';
// Subset of gnome-mag's Magnifier dbus interface -- to be expanded. See: // Subset of gnome-mag's Magnifier dbus interface -- to be expanded. See:
// http://git.gnome.org/browse/gnome-mag/tree/xml/...Magnifier.xml // http://git.gnome.org/browse/gnome-mag/tree/xml/...Magnifier.xml
const MagnifierIface = { const MagnifierIface = <interface name={MAG_SERVICE_NAME}>
name: MAG_SERVICE_NAME, <method name="setActive">
methods: [ <arg type="b" direction="in" />
{ name: 'setActive', inSignature: 'b', outSignature: '' }, </method>
{ name: 'isActive', inSignature: '', outSignature: 'b' }, <method name="isActive">
{ name: 'showCursor', inSignature: '', outSignature: '' }, <arg type="b" direction="out" />
{ name: 'hideCursor', inSignature: '', outSignature: '' }, </method>
{ name: 'createZoomRegion', inSignature: 'ddaiai', outSignature: 'o' }, <method name="showCursor" />
{ name: 'addZoomRegion', inSignature: 'o', outSignature: 'b' }, <method name="hideCursor" />
{ name: 'getZoomRegions', inSignature: '', outSignature: 'ao' }, <method name="createZoomRegion">
{ name: 'clearAllZoomRegions', inSignature: '', outSignature: '' }, <arg type="d" direction="in" />
{ name: 'fullScreenCapable', inSignature: '', outSignature: 'b' }, <arg type="d" direction="in" />
<arg type="ai" direction="in" />
{ name: 'setCrosswireSize', inSignature: 'i', outSignature: '' }, <arg type="ai" direction="in" />
{ name: 'getCrosswireSize', inSignature: '', outSignature: 'i' }, <arg type="o" direction="out" />
{ name: 'setCrosswireLength', inSignature: 'i', outSignature: '' }, </method>
{ name: 'getCrosswireLength', inSignature: '', outSignature: 'i' }, <method name="addZoomRegion">
{ name: 'setCrosswireClip', inSignature: 'b', outSignature: '' }, <arg type="o" direction="in" />
{ name: 'getCrosswireClip', inSignature: '', outSignature: 'b' }, <arg type="b" direction="out" />
{ name: 'setCrosswireColor', inSignature: 'u', outSignature: '' }, </method>
{ name: 'getCrosswireColor', inSignature: '', outSignature: 'u' } <method name="getZoomRegions">
], <arg type="ao" direction="out" />
signals: [], </method>
properties: [] <method name="clearAllZoomRegions" />
}; <method name="fullScreenCapable">
<arg type="b" direction="out" />
</method>
<method name="setCrosswireSize">
<arg type="i" direction="in" />
</method>
<method name="getCrosswireSize">
<arg type="i" direction="out" />
</method>
<method name="setCrosswireLength">
<arg type="i" direction="in" />
</method>
<method name="getCrosswireLength">
<arg type="i" direction="out" />
</method>
<method name="setCrosswireClip">
<arg type="b" direction="in" />
</method>
<method name="getCrosswireClip">
<arg type="b" direction="out" />
</method>
<method name="setCrosswireColor">
<arg type="u" direction="in" />
</method>
<method name="getCrosswireColor">
<arg type="u" direction="out" />
</method>
</interface>;
// Subset of gnome-mag's ZoomRegion dbus interface -- to be expanded. See: // Subset of gnome-mag's ZoomRegion dbus interface -- to be expanded. See:
// http://git.gnome.org/browse/gnome-mag/tree/xml/...ZoomRegion.xml // http://git.gnome.org/browse/gnome-mag/tree/xml/...ZoomRegion.xml
const ZoomRegionIface = { const ZoomRegionIface = <interface name={ZOOM_SERVICE_NAME}>
name: ZOOM_SERVICE_NAME, <method name="setMagFactor">
methods: [ <arg type="d" direction="in" />
{ name: 'setMagFactor', inSignature: 'dd', outSignature: ''}, <arg type="d" direction="in" />
{ name: 'getMagFactor', inSignature: '', outSignature: 'dd' }, </method>
{ name: 'setRoi', inSignature: 'ai', outSignature: '' }, <method name="getMagFactor">
{ name: 'getRoi', inSignature: '', outSignature: 'ai' }, <arg type="d" direction="out" />
{ name: 'shiftContentsTo', inSignature: 'ii', outSignature: 'b' }, <arg type="d" direction="out" />
{ name: 'moveResize', inSignature: 'ai', outSignature: '' } </method>
], <method name="setRoi">
signals: [], <arg type="ai" direction="in" />
properties: [] </method>
}; <method name="getRoi">
<arg type="ai" direction="out" />
</method>
<method name="shiftContentsTo">
<arg type="i" direction="in" />
<arg type="i" direction="in" />
<arg type="b" direction="out" />
</method>
<method name="moveResize">
<arg type="ai" direction="in" />
</method>
</interface>;
// For making unique ZoomRegion DBus proxy object paths of the form: // For making unique ZoomRegion DBus proxy object paths of the form:
// '/org/gnome/Magnifier/ZoomRegion/zoomer0', // '/org/gnome/Magnifier/ZoomRegion/zoomer0',
@ -64,7 +102,9 @@ function ShellMagnifier() {
ShellMagnifier.prototype = { ShellMagnifier.prototype = {
_init: function() { _init: function() {
this._zoomers = {}; this._zoomers = {};
DBus.session.exportObject(MAG_SERVICE_PATH, this);
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(MagnifierIface, this);
this._dbusImpl.export(Gio.DBus.session, MAG_SERVICE_PATH);
}, },
/** /**
@ -195,10 +235,10 @@ ShellMagnifier.prototype = {
Main.magnifier.clearAllZoomRegions(); Main.magnifier.clearAllZoomRegions();
for (let objectPath in this._zoomers) { for (let objectPath in this._zoomers) {
let proxyAndZoomer = this._zoomers[objectPath]; let proxyAndZoomer = this._zoomers[objectPath];
proxyAndZoomer.proxy.destroy();
proxyAndZoomer.proxy = null; proxyAndZoomer.proxy = null;
proxyAndZoomer.zoomRegion = null; proxyAndZoomer.zoomRegion = null;
delete this._zoomers[objectPath]; delete this._zoomers[objectPath];
DBus.session.unexportObject(proxyAndZoomer);
} }
this._zoomers = {}; this._zoomers = {};
}, },
@ -300,8 +340,9 @@ function ShellMagnifierZoomRegion(zoomerObjectPath, zoomRegion) {
ShellMagnifierZoomRegion.prototype = { ShellMagnifierZoomRegion.prototype = {
_init: function(zoomerObjectPath, zoomRegion) { _init: function(zoomerObjectPath, zoomRegion) {
this._zoomRegion = zoomRegion; this._zoomRegion = zoomRegion;
DBus.session.proxifyObject(this, ZOOM_SERVICE_NAME, zoomerObjectPath);
DBus.session.exportObject(zoomerObjectPath, this); this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ZoomRegionIface, this);
this._dbusImpl.export(Gio.DBus.session, zoomerObjectPath);
}, },
/** /**
@ -376,8 +417,9 @@ ShellMagnifierZoomRegion.prototype = {
moveResize: function(viewPort) { moveResize: function(viewPort) {
let viewRect = { x: viewPort[0], y: viewPort[1], width: viewPort[2] - viewPort[0], height: viewPort[3] - viewPort[1] }; let viewRect = { x: viewPort[0], y: viewPort[1], width: viewPort[2] - viewPort[0], height: viewPort[3] - viewPort[1] };
this._zoomRegion.setViewPort(viewRect); this._zoomRegion.setViewPort(viewRect);
},
destroy: function() {
this._dbusImpl.unexport();
} }
}; };
DBus.conformExport(ShellMagnifier.prototype, MagnifierIface);
DBus.conformExport(ShellMagnifierZoomRegion.prototype, ZoomRegionIface);

View File

@ -1,7 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const DBus = imports.dbus; const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib; const GLib = imports.gi.GLib;
const Lang = imports.lang; const Lang = imports.lang;
const Shell = imports.gi.Shell; const Shell = imports.gi.Shell;
@ -16,49 +16,52 @@ const Util = imports.misc.util;
let nextNotificationId = 1; let nextNotificationId = 1;
// Should really be defined in dbus.js // Should really be defined in Gio.js
const BusIface = { const BusIface = <interface name="org.freedesktop.DBus">
name: 'org.freedesktop.DBus', <method name="GetConnectionUnixProcessID">
methods: [{ name: 'GetConnectionUnixProcessID', <arg type="s" direction="in" />
inSignature: 's', <arg type="u" direction="out" />
outSignature: 'i' }] </method>
}; </interface>;
const Bus = function () { var BusProxy = Gio.DBusProxy.makeProxyWrapper(BusIface);
this._init(); function Bus() {
}; return new BusProxy(Gio.DBus.session, 'org.freedesktop.DBus', '/org/freedesktop/DBus');
}
Bus.prototype = { const NotificationDaemonIface = <interface name="org.freedesktop.Notifications">
_init: function() { <method name="Notify">
DBus.session.proxifyObject(this, 'org.freedesktop.DBus', '/org/freedesktop/DBus'); <arg type="s" direction="in"/>
} <arg type="u" direction="in"/>
}; <arg type="s" direction="in"/>
<arg type="s" direction="in"/>
DBus.proxifyPrototype(Bus.prototype, BusIface); <arg type="s" direction="in"/>
<arg type="as" direction="in"/>
const NotificationDaemonIface = { <arg type="a{sv}" direction="in"/>
name: 'org.freedesktop.Notifications', <arg type="i" direction="in"/>
methods: [{ name: 'Notify', <arg type="u" direction="out"/>
inSignature: 'susssasa{sv}i', </method>
outSignature: 'u' <method name="CloseNotification">
}, <arg type="u" direction="in"/>
{ name: 'CloseNotification', </method>
inSignature: 'u', <method name="GetCapabilities">
outSignature: '' <arg type="as" direction="out"/>
}, </method>
{ name: 'GetCapabilities', <method name="GetServerInformation">
inSignature: '', <arg type="s" direction="out"/>
outSignature: 'as' <arg type="s" direction="out"/>
}, <arg type="s" direction="out"/>
{ name: 'GetServerInformation', <arg type="s" direction="out"/>
inSignature: '', </method>
outSignature: 'ssss' <signal name="NotificationClosed">
}], <arg type="u"/>
signals: [{ name: 'NotificationClosed', <arg type="u"/>
inSignature: 'uu' }, </signal>
{ name: 'ActionInvoked', <signal name="ActionInvoked">
inSignature: 'us' }] <arg type="u"/>
}; <arg type="s"/>
</signal>
</interface>;
const NotificationClosedReason = { const NotificationClosedReason = {
EXPIRED: 1, EXPIRED: 1,
@ -90,7 +93,8 @@ function NotificationDaemon() {
NotificationDaemon.prototype = { NotificationDaemon.prototype = {
_init: function() { _init: function() {
DBus.session.exportObject('/org/freedesktop/Notifications', this); this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(NotificationDaemonIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
this._sources = {}; this._sources = {};
this._senderToPid = {}; this._senderToPid = {};
@ -195,8 +199,8 @@ NotificationDaemon.prototype = {
return source; return source;
}, },
Notify: function(appName, replacesId, icon, summary, body, NotifyAsync: function(params, invocation) {
actions, hints, timeout) { let [appName, replacesId, icon, summary, body, actions, hints, timeout] = params;
let id; let id;
// Filter out chat, presence, calls and invitation notifications from // Filter out chat, presence, calls and invitation notifications from
@ -215,7 +219,7 @@ NotificationDaemon.prototype = {
function () { function () {
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED); this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
})); }));
return id; return invocation.return_value(GLib.Variant.new('(u)', [id]));
} }
let rewrites = rewriteRules[appName]; let rewrites = rewriteRules[appName];
@ -227,6 +231,11 @@ NotificationDaemon.prototype = {
} }
} }
for (let hint in hints) {
// unpack the variants
hints[hint] = hints[hint].deep_unpack();
}
hints = Params.parse(hints, { urgency: Urgency.NORMAL }, true); hints = Params.parse(hints, { urgency: Urgency.NORMAL }, true);
// Be compatible with the various hints for image data and image path // Be compatible with the various hints for image data and image path
@ -258,51 +267,55 @@ NotificationDaemon.prototype = {
} }
this._notifications[id] = ndata; this._notifications[id] = ndata;
let sender = DBus.getCurrentMessageContext().sender; let sender = invocation.get_sender();
let pid = this._senderToPid[sender]; let pid = this._senderToPid[sender];
let source = this._getSource(appName, pid, ndata, sender); let source = this._getSource(appName, pid, ndata, sender);
if (source) { if (source) {
this._notifyForSource(source, ndata); this._notifyForSource(source, ndata);
return id; return invocation.return_value(GLib.Variant.new('(u)', [id]));
} }
if (replacesId) { if (replacesId) {
// There's already a pending call to GetConnectionUnixProcessID, // There's already a pending call to GetConnectionUnixProcessID,
// which will see the new notification data when it finishes, // which will see the new notification data when it finishes,
// so we don't have to do anything. // so we don't have to do anything.
return id; return invocation.return_value(GLib.Variant.new('(u)', [id]));;
} }
this._busProxy.GetConnectionUnixProcessIDRemote(sender, Lang.bind(this, this._busProxy.GetConnectionUnixProcessIDRemote(sender, Lang.bind(this, function (result, excp) {
function (pid, ex) { // The app may have updated or removed the notification
// The app may have updated or removed the notification ndata = this._notifications[id];
ndata = this._notifications[id]; if (!ndata)
if (!ndata) return;
return;
source = this._getSource(appName, pid, ndata, sender); if (excp) {
logError(excp, 'Call to GetConnectionUnixProcessID failed');
return;
}
// We only store sender-pid entries for persistent sources. let [pid] = result;
// Removing the entries once the source is destroyed source = this._getSource(appName, pid, ndata, sender);
// would result in the entries associated with transient
// sources removed once the notification is shown anyway.
// However, keeping these pairs would mean that we would
// possibly remove an entry associated with a persistent
// source when a transient source for the same sender is
// distroyed.
if (!source.isTransient) {
this._senderToPid[sender] = pid;
source.connect('destroy', Lang.bind(this,
function() {
delete this._senderToPid[sender];
}));
}
this._notifyForSource(source, ndata);
}));
return id; // We only store sender-pid entries for persistent sources.
// Removing the entries once the source is destroyed
// would result in the entries associated with transient
// sources removed once the notification is shown anyway.
// However, keeping these pairs would mean that we would
// possibly remove an entry associated with a persistent
// source when a transient source for the same sender is
// distroyed.
if (!source.isTransient) {
this._senderToPid[sender] = pid;
source.connect('destroy', Lang.bind(this, function() {
delete this._senderToPid[sender];
}));
}
this._notifyForSource(source, ndata);
}));
return invocation.return_value(GLib.Variant.new('(u)', [id]));
}, },
_notifyForSource: function(source, ndata) { _notifyForSource: function(source, ndata) {
@ -442,17 +455,13 @@ NotificationDaemon.prototype = {
}, },
_emitNotificationClosed: function(id, reason) { _emitNotificationClosed: function(id, reason) {
DBus.session.emit_signal('/org/freedesktop/Notifications', this._dbusImpl.emit_signal('NotificationClosed',
'org.freedesktop.Notifications', GLib.Variant.new('(uu)', [id, reason]));
'NotificationClosed', 'uu',
[id, reason]);
}, },
_emitActionInvoked: function(id, action) { _emitActionInvoked: function(id, action) {
DBus.session.emit_signal('/org/freedesktop/Notifications', this._dbusImpl.emit_signal('ActionInvoked',
'org.freedesktop.Notifications', GLib.Variant.new('(us)', [id, action]));
'ActionInvoked', 'us',
[id, action]);
}, },
_onTrayIconAdded: function(o, icon) { _onTrayIconAdded: function(o, icon) {
@ -467,8 +476,6 @@ NotificationDaemon.prototype = {
} }
}; };
DBus.conformExport(NotificationDaemon.prototype, NotificationDaemonIface);
function Source(title, pid, sender) { function Source(title, pid, sender) {
this._init(title, pid, sender); this._init(title, pid, sender);
} }
@ -481,15 +488,12 @@ Source.prototype = {
this._pid = pid; this._pid = pid;
if (sender) if (sender)
// TODO: dbus-glib implementation of watch_name() doesnt return an id to be used for this._nameWatcherId = Gio.DBus.session.watch_name(sender,
// unwatch_name() or implement unwatch_name(), however when we move to using GDBus implementation, Gio.BusNameWatcherFlags.NONE,
// we should save the id here and call unwatch_name() with it in destroy(). null,
// Moving to GDBus is the work in progress: https://bugzilla.gnome.org/show_bug.cgi?id=648651 Lang.bind(this, this._onNameVanished));
// and https://bugzilla.gnome.org/show_bug.cgi?id=622921 . else
DBus.session.watch_name(sender, this._nameWatcherId = 0;
false,
null,
Lang.bind(this, this._onNameVanished));
this._setApp(); this._setApp();
if (this.app) if (this.app)
@ -597,6 +601,11 @@ Source.prototype = {
}, },
destroy: function() { destroy: function() {
if (this._nameWatcherId) {
Gio.DBus.session.unwatch_name(this._nameWatcherId);
this._nameWatcherId = 0;
}
MessageTray.Source.prototype.destroy.call(this); MessageTray.Source.prototype.destroy.call(this);
} }
}; };