Compare commits

..

5 Commits

Author SHA1 Message Date
d2052a885e NetworkMenu: use async initialization for libnm-glib objects
NMClient recently got more heavyweight, with a property holding supported
connections. As fully initializing a NMObject is a recursive operation
and requires multiple DBus calls, switch to async initalization for NMClient
and NMRemoteSettings.

https://bugzilla.gnome.org/show_bug.cgi?id=683288
2012-11-02 14:11:10 +01:00
afcc1b7b52 Try to do more async initialization
Synchronous calls in the main loop are a performance killer, especially
at login.
2012-11-02 14:11:10 +01:00
a6b4d68a1d Port to GDBus 2
The GDBus bindings in gjs have been updated to leverage metaclasses
and gobject inheritance, which should result in cleaner and more
maintainable code.
2012-11-02 14:11:10 +01:00
aef9b733e5 loginDialog: drop spurious parameter
_onNotListed had an unusued, incorrect parameter.

This commit drops it.

https://bugzilla.gnome.org/show_bug.cgi?id=660660
2012-11-01 14:24:45 -04:00
348208617b Use the correct icon in the restart dialog
It currently uses system-shutdown-symbolic. view-refresh-symbolic
is a better fit in this case.

https://bugzilla.gnome.org/show_bug.cgi?id=670687
2012-11-01 16:21:52 +00:00
42 changed files with 1321 additions and 1347 deletions

View File

@ -113,13 +113,9 @@
<doc:summary>
<doc:para>
A dictionary describing the given search result, containing
'id' and 'name' (both strings). Optionally, either 'gicon' (a
serialized GIcon) or 'icon-data' (raw image data as (iiibiiay)
- width, height, rowstride, has-alpha, bits per sample,
channels, data) can be specified if the result can be better
served with a thumbnail of the content (such as with images).
A 'description' field (string) may also be specified if more
context would help the user find the desired result.
'id', 'name' (both strings) and either 'icon' (a serialized
GIcon) or 'icon-data' (raw image data as (iiibiiay) - width,
height, rowstride, has-alpha, bits per sample, channels, data)
</doc:para>
</doc:summary>
</doc:doc>
@ -147,25 +143,5 @@
</doc:doc>
</arg>
</method>
<method name="LaunchSearch">
<doc:doc>
<doc:description>
<doc:para>
Called when the user clicks on the provider icon. The provider
application should open and run the active search term itself.
</doc:para>
</doc:description>
</doc:doc>
<arg type="as" direction="in">
<doc:doc>
<doc:summary>
<doc:para>
The current search term(s).
</doc:para>
</doc:summary>
</doc:doc>
</arg>
</method>
</interface>
</node>

View File

@ -577,10 +577,6 @@ StScrollBar StButton#vhandle:active {
spacing: 40px;
}
#overview-group {
spacing: 12px;
}
.window-caption {
spacing: 25px;
}
@ -715,7 +711,7 @@ StScrollBar StButton#vhandle:active {
#searchResultsContent {
padding-right: 20px;
spacing: 16px;
spacing: 36px;
}
#searchResultsContent:rtl {
@ -723,25 +719,6 @@ StScrollBar StButton#vhandle:active {
padding-left: 20px;
}
.search-section {
/* This should be equal to #searchResultsContent spacing */
spacing: 16px;
}
.search-section-separator {
-gradient-height: 1px;
-gradient-start: rgba(255,255,255,0);
-gradient-end: rgba(255,255,255,0.5);
-margin-horizontal: 1.5em;
height: 1px;
}
.search-section-content {
/* This is the space between the provider icon and the results container */
spacing: 25px;
}
.search-statustext,
.search-section-header {
padding: 4px 12px;
spacing: 4px;
@ -767,14 +744,6 @@ StScrollBar StButton#vhandle:active {
spacing: 4px;
}
.search-providers-box {
spacing: 12px;
}
.results-list {
spacing: 5px;
}
/* Text labels are an odd number of pixels tall. The uneven top and bottom
* padding compensates for this and ensures that the label is vertically
* centered */
@ -855,10 +824,7 @@ StScrollBar StButton#vhandle:active {
.app-well-app > .overview-icon,
.show-apps > .overview-icon,
.remove-favorite > .overview-icon,
.search-section-icon-bin,
.search-result,
.grid-search-result-content > .overview-icon {
.search-result-content > .overview-icon {
border-radius: 4px;
padding: 3px;
border: 1px rgba(0,0,0,0);
@ -874,10 +840,7 @@ StScrollBar StButton#vhandle:active {
.app-well-app:hover > .overview-icon,
.show-apps:hover > .overview-icon,
.remove-favorite:hover > .overview-icon,
.search-section-icon-bin:hover,
.search-result:hover,
.grid-search-result-content:hover > .overview-icon {
.search-result-content:hover > .overview-icon {
background-color: rgba(255,255,255,0.1);
text-shadow: black 0px 2px 2px;
transition-duration: 100;
@ -912,39 +875,13 @@ StScrollBar StButton#vhandle:active {
}
.app-well-app:focus > .overview-icon,
.search-result-content:focus > .overview-icon,
.show-apps:focus > .overview-icon,
.search-section-icon-bin:focus,
.search-result:focus,
.grid-search-result-content:focus > .overview-icon,
.app-well-app:selected > .overview-icon,
.search-section-icon-bin:selected,
.search-result:selected,
.grid-search-result-content:selected > .overview-icon {
.search-result-content:selected > .overview-icon {
background-color: rgba(255,255,255,0.33);
}
/* List Results */
.search-result {
padding: 15px;
}
.search-result-content {
spacing: 12px;
}
.search-result-details {
font-weight: bold;
}
.search-result-details-title {
font-size: 16pt;
}
.search-result-details-description {
font-size: 14pt;
}
/* LookingGlass */
#LookingGlassDialog {

View File

@ -41,7 +41,6 @@ nobase_dist_js_DATA = \
ui/boxpointer.js \
ui/calendar.js \
ui/checkBox.js \
ui/centerLayout.js \
ui/ctrlAltTab.js \
ui/dash.js \
ui/dateMenu.js \

View File

@ -21,7 +21,16 @@ const GnomeShellIface = <interface name="org.gnome.Shell.Extensions">
</signal>
</interface>;
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
const GnomeShellProxy = new Gio.DBusProxyClass({
Name: 'GnomeShellProxy',
Interface: GnomeShellIface,
_init: function() {
this.parent({ g_bus_type: Gio.BusType.SESSION,
g_name: 'org.gnome.Shell',
g_object_path: '/org/gnome/Shell' });
}
});
function stripPrefix(string, prefix) {
if (string.slice(0, prefix.length) == prefix)
@ -191,7 +200,8 @@ const Application = new Lang.Class({
this._extensionPrefsBin.add(label);
this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
this._shellProxy = new GnomeShellProxy();
this._shellProxy.init(null);
this._shellProxy.connectSignal('ExtensionStatusChanged', Lang.bind(this, function(proxy, senderName, [uuid, state, error]) {
if (ExtensionUtils.extensions[uuid] !== undefined)
this._scanExtensions();

View File

@ -11,16 +11,14 @@ const FprintManagerIface = <interface name='net.reactivated.Fprint.Manager'>
</method>
</interface>;
const FprintManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(FprintManagerIface);
const FprintManager = new Gio.DBusProxyClass({
Name: 'FprintManager',
Interface: FprintManagerIface,
function FprintManager() {
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.system,
g_interface_name: FprintManagerInfo.name,
g_interface_info: FprintManagerInfo,
g_name: 'net.reactivated.Fprint',
g_object_path: '/net/reactivated/Fprint/Manager',
g_flags: (Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
self.init(null);
return self;
}
_init: function() {
this.parent({ g_bus_type: Gio.BusType.SYSTEM,
g_name: 'net.reactivated.Fprint',
g_object_path: '/net/reactivated/Fprint/Manager',
g_flags: (Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
}
});

View File

@ -1089,7 +1089,7 @@ const LoginDialog = new Lang.Class({
}));
},
_onNotListedClicked: function(user) {
_onNotListedClicked: function() {
let tasks = [function() {
return this._userList.hideItems();
},

View File

@ -35,7 +35,13 @@ const PowerMenuButton = new Lang.Class({
/* Translators: accessible name of the power menu in the login screen */
this.parent('system-shutdown-symbolic', _("Power"));
this._loginManager = LoginManager.getLoginManager();
LoginManager.getLoginManager(Lang.bind(this, function(manager) {
this._loginManager = manager;
this._updateHaveShutdown();
this._updateHaveRestart();
this._updateHaveSuspend();
}));
this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
this._settings.connect('changed::disable-restart-buttons',
@ -64,6 +70,12 @@ const PowerMenuButton = new Lang.Class({
},
_updateHaveShutdown: function() {
if (!this._loginManager) {
this._haveShutdown = false;
this._powerOffItem.actor.visible = false;
return;
}
this._loginManager.canPowerOff(Lang.bind(this, function(result) {
this._haveShutdown = result;
this._powerOffItem.actor.visible = this._haveShutdown;
@ -72,6 +84,12 @@ const PowerMenuButton = new Lang.Class({
},
_updateHaveRestart: function() {
if (!this._loginManager) {
this._haveRestart = false;
this._restartItem.actor.visible = false;
return;
}
this._loginManager.canReboot(Lang.bind(this, function(result) {
this._haveRestart = result;
this._restartItem.actor.visible = this._haveRestart;
@ -80,6 +98,12 @@ const PowerMenuButton = new Lang.Class({
},
_updateHaveSuspend: function() {
if (!this._loginManager) {
this._haveSuspend = false;
this._suspendItem.actor.visible = false;
return;
}
this._loginManager.canSuspend(Lang.bind(this, function(result) {
this._haveSuspend = result;
this._suspendItem.actor.visible = this._haveSuspend;

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
@ -16,7 +17,16 @@ const ProviderIface = <interface name='org.freedesktop.realmd.Provider'>
<arg name="realm" type="ao" direction="out"/>
</method>
</interface>;
const Provider = Gio.DBusProxy.makeProxyWrapper(ProviderIface);
const Provider = new Gio.DBusProxyClass({
Name: 'RealmdProvider',
Interface: ProviderIface,
_init: function() {
this.parent({ g_bus_type: Gio.BusType.SYSTEM,
g_name: 'org.freedesktop.realmd',
g_object_path: '/org/freedesktop/realmd' });
}
});
const ServiceIface = <interface name="org.freedesktop.realmd.Service">
<method name="Cancel">
@ -31,7 +41,16 @@ const ServiceIface = <interface name="org.freedesktop.realmd.Service">
<arg name="operation" type="s"/>
</signal>
</interface>;
const Service = Gio.DBusProxy.makeProxyWrapper(ServiceIface);
const Service = new Gio.DBusProxyClass({
Name: 'RealmdService',
Interface: ServiceIface,
_init: function(service) {
this.parent({ g_bus_type: Gio.BusType.SYSTEM,
g_name: 'org.freedesktop.realmd',
g_object_path: service });
}
});
const RealmIface = <interface name="org.freedesktop.realmd.Realm">
<property name="Name" type="s" access="read"/>
@ -51,16 +70,22 @@ const RealmIface = <interface name="org.freedesktop.realmd.Realm">
<arg name="options" type="a{sv}" direction="in"/>
</method>
</interface>;
const Realm = Gio.DBusProxy.makeProxyWrapper(RealmIface);
const Realm = new Gio.DBusProxyClass({
Name: 'RealmdRealm',
Interface: RealmIface,
_init: function(realm) {
this.parent({ g_bus_type: Gio.BusType.SYSTEM,
g_name: 'org.freedesktop.realmd',
g_object_path: realm });
}
});
const Manager = new Lang.Class({
Name: 'Manager',
_init: function(parentActor) {
this._aggregateProvider = Provider(Gio.DBus.system,
'org.freedesktop.realmd',
'/org/freedesktop/realmd',
Lang.bind(this, this._reloadRealms))
this._aggregateProvider = new Provider();
this._realms = {};
this._aggregateProvider.connect('g-properties-changed',
@ -68,6 +93,16 @@ const Manager = new Lang.Class({
if ('Realms' in properties.deep_unpack())
this._reloadRealms();
}));
this._aggregateProvider.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(proxy, result) {
try {
proxy.init_finish(result);
} catch(e) {
return;
}
this._reloadRealms();
}));
},
_reloadRealms: function() {
@ -77,10 +112,8 @@ const Manager = new Lang.Class({
return;
for (let i = 0; i < realmPaths.length; i++) {
let realm = Realm(Gio.DBus.system,
'org.freedesktop.realmd',
realmPaths[i],
Lang.bind(this, this._onRealmLoaded));
let realm = new Realm(realmPaths[i]);
realm.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, this._onRealmLoaded));
}
},
@ -97,9 +130,10 @@ const Manager = new Lang.Class({
this._updateLoginFormat();
},
_onRealmLoaded: function(realm, error) {
if (error)
return;
_onRealmLoaded: function(realm, result) {
try {
realm.init_finish(result);
} catch(e) { return; }
this._reloadRealm(realm);

View File

@ -82,6 +82,8 @@ const ShellUserVerifier = new Lang.Class({
this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
this._fprintManager = new Fprint.FprintManager();
this._fprintManager.init(null);
this._realmManager = new Realmd.Manager();
this._failCounter = 0;
@ -137,11 +139,14 @@ const ShellUserVerifier = new Lang.Class({
if (!this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY))
return;
this._fprintManager.GetDefaultDeviceRemote(Gio.DBusCallFlags.NONE, this._cancellable, Lang.bind(this,
function(device, error) {
if (!error && device)
this._haveFingerprintReader = true;
}));
this._fprintManager.GetDefaultDeviceRemote(this._cancellable, Lang.bind(this, function(manager, result) {
try {
let device = manager.GetDefaultDeviceFinish(result);
this._haveFingerprintReader = !!device;
} catch(e) {
this._haveFingerprintReader = false;
}
}));
},
_reportInitError: function(where, error) {

View File

@ -21,11 +21,16 @@ const PresenceStatus = {
IDLE: 3
};
var PresenceProxy = Gio.DBusProxy.makeProxyWrapper(PresenceIface);
function Presence(initCallback, cancellable) {
return new PresenceProxy(Gio.DBus.session, 'org.gnome.SessionManager',
'/org/gnome/SessionManager/Presence', initCallback, cancellable);
}
const Presence = new Gio.DBusProxyClass({
Name: 'GnomeSessionPresence',
Interface: PresenceIface,
_init: function() {
this.parent({ g_bus_type: Gio.BusType.SESSION,
g_name: 'org.gnome.SessionManager',
g_object_path: '/org/gnome/SessionManager/Presence' });
}
});
// Note inhibitors are immutable objects, so they don't
// change at runtime (changes always come in the form
@ -39,10 +44,16 @@ const InhibitorIface = <interface name="org.gnome.SessionManager.Inhibitor">
</method>
</interface>;
var InhibitorProxy = Gio.DBusProxy.makeProxyWrapper(InhibitorIface);
function Inhibitor(objectPath, initCallback, cancellable) {
return new InhibitorProxy(Gio.DBus.session, 'org.gnome.SessionManager', objectPath, initCallback, cancellable);
}
const Inhibitor = new Gio.DBusProxyClass({
Name: 'GnomeSessionInhibitor',
Interface: InhibitorIface,
_init: function(inhibitor) {
this.parent({ g_bus_type: Gio.BusType.SESSION,
g_name: 'org.gnome.SessionManager',
g_object_path: inhibitor });
}
});
// Not the full interface, only the methods we use
const SessionManagerIface = <interface name="org.gnome.SessionManager">
@ -66,7 +77,14 @@ const SessionManagerIface = <interface name="org.gnome.SessionManager">
</signal>
</interface>;
var SessionManagerProxy = Gio.DBusProxy.makeProxyWrapper(SessionManagerIface);
function SessionManager(initCallback, cancellable) {
return new SessionManagerProxy(Gio.DBus.session, 'org.gnome.SessionManager', '/org/gnome/SessionManager', initCallback, cancellable);
}
const SessionManager = new Gio.DBusProxyClass({
Name: 'GnomeSessionManager',
Interface: SessionManagerIface,
_init: function() {
this.parent({ g_bus_type: Gio.BusType.SESSION,
g_name: 'org.gnome.SessionManager',
g_object_path: '/org/gnome/SessionManager' });
},
});

View File

@ -2,6 +2,7 @@
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const GObject = imports.gi.GObject;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
@ -33,8 +34,26 @@ const SystemdLoginSessionIface = <interface name='org.freedesktop.login1.Session
<signal name='Unlock' />
</interface>;
const SystemdLoginManager = Gio.DBusProxy.makeProxyWrapper(SystemdLoginManagerIface);
const SystemdLoginSession = Gio.DBusProxy.makeProxyWrapper(SystemdLoginSessionIface);
const SystemdLoginManager = new Gio.DBusProxyClass({
Name: 'SystemdLoginManager',
Interface: SystemdLoginManagerIface,
_init: function() {
this.parent({ g_bus_type: Gio.BusType.SYSTEM,
g_name: 'org.freedesktop.login1',
g_object_path: '/org/freedesktop/login1' });
}
});
const SystemdLoginSession = new Gio.DBusProxyClass({
Name: 'SystemdLoginSession',
Interface: SystemdLoginSessionIface,
_init: function(session) {
this.parent({ g_bus_type: Gio.BusType.SYSTEM,
g_name: 'org.freedesktop.login1',
g_object_path: session });
}
});
const ConsoleKitManagerIface = <interface name='org.freedesktop.ConsoleKit.Manager'>
<method name='CanRestart'>
@ -61,51 +80,128 @@ const ConsoleKitSessionIface = <interface name='org.freedesktop.ConsoleKit.Sessi
<signal name='Unlock' />
</interface>;
const ConsoleKitSession = Gio.DBusProxy.makeProxyWrapper(ConsoleKitSessionIface);
const ConsoleKitManager = Gio.DBusProxy.makeProxyWrapper(ConsoleKitManagerIface);
const ConsoleKitSession = new Gio.DBusProxyClass({
Name: 'ConsoleKitSession',
Interface: ConsoleKitSessionIface,
_init: function(session) {
this.parent({ g_bus_type: Gio.BusType.SYSTEM,
g_name: 'org.freedesktop.ConsoleKit',
g_object_path: session });
}
});
const ConsoleKitManager = new Gio.DBusProxyClass({
Name: 'ConsoleKitManager',
Interface: ConsoleKitManagerIface,
_init: function() {
this.parent({ g_bus_type: Gio.BusType.SYSTEM,
g_name: 'org.freedesktop.ConsoleKit',
g_object_path: '/org/freedesktop/ConsoleKit/Manager' });
}
});
function haveSystemd() {
return GLib.access("/sys/fs/cgroup/systemd", 0) >= 0;
}
let _loginManager = null;
let _pendingAsyncCallbacks = [];
/**
* LoginManager:
* An abstraction over systemd/logind and ConsoleKit.
*
*/
function getLoginManager() {
function getLoginManager(asyncCallback) {
if (_loginManager == null) {
if (haveSystemd())
_loginManager = new LoginManagerSystemd();
else
_loginManager = new LoginManagerConsoleKit();
}
if (_pendingAsyncCallbacks.length == 0) {
let manager;
return _loginManager;
if (haveSystemd())
manager = new LoginManagerSystemd();
else
manager = new LoginManagerConsoleKit();
manager.initAsync(null, function(obj, result) {
obj.initFinish(result);
_loginManager = manager;
_pendingAsyncCallbacks.forEach(function (f) { f(obj) });
_pendingAsyncCallbacks = [];
});
_pendingAsyncCallbacks = [asyncCallback];
} else {
_pendingAsyncCallbacks.push(asyncCallback);
}
} else {
GLib.idle_add(GLib.PRIORITY_DEFAULT, function() {
asyncCallback(_loginManager);
});
}
}
const LoginManagerSystemd = new Lang.Class({
Name: 'LoginManagerSystemd',
Extends: GObject.Object,
_init: function() {
this._proxy = new SystemdLoginManager(Gio.DBus.system,
'org.freedesktop.login1',
'/org/freedesktop/login1');
this.parent();
this._proxy = new SystemdLoginManager();
},
initAsync: function(cancellable, asyncCallback) {
let simpleResult = Gio.SimpleAsyncResult.new(this, asyncCallback, null);
simpleResult.set_check_cancellable(cancellable);
this._proxy.init_async(GLib.PRIORITY_DEFAULT, cancellable, Lang.bind(this, function(proxy, result) {
try {
proxy.init_finish(result);
if (cancellable && cancellable.is_cancelled())
return;
this._fetchCurrentSession(cancellable, simpleResult);
} catch(e if e instanceof GLib.Error) {
simpleResult.set_from_error(e);
simpleResult.complete();
}
}));
},
initFinish: function(simpleResult) {
if (!simpleResult.propagate_error())
return simpleResult.get_op_res_gboolean();
return true;
},
_fetchCurrentSession: function(cancellable, simpleResult) {
this._currentSession = new SystemdLoginSession('/org/freedesktop/login1/session/' +
GLib.getenv('XDG_SESSION_ID'));
this._currentSession.init_async(GLib.PRIORITY_DEFAULT, cancellable, Lang.bind(this, function(proxy, result) {
try {
proxy.init_finish(result);
simpleResult.set_op_res_gboolean(true);
} catch(e if e instanceof GLib.Error) {
simpleResult.set_from_error(e);
}
simpleResult.complete();
}));
},
// Having this function is a bit of a hack since the Systemd and ConsoleKit
// session objects have different interfaces - but in both cases there are
// Lock/Unlock signals, and that's all we count upon at the moment.
//
// This is only valid after async initialization
getCurrentSessionProxy: function() {
if (!this._currentSession) {
this._currentSession = new SystemdLoginSession(Gio.DBus.system,
'org.freedesktop.login1',
'/org/freedesktop/login1/session/' +
GLib.getenv('XDG_SESSION_ID'));
}
return this._currentSession;
},
@ -114,66 +210,126 @@ const LoginManagerSystemd = new Lang.Class({
},
canPowerOff: function(asyncCallback) {
this._proxy.CanPowerOffRemote(function(result, error) {
if (error)
asyncCallback(false);
else
asyncCallback(result[0] != 'no');
this._proxy.CanPowerOffRemote(null, function(proxy, result) {
let val = false;
try {
val = proxy.CanPowerOffFinish(result)[0] != 'no';
} catch(e) { }
asyncCallback(val);
});
},
canReboot: function(asyncCallback) {
this._proxy.CanRebootRemote(function(result, error) {
if (error)
asyncCallback(false);
else
asyncCallback(result[0] != 'no');
this._proxy.CanRebootRemote(null, function(proxy, result) {
let val = false;
try {
val = proxy.CanRebootFinish(result)[0] != 'no';
} catch(e) { }
asyncCallback(val);
});
},
canSuspend: function(asyncCallback) {
this._proxy.CanSuspendRemote(function(result, error) {
if (error)
asyncCallback(false);
else
asyncCallback(result[0] != 'no');
this._proxy.CanSuspendRemote(null, function(proxy, result) {
let val = false;
try {
val = proxy.CanRebootFinish(result)[0] != 'no';
} catch(e) { }
asyncCallback(val);
});
},
powerOff: function() {
this._proxy.PowerOffRemote(true);
this._proxy.PowerOffRemote(true, null, null);
},
reboot: function() {
this._proxy.RebootRemote(true);
this._proxy.RebootRemote(true, null, null);
},
suspend: function() {
this._proxy.SuspendRemote(true);
this._proxy.SuspendRemote(true, null, null);
}
});
const LoginManagerConsoleKit = new Lang.Class({
Name: 'LoginManagerConsoleKit',
Extends: GObject.Object,
_init: function() {
this._proxy = new ConsoleKitManager(Gio.DBus.system,
'org.freedesktop.ConsoleKit',
'/org/freedesktop/ConsoleKit/Manager');
this.parent();
this._proxy = new ConsoleKitManager();
this._upClient = new UPowerGlib.Client();
},
initAsync: function(cancellable, asyncCallback) {
let simpleResult = Gio.SimpleAsyncResult.new(this, asyncCallback, null);
simpleResult.set_check_cancellable(cancellable);
this._proxy.init_async(GLib.PRIORITY_DEFAULT, cancellable, Lang.bind(this, function(proxy, result) {
try {
proxy.init_finish(result);
if (cancellable && cancellable.is_cancelled())
return;
this._fetchCurrentSession(cancellable, simpleResult);
} catch(e if e instanceof GLib.Error) {
simpleResult.set_from_error(e);
simpleResult.complete();
}
}));
},
initFinish: function(simpleResult) {
if (!simpleResult.propagate_error())
return simpleResult.get_op_res_gboolean();
return true;
},
_fetchCurrentSession: function(cancellable, simpleResult) {
this._proxy.GetCurrentSessionRemote(cancellable, Lang.bind(this, function(proxy, result) {
try {
let [currentSessionId] = proxy.GetCurrentSessionFinish(result);
if (cancellable && cancellable.is_cancelled())
return;
this._createSessionProxy(currentSessionId, cancellable, simpleResult);
} catch(e if e instanceof GLib.Error) {
simpleResult.set_from_error(e);
simpleResult.complete();
}
}));
},
_createSessionProxy: function(currentSessionId, cancellable, simpleResult) {
this._currentSession = new ConsoleKitSession(currentSessionId);
this._currentSession.init_async(GLib.PRIORITY_DEFAULT, cancellable, Lang.bind(this, function(proxy, result) {
try {
proxy.init_finish(result);
simpleResult.set_op_res_gboolean(true);
} catch(e if e instanceof GLib.Error) {
simpleResult.set_from_error(e);
}
simpleResult.complete();
}));
},
// Having this function is a bit of a hack since the Systemd and ConsoleKit
// session objects have different interfaces - but in both cases there are
// Lock/Unlock signals, and that's all we count upon at the moment.
getCurrentSessionProxy: function() {
if (!this._currentSession) {
let [currentSessionId] = this._proxy.GetCurrentSessionSync();
this._currentSession = new ConsoleKitSession(Gio.DBus.system,
'org.freedesktop.ConsoleKit',
currentSessionId);
}
return this._currentSession;
},
@ -185,26 +341,32 @@ const LoginManagerConsoleKit = new Lang.Class({
session.connectSignal('ActiveChanged', Lang.bind(this, function(object, senderName, [isActive]) {
this._sessionActive = isActive;
}));
[this._sessionActive] = session.IsActiveSync();
[this._sessionActive] = session.IsActiveSync(null);
return this._sessionActive;
},
canPowerOff: function(asyncCallback) {
this._proxy.CanStopRemote(function(result, error) {
if (error)
asyncCallback(false);
else
asyncCallback(result[0]);
this._proxy.CanStopRemote(null, function(proxy, result) {
let val = false;
try {
[val] = proxy.CanStopFinish(result);
} catch(e) { }
asyncCallback(val);
});
},
canReboot: function(asyncCallback) {
this._proxy.CanRestartRemote(function(result, error) {
if (error)
asyncCallback(false);
else
asyncCallback(result[0]);
this._proxy.CanRestartRemote(null, function(proxy, result) {
let val = false;
try {
[val] = proxy.CanRestartFinish(result);
} catch(e) { }
asyncCallback(val);
});
},
@ -216,11 +378,11 @@ const LoginManagerConsoleKit = new Lang.Class({
},
powerOff: function() {
this._proxy.StopRemote();
this._proxy.StopRemote(null, null);
},
reboot: function() {
this._proxy.RestartRemote();
this._proxy.RestartRemote(null, null);
},
suspend: function() {

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
@ -26,7 +27,16 @@ const ModemGsmNetworkInterface = <interface name="org.freedesktop.ModemManager.M
</signal>
</interface>;
const ModemGsmNetworkProxy = Gio.DBusProxy.makeProxyWrapper(ModemGsmNetworkInterface);
const ModemGsmNetworkProxy = new Gio.DBusProxyClass({
Name: 'ModemGsmNetworkProxy',
Interface: ModemGsmNetworkInterface,
_init: function(modem) {
this.parent({ g_bus_type: Gio.BusType.SYSTEM,
g_name: 'org.freedesktop.ModemManager',
g_object_path: modem });
}
});
const ModemCdmaInterface = <interface name="org.freedesktop.ModemManager.Modem.Cdma">
<method name="GetSignalQuality">
@ -40,7 +50,16 @@ const ModemCdmaInterface = <interface name="org.freedesktop.ModemManager.Modem.C
</signal>
</interface>;
const ModemCdmaProxy = Gio.DBusProxy.makeProxyWrapper(ModemCdmaInterface);
const ModemCdmaProxy = new Gio.DBusProxyClass({
Name: 'ModemCdmaProxy',
Interface: ModemCdmaInterface,
_init: function(modem) {
this.parent({ g_bus_type: Gio.BusType.SYSTEM,
g_name: 'org.freedesktop.ModemManager',
g_object_path: modem });
},
});
let _providersTable;
function _getProvidersTable() {
@ -54,11 +73,18 @@ const ModemGsm = new Lang.Class({
Name: 'ModemGsm',
_init: function(path) {
this._proxy = new ModemGsmNetworkProxy(Gio.DBus.system, 'org.freedesktop.ModemManager', path);
this._proxy = new ModemGsmNetworkProxy(path);
this._proxy.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(obj, result) {
obj.init_finish(result);
this._finishInit();
}));
this.signal_quality = 0;
this.operator_name = null;
},
_finishInit: function() {
// Code is duplicated because the function have different signatures
this._proxy.connectSignal('SignalQuality', Lang.bind(this, function(proxy, sender, [quality]) {
this.signal_quality = quality;
@ -68,24 +94,19 @@ const ModemGsm = new Lang.Class({
this.operator_name = this._findOperatorName(name, code);
this.emit('notify::operator-name');
}));
this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function([result], err) {
if (err) {
log(err);
return;
}
let [status, code, name] = result;
this._proxy.GetRegistrationInfoRemote(null, Lang.bind(this, function(proxy, result) {
let [status, code, name] = proxy.GetRegistrationInfoFinish(result);
this.operator_name = this._findOperatorName(name, code);
this.emit('notify::operator-name');
}));
this._proxy.GetSignalQualityRemote(Lang.bind(this, function(result, err) {
if (err) {
this._proxy.GetSignalQualityRemote(null, Lang.bind(this, function(proxy, result) {
try {
[this.signal_quality] = proxy.GetSignalQualityFinish(result);
} catch(e) {
// it will return an error if the device is not connected
this.signal_quality = 0;
} else {
let [quality] = result;
this.signal_quality = quality;
}
this.emit('notify::signal-quality');
}));
},
@ -157,10 +178,18 @@ const ModemCdma = new Lang.Class({
Name: 'ModemCdma',
_init: function(path) {
this._proxy = new ModemCdmaProxy(Gio.DBus.system, 'org.freedesktop.ModemManager', path);
this._proxy = new ModemCdmaProxy(path);
this._proxy.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(obj, result) {
obj.init_finish(result);
this._finishInit();
}));
this.signal_quality = 0;
this.operator_name = null;
},
_finishInit: function() {
this._proxy.connectSignal('SignalQuality', Lang.bind(this, function(proxy, sender, params) {
this.signal_quality = params[0];
this.emit('notify::signal-quality');
@ -170,30 +199,31 @@ const ModemCdma = new Lang.Class({
if (this.operator_name == null)
this._refreshServingSystem();
}));
this._proxy.GetSignalQualityRemote(Lang.bind(this, function(result, err) {
if (err) {
this._proxy.GetSignalQualityRemote(null, Lang.bind(this, function(proxy, result) {
try {
[this.signal_quality] = proxy.GetSignalQualityFinish(result);
} catch(e) {
// it will return an error if the device is not connected
this.signal_quality = 0;
} else {
let [quality] = result;
this.signal_quality = quality;
}
this.emit('notify::signal-quality');
}));
},
_refreshServingSystem: function() {
this._proxy.GetServingSystemRemote(Lang.bind(this, function([result], err) {
if (err) {
// it will return an error if the device is not connected
this.operator_name = null;
} else {
let [bandClass, band, id] = result;
this._proxy.GetServingSystemRemote(null, Lang.bind(this, function(proxy, result) {
try {
let [bandClass, band, name] = proxy.GetServingSystemFinish(result);
if (name.length > 0)
this.operator_name = this._findProviderForSid(id);
this.operator_name = this._findProviderForSid(name);
else
this.operator_name = null;
} catch(e) {
// it will return an error if the device is not connected
this.operator_name = null;
}
this.emit('notify::operator-name');
}));
},

View File

@ -1,7 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const GMenu = imports.gi.GMenu;
@ -372,8 +371,6 @@ const SettingsSearchProvider = new Lang.Class({
this._appSys = Shell.AppSystem.get_default();
this._gnomecc = this._appSys.lookup_app('gnome-control-center.desktop');
let appInfo = Gio.DesktopAppInfo.new('gnome-control-center.desktop');
this.icon = appInfo.get_icon();
},
getResultMetas: function(prefs, callback) {
@ -382,7 +379,9 @@ const SettingsSearchProvider = new Lang.Class({
let pref = prefs[i];
metas.push({ 'id': pref,
'name': pref.get_name(),
'createIcon': function(size) { return; }
'createIcon': function(size) {
return pref.create_icon_texture(size);
}
});
}
callback(metas);
@ -462,15 +461,15 @@ const AppWellIcon = new Lang.Class({
this._draggable.connect('drag-begin', Lang.bind(this,
function () {
this._removeMenuTimeout();
Main.overview.beginAppDrag(this);
Main.overview.beginItemDrag(this);
}));
this._draggable.connect('drag-cancelled', Lang.bind(this,
function () {
Main.overview.cancelledAppDrag(this);
Main.overview.cancelledItemDrag(this);
}));
this._draggable.connect('drag-end', Lang.bind(this,
function () {
Main.overview.endAppDrag(this);
Main.overview.endItemDrag(this);
}));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const St = imports.gi.St;
@ -200,19 +201,17 @@ const CalendarServerIface = <interface name="org.gnome.Shell.CalendarServer">
<signal name="Changed" />
</interface>;
const CalendarServerInfo = Gio.DBusInterfaceInfo.new_for_xml(CalendarServerIface);
const CalendarServer = new Gio.DBusProxyClass({
Name: 'CalendarServer',
Interface: CalendarServerIface,
function CalendarServer() {
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.session,
g_interface_name: CalendarServerInfo.name,
g_interface_info: CalendarServerInfo,
g_name: 'org.gnome.Shell.CalendarServer',
g_object_path: '/org/gnome/Shell/CalendarServer',
g_flags: Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES });
self.init(null);
return self;
}
_init: function() {
this.parent({ g_bus_type: Gio.BusType.SESSION,
g_name: 'org.gnome.Shell.CalendarServer',
g_object_path: '/org/gnome/Shell/CalendarServer',
g_flags: Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES });
}
});
function _datesEqual(a, b) {
if (a < b)
@ -242,11 +241,15 @@ const DBusEventSource = new Lang.Class({
this._dbusProxy = new CalendarServer();
this._dbusProxy.connectSignal('Changed', Lang.bind(this, this._onChanged));
this._dbusProxy.connect('notify::g-name-owner', Lang.bind(this, function() {
if (this._dbusProxy.g_name_owner)
this._onNameAppeared();
else
this._onNameVanished();
this._dbusProxy.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(proxy, result) {
try {
proxy.init_finish(result);
} catch(e) {
return;
}
this._resetCache();
this.emit('changed');
}));
},
@ -256,52 +259,52 @@ const DBusEventSource = new Lang.Class({
this._lastRequestEnd = null;
},
_onNameAppeared: function(owner) {
this._resetCache();
this._loadEvents(true);
},
_onNameVanished: function(oldOwner) {
this._resetCache();
this.emit('changed');
},
_onChanged: function() {
this._loadEvents(false);
},
_onEventsReceived: function(results, error) {
let newEvents = [];
let appointments = results ? results[0] : null;
if (appointments != null) {
for (let n = 0; n < appointments.length; n++) {
let a = appointments[n];
let date = new Date(a[4] * 1000);
let end = new Date(a[5] * 1000);
let summary = a[1];
let allDay = a[3];
let event = new CalendarEvent(date, end, summary, allDay);
newEvents.push(event);
}
newEvents.sort(function(event1, event2) {
return event1.date.getTime() - event2.date.getTime();
});
_onEventsReceived: function(proxy, result) {
let appointments;
try {
[appointments] = proxy.call_finish(result).deep_unpack();
} catch(e if e instanceof GLib.Error) {
// ignore errors coming from DBus
appointments = [];
}
let newEvents = [];
for (let n = 0; n < appointments.length; n++) {
let a = appointments[n];
let date = new Date(a[4] * 1000);
let end = new Date(a[5] * 1000);
let summary = a[1];
let allDay = a[3];
let event = new CalendarEvent(date, end, summary, allDay);
newEvents.push(event);
}
newEvents.sort(function(event1, event2) {
return event1.date.getTime() - event2.date.getTime();
});
this._events = newEvents;
this.emit('changed');
},
_loadEvents: function(forceReload) {
if (this._curRequestBegin && this._curRequestEnd){
/* Can't use GetEventsRemote because we need to pass the
flags here */
let callFlags = Gio.DBusCallFlags.NO_AUTO_START;
if (forceReload)
callFlags = Gio.DBusCallFlags.NONE;
this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
this._curRequestEnd.getTime() / 1000,
forceReload,
Lang.bind(this, this._onEventsReceived),
callFlags);
callFlags = Gio.DBusCallFlags.NONE;
this._dbusProxy.call("GetEvents",
GLib.Variant.new("(xxb)", [this._curRequestBegin.getTime() / 1000,
this._curRequestEnd.getTime() / 1000,
forceReload]),
callFlags,
-1,
null,
Lang.bind(this, this._onEventsReceived));
}
},
@ -394,7 +397,6 @@ const Calendar = new Lang.Class({
this._eventSourceChangedId = this._eventSource.connect('changed', Lang.bind(this, function() {
this._update(false);
}));
this._update(true);
}
},

View File

@ -1,93 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Lang = imports.lang;
const Clutter = imports.gi.Clutter;
const St = imports.gi.St;
function connectLayoutManager(layoutManager, styleChanged) {
let widget, styleChangedId;
function _styleChanged() {
let themeNode = widget.get_theme_node();
styleChanged(themeNode, widget);
}
function actorChanged() {
if (widget) {
widget.disconnect(styleChangedId);
styleChangedId = 0;
}
let actor = layoutManager.get_actor();
if (actor && actor instanceof St.Widget) {
widget = actor;
styleChangedId = widget.connect('style-changed', _styleChanged);
_styleChanged();
}
}
layoutManager.connect('notify::actor', actorChanged);
return layoutManager;
}
function connectSpacing(layoutManager) {
return connectLayoutManager(layoutManager, function(themeNode, widget) {
layoutManager.spacing = themeNode.get_length('spacing');
});
}
const CenterLayout = new Lang.Class({
Name: 'CenterLayout',
Extends: Clutter.BoxLayout,
vfunc_allocate: function(container, box, flags) {
let rtl = container.get_text_direction() == Clutter.TextDirection.RTL;
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
// Assume that these are the first three widgets and they are all visible.
let [left, center, right] = container.get_children();
// Only support horizontal layouts for now.
let [centerMinWidth, centerNaturalWidth] = center.get_preferred_width(availWidth);
let sideWidth = (availWidth - centerNaturalWidth) / 2;
let childBox = new Clutter.ActorBox();
childBox.y1 = box.y1;
childBox.y2 = box.y1 + availHeight;
if (left) {
let [leftMinWidth, leftNaturalWidth] = left.get_preferred_width(availWidth);
let leftSide = Math.min(Math.floor(sideWidth), leftNaturalWidth);
if (rtl) {
childBox.x1 = availWidth - leftSide;
childBox.x2 = availWidth;
} else {
childBox.x1 = 0;
childBox.x2 = leftSide;
}
childBox.x1 += box.x1;
left.allocate(childBox, flags);
}
childBox.x1 = box.x1 + Math.ceil(sideWidth);
childBox.x2 = childBox.x1 + centerNaturalWidth;
center.allocate(childBox, flags);
if (right) {
let [rightMinWidth, rightNaturalWidth] = right.get_preferred_width(availWidth);
let rightSide = Math.min(Math.floor(sideWidth), rightNaturalWidth);
if (rtl) {
childBox.x1 = 0;
childBox.x2 = rightSide;
} else {
childBox.x1 = availWidth - rightSide;
childBox.x2 = availWidth;
}
childBox.x1 += box.x1;
right.allocate(childBox, flags);
}
}
});

View File

@ -33,7 +33,9 @@ const AutomountManager = new Lang.Class({
Lang.bind(this, this._InhibitorsChanged));
this._inhibited = false;
this._loginManager = LoginManager.getLoginManager();
LoginManager.getLoginManager(Lang.bind(this, function(manager) {
this._loginManager = manager;
}));
this._volumeMonitor = Gio.VolumeMonitor.get();
},
@ -85,7 +87,7 @@ const AutomountManager = new Lang.Class({
_onDriveConnected: function() {
// if we're not in the current ConsoleKit session,
// or screensaver is active, don't play sounds
if (!this._loginManager.sessionActive)
if (!this._loginManager || !this._loginManager.sessionActive)
return;
global.play_theme_sound(0, 'device-added-media');
@ -94,7 +96,7 @@ const AutomountManager = new Lang.Class({
_onDriveDisconnected: function() {
// if we're not in the current ConsoleKit session,
// or screensaver is active, don't play sounds
if (!this._loginManager.sessionActive)
if (!this._loginManager || !this._loginManager.sessionActive)
return;
global.play_theme_sound(0, 'device-removed-media');
@ -103,7 +105,7 @@ const AutomountManager = new Lang.Class({
_onDriveEjectButton: function(monitor, drive) {
// TODO: this code path is not tested, as the GVfs volume monitor
// doesn't emit this signal just yet.
if (!this._loginManager.sessionActive)
if (!this._loginManager || !this._loginManager.sessionActive)
return;
// we force stop/eject in this case, so we don't have to pass a
@ -143,7 +145,7 @@ const AutomountManager = new Lang.Class({
if (params.checkSession) {
// if we're not in the current ConsoleKit session,
// don't attempt automount
if (!this._loginManager.sessionActive)
if (!this._loginManager || !this._loginManager.sessionActive)
return;
}

View File

@ -2,6 +2,7 @@
const Lang = imports.lang;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const St = imports.gi.St;
const LoginManager = imports.misc.loginManager;
@ -82,12 +83,16 @@ const HotplugSnifferIface = <interface name="org.gnome.Shell.HotplugSniffer">
</method>
</interface>;
const HotplugSnifferProxy = Gio.DBusProxy.makeProxyWrapper(HotplugSnifferIface);
function HotplugSniffer() {
return new HotplugSnifferProxy(Gio.DBus.session,
'org.gnome.Shell.HotplugSniffer',
'/org/gnome/Shell/HotplugSniffer');
}
const HotplugSniffer = new Gio.DBusProxyClass({
Name: 'HotplugSnifferProxy',
Interface: HotplugSnifferIface,
_init: function() {
this.parent({ g_bus_type: Gio.BusType.SESSION,
g_name: 'org.gnome.Shell.HotplugSniffer',
g_object_path: '/org/gnome/Shell/HotplugSniffer' });
}
});
const ContentTypeDiscoverer = new Lang.Class({
Name: 'ContentTypeDiscoverer',
@ -127,10 +132,14 @@ const ContentTypeDiscoverer = new Lang.Class({
let root = mount.get_root();
let hotplugSniffer = new HotplugSniffer();
hotplugSniffer.SniffURIRemote(root.get_uri(),
Lang.bind(this, function([contentTypes]) {
this._emitCallback(mount, contentTypes);
}));
hotplugSniffer.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(proxy, result) {
proxy.init_finish(result);
proxy.SniffURIRemote(root.get_uri(), null, Lang.bind(this, function(proxy, result) {
let [contentTypes] = proxy.SniffURIFinish(result);
this._emitCallback(mount, contentTypes);
}));
}));
}
},
@ -162,7 +171,9 @@ const AutorunManager = new Lang.Class({
Name: 'AutorunManager',
_init: function() {
this._loginManager = LoginManager.getLoginManager();
LoginManager.getLoginManager(Lang.bind(this, function(manager) {
this._loginManager = manager;
}));
this._volumeMonitor = Gio.VolumeMonitor.get();
@ -215,7 +226,7 @@ const AutorunManager = new Lang.Class({
_onMountAdded: function(monitor, mount) {
// don't do anything if our session is not the currently
// active one
if (!this._loginManager.sessionActive)
if (!this._loginManager || !this._loginManager.sessionActive)
return;
this._processMount(mount, true);

View File

@ -372,9 +372,6 @@ const Dash = new Lang.Class({
this._maxHeight = -1;
this.iconSize = 64;
this._shownInitially = false;
this.visible = false;
this._hiddenX;
this._targetX;
this._dragPlaceholder = null;
this._dragPlaceholderPos = -1;
@ -402,8 +399,7 @@ const Dash = new Lang.Class({
function() {
if (this._maxHeight != this.actor.height)
this._queueRedisplay();
if (this.actor.height > this._maxHeight)
this._maxHeight = this.actor.height;
this._maxHeight = this.actor.height;
}));
this._workId = Main.initializeDeferredWork(this._box, Lang.bind(this, this._redisplay));
@ -414,11 +410,11 @@ const Dash = new Lang.Class({
AppFavorites.getAppFavorites().connect('changed', Lang.bind(this, this._queueRedisplay));
this._appSystem.connect('app-state-changed', Lang.bind(this, this._queueRedisplay));
Main.overview.connect('app-drag-begin',
Main.overview.connect('item-drag-begin',
Lang.bind(this, this._onDragBegin));
Main.overview.connect('app-drag-end',
Main.overview.connect('item-drag-end',
Lang.bind(this, this._onDragEnd));
Main.overview.connect('app-drag-cancelled',
Main.overview.connect('item-drag-cancelled',
Lang.bind(this, this._onDragCancelled));
Main.overview.connect('window-drag-begin',
Lang.bind(this, this._onDragBegin));
@ -550,17 +546,6 @@ const Dash = new Lang.Class({
}
},
_computeDashX: function() {
this._targetX = this.actor.get_x();
let rtl = (this.actor.get_text_direction() == Clutter.TextDirection.RTL);
if (rtl)
this._hiddenX = this._targetX + this.actor.width;
else
this._hiddenX = -this.actor.width;
},
_adjustIconSize: function() {
// For the icon size, we only consider children which are "proper"
// icons (i.e. ignoring drag placeholders) and which are not
@ -656,8 +641,6 @@ const Dash = new Lang.Class({
}
});
}
this._computeDashX();
},
_redisplay: function () {
@ -774,7 +757,6 @@ const Dash = new Lang.Class({
// of items, to avoid all items zooming in at once
if (!this._shownInitially) {
this._shownInitially = true;
this.visible = true;
return;
}
@ -919,34 +901,6 @@ const Dash = new Lang.Class({
}));
return true;
},
show: function() {
if (this.visible)
return;
this.visible = true;
this.actor.show();
Tweener.addTween(this.actor, { translation_x: this._targetX,
transition: 'easeOutQuad',
time: DASH_ANIMATION_TIME
});
},
hide: function() {
if (!this.visible)
return;
this.visible = false;
Tweener.addTween(this.actor, { translation_x: this._hiddenX,
transition: 'easeOutQuad',
time: DASH_ANIMATION_TIME,
onComplete: Lang.bind(this, function () {
this.actor.hide();
})
});
}
});

View File

@ -105,7 +105,7 @@ const restartDialogContent = {
endDescription: _("Restarting the system."),
confirmButtons: [{ signal: 'ConfirmedReboot',
label: C_("button", "Restart") }],
iconName: 'system-shutdown-symbolic',
iconName: 'view-refresh-symbolic',
iconStyleClass: 'end-session-dialog-shutdown-icon'
};
@ -218,6 +218,34 @@ function init() {
_endSessionDialog = new EndSessionDialog();
}
const EndSessionExporter = new Gio.DBusImplementerClass({
Name: 'EndSessionExporter',
Interface: EndSessionDialogIface,
_init: function() {
this.parent();
this.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog');
},
OpenAsync: function(parameters, invocation) {
this.emit('open', parameters, invocation);
},
close: function() {
this.emit_signal('Closed');
},
cancel: function() {
this.emit_signal('Canceled');
},
confirm: function(type) {
this.emit_signal(type);
},
});
Signals.addSignalMethods(EndSessionExporter.prototype);
const EndSessionDialog = new Lang.Class({
Name: 'EndSessionDialog',
Extends: ModalDialog.ModalDialog,
@ -295,8 +323,8 @@ const EndSessionDialog = new Lang.Class({
scrollView.hide();
}));
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(EndSessionDialogIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog');
this._exporter = new EndSessionExporter();
this._exporter.connect('open', Lang.bind(this, this._onOpenRequest));
},
_onDestroy: function() {
@ -387,19 +415,19 @@ const EndSessionDialog = new Lang.Class({
close: function() {
this.parent();
this._dbusImpl.emit_signal('Closed', null);
this._exporter.close();
},
cancel: function() {
this._stopTimer();
this._dbusImpl.emit_signal('Canceled', null);
this._exporter.cancel();
this.close(global.get_current_time());
},
_confirm: function(signal) {
this._fadeOutDialog();
this._stopTimer();
this._dbusImpl.emit_signal(signal, null);
this._exporter.confirm(signal);
},
_onOpened: function() {
@ -452,7 +480,7 @@ const EndSessionDialog = new Lang.Class({
this._updateContent();
},
OpenAsync: function(parameters, invocation) {
_onOpenRequest: function(exporter, parameters, invocation) {
let [type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths] = parameters;
this._totalSecondsToStayOpen = totalSecondsToStayOpen;
this._inhibitors = [];
@ -466,7 +494,10 @@ const EndSessionDialog = new Lang.Class({
}
for (let i = 0; i < inhibitorObjectPaths.length; i++) {
let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i], Lang.bind(this, function(proxy, error) {
let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i]);
inhibitor.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(proxy, result) {
proxy.init_finish(result);
this._onInhibitorLoaded(proxy);
}));

View File

@ -198,11 +198,7 @@ const IconGrid = new Lang.Class({
_getPreferredHeight: function (grid, forWidth, alloc) {
let children = this._getVisibleChildren();
let nColumns;
if (forWidth < 0)
nColumns = children.length;
else
nColumns = this._computeLayout(forWidth)[0];
let [nColumns, usedWidth] = this._computeLayout(forWidth);
let nRows;
if (nColumns > 0)
nRows = Math.ceil(children.length / nColumns);

View File

@ -2,7 +2,6 @@
const Caribou = imports.gi.Caribou;
const Clutter = imports.gi.Clutter;
const DBus = imports.dbus;
const Gdk = imports.gi.Gdk;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
@ -191,13 +190,14 @@ const Key = new Lang.Class({
}
});
const Keyboard = new Lang.Class({
const Keyboard = new Gio.DBusImplementerClass({
// HACK: we can't set Name, because it collides with Name dbus property
// Name: 'Keyboard',
Interface: CaribouKeyboardIface,
_init: function () {
this._impl = Gio.DBusExportedObject.wrapJSObject(CaribouKeyboardIface, this);
this._impl.export(Gio.DBus.session, '/org/gnome/Caribou/Keyboard');
this.parent();
this.export(Gio.DBus.session, '/org/gnome/Caribou/Keyboard');
this.actor = null;
this._focusInTray = false;

View File

@ -96,14 +96,15 @@ const ZoomRegionIface = <interface name={ZOOM_SERVICE_NAME}>
// '/org/gnome/Magnifier/ZoomRegion/zoomer1', etc.
let _zoomRegionInstanceCount = 0;
const ShellMagnifier = new Lang.Class({
const ShellMagnifier = new Gio.DBusImplementerClass({
Name: 'ShellMagnifier',
Interface: MagnifierIface,
_init: function() {
this._zoomers = {};
this.parent();
this.export(Gio.DBus.session, MAG_SERVICE_PATH);
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(MagnifierIface, this);
this._dbusImpl.export(Gio.DBus.session, MAG_SERVICE_PATH);
this._zoomers = {};
},
/**
@ -332,14 +333,15 @@ const ShellMagnifier = new Lang.Class({
* @zoomerObjectPath: String that is the path to a DBus ZoomRegion.
* @zoomRegion: The actual zoom region associated with the object path.
*/
const ShellMagnifierZoomRegion = new Lang.Class({
const ShellMagnifierZoomRegion = new Gio.DBusImplementerClass({
Name: 'ShellMagnifierZoomRegion',
Interface: ZoomRegionIface,
_init: function(zoomerObjectPath, zoomRegion) {
this._zoomRegion = zoomRegion;
this.parent();
this.export(Gio.DBus.session, zoomerObjectPath);
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ZoomRegionIface, this);
this._dbusImpl.export(Gio.DBus.session, zoomerObjectPath);
this._zoomRegion = zoomRegion;
},
/**
@ -417,6 +419,6 @@ const ShellMagnifierZoomRegion = new Lang.Class({
},
destroy: function() {
this._dbusImpl.unexport();
this.unexport();
}
});

View File

@ -1365,13 +1365,16 @@ const MessageTray = new Lang.Class({
Name: 'MessageTray',
_init: function() {
this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) {
this._presence = new GnomeSession.Presence();
this._presence.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(proxy, result) {
proxy.init_finish(result);
this._onStatusChanged(proxy.status);
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
this._onStatusChanged(status);
}));
}));
this._busy = false;
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
this._onStatusChanged(status);
}));
this.actor = new St.Widget({ name: 'message-tray',
reactive: true,
@ -1498,7 +1501,7 @@ const MessageTray = new Lang.Class({
this._overviewVisible = true;
this._grabHelper.ungrab(); // drop modal grab if necessary
this.actor.add_style_pseudo_class('overview');
this.show();
this._updateState();
}));
Main.overview.connect('hiding', Lang.bind(this,
function() {
@ -1736,11 +1739,6 @@ const MessageTray = new Lang.Class({
this._updateState();
},
show: function() {
this._traySummoned = true;
this._updateState();
},
_onNotify: function(source, notification) {
if (this._summaryBoxPointerItem && this._summaryBoxPointerItem.source == source) {
if (this._summaryBoxPointerState == State.HIDING) {
@ -1983,7 +1981,7 @@ const MessageTray = new Lang.Class({
}
// Summary
let summarySummoned = this._pointerInSummary || this._traySummoned;
let summarySummoned = this._pointerInSummary || this._overviewVisible || this._traySummoned;
let summaryPinned = this._pointerInTray || summarySummoned || this._locked;
let summaryHovered = this._pointerInTray || this._pointerInSummary;
@ -1991,7 +1989,7 @@ const MessageTray = new Lang.Class({
this._notificationState == State.SHOWN);
let notificationsDone = !notificationsVisible && !notificationsPending;
let summaryOptionalInOverview = !this._locked && !summaryHovered;
let summaryOptionalInOverview = this._overviewVisible && !this._locked && !summaryHovered;
let mustHideSummary = (notificationsPending && (notificationUrgent || summaryOptionalInOverview))
|| notificationsVisible || !Main.sessionMode.hasNotifications;

View File

@ -25,10 +25,19 @@ const BusIface = <interface name="org.freedesktop.DBus">
</method>
</interface>;
var BusProxy = Gio.DBusProxy.makeProxyWrapper(BusIface);
function Bus() {
return new BusProxy(Gio.DBus.session, 'org.freedesktop.DBus', '/org/freedesktop/DBus');
}
const Bus = new Gio.DBusProxyClass({
Name: 'SessionBusProxy',
Interface: BusIface,
_init: function() {
this.parent({ g_bus_type: Gio.BusType.SESSION,
g_name: 'org.freedesktop.DBus',
g_object_path: '/org/freedesktop/DBus',
g_flags: (Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES |
Gio.DBusProxyFlags.DO_NOT_CONNECT_SIGNALS |
Gio.DBusProxyFlags.DO_NOT_AUTO_START) });
}
});
const NotificationDaemonIface = <interface name="org.freedesktop.Notifications">
<method name="Notify">
@ -103,17 +112,20 @@ const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
'ibus-ui-gtk': 'keyboard'
};
const NotificationDaemon = new Lang.Class({
const NotificationDaemon = new Gio.DBusImplementerClass({
Name: 'NotificationDaemon',
Interface: NotificationDaemonIface,
_init: function() {
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(NotificationDaemonIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
this.parent();
this.export(Gio.DBus.session, '/org/freedesktop/Notifications');
this._sources = [];
this._senderToPid = {};
this._notifications = {};
this._busProxy = new Bus();
// This is synchronous but fast because of the flags we use.
this._busProxy.init(null);
this._trayManager = new Shell.TrayManager();
this._trayIconAddedId = this._trayManager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
@ -316,18 +328,20 @@ const NotificationDaemon = new Lang.Class({
return invocation.return_value(GLib.Variant.new('(u)', [id]));;
}
this._busProxy.GetConnectionUnixProcessIDRemote(sender, Lang.bind(this, function (result, excp) {
this._busProxy.GetConnectionUnixProcessIDRemote(sender, null, Lang.bind(this, function (proxy, result) {
// The app may have updated or removed the notification
ndata = this._notifications[id];
if (!ndata)
return;
if (excp) {
let pid;
try {
[pid] = proxy.GetConnectionUnixProcessIDFinish(result);
} catch(excp) {
logError(excp, 'Call to GetConnectionUnixProcessID failed');
return;
}
let [pid] = result;
source = this._getSource(appName, pid, ndata, sender, null);
// We only store sender-pid entries for persistent sources.
@ -487,13 +501,11 @@ const NotificationDaemon = new Lang.Class({
},
_emitNotificationClosed: function(id, reason) {
this._dbusImpl.emit_signal('NotificationClosed',
GLib.Variant.new('(uu)', [id, reason]));
this.emit_signal('NotificationClosed', id, reason);
},
_emitActionInvoked: function(id, action) {
this._dbusImpl.emit_signal('ActionInvoked',
GLib.Variant.new('(us)', [id, action]));
this.emit_signal('ActionInvoked', id, action);
},
_onTrayIconAdded: function(o, icon) {

View File

@ -10,7 +10,6 @@ const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Gdk = imports.gi.Gdk;
const CenterLayout = imports.ui.centerLayout;
const Dash = imports.ui.dash;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
@ -24,6 +23,9 @@ const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
// Time for initial animation going into Overview mode
const ANIMATION_TIME = 0.25;
// XXX -- grab this automatically. Hard to do.
const DASH_MAX_WIDTH = 96;
const DND_WINDOW_SWITCH_TIMEOUT = 1250;
const SwipeScrollDirection = {
@ -117,18 +119,23 @@ const Overview = new Lang.Class({
this._desktopFade = new St.Bin();
global.overlay_group.add_actor(this._desktopFade);
this._spacing = 0;
/* Translators: This is the main view to select
activities. See also note for "Activities" string. */
this._overview = new St.BoxLayout({ name: 'overview',
accessible_name: _("Overview"),
reactive: true,
vertical: true });
this._overview._delegate = this;
let layout = new CenterLayout.CenterLayout();
CenterLayout.connectSpacing(layout);
this._group = new St.Widget({ name: 'overview-group',
layout_manager: layout });
this._group = new St.Widget({ name: 'overview',
accessible_name: _("Overview"),
reactive: true });
this._group._delegate = this;
this._group.connect('style-changed',
Lang.bind(this, function() {
let node = this._group.get_theme_node();
let spacing = node.get_length('spacing');
if (spacing != this._spacing) {
this._spacing = spacing;
this._relayout();
}
}));
this._scrollDirection = SwipeScrollDirection.NONE;
this._scrollAdjustment = null;
@ -141,19 +148,18 @@ const Overview = new Lang.Class({
this._modal = false; // have a modal grab
this.animationInProgress = false;
this._hideInProgress = false;
this.searchActive = false;
this.appsActive = false;
// During transitions, we raise this to the top to avoid having the overview
// area be reactive; it causes too many issues such as double clicks on
// Dash elements, or mouseover handlers in the workspaces.
this._coverPane = new Clutter.Rectangle({ opacity: 0,
reactive: true });
this._overview.add_actor(this._coverPane);
this._group.add_actor(this._coverPane);
this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return true; }));
this._overview.hide();
global.overlay_group.add_actor(this._overview);
this._group.hide();
global.overlay_group.add_actor(this._group);
this._coverPane.hide();
@ -165,8 +171,6 @@ const Overview = new Lang.Class({
Main.xdndHandler.connect('drag-begin', Lang.bind(this, this._onDragBegin));
Main.xdndHandler.connect('drag-end', Lang.bind(this, this._onDragEnd));
global.screen.connect('restacked', Lang.bind(this, this._onRestacked));
this._windowSwitchTimeoutId = 0;
this._windowSwitchTimestamp = 0;
this._lastActiveWorkspaceIndex = -1;
@ -189,13 +193,6 @@ const Overview = new Lang.Class({
this._shellInfo = new ShellInfo();
// Add a clone of the panel to the overview so spacing and such is
// automatic
this._panelGhost = new St.Bin({ child: new Clutter.Clone({ source: Main.panel.actor }),
reactive: false,
opacity: 0 });
this._overview.add_actor(this._panelGhost);
this._searchEntry = new St.Entry({ name: 'searchEntry',
/* Translators: this is the text displayed
in the search entry when no search is
@ -204,13 +201,16 @@ const Overview = new Lang.Class({
hint_text: _("Type to search..."),
track_hover: true,
can_focus: true });
this._searchEntryBin = new St.Bin({ child: this._searchEntry,
x_align: St.Align.MIDDLE });
this._overview.add_actor(this._searchEntryBin);
this._group.add_actor(this._searchEntry);
this._dash = new Dash.Dash();
this._viewSelector = new ViewSelector.ViewSelector(this._searchEntry,
this._dash.showAppsButton);
this._group.add_actor(this._viewSelector.actor);
this._group.add_actor(this._dash.actor);
// TODO - recalculate everything when desktop size changes
this._dash = new Dash.Dash();
this._group.add_actor(this._dash.actor);
this._dash.actor.add_constraint(this._viewSelector.constrainHeight);
this.dashIconSize = this._dash.iconSize;
this._dash.connect('icon-size-changed',
Lang.bind(this, function() {
@ -221,82 +221,6 @@ const Overview = new Lang.Class({
// the left of the overview
Main.ctrlAltTabManager.addGroup(this._dash.actor, _("Dash"), 'user-bookmarks-symbolic');
this._viewSelector = new ViewSelector.ViewSelector(this._searchEntry,
this._dash.showAppsButton);
this._group.add_actor(this._viewSelector.actor);
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
this._group.add_actor(this._thumbnailsBox.actor);
// TODO: unique icon
Main.ctrlAltTabManager.addGroup(this._thumbnailsBox.actor, _("Workspaces"), 'user-bookmarks-symbolic');
// Add our same-line elements after the search entry
this._overview.add_actor(this._group);
// Then account for message tray
this._messageTrayGhost = new St.Bin({ child: new Clutter.Clone({ source: Main.messageTray.actor }),
reactive: false,
opacity: 0 });
this._overview.add_actor(this._messageTrayGhost);
this._viewSelector.connect('search-begin', Lang.bind(this,
function() {
this.searchActive = true;
this._dash.hide();
this._thumbnailsBox.hide();
Main.messageTray.hide();
}));
this._viewSelector.connect('search-cancelled', Lang.bind(this,
function() {
this.searchActive = false;
this._dash.show();
this._thumbnailsBox.show();
// search-cancelled is emitted if we leave the overview
// directly from searching. That means the message tray will
// be shown when we reach the workspace. Don't do this, only
// show the message tray on search-cancelled if we are still
// in the overview/not transitioning out of it.
if (this.visible && !this.animationInProgress)
Main.messageTray.show();
}));
this._viewSelector.connect('apps-button-checked', Lang.bind(this,
function(vs, checked) {
this.appsActive = checked;
if (checked) {
this._thumbnailsBox.hide();
Main.messageTray.hide();
} else {
this._thumbnailsBox.show();
if (this.visible && !this.animationInProgress)
Main.messageTray.show();
}
}));
this.connect('app-drag-begin',
Lang.bind(this, function () {
this._dash.show();
this._thumbnailsBox.show();
}));
this.connect('app-drag-cancelled',
Lang.bind(this, function () {
if (this.searchActive) {
this._dash.hide();
this._thumbnailsBox.hide();
} else if (this.appsActive) {
this._thumbnailsBox.hide();
}
}));
this.connect('app-drag-end',
Lang.bind(this, function () {
if (this.searchActive) {
this._dash.hide();
this._thumbnailsBox.hide();
} else if (this.appsActive) {
this._thumbnailsBox.hide();
}
}));
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._relayout));
this._relayout();
},
@ -562,41 +486,55 @@ const Overview = new Lang.Class({
this.hide();
let primary = Main.layoutManager.primaryMonitor;
let rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL);
let contentY = Main.panel.actor.height;
let contentHeight = primary.height - contentY - Main.messageTray.actor.height;
this._overview.set_position(primary.x, primary.y);
this._overview.set_size(primary.width, primary.height);
this._group.set_position(primary.x, primary.y);
this._group.set_size(primary.width, primary.height);
this._coverPane.set_position(0, contentY);
this._coverPane.set_size(primary.width, contentHeight);
},
_onRestacked: function() {
let stack = global.get_window_actors();
let stackIndices = {};
let searchWidth = this._searchEntry.get_width();
let searchHeight = this._searchEntry.get_height();
let searchX = (primary.width - searchWidth) / 2;
let searchY = contentY + this._spacing;
for (let i = 0; i < stack.length; i++) {
// Use the stable sequence for an integer to use as a hash key
stackIndices[stack[i].get_meta_window().get_stable_sequence()] = i;
let dashWidth = DASH_MAX_WIDTH;
let dashY = searchY + searchHeight + this._spacing;
let dashX;
if (rtl) {
this._dash.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
dashX = primary.width;
} else {
dashX = 0;
}
this.emit('sync-window-stacking', stackIndices);
let viewX = rtl ? 0 : dashWidth + this._spacing;
let viewY = searchY + searchHeight + this._spacing;
let viewWidth = primary.width - dashWidth - this._spacing;
let viewHeight = contentHeight - this._spacing - viewY;
this._searchEntry.set_position(searchX, searchY);
this._dash.actor.set_position(dashX, dashY);
this._viewSelector.actor.set_position(viewX, viewY);
this._viewSelector.actor.set_size(viewWidth, viewHeight);
},
//// Public methods ////
beginAppDrag: function(source) {
this.emit('app-drag-begin');
beginItemDrag: function(source) {
this.emit('item-drag-begin');
},
cancelledAppDrag: function(source) {
this.emit('app-drag-cancelled');
cancelledItemDrag: function(source) {
this.emit('item-drag-cancelled');
},
endAppDrag: function(source) {
this.emit('app-drag-end');
endItemDrag: function(source) {
this.emit('item-drag-end');
},
beginWindowDrag: function(source) {
@ -620,13 +558,13 @@ const Overview = new Lang.Class({
if (this._shown)
return;
// Do this manually instead of using _syncInputMode, to handle failure
if (!Main.pushModal(this._overview))
if (!Main.pushModal(this._group))
return;
this._modal = true;
this._animateVisible();
this._shown = true;
this._buttonPressId = this._overview.connect('button-press-event',
this._buttonPressId = this._group.connect('button-press-event',
Lang.bind(this, this._onButtonPress));
},
@ -670,12 +608,12 @@ const Overview = new Lang.Class({
// Disable unredirection while in the overview
Meta.disable_unredirect_for_screen(global.screen);
global.window_group.hide();
this._overview.show();
this._group.show();
this._background.show();
this._viewSelector.show();
this._overview.opacity = 0;
Tweener.addTween(this._overview,
this._group.opacity = 0;
Tweener.addTween(this._group,
{ opacity: 255,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
@ -729,7 +667,7 @@ const Overview = new Lang.Class({
this._syncInputMode();
if (this._buttonPressId > 0)
this._overview.disconnect(this._buttonPressId);
this._group.disconnect(this._buttonPressId);
this._buttonPressId = 0;
},
@ -771,20 +709,20 @@ const Overview = new Lang.Class({
if (this._shown) {
if (!this._modal) {
if (Main.pushModal(this._overview))
if (Main.pushModal(this._group))
this._modal = true;
else
this.hide();
}
} else if (this._shownTemporarily) {
if (this._modal) {
Main.popModal(this._overview);
Main.popModal(this._group);
this._modal = false;
}
global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
} else {
if (this._modal) {
Main.popModal(this._overview);
Main.popModal(this._group);
this._modal = false;
}
else if (global.stage_input_mode == Shell.StageInputMode.FULLSCREEN)
@ -802,7 +740,7 @@ const Overview = new Lang.Class({
this._viewSelector.zoomFromOverview();
// Make other elements fade out.
Tweener.addTween(this._overview,
Tweener.addTween(this._group,
{ opacity: 0,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
@ -844,7 +782,7 @@ const Overview = new Lang.Class({
this._viewSelector.hide();
this._desktopFade.hide();
this._background.hide();
this._overview.hide();
this._group.hide();
this.visible = false;
this.animationInProgress = false;

View File

@ -15,7 +15,6 @@ const Signals = imports.signals;
const Atk = imports.gi.Atk;
const CenterLayout = imports.ui.centerLayout;
const Config = imports.misc.config;
const CtrlAltTab = imports.ui.ctrlAltTab;
const DND = imports.ui.dnd;
@ -932,47 +931,12 @@ try {
log('NMApplet is not supported. It is possible that your NetworkManager version is too old');
}
const PanelLayout = new Lang.Class({
Name: 'PanelLayout',
Extends: CenterLayout.CenterLayout,
vfunc_allocate: function(container, box, flags) {
this.parent(container, box, flags);
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
let [left, center, right, leftCorner, rightCorner] = container.get_children();
let childBox = new Clutter.ActorBox();
let cornerMinWidth, cornerMinHeight;
let cornerWidth, cornerHeight;
[cornerMinWidth, cornerWidth] = leftCorner.get_preferred_width(-1);
[cornerMinHeight, cornerHeight] = leftCorner.get_preferred_height(-1);
childBox.x1 = 0;
childBox.x2 = cornerWidth;
childBox.y1 = availHeight;
childBox.y2 = availHeight + cornerHeight;
leftCorner.allocate(childBox, flags);
[cornerMinWidth, cornerWidth] = rightCorner.get_preferred_width(-1);
[cornerMinHeight, cornerHeight] = rightCorner.get_preferred_height(-1);
childBox.x1 = availWidth - cornerWidth;
childBox.x2 = availWidth;
childBox.y1 = availHeight;
childBox.y2 = availHeight + cornerHeight;
rightCorner.allocate(childBox, flags);
}
});
const Panel = new Lang.Class({
Name: 'Panel',
_init : function() {
this.actor = new St.Widget({ name: 'panel',
reactive: true,
layoutManager: new PanelLayout() });
this.actor = new Shell.GenericContainer({ name: 'panel',
reactive: true });
this.actor._delegate = this;
this.statusArea = {};
@ -997,6 +961,7 @@ const Panel = new Lang.Class({
this._leftCorner = new PanelCorner(this._rightBox, St.Side.LEFT);
else
this._leftCorner = new PanelCorner(this._leftBox, St.Side.LEFT);
this.actor.add_actor(this._leftCorner.actor);
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL)
@ -1005,6 +970,9 @@ const Panel = new Lang.Class({
this._rightCorner = new PanelCorner(this._rightBox, St.Side.RIGHT);
this.actor.add_actor(this._rightCorner.actor);
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
this.actor.connect('allocate', Lang.bind(this, this._allocate));
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
Main.layoutManager.panelBox.add(this.actor);
@ -1015,6 +983,83 @@ const Panel = new Lang.Class({
this._updatePanel();
},
_getPreferredWidth: function(actor, forHeight, alloc) {
alloc.min_size = -1;
alloc.natural_size = Main.layoutManager.primaryMonitor.width;
},
_getPreferredHeight: function(actor, forWidth, alloc) {
// We don't need to implement this; it's forced by the CSS
alloc.min_size = -1;
alloc.natural_size = -1;
},
_allocate: function(actor, box, flags) {
let allocWidth = box.x2 - box.x1;
let allocHeight = box.y2 - box.y1;
let [leftMinWidth, leftNaturalWidth] = this._leftBox.get_preferred_width(-1);
let [centerMinWidth, centerNaturalWidth] = this._centerBox.get_preferred_width(-1);
let [rightMinWidth, rightNaturalWidth] = this._rightBox.get_preferred_width(-1);
let sideWidth, centerWidth;
centerWidth = centerNaturalWidth;
sideWidth = (allocWidth - centerWidth) / 2;
let childBox = new Clutter.ActorBox();
childBox.y1 = 0;
childBox.y2 = allocHeight;
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL) {
childBox.x1 = allocWidth - Math.min(Math.floor(sideWidth),
leftNaturalWidth);
childBox.x2 = allocWidth;
} else {
childBox.x1 = 0;
childBox.x2 = Math.min(Math.floor(sideWidth),
leftNaturalWidth);
}
this._leftBox.allocate(childBox, flags);
childBox.x1 = Math.ceil(sideWidth);
childBox.y1 = 0;
childBox.x2 = childBox.x1 + centerWidth;
childBox.y2 = allocHeight;
this._centerBox.allocate(childBox, flags);
childBox.y1 = 0;
childBox.y2 = allocHeight;
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL) {
childBox.x1 = 0;
childBox.x2 = Math.min(Math.floor(sideWidth),
rightNaturalWidth);
} else {
childBox.x1 = allocWidth - Math.min(Math.floor(sideWidth),
rightNaturalWidth);
childBox.x2 = allocWidth;
}
this._rightBox.allocate(childBox, flags);
let cornerMinWidth, cornerMinHeight;
let cornerWidth, cornerHeight;
[cornerMinWidth, cornerWidth] = this._leftCorner.actor.get_preferred_width(-1);
[cornerMinHeight, cornerHeight] = this._leftCorner.actor.get_preferred_height(-1);
childBox.x1 = 0;
childBox.x2 = cornerWidth;
childBox.y1 = allocHeight;
childBox.y2 = allocHeight + cornerHeight;
this._leftCorner.actor.allocate(childBox, flags);
[cornerMinWidth, cornerWidth] = this._rightCorner.actor.get_preferred_width(-1);
[cornerMinHeight, cornerHeight] = this._rightCorner.actor.get_preferred_height(-1);
childBox.x1 = allocWidth - cornerWidth;
childBox.x2 = allocWidth;
childBox.y1 = allocHeight;
childBox.y2 = allocHeight + cornerHeight;
this._rightCorner.actor.allocate(childBox, flags);
},
_onButtonPress: function(actor, event) {
if (event.get_source() != actor)
return false;

View File

@ -404,17 +404,9 @@ const PopupSeparatorMenuItem = new Lang.Class({
this.parent({ reactive: false,
can_focus: false});
this._separator = new HorzSeparator({ style_class: 'popup-separator-menu-item' });
this.addActor(this._separator.actor, { span: -1, expand: true });
}
});
const HorzSeparator = new Lang.Class({
Name: 'HorzSeparator',
_init: function (params) {
this.actor = new St.DrawingArea(params);
this.actor.connect('repaint', Lang.bind(this, this._onRepaint));
this._drawingArea = new St.DrawingArea({ style_class: 'popup-separator-menu-item' });
this.addActor(this._drawingArea, { span: -1, expand: true });
this._drawingArea.connect('repaint', Lang.bind(this, this._onRepaint));
},
_onRepaint: function(area) {

View File

@ -27,13 +27,17 @@ const SearchProviderIface = <interface name="org.gnome.Shell.SearchProvider">
<method name="ActivateResult">
<arg type="s" direction="in" />
</method>
<method name="LaunchSearch">
<arg type="as" direction="in" />
</method>
</interface>;
var SearchProviderProxy = Gio.DBusProxy.makeProxyWrapper(SearchProviderIface);
var SearchProviderProxy = new Gio.DBusProxyClass({
Name: 'SearchProviderProxy',
Interface: SearchProviderIface,
_init: function(params) {
params.g_bus_type = Gio.BusType.SESSION;
this.parent(params);
}
});
function loadRemoteSearchProviders(addProviderCallback) {
let dataDirs = GLib.get_system_data_dirs();
@ -93,13 +97,22 @@ function loadRemoteSearchProvidersFromDir(dir, loadedProviders, addProviderCallb
icon,
busName,
objectPath);
remoteProvider.initAsync(null, function(obj, result) {
try {
remoteProvider.initFinish(result);
} catch(e) {
log('Failed to add search provider "%s": %s'.format(title, e.toString()));
return;
}
addProviderCallback(remoteProvider);
});
loadedProviders[objectPath] = remoteProvider;
} catch(e) {
log('Failed to add search provider "%s": %s'.format(title, e.toString()));
continue;
}
addProviderCallback(remoteProvider);
}
}));
@ -110,12 +123,39 @@ const RemoteSearchProvider = new Lang.Class({
Extends: Search.SearchProvider,
_init: function(title, icon, dbusName, dbusPath) {
this._proxy = new SearchProviderProxy(Gio.DBus.session,
dbusName, dbusPath);
this.parent(title.toUpperCase());
this._proxy = new SearchProviderProxy({ g_name: dbusName,
g_object_path: dbusPath });
this._cancellable = new Gio.Cancellable();
this.icon = icon;
},
initAsync: function(cancellable, asyncCallback) {
// Can't pass "this" as source object, because RemoteSearchProvider
// is not a GObject.Object (and in gjs you can't inherit from a JS
// type that in turn inherits from GObject)
let simpleResult = Gio.SimpleAsyncResult.new(null, asyncCallback, null);
simpleResult.set_check_cancellable(cancellable);
this._proxy.init_async(GLib.PRIORITY_DEFAULT, cancellable, Lang.bind(this, function(proxy, result) {
try {
proxy.init_finish(result);
simpleResult.set_op_res_gboolean(true);
} catch(e if e instanceof GLib.Error) {
simpleResult.set_from_error(e);
}
simpleResult.complete();
}));
},
initFinish: function(simpleResult) {
if (!simpleResult.propagate_error())
return simpleResult.get_op_res_gboolean();
return false;
},
createIcon: function(size, meta) {
@ -130,13 +170,22 @@ const RemoteSearchProvider = new Lang.Class({
width, height, rowStride, size);
}
return null;
// Ugh, but we want to fall back to something ...
return new St.Icon({ icon_name: 'text-x-generic',
icon_size: size });
},
_getResultsFinished: function(results, error) {
if (error)
return;
this.searchSystem.pushResults(this, results[0]);
_getResultsFinished: function(proxy, result) {
try {
// We rely on a small implementation detail of the
// GDBus bindings here: all *Finish are equal
let [results] = proxy.GetInitialResultSetFinish(result);
this.searchSystem.pushResults(this, results);
} catch(e) {
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
log('Received error from search provider %s: %s'.format(this.title, String(e)));
}
},
getInitialResultSet: function(terms) {
@ -144,8 +193,8 @@ const RemoteSearchProvider = new Lang.Class({
this._cancellable.reset();
try {
this._proxy.GetInitialResultSetRemote(terms,
Lang.bind(this, this._getResultsFinished),
this._cancellable);
this._cancellable,
Lang.bind(this, this._getResultsFinished));
} catch(e) {
log('Error calling GetInitialResultSet for provider %s: %s'.format( this.title, e.toString()));
this.searchSystem.pushResults(this, []);
@ -157,30 +206,30 @@ const RemoteSearchProvider = new Lang.Class({
this._cancellable.reset();
try {
this._proxy.GetSubsearchResultSetRemote(previousResults, newTerms,
Lang.bind(this, this._getResultsFinished),
this._cancellable);
this._cancellable,
Lang.bind(this, this._getResultsFinished))
} catch(e) {
log('Error calling GetSubsearchResultSet for provider %s: %s'.format(this.title, e.toString()));
this.searchSystem.pushResults(this, []);
}
},
_getResultMetasFinished: function(results, error, callback) {
if (error) {
_getResultMetasFinished: function(proxy, result, callback) {
try {
let [metas] = results.GetResultMetasFinish(result);
let resultMetas = [];
for (let i = 0; i < metas.length; i++) {
for (let prop in metas[i])
metas[i][prop] = metas[i][prop].deep_unpack();
resultMetas.push({ id: metas[i]['id'],
name: metas[i]['name'],
createIcon: Lang.bind(this,
this.createIcon, metas[i]) });
}
callback(resultMetas);
} catch(e) {
callback([]);
return;
}
let metas = results[0];
let resultMetas = [];
for (let i = 0; i < metas.length; i++) {
for (let prop in metas[i])
metas[i][prop] = metas[i][prop].deep_unpack();
resultMetas.push({ id: metas[i]['id'],
name: metas[i]['name'],
createIcon: Lang.bind(this,
this.createIcon, metas[i]) });
}
callback(resultMetas);
},
getResultMetas: function(ids, callback) {
@ -188,8 +237,8 @@ const RemoteSearchProvider = new Lang.Class({
this._cancellable.reset();
try {
this._proxy.GetResultMetasRemote(ids,
Lang.bind(this, this._getResultMetasFinished, callback),
this._cancellable);
this._cancellable,
Lang.bind(this, this._getResultMetasFinished, callback));
} catch(e) {
log('Error calling GetResultMetas for provider %s: %s'.format(this.title, e.toString()));
callback([]);
@ -197,11 +246,7 @@ const RemoteSearchProvider = new Lang.Class({
},
activateResult: function(id) {
this._proxy.ActivateResultRemote(id);
},
launchSearch: function(terms) {
this._proxy.LaunchSearchRemote(terms);
this._proxy.ActivateResultRemote(id, null, null);
}
});

View File

@ -418,10 +418,11 @@ const ScreenShield = new Lang.Class({
this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this);
this._loginManager = LoginManager.getLoginManager();
this._loginSession = this._loginManager.getCurrentSessionProxy();
this._loginSession.connectSignal('Lock', Lang.bind(this, function() { this.lock(false); }));
this._loginSession.connectSignal('Unlock', Lang.bind(this, function() { this.unlock(); }));
LoginManager.getLoginManager(Lang.bind(this, function(manager) {
this._loginSession = manager.getCurrentSessionProxy();
this._loginSession.connectSignal('Lock', Lang.bind(this, function() { this.lock(false); }));
this._loginSession.connectSignal('Unlock', Lang.bind(this, function() { this.unlock(); }));
}));
this._settings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
@ -875,6 +876,7 @@ const ScreenShieldFallback = new Lang.Class({
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES),
});
// This is synchronous but it is the fallback case.
this._proxy.init(null);
this._proxy.connect('g-signal', Lang.bind(this, this._onSignal));

View File

@ -80,15 +80,23 @@ const PerfHelperIface = <interface name="org.gnome.Shell.PerfHelper">
<method name="DestroyWindows" />
</interface>;
var PerfHelperProxy = Gio.DBusProxy.makeProxyWrapper(PerfHelperIface);
function PerfHelper() {
return new PerfHelperProxy(Gio.DBus.session, 'org.gnome.Shell.PerfHelper', '/org/gnome/Shell/PerfHelper');
}
const PerfHelper = new Gio.DBusProxyClass({
Name: 'PerfHelperProxy',
Interface: PerfHelperIface,
_init: function() {
this.parent({ g_bus_type: Gio.BusType.SESSION,
g_name: 'org.gnome.Shell.PerfHelper',
g_object_path: '/org/gnome/Shell/PerfHelper' });
}
});
let _perfHelper = null;
function _getPerfHelper() {
if (_perfHelper == null)
if (_perfHelper == null) {
_perfHelper = new PerfHelper();
_perfHelper.init(null);
}
return _perfHelper;
}
@ -111,7 +119,8 @@ function createTestWindow(width, height, alpha, maximized) {
let perfHelper = _getPerfHelper();
perfHelper.CreateWindowRemote(width, height, alpha, maximized,
function(result, excp) {
null,
function(proxy, result) {
if (cb)
cb();
});
@ -131,7 +140,7 @@ function waitTestWindows() {
let cb;
let perfHelper = _getPerfHelper();
perfHelper.WaitWindowsRemote(function(result, excp) {
perfHelper.WaitWindowsRemote(null, function(proxy, result) {
if (cb)
cb();
});
@ -154,7 +163,7 @@ function destroyTestWindows() {
let cb;
let perfHelper = _getPerfHelper();
perfHelper.DestroyWindowsRemote(function(result, excp) {
perfHelper.DestroyWindowsRemote(null, function(proxy, result) {
if (cb)
cb();
});

View File

@ -2,6 +2,7 @@
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Lang = imports.lang;
const Signals = imports.signals;
const Shell = imports.gi.Shell;
@ -75,6 +76,8 @@ const SearchProvider = new Lang.Class({
Name: 'SearchProvider',
_init: function(title) {
this.parent();
this.title = title;
this.searchSystem = null;
},
@ -163,16 +166,6 @@ const SearchProvider = new Lang.Class({
*/
activateResult: function(id) {
throw new Error('Not implemented');
},
/**
* launchSearch:
* @terms: Current search terms
*
* Called when the user clicks the provider icon.
*/
launchSearch: function(terms) {
throw new Error('Not implemented');
}
});
Signals.addSignalMethods(SearchProvider.prototype);
@ -271,11 +264,5 @@ const SearchSystem = new Lang.Class({
}
}
},
launchSearch: function(provider) {
let terms = this.getTerms();
provider.launchSearch(terms);
Main.overview.toggle();
}
});
Signals.addSignalMethods(SearchSystem.prototype);

View File

@ -4,191 +4,25 @@ const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Gtk = imports.gi.Gtk;
const Meta = imports.gi.Meta;
const Signals = imports.signals;
const St = imports.gi.St;
const Atk = imports.gi.Atk;
const AppDisplay = imports.ui.appDisplay;
const DND = imports.ui.dnd;
const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const PopupMenu = imports.ui.popupMenu;
const Search = imports.ui.search;
const MAX_SEARCH_RESULTS_ROWS = 3;
const MAX_GRID_SEARCH_RESULTS_ROWS = 1;
const MAX_SEARCH_RESULTS_ROWS = 1;
const ListSearchResult = new Lang.Class({
Name: 'ListSearchResult',
ICON_SIZE: 64,
const SearchResult = new Lang.Class({
Name: 'SearchResult',
_init: function(provider, metaInfo, terms) {
this.provider = provider;
this.metaInfo = metaInfo;
this.actor = new St.Button({ style_class: 'search-result',
reactive: true,
can_focus: true,
track_hover: true,
x_align: St.Align.START,
x_fill: true,
y_fill: true });
this.actor._delegate = this;
let content = new St.BoxLayout({ style_class: 'search-result-content',
vertical: false });
this._content = content;
this.actor.set_child(content);
// An icon for, or thumbnail of, content
let icon = this.metaInfo['createIcon'](this.ICON_SIZE);
if (icon) {
let iconBin = new St.Bin({ style_class: 'search-result-icon',
child: icon });
content.add(iconBin);
}
let details = new St.BoxLayout({ style_class: 'search-result-details',
vertical: true });
content.add(details, { x_fill: true,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.MIDDLE });
let title = new St.Label({ style_class: 'search-result-details-title',
text: this.metaInfo['name'] })
details.add(title, { x_fill: true,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.START });
// TODO: could highlight terms in the description here, or should
// providers provide what should be highlighted?
if (this.metaInfo['description']) {
let description = new St.Label({ style_class: 'search-result-details-description',
text: this.metaInfo['description'] });
details.add(description, { x_fill: false,
y_fill: true,
x_align: St.Align.START,
y_align: St.Align.END });
}
this.actor.connect('clicked', Lang.bind(this, this._onResultClicked));
},
setSelected: function(selected) {
if (selected)
this.actor.add_style_pseudo_class('selected');
else
this.actor.remove_style_pseudo_class('selected');
},
activate: function() {
this.provider.activateResult(this.metaInfo.id);
Main.overview.toggle();
},
_onResultClicked: function(actor) {
this.activate();
}
});
const ListSearchResults = new Lang.Class({
Name: 'ListSearchResults',
Extends: Search.SearchResultDisplay,
_init: function(provider) {
this.parent(provider);
this.actor = new St.BoxLayout({ style_class: 'results-list',
vertical: true });
this.actor.connect('notify::width', Lang.bind(this, function() {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
let results = this.getResultsForDisplay();
if (results.length == 0)
return;
provider.getResultMetas(results, Lang.bind(this, this.renderResults));
}));
}));
this._notDisplayedResult = [];
this._terms = [];
this._pendingClear = false;
},
getResultsForDisplay: function() {
let alreadyVisible = this._pendingClear ? 0 : this.getVisibleResultCount();
let canDisplay = MAX_SEARCH_RESULTS_ROWS - alreadyVisible;
let numResults = Math.min(this._notDisplayedResult.length, canDisplay);
return this._notDisplayedResult.splice(0, numResults);
},
getVisibleResultCount: function() {
return this.actor.get_n_children();
},
hasMoreResults: function() {
return this._notDisplayedResult.length > 0;
},
setResults: function(results, terms) {
// copy the lists
this._notDisplayedResult = results.slice(0);
this._terms = terms.slice(0);
this._pendingClear = true;
},
renderResults: function(metas) {
for (let i = 0; i < metas.length; i++) {
let display = new ListSearchResult(this.provider, metas[i], this._terms);
this.addItem(display.actor);
display.actor.connect('key-focus-in', Lang.bind(this, this._onFocusedProviderChanged));
}
},
clear: function () {
this.actor.destroy_all_children();
this._pendingClear = false;
},
getFirstResult: function() {
if (this.getVisibleResultCount() > 0)
return this.getItemAtIndex(0)._delegate;
else
return null;
},
addItem: function(actor, index) {
if (index !== undefined)
this.actor.insert_child_at_index(actor, index);
else
this.actor.add_actor(actor);
},
getItemAtIndex: function(index) {
return this.actor.get_child_at_index(index);
},
_onFocusedProviderChanged: function() {
this.emit('focused-provider-changed');
}
});
Signals.addSignalMethods(ListSearchResults.prototype);
const GridSearchResult = new Lang.Class({
Name: 'GridSearchResult',
_init: function(provider, metaInfo, terms) {
this.provider = provider;
this.metaInfo = metaInfo;
this.actor = new St.Button({ style_class: 'grid-search-result',
reactive: true,
x_align: St.Align.START,
y_fill: true });
@ -197,7 +31,7 @@ const GridSearchResult = new Lang.Class({
let content = provider.createResultActor(metaInfo, terms);
if (content == null) {
content = new St.Bin({ style_class: 'grid-search-result-content',
content = new St.Bin({ style_class: 'search-result-content',
reactive: true,
can_focus: true,
track_hover: true,
@ -211,7 +45,7 @@ const GridSearchResult = new Lang.Class({
if (content._delegate && content._delegate.getDragActorSource)
this._dragActorSource = content._delegate.getDragActorSource();
}
this.content = content;
this._content = content;
this.actor.set_child(content);
this.actor.connect('clicked', Lang.bind(this, this._onResultClicked));
@ -219,23 +53,23 @@ const GridSearchResult = new Lang.Class({
let draggable = DND.makeDraggable(this.actor);
draggable.connect('drag-begin',
Lang.bind(this, function() {
Main.overview.beginAppDrag(this);
Main.overview.beginItemDrag(this);
}));
draggable.connect('drag-cancelled',
Lang.bind(this, function() {
Main.overview.cancelledAppDrag(this);
Main.overview.cancelledItemDrag(this);
}));
draggable.connect('drag-end',
Lang.bind(this, function() {
Main.overview.endAppDrag(this);
Main.overview.endItemDrag(this);
}));
},
setSelected: function(selected) {
if (selected)
this.content.add_style_pseudo_class('selected');
this._content.add_style_pseudo_class('selected');
else
this.content.remove_style_pseudo_class('selected');
this._content.remove_style_pseudo_class('selected');
},
activate: function() {
@ -251,7 +85,7 @@ const GridSearchResult = new Lang.Class({
if (this._dragActorSource)
return this._dragActorSource;
// not exactly right, but alignment problems are hard to notice
return this.content;
return this._content;
},
getDragActor: function(stageX, stageY) {
@ -274,11 +108,11 @@ const GridSearchResults = new Lang.Class({
_init: function(provider, grid) {
this.parent(provider);
this._grid = grid || new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
this._grid = grid || new IconGrid.IconGrid({ rowLimit: MAX_SEARCH_RESULTS_ROWS,
xAlign: St.Align.START });
this.actor = new St.Bin({ x_align: St.Align.MIDDLE });
this.actor.set_child(this._grid.actor);
this.actor = new St.Bin({ x_align: St.Align.START });
this.actor.set_child(this._grid.actor);
this._width = 0;
this.actor.connect('notify::width', Lang.bind(this, function() {
this._width = this.actor.width;
@ -296,7 +130,6 @@ const GridSearchResults = new Lang.Class({
},
getResultsForDisplay: function() {
this._grid.actor.ensure_style();
let alreadyVisible = this._pendingClear ? 0 : this._grid.visibleItemsCount();
let canDisplay = this._grid.childrenInRow(this._width) * this._grid.getRowLimit()
- alreadyVisible;
@ -310,10 +143,6 @@ const GridSearchResults = new Lang.Class({
return this._grid.visibleItemsCount();
},
hasMoreResults: function() {
return this._notDisplayedResult.length > 0;
},
setResults: function(results, terms) {
// copy the lists
this._notDisplayedResult = results.slice(0);
@ -323,10 +152,8 @@ const GridSearchResults = new Lang.Class({
renderResults: function(metas) {
for (let i = 0; i < metas.length; i++) {
let display = new GridSearchResult(this.provider, metas[i], this._terms);
let display = new SearchResult(this.provider, metas[i], this._terms);
this._grid.addItem(display.actor);
display.content.connect('key-focus-in', Lang.bind(this, this._onFocusedProviderChanged));
}
},
@ -340,17 +167,11 @@ const GridSearchResults = new Lang.Class({
return this._grid.getItemAtIndex(0)._delegate;
else
return null;
},
_onFocusedProviderChanged: function() {
this.emit('focused-provider-changed');
}
});
Signals.addSignalMethods(GridSearchResults.prototype);
const SearchDisplay = new Lang.Class({
Name: 'SearchDisplay',
const SearchResults = new Lang.Class({
Name: 'SearchResults',
_init: function(searchSystem) {
this._searchSystem = searchSystem;
@ -401,43 +222,19 @@ const SearchDisplay = new Lang.Class({
createProviderMeta: function(provider) {
let providerBox = new St.BoxLayout({ style_class: 'search-section',
vertical: true });
let providerBoxContent = new St.BoxLayout({ style_class: 'search-section-content' });
let isAppsProvider = (provider instanceof AppDisplay.AppSearchProvider);
let providerIcon;
if (!isAppsProvider) {
let separator = new PopupMenu.HorzSeparator({ style_class: 'search-section-separator' });
providerBox.add(separator.actor, { expand: true });
providerIcon = new ProviderIcon(provider);
providerIcon.connect('launch-search', Lang.bind(this, function(providerIcon) {
this._searchSystem.launchSearch(providerIcon.provider);
}));
providerBoxContent.add(providerIcon.actor, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.START });
}
let title = new St.Label({ style_class: 'search-section-header',
text: provider.title });
providerBox.add(title, { x_fill: false, x_align: St.Align.START });
let resultDisplayBin = new St.Bin({ style_class: 'search-section-results',
x_fill: true,
y_fill: true });
providerBoxContent.add(resultDisplayBin, { expand: true });
providerBox.add(providerBoxContent);
let resultDisplay;
if (isAppsProvider)
resultDisplay = new GridSearchResults(provider);
else
resultDisplay = new ListSearchResults(provider);
resultDisplay.connect('focused-provider-changed', Lang.bind(this, this._updateProviderIconCanFocus));
providerBox.add(resultDisplayBin, { expand: true });
let resultDisplay = new GridSearchResults(provider);
resultDisplayBin.set_child(resultDisplay.actor);
this._providerMeta.push({ provider: provider,
actor: providerBox,
icon: providerIcon,
resultDisplay: resultDisplay });
this._content.add(providerBox);
},
@ -458,7 +255,6 @@ const SearchDisplay = new Lang.Class({
let meta = this._providerMeta[i];
meta.resultDisplay.clear();
meta.actor.hide();
if (meta.icon) meta.icon.actor.can_focus = false;
}
},
@ -466,7 +262,6 @@ const SearchDisplay = new Lang.Class({
let meta = this._metaForProvider(provider);
meta.resultDisplay.clear();
meta.actor.hide();
if (meta.icon) meta.icon.actor.can_focus = false;
},
reset: function() {
@ -489,11 +284,6 @@ const SearchDisplay = new Lang.Class({
return this._providerMeta[this._providers.indexOf(provider)];
},
_metaForProvidersExcept: function(provider) {
let skip = this._providers.indexOf(provider);
return this._providerMeta.filter(function(meta, index) { return index != skip }, this);
},
_maybeSetInitialSelection: function() {
let newDefaultResult = null;
@ -551,9 +341,6 @@ const SearchDisplay = new Lang.Class({
meta.resultDisplay.setResults(providerResults, terms);
let results = meta.resultDisplay.getResultsForDisplay();
if (meta.icon)
meta.icon.moreIcon.visible = meta.resultDisplay.hasMoreResults();
provider.getResultMetas(results, Lang.bind(this, function(metas) {
this._clearDisplayForProvider(provider);
meta.actor.show();
@ -587,15 +374,6 @@ const SearchDisplay = new Lang.Class({
this._defaultResult.setSelected(highlight);
},
_updateProviderIconCanFocus: function(resultDisplay) {
let meta = this._metaForProvider(resultDisplay.provider);
if (meta.icon)
meta.icon.actor.can_focus = true;
let others = this._metaForProvidersExcept(resultDisplay.provider);
others.forEach(function(meta) { if (meta.icon) meta.icon.actor.can_focus = false; });
},
navigateFocus: function(direction) {
let rtl = this.actor.get_text_direction() == Clutter.TextDirection.RTL;
if (direction == Gtk.DirectionType.TAB_BACKWARD ||
@ -615,65 +393,3 @@ const SearchDisplay = new Lang.Class({
}
}
});
const ProviderIcon = new Lang.Class({
Name: 'ProviderIcon',
PROVIDER_ICON_SIZE: 48,
MORE_ICON_SIZE: 16,
_init: function(provider) {
this.provider = provider;
this.actor = new St.Button({ style_class: 'search-section-icon-bin',
reactive: true,
track_hover: true });
this.actor.connect('clicked', Lang.bind(this, this._onIconClicked));
this._content = new St.Widget({ layout_manager: new Clutter.BinLayout() });
this.actor.set_child(this._content);
let rtl = (this.actor.get_text_direction() == Clutter.TextDirection.RTL);
this.moreIcon = new St.Icon({ style_class: 'search-section-icon-more',
icon_size: this.MORE_ICON_SIZE,
icon_name: 'list-add-symbolic',
visible: false,
x_align: rtl ? Clutter.ActorAlign.START : Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.END,
// HACK: without these, ClutterBinLayout
// ignores alignment properties on the actor
x_expand: true,
y_expand: true });
this._iconBin = new St.Bin({ style_class: 'search-section-icon',
width: this.PROVIDER_ICON_SIZE,
height: this.PROVIDER_ICON_SIZE });
this._content.add_actor(this._iconBin);
this._content.add_actor(this.moreIcon);
this._createProviderIcon();
},
_createProviderIcon: function() {
let icon = new St.Icon({ icon_size: this.PROVIDER_ICON_SIZE });
if (this.provider.icon)
icon.gicon = this.provider.icon;
else
icon.icon_name = 'application-x-executable';
this._iconBin.set_child(icon);
},
activate: function() {
this.emit('launch-search');
},
_onIconClicked: function(actor) {
this.activate();
}
});
Signals.addSignalMethods(ProviderIcon.prototype);

View File

@ -67,14 +67,16 @@ const ScreenSaverIface = <interface name="org.gnome.ScreenSaver">
</signal>
</interface>;
const GnomeShell = new Lang.Class({
const GnomeShell = new Gio.DBusImplementerClass({
Name: 'GnomeShellDBus',
Interface: GnomeShellIface,
_init: function() {
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
this.parent();
this._extensionsSerivce = new GnomeShellExtensions();
this.export(Gio.DBus.session, '/org/gnome/Shell');
this._extensionsService = new GnomeShellExtensions();
},
/**
@ -236,12 +238,14 @@ const GnomeShellExtensionsIface = <interface name="org.gnome.Shell.Extensions">
<property name="ShellVersion" type="s" access="read" />
</interface>;
const GnomeShellExtensions = new Lang.Class({
const GnomeShellExtensions = new Gio.DBusImplementerClass({
Name: 'GnomeShellExtensionsDBus',
Interface: GnomeShellExtensionsIface,
_init: function() {
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellExtensionsIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
this.parent();
this.export(Gio.DBus.session, '/org/gnome/Shell');
ExtensionSystem.connect('extension-state-changed',
Lang.bind(this, this._extensionStateChanged));
},
@ -335,25 +339,23 @@ const GnomeShellExtensions = new Lang.Class({
ShellVersion: Config.PACKAGE_VERSION,
_extensionStateChanged: function(_, newState) {
this._dbusImpl.emit_signal('ExtensionStatusChanged',
GLib.Variant.new('(sis)', [newState.uuid, newState.state, newState.error]));
this.emit_signal('ExtensionStatusChanged', newState.uuid, newState.state, newState.error);
}
});
const ScreenSaverDBus = new Lang.Class({
const ScreenSaverDBus = new Gio.DBusImplementerClass({
Name: 'ScreenSaverDBus',
Interface: ScreenSaverIface,
_init: function(screenShield) {
this.parent();
this._screenShield = screenShield;
screenShield.connect('lock-status-changed', Lang.bind(this, function(shield) {
this._dbusImpl.emit_signal('ActiveChanged', GLib.Variant.new('(b)', [shield.locked]));
this.emit_signal('ActiveChanged', shield.locked);
}));
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreenSaverIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/ScreenSaver');
this.export(Gio.DBus.session, '/org/gnome/ScreenSaver');
Gio.DBus.session.own_name('org.gnome.ScreenSaver', Gio.BusNameOwnerFlags.REPLACE, null, null);
},

View File

@ -554,14 +554,16 @@ const ShellMountOperationType = {
SHOW_PROCESSES: 3
};
const GnomeShellMountOpHandler = new Lang.Class({
const GnomeShellMountOpHandler = new Gio.DBusImplementerClass({
Name: 'GnomeShellMountOpHandler',
Interface: GnomeShellMountOpIface,
_init: function() {
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellMountOpIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gtk/MountOperationHandler');
Gio.bus_own_name_on_connection(Gio.DBus.session, 'org.gtk.MountOperationHandler',
Gio.BusNameOwnerFlags.REPLACE, null, null);
this.parent();
this.export(Gio.DBus.session, '/org/gtk/MountOperationHandler');
Gio.DBus.session.own_name('org.gtk.MountOperationHandler',
Gio.BusNameOwnerFlags.REPLACE, null, null);
this._dialog = null;
this._volumeMonitor = Gio.VolumeMonitor.get();

View File

@ -1629,7 +1629,44 @@ const NMApplet = new Lang.Class({
this.secondaryIcon = this.addIcon(new Gio.ThemedIcon({ name: 'network-vpn-symbolic' }));
this.secondaryIcon.hide();
this._client = NMClient.Client.new();
// Device types
this._dtypes = { };
this._dtypes[NetworkManager.DeviceType.ETHERNET] = NMDeviceWired;
this._dtypes[NetworkManager.DeviceType.WIFI] = NMDeviceWireless;
this._dtypes[NetworkManager.DeviceType.MODEM] = NMDeviceModem;
this._dtypes[NetworkManager.DeviceType.BT] = NMDeviceBluetooth;
// TODO: WiMax support
// Connection types
this._ctypes = { };
this._ctypes[NetworkManager.SETTING_WIRELESS_SETTING_NAME] = NMConnectionCategory.WIRELESS;
this._ctypes[NetworkManager.SETTING_WIRED_SETTING_NAME] = NMConnectionCategory.WIRED;
this._ctypes[NetworkManager.SETTING_PPPOE_SETTING_NAME] = NMConnectionCategory.WIRED;
this._ctypes[NetworkManager.SETTING_PPP_SETTING_NAME] = NMConnectionCategory.WIRED;
this._ctypes[NetworkManager.SETTING_BLUETOOTH_SETTING_NAME] = NMConnectionCategory.WWAN;
this._ctypes[NetworkManager.SETTING_CDMA_SETTING_NAME] = NMConnectionCategory.WWAN;
this._ctypes[NetworkManager.SETTING_GSM_SETTING_NAME] = NMConnectionCategory.WWAN;
this._ctypes[NetworkManager.SETTING_VPN_SETTING_NAME] = NMConnectionCategory.VPN;
NMClient.Client.new_async(null, Lang.bind(this, this._clientGot));
NMClient.RemoteSettings.new_async(null, null, Lang.bind(this, this._remoteSettingsGot));
},
_clientGot: function(obj, result) {
this._client = NMClient.Client.new_finish(result);
this._tryLateInit();
},
_remoteSettingsGot: function(obj, result) {
this._settings = NMClient.RemoteSettings.new_finish(result);
this._tryLateInit();
},
_tryLateInit: function() {
if (!this._client || !this._settings)
return;
this._statusSection = new PopupMenu.PopupMenuSection();
this._statusItem = new PopupMenu.PopupMenuItem('', { reactive: false });
@ -1690,44 +1727,17 @@ const NMApplet = new Lang.Class({
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addSettingsAction(_("Network Settings"), 'gnome-network-panel.desktop');
// Device types
this._dtypes = { };
this._dtypes[NetworkManager.DeviceType.ETHERNET] = NMDeviceWired;
this._dtypes[NetworkManager.DeviceType.WIFI] = NMDeviceWireless;
this._dtypes[NetworkManager.DeviceType.MODEM] = NMDeviceModem;
this._dtypes[NetworkManager.DeviceType.BT] = NMDeviceBluetooth;
// TODO: WiMax support
this._readConnections();
this._readDevices();
this._syncNMState();
// Connection types
this._ctypes = { };
this._ctypes[NetworkManager.SETTING_WIRELESS_SETTING_NAME] = NMConnectionCategory.WIRELESS;
this._ctypes[NetworkManager.SETTING_WIRED_SETTING_NAME] = NMConnectionCategory.WIRED;
this._ctypes[NetworkManager.SETTING_PPPOE_SETTING_NAME] = NMConnectionCategory.WIRED;
this._ctypes[NetworkManager.SETTING_PPP_SETTING_NAME] = NMConnectionCategory.WIRED;
this._ctypes[NetworkManager.SETTING_BLUETOOTH_SETTING_NAME] = NMConnectionCategory.WWAN;
this._ctypes[NetworkManager.SETTING_CDMA_SETTING_NAME] = NMConnectionCategory.WWAN;
this._ctypes[NetworkManager.SETTING_GSM_SETTING_NAME] = NMConnectionCategory.WWAN;
this._ctypes[NetworkManager.SETTING_VPN_SETTING_NAME] = NMConnectionCategory.VPN;
this._settings = NMClient.RemoteSettings.new(null);
this._connectionsReadId = this._settings.connect('connections-read', Lang.bind(this, function() {
this._readConnections();
this._readDevices();
this._syncNMState();
// Connect to signals late so that early signals don't find in inconsistent state
// and connect only once (this signal handler can be called again if NetworkManager goes up and down)
if (!this._inited) {
this._inited = true;
this._client.connect('notify::manager-running', Lang.bind(this, this._syncNMState));
this._client.connect('notify::networking-enabled', Lang.bind(this, this._syncNMState));
this._client.connect('notify::state', Lang.bind(this, this._syncNMState));
this._client.connect('notify::active-connections', Lang.bind(this, this._updateIcon));
this._client.connect('device-added', Lang.bind(this, this._deviceAdded));
this._client.connect('device-removed', Lang.bind(this, this._deviceRemoved));
this._settings.connect('new-connection', Lang.bind(this, this._newConnection));
}
}));
this._client.connect('notify::manager-running', Lang.bind(this, this._syncNMState));
this._client.connect('notify::networking-enabled', Lang.bind(this, this._syncNMState));
this._client.connect('notify::state', Lang.bind(this, this._syncNMState));
this._client.connect('notify::active-connections', Lang.bind(this, this._updateIcon));
this._client.connect('device-added', Lang.bind(this, this._deviceAdded));
this._client.connect('device-removed', Lang.bind(this, this._deviceRemoved));
this._settings.connect('new-connection', Lang.bind(this, this._newConnection));
},
_ensureSource: function() {

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const St = imports.gi.St;
@ -45,7 +46,16 @@ const PowerManagerInterface = <interface name="org.gnome.SettingsDaemon.Power">
<property name="Icon" type="s" access="read" />
</interface>;
const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(PowerManagerInterface);
const PowerManagerProxy = new Gio.DBusProxyClass({
Name: 'PowerManagerProxy',
Interface: PowerManagerInterface,
_init: function() {
this.parent({ g_bus_type: Gio.BusType.SESSION,
g_name: BUS_NAME,
g_object_path: OBJECT_PATH });
}
});
const Indicator = new Lang.Class({
Name: 'PowerIndicator',
@ -54,7 +64,7 @@ const Indicator = new Lang.Class({
_init: function() {
this.parent('battery-missing-symbolic', _("Battery"));
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
this._proxy = new PowerManagerProxy();
this._deviceItems = [ ];
this._hasPrimary = false;
@ -73,18 +83,26 @@ const Indicator = new Lang.Class({
this._proxy.connect('g-properties-changed',
Lang.bind(this, this._devicesChanged));
this._devicesChanged();
this._proxy.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(proxy, result) {
proxy.init_finish(result);
this._devicesChanged();
}));
},
_readPrimaryDevice: function() {
this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(result, error) {
if (error) {
this._proxy.GetPrimaryDeviceRemote(null, Lang.bind(this, function(proxy, result) {
let device_id, device_type, icon, percentage, state, seconds;
try {
[[device_id, device_type, icon, percentage, state, seconds]] =
proxy.GetPrimaryDeviceFinish(result);
} catch(e) {
this._hasPrimary = false;
this._primaryDeviceId = null;
this._batteryItem.actor.hide();
return;
}
let [[device_id, device_type, icon, percentage, state, seconds]] = result;
if (device_type == UPDeviceType.BATTERY) {
this._hasPrimary = true;
let time = Math.round(seconds / 60);
@ -121,16 +139,18 @@ const Indicator = new Lang.Class({
},
_readOtherDevices: function() {
this._proxy.GetDevicesRemote(Lang.bind(this, function(result, error) {
this._proxy.GetDevicesRemote(null, Lang.bind(this, function(proxy, result) {
this._deviceItems.forEach(function(i) { i.destroy(); });
this._deviceItems = [];
if (error) {
let devices;
try {
[devices] = proxy.GetDevicesFinish(result);
} catch(e) {
return;
}
let position = 0;
let [devices] = result;
for (let i = 0; i < devices.length; i++) {
let [device_id, device_type] = devices[i];
if (device_type == UPDeviceType.AC_POWER || device_id == this._primaryDeviceId)

View File

@ -195,8 +195,12 @@ const IMStatusChooserItem = new Lang.Class({
Lang.bind(this, this._changeIMStatus));
this._presence = new GnomeSession.Presence();
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
this._sessionStatusChanged(status);
this._presence.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(obj, result) {
obj.init_finish(result);
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
this._sessionStatusChanged(status);
}));
}));
this._sessionPresenceRestored = false;
@ -480,14 +484,33 @@ const UserMenuButton = new Lang.Class({
this._userManager = AccountsService.UserManager.get_default();
this._user = this._userManager.get_user(GLib.get_user_name());
this._presence = new GnomeSession.Presence();
this._session = new GnomeSession.SessionManager();
this._presence.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(proxy, result) {
proxy.init_finish(result);
this._updateSwitch(this._presence.status);
this._presence.connectSignal('StatusChanged', Lang.bind(this, function (proxy, senderName, [status]) {
this._updateSwitch(status);
}));
}));
let session = new GnomeSession.SessionManager();
session.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(proxy, result) {
// This should never fail.
proxy.init_finish(result);
this._session = proxy;
this._updateHaveShutdown();
}));
this._haveShutdown = true;
this._haveSuspend = true;
this._accountMgr = Tp.AccountManager.dup();
this._loginManager = LoginManager.getLoginManager();
LoginManager.getLoginManager(Lang.bind(this, function(manager) {
this._loginManager = manager;
}));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._iconBox = new St.Bin();
@ -533,11 +556,6 @@ const UserMenuButton = new Lang.Class({
this._createSubMenu();
this._updateSwitch(this._presence.status);
this._presence.connectSignal('StatusChanged', Lang.bind(this, function (proxy, senderName, [status]) {
this._updateSwitch(status);
}));
this._userManager.connect('notify::is-loaded',
Lang.bind(this, this._updateMultiUser));
this._userManager.connect('notify::has-multiple-users',
@ -637,17 +655,29 @@ const UserMenuButton = new Lang.Class({
},
_updateHaveShutdown: function() {
this._session.CanShutdownRemote(Lang.bind(this,
function(result, error) {
if (!error) {
this._haveShutdown = result[0];
this._updateInstallUpdates();
this._updateSuspendOrPowerOff();
}
}));
if (!this._session) {
this._haveShutdown = false;
return;
}
this._session.CanShutdownRemote(null, Lang.bind(this, function(proxy, result) {
try {
[this._haveShutdown] = proxy.CanShutdownFinish(result);
} catch(e) {
this._haveShutdown = false;
}
this._updateInstallUpdates();
this._updateSuspendOrPowerOff();
}));
},
_updateHaveSuspend: function() {
if (!this._loginManager) {
this._haveSuspend = false;
return;
}
this._loginManager.canSuspend(Lang.bind(this,
function(result) {
this._haveSuspend = result;
@ -837,14 +867,17 @@ const UserMenuButton = new Lang.Class({
_onQuitSessionActivate: function() {
Main.overview.hide();
this._session.LogoutRemote(0);
if (this._session)
this._session.LogoutRemote(0, null, null);
},
_onInstallUpdatesActivate: function() {
Main.overview.hide();
Util.spawn(['pkexec', '/usr/libexec/pk-trigger-offline-update']);
this._session.RebootRemote();
if (this._haveShutdown)
this._session.RebootRemote(null, null);
},
_onSuspendOrPowerOffActivate: function() {
@ -852,8 +885,8 @@ const UserMenuButton = new Lang.Class({
if (this._haveShutdown &&
this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
this._session.ShutdownRemote();
} else {
this._session.ShutdownRemote(null, null);
} else if (this._haveSuspend) {
if (this._screenSaverSettings.get_boolean(LOCK_ENABLED_KEY)) {
let tmpId = Main.screenShield.connect('lock-screen-shown', Lang.bind(this, function() {
Main.screenShield.disconnect(tmpId);

View File

@ -52,7 +52,7 @@ const ViewSelector = new Lang.Class({
this._activePage = null;
this.entryNonEmpty = false;
this.active = false;
this._searchPending = false;
this._searchTimeoutId = 0;
@ -90,7 +90,7 @@ const ViewSelector = new Lang.Class({
this._appsPage = this._addPage(this._appDisplay.actor, null,
_("Applications"), 'system-run-symbolic');
this._searchResults = new SearchDisplay.SearchDisplay(this._searchSystem);
this._searchResults = new SearchDisplay.SearchResults(this._searchSystem);
this._searchPage = this._addPage(this._searchResults.actor, this._entry,
_("Search"), 'edit-find-symbolic');
@ -114,6 +114,9 @@ const ViewSelector = new Lang.Class({
global.focus_manager.add_group(this._searchResults.actor);
Main.overview.connect('item-drag-begin',
Lang.bind(this, this._resetShowAppsButton));
this._stageKeyPressId = 0;
Main.overview.connect('showing', Lang.bind(this,
function () {
@ -130,6 +133,17 @@ const ViewSelector = new Lang.Class({
}
}));
// Public constraints which may be used to tie actors' height or
// vertical position to the current tab's content; as the content's
// height and position depend on the view selector's style properties
// (e.g. font size, padding, spacing, ...) it would be extremely hard
// and ugly to get these from the outside. While it would be possible
// to use position and height properties directly, outside code would
// need to ensure that the content is properly allocated before
// accessing the properties.
this.constrainHeight = new Clutter.BindConstraint({ source: this._pageArea,
coordinate: Clutter.BindCoordinate.HEIGHT });
global.display.add_keybinding('toggle-application-view',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
@ -216,9 +230,7 @@ const ViewSelector = new Lang.Class({
},
_onShowAppsButtonToggled: function() {
this.emit('apps-button-checked', this._showAppsButton.checked);
if (this.entryNonEmpty)
if (this.active)
this.reset();
else
this._showPage(this._showAppsButton.checked ? this._appsPage
@ -234,7 +246,7 @@ const ViewSelector = new Lang.Class({
let symbol = event.get_key_symbol();
if (symbol == Clutter.Escape) {
if (this.entryNonEmpty)
if (this.active)
this.reset();
else if (this._showAppsButton.checked)
this._resetShowAppsButton();
@ -242,9 +254,9 @@ const ViewSelector = new Lang.Class({
Main.overview.hide();
return true;
} else if (Clutter.keysym_to_unicode(symbol) ||
(symbol == Clutter.BackSpace && this.entryNonEmpty)) {
(symbol == Clutter.BackSpace && this.active)) {
this.startSearch(event);
} else if (!this.entryNonEmpty) {
} else if (!this.active) {
if (symbol == Clutter.Tab || symbol == Clutter.Down) {
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
return true;
@ -257,7 +269,6 @@ const ViewSelector = new Lang.Class({
},
_searchCancelled: function() {
this.emit('search-cancelled');
this._showPage(this._showAppsButton.checked ? this._appsPage
: this._workspacesPage);
@ -319,14 +330,13 @@ const ViewSelector = new Lang.Class({
},
_onTextChanged: function (se, prop) {
let searchPreviouslyActive = this.entryNonEmpty;
this.entryNonEmpty = this._entry.get_text() != '';
this._searchPending = this.entryNonEmpty && !searchPreviouslyActive;
let searchPreviouslyActive = this.active;
this.active = this._entry.get_text() != '';
this._searchPending = this.active && !searchPreviouslyActive;
if (this._searchPending) {
this._searchResults.startingSearch();
}
if (this.entryNonEmpty) {
this.emit('search-begin');
if (this.active) {
this._entry.set_secondary_icon(this._activeIcon);
if (this._iconClickedId == 0) {
@ -343,7 +353,7 @@ const ViewSelector = new Lang.Class({
this._entry.set_secondary_icon(this._inactiveIcon);
this._searchCancelled();
}
if (!this.entryNonEmpty) {
if (!this.active) {
if (this._searchTimeoutId > 0) {
Mainloop.source_remove(this._searchTimeoutId);
this._searchTimeoutId = 0;
@ -371,7 +381,7 @@ const ViewSelector = new Lang.Class({
}
this._searchResults.activateDefault();
return true;
} else if (this.entryNonEmpty) {
} else if (this.active) {
let arrowNext, nextDirection;
if (entry.get_text_direction() == Clutter.TextDirection.RTL) {
arrowNext = Clutter.Left;

View File

@ -1073,9 +1073,6 @@ const Workspace = new Lang.Class({
* ANIMATE - Indicates that we need animate changing position.
*/
positionWindows: function(flags) {
if (this.leavingOverview)
return;
this._positionWindowsFlags |= flags;
if (this._positionWindowsId > 0)

View File

@ -493,7 +493,6 @@ const ThumbnailsBox = new Lang.Class({
_init: function() {
this.actor = new Shell.GenericContainer({ reactive: true,
style_class: 'workspace-thumbnails',
can_focus: true,
request_mode: Clutter.RequestMode.WIDTH_FOR_HEIGHT });
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
@ -527,8 +526,6 @@ const ThumbnailsBox = new Lang.Class({
this._dropPlaceholder = new St.Bin({ style_class: 'placeholder' });
this.actor.add_actor(this._dropPlaceholder);
this.visible = true;
this._targetScale = 0;
this._scale = 0;
this._pendingScaleUpdate = false;
@ -544,21 +541,12 @@ const ThumbnailsBox = new Lang.Class({
this.actor.connect('button-press-event', function() { return true; });
this.actor.connect('button-release-event', Lang.bind(this, this._onButtonRelease));
this.actor.connect('scroll-event',
Lang.bind(this, this._onScrollEvent));
this.actor.connect('key-release-event',
Lang.bind(this, this._onKeyRelease));
Main.overview.connect('showing',
Lang.bind(this, this._createThumbnails));
Main.overview.connect('hidden',
Lang.bind(this, this._destroyThumbnails));
Main.overview.connect('app-drag-begin',
Main.overview.connect('item-drag-begin',
Lang.bind(this, this._onDragBegin));
Main.overview.connect('app-drag-end',
Main.overview.connect('item-drag-end',
Lang.bind(this, this._onDragEnd));
Main.overview.connect('app-drag-cancelled',
Main.overview.connect('item-drag-cancelled',
Lang.bind(this, this._onDragCancelled));
Main.overview.connect('window-drag-begin',
Lang.bind(this, this._onDragBegin));
@ -731,16 +719,10 @@ const ThumbnailsBox = new Lang.Class({
}
},
_createThumbnails: function() {
show: function() {
this._switchWorkspaceNotifyId =
global.window_manager.connect('switch-workspace',
Lang.bind(this, this._activeWorkspaceChanged));
this._nWorkspacesNotifyId =
global.screen.connect('notify::n-workspaces',
Lang.bind(this, this._workspacesChanged));
this._syncStackingId =
Main.overview.connect('sync-window-stacking',
Lang.bind(this, this.syncStacking));
this._targetScale = 0;
this._scale = 0;
@ -764,86 +746,17 @@ const ThumbnailsBox = new Lang.Class({
this.addThumbnails(0, global.screen.n_workspaces);
},
_destroyThumbnails: function() {
hide: function() {
if (this._switchWorkspaceNotifyId > 0) {
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
this._switchWorkspaceNotifyId = 0;
}
if (this._nWorkspacesNotifyId > 0) {
global.screen.disconnect(this._nWorkspacesNotifyId);
this._nWorkspacesNotifyId = 0;
}
if (this._syncStackingId > 0) {
Main.overview.disconnect(this._syncStackingId);
this._syncStackingId = 0;
}
for (let w = 0; w < this._thumbnails.length; w++)
this._thumbnails[w].destroy();
this._thumbnails = [];
},
_computeThumbnailsX: function() {
this._targetX = this.actor.get_x();
let rtl = (this.actor.get_text_direction() == Clutter.TextDirection.RTL);
if (rtl)
this._hiddenX = -this.actor.width;
else
this._hiddenX = this._targetX + this.actor.width;
},
show: function() {
if (this.visible)
return;
this.visible = true;
this.actor.show();
Tweener.addTween(this.actor, { translation_x: this._targetX,
transition: 'easeOutQuad',
time: SLIDE_ANIMATION_TIME
});
},
hide: function() {
if (!this.visible)
return;
this.visible = false;
Tweener.addTween(this.actor, { translation_x: this._hiddenX,
transition: 'easeOutQuad',
time: SLIDE_ANIMATION_TIME,
onComplete: Lang.bind(this, function () {
this.actor.hide();
})
});
},
_workspacesChanged: function() {
let oldNumWorkspaces = this._thumbnails.length;
let newNumWorkspaces = global.screen.n_workspaces;
let active = global.screen.get_active_workspace_index();
if (newNumWorkspaces > oldNumWorkspaces) {
this.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces);
} else {
let removedIndex;
let removedNum = oldNumWorkspaces - newNumWorkspaces;
for (let w = 0; w < oldNumWorkspaces; w++) {
let metaWorkspace = global.screen.get_workspace_by_index(w);
if (this._thumbnails[w].metaWorkspace != metaWorkspace) {
removedIndex = w;
break;
}
}
this.removeThumbnails(removedIndex, removedNum);
}
},
addThumbnails: function(start, count) {
for (let k = start; k < start + count; k++) {
let metaWorkspace = global.screen.get_workspace_by_index(k);
@ -889,7 +802,7 @@ const ThumbnailsBox = new Lang.Class({
this._queueUpdateStates();
},
syncStacking: function(actor, stackIndices) {
syncStacking: function(stackIndices) {
for (let i = 0; i < this._thumbnails.length; i++)
this._thumbnails[i].syncStacking(stackIndices);
},
@ -1011,8 +924,6 @@ const ThumbnailsBox = new Lang.Class({
onCompleteScope: this
});
});
this._computeThumbnailsX();
},
_queueUpdateStates: function() {
@ -1246,30 +1157,5 @@ const ThumbnailsBox = new Lang.Class({
},
onCompleteScope: this
});
},
_onScrollEvent: function (actor, event) {
switch (event.get_scroll_direction()) {
case Clutter.ScrollDirection.UP:
Main.wm.actionMoveWorkspace(Meta.MotionDirection.UP);
break;
case Clutter.ScrollDirection.DOWN:
Main.wm.actionMoveWorkspace(Meta.MotionDirection.DOWN);
break;
}
},
_onKeyRelease: function (actor, event) {
switch (event.get_key_symbol()) {
case Clutter.KEY_Up:
Main.wm.actionMoveWorkspace(Meta.MotionDirection.UP);
break;
case Clutter.KEY_Down:
Main.wm.actionMoveWorkspace(Meta.MotionDirection.DOWN);
break;
case Clutter.KEY_Return:
Main.overview.toggle();
break;
}
}
});

View File

@ -22,6 +22,8 @@ const MAX_WORKSPACES = 16;
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
const CONTROLS_POP_IN_TIME = 0.1;
const WorkspacesView = new Lang.Class({
Name: 'WorkspacesView',
@ -104,9 +106,9 @@ const WorkspacesView = new Lang.Class({
global.window_manager.connect('switch-workspace',
Lang.bind(this, this._activeWorkspaceChanged));
this._appDragBeginId = Main.overview.connect('app-drag-begin',
this._itemDragBeginId = Main.overview.connect('item-drag-begin',
Lang.bind(this, this._dragBegin));
this._appDragEndId = Main.overview.connect('app-drag-end',
this._itemDragEndId = Main.overview.connect('item-drag-end',
Lang.bind(this, this._dragEnd));
this._windowDragBeginId = Main.overview.connect('window-drag-begin',
Lang.bind(this, this._dragBegin));
@ -325,13 +327,13 @@ const WorkspacesView = new Lang.Class({
if (this._inDrag)
this._dragEnd();
if (this._appDragBeginId > 0) {
Main.overview.disconnect(this._appDragBeginId);
this._appDragBeginId = 0;
if (this._itemDragBeginId > 0) {
Main.overview.disconnect(this._itemDragBeginId);
this._itemDragBeginId = 0;
}
if (this._appDragEndId > 0) {
Main.overview.disconnect(this._appDragEndId);
this._appDragEndId = 0;
if (this._itemDragEndId > 0) {
Main.overview.disconnect(this._itemDragEndId);
this._itemDragEndId = 0;
}
if (this._windowDragBeginId > 0) {
Main.overview.disconnect(this._windowDragBeginId);
@ -458,8 +460,25 @@ const WorkspacesDisplay = new Lang.Class({
this.actor.connect('parent-set', Lang.bind(this, this._parentSet));
this.actor.set_clip_to_allocation(true);
let controls = new St.Bin({ style_class: 'workspace-controls',
request_mode: Clutter.RequestMode.WIDTH_FOR_HEIGHT,
y_align: St.Align.START,
y_fill: true });
this._controls = controls;
this.actor.add_actor(controls);
controls.reactive = true;
controls.track_hover = true;
controls.connect('notify::hover',
Lang.bind(this, this._onControlsHoverChanged));
controls.connect('scroll-event',
Lang.bind(this, this._onScrollEvent));
this._primaryIndex = Main.layoutManager.primaryIndex;
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
controls.add_actor(this._thumbnailsBox.actor);
this._workspacesViews = null;
this._primaryScrollAdjustment = null;
@ -472,14 +491,34 @@ const WorkspacesDisplay = new Lang.Class({
this._inDrag = false;
this._cancelledDrag = false;
this._controlsInitiallyHovered = false;
this._alwaysZoomOut = false;
this._zoomOut = false;
this._zoomFraction = 0;
this._updateAlwaysZoom();
// If we stop hiding the overview on layout changes, we will need to
// update the _workspacesViews here
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom));
Main.xdndHandler.connect('drag-begin', Lang.bind(this, function(){
this._alwaysZoomOut = true;
}));
Main.xdndHandler.connect('drag-end', Lang.bind(this, function(){
this._alwaysZoomOut = false;
this._updateAlwaysZoom();
}));
global.screen.connect('notify::n-workspaces',
Lang.bind(this, this._workspacesChanged));
this._switchWorkspaceNotifyId = 0;
this._appDragBeginId = 0;
this._appDragCancelledId = 0;
this._appDragEndId = 0;
this._itemDragBeginId = 0;
this._itemDragCancelledId = 0;
this._itemDragEndId = 0;
this._windowDragBeginId = 0;
this._windowDragCancelledId = 0;
this._windowDragEndId = 0;
@ -499,20 +538,41 @@ const WorkspacesDisplay = new Lang.Class({
},
show: function() {
if(!this._alwaysZoomOut) {
let [mouseX, mouseY] = global.get_pointer();
let [x, y] = this._controls.get_transformed_position();
let [width, height] = this._controls.get_transformed_size();
let visibleWidth = this._controls.get_theme_node().get_length('visible-width');
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
if(rtl)
x = x + width - visibleWidth;
if(mouseX > x - 0.5 && mouseX < x + visibleWidth + 0.5 &&
mouseY > y - 0.5 && mouseY < y + height + 0.5)
this._controlsInitiallyHovered = true;
}
this._zoomOut = this._alwaysZoomOut;
this._zoomFraction = this._alwaysZoomOut ? 1 : 0;
this._updateZoom();
this._controls.show();
this._thumbnailsBox.show();
this._updateSwitcherVisibility();
this._updateWorkspacesViews();
this._restackedNotifyId =
Main.overview.connect('sync-window-stacking',
global.screen.connect('restacked',
Lang.bind(this, this._onRestacked));
if (this._appDragBeginId == 0)
this._appDragBeginId = Main.overview.connect('app-drag-begin',
if (this._itemDragBeginId == 0)
this._itemDragBeginId = Main.overview.connect('item-drag-begin',
Lang.bind(this, this._dragBegin));
if (this._appDragCancelledId == 0)
this._appDragCancelledId = Main.overview.connect('app-drag-cancelled',
if (this._itemDragCancelledId == 0)
this._itemDragCancelledId = Main.overview.connect('item-drag-cancelled',
Lang.bind(this, this._dragCancelled));
if (this._appDragEndId == 0)
this._appDragEndId = Main.overview.connect('app-drag-end',
if (this._itemDragEndId == 0)
this._itemDragEndId = Main.overview.connect('item-drag-end',
Lang.bind(this, this._dragEnd));
if (this._windowDragBeginId == 0)
this._windowDragBeginId = Main.overview.connect('window-drag-begin',
@ -523,6 +583,8 @@ const WorkspacesDisplay = new Lang.Class({
if (this._windowDragEndId == 0)
this._windowDragEndId = Main.overview.connect('window-drag-end',
Lang.bind(this, this._dragEnd));
this._onRestacked();
},
zoomFromOverview: function() {
@ -532,21 +594,27 @@ const WorkspacesDisplay = new Lang.Class({
},
hide: function() {
this._controls.hide();
this._thumbnailsBox.hide();
if (!this._alwaysZoomOut)
this.zoomFraction = 0;
if (this._restackedNotifyId > 0){
Main.overview.disconnect(this._restackedNotifyId);
global.screen.disconnect(this._restackedNotifyId);
this._restackedNotifyId = 0;
}
if (this._appDragBeginId > 0) {
Main.overview.disconnect(this._appDragBeginId);
this._appDragBeginId = 0;
if (this._itemDragBeginId > 0) {
Main.overview.disconnect(this._itemDragBeginId);
this._itemDragBeginId = 0;
}
if (this._appDragCancelledId > 0) {
Main.overview.disconnect(this._appDragCancelledId);
this._appDragCancelledId = 0;
if (this._itemDragCancelledId > 0) {
Main.overview.disconnect(this._itemDragCancelledId);
this._itemDragCancelledId = 0;
}
if (this._appDragEndId > 0) {
Main.overview.disconnect(this._appDragEndId);
this._appDragEndId = 0;
if (this._itemDragEndId > 0) {
Main.overview.disconnect(this._itemDragEndId);
this._itemDragEndId = 0;
}
if (this._windowDragBeginId > 0) {
Main.overview.disconnect(this._windowDragBeginId);
@ -677,15 +745,73 @@ const WorkspacesDisplay = new Lang.Class({
return this._getPrimaryView().getActiveWorkspace().hasMaximizedWindows();
},
// zoomFraction property allows us to tween the controls sliding in and out
set zoomFraction(fraction) {
this._zoomFraction = fraction;
this.actor.queue_relayout();
},
get zoomFraction() {
return this._zoomFraction;
},
_updateAlwaysZoom: function() {
// Always show the pager if workspaces are actually used,
// e.g. there are windows on more than one
this._alwaysZoomOut = global.screen.n_workspaces > 2;
if (this._alwaysZoomOut)
return;
let monitors = Main.layoutManager.monitors;
let primary = Main.layoutManager.primaryMonitor;
/* Look for any monitor to the right of the primary, if there is
* one, we always keep zoom out, otherwise its hard to reach
* the thumbnail area without passing into the next monitor. */
for (let i = 0; i < monitors.length; i++) {
if (monitors[i].x >= primary.x + primary.width) {
this._alwaysZoomOut = true;
break;
}
}
},
_getPreferredWidth: function (actor, forHeight, alloc) {
// pass through the call in case the child needs it, but report 0x0
this._controls.get_preferred_width(forHeight);
},
_getPreferredHeight: function (actor, forWidth, alloc) {
// pass through the call in case the child needs it, but report 0x0
this._controls.get_preferred_height(forWidth);
},
_allocate: function (actor, box, flags) {
let childBox = new Clutter.ActorBox();
let totalWidth = box.x2 - box.x1;
// width of the controls
let [controlsMin, controlsNatural] = this._controls.get_preferred_width(box.y2 - box.y1);
// Amount of space on the screen we reserve for the visible control
let controlsVisible = this._controls.get_theme_node().get_length('visible-width');
let controlsReserved = controlsVisible * (1 - this._zoomFraction) + controlsNatural * this._zoomFraction;
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
if (rtl) {
childBox.x2 = controlsReserved;
childBox.x1 = childBox.x2 - controlsNatural;
} else {
childBox.x1 = totalWidth - controlsReserved;
childBox.x2 = childBox.x1 + controlsNatural;
}
childBox.y1 = 0;
childBox.y2 = box.y2- box.y1;
this._controls.allocate(childBox, flags);
this._updateWorkspacesGeometry();
},
@ -725,15 +851,24 @@ const WorkspacesDisplay = new Lang.Class({
let width = fullWidth;
let height = fullHeight;
let [controlsMin, controlsNatural] = this._controls.get_preferred_width(height);
let controlsVisible = this._controls.get_theme_node().get_length('visible-width');
let [x, y] = this.actor.get_transformed_position();
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
let clipWidth = width;
let clipWidth = width - controlsVisible;
let clipHeight = fullHeight;
let clipX = x;
let clipX = rtl ? x + controlsVisible : x;
let clipY = y + (fullHeight - clipHeight) / 2;
let widthAdjust = this._zoomOut ? controlsNatural : controlsVisible;
widthAdjust += Main.overview._spacing;
width -= widthAdjust;
if (rtl)
x += widthAdjust;
let monitors = Main.layoutManager.monitors;
let m = 0;
for (let i = 0; i < monitors.length; i++) {
@ -756,12 +891,25 @@ const WorkspacesDisplay = new Lang.Class({
}
},
_onRestacked: function(actor, stackIndices) {
_onRestacked: function() {
let stack = global.get_window_actors();
let stackIndices = {};
for (let i = 0; i < stack.length; i++) {
// Use the stable sequence for an integer to use as a hash key
stackIndices[stack[i].get_meta_window().get_stable_sequence()] = i;
}
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].syncStacking(stackIndices);
this._thumbnailsBox.syncStacking(stackIndices);
},
_workspacesChanged: function() {
this._updateAlwaysZoom();
this._updateZoom();
if (this._workspacesViews == null)
return;
@ -786,6 +934,8 @@ const WorkspacesDisplay = new Lang.Class({
}
m++;
}
this._thumbnailsBox.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces);
} else {
// Assume workspaces are only removed sequentially
// (e.g. 2,3,4 - not 2,4,7)
@ -808,6 +958,8 @@ const WorkspacesDisplay = new Lang.Class({
lostWorkspaces[l].destroy();
}
}
this._thumbnailsBox.removeThumbnails(removedIndex, removedNum);
}
for (let i = 0; i < this._workspacesViews.length; i++)
@ -816,6 +968,35 @@ const WorkspacesDisplay = new Lang.Class({
this._updateSwitcherVisibility();
},
_updateZoom : function() {
if (Main.overview.animationInProgress)
return;
let shouldZoom = this._alwaysZoomOut || this._controls.hover;
if (shouldZoom != this._zoomOut) {
this._zoomOut = shouldZoom;
this._updateWorkspacesGeometry();
if (!this._workspacesViews)
return;
Tweener.addTween(this,
{ zoomFraction: this._zoomOut ? 1 : 0,
time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad' });
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].updateWindowPositions();
}
},
_onControlsHoverChanged: function() {
if(!this._controls.hover)
this._controlsInitiallyHovered = false;
if(!this._controlsInitiallyHovered)
this._updateZoom();
},
_dragBegin: function() {
this._inDrag = true;
this._cancelledDrag = false;
@ -831,11 +1012,33 @@ const WorkspacesDisplay = new Lang.Class({
},
_onDragMotion: function(dragEvent) {
let controlsHovered = this._controls.contains(dragEvent.targetActor);
this._controls.set_hover(controlsHovered);
return DND.DragMotionResult.CONTINUE;
},
_dragEnd: function() {
this._inDrag = false;
// We do this deferred because drag-end is emitted before dnd.js emits
// event/leave events that were suppressed during the drag. If we didn't
// defer this, we'd zoom out then immediately zoom in because of the
// enter event we received. That would normally be invisible but we
// might as well avoid it.
Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
Lang.bind(this, this._updateZoom));
},
_onScrollEvent: function (actor, event) {
switch ( event.get_scroll_direction() ) {
case Clutter.ScrollDirection.UP:
Main.wm.actionMoveWorkspace(Meta.MotionDirection.UP);
break;
case Clutter.ScrollDirection.DOWN:
Main.wm.actionMoveWorkspace(Meta.MotionDirection.DOWN);
break;
}
}
});
Signals.addSignalMethods(WorkspacesDisplay.prototype);

View File

@ -1,30 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const St = imports.gi.St;
const CenterLayout = imports.ui.centerLayout;
const UI = imports.testcommon.ui;
function test() {
let stage = new Clutter.Stage({ user_resizable: true });
UI.init(stage);
////////////////////////////////////////////////////////////////////////////////
let container = new St.Widget({ style: 'border: 2px solid black;',
layout_manager: new CenterLayout.CenterLayout() });
container.add_constraint(new Clutter.BindConstraint({ coordinate: Clutter.BindCoordinate.SIZE, source: stage }));
stage.add_actor(container);
let left = new Clutter.Actor({ background_color: Clutter.Color.get_static(Clutter.StaticColor.RED), width: 300 });
let center = new Clutter.Actor({ background_color: Clutter.Color.get_static(Clutter.StaticColor.BLUE), width: 100 });
let right = new Clutter.Actor({ background_color: Clutter.Color.get_static(Clutter.StaticColor.YELLOW), width: 200 });
container.add_actor(left);
container.add_actor(center);
container.add_actor(right);
UI.main(stage);
}
test();