Compare commits
8 Commits
wip/gdbus-
...
screen-shi
Author | SHA1 | Date | |
---|---|---|---|
6e448a2711 | |||
1d484e2278 | |||
0b7ca098ad | |||
5cb9aa9cf3 | |||
0171e561f2 | |||
82f7431a28 | |||
29958df7e7 | |||
2f990346df |
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,7 +16,6 @@ config.log
|
|||||||
config.status
|
config.status
|
||||||
config
|
config
|
||||||
configure
|
configure
|
||||||
data/50-gnome-shell-*.xml
|
|
||||||
data/gnome-shell.desktop
|
data/gnome-shell.desktop
|
||||||
data/gnome-shell.desktop.in
|
data/gnome-shell.desktop.in
|
||||||
data/gnome-shell-extension-prefs.desktop
|
data/gnome-shell-extension-prefs.desktop
|
||||||
|
331
HACKING
331
HACKING
@ -1,331 +0,0 @@
|
|||||||
Coding guide
|
|
||||||
============
|
|
||||||
|
|
||||||
Our goal is to have all JavaScript code in GNOME follow a consistent style. In
|
|
||||||
a dynamic language like JavaScript, it is essential to be rigorous about style
|
|
||||||
(and unit tests), or you rapidly end up with a spaghetti-code mess.
|
|
||||||
|
|
||||||
A quick note
|
|
||||||
------------
|
|
||||||
|
|
||||||
Life isn't fun if you can't break the rules. If a rule seems unnecessarily
|
|
||||||
restrictive while you're coding, ignore it, and let the patch reviewer decide
|
|
||||||
what to do.
|
|
||||||
|
|
||||||
Indentation and whitespace
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
Use four-space indents. Braces are on the same line as their associated
|
|
||||||
statements. You should only omit braces if *both* sides of the statement are
|
|
||||||
on one line.
|
|
||||||
|
|
||||||
* One space after the `function` keyword. No space between the function name
|
|
||||||
* in a declaration or a call. One space before the parens in the `if`
|
|
||||||
* statements, or `while`, or `for` loops.
|
|
||||||
|
|
||||||
function foo(a, b) {
|
|
||||||
let bar;
|
|
||||||
|
|
||||||
if (a > b)
|
|
||||||
bar = do_thing(a);
|
|
||||||
else
|
|
||||||
bar = do_thing(b);
|
|
||||||
|
|
||||||
if (var == 5) {
|
|
||||||
for (let i = 0; i < 10; i++) {
|
|
||||||
print(i);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print(20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Semicolons
|
|
||||||
----------
|
|
||||||
|
|
||||||
JavaScript allows omitting semicolons at the end of lines, but don't. Always
|
|
||||||
end statements with a semicolon.
|
|
||||||
|
|
||||||
js2-mode
|
|
||||||
--------
|
|
||||||
|
|
||||||
If using Emacs, do not use js2-mode. It is outdated and hasn't worked for a
|
|
||||||
while. emacs now has a built-in JavaScript mode, js-mode, based on
|
|
||||||
espresso-mode. It is the de facto emacs mode for JavaScript.
|
|
||||||
|
|
||||||
File naming and creation
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
For JavaScript files, use lowerCamelCase-style names, with a `.js` extension.
|
|
||||||
|
|
||||||
We only use C where gjs/gobject-introspection is not available for the task, or
|
|
||||||
where C would be cleaner. To work around limitations in
|
|
||||||
gjs/gobject-introspection itself, add a new method in `shell-util.[ch]`.
|
|
||||||
|
|
||||||
Like many other GNOME projects, we prefix our C source filenames with the
|
|
||||||
library name followed by a dash, e.g. `shell-app-system.c`. Create a
|
|
||||||
`-private.h` header when you want to share code internally in the
|
|
||||||
library. These headers are not installed, distributed or introspected.
|
|
||||||
|
|
||||||
Imports
|
|
||||||
-------
|
|
||||||
|
|
||||||
Use UpperCamelCase when importing modules to distinguish them from ordinary
|
|
||||||
variables, e.g.
|
|
||||||
|
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
|
|
||||||
Imports should be categorized into one of two places. The top-most import block
|
|
||||||
should contain only "environment imports". These are either modules from
|
|
||||||
gobject-introspection or modules added by gjs itself.
|
|
||||||
|
|
||||||
The second block of imports should contain only "application imports". These
|
|
||||||
are the JS code that is in the gnome-shell codebase,
|
|
||||||
e.g. `imports.ui.popupMenu`.
|
|
||||||
|
|
||||||
Each import block should be sorted alphabetically. Don't import modules you
|
|
||||||
don't use.
|
|
||||||
|
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const Gio = imports.gi.Gio;
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const St = imports.gi.St;
|
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
|
||||||
const Params = imports.misc.params;
|
|
||||||
const Tweener = imports.ui.tweener;
|
|
||||||
const Util = imports.misc.util;
|
|
||||||
|
|
||||||
The alphabetical ordering should be done independently of the location of the
|
|
||||||
location. Never reference `imports` in actual code.
|
|
||||||
|
|
||||||
Constants
|
|
||||||
---------
|
|
||||||
|
|
||||||
We use CONSTANTS_CASE to define constants. All constants should be directly
|
|
||||||
under the imports:
|
|
||||||
|
|
||||||
const MY_DBUS_INTERFACE = 'org.my.Interface';
|
|
||||||
|
|
||||||
Variable declaration
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
Always use either `const` or `let` when defining a variable.
|
|
||||||
|
|
||||||
// Iterating over an array
|
|
||||||
for (let i = 0; i < arr.length; ++i) {
|
|
||||||
let item = arr[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterating over an object's properties
|
|
||||||
for (let prop in someobj) {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
If you use "var" then the variable is added to function scope, not block scope.
|
|
||||||
See [What's new in JavaScript 1.7](https://developer.mozilla.org/en/JavaScript/New_in_JavaScript/1.7#Block_scope_with_let_%28Merge_into_let_Statement%29)
|
|
||||||
|
|
||||||
Classes
|
|
||||||
-------
|
|
||||||
|
|
||||||
There are many approaches to classes in JavaScript. We use our own class framework
|
|
||||||
(sigh), which is built in gjs. The advantage is that it supports inheriting from
|
|
||||||
GObjects, although this feature isn't used very often in the Shell itself.
|
|
||||||
|
|
||||||
const IconLabelMenuItem = new Lang.Class({
|
|
||||||
Name: 'IconLabelMenuItem',
|
|
||||||
Extends: PopupMenu.PopupMenuBaseItem,
|
|
||||||
|
|
||||||
_init: function(icon, label) {
|
|
||||||
this.parent({ reactive: false });
|
|
||||||
this.addActor(icon);
|
|
||||||
this.addActor(label);
|
|
||||||
},
|
|
||||||
|
|
||||||
open: function() {
|
|
||||||
log("menu opened!");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
* 'Name' is required. 'Extends' is optional. If you leave it out, you will
|
|
||||||
automatically inherit from Object.
|
|
||||||
|
|
||||||
* Leave a blank line between the "class header" (Name, Extends, and other
|
|
||||||
things) and the "class body" (methods). Leave a blank line between each
|
|
||||||
method.
|
|
||||||
|
|
||||||
* No space before the colon, one space after.
|
|
||||||
|
|
||||||
* No trailing comma after the last item.
|
|
||||||
|
|
||||||
* Make sure to use a semicolon after the closing paren to the class. It's
|
|
||||||
still a giant function call, even though it may resemble a more
|
|
||||||
conventional syntax.
|
|
||||||
|
|
||||||
GObject Introspection
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
GObject Introspection is a powerful feature that allows us to have native
|
|
||||||
bindings for almost any library built around GObject. If a library requires
|
|
||||||
you to inherit from a type to use it, you can do so:
|
|
||||||
|
|
||||||
const MyClutterActor = new Lang.Class({
|
|
||||||
Name: 'MyClutterActor',
|
|
||||||
Extends: Clutter.Actor,
|
|
||||||
|
|
||||||
vfunc_get_preferred_width: function(actor, forHeight) {
|
|
||||||
return [100, 100];
|
|
||||||
},
|
|
||||||
|
|
||||||
vfunc_get_preferred_height: function(actor, forWidth) {
|
|
||||||
return [100, 100];
|
|
||||||
},
|
|
||||||
|
|
||||||
vfunc_paint: function(actor) {
|
|
||||||
let alloc = this.get_allocation_box();
|
|
||||||
Cogl.set_source_color4ub(255, 0, 0, 255);
|
|
||||||
Cogl.rectangle(alloc.x1, alloc.y1,
|
|
||||||
alloc.x2, alloc.y2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Translatable strings, `environment.js`
|
|
||||||
--------------------------------------
|
|
||||||
|
|
||||||
We use gettext to translate the GNOME Shell into all the languages that GNOME
|
|
||||||
supports. The `gettext` function is aliased globally as `_`, you do not need to
|
|
||||||
explicitly import it. This is done through some magic in the
|
|
||||||
[environment.js](http://git.gnome.org/browse/gnome-shell/tree/js/ui/environment.js)
|
|
||||||
file. If you can't find a method that's used, it's probably either in gjs itself
|
|
||||||
or installed on the global object from the Environment.
|
|
||||||
|
|
||||||
Use 'single quotes' for programming strings that should not be translated
|
|
||||||
and "double quotes" for strings that the user may see. This allows us to
|
|
||||||
quickly find untranslated or mistranslated strings by grepping through the
|
|
||||||
sources for double quotes without a gettext call around them.
|
|
||||||
|
|
||||||
`actor` and `_delegate`
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
gjs allows us to set so-called "expando properties" on introspected objects,
|
|
||||||
allowing us to treat them like any other. Because the Shell was built before
|
|
||||||
you could inherit from GTypes natively in JS, we usually have a wrapper class
|
|
||||||
that has a property called `actor`. We call this wrapper class the "delegate".
|
|
||||||
|
|
||||||
We sometimes use expando properties to set a property called `_delegate` on
|
|
||||||
the actor itself:
|
|
||||||
|
|
||||||
const MyClass = new Lang.Class({
|
|
||||||
Name: 'MyClass',
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this.actor = new St.Button({ text: "This is a button" });
|
|
||||||
this.actor._delegate = this;
|
|
||||||
|
|
||||||
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
|
||||||
},
|
|
||||||
|
|
||||||
_onClicked: function(actor) {
|
|
||||||
actor.set_label("You clicked the button!");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
The 'delegate' property is important for anything which trying to get the
|
|
||||||
delegate object from an associated actor. For instance, the drag and drop
|
|
||||||
system calls the `handleDragOver` function on the delegate of a "drop target"
|
|
||||||
when the user drags an item over it. If you do not set the `_delegate`
|
|
||||||
property, your actor will not be able to be dropped onto.
|
|
||||||
|
|
||||||
Functional style
|
|
||||||
----------------
|
|
||||||
|
|
||||||
JavaScript Array objects offer a lot of common functional programming
|
|
||||||
capabilities such as forEach, map, filter and so on. You can use these when
|
|
||||||
they make sense, but please don't have a spaghetti mess of function programming
|
|
||||||
messed in a procedural style. Use your best judgment.
|
|
||||||
|
|
||||||
Closures
|
|
||||||
--------
|
|
||||||
|
|
||||||
`this` will not be captured in a closure, it is relative to how the closure is
|
|
||||||
invoked, not to the value of this where the closure is created, because "this"
|
|
||||||
is a keyword with a value passed in at function invocation time, it is not a
|
|
||||||
variable that can be captured in closures.
|
|
||||||
|
|
||||||
All closures should be wrapped with a Lang.bind.
|
|
||||||
|
|
||||||
const Lang = imports.lang;
|
|
||||||
|
|
||||||
let closure = Lang.bind(this, function() { this._fnorbate(); });
|
|
||||||
|
|
||||||
A more realistic example would be connecting to a signal on a method of a
|
|
||||||
prototype:
|
|
||||||
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const FnorbLib = imports.fborbLib;
|
|
||||||
|
|
||||||
const MyClass = new Lang.Class({
|
|
||||||
_init: function() {
|
|
||||||
let fnorb = new FnorbLib.Fnorb();
|
|
||||||
fnorb.connect('frobate', Lang.bind(this, this._onFnorbFrobate));
|
|
||||||
},
|
|
||||||
|
|
||||||
_onFnorbFrobate: function(fnorb) {
|
|
||||||
this._updateFnorb();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Object literal syntax
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
In JavaScript, these are equivalent:
|
|
||||||
|
|
||||||
foo = { 'bar': 42 };
|
|
||||||
foo = { bar: 42 };
|
|
||||||
|
|
||||||
and so are these:
|
|
||||||
|
|
||||||
var b = foo['bar'];
|
|
||||||
var b = foo.bar;
|
|
||||||
|
|
||||||
If your usage of an object is like an object, then you're defining "member
|
|
||||||
variables." For member variables, use the no-quotes no-brackets syntax: `{ bar:
|
|
||||||
42 }` `foo.bar`.
|
|
||||||
|
|
||||||
If your usage of an object is like a hash table (and thus conceptually the keys
|
|
||||||
can have special chars in them), don't use quotes, but use brackets: `{ bar: 42
|
|
||||||
}`, `foo['bar']`.
|
|
||||||
|
|
||||||
Getters, setters, and Tweener
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
Getters and setters should be used when you are dealing with an API that is
|
|
||||||
designed around setting properties, like Tweener. If you want to animate an
|
|
||||||
arbitrary property, create a getter and setter, and use Tweener to animate the
|
|
||||||
property.
|
|
||||||
|
|
||||||
const ANIMATION_TIME = 2000;
|
|
||||||
|
|
||||||
const MyClass = new Lang.Class({
|
|
||||||
Name: 'MyClass',
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this.actor = new St.BoxLayout();
|
|
||||||
this._position = 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
get position() {
|
|
||||||
return this._position;
|
|
||||||
},
|
|
||||||
|
|
||||||
set position(value) {
|
|
||||||
this._position = value;
|
|
||||||
this.actor.set_position(value, value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let myThing = new MyClass();
|
|
||||||
Tweener.addTween(myThing,
|
|
||||||
{ position: 100,
|
|
||||||
time: ANIMATION_TIME,
|
|
||||||
transition: 'easeOutQuad' });
|
|
@ -13,7 +13,6 @@ EXTRA_DIST = \
|
|||||||
DIST_EXCLUDE = \
|
DIST_EXCLUDE = \
|
||||||
.gitignore \
|
.gitignore \
|
||||||
gnome-shell.doap \
|
gnome-shell.doap \
|
||||||
HACKING \
|
|
||||||
MAINTAINERS \
|
MAINTAINERS \
|
||||||
tools/build/*
|
tools/build/*
|
||||||
|
|
||||||
|
324
NEWS
324
NEWS
@ -1,327 +1,3 @@
|
|||||||
3.7.1
|
|
||||||
=====
|
|
||||||
* Add shortcut to open application view directly [Jeremy; #685738]
|
|
||||||
* Expose '<Super>F10' shortcut in System Settings [Florian; #672909]
|
|
||||||
* Clean up timestamp format in chat notifications [Carlos; #680989]
|
|
||||||
* loginScreen: Add support for 'disable-restart-buttons' [Florian; #686247]
|
|
||||||
* Update textures automatically on file changes [Florian; #679268]
|
|
||||||
* Implement org.gnome.ScreenSaver.GetActiveTime [Giovanni; #686064]
|
|
||||||
* Add missing translations for GSetting schema [Giovanni; #686413]
|
|
||||||
* Hide workspace switcher completely when it's not necessary [Seif; #686483]
|
|
||||||
* Explicitly load gnome-screensaver when not running GDM [Tim; #683060]
|
|
||||||
* Port to GnomeIdleMonitor [Jasper; #682224]
|
|
||||||
* Set Empathy as preferred handler when delegating channels [Xavier; #686296]
|
|
||||||
* Allow testing GDM login dialog from the session [Giovanni; #683725]
|
|
||||||
* Use all available space for windows in window picker [Jasper, Pierre-Eric;
|
|
||||||
#582650]
|
|
||||||
* Use logind for suspend if available [Florian; #686482]
|
|
||||||
* Misc. fixes and cleanups [Jasper, Florian, Adel, Rui; #677426, #680426,
|
|
||||||
#686233, #686241, #686318, #686240, #686484, #686002, #684650, #686487]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Jeremy Bicha, Giovanni Campagna, Xavier Claessens, Adel Gadllah, Seif Lotfy,
|
|
||||||
Tim Lunn, Rui Matos, Florian Müllner, Pierre-Eric Pelloux-Prayer,
|
|
||||||
Carlos Soriano, Jasper St. Pierre
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
Andika Triwidada [id], Matej Urbančič [sl], Ihar Hrachyshka [be],
|
|
||||||
Daniel Mustieles [es], Fran Diéguez [gl], Takayuki KUSANO [ja],
|
|
||||||
Мирослав Николић [sr, sr@latin], Dušan Kazik [sk], Tom Tryfonidis [el]
|
|
||||||
|
|
||||||
3.6.1
|
|
||||||
=====
|
|
||||||
* dash: Make padding even on the top/bottom of the dash [Jasper; #684619]
|
|
||||||
* Fix a crash when dragging search results [Jasper; #684888]
|
|
||||||
* workspaceThumbnail: Fix dragging with static workspaces [Jasper; #684641]
|
|
||||||
* Really hide 'Show Keyboard Layout' on the lock screen [Matthias]
|
|
||||||
* Misc. improvements to jhbuild setup [Owen; #685352, #685353, #685354, #685355]
|
|
||||||
* Show message tray in Ctrl+Alt+Tab outside of the overview [Jasper, Florian;
|
|
||||||
#684633, #685914]
|
|
||||||
* Disable hotplug sniffer on remote filesystems [Jasper; #684093]
|
|
||||||
* userMenu: Remove 'Switch Session' item [Florian; #685062]
|
|
||||||
* unlockDialog: Make prompt entry insensitive while logging in [Jasper; #685444]
|
|
||||||
* messageTray: Don't animate desktop clone for failed grabs [Jasper; #685342]
|
|
||||||
* Fix crash on dragging windows between workspaces [Ryan; #681399]
|
|
||||||
* userMenu: Ignore 'lock-enabled' setting for user switching [Florian; #685536]
|
|
||||||
* gdm: Fix key-focus on first user [Adel; #684650]
|
|
||||||
* Make grid button insensitive when dragging non-favorites [Jasper; #685313]
|
|
||||||
* Calendar: hide all actions when on the login screen [Matthias; #685142]
|
|
||||||
* Adapt unlock dialog layout for the login screen [Florian; #685201]
|
|
||||||
* Make focus-follows-mouse work better with Shell UI [Florian; #678169]
|
|
||||||
* Improve look of screen shield [Jasper; #685919]
|
|
||||||
* Fix keynav in the login screen [Florian; #684730]
|
|
||||||
* dateMenu: Hide "Open Calendar" item if calendar unavailable [Florian; #686050]
|
|
||||||
* unlockDialog: Reset UI on verification failure [Giovanni; #685441]
|
|
||||||
* Show unlock dialog on primary monitor when using keynav [Giovanni; #685855]
|
|
||||||
* Fix height changes of entries when entering text [Florian; #685534]
|
|
||||||
* Fix show-apps label after successful drags [Florian; #684627]
|
|
||||||
* Misc. bugfixes and cleanups [Jasper, Olivier, Florian, Owen, Adel, Tanner, Tim, Matthias; #685434, #685511, #685466, #685341, #685156, #681159, #673189, #686016, 684869, #686079, #686063
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Jasper St. Pierre
|
|
||||||
Matthias Clasen
|
|
||||||
Owen Taylor
|
|
||||||
Olivier Blin
|
|
||||||
Florian Müllner
|
|
||||||
Ryan Lortie
|
|
||||||
Adel Gadllah
|
|
||||||
Tanner Doshier
|
|
||||||
Tim Lunn
|
|
||||||
Giovanni Campagna
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
Tobias Endrigkeit [de], Rudolfs Mazurs [lv], Ask H. Larsen [da],
|
|
||||||
Shankar Prasad [kn], Changwoo Ryu [ko], Chris Leonard [en_GB],
|
|
||||||
Arash Mousavi [fa], Theppitak Karoonboonyanan [th], Seán de Búrca [ga],
|
|
||||||
Yaron Shahrabani [he], Alexander Shopov [bg], Žygimantas Beručka [lt],
|
|
||||||
Milo Casagrande [it], Kjartan Maraas [nb], Kris Thomsen [da],
|
|
||||||
Aurimas Černius [lt], Yuri Myasoedov [ru], Мирослав Николић [sr],
|
|
||||||
Marek Černocký [cs], Gabor Kelemen [hu], Ihar Hrachyshka [be],
|
|
||||||
Chao-Hsiung Liao [zh_HK, zh_TW], Eleanor Chen [zh_CN],
|
|
||||||
Carles Ferrando [ca@valencia], Vicent Cubells [ca], Daniel Korostil [uk],
|
|
||||||
Alexandre Franke [fr], Piotr Drąg [pl]
|
|
||||||
|
|
||||||
3.6.0
|
|
||||||
=====
|
|
||||||
* keyboard: Make input source items accessible [Florian; #684462]
|
|
||||||
* Don't show network dialogs in the lock screen [Giovanni; #684384]
|
|
||||||
* popupMenu: Fix initial visibility of settings items [Florian; #684473]
|
|
||||||
* userMenu: Close menu immediately on user/session switch [Florian; #684459]
|
|
||||||
* Fix alignment of search section headers in RTL locales [Florian; #684379]
|
|
||||||
* screenShield: Fix unlock animation [Florian; #684591]
|
|
||||||
* Don't open the tray from a dwell while in a modal grab [Jasper; #684458]
|
|
||||||
* userMenu: Fix texture updates on icon changes [Florian; #679268]
|
|
||||||
* Fix a11y support in the login screen [Florian, Ray; #684727, #684728, #684748]
|
|
||||||
* Make On-Screen-Keyboard usable with new message tray [Giovanni, Florian;
|
|
||||||
#683546]
|
|
||||||
* Fix initial visibility of input volume in lock-screen [Florian; #684611]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Giovanni Campagna, Florian Müllner, Jasper St. Pierre, Ray Strode
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
Matej Urbančič [sl], Dr.T.Vasudevan [ta], Piotr Drąg [pl], A S Alam [pa],
|
|
||||||
Alexander Shopov [bg], Nilamdyuti Goswami [as], Chandan Kumar [hi],
|
|
||||||
Khaled Hosny [ar], Ibrahim Saed [ar], Sandeep Sheshrao Shedmake [mr],
|
|
||||||
Tom Tryfonidis [el], Theppitak Karoonboonyanan [th], Alexandre Franke [fr],
|
|
||||||
Fran Diéguez [gl], Gabor Kelemen [hu], Ani Peter [ml], Daniel Mustieles [es],
|
|
||||||
Мирослав Николић [sr, sr@latin], Duarte Loreto [pt], ManojKumar Giri [or],
|
|
||||||
Ihar Hrachyshka [be], Aurimas Černius [lt], Djavan Fagundes [pt_BR],
|
|
||||||
Changwoo Ryu [ko], Bruce Cowan [en_GB], Kris Thomsen [da], Gil Forcada [ca],
|
|
||||||
Yaron Shahrabani [he], Milo Casagrande [it], Ville-Pekka Vainio [fi],
|
|
||||||
YunQiang Su [zh_CN], Carles Ferrando [ca@valencia], Mario Blättermann [de],
|
|
||||||
Rajesh Ranjan [hi], Yuri Myasoedov [ru], Rūdolfs Mazurs [lv],
|
|
||||||
Jiro Matsuzawa [ja], Mattias Põldaru [et], Timur Zhamakeev [ky],
|
|
||||||
Petr Kovar [cs], Chao-Hsiung Liao [zh_HK,zh_TW], Andika Triwidada [id]
|
|
||||||
|
|
||||||
3.5.92
|
|
||||||
======
|
|
||||||
* Login/UnlockDialog: Don't reset immediately if auth fails [Giovanni; #682544]
|
|
||||||
* Allow changing session mode at runtime [Jasper, Giovanni; #683156]
|
|
||||||
* Add zoom out animation on login [Jasper; #683170]
|
|
||||||
* Bluetooth: don't restrict the length of non numeric PINs [Giovanni; #683356]
|
|
||||||
* Force chat notification to stay open when focusing entry [Debarshi; #682236]
|
|
||||||
* Make sure the screen is fully locked before suspending [Giovanni; #683448]
|
|
||||||
* st-texture-cache: Fix a case of distorted textures [Florian; #683483]
|
|
||||||
* popupSubMenu: Fix padding for non-scrolled submenus [Florian; #683009]
|
|
||||||
* popupMenu: Fix width changes on submenu open/close [Florian; #683485]
|
|
||||||
* boxpointer: Avoid malformed boxpointer arrow [Debarshi; #680077]
|
|
||||||
* Change stage background color to grey [Adel; #683514]
|
|
||||||
* messageTray: Update style of summary counters [Debarshi; #682891]
|
|
||||||
* Don't fail if a legacy tray icon has no WM_CLASS [Giovanni; #683724]
|
|
||||||
* PolkitAgent: Fix a crash if there is no avatar [Giovanni; #683707]
|
|
||||||
* Hide the a11y menu in the lock screen, but show it in the login screen
|
|
||||||
[Giovanni; #682542]
|
|
||||||
* Fix show-apps button dropping off the dash [Florian; #683340]
|
|
||||||
* Fix committing strings to shell entries from input method [Florian; #658325]
|
|
||||||
* Make IBus display strings consistent with control-center [Rui; #683124]
|
|
||||||
* Fix missing short codes for some input sources [Rui; #683613]
|
|
||||||
* Remove support for long-press from entry context menus [Jasper; #683509]
|
|
||||||
* screenShield: Add box-shadow to the shield [Florian]
|
|
||||||
* Don't show a right-click menu for the hotplug source [Jasper; #683438]
|
|
||||||
* Fix extension styling [Giovanni; #682128]
|
|
||||||
* Fix on-screen keyboard not working with system-modal dialogs
|
|
||||||
[Giovanni; #664309]
|
|
||||||
* Fix insensitive styling for popup menu items [Giovanni; #683988]
|
|
||||||
* Disable the message tray dwell when the user is interacting [Owen; #683811]
|
|
||||||
* Animate going from the unlock dialog to the lock screen [Giovanni; #681143]
|
|
||||||
* Autostart fprintd when necessary [Ray; #683131]
|
|
||||||
* UnlockDialog: Allow typing before the first PAM question [Giovanni; #681576]
|
|
||||||
* Make Return key dismiss screenshield [Ray; #683889]
|
|
||||||
* Fix keyboard navigation in the message tray [Florian; #682243]
|
|
||||||
* Remove the places & devices search provider [Giovanni; #683506]
|
|
||||||
* Enable hot corner while the message tray is up [Florian; #682255]
|
|
||||||
* Port screen recorder to new GStreamer vp8enc API [Adel; #684206]
|
|
||||||
* Fix fish flickering [Giovanni; #684154]
|
|
||||||
* Fix extension ordering with !important [Jasper; #684163]
|
|
||||||
* Allow the shell to run without the screenshield [Giovanni; #683060]
|
|
||||||
* Add menu items for IBus Anthy's InputMode, TypingMode [Rui; #682314]
|
|
||||||
* Improve transition to the login dialog [Jasper; #682428]
|
|
||||||
* Keep unlock dialog around until shield animation ends [Florian; #684342]
|
|
||||||
* Expose shell keybindings in System Settings [Florian; #671010]
|
|
||||||
* Misc. bugfixes and cleanups [Debarshi, Florian, Giovanni, Jasper, Rico, Rui;
|
|
||||||
#672790, #677434, #683305, #683357, #683369, #683377, #683378, #683400,
|
|
||||||
#683449, #683472, #683482, #683487, #683488, #683526, #683529, #683546,
|
|
||||||
#683583, #683628, #683705, #683982, #683989, #684035, #684036, #684040,
|
|
||||||
#684162, #684214, #684343]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Giovanni Campagna, Adel Gadllah, Rui Matos, Florian Müllner, Debarshi Ray,
|
|
||||||
Jasper St. Pierre, Ray Strode, Owen Taylor, Rico Tzschichholz
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
Gabor Kelemen [hu], Piotr Drąg [pl], Khaled Hosny [ar],
|
|
||||||
Мирослав Николић [sr, sr@latin], Chao-Hsiung Liao [zh_HK, zh_TW],
|
|
||||||
Bruce Cowan [en_GB], Dirgita [id], Tom Tryfonidis [el], Timo Jyrinki [fi],
|
|
||||||
Adorilson Bezerra [pt_BR], Arash Mousavi [fa], Matej Urbančič [sl],
|
|
||||||
Christian Kirbach [de], Yaron Shahrabani [he], Ihar Hrachyshka [be],
|
|
||||||
Changwoo Ryu [ko], Duarte Loreto [pt], Theppitak Karoonboonyanan [th],
|
|
||||||
Nilamdyuti Goswami [as], Sandeep Sheshrao Shedmake [mr],
|
|
||||||
Alexandre Franke [fr], Ivaylo Valkov [bg], tuhaihe [zh_CN],
|
|
||||||
Yuri Myasoedov [ru], Aurimas Černius [lt], Andika Triwidada [id],
|
|
||||||
Rajesh Ranjan [hi], Sweta Kothari [gu], Daniel Mustieles [es],
|
|
||||||
Fran Diéguez [gl], Praveen Illa [te]
|
|
||||||
|
|
||||||
3.5.91
|
|
||||||
======
|
|
||||||
* Improve modal dialog styling of network secret prompts [Jasper; #682412]
|
|
||||||
* Fix visibility of non-active workspaces during overview transition
|
|
||||||
[Florian; #682002]
|
|
||||||
* Improve scrollbar theming [Cosimo; #682476]
|
|
||||||
* Make sure the app menu remains hidden in locked state [Florian; #682475]
|
|
||||||
* Add tooltip to show-applications icon [Jasper; #682445]
|
|
||||||
* Do not add duplicate remote search providers [Florian; #682470]
|
|
||||||
* Handle 'popup-menu' signal on summary items [Florian; #682486]
|
|
||||||
* Fix dwelling during mouse-down [Owen; #682385]
|
|
||||||
* Set label actor for endSessionDialog.ListItem [Alejandro; #677503]
|
|
||||||
* Don't match on comments when searching applications [Florian; #682529]
|
|
||||||
* Make workspace selector more similar to the mockup [Stefano; #662087]
|
|
||||||
* Fix extension installation and reloading [Jasper; #682578]
|
|
||||||
* Hide removable devices in the lock screen [Giovanni; #681143]
|
|
||||||
* Reset cancellable after hitting Escape on login screen [Alban; #681537]
|
|
||||||
* Fix suspend from the user menu [Giovanni; #682746]
|
|
||||||
* Set label actor for summary items in message tray [Alejandro; #677229]
|
|
||||||
* Set label for the "Show applications" dash button [Alejandro; #682366]
|
|
||||||
* Load extensions as late as possible [Jasper; #682822]
|
|
||||||
* Improve mount operation dialogs [Jon; #682645]
|
|
||||||
* Remove "Connect to ..." item from places search [Florian; #682817]
|
|
||||||
* Don't auto-expand notifications with actions [Giovanni; #682738]
|
|
||||||
* Add a new lock screen menu to combine volume network and power
|
|
||||||
[Giovanni; #682540]
|
|
||||||
* Add support for pre-edit to StIMText [Daiki; #664041]
|
|
||||||
* Remove StIconType [Jasper, Florian, Rui, Giovanni, Debarshi; #682540]
|
|
||||||
* Use monitor geometry for dwelling [Florian; #683044]
|
|
||||||
* Add support for surrounding-text to StIMText [Daiki; #683015]
|
|
||||||
* Improve the placement and style of the "No results" text [Jasper; #683135]
|
|
||||||
* Remove broken network device activation policy [Giovanni; #683136]
|
|
||||||
* Hide power status icon when no battery is present [Tim; #683080]
|
|
||||||
* Ensure summary items are square and have spacing [Debarshi; #682248]
|
|
||||||
* Fix close buttons overlapping screen edge [Debarshi; #682343]
|
|
||||||
* Escape the tray when a legacy icon is clicked [Giovanni; #682244]
|
|
||||||
* Update arrow in the screen shield to match latest mockups [Giovanni; #682285]
|
|
||||||
* Allow lifting the screen shield with the mouse wheel [Giovanni; #683164]
|
|
||||||
* Make sure to show the app menu after unlocking the screen [Jasper; #683154]
|
|
||||||
* Misc bug fixes and cleanups [Debarshi, Florian, Giovanni, Jasper, Rui;
|
|
||||||
#582650, #667439, #682238, #682268, #682429, #682455, #682544, #682546,
|
|
||||||
#682683, #682710, #682998, #683073, #683137, #683156]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Alban Browaeys, Giovanni Campagna, Cosimo Cecchi, Stefano Facchini,
|
|
||||||
Adel Gadllah, Tim Lunn, Rui Matos, William Jon McCann, Florian Müllner,
|
|
||||||
Alejandro Piñeiro, Debarshi Ray, Jasper St. Pierre, Owen Taylor, Daiki Ueno
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
Piotr Drąg [pl], Takayuki KUSANO [ja], Kjartan Maraas [nb],
|
|
||||||
Aurimas Černius [lt], Daniel Mustieles [es], Yuri Myasoedov [ru],
|
|
||||||
Khaled Hosny [ar], Yaron Shahrabani [he], Tom Tryfonidis [el],
|
|
||||||
Nilamdyuti Goswami [as], Fran Diéguez [gl], Nguyễn Thái Ngọc Duy [vi],
|
|
||||||
A S Alam [pa], Dr.T.Vasudevan [ta], Luca Ferretti [it]
|
|
||||||
|
|
||||||
3.5.90
|
|
||||||
======
|
|
||||||
* Use symbolic icons for workspace switch OSD [Jon; #680738]
|
|
||||||
* Lock screen improvements:
|
|
||||||
- Hide user menu and a11y menu in the screen lock [Giovanni; #681143]
|
|
||||||
- Bump the lock screen slightly when pressing a key [Giovanni; #681143]
|
|
||||||
- Constrain vertical movement of the screen shield [Giovanni; #681143]
|
|
||||||
- Return to lock screen on idle [Giovanni; #682041]
|
|
||||||
- Unlock screen automatically after fast-user switching [Giovanni; #682096]
|
|
||||||
- Fix "other user" label [Ray; #681750]
|
|
||||||
* Constrain content of system modals to primary monitor [#681743]
|
|
||||||
* Respect automatic lock setting on suspend/user-switch [Giovanni; #680231]
|
|
||||||
* Improve styling of keyring prompt [Jasper; #681821]
|
|
||||||
* Do not hard-code <super> as overlay-key [Florian; #665547]
|
|
||||||
* Update style of attached modal dialogs [Florian; #681601]
|
|
||||||
* a11y: allow navigation on non reactive items [Alejandro; #667439, #667439]
|
|
||||||
* Implement mode-less overview design [Joost, Florian; #682109]
|
|
||||||
* Implement message-tray redesign:
|
|
||||||
- Restyle the message tray [Ana, Allan, Florian; #677213, #682342]
|
|
||||||
- Move the desktop upwards when showing the tray [Debarshi; #681392]
|
|
||||||
- Add a close button to notifications [Ana, Jasper; #682253]
|
|
||||||
- Add a keybinding to toggle the tray [Debarshi; #681392]
|
|
||||||
- Make the tray keyboard navigable [Debarshi; #681519]
|
|
||||||
- Add dwelling at the bottom of the screen to open the tray [Owen; #682310]
|
|
||||||
- Don't time out banners when the user is inactive [Marina, Jasper]
|
|
||||||
- Misc fixes and cleanups [Jasper, Marina]
|
|
||||||
* Fix showing "Next Week" on Sundays [Sebastian; #682198]
|
|
||||||
* Delay restoring IM presence until the network comes up [Florian; #677982]
|
|
||||||
* Display enterprise login hint [Ray; #681975]
|
|
||||||
* Ignore unrecognized/irrelevant network devices/connections [Dan; #682364]
|
|
||||||
* Misc bug fixes and cleanups: [Dan, Florian, Jasper, Jiro, Piotr, Rico;
|
|
||||||
#643687, #682045, #682189]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Giovanni Campagna, Allan Day, Piotr Drąg, William Jon McCann,
|
|
||||||
Sebastian Keller, Jiro Matsuzawa, Florian Müllner, Alejandro Piñeiro,
|
|
||||||
Debarshi Ray, Ana Risteska, Jasper St. Pierre, Ray Strode, Owen Taylor,
|
|
||||||
Rico Tzschichholz, Joost Verdoorn, Dan Winship, Marina Zhurakhinskaya
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
Nilamdyuti Goswami [as], Daniel Mustieles [es], Yaron Shahrabani [he],
|
|
||||||
Chao-Hsiung Liao [zh_HK, zh_TW], Tobias Endrigkeit [de], A S Alam [pa],
|
|
||||||
Sandeep Sheshrao Shedmake [mr], Fran Diéguez [gl],
|
|
||||||
Мирослав Николић [sr, sr@latin]
|
|
||||||
|
|
||||||
3.5.5
|
|
||||||
=====
|
|
||||||
* Update style to match mockups [Allan]
|
|
||||||
- improve calendar layout and legibility
|
|
||||||
- update notifications and menus
|
|
||||||
- use a common style for entries
|
|
||||||
- update scrollbars to match GTK+
|
|
||||||
- improve clock/unlock button in lock screen
|
|
||||||
- update polkit dialogs [Jasper]
|
|
||||||
* Fix login dialog growing when selecting different users [Florian; #675076]
|
|
||||||
* Implement screen lock in the shell [Giovanni]
|
|
||||||
- restructure login code to be shared with session unlock [#619955]
|
|
||||||
- add initial screen shield / unlock dialog implementation [#619955]
|
|
||||||
- implement (optional) notification list on lock shield [#619955]
|
|
||||||
- update login dialog style to match lock screen [#619955]
|
|
||||||
- filter notifications to only show new ones on the screen lock [#681143]
|
|
||||||
- make notifications scrollable if necessary [#681143]
|
|
||||||
- use correct application names in notifications [#681143]
|
|
||||||
- allow to return to the shield by pressing Escape [#681143]
|
|
||||||
* Minor login dialog improvements [Florian]
|
|
||||||
- update style to match the overall visuals [#660913]
|
|
||||||
- indicate whether users are logged in [#658185]
|
|
||||||
* Add support for background-repeat CSS property [Jasper; #680801]
|
|
||||||
* Add :active pseudo class on scroll handles [Florian]
|
|
||||||
* Remove markup from translated strings [Matthias; #681270]
|
|
||||||
* Misc bug fixes and cleanups: [Alban, Florian, Giovanni, Jasper, Jeremy,
|
|
||||||
Matthias, Piotr; #677893, #679944, #680064, #680170, #680216, #680426,
|
|
||||||
#681101, #681382]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Jeremy Bicha, Alban Browaeys, Giovanni Campagna, Matthias Clasen, Allan Day,
|
|
||||||
Piotr Drąg , Florian Müllner, Jasper St. Pierre
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
Matej Urbančič [sl], Tom Tryfonidis [el], Yaron Shahrabani [he],
|
|
||||||
Kjartan Maraas [nb], Baurzhan Muftakhidinov [kk], Praveen Illa [te],
|
|
||||||
Khaled Hosny [ar], Daniel Mustieles [es], Gabor Kelemen [hu],
|
|
||||||
Fran Diéguez [gl], Sweta Kothari [gu], Aleksej Kabanov [ru],
|
|
||||||
Nilamdyuti Goswami [as], Arash Mousavi [fa], Мирослав Николић [sr, sr@latin]
|
|
||||||
|
|
||||||
3.5.4
|
3.5.4
|
||||||
=====
|
=====
|
||||||
* Fix wrong result handling of remote calls [Florian; #678852]
|
* Fix wrong result handling of remote calls [Florian; #678852]
|
||||||
|
@ -153,6 +153,8 @@ NP_Initialize(NPNetscapeFuncs *pfuncs, NPPluginFuncs *plugin)
|
|||||||
/* global initialization routine, called once when plugin
|
/* global initialization routine, called once when plugin
|
||||||
is loaded */
|
is loaded */
|
||||||
|
|
||||||
|
g_type_init ();
|
||||||
|
|
||||||
g_debug ("plugin loaded");
|
g_debug ("plugin loaded");
|
||||||
|
|
||||||
memcpy (&funcs, pfuncs, sizeof (funcs));
|
memcpy (&funcs, pfuncs, sizeof (funcs));
|
||||||
|
22
configure.ac
22
configure.ac
@ -1,5 +1,5 @@
|
|||||||
AC_PREREQ(2.63)
|
AC_PREREQ(2.63)
|
||||||
AC_INIT([gnome-shell],[3.7.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
AC_INIT([gnome-shell],[3.5.4],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||||
|
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
AC_CONFIG_SRCDIR([src/shell-global.c])
|
AC_CONFIG_SRCDIR([src/shell-global.c])
|
||||||
@ -52,7 +52,7 @@ AC_MSG_CHECKING([for GStreamer (needed for recording functionality)])
|
|||||||
if $PKG_CONFIG --exists gstreamer-1.0 '>=' $GSTREAMER_MIN_VERSION ; then
|
if $PKG_CONFIG --exists gstreamer-1.0 '>=' $GSTREAMER_MIN_VERSION ; then
|
||||||
AC_MSG_RESULT(yes)
|
AC_MSG_RESULT(yes)
|
||||||
build_recorder=true
|
build_recorder=true
|
||||||
recorder_modules="gstreamer-1.0 gstreamer-base-1.0 x11 gtk+-3.0"
|
recorder_modules="gstreamer-1.0 gstreamer-base-1.0 x11"
|
||||||
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0 xfixes gl)
|
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0 xfixes gl)
|
||||||
else
|
else
|
||||||
AC_MSG_RESULT(no)
|
AC_MSG_RESULT(no)
|
||||||
@ -60,12 +60,12 @@ fi
|
|||||||
|
|
||||||
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
||||||
|
|
||||||
CLUTTER_MIN_VERSION=1.11.11
|
CLUTTER_MIN_VERSION=1.9.16
|
||||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
||||||
GJS_MIN_VERSION=1.33.2
|
GJS_MIN_VERSION=1.33.2
|
||||||
MUTTER_MIN_VERSION=3.7.1
|
MUTTER_MIN_VERSION=3.5.4
|
||||||
GTK_MIN_VERSION=3.3.9
|
GTK_MIN_VERSION=3.3.9
|
||||||
GIO_MIN_VERSION=2.35.0
|
GIO_MIN_VERSION=2.31.6
|
||||||
LIBECAL_MIN_VERSION=3.5.3
|
LIBECAL_MIN_VERSION=3.5.3
|
||||||
LIBEDATASERVER_MIN_VERSION=3.5.3
|
LIBEDATASERVER_MIN_VERSION=3.5.3
|
||||||
LIBEDATASERVERUI_MIN_VERSION=3.5.3
|
LIBEDATASERVERUI_MIN_VERSION=3.5.3
|
||||||
@ -74,7 +74,7 @@ TELEPATHY_LOGGER_MIN_VERSION=0.2.4
|
|||||||
POLKIT_MIN_VERSION=0.100
|
POLKIT_MIN_VERSION=0.100
|
||||||
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
||||||
GCR_MIN_VERSION=3.3.90
|
GCR_MIN_VERSION=3.3.90
|
||||||
GNOME_DESKTOP_REQUIRED_VERSION=3.7.1
|
GNOME_DESKTOP_REQUIRED_VERSION=3.5.1
|
||||||
GNOME_MENUS_REQUIRED_VERSION=3.5.3
|
GNOME_MENUS_REQUIRED_VERSION=3.5.3
|
||||||
|
|
||||||
# Collect more than 20 libraries for a prize!
|
# Collect more than 20 libraries for a prize!
|
||||||
@ -97,7 +97,8 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
|
|||||||
telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION
|
telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION
|
||||||
polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes
|
polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes
|
||||||
libnm-glib libnm-util gnome-keyring-1
|
libnm-glib libnm-util gnome-keyring-1
|
||||||
gcr-3 >= $GCR_MIN_VERSION)
|
gcr-3 >= $GCR_MIN_VERSION
|
||||||
|
gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION)
|
||||||
|
|
||||||
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
|
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
|
||||||
|
|
||||||
@ -105,9 +106,6 @@ PKG_CHECK_MODULES(SHELL_HOTPLUG_SNIFFER, gio-2.0 gdk-pixbuf-2.0)
|
|||||||
|
|
||||||
PKG_CHECK_MODULES(BROWSER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION json-glib-1.0 >= 0.13.2)
|
PKG_CHECK_MODULES(BROWSER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION json-glib-1.0 >= 0.13.2)
|
||||||
|
|
||||||
GNOME_KEYBINDINGS_KEYSDIR=`$PKG_CONFIG --variable keysdir gnome-keybindings`
|
|
||||||
AC_SUBST([GNOME_KEYBINDINGS_KEYSDIR])
|
|
||||||
|
|
||||||
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
|
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
|
||||||
|
|
||||||
saved_CFLAGS=$CFLAGS
|
saved_CFLAGS=$CFLAGS
|
||||||
@ -119,7 +117,7 @@ CFLAGS=$saved_CFLAGS
|
|||||||
LIBS=$saved_LIBS
|
LIBS=$saved_LIBS
|
||||||
|
|
||||||
PKG_CHECK_MODULES(GNOME_SHELL_JS, gio-2.0 gjs-internals-1.0 >= $GJS_MIN_VERSION)
|
PKG_CHECK_MODULES(GNOME_SHELL_JS, gio-2.0 gjs-internals-1.0 >= $GJS_MIN_VERSION)
|
||||||
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.8 x11)
|
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.2 x11)
|
||||||
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
|
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
|
||||||
PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
|
PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
|
||||||
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.5.4)
|
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.5.4)
|
||||||
@ -138,7 +136,7 @@ PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0],
|
|||||||
AC_SUBST([HAVE_BLUETOOTH],[0])
|
AC_SUBST([HAVE_BLUETOOTH],[0])
|
||||||
AC_MSG_RESULT([no])])
|
AC_MSG_RESULT([no])])
|
||||||
|
|
||||||
PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION gio-2.0)
|
PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION libedataserverui-3.0 >= $LIBEDATASERVERUI_MIN_VERSION gio-2.0)
|
||||||
AC_SUBST(CALENDAR_SERVER_CFLAGS)
|
AC_SUBST(CALENDAR_SERVER_CFLAGS)
|
||||||
AC_SUBST(CALENDAR_SERVER_LIBS)
|
AC_SUBST(CALENDAR_SERVER_LIBS)
|
||||||
|
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<KeyListEntries schema="org.gnome.shell.keybindings"
|
|
||||||
group="system"
|
|
||||||
_name="Screenshots"
|
|
||||||
wm_name="GNOME Shell"
|
|
||||||
package="gnome-shell">
|
|
||||||
|
|
||||||
<KeyListEntry name="toggle-recording"
|
|
||||||
_description="Record a screencast"/>
|
|
||||||
|
|
||||||
</KeyListEntries>
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<KeyListEntries schema="org.gnome.shell.keybindings"
|
|
||||||
group="system"
|
|
||||||
_name="System"
|
|
||||||
wm_name="GNOME Shell"
|
|
||||||
package="gnome-shell">
|
|
||||||
|
|
||||||
<KeyListEntry name="toggle-message-tray"
|
|
||||||
_description="Show the message tray"/>
|
|
||||||
|
|
||||||
<KeyListEntry name="toggle-application-view"
|
|
||||||
_description="Show all applications"/>
|
|
||||||
|
|
||||||
<KeyListEntry name="open-application-menu"
|
|
||||||
_description="Open the application menu"/>
|
|
||||||
|
|
||||||
</KeyListEntries>
|
|
||||||
|
|
@ -10,6 +10,11 @@ desktop_DATA = gnome-shell.desktop gnome-shell-extension-prefs.desktop
|
|||||||
|
|
||||||
@INTLTOOL_DESKTOP_RULE@
|
@INTLTOOL_DESKTOP_RULE@
|
||||||
|
|
||||||
|
searchprovidersdir = $(pkgdatadir)/open-search-providers
|
||||||
|
dist_searchproviders_DATA = \
|
||||||
|
open-search-providers/google.xml \
|
||||||
|
open-search-providers/wikipedia.xml
|
||||||
|
|
||||||
introspectiondir = $(datadir)/dbus-1/interfaces
|
introspectiondir = $(datadir)/dbus-1/interfaces
|
||||||
introspection_DATA = org.gnome.ShellSearchProvider.xml
|
introspection_DATA = org.gnome.ShellSearchProvider.xml
|
||||||
|
|
||||||
@ -31,7 +36,6 @@ dist_theme_DATA = \
|
|||||||
theme/filter-selected-rtl.svg \
|
theme/filter-selected-rtl.svg \
|
||||||
theme/gnome-shell.css \
|
theme/gnome-shell.css \
|
||||||
theme/logged-in-indicator.svg \
|
theme/logged-in-indicator.svg \
|
||||||
theme/message-tray-background.png \
|
|
||||||
theme/noise-texture.png \
|
theme/noise-texture.png \
|
||||||
theme/panel-button-border.svg \
|
theme/panel-button-border.svg \
|
||||||
theme/panel-button-highlight-narrow.svg \
|
theme/panel-button-highlight-narrow.svg \
|
||||||
@ -39,20 +43,12 @@ dist_theme_DATA = \
|
|||||||
theme/process-working.svg \
|
theme/process-working.svg \
|
||||||
theme/running-indicator.svg \
|
theme/running-indicator.svg \
|
||||||
theme/source-button-border.svg \
|
theme/source-button-border.svg \
|
||||||
theme/summary-counter.svg \
|
|
||||||
theme/toggle-off-us.svg \
|
theme/toggle-off-us.svg \
|
||||||
theme/toggle-off-intl.svg \
|
theme/toggle-off-intl.svg \
|
||||||
theme/toggle-on-us.svg \
|
theme/toggle-on-us.svg \
|
||||||
theme/toggle-on-intl.svg \
|
theme/toggle-on-intl.svg \
|
||||||
theme/ws-switch-arrow-up.png \
|
theme/ws-switch-arrow-up.svg \
|
||||||
theme/ws-switch-arrow-down.png
|
theme/ws-switch-arrow-down.svg
|
||||||
|
|
||||||
keysdir = @GNOME_KEYBINDINGS_KEYSDIR@
|
|
||||||
keys_in_files = \
|
|
||||||
50-gnome-shell-screenshot.xml.in \
|
|
||||||
50-gnome-shell-system.xml.in \
|
|
||||||
$(NULL)
|
|
||||||
keys_DATA = $(keys_in_files:.xml.in=.xml)
|
|
||||||
|
|
||||||
gsettings_SCHEMAS = org.gnome.shell.gschema.xml
|
gsettings_SCHEMAS = org.gnome.shell.gschema.xml
|
||||||
|
|
||||||
@ -80,14 +76,12 @@ EXTRA_DIST = \
|
|||||||
$(introspection_DATA) \
|
$(introspection_DATA) \
|
||||||
$(menu_DATA) \
|
$(menu_DATA) \
|
||||||
$(convert_DATA) \
|
$(convert_DATA) \
|
||||||
$(keys_in_files) \
|
|
||||||
org.gnome.shell.gschema.xml.in.in
|
org.gnome.shell.gschema.xml.in.in
|
||||||
|
|
||||||
CLEANFILES = \
|
CLEANFILES = \
|
||||||
gnome-shell.desktop.in \
|
gnome-shell.desktop.in \
|
||||||
gnome-shell-extension-prefs.in \
|
gnome-shell-extension-prefs.in \
|
||||||
$(desktop_DATA) \
|
$(desktop_DATA) \
|
||||||
$(keys_DATA) \
|
|
||||||
$(gsettings_SCHEMAS) \
|
$(gsettings_SCHEMAS) \
|
||||||
gschemas.compiled \
|
gschemas.compiled \
|
||||||
org.gnome.shell.gschema.valid \
|
org.gnome.shell.gschema.valid \
|
||||||
|
7
data/open-search-providers/google.xml
Normal file
7
data/open-search-providers/google.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
|
||||||
|
<ShortName>Google</ShortName>
|
||||||
|
<Description>Google Search</Description>
|
||||||
|
<InputEncoding>UTF-8</InputEncoding>
|
||||||
|
<Image width="16" height="16">data:image/x-icon;base64,AAABAAEAEBAAAAEAGABoAwAAFgAAACgAAAAQAAAAIAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs9Pt8xetPtu9FsfFNtu%2BTzvb2%2B%2Fne4dFJeBw0egA%2FfAJAfAA8ewBBegAAAAD%2B%2FPtft98Mp%2BwWsfAVsvEbs%2FQeqvF8xO7%2F%2F%2F63yqkxdgM7gwE%2FggM%2BfQA%2BegBDeQDe7PIbotgQufcMufEPtfIPsvAbs%2FQvq%2Bfz%2Bf%2F%2B%2B%2FZKhR05hgBBhQI8hgBAgAI9ewD0%2B%2Fg3pswAtO8Cxf4Kw%2FsJvvYAqupKsNv%2B%2Fv7%2F%2FP5VkSU0iQA7jQA9hgBDgQU%2BfQH%2F%2Ff%2FQ6fM4sM4KsN8AteMCruIqqdbZ7PH8%2Fv%2Fg6Nc%2Fhg05kAA8jAM9iQI%2BhQA%2BgQDQu6b97uv%2F%2F%2F7V8Pqw3eiWz97q8%2Ff%2F%2F%2F%2F7%2FPptpkkqjQE4kwA7kAA5iwI8iAA8hQCOSSKdXjiyflbAkG7u2s%2F%2B%2F%2F39%2F%2F7r8utrqEYtjQE8lgA7kwA7kwA9jwA9igA9hACiWSekVRyeSgiYSBHx6N%2F%2B%2Fv7k7OFRmiYtlAA5lwI7lwI4lAA7kgI9jwE9iwI4iQCoVhWcTxCmb0K%2BooT8%2Fv%2F7%2F%2F%2FJ2r8fdwI1mwA3mQA3mgA8lAE8lAE4jwA9iwE%2BhwGfXifWvqz%2B%2Ff%2F58u%2Fev6Dt4tr%2B%2F%2F2ZuIUsggA7mgM6mAM3lgA5lgA6kQE%2FkwBChwHt4dv%2F%2F%2F728ei1bCi7VAC5XQ7kz7n%2F%2F%2F6bsZkgcB03lQA9lgM7kwA2iQktZToPK4r9%2F%2F%2F9%2F%2F%2FSqYK5UwDKZAS9WALIkFn%2B%2F%2F3%2F%2BP8oKccGGcIRJrERILYFEMwAAuEAAdX%2F%2Ff7%2F%2FP%2B%2BfDvGXQLIZgLEWgLOjlf7%2F%2F%2F%2F%2F%2F9QU90EAPQAAf8DAP0AAfMAAOUDAtr%2F%2F%2F%2F7%2B%2Fu2bCTIYwDPZgDBWQDSr4P%2F%2Fv%2F%2F%2FP5GRuABAPkAA%2FwBAfkDAPAAAesAAN%2F%2F%2B%2Fz%2F%2F%2F64g1C5VwDMYwK8Yg7y5tz8%2Fv%2FV1PYKDOcAAP0DAf4AAf0AAfYEAOwAAuAAAAD%2F%2FPvi28ymXyChTATRrIb8%2F%2F3v8fk6P8MAAdUCAvoAAP0CAP0AAfYAAO4AAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAA</Image>
|
||||||
|
<Url type="text/html" method="GET" template="http://www.google.com/search?q={searchTerms}"/>
|
||||||
|
</OpenSearchDescription>
|
44
data/open-search-providers/wikipedia.xml
Normal file
44
data/open-search-providers/wikipedia.xml
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
|
||||||
|
<ShortName>Wikipedia</ShortName>
|
||||||
|
<Description>Wikipedia, the free encyclopedia</Description>
|
||||||
|
<InputEncoding>UTF-8</InputEncoding>
|
||||||
|
<Image width="16" height="16">data:image/x-icon;base64,AAABAAEAEBAQAAEABAAoAQAAFgAAACgAAAAQAAAAIAAAAAEABAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAEAgQAhIOEAMjHyABIR0gA6ejpAGlqaQCpqKkAKCgoAPz9%2FAAZGBkAmJiYANjZ2ABXWFcAent6ALm6uQA8OjwAiIiIiIiIiIiIiI4oiL6IiIiIgzuIV4iIiIhndo53KIiIiB%2FWvXoYiIiIfEZfWBSIiIEGi%2FfoqoiIgzuL84i9iIjpGIoMiEHoiMkos3FojmiLlUipYliEWIF%2BiDe0GoRa7D6GPbjcu1yIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</Image>
|
||||||
|
<Url type="text/html" method="GET" template="http://{language}.wikipedia.org/wiki/Special:Search?search={searchTerms}"/>
|
||||||
|
<!-- The criterion for being below is being listed with more than 100,000
|
||||||
|
articles on http://meta.wikimedia.org/wiki/List_of_Wikipedias -->
|
||||||
|
<Language>ar</Language>
|
||||||
|
<Language>bg</Language>
|
||||||
|
<Language>ca</Language>
|
||||||
|
<Language>cs</Language>
|
||||||
|
<Language>da</Language>
|
||||||
|
<Language>de</Language>
|
||||||
|
<Language>en</Language>
|
||||||
|
<Language>eo</Language>
|
||||||
|
<Language>es</Language>
|
||||||
|
<Language>fa</Language>
|
||||||
|
<Language>fi</Language>
|
||||||
|
<Language>fr</Language>
|
||||||
|
<Language>he</Language>
|
||||||
|
<Language>hu</Language>
|
||||||
|
<Language>id</Language>
|
||||||
|
<Language>it</Language>
|
||||||
|
<Language>ja</Language>
|
||||||
|
<Language>ko</Language>
|
||||||
|
<Language>lt</Language>
|
||||||
|
<Language>nl</Language>
|
||||||
|
<Language>no</Language>
|
||||||
|
<Language>pl</Language>
|
||||||
|
<Language>pt</Language>
|
||||||
|
<Language>ro</Language>
|
||||||
|
<Language>ru</Language>
|
||||||
|
<Language>sk</Language>
|
||||||
|
<Language>sl</Language>
|
||||||
|
<Language>sr</Language>
|
||||||
|
<Language>sv</Language>
|
||||||
|
<Language>tr</Language>
|
||||||
|
<Language>uk</Language>
|
||||||
|
<Language>vi</Language>
|
||||||
|
<Language>vo</Language>
|
||||||
|
<Language>war</Language>
|
||||||
|
<Language>zh</Language>
|
||||||
|
</OpenSearchDescription>
|
@ -108,7 +108,7 @@
|
|||||||
</doc:summary>
|
</doc:summary>
|
||||||
</doc:doc>
|
</doc:doc>
|
||||||
</arg>
|
</arg>
|
||||||
<arg type="aa{sv}" direction="out">
|
<arg type="a{sv}" direction="out">
|
||||||
<doc:doc>
|
<doc:doc>
|
||||||
<doc:summary>
|
<doc:summary>
|
||||||
<doc:para>
|
<doc:para>
|
||||||
|
@ -39,6 +39,10 @@
|
|||||||
will be displayed in the favorites area.
|
will be displayed in the favorites area.
|
||||||
</_description>
|
</_description>
|
||||||
</key>
|
</key>
|
||||||
|
<key name="disabled-open-search-providers" type="as">
|
||||||
|
<default>[]</default>
|
||||||
|
<_summary>disabled OpenSearch providers</_summary>
|
||||||
|
</key>
|
||||||
<key name="command-history" type="as">
|
<key name="command-history" type="as">
|
||||||
<default>[]</default>
|
<default>[]</default>
|
||||||
<_summary>History for command (Alt-F2) dialog</_summary>
|
<_summary>History for command (Alt-F2) dialog</_summary>
|
||||||
@ -57,14 +61,6 @@ value here is from the TpConnectionPresenceType enumeration.</_summary>
|
|||||||
<_summary>Internally used to store the last session presence status for the user. The
|
<_summary>Internally used to store the last session presence status for the user. The
|
||||||
value here is from the GsmPresenceStatus enumeration.</_summary>
|
value here is from the GsmPresenceStatus enumeration.</_summary>
|
||||||
</key>
|
</key>
|
||||||
<key name="always-show-log-out" type="b">
|
|
||||||
<default>false</default>
|
|
||||||
<_summary>Always show the 'Log out' menuitem in the user menu.</_summary>
|
|
||||||
<_description>
|
|
||||||
This key overrides the automatic hiding of the 'Log out'
|
|
||||||
menuitem in single-user, single-session situations.
|
|
||||||
</_description>
|
|
||||||
</key>
|
|
||||||
<child name="calendar" schema="org.gnome.shell.calendar"/>
|
<child name="calendar" schema="org.gnome.shell.calendar"/>
|
||||||
<child name="recorder" schema="org.gnome.shell.recorder"/>
|
<child name="recorder" schema="org.gnome.shell.recorder"/>
|
||||||
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
|
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
|
||||||
@ -91,21 +87,6 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
|
|||||||
Keybinding to open the application menu.
|
Keybinding to open the application menu.
|
||||||
</_description>
|
</_description>
|
||||||
</key>
|
</key>
|
||||||
<key name="toggle-application-view" type="as">
|
|
||||||
<default>["<Super>a"]</default>
|
|
||||||
<_summary>Keybinding to open the "Show Applications" view</_summary>
|
|
||||||
<_description>
|
|
||||||
Keybinding to open the "Show Applications" view of the Activities
|
|
||||||
Overview.
|
|
||||||
</_description>
|
|
||||||
</key>
|
|
||||||
<key name="toggle-message-tray" type="as">
|
|
||||||
<default>["<Super>m"]</default>
|
|
||||||
<_summary>Keybinding to toggle the visibility of the message tray</_summary>
|
|
||||||
<_description>
|
|
||||||
Keybinding to toggle the visibility of the message tray.
|
|
||||||
</_description>
|
|
||||||
</key>
|
|
||||||
<key name="toggle-recording" type="as">
|
<key name="toggle-recording" type="as">
|
||||||
<default><![CDATA[['<Control><Shift><Alt>r']]]></default>
|
<default><![CDATA[['<Control><Shift><Alt>r']]]></default>
|
||||||
<_summary>Keybinding to toggle the screen recorder</_summary>
|
<_summary>Keybinding to toggle the screen recorder</_summary>
|
||||||
@ -148,7 +129,7 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
|
|||||||
take care of its own output - this might be used to send the output
|
take care of its own output - this might be used to send the output
|
||||||
to an icecast server via shout2send or similar. When unset or set
|
to an icecast server via shout2send or similar. When unset or set
|
||||||
to an empty value, the default pipeline will be used. This is currently
|
to an empty value, the default pipeline will be used. This is currently
|
||||||
'vp8enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! queue ! webmmux'
|
'vp8enc quality=8 speed=6 threads=%T ! queue ! webmmux'
|
||||||
and records to WEBM using the VP8 codec. %T is used as a placeholder
|
and records to WEBM using the VP8 codec. %T is used as a placeholder
|
||||||
for a guess at the optimal thread count on the system.
|
for a guess at the optimal thread count on the system.
|
||||||
</_description>
|
</_description>
|
||||||
@ -164,53 +145,44 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
|
|||||||
</key>
|
</key>
|
||||||
</schema>
|
</schema>
|
||||||
|
|
||||||
<schema id="org.gnome.shell.overrides" path="/org/gnome/shell/overrides/"
|
<schema id="org.gnome.shell.overrides" path="/org/gnome/shell/overrides/">
|
||||||
gettext-domain="@GETTEXT_PACKAGE@">
|
|
||||||
<key name="attach-modal-dialogs" type="b">
|
<key name="attach-modal-dialogs" type="b">
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
<_summary>Attach modal dialog to the parent window</_summary>
|
<summary>Attach modal dialog to the parent window</summary>
|
||||||
<_description>
|
<description>
|
||||||
This key overrides the key in org.gnome.mutter when running
|
This key overrides the key in org.gnome.mutter when running
|
||||||
GNOME Shell.
|
GNOME Shell.
|
||||||
</_description>
|
</description>
|
||||||
</key>
|
</key>
|
||||||
|
|
||||||
<key name="button-layout" type="s">
|
<key name="button-layout" type="s">
|
||||||
<default>":close"</default>
|
<default>":close"</default>
|
||||||
<_summary>Arrangement of buttons on the titlebar</_summary>
|
<summary>Arrangement of buttons on the titlebar</summary>
|
||||||
<_description>
|
<description>
|
||||||
This key overrides the key in org.gnome.desktop.wm.preferences when
|
This key overrides the key in org.gnome.desktop.wm.preferences when
|
||||||
running GNOME Shell.
|
running GNOME Shell.
|
||||||
</_description>
|
</description>
|
||||||
</key>
|
</key>
|
||||||
|
|
||||||
<key name="edge-tiling" type="b">
|
<key name="edge-tiling" type="b">
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
<_summary>Enable edge tiling when dropping windows on screen edges</_summary>
|
<summary>Enable edge tiling when dropping windows on screen edges</summary>
|
||||||
<_description>
|
<description>
|
||||||
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
||||||
</_description>
|
</description>
|
||||||
</key>
|
</key>
|
||||||
|
|
||||||
<key name="dynamic-workspaces" type="b">
|
<key name="dynamic-workspaces" type="b">
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
<_summary>Workspaces are managed dynamically</_summary>
|
<summary>Workspaces are managed dynamically</summary>
|
||||||
<_description>
|
<description>
|
||||||
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
||||||
</_description>
|
</description>
|
||||||
</key>
|
</key>
|
||||||
|
|
||||||
<key name="workspaces-only-on-primary" type="b">
|
<key name="workspaces-only-on-primary" type="b">
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
<_summary>Workspaces only on primary monitor</_summary>
|
<summary>Workspaces only on primary monitor</summary>
|
||||||
<_description>
|
|
||||||
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
|
||||||
</_description>
|
|
||||||
</key>
|
|
||||||
|
|
||||||
<key name="focus-change-on-pointer-rest" type="b">
|
|
||||||
<default>true</default>
|
|
||||||
<summary>Delay focus changes in mouse mode until the pointer stops moving</summary>
|
|
||||||
<description>
|
<description>
|
||||||
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
||||||
</description>
|
</description>
|
||||||
|
@ -39,6 +39,7 @@ stage {
|
|||||||
/* small */
|
/* small */
|
||||||
.app-well-menu,
|
.app-well-menu,
|
||||||
.contact-details-status,
|
.contact-details-status,
|
||||||
|
.run-dialog-label,
|
||||||
.run-dialog-error-label {
|
.run-dialog-error-label {
|
||||||
font-size: 9pt;
|
font-size: 9pt;
|
||||||
}
|
}
|
||||||
@ -47,8 +48,9 @@ stage {
|
|||||||
.dash-label,
|
.dash-label,
|
||||||
.window-caption,
|
.window-caption,
|
||||||
.switcher-list,
|
.switcher-list,
|
||||||
|
.source-title,
|
||||||
.app-well-app > .overview-icon,
|
.app-well-app > .overview-icon,
|
||||||
.show-apps > .overview-icon,
|
.remove-favorite > .overview-icon,
|
||||||
.search-result-content > .overview-icon {
|
.search-result-content > .overview-icon {
|
||||||
font-size: 9pt;
|
font-size: 9pt;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@ -79,25 +81,25 @@ StScrollBar StBin#trough {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StScrollBar StButton#vhandle {
|
StScrollBar StButton#vhandle {
|
||||||
background-color: #5d6464;
|
background-color: #959797;
|
||||||
border: 2px solid #242424;
|
border: 2px solid #242424;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
StScrollBar StButton#hhandle {
|
StScrollBar StButton#hhandle {
|
||||||
background-color: #5d6464;
|
background-color: #959797;
|
||||||
border: 2px solid #242424;
|
border: 2px solid #242424;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
StScrollBar StButton#hhandle:hover,
|
StScrollBar StButton#hhandle:hover,
|
||||||
StScrollBar StButton#vhandle:hover {
|
StScrollBar StButton#vhandle:hover {
|
||||||
background-color: #777d7c;
|
background-color: #c2c3c3;
|
||||||
}
|
}
|
||||||
|
|
||||||
StScrollBar StButton#hhandle:active,
|
StScrollBar StButton#hhandle:active,
|
||||||
StScrollBar StButton#vhandle:active {
|
StScrollBar StButton#vhandle:active {
|
||||||
background-color: #3465a4;
|
background-color: #729fcf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check Boxes */
|
/* Check Boxes */
|
||||||
@ -150,11 +152,11 @@ StScrollBar StButton#vhandle:active {
|
|||||||
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9);
|
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-sub-menu:scrolled .popup-menu-item:ltr {
|
.popup-sub-menu .popup-menu-item:ltr {
|
||||||
padding-right: 0em;
|
padding-right: 0em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-sub-menu:scrolled .popup-menu-item:rtl {
|
.popup-sub-menu .popup-menu-item:rtl {
|
||||||
padding-left: 0em;
|
padding-left: 0em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +196,7 @@ StScrollBar StButton#vhandle:active {
|
|||||||
background-color: #4c4c4c;
|
background-color: #4c4c4c;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-menu-item:insensitive {
|
StButton.popup-menu-item:insensitive {
|
||||||
color: #9f9f9f;
|
color: #9f9f9f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,18 +235,13 @@ StScrollBar StButton#vhandle:active {
|
|||||||
spacing: .5em;
|
spacing: .5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-status-menu-item {
|
.popup-inactive-menu-item {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-inactive-menu-item, .popup-inactive-menu-item:insensitive {
|
.popup-subtitle-menu-item {
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popup-subtitle-menu-item, .popup-subtitle-menu-item:insensitive {
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-menu-icon {
|
.popup-menu-icon {
|
||||||
@ -310,7 +307,7 @@ StScrollBar StButton#vhandle:active {
|
|||||||
.notification-icon-button:focus,
|
.notification-icon-button:focus,
|
||||||
.hotplug-notification-item:focus,
|
.hotplug-notification-item:focus,
|
||||||
.modal-dialog-button:focus {
|
.modal-dialog-button:focus {
|
||||||
border-width: 2px;
|
border: 2px solid #8b8b8b;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dash-search-button:active,
|
.dash-search-button:active,
|
||||||
@ -325,30 +322,26 @@ StScrollBar StButton#vhandle:active {
|
|||||||
background-gradient-end: rgba(255, 255, 255, 0.2);
|
background-gradient-end: rgba(255, 255, 255, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-button:insensitive,
|
|
||||||
.notification-icon-button:insensitive,
|
.notification-icon-button:insensitive,
|
||||||
.modal-dialog-button:insensitive {
|
.notification-button:insensitive {
|
||||||
border-color: #666666;
|
|
||||||
color: #9f9f9f;
|
color: #9f9f9f;
|
||||||
background-gradient-direction: none;
|
|
||||||
background-color: rgba(102, 102, 102, 0.15);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Entries */
|
/* Entries */
|
||||||
|
|
||||||
#searchEntry,
|
#searchEntry,
|
||||||
.notification StEntry,
|
.notification StEntry,
|
||||||
.modal-dialog StEntry {
|
.login-dialog-prompt-entry,
|
||||||
|
.prompt-dialog-password-entry {
|
||||||
color: rgb(64, 64, 64);
|
color: rgb(64, 64, 64);
|
||||||
caret-color: rgb(64, 64, 64);
|
caret-color: rgb(64, 64, 64);
|
||||||
font-size: 12pt;
|
font-size: 12pt;
|
||||||
caret-size: 1px;
|
caret-size: 1px;
|
||||||
selected-color: white;
|
selected-color: black;
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#searchEntry,
|
#searchEntry,
|
||||||
.run-dialog-entry,
|
|
||||||
.notification StEntry {
|
.notification StEntry {
|
||||||
border: 2px solid rgba(245,245,245,0.2);
|
border: 2px solid rgba(245,245,245,0.2);
|
||||||
background-gradient-start: rgba(5,5,6,0.1);
|
background-gradient-start: rgba(5,5,6,0.1);
|
||||||
@ -361,7 +354,8 @@ StScrollBar StButton#vhandle:active {
|
|||||||
#searchEntry:focus,
|
#searchEntry:focus,
|
||||||
#searchEntry:hover,
|
#searchEntry:hover,
|
||||||
.notification StEntry:focus,
|
.notification StEntry:focus,
|
||||||
.modal-dialog StEntry {
|
.login-dialog-prompt-entry,
|
||||||
|
.prompt-dialog-password-entry {
|
||||||
border: 2px solid rgb(136,138,133);
|
border: 2px solid rgb(136,138,133);
|
||||||
background-gradient-start: rgb(200,200,200);
|
background-gradient-start: rgb(200,200,200);
|
||||||
background-gradient-end: white;
|
background-gradient-end: white;
|
||||||
@ -370,17 +364,12 @@ StScrollBar StButton#vhandle:active {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.notification StEntry:focus,
|
.notification StEntry:focus,
|
||||||
.modal-dialog StEntry:focus {
|
.prompt-dialog-password-entry:focus,
|
||||||
|
.login-dialog-prompt-entry:focus {
|
||||||
border: 2px solid #3465a4;
|
border: 2px solid #3465a4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#searchEntry {
|
#searchEntry {
|
||||||
border-color: rgba(245,245,245,0.3);
|
|
||||||
color: rgb(192, 192, 192);
|
|
||||||
caret-color: rgb(192, 192, 192);
|
|
||||||
}
|
|
||||||
|
|
||||||
#searchEntry:hover {
|
|
||||||
color: rgb(128, 128, 128);
|
color: rgb(128, 128, 128);
|
||||||
caret-color: rgb(128, 128, 128);
|
caret-color: rgb(128, 128, 128);
|
||||||
}
|
}
|
||||||
@ -393,7 +382,8 @@ StScrollBar StButton#vhandle:active {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.notification StEntry,
|
.notification StEntry,
|
||||||
.modal-dialog StEntry {
|
.prompt-dialog-password-entry,
|
||||||
|
.login-dialog-prompt-entry {
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 4px 4px;
|
padding: 4px 4px;
|
||||||
}
|
}
|
||||||
@ -408,8 +398,6 @@ StScrollBar StButton#vhandle:active {
|
|||||||
.login-dialog-prompt-entry:insensitive {
|
.login-dialog-prompt-entry:insensitive {
|
||||||
color: rgba(0,0,0,0.7);
|
color: rgba(0,0,0,0.7);
|
||||||
border: 2px solid #565656;
|
border: 2px solid #565656;
|
||||||
background-gradient-start: rgb(200,200,200);
|
|
||||||
background-gradient-end: rgb(210,210,210);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Panel */
|
/* Panel */
|
||||||
@ -515,7 +503,7 @@ StScrollBar StButton#vhandle:active {
|
|||||||
-boxpointer-gap: 4px
|
-boxpointer-gap: 4px
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-status-button-box {
|
#networkMenu {
|
||||||
spacing: 4px;
|
spacing: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -557,6 +545,7 @@ StScrollBar StButton#vhandle:active {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.status-chooser-combo.popup-combo-menu {
|
.status-chooser-combo.popup-combo-menu {
|
||||||
|
background-color: rgba(0,0,0,0.7);
|
||||||
padding: .4em 0em;
|
padding: .4em 0em;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 1px solid #5f5f5f;
|
border: 1px solid #5f5f5f;
|
||||||
@ -574,7 +563,7 @@ StScrollBar StButton#vhandle:active {
|
|||||||
/* Overview */
|
/* Overview */
|
||||||
|
|
||||||
#overview {
|
#overview {
|
||||||
spacing: 40px;
|
spacing: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.window-caption {
|
.window-caption {
|
||||||
@ -590,24 +579,22 @@ StScrollBar StButton#vhandle:active {
|
|||||||
border-right: 0px;
|
border-right: 0px;
|
||||||
border-radius: 9px 0px 0px 9px;
|
border-radius: 9px 0px 0px 9px;
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
padding: 11px 7px 11px 11px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-thumbnails-background:rtl {
|
.workspace-thumbnails-background:rtl {
|
||||||
border-right: 1px;
|
border-right: 1px;
|
||||||
border-left: 0px;
|
border-left: 0px;
|
||||||
border-radius: 0px 9px 9px 0px;
|
border-radius: 0px 9px 9px 0px;
|
||||||
padding: 11px 11px 11px 7px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-thumbnails {
|
.workspace-thumbnails {
|
||||||
spacing: 11px;
|
spacing: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-thumbnail-indicator {
|
.workspace-thumbnail-indicator {
|
||||||
border: 4px solid rgba(255,255,255,0.7);
|
outline: 2px solid white;
|
||||||
border-radius: 4px;
|
border: 1px solid #888;
|
||||||
padding: 1px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.window-caption {
|
.window-caption {
|
||||||
@ -617,46 +604,18 @@ StScrollBar StButton#vhandle:active {
|
|||||||
-shell-caption-spacing: 12px;
|
-shell-caption-spacing: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.window-close, .notification-close {
|
|
||||||
background-image: url("close-window.svg");
|
|
||||||
background-size: 32px;
|
|
||||||
height: 32px;
|
|
||||||
width: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-close {
|
.window-close {
|
||||||
|
background-image: url("close-window.svg");
|
||||||
|
background-size: 34px;
|
||||||
|
height: 34px;
|
||||||
|
width: 34px;
|
||||||
-shell-close-overlap: 20px;
|
-shell-close-overlap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-close {
|
|
||||||
/* we start out in the top right of the
|
|
||||||
* notification, inset.
|
|
||||||
*
|
|
||||||
* center is 32px/2 = 16px
|
|
||||||
*
|
|
||||||
* adjust left 2px
|
|
||||||
* adjust down 8px */
|
|
||||||
|
|
||||||
-shell-close-overlap-x: 14px;
|
|
||||||
-shell-close-overlap-y: -12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-close:rtl {
|
|
||||||
/* as above, but starting out in the top left of the
|
|
||||||
* notification. */
|
|
||||||
|
|
||||||
-shell-close-overlap-x: -14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-close:rtl {
|
.window-close:rtl {
|
||||||
-st-background-image-shadow: 2px 2px 6px rgba(0,0,0,0.5);
|
-st-background-image-shadow: 2px 2px 6px rgba(0,0,0,0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.window-picker {
|
|
||||||
-horizontal-spacing: 40px;
|
|
||||||
-vertical-spacing: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Dash */
|
/* Dash */
|
||||||
|
|
||||||
#dash {
|
#dash {
|
||||||
@ -675,6 +634,11 @@ StScrollBar StButton#vhandle:active {
|
|||||||
border-radius: 9px 0px 0px 9px;
|
border-radius: 9px 0px 0px 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#dash:empty {
|
||||||
|
height: 100px;
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
.placeholder {
|
.placeholder {
|
||||||
background-image: url("dash-placeholder.svg");
|
background-image: url("dash-placeholder.svg");
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
@ -685,21 +649,44 @@ StScrollBar StButton#vhandle:active {
|
|||||||
spacing: 1em;
|
spacing: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#viewSelectorTabBar {
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
/* Search Box */
|
/* Search Box */
|
||||||
|
|
||||||
|
#searchArea {
|
||||||
|
padding: 0px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
#searchEntry {
|
#searchEntry {
|
||||||
border-radius: 17px;
|
border-radius: 17px;
|
||||||
width: 320px;
|
width: 250px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-entry-icon {
|
.search-entry-icon {
|
||||||
icon-size: 1em;
|
icon-size: 1em;
|
||||||
color: #c0c0c0;
|
color: #8d8f8a;
|
||||||
}
|
}
|
||||||
|
|
||||||
#searchEntry:hover .search-entry-icon,
|
/* View Tabs */
|
||||||
#searchEntry:focus .search-entry-icon {
|
|
||||||
color: #8d8f8a;
|
.view-tab-title {
|
||||||
|
color: #888a85;
|
||||||
|
font-size: 12pt;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 0px 0.75em;
|
||||||
|
height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-tab-title:hover {
|
||||||
|
color: #bbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-tab-title:selected {
|
||||||
|
color: #000000;
|
||||||
|
background-color: #c2c7cd;
|
||||||
|
border-radius: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search Results */
|
/* Search Results */
|
||||||
@ -719,6 +706,7 @@ StScrollBar StButton#vhandle:active {
|
|||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-statustext,
|
||||||
.search-section-header {
|
.search-section-header {
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
spacing: 4px;
|
spacing: 4px;
|
||||||
@ -726,12 +714,6 @@ StScrollBar StButton#vhandle:active {
|
|||||||
font-size: .8em;
|
font-size: .8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-statustext {
|
|
||||||
color: #efefef;
|
|
||||||
font-size: 2em;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-section-results {
|
.search-section-results {
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
}
|
}
|
||||||
@ -744,6 +726,10 @@ StScrollBar StButton#vhandle:active {
|
|||||||
spacing: 4px;
|
spacing: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-providers-box {
|
||||||
|
spacing: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Text labels are an odd number of pixels tall. The uneven top and bottom
|
/* 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
|
* padding compensates for this and ensures that the label is vertically
|
||||||
* centered */
|
* centered */
|
||||||
@ -818,12 +804,21 @@ StScrollBar StButton#vhandle:active {
|
|||||||
outline: 1px solid #aaa;
|
outline: 1px solid #aaa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dash-item-container > StButton {
|
.dash-item-container > .app-well-app {
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.remove-favorite-icon {
|
||||||
|
color: #a0a0a0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-favorite-icon:hover {
|
||||||
|
color: white;
|
||||||
|
icon-shadow: black 0px 2px 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.app-well-app > .overview-icon,
|
.app-well-app > .overview-icon,
|
||||||
.show-apps > .overview-icon,
|
.remove-favorite > .overview-icon,
|
||||||
.search-result-content > .overview-icon {
|
.search-result-content > .overview-icon {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
@ -839,44 +834,15 @@ StScrollBar StButton#vhandle:active {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.app-well-app:hover > .overview-icon,
|
.app-well-app:hover > .overview-icon,
|
||||||
.show-apps:hover > .overview-icon,
|
.remove-favorite:hover > .overview-icon,
|
||||||
.search-result-content:hover > .overview-icon {
|
.search-result-content:hover > .overview-icon {
|
||||||
background-color: rgba(255,255,255,0.1);
|
background-color: rgba(255,255,255,0.1);
|
||||||
text-shadow: black 0px 2px 2px;
|
text-shadow: black 0px 2px 2px;
|
||||||
transition-duration: 100;
|
transition-duration: 100;
|
||||||
color:white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.show-apps {
|
|
||||||
padding: 4px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.show-apps-icon {
|
|
||||||
color: #a0a0a0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.show-apps:hover .show-apps-icon {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.show-apps:checked > .overview-icon {
|
|
||||||
background-gradient-start: rgba(255, 255, 255, .05);
|
|
||||||
background-gradient-end: rgba(255, 255, 255, .15);
|
|
||||||
background-gradient-direction: vertical;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: inset 0px 1px 2px 0px rgba(0, 0, 0, 1);
|
|
||||||
transition-duration: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
.show-apps:checked .show-apps-icon,
|
|
||||||
.show-apps:focus .show-apps-icon {
|
|
||||||
color: white;
|
|
||||||
transition-duration: 100;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-well-app:focus > .overview-icon,
|
.app-well-app:focus > .overview-icon,
|
||||||
.search-result-content:focus > .overview-icon,
|
.search-result-content:focus > .overview-icon,
|
||||||
.show-apps:focus > .overview-icon,
|
|
||||||
.app-well-app:selected > .overview-icon,
|
.app-well-app:selected > .overview-icon,
|
||||||
.search-result-content:selected > .overview-icon {
|
.search-result-content:selected > .overview-icon {
|
||||||
background-color: rgba(255,255,255,0.33);
|
background-color: rgba(255,255,255,0.33);
|
||||||
@ -1207,31 +1173,19 @@ StScrollBar StButton#vhandle:active {
|
|||||||
|
|
||||||
/* Message Tray */
|
/* Message Tray */
|
||||||
#message-tray {
|
#message-tray {
|
||||||
background: #2e3436 url(message-tray-background.png);
|
background-gradient-direction: vertical;
|
||||||
background-repeat: repeat;
|
background-gradient-start: rgba(0,0,0,0.01);
|
||||||
transition-duration: 250;
|
background-gradient-end: rgba(0,0,0,0.82);
|
||||||
}
|
height: 36px;
|
||||||
|
|
||||||
#message-tray:keyboard {
|
|
||||||
/* Same as the OSK */
|
|
||||||
background: rgba(0, 0, 0, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
#message-tray:overview {
|
|
||||||
background: rgba(0, 0, 0, 0.1);
|
|
||||||
outline: 1px solid rgba(128, 128, 128, 0.3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification {
|
.notification {
|
||||||
|
font-size: 11pt;
|
||||||
border-radius: 10px 10px 0px 0px;
|
border-radius: 10px 10px 0px 0px;
|
||||||
background: rgba(0,0,0,0.8);
|
background: rgba(0,0,0,0.8);
|
||||||
padding: 8px 8px 4px 8px;
|
padding: 8px 8px 4px 8px;
|
||||||
spacing-rows: 10px;
|
spacing-rows: 10px;
|
||||||
spacing-columns: 10px;
|
spacing-columns: 10px;
|
||||||
}
|
|
||||||
|
|
||||||
.notification, #notification-container {
|
|
||||||
font-size: 11pt;
|
|
||||||
width: 34em;
|
width: 34em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1239,13 +1193,6 @@ StScrollBar StButton#vhandle:active {
|
|||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-unexpanded {
|
|
||||||
/* We want to force the actor at a specific size, irrespective
|
|
||||||
of its minimum and preferred size, so we override both */
|
|
||||||
min-height: 36px;
|
|
||||||
height: 36px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We use row-span = 2 for the image cell, which prevents its height preferences to be
|
/* We use row-span = 2 for the image cell, which prevents its height preferences to be
|
||||||
taken into account during allocation, so its height ends up being limited by the height
|
taken into account during allocation, so its height ends up being limited by the height
|
||||||
of the content in the other rows. To avoid showing a stretched image, we set the minimum
|
of the content in the other rows. To avoid showing a stretched image, we set the minimum
|
||||||
@ -1260,7 +1207,6 @@ StScrollBar StButton#vhandle:active {
|
|||||||
-arrow-base: 36px;
|
-arrow-base: 36px;
|
||||||
-arrow-rise: 18px;
|
-arrow-rise: 18px;
|
||||||
color: white;
|
color: white;
|
||||||
-boxpointer-gap: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-boxpointer .notification {
|
.summary-boxpointer .notification {
|
||||||
@ -1440,46 +1386,87 @@ StScrollBar StButton#vhandle:active {
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The spacing and padding on the summary is tricky; we want to keep
|
||||||
|
* the icons from touching each other or the edges of the screen, but
|
||||||
|
* we also want them to be "Fitts"-y with respect to the edges, so the
|
||||||
|
* summary area's bottom and right padding must actually be part of
|
||||||
|
* the icons. However, we can't put *all* of the padding into the
|
||||||
|
* icons, because then the summary would be 0x0 when there were no
|
||||||
|
* icons in it, and so you wouldn't be able to hover over it to
|
||||||
|
* activate it.
|
||||||
|
*
|
||||||
|
* Also, the spacing between a summary-source's icon and title is
|
||||||
|
* actually specified as padding-left in source-title, because we
|
||||||
|
* want the spacing to collapse along with the title.
|
||||||
|
*/
|
||||||
#summary-mode {
|
#summary-mode {
|
||||||
height: 72px;
|
padding: 2px 0px 0px 4px;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#summary-mode:rtl {
|
||||||
|
padding: 2px 4px 0px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-source-button {
|
.summary-source-button {
|
||||||
padding: 6px 3px 6px 3px;
|
text-shadow: black 0px 2px 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-source-button:ltr {
|
||||||
|
padding-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-source-button:selected .summary-source {
|
||||||
|
background-image: url("panel-button-highlight-narrow.svg");
|
||||||
|
background-size: contain;
|
||||||
|
border-image: url("source-button-border.svg") 10 10 0 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-source-button:expanded:selected .summary-source {
|
||||||
|
background-image: none;
|
||||||
|
border-image: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-source-button:expanded:selected {
|
||||||
|
background-image: url("panel-button-highlight-wide.svg");
|
||||||
|
background-size: contain;
|
||||||
|
border-image: url("source-button-border.svg") 10 10 0 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-source-button:rtl {
|
||||||
|
padding-left: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-source-button:last-child:ltr {
|
.summary-source-button:last-child:ltr {
|
||||||
padding-right: 6px;
|
padding-right: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-source-button:last-child:rtl {
|
.summary-source-button:last-child:rtl {
|
||||||
padding-left: 6px;
|
padding-left: 12px;
|
||||||
}
|
|
||||||
|
|
||||||
.summary-source-button:hover .summary-source {
|
|
||||||
background-color: rgba(255,255,255,0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.summary-source-button:focus .summary-source,
|
|
||||||
.summary-source-button:selected .summary-source {
|
|
||||||
background-color: rgba(255,255,255,0.33);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-source {
|
.summary-source {
|
||||||
border-radius: 4px;
|
padding-right: 4px;
|
||||||
padding: 0 6px 0 6px;
|
padding-left: 4px;
|
||||||
transition-duration: 100;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-source-counter {
|
.summary-source-counter {
|
||||||
background-image: url("summary-counter.svg");
|
color: white;
|
||||||
background-size: 2.5em;
|
background-color: #3465A4;
|
||||||
font-size: 10pt;
|
text-shadow: black 1px 1px 0;
|
||||||
font-weight: bold;
|
font-size: 9pt;
|
||||||
height: 2.5em;
|
border-radius: 1em;
|
||||||
width: 2.5em;
|
min-height: 1em;
|
||||||
-shell-counter-overlap-x: 4px;
|
min-width: 1em;
|
||||||
-shell-counter-overlap-y: 4px;
|
}
|
||||||
|
|
||||||
|
.source-title {
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.source-title:rtl {
|
||||||
|
padding-left: 0px;
|
||||||
|
padding-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* App Switcher */
|
/* App Switcher */
|
||||||
@ -1592,7 +1579,7 @@ StScrollBar StButton#vhandle:active {
|
|||||||
height: 100px;
|
height: 100px;
|
||||||
border: 0px;
|
border: 0px;
|
||||||
background: rgba(255,255,255,0.5);
|
background: rgba(255,255,255,0.5);
|
||||||
background-image: url("ws-switch-arrow-up.png");
|
background-image: url("ws-switch-arrow-up.svg");
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1600,7 +1587,7 @@ StScrollBar StButton#vhandle:active {
|
|||||||
height: 100px;
|
height: 100px;
|
||||||
border: 0px;
|
border: 0px;
|
||||||
background: rgba(255,255,255,0.5);
|
background: rgba(255,255,255,0.5);
|
||||||
background-image: url("ws-switch-arrow-down.png");
|
background-image: url("ws-switch-arrow-down.svg");
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1646,26 +1633,35 @@ StScrollBar StButton#vhandle:active {
|
|||||||
padding: 4px 32px 5px;
|
padding: 4px 32px 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-dialog-button:insensitive {
|
||||||
|
color: rgb(60, 60, 60);
|
||||||
|
}
|
||||||
|
|
||||||
.modal-dialog-button:focus {
|
.modal-dialog-button:focus {
|
||||||
padding: 3px 31px 4px;
|
padding: 3px 31px 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Run Dialog */
|
/* Run Dialog */
|
||||||
|
|
||||||
.run-dialog-label {
|
|
||||||
font-size: 12pt;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #999999;
|
|
||||||
padding-bottom: .4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.run-dialog-error-box {
|
.run-dialog-error-box {
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
spacing: 5px;
|
spacing: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-dialog .run-dialog-entry {
|
.run-dialog-entry {
|
||||||
width: 20em;
|
font-weight: bold;
|
||||||
|
width: 23em;
|
||||||
|
selection-background-color: white;
|
||||||
|
selected-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.run-dialog {
|
||||||
|
border-radius: 16px;
|
||||||
|
|
||||||
|
padding-right: 21px;
|
||||||
|
padding-left: 21px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
padding-top: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lightbox {
|
.lightbox {
|
||||||
@ -1705,7 +1701,6 @@ StScrollBar StButton#vhandle:active {
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
background-size: contain;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.end-session-dialog-shutdown-icon {
|
.end-session-dialog-shutdown-icon {
|
||||||
@ -1866,7 +1861,6 @@ StScrollBar StButton#vhandle:active {
|
|||||||
|
|
||||||
.prompt-dialog-password-box {
|
.prompt-dialog-password-box {
|
||||||
spacing: 1em;
|
spacing: 1em;
|
||||||
padding-bottom: 1em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.prompt-dialog-error-label {
|
.prompt-dialog-error-label {
|
||||||
@ -1905,24 +1899,14 @@ StScrollBar StButton#vhandle:active {
|
|||||||
color: #ff0000;
|
color: #ff0000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.polkit-dialog-user-icon {
|
|
||||||
border: 2px solid #8b8b8b;
|
|
||||||
border-radius: 5px;
|
|
||||||
background-size: contain;
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Network Agent Dialog */
|
/* Network Agent Dialog */
|
||||||
|
|
||||||
.network-dialog-secret-table {
|
.network-dialog-secret-table {
|
||||||
spacing-rows: 15px;
|
spacing-rows: 15px;
|
||||||
spacing-columns: 1em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.keyring-dialog-control-table {
|
.keyring-dialog-control-table {
|
||||||
spacing-rows: 15px;
|
spacing-rows: 15px;
|
||||||
spacing-columns: 1em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Magnifier */
|
/* Magnifier */
|
||||||
@ -2032,7 +2016,7 @@ StScrollBar StButton#vhandle:active {
|
|||||||
min-width: 350px;
|
min-width: 350px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-dialog-prompt-login-hint-message {
|
.login-dialog-prompt-fingerprint-message {
|
||||||
font-size: 10.5pt;
|
font-size: 10.5pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2046,6 +2030,7 @@ StScrollBar StButton#vhandle:active {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.login-dialog-user-list-item {
|
.login-dialog-user-list-item {
|
||||||
|
color: #666666;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: .2em;
|
padding: .2em;
|
||||||
}
|
}
|
||||||
@ -2063,11 +2048,6 @@ StScrollBar StButton#vhandle:active {
|
|||||||
padding-left: 1em;
|
padding-left: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-dialog-user-list:expanded .login-dialog-user-list-item {
|
|
||||||
color: #666666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-dialog-user-list-item,
|
|
||||||
.login-dialog-user-list-item:hover .login-dialog-user-list-item-name,
|
.login-dialog-user-list-item:hover .login-dialog-user-list-item-name,
|
||||||
.login-dialog-user-list:expanded .login-dialog-user-list-item:focus .login-dialog-user-list-item-name,
|
.login-dialog-user-list:expanded .login-dialog-user-list-item:focus .login-dialog-user-list-item-name,
|
||||||
.login-dialog-user-list:expanded .login-dialog-user-list-item:logged-in {
|
.login-dialog-user-list:expanded .login-dialog-user-list-item:logged-in {
|
||||||
@ -2112,10 +2092,8 @@ StScrollBar StButton#vhandle:active {
|
|||||||
font-size: 10.5pt;
|
font-size: 10.5pt;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #666666;
|
color: #666666;
|
||||||
padding-top: 1em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-dialog-not-listed-button:focus .login-dialog-not-listed-label,
|
|
||||||
.login-dialog-not-listed-button:hover .login-dialog-not-listed-label {
|
.login-dialog-not-listed-button:hover .login-dialog-not-listed-label {
|
||||||
color: #E8E8E8;
|
color: #E8E8E8;
|
||||||
}
|
}
|
||||||
@ -2191,78 +2169,46 @@ StScrollBar StButton#vhandle:active {
|
|||||||
height: .75em;
|
height: .75em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.login-dialog .modal-dialog-button {
|
.login-dialog .modal-dialog-button {
|
||||||
|
border: 1px solid white;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 3px 18px;
|
padding: 3px 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-dialog .modal-dialog-button:focus {
|
|
||||||
padding: 2px 17px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-dialog .modal-dialog-button:default {
|
.login-dialog .modal-dialog-button:default {
|
||||||
background-gradient-start: #6793c4;
|
background-gradient-start: #6793c4;
|
||||||
background-gradient-end: #335d8f;
|
background-gradient-end: #335d8f;
|
||||||
background-gradient-direction: vertical;
|
background-gradient-direction: vertical;
|
||||||
border-color: #16335d;
|
border: 2px solid #16335d;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-dialog .modal-dialog-button:default:focus {
|
.login-dialog .modal-dialog-button:hover {
|
||||||
border: 2px solid #377fe7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-dialog .modal-dialog-button:default:hover {
|
|
||||||
background-gradient-start: #74a0d0;
|
background-gradient-start: #74a0d0;
|
||||||
background-gradient-end: #436d9f;
|
background-gradient-end: #436d9f;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-dialog .modal-dialog-button:default:active,
|
.login-dialog .modal-dialog-button:active,
|
||||||
.login-dialog .modal-dialog-button:default:pressed {
|
.login-dialog .modal-dialog-button:pressed {
|
||||||
background-gradient-start: #436d9f;
|
background-gradient-start: #436d9f;
|
||||||
background-gradient-end: #74a0d0;
|
background-gradient-end: #74a0d0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-dialog .modal-dialog-button:default:insensitive {
|
|
||||||
border-color: #666666;
|
|
||||||
color: #9f9f9f;
|
|
||||||
background-gradient-direction: none;
|
|
||||||
background-color: rgba(102, 102, 102, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-dialog-message-warning {
|
|
||||||
color: orange;
|
|
||||||
}
|
|
||||||
|
|
||||||
.unlock-dialog-user-name-container {
|
.unlock-dialog-user-name-container {
|
||||||
spacing: .4em;
|
spacing: .4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Screen shield */
|
/* Screen shield */
|
||||||
|
|
||||||
.screen-shield-background {
|
#screenShieldGroup {
|
||||||
background: black;
|
|
||||||
box-shadow: 0px 4px 8px rgba(0,0,0,0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
#lockDialogGroup {
|
|
||||||
background: #2e3436 url(noise-texture.png);
|
background: #2e3436 url(noise-texture.png);
|
||||||
background-repeat: repeat;
|
background-repeat: repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
.screen-shield-arrows {
|
#screenShieldGroup .arrow {
|
||||||
padding-bottom: 3em;
|
color: #333333;
|
||||||
}
|
width: 100px;
|
||||||
|
height: 50px;
|
||||||
.screen-shield-arrows Gjs_Arrow {
|
|
||||||
color: white;
|
|
||||||
width: 80px;
|
|
||||||
height: 48px;
|
|
||||||
-arrow-thickness: 12px;
|
|
||||||
-arrow-shadow: 0 1px 1px rgba(0,0,0,0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.screen-shield-contents-box {
|
|
||||||
spacing: 48px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.screen-shield-clock {
|
.screen-shield-clock {
|
||||||
@ -2274,12 +2220,12 @@ StScrollBar StButton#vhandle:active {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.screen-shield-clock-time {
|
.screen-shield-clock-time {
|
||||||
font-size: 72pt;
|
font-size: 86px;
|
||||||
text-shadow: 0px 2px 2px rgba(0,0,0,0.4);
|
text-shadow: 0px 2px 2px rgba(0,0,0,0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.screen-shield-clock-date {
|
.screen-shield-clock-date {
|
||||||
font-size: 28pt;
|
font-size: 48px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#screenShieldNotifications {
|
#screenShieldNotifications {
|
||||||
@ -2287,12 +2233,11 @@ StScrollBar StButton#vhandle:active {
|
|||||||
background-color: rgba(0.0, 0.0, 0.0, 0.9);
|
background-color: rgba(0.0, 0.0, 0.0, 0.9);
|
||||||
border: 2px solid #868686;
|
border: 2px solid #868686;
|
||||||
max-height: 500px;
|
max-height: 500px;
|
||||||
padding: 18px 0;
|
padding: 12px 0;
|
||||||
box-shadow: .5em .5em 20px rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.screen-shield-notifications-box {
|
.screen-shield-notifications-box {
|
||||||
spacing: 18px;
|
spacing: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.screen-shield-notification-source {
|
.screen-shield-notification-source {
|
||||||
@ -2303,7 +2248,6 @@ StScrollBar StButton#vhandle:active {
|
|||||||
.screen-shield-notification-label {
|
.screen-shield-notification-label {
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #babdb6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove background from notifications, otherwise
|
/* Remove background from notifications, otherwise
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 25 KiB |
@ -1,120 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
version="1.0"
|
|
||||||
id="Foreground"
|
|
||||||
x="0px"
|
|
||||||
y="0px"
|
|
||||||
width="32"
|
|
||||||
height="32"
|
|
||||||
viewBox="0 0 23.272727 23.272727"
|
|
||||||
enable-background="new 0 0 16 16"
|
|
||||||
xml:space="preserve"
|
|
||||||
sodipodi:version="0.32"
|
|
||||||
inkscape:version="0.48.2 r9819"
|
|
||||||
sodipodi:docname="summary-counter.svg"
|
|
||||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
|
|
||||||
id="metadata2399"><rdf:RDF><cc:Work
|
|
||||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
|
||||||
id="defs2397"><linearGradient
|
|
||||||
id="linearGradient3173"><stop
|
|
||||||
style="stop-color:#c4c4c4;stop-opacity:1;"
|
|
||||||
offset="0"
|
|
||||||
id="stop3175" /><stop
|
|
||||||
style="stop-color:#ffffff;stop-opacity:1;"
|
|
||||||
offset="1"
|
|
||||||
id="stop3177" /></linearGradient><inkscape:perspective
|
|
||||||
sodipodi:type="inkscape:persp3d"
|
|
||||||
inkscape:vp_x="0 : 8 : 1"
|
|
||||||
inkscape:vp_y="0 : 1000 : 0"
|
|
||||||
inkscape:vp_z="16 : 8 : 1"
|
|
||||||
inkscape:persp3d-origin="8 : 5.3333333 : 1"
|
|
||||||
id="perspective2401" /><filter
|
|
||||||
color-interpolation-filters="sRGB"
|
|
||||||
inkscape:collect="always"
|
|
||||||
id="filter16494-4"
|
|
||||||
x="-0.20989846"
|
|
||||||
width="1.4197969"
|
|
||||||
y="-0.20903821"
|
|
||||||
height="1.4180764"><feGaussianBlur
|
|
||||||
inkscape:collect="always"
|
|
||||||
stdDeviation="1.3282637"
|
|
||||||
id="feGaussianBlur16496-8" /></filter><radialGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
xlink:href="#linearGradient16498-6"
|
|
||||||
id="radialGradient16504-1"
|
|
||||||
cx="7.6582627"
|
|
||||||
cy="5.8191104"
|
|
||||||
fx="7.6582627"
|
|
||||||
fy="5.8191104"
|
|
||||||
r="8.6928644"
|
|
||||||
gradientTransform="matrix(1.0474339,0,0,1.0517402,-0.3632615,-0.42032492)"
|
|
||||||
gradientUnits="userSpaceOnUse" /><linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
id="linearGradient16498-6"><stop
|
|
||||||
style="stop-color:#9FD0FF;stop-opacity:1"
|
|
||||||
offset="0"
|
|
||||||
id="stop16500-8" /><stop
|
|
||||||
style="stop-color:#3465A4;stop-opacity:1"
|
|
||||||
offset="1"
|
|
||||||
id="stop16502-0" /></linearGradient></defs><sodipodi:namedview
|
|
||||||
inkscape:window-height="709"
|
|
||||||
inkscape:window-width="1366"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
guidetolerance="10.0"
|
|
||||||
gridtolerance="10.0"
|
|
||||||
objecttolerance="10.0"
|
|
||||||
borderopacity="1.0"
|
|
||||||
bordercolor="#666666"
|
|
||||||
pagecolor="#000000"
|
|
||||||
id="base"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="11.313708"
|
|
||||||
inkscape:cx="15.386407"
|
|
||||||
inkscape:cy="13.739577"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="1179"
|
|
||||||
inkscape:current-layer="g16402-8"
|
|
||||||
showguides="true"
|
|
||||||
inkscape:guide-bbox="true"
|
|
||||||
borderlayer="true"
|
|
||||||
inkscape:showpageshadow="false"
|
|
||||||
inkscape:window-maximized="1"><inkscape:grid
|
|
||||||
type="xygrid"
|
|
||||||
id="grid11246"
|
|
||||||
empspacing="5"
|
|
||||||
visible="true"
|
|
||||||
enabled="true"
|
|
||||||
snapvisiblegridlinesonly="true" /></sodipodi:namedview><g
|
|
||||||
style="display:inline"
|
|
||||||
id="g16402-8"
|
|
||||||
transform="translate(4.7533483,2.8238929)"><g
|
|
||||||
id="g3175-4"
|
|
||||||
transform="translate(-0.89995416,0.94028614)"><path
|
|
||||||
sodipodi:type="inkscape:offset"
|
|
||||||
inkscape:radius="0"
|
|
||||||
inkscape:original="M 7.65625 0.125 C 3.2589349 0.125 -0.3125 3.7070002 -0.3125 8.125 C -0.3125 12.543001 3.2589349 16.125 7.65625 16.125 C 12.053566 16.125 15.625 12.543001 15.625 8.125 C 15.625 3.7070002 12.053566 0.125 7.65625 0.125 z "
|
|
||||||
xlink:href="#path2394-32"
|
|
||||||
style="opacity:0.52994014;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.18181825;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter16494-4);enable-background:accumulate"
|
|
||||||
id="path16480-5"
|
|
||||||
inkscape:href="#path2394-32"
|
|
||||||
d="m 7.65625,0.125 c -4.3973151,0 -7.96875,3.5820002 -7.96875,8 0,4.418001 3.5714349,8 7.96875,8 4.397316,0 7.96875,-3.581999 7.96875,-8 0,-4.4179998 -3.571434,-8 -7.96875,-8 z"
|
|
||||||
transform="translate(0,1.028519)" /><path
|
|
||||||
clip-rule="evenodd"
|
|
||||||
d="m -0.30428257,8.1237596 c 0,-4.4179998 3.56522987,-7.9999996 7.96254497,-7.9999996 4.3973156,0 7.9625456,3.5819998 7.9625456,7.9999996 0,4.4180014 -3.56523,8.0000004 -7.9625456,8.0000004 -4.3973151,0 -7.96254497,-3.581999 -7.96254497,-8.0000004 z"
|
|
||||||
id="path2394-32"
|
|
||||||
style="color:#000000;fill:url(#radialGradient16504-1);fill-opacity:1;fill-rule:nonzero;stroke:#eeeeec;stroke-width:1.4545455;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
|
||||||
sodipodi:nodetypes="csssc"
|
|
||||||
inkscape:connector-curvature="0" /><g
|
|
||||||
id="g3172-6" /></g></g></svg>
|
|
Before Width: | Height: | Size: 5.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 850 B |
376
data/theme/ws-switch-arrow-down.svg
Normal file
376
data/theme/ws-switch-arrow-down.svg
Normal file
@ -0,0 +1,376 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
width="96"
|
||||||
|
height="96"
|
||||||
|
id="svg25070"
|
||||||
|
inkscape:version="0.48.0 r9654"
|
||||||
|
sodipodi:docname="ws-switch-arrow-down.svg">
|
||||||
|
<metadata
|
||||||
|
id="metadata3353">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="718"
|
||||||
|
inkscape:window-height="480"
|
||||||
|
id="namedview3351"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="2.6979167"
|
||||||
|
inkscape:cx="48"
|
||||||
|
inkscape:cy="48"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="26"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg25070" />
|
||||||
|
<defs
|
||||||
|
id="defs25072">
|
||||||
|
<linearGradient
|
||||||
|
x1="-86.552246"
|
||||||
|
y1="185.439"
|
||||||
|
x2="-83.37072"
|
||||||
|
y2="197.31261"
|
||||||
|
id="linearGradient24957"
|
||||||
|
xlink:href="#linearGradient4034-0-4"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(6,0)" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4034-0-4">
|
||||||
|
<stop
|
||||||
|
id="stop4036-5-7"
|
||||||
|
style="stop-color:#eeeeec;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop4038-9-6"
|
||||||
|
style="stop-color:#babdb6;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="1"
|
||||||
|
height="1"
|
||||||
|
color-interpolation-filters="sRGB"
|
||||||
|
id="filter24765">
|
||||||
|
<feColorMatrix
|
||||||
|
result="fbSourceGraphic"
|
||||||
|
values="1"
|
||||||
|
type="saturate"
|
||||||
|
id="feColorMatrix24767" />
|
||||||
|
<feColorMatrix
|
||||||
|
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"
|
||||||
|
in="fbSourceGraphic"
|
||||||
|
id="feColorMatrix24769" />
|
||||||
|
</filter>
|
||||||
|
<linearGradient
|
||||||
|
x1="-74.520325"
|
||||||
|
y1="169.06032"
|
||||||
|
x2="-74.520325"
|
||||||
|
y2="205.94189"
|
||||||
|
id="linearGradient24955"
|
||||||
|
xlink:href="#linearGradient4632-1-3-9-3-2"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(-5,0)" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4632-1-3-9-3-2">
|
||||||
|
<stop
|
||||||
|
id="stop4634-1-8-3-9-0"
|
||||||
|
style="stop-color:#eeeeec;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop4636-1-9-9-8-8"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
offset="0.0274937" />
|
||||||
|
<stop
|
||||||
|
id="stop4638-8-3-9-6-6"
|
||||||
|
style="stop-color:#f2f2f2;stop-opacity:1"
|
||||||
|
offset="0.274937" />
|
||||||
|
<stop
|
||||||
|
id="stop4640-8-5-7-8-9"
|
||||||
|
style="stop-color:#eeeeec;stop-opacity:1"
|
||||||
|
offset="0.38707438" />
|
||||||
|
<stop
|
||||||
|
id="stop4642-5-41-9-6-9"
|
||||||
|
style="stop-color:#d9dad8;stop-opacity:1"
|
||||||
|
offset="0.66528589" />
|
||||||
|
<stop
|
||||||
|
id="stop4644-5-2-7-9-2"
|
||||||
|
style="stop-color:#dfe0dd;stop-opacity:1"
|
||||||
|
offset="0.76745707" />
|
||||||
|
<stop
|
||||||
|
id="stop4646-3-2-3-7-3"
|
||||||
|
style="stop-color:#f0f0f0;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
cx="-33.412369"
|
||||||
|
cy="185.74171"
|
||||||
|
r="2.3554697"
|
||||||
|
fx="-33.412369"
|
||||||
|
fy="185.74171"
|
||||||
|
id="radialGradient24959"
|
||||||
|
xlink:href="#linearGradient4869-4-1"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.0075,0,0,1.0075,-5.4544,-1.25141)" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4869-4-1">
|
||||||
|
<stop
|
||||||
|
id="stop4871-6-2"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop4879-7-4"
|
||||||
|
style="stop-color:#eeeeec;stop-opacity:1"
|
||||||
|
offset="0.31807542" />
|
||||||
|
<stop
|
||||||
|
id="stop4877-6-1"
|
||||||
|
style="stop-color:#c8c9c6;stop-opacity:1"
|
||||||
|
offset="0.74691135" />
|
||||||
|
<stop
|
||||||
|
id="stop4873-1-0"
|
||||||
|
style="stop-color:#d3d7cf;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="1"
|
||||||
|
height="1"
|
||||||
|
color-interpolation-filters="sRGB"
|
||||||
|
id="filter25011">
|
||||||
|
<feColorMatrix
|
||||||
|
result="fbSourceGraphic"
|
||||||
|
values="1"
|
||||||
|
type="saturate"
|
||||||
|
id="feColorMatrix25013" />
|
||||||
|
<feColorMatrix
|
||||||
|
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"
|
||||||
|
in="fbSourceGraphic"
|
||||||
|
id="feColorMatrix25015" />
|
||||||
|
</filter>
|
||||||
|
<radialGradient
|
||||||
|
cx="-33.412369"
|
||||||
|
cy="185.74171"
|
||||||
|
r="2.3554697"
|
||||||
|
fx="-33.412369"
|
||||||
|
fy="185.74171"
|
||||||
|
id="radialGradient24961"
|
||||||
|
xlink:href="#linearGradient4869-4-0"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.0075,0,0,1.0075,-5.4544,-1.25141)" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4869-4-0">
|
||||||
|
<stop
|
||||||
|
id="stop4871-6-8"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop4879-7-5"
|
||||||
|
style="stop-color:#eeeeec;stop-opacity:1"
|
||||||
|
offset="0.31807542" />
|
||||||
|
<stop
|
||||||
|
id="stop4877-6-5"
|
||||||
|
style="stop-color:#c8c9c6;stop-opacity:1"
|
||||||
|
offset="0.74691135" />
|
||||||
|
<stop
|
||||||
|
id="stop4873-1-4"
|
||||||
|
style="stop-color:#d3d7cf;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="1"
|
||||||
|
height="1"
|
||||||
|
color-interpolation-filters="sRGB"
|
||||||
|
id="filter25023">
|
||||||
|
<feColorMatrix
|
||||||
|
result="fbSourceGraphic"
|
||||||
|
values="1"
|
||||||
|
type="saturate"
|
||||||
|
id="feColorMatrix25025" />
|
||||||
|
<feColorMatrix
|
||||||
|
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"
|
||||||
|
in="fbSourceGraphic"
|
||||||
|
id="feColorMatrix25027" />
|
||||||
|
</filter>
|
||||||
|
<linearGradient
|
||||||
|
x1="-39.858727"
|
||||||
|
y1="184.61784"
|
||||||
|
x2="-38.244785"
|
||||||
|
y2="188.84898"
|
||||||
|
id="linearGradient24963"
|
||||||
|
xlink:href="#linearGradient4941"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4941">
|
||||||
|
<stop
|
||||||
|
id="stop4943"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop4945"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="1"
|
||||||
|
height="1"
|
||||||
|
color-interpolation-filters="sRGB"
|
||||||
|
id="filter25033">
|
||||||
|
<feColorMatrix
|
||||||
|
result="fbSourceGraphic"
|
||||||
|
values="1"
|
||||||
|
type="saturate"
|
||||||
|
id="feColorMatrix25035" />
|
||||||
|
<feColorMatrix
|
||||||
|
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"
|
||||||
|
in="fbSourceGraphic"
|
||||||
|
id="feColorMatrix25037" />
|
||||||
|
</filter>
|
||||||
|
<linearGradient
|
||||||
|
x1="-39.858727"
|
||||||
|
y1="184.61784"
|
||||||
|
x2="-38.244785"
|
||||||
|
y2="188.84898"
|
||||||
|
id="linearGradient24965"
|
||||||
|
xlink:href="#linearGradient4941-7"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4941-7">
|
||||||
|
<stop
|
||||||
|
id="stop4943-2"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop4945-5"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="1"
|
||||||
|
height="1"
|
||||||
|
color-interpolation-filters="sRGB"
|
||||||
|
id="filter25043">
|
||||||
|
<feColorMatrix
|
||||||
|
result="fbSourceGraphic"
|
||||||
|
values="1"
|
||||||
|
type="saturate"
|
||||||
|
id="feColorMatrix25045" />
|
||||||
|
<feColorMatrix
|
||||||
|
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"
|
||||||
|
in="fbSourceGraphic"
|
||||||
|
id="feColorMatrix25047" />
|
||||||
|
</filter>
|
||||||
|
<filter
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="1"
|
||||||
|
height="1"
|
||||||
|
color-interpolation-filters="sRGB"
|
||||||
|
id="filter25049">
|
||||||
|
<feColorMatrix
|
||||||
|
result="fbSourceGraphic"
|
||||||
|
values="1"
|
||||||
|
type="saturate"
|
||||||
|
id="feColorMatrix25051" />
|
||||||
|
<feColorMatrix
|
||||||
|
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"
|
||||||
|
in="fbSourceGraphic"
|
||||||
|
id="feColorMatrix25053" />
|
||||||
|
</filter>
|
||||||
|
<filter
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="1"
|
||||||
|
height="1"
|
||||||
|
color-interpolation-filters="sRGB"
|
||||||
|
id="filter25055">
|
||||||
|
<feColorMatrix
|
||||||
|
result="fbSourceGraphic"
|
||||||
|
values="1"
|
||||||
|
type="saturate"
|
||||||
|
id="feColorMatrix25057" />
|
||||||
|
<feColorMatrix
|
||||||
|
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"
|
||||||
|
in="fbSourceGraphic"
|
||||||
|
id="feColorMatrix25059" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<g
|
||||||
|
transform="matrix(0,1,-1,0,48.0003,4.1307112e-7)"
|
||||||
|
id="layer1">
|
||||||
|
<g
|
||||||
|
transform="matrix(-2,0,0,2,-97.2497,-374.967)"
|
||||||
|
id="g4030-1-8"
|
||||||
|
style="stroke:#000000;stroke-opacity:1;display:inline">
|
||||||
|
<path
|
||||||
|
d="m -72.5,173.5 -14,14 14,14"
|
||||||
|
id="path3165-7-3"
|
||||||
|
style="color:#000000;fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z"
|
||||||
|
transform="matrix(-3.34328,0,0,3.34328,-89.2797,-623.176)"
|
||||||
|
id="path4050-2-7-9-4"
|
||||||
|
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52343899;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z"
|
||||||
|
transform="matrix(-3.34328,0,0,3.34328,-111.2797,-623.176)"
|
||||||
|
id="path4050-2-7-9-4-8"
|
||||||
|
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52343899;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z"
|
||||||
|
transform="matrix(-2.86565,0,0,2.86565,-70.8457,-534.143)"
|
||||||
|
id="path4050-2-7-9-4-0"
|
||||||
|
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.69792098;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z"
|
||||||
|
transform="matrix(-2.86565,0,0,2.86565,-92.8457,-534.143)"
|
||||||
|
id="path4050-2-7-9-4-0-9"
|
||||||
|
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.69792098;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m 47.87528,-34.0295 c 1.53896,0.0448 3.0511,0.70928 4.125,1.8125 l 32.25,32.25 -32.25,32.25 c -2.2253,2.2253 -6.2747,2.2253 -8.5,0 -2.2253,-2.22528 -2.2253,-6.2747 0,-8.5 l 23.75,-23.75 -23.75,-23.75 c -1.73168,-1.6731 -2.295,-4.44228 -1.3546,-6.65894 0.94042,-2.21668 3.32312,-3.73604 5.7296,-3.65356 z"
|
||||||
|
id="path3165-7-3-1"
|
||||||
|
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0pt;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;opacity:0.35;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m 41.8316,28.09418 c -0.014,-1.58898 0.54158,-3.18406 1.66868,-4.31118 l 23.75,-23.75 m -25.1046,-30.40894 c 0.94042,-2.21668 3.32312,-3.73604 5.7296,-3.65356 1.53896,0.0448 3.0511,0.70928 4.125,1.8125 l 32.25,32.25"
|
||||||
|
id="path3165-7-3-1-9"
|
||||||
|
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0pt;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
Before Width: | Height: | Size: 841 B |
447
data/theme/ws-switch-arrow-up.svg
Normal file
447
data/theme/ws-switch-arrow-up.svg
Normal file
@ -0,0 +1,447 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="96"
|
||||||
|
height="96"
|
||||||
|
id="svg25070"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.0 r9654"
|
||||||
|
sodipodi:docname="ws-switch-arrow-up.svg">
|
||||||
|
<defs
|
||||||
|
id="defs25072">
|
||||||
|
<inkscape:perspective
|
||||||
|
sodipodi:type="inkscape:persp3d"
|
||||||
|
inkscape:vp_x="0 : 24 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_z="48 : 24 : 1"
|
||||||
|
inkscape:persp3d-origin="24 : 16 : 1"
|
||||||
|
id="perspective25078" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective24985"
|
||||||
|
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||||
|
inkscape:vp_z="1 : 0.5 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 0.5 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4034-0-4"
|
||||||
|
id="linearGradient24957"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(6)"
|
||||||
|
x1="-86.552246"
|
||||||
|
y1="185.439"
|
||||||
|
x2="-83.37072"
|
||||||
|
y2="197.31261" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient4034-0-4">
|
||||||
|
<stop
|
||||||
|
style="stop-color: rgb(238, 238, 236); stop-opacity: 1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4036-5-7" />
|
||||||
|
<stop
|
||||||
|
style="stop-color: rgb(186, 189, 182); stop-opacity: 1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4038-9-6" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
id="filter24765"
|
||||||
|
inkscape:label="Invert"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="1"
|
||||||
|
height="1"
|
||||||
|
inkscape:menu="Color"
|
||||||
|
inkscape:menu-tooltip="Invert colors"
|
||||||
|
color-interpolation-filters="sRGB">
|
||||||
|
<feColorMatrix
|
||||||
|
id="feColorMatrix24767"
|
||||||
|
type="saturate"
|
||||||
|
values="1"
|
||||||
|
result="fbSourceGraphic" />
|
||||||
|
<feColorMatrix
|
||||||
|
id="feColorMatrix24769"
|
||||||
|
in="fbSourceGraphic"
|
||||||
|
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" />
|
||||||
|
</filter>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4632-1-3-9-3-2"
|
||||||
|
id="linearGradient24955"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(-5)"
|
||||||
|
x1="-74.520325"
|
||||||
|
y1="169.06032"
|
||||||
|
x2="-74.520325"
|
||||||
|
y2="205.94189" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4632-1-3-9-3-2">
|
||||||
|
<stop
|
||||||
|
style="stop-color: rgb(238, 238, 236); stop-opacity: 1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4634-1-8-3-9-0" />
|
||||||
|
<stop
|
||||||
|
id="stop4636-1-9-9-8-8"
|
||||||
|
offset="0.0274937"
|
||||||
|
style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" />
|
||||||
|
<stop
|
||||||
|
id="stop4638-8-3-9-6-6"
|
||||||
|
offset="0.274937"
|
||||||
|
style="stop-color: rgb(242, 242, 242); stop-opacity: 1;" />
|
||||||
|
<stop
|
||||||
|
id="stop4640-8-5-7-8-9"
|
||||||
|
offset="0.38707438"
|
||||||
|
style="stop-color: rgb(238, 238, 236); stop-opacity: 1;" />
|
||||||
|
<stop
|
||||||
|
id="stop4642-5-41-9-6-9"
|
||||||
|
offset="0.66528589"
|
||||||
|
style="stop-color: rgb(217, 218, 216); stop-opacity: 1;" />
|
||||||
|
<stop
|
||||||
|
id="stop4644-5-2-7-9-2"
|
||||||
|
offset="0.76745707"
|
||||||
|
style="stop-color: rgb(223, 224, 221); stop-opacity: 1;" />
|
||||||
|
<stop
|
||||||
|
style="stop-color: rgb(240, 240, 240); stop-opacity: 1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4646-3-2-3-7-3" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4869-4-1"
|
||||||
|
id="radialGradient24959"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.0075, 0, 0, 1.0075, -5.4544, -1.25141)"
|
||||||
|
cx="-33.412369"
|
||||||
|
cy="185.74171"
|
||||||
|
fx="-33.412369"
|
||||||
|
fy="185.74171"
|
||||||
|
r="2.3554697" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4869-4-1">
|
||||||
|
<stop
|
||||||
|
style="stop-color: rgb(255, 255, 255); stop-opacity: 1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4871-6-2" />
|
||||||
|
<stop
|
||||||
|
id="stop4879-7-4"
|
||||||
|
offset="0.31807542"
|
||||||
|
style="stop-color: rgb(238, 238, 236); stop-opacity: 1;" />
|
||||||
|
<stop
|
||||||
|
id="stop4877-6-1"
|
||||||
|
offset="0.74691135"
|
||||||
|
style="stop-color: rgb(200, 201, 198); stop-opacity: 1;" />
|
||||||
|
<stop
|
||||||
|
style="stop-color: rgb(211, 215, 207); stop-opacity: 1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4873-1-0" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
id="filter25011"
|
||||||
|
inkscape:label="Invert"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="1"
|
||||||
|
height="1"
|
||||||
|
inkscape:menu="Color"
|
||||||
|
inkscape:menu-tooltip="Invert colors"
|
||||||
|
color-interpolation-filters="sRGB">
|
||||||
|
<feColorMatrix
|
||||||
|
id="feColorMatrix25013"
|
||||||
|
type="saturate"
|
||||||
|
values="1"
|
||||||
|
result="fbSourceGraphic" />
|
||||||
|
<feColorMatrix
|
||||||
|
id="feColorMatrix25015"
|
||||||
|
in="fbSourceGraphic"
|
||||||
|
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" />
|
||||||
|
</filter>
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4869-4-0"
|
||||||
|
id="radialGradient24961"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.0075, 0, 0, 1.0075, -5.4544, -1.25141)"
|
||||||
|
cx="-33.412369"
|
||||||
|
cy="185.74171"
|
||||||
|
fx="-33.412369"
|
||||||
|
fy="185.74171"
|
||||||
|
r="2.3554697" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4869-4-0">
|
||||||
|
<stop
|
||||||
|
style="stop-color: rgb(255, 255, 255); stop-opacity: 1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4871-6-8" />
|
||||||
|
<stop
|
||||||
|
id="stop4879-7-5"
|
||||||
|
offset="0.31807542"
|
||||||
|
style="stop-color: rgb(238, 238, 236); stop-opacity: 1;" />
|
||||||
|
<stop
|
||||||
|
id="stop4877-6-5"
|
||||||
|
offset="0.74691135"
|
||||||
|
style="stop-color: rgb(200, 201, 198); stop-opacity: 1;" />
|
||||||
|
<stop
|
||||||
|
style="stop-color: rgb(211, 215, 207); stop-opacity: 1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4873-1-4" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
id="filter25023"
|
||||||
|
inkscape:label="Invert"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="1"
|
||||||
|
height="1"
|
||||||
|
inkscape:menu="Color"
|
||||||
|
inkscape:menu-tooltip="Invert colors"
|
||||||
|
color-interpolation-filters="sRGB">
|
||||||
|
<feColorMatrix
|
||||||
|
id="feColorMatrix25025"
|
||||||
|
type="saturate"
|
||||||
|
values="1"
|
||||||
|
result="fbSourceGraphic" />
|
||||||
|
<feColorMatrix
|
||||||
|
id="feColorMatrix25027"
|
||||||
|
in="fbSourceGraphic"
|
||||||
|
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" />
|
||||||
|
</filter>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4941"
|
||||||
|
id="linearGradient24963"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="-39.858727"
|
||||||
|
y1="184.61784"
|
||||||
|
x2="-38.244785"
|
||||||
|
y2="188.84898" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient4941">
|
||||||
|
<stop
|
||||||
|
style="stop-color: rgb(255, 255, 255); stop-opacity: 1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4943" />
|
||||||
|
<stop
|
||||||
|
style="stop-color: rgb(255, 255, 255); stop-opacity: 0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4945" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
id="filter25033"
|
||||||
|
inkscape:label="Invert"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="1"
|
||||||
|
height="1"
|
||||||
|
inkscape:menu="Color"
|
||||||
|
inkscape:menu-tooltip="Invert colors"
|
||||||
|
color-interpolation-filters="sRGB">
|
||||||
|
<feColorMatrix
|
||||||
|
id="feColorMatrix25035"
|
||||||
|
type="saturate"
|
||||||
|
values="1"
|
||||||
|
result="fbSourceGraphic" />
|
||||||
|
<feColorMatrix
|
||||||
|
id="feColorMatrix25037"
|
||||||
|
in="fbSourceGraphic"
|
||||||
|
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" />
|
||||||
|
</filter>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4941-7"
|
||||||
|
id="linearGradient24965"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="-39.858727"
|
||||||
|
y1="184.61784"
|
||||||
|
x2="-38.244785"
|
||||||
|
y2="188.84898" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient4941-7">
|
||||||
|
<stop
|
||||||
|
style="stop-color: rgb(255, 255, 255); stop-opacity: 1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4943-2" />
|
||||||
|
<stop
|
||||||
|
style="stop-color: rgb(255, 255, 255); stop-opacity: 0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4945-5" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
id="filter25043"
|
||||||
|
inkscape:label="Invert"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="1"
|
||||||
|
height="1"
|
||||||
|
inkscape:menu="Color"
|
||||||
|
inkscape:menu-tooltip="Invert colors"
|
||||||
|
color-interpolation-filters="sRGB">
|
||||||
|
<feColorMatrix
|
||||||
|
id="feColorMatrix25045"
|
||||||
|
type="saturate"
|
||||||
|
values="1"
|
||||||
|
result="fbSourceGraphic" />
|
||||||
|
<feColorMatrix
|
||||||
|
id="feColorMatrix25047"
|
||||||
|
in="fbSourceGraphic"
|
||||||
|
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" />
|
||||||
|
</filter>
|
||||||
|
<filter
|
||||||
|
id="filter25049"
|
||||||
|
inkscape:label="Invert"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="1"
|
||||||
|
height="1"
|
||||||
|
inkscape:menu="Color"
|
||||||
|
inkscape:menu-tooltip="Invert colors"
|
||||||
|
color-interpolation-filters="sRGB">
|
||||||
|
<feColorMatrix
|
||||||
|
id="feColorMatrix25051"
|
||||||
|
type="saturate"
|
||||||
|
values="1"
|
||||||
|
result="fbSourceGraphic" />
|
||||||
|
<feColorMatrix
|
||||||
|
id="feColorMatrix25053"
|
||||||
|
in="fbSourceGraphic"
|
||||||
|
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" />
|
||||||
|
</filter>
|
||||||
|
<filter
|
||||||
|
id="filter25055"
|
||||||
|
inkscape:label="Invert"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="1"
|
||||||
|
height="1"
|
||||||
|
inkscape:menu="Color"
|
||||||
|
inkscape:menu-tooltip="Invert colors"
|
||||||
|
color-interpolation-filters="sRGB">
|
||||||
|
<feColorMatrix
|
||||||
|
id="feColorMatrix25057"
|
||||||
|
type="saturate"
|
||||||
|
values="1"
|
||||||
|
result="fbSourceGraphic" />
|
||||||
|
<feColorMatrix
|
||||||
|
id="feColorMatrix25059"
|
||||||
|
in="fbSourceGraphic"
|
||||||
|
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="2.8284271"
|
||||||
|
inkscape:cx="-12.356322"
|
||||||
|
inkscape:cy="57.536221"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:grid-bbox="true"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:window-width="1200"
|
||||||
|
inkscape:window-height="840"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="26"
|
||||||
|
inkscape:window-maximized="0" />
|
||||||
|
<metadata
|
||||||
|
id="metadata25075">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
transform="translate(0, 48)">
|
||||||
|
<g
|
||||||
|
id="g3181"
|
||||||
|
transform="matrix(0,1,-1,0,48.0003,-48)">
|
||||||
|
<g
|
||||||
|
style="stroke:#000000;stroke-opacity:1;display:inline"
|
||||||
|
transform="matrix(2,0,0,2,193.25,-374.967)"
|
||||||
|
id="g4030-1-8">
|
||||||
|
<path
|
||||||
|
style="color:#000000;fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||||
|
d="m -72.5,173.5 -14,14 14,14"
|
||||||
|
id="path3165-7-3"
|
||||||
|
sodipodi:nodetypes="ccc"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
transform="matrix(3.34328,0,0,3.34328,185.28,-623.176)"
|
||||||
|
d="m -36.5,186.40625 c 0,1.15635 -0.937404,2.09375 -2.09375,2.09375 -1.156346,0 -2.09375,-0.9374 -2.09375,-2.09375 0,-1.15635 0.937404,-2.09375 2.09375,-2.09375 1.156346,0 2.09375,0.9374 2.09375,2.09375 z"
|
||||||
|
sodipodi:ry="2.09375"
|
||||||
|
sodipodi:rx="2.09375"
|
||||||
|
sodipodi:cy="186.40625"
|
||||||
|
sodipodi:cx="-38.59375"
|
||||||
|
id="path4050-2-7-9-4"
|
||||||
|
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52343899;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||||
|
sodipodi:type="arc" />
|
||||||
|
<path
|
||||||
|
transform="matrix(3.34328,0,0,3.34328,207.28,-623.176)"
|
||||||
|
d="m -36.5,186.40625 c 0,1.15635 -0.937404,2.09375 -2.09375,2.09375 -1.156346,0 -2.09375,-0.9374 -2.09375,-2.09375 0,-1.15635 0.937404,-2.09375 2.09375,-2.09375 1.156346,0 2.09375,0.9374 2.09375,2.09375 z"
|
||||||
|
sodipodi:ry="2.09375"
|
||||||
|
sodipodi:rx="2.09375"
|
||||||
|
sodipodi:cy="186.40625"
|
||||||
|
sodipodi:cx="-38.59375"
|
||||||
|
id="path4050-2-7-9-4-8"
|
||||||
|
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52343899;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||||
|
sodipodi:type="arc" />
|
||||||
|
<path
|
||||||
|
transform="matrix(2.86565,0,0,2.86565,166.846,-534.143)"
|
||||||
|
d="m -36.5,186.40625 c 0,1.15635 -0.937404,2.09375 -2.09375,2.09375 -1.156346,0 -2.09375,-0.9374 -2.09375,-2.09375 0,-1.15635 0.937404,-2.09375 2.09375,-2.09375 1.156346,0 2.09375,0.9374 2.09375,2.09375 z"
|
||||||
|
sodipodi:ry="2.09375"
|
||||||
|
sodipodi:rx="2.09375"
|
||||||
|
sodipodi:cy="186.40625"
|
||||||
|
sodipodi:cx="-38.59375"
|
||||||
|
id="path4050-2-7-9-4-0"
|
||||||
|
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.69792098;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||||
|
sodipodi:type="arc" />
|
||||||
|
<path
|
||||||
|
transform="matrix(2.86565,0,0,2.86565,188.846,-534.143)"
|
||||||
|
d="m -36.5,186.40625 c 0,1.15635 -0.937404,2.09375 -2.09375,2.09375 -1.156346,0 -2.09375,-0.9374 -2.09375,-2.09375 0,-1.15635 0.937404,-2.09375 2.09375,-2.09375 1.156346,0 2.09375,0.9374 2.09375,2.09375 z"
|
||||||
|
sodipodi:ry="2.09375"
|
||||||
|
sodipodi:rx="2.09375"
|
||||||
|
sodipodi:cy="186.40625"
|
||||||
|
sodipodi:cx="-38.59375"
|
||||||
|
id="path4050-2-7-9-4-0-9"
|
||||||
|
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.69792098;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||||
|
sodipodi:type="arc" />
|
||||||
|
<path
|
||||||
|
transform="matrix(2,0,0,2,-586,-765.967)"
|
||||||
|
sodipodi:nodetypes="ccccscccsc"
|
||||||
|
id="path3165-7-3-1"
|
||||||
|
d="m 317.06251,365.96875 c -0.76948,0.0224 -1.52555,0.35464 -2.0625,0.90625 l -16.125,16.125 16.125,16.125 c 1.11265,1.11265 3.13735,1.11265 4.25,0 1.11265,-1.11264 1.11265,-3.13735 0,-4.25 l -11.875,-11.875 11.875,-11.875 c 0.86584,-0.83655 1.1475,-2.22114 0.6773,-3.32947 -0.47021,-1.10834 -1.66156,-1.86802 -2.8648,-1.82678 z"
|
||||||
|
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0pt;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;opacity:0.35;color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
transform="matrix(2,0,0,2,-586,-765.967)"
|
||||||
|
sodipodi:nodetypes="ccccccc"
|
||||||
|
id="path3165-7-3-1-9"
|
||||||
|
d="m 320.08435,397.03059 c 0.007,-0.79449 -0.27079,-1.59203 -0.83434,-2.15559 L 307.37501,383 m 12.5523,-15.20447 c -0.47021,-1.10834 -1.66156,-1.86802 -2.8648,-1.82678 -0.76948,0.0224 -1.52555,0.35464 -2.0625,0.90625 L 298.87501,383"
|
||||||
|
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0pt;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 16 KiB |
@ -29,6 +29,8 @@
|
|||||||
<chapter>
|
<chapter>
|
||||||
<title>Search</title>
|
<title>Search</title>
|
||||||
<xi:include href="xml/shell-app-system.xml"/>
|
<xi:include href="xml/shell-app-system.xml"/>
|
||||||
|
<xi:include href="xml/shell-contact-system.xml"/>
|
||||||
|
<xi:include href="xml/shell-doc-system.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
<chapter>
|
<chapter>
|
||||||
<title>Tray Icons</title>
|
<title>Tray Icons</title>
|
||||||
@ -40,6 +42,7 @@
|
|||||||
<chapter>
|
<chapter>
|
||||||
<title>Recorder</title>
|
<title>Recorder</title>
|
||||||
<xi:include href="xml/shell-recorder.xml"/>
|
<xi:include href="xml/shell-recorder.xml"/>
|
||||||
|
<xi:include href="xml/shell-recorder-src.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
<chapter>
|
<chapter>
|
||||||
<title>Integration helpers and utilities</title>
|
<title>Integration helpers and utilities</title>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
NULL =
|
|
||||||
|
|
||||||
EXTRA_DIST = misc/config.js.in
|
EXTRA_DIST = misc/config.js.in
|
||||||
CLEANFILES = misc/config.js
|
CLEANFILES = misc/config.js
|
||||||
@ -18,10 +17,11 @@ jsdir = $(pkgdatadir)/js
|
|||||||
|
|
||||||
nobase_dist_js_DATA = \
|
nobase_dist_js_DATA = \
|
||||||
gdm/batch.js \
|
gdm/batch.js \
|
||||||
|
gdm/consoleKit.js \
|
||||||
gdm/fingerprint.js \
|
gdm/fingerprint.js \
|
||||||
gdm/loginDialog.js \
|
gdm/loginDialog.js \
|
||||||
gdm/powerMenu.js \
|
gdm/powerMenu.js \
|
||||||
gdm/realmd.js \
|
gdm/systemd.js \
|
||||||
gdm/util.js \
|
gdm/util.js \
|
||||||
extensionPrefs/main.js \
|
extensionPrefs/main.js \
|
||||||
misc/config.js \
|
misc/config.js \
|
||||||
@ -30,7 +30,6 @@ nobase_dist_js_DATA = \
|
|||||||
misc/gnomeSession.js \
|
misc/gnomeSession.js \
|
||||||
misc/history.js \
|
misc/history.js \
|
||||||
misc/jsParse.js \
|
misc/jsParse.js \
|
||||||
misc/loginManager.js \
|
|
||||||
misc/modemManager.js \
|
misc/modemManager.js \
|
||||||
misc/params.js \
|
misc/params.js \
|
||||||
misc/util.js \
|
misc/util.js \
|
||||||
@ -38,6 +37,8 @@ nobase_dist_js_DATA = \
|
|||||||
ui/altTab.js \
|
ui/altTab.js \
|
||||||
ui/appDisplay.js \
|
ui/appDisplay.js \
|
||||||
ui/appFavorites.js \
|
ui/appFavorites.js \
|
||||||
|
ui/automountManager.js \
|
||||||
|
ui/autorunManager.js \
|
||||||
ui/boxpointer.js \
|
ui/boxpointer.js \
|
||||||
ui/calendar.js \
|
ui/calendar.js \
|
||||||
ui/checkBox.js \
|
ui/checkBox.js \
|
||||||
@ -46,14 +47,14 @@ nobase_dist_js_DATA = \
|
|||||||
ui/dateMenu.js \
|
ui/dateMenu.js \
|
||||||
ui/dnd.js \
|
ui/dnd.js \
|
||||||
ui/endSessionDialog.js \
|
ui/endSessionDialog.js \
|
||||||
|
ui/environment.js \
|
||||||
ui/extensionSystem.js \
|
ui/extensionSystem.js \
|
||||||
ui/extensionDownloader.js \
|
ui/extensionDownloader.js \
|
||||||
ui/environment.js \
|
|
||||||
ui/flashspot.js \
|
ui/flashspot.js \
|
||||||
ui/ibusCandidatePopup.js\
|
ui/ibusCandidatePopup.js\
|
||||||
ui/grabHelper.js \
|
|
||||||
ui/iconGrid.js \
|
ui/iconGrid.js \
|
||||||
ui/keyboard.js \
|
ui/keyboard.js \
|
||||||
|
ui/keyringPrompt.js \
|
||||||
ui/layout.js \
|
ui/layout.js \
|
||||||
ui/lightbox.js \
|
ui/lightbox.js \
|
||||||
ui/lookingGlass.js \
|
ui/lookingGlass.js \
|
||||||
@ -62,6 +63,7 @@ nobase_dist_js_DATA = \
|
|||||||
ui/main.js \
|
ui/main.js \
|
||||||
ui/messageTray.js \
|
ui/messageTray.js \
|
||||||
ui/modalDialog.js \
|
ui/modalDialog.js \
|
||||||
|
ui/networkAgent.js \
|
||||||
ui/sessionMode.js \
|
ui/sessionMode.js \
|
||||||
ui/shellEntry.js \
|
ui/shellEntry.js \
|
||||||
ui/shellMountOperation.js \
|
ui/shellMountOperation.js \
|
||||||
@ -69,7 +71,8 @@ nobase_dist_js_DATA = \
|
|||||||
ui/overview.js \
|
ui/overview.js \
|
||||||
ui/panel.js \
|
ui/panel.js \
|
||||||
ui/panelMenu.js \
|
ui/panelMenu.js \
|
||||||
ui/pointerWatcher.js \
|
ui/placeDisplay.js \
|
||||||
|
ui/polkitAuthenticationAgent.js \
|
||||||
ui/popupMenu.js \
|
ui/popupMenu.js \
|
||||||
ui/remoteSearch.js \
|
ui/remoteSearch.js \
|
||||||
ui/runDialog.js \
|
ui/runDialog.js \
|
||||||
@ -80,11 +83,11 @@ nobase_dist_js_DATA = \
|
|||||||
ui/shellDBus.js \
|
ui/shellDBus.js \
|
||||||
ui/status/accessibility.js \
|
ui/status/accessibility.js \
|
||||||
ui/status/keyboard.js \
|
ui/status/keyboard.js \
|
||||||
ui/status/lockScreenMenu.js \
|
|
||||||
ui/status/network.js \
|
ui/status/network.js \
|
||||||
ui/status/power.js \
|
ui/status/power.js \
|
||||||
ui/status/volume.js \
|
ui/status/volume.js \
|
||||||
ui/status/bluetooth.js \
|
ui/status/bluetooth.js \
|
||||||
|
ui/telepathyClient.js \
|
||||||
ui/tweener.js \
|
ui/tweener.js \
|
||||||
ui/unlockDialog.js \
|
ui/unlockDialog.js \
|
||||||
ui/userMenu.js \
|
ui/userMenu.js \
|
||||||
@ -96,13 +99,4 @@ nobase_dist_js_DATA = \
|
|||||||
ui/workspaceThumbnail.js \
|
ui/workspaceThumbnail.js \
|
||||||
ui/workspacesView.js \
|
ui/workspacesView.js \
|
||||||
ui/workspaceSwitcherPopup.js \
|
ui/workspaceSwitcherPopup.js \
|
||||||
ui/xdndHandler.js \
|
ui/xdndHandler.js
|
||||||
ui/components/__init__.js \
|
|
||||||
ui/components/autorunManager.js \
|
|
||||||
ui/components/automountManager.js \
|
|
||||||
ui/components/networkAgent.js \
|
|
||||||
ui/components/polkitAgent.js \
|
|
||||||
ui/components/recorder.js \
|
|
||||||
ui/components/telepathyClient.js \
|
|
||||||
ui/components/keyring.js \
|
|
||||||
$(NULL)
|
|
||||||
|
@ -21,16 +21,7 @@ const GnomeShellIface = <interface name="org.gnome.Shell.Extensions">
|
|||||||
</signal>
|
</signal>
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
const GnomeShellProxy = new Gio.DBusProxyClass({
|
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
|
||||||
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) {
|
function stripPrefix(string, prefix) {
|
||||||
if (string.slice(0, prefix.length) == prefix)
|
if (string.slice(0, prefix.length) == prefix)
|
||||||
@ -183,7 +174,7 @@ const Application = new Lang.Class({
|
|||||||
let renderer = new Gtk.CellRendererText();
|
let renderer = new Gtk.CellRendererText();
|
||||||
this._extensionSelector.pack_start(renderer, true);
|
this._extensionSelector.pack_start(renderer, true);
|
||||||
this._extensionSelector.add_attribute(renderer, 'text', 1);
|
this._extensionSelector.add_attribute(renderer, 'text', 1);
|
||||||
this._extensionSelector.set_cell_data_func(renderer, Lang.bind(this, this._setExtensionInsensitive));
|
this._extensionSelector.set_cell_data_func(renderer, Lang.bind(this, this._setExtensionInsensitive), null);
|
||||||
this._extensionSelector.connect('changed', Lang.bind(this, this._extensionSelected));
|
this._extensionSelector.connect('changed', Lang.bind(this, this._extensionSelected));
|
||||||
|
|
||||||
toolitem = new Gtk.ToolItem({ child: this._extensionSelector });
|
toolitem = new Gtk.ToolItem({ child: this._extensionSelector });
|
||||||
@ -200,8 +191,7 @@ const Application = new Lang.Class({
|
|||||||
|
|
||||||
this._extensionPrefsBin.add(label);
|
this._extensionPrefsBin.add(label);
|
||||||
|
|
||||||
this._shellProxy = new GnomeShellProxy();
|
this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
|
||||||
this._shellProxy.init(null);
|
|
||||||
this._shellProxy.connectSignal('ExtensionStatusChanged', Lang.bind(this, function(proxy, senderName, [uuid, state, error]) {
|
this._shellProxy.connectSignal('ExtensionStatusChanged', Lang.bind(this, function(proxy, senderName, [uuid, state, error]) {
|
||||||
if (ExtensionUtils.extensions[uuid] !== undefined)
|
if (ExtensionUtils.extensions[uuid] !== undefined)
|
||||||
this._scanExtensions();
|
this._scanExtensions();
|
||||||
|
22
js/gdm/consoleKit.js
Normal file
22
js/gdm/consoleKit.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
|
||||||
|
const ConsoleKitManagerIface = <interface name='org.freedesktop.ConsoleKit.Manager'>
|
||||||
|
<method name='CanRestart'>
|
||||||
|
<arg type='b' direction='out'/>
|
||||||
|
</method>
|
||||||
|
<method name='CanStop'>
|
||||||
|
<arg type='b' direction='out'/>
|
||||||
|
</method>
|
||||||
|
<method name='Restart' />
|
||||||
|
<method name='Stop' />
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
const ConsoleKitProxy = Gio.DBusProxy.makeProxyWrapper(ConsoleKitManagerIface);
|
||||||
|
|
||||||
|
function ConsoleKitManager() {
|
||||||
|
return new ConsoleKitProxy(Gio.DBus.system,
|
||||||
|
'org.freedesktop.ConsoleKit',
|
||||||
|
'/org/freedesktop/ConsoleKit/Manager');
|
||||||
|
};
|
@ -11,14 +11,17 @@ const FprintManagerIface = <interface name='net.reactivated.Fprint.Manager'>
|
|||||||
</method>
|
</method>
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
const FprintManager = new Gio.DBusProxyClass({
|
const FprintManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(FprintManagerIface);
|
||||||
Name: 'FprintManager',
|
|
||||||
Interface: FprintManagerIface,
|
|
||||||
|
|
||||||
_init: function() {
|
function FprintManager() {
|
||||||
this.parent({ g_bus_type: Gio.BusType.SYSTEM,
|
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.system,
|
||||||
g_name: 'net.reactivated.Fprint',
|
g_interface_name: FprintManagerInfo.name,
|
||||||
g_object_path: '/net/reactivated/Fprint/Manager',
|
g_interface_info: FprintManagerInfo,
|
||||||
g_flags: (Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
g_name: 'net.reactivated.Fprint',
|
||||||
}
|
g_object_path: '/net/reactivated/Fprint/Manager',
|
||||||
});
|
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
|
||||||
|
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
||||||
|
|
||||||
|
self.init(null);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
@ -25,7 +25,6 @@ const Gio = imports.gi.Gio;
|
|||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Meta = imports.gi.Meta;
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Pango = imports.gi.Pango;
|
const Pango = imports.gi.Pango;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
@ -39,14 +38,12 @@ const GdmUtil = imports.gdm.util;
|
|||||||
const Lightbox = imports.ui.lightbox;
|
const Lightbox = imports.ui.lightbox;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
const PanelMenu = imports.ui.panelMenu;
|
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
const UserMenu = imports.ui.userMenu;
|
|
||||||
|
|
||||||
const _RESIZE_ANIMATION_TIME = 0.25;
|
const _RESIZE_ANIMATION_TIME = 0.25;
|
||||||
const _SCROLL_ANIMATION_TIME = 0.5;
|
const _SCROLL_ANIMATION_TIME = 0.5;
|
||||||
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
|
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
|
||||||
const _LOGO_ICON_HEIGHT = 16;
|
const _LOGO_ICON_NAME_SIZE = 48;
|
||||||
|
|
||||||
let _loginDialog = null;
|
let _loginDialog = null;
|
||||||
|
|
||||||
@ -83,36 +80,6 @@ function _smoothlyResizeActor(actor, width, height) {
|
|||||||
return hold;
|
return hold;
|
||||||
}
|
}
|
||||||
|
|
||||||
const LogoMenuButton = new Lang.Class({
|
|
||||||
Name: 'LogoMenuButton',
|
|
||||||
Extends: PanelMenu.Button,
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this.parent(0.0, null, true);
|
|
||||||
|
|
||||||
this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
|
|
||||||
this._settings.connect('changed::' + GdmUtil.LOGO_KEY,
|
|
||||||
Lang.bind(this, this._updateLogo));
|
|
||||||
|
|
||||||
this._iconBin = new St.Bin();
|
|
||||||
this.actor.add_actor(this._iconBin);
|
|
||||||
|
|
||||||
this._updateLogo();
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateLogo: function() {
|
|
||||||
let path = this._settings.get_string(GdmUtil.LOGO_KEY);
|
|
||||||
let icon = null;
|
|
||||||
|
|
||||||
if (path) {
|
|
||||||
let file = Gio.file_new_for_path(path);
|
|
||||||
let cache = St.TextureCache.get_default();
|
|
||||||
icon = cache.load_uri_async(file.get_uri(), -1, _LOGO_ICON_HEIGHT);
|
|
||||||
}
|
|
||||||
this._iconBin.set_child(icon);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const UserListItem = new Lang.Class({
|
const UserListItem = new Lang.Class({
|
||||||
Name: 'UserListItem',
|
Name: 'UserListItem',
|
||||||
|
|
||||||
@ -129,15 +96,14 @@ const UserListItem = new Lang.Class({
|
|||||||
x_align: St.Align.START,
|
x_align: St.Align.START,
|
||||||
x_fill: true });
|
x_fill: true });
|
||||||
|
|
||||||
this._userAvatar = new UserMenu.UserAvatarWidget(this.user,
|
this._iconBin = new St.Bin();
|
||||||
{ styleClass: 'login-dialog-user-list-item-icon' });
|
layout.add(this._iconBin);
|
||||||
layout.add(this._userAvatar.actor);
|
|
||||||
let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
|
let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
layout.add(textLayout, { expand: true });
|
layout.add(textLayout, { expand: true });
|
||||||
|
|
||||||
this._nameLabel = new St.Label({ style_class: 'login-dialog-user-list-item-name' });
|
this._nameLabel = new St.Label({ text: this.user.get_real_name(),
|
||||||
this.actor.label_actor = this._nameLabel;
|
style_class: 'login-dialog-user-list-item-name' });
|
||||||
textLayout.add(this._nameLabel,
|
textLayout.add(this._nameLabel,
|
||||||
{ y_fill: false,
|
{ y_fill: false,
|
||||||
y_align: St.Align.MIDDLE,
|
y_align: St.Align.MIDDLE,
|
||||||
@ -151,16 +117,63 @@ const UserListItem = new Lang.Class({
|
|||||||
y_fill: false,
|
y_fill: false,
|
||||||
y_align: St.Align.END });
|
y_align: St.Align.END });
|
||||||
|
|
||||||
|
this._updateIcon();
|
||||||
|
this._updateLoggedIn();
|
||||||
|
|
||||||
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||||
this._onUserChanged();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onUserChanged: function() {
|
_onUserChanged: function() {
|
||||||
this._nameLabel.set_text(this.user.get_real_name());
|
this._nameLabel.set_text(this.user.get_real_name());
|
||||||
this._userAvatar.update();
|
this._updateIcon();
|
||||||
this._updateLoggedIn();
|
this._updateLoggedIn();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_setIconFromFile: function(iconFile, styleClass) {
|
||||||
|
if (styleClass)
|
||||||
|
this._iconBin.set_style_class_name(styleClass);
|
||||||
|
this._iconBin.set_style(null);
|
||||||
|
|
||||||
|
this._iconBin.child = null;
|
||||||
|
if (iconFile) {
|
||||||
|
this._iconBin.show();
|
||||||
|
// We use background-image instead of, say, St.TextureCache
|
||||||
|
// so the theme writers can add a rounded frame around the image
|
||||||
|
// and so theme writers can pick the icon size.
|
||||||
|
this._iconBin.set_style('background-image: url("' + iconFile + '");' +
|
||||||
|
'background-size: contain;');
|
||||||
|
} else {
|
||||||
|
this._iconBin.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_setIconFromName: function(iconName, styleClass) {
|
||||||
|
if (styleClass)
|
||||||
|
this._iconBin.set_style_class_name(styleClass);
|
||||||
|
this._iconBin.set_style(null);
|
||||||
|
|
||||||
|
if (iconName != null) {
|
||||||
|
let icon = new St.Icon();
|
||||||
|
icon.set_icon_name(iconName)
|
||||||
|
|
||||||
|
this._iconBin.child = icon;
|
||||||
|
this._iconBin.show();
|
||||||
|
} else {
|
||||||
|
this._iconBin.child = null;
|
||||||
|
this._iconBin.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateIcon: function() {
|
||||||
|
let iconFileName = this.user.get_icon_file();
|
||||||
|
let gicon = null;
|
||||||
|
|
||||||
|
if (GLib.file_test(iconFileName, GLib.FileTest.EXISTS))
|
||||||
|
this._setIconFromFile(iconFileName, 'login-dialog-user-list-item-icon');
|
||||||
|
else
|
||||||
|
this._setIconFromName('avatar-default', 'login-dialog-user-list-item-icon');
|
||||||
|
},
|
||||||
|
|
||||||
syncStyleClasses: function() {
|
syncStyleClasses: function() {
|
||||||
this._updateLoggedIn();
|
this._updateLoggedIn();
|
||||||
|
|
||||||
@ -181,6 +194,14 @@ const UserListItem = new Lang.Class({
|
|||||||
this.emit('activate');
|
this.emit('activate');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
fadeOutName: function() {
|
||||||
|
return GdmUtil.fadeOutActor(this._nameLabel);
|
||||||
|
},
|
||||||
|
|
||||||
|
fadeInName: function() {
|
||||||
|
return GdmUtil.fadeInActor(this._nameLabel);
|
||||||
|
},
|
||||||
|
|
||||||
showTimedLoginIndicator: function(time) {
|
showTimedLoginIndicator: function(time) {
|
||||||
let hold = new Batch.Hold();
|
let hold = new Batch.Hold();
|
||||||
|
|
||||||
@ -231,18 +252,16 @@ const UserList = new Lang.Class({
|
|||||||
if (global.stage.get_key_focus() != this.actor)
|
if (global.stage.get_key_focus() != this.actor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let focusSet = this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||||
if (!focusSet) {
|
|
||||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
|
||||||
this._moveFocusToItems();
|
|
||||||
return false;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_showItem: function(item) {
|
_showItem: function(item) {
|
||||||
let tasks = [function() {
|
let tasks = [function() {
|
||||||
return GdmUtil.fadeInActor(item.actor);
|
return GdmUtil.fadeInActor(item.actor);
|
||||||
|
},
|
||||||
|
|
||||||
|
function() {
|
||||||
|
return item.fadeInName();
|
||||||
}];
|
}];
|
||||||
|
|
||||||
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||||
@ -306,16 +325,13 @@ const UserList = new Lang.Class({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._box.remove_style_pseudo_class('expanded');
|
||||||
let batch = new Batch.ConsecutiveBatch(this,
|
let batch = new Batch.ConsecutiveBatch(this,
|
||||||
[function() {
|
[function() {
|
||||||
return GdmUtil.fadeOutActor(this.actor.vscroll);
|
return GdmUtil.fadeOutActor(this.actor.vscroll);
|
||||||
},
|
},
|
||||||
|
|
||||||
new Batch.ConcurrentBatch(this, tasks),
|
new Batch.ConcurrentBatch(this, tasks)
|
||||||
|
|
||||||
function() {
|
|
||||||
this._box.remove_style_pseudo_class('expanded');
|
|
||||||
}
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return batch.run();
|
return batch.run();
|
||||||
@ -365,6 +381,7 @@ const UserList = new Lang.Class({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._box.add_style_pseudo_class('expanded');
|
||||||
let batch = new Batch.ConsecutiveBatch(this,
|
let batch = new Batch.ConsecutiveBatch(this,
|
||||||
[function() {
|
[function() {
|
||||||
this.takeOverWhitespace();
|
this.takeOverWhitespace();
|
||||||
@ -375,10 +392,6 @@ const UserList = new Lang.Class({
|
|||||||
return _smoothlyResizeActor(this._box, -1, fullHeight);
|
return _smoothlyResizeActor(this._box, -1, fullHeight);
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
|
||||||
this._box.add_style_pseudo_class('expanded');
|
|
||||||
},
|
|
||||||
|
|
||||||
new Batch.ConcurrentBatch(this, tasks),
|
new Batch.ConcurrentBatch(this, tasks),
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
@ -504,7 +517,6 @@ const SessionListItem = new Lang.Class({
|
|||||||
|
|
||||||
let label = new St.Label({ style_class: 'login-dialog-session-list-item-label',
|
let label = new St.Label({ style_class: 'login-dialog-session-list-item-label',
|
||||||
text: name });
|
text: name });
|
||||||
this.actor.label_actor = label;
|
|
||||||
|
|
||||||
this._box.add_actor(label);
|
this._box.add_actor(label);
|
||||||
},
|
},
|
||||||
@ -659,8 +671,8 @@ const LoginDialog = new Lang.Class({
|
|||||||
_init: function(parentActor) {
|
_init: function(parentActor) {
|
||||||
this.parent({ shellReactive: true,
|
this.parent({ shellReactive: true,
|
||||||
styleClass: 'login-dialog',
|
styleClass: 'login-dialog',
|
||||||
parentActor: parentActor,
|
parentActor: parentActor
|
||||||
shouldFadeIn: false });
|
});
|
||||||
this.connect('destroy',
|
this.connect('destroy',
|
||||||
Lang.bind(this, this._onDestroy));
|
Lang.bind(this, this._onDestroy));
|
||||||
this.connect('opened',
|
this.connect('opened',
|
||||||
@ -669,32 +681,37 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._userManager = AccountsService.UserManager.get_default()
|
this._userManager = AccountsService.UserManager.get_default()
|
||||||
this._greeterClient = new Gdm.Client();
|
this._greeterClient = new Gdm.Client();
|
||||||
|
|
||||||
if (GLib.getenv('GDM_GREETER_TEST') != '1') {
|
this._greeter = this._greeterClient.get_greeter_sync(null);
|
||||||
this._greeter = this._greeterClient.get_greeter_sync(null);
|
|
||||||
|
|
||||||
this._greeter.connect('default-session-name-changed',
|
this._greeter.connect('default-session-name-changed',
|
||||||
Lang.bind(this, this._onDefaultSessionChanged));
|
Lang.bind(this, this._onDefaultSessionChanged));
|
||||||
|
|
||||||
this._greeter.connect('session-opened',
|
this._greeter.connect('session-opened',
|
||||||
Lang.bind(this, this._onSessionOpened));
|
Lang.bind(this, this._onSessionOpened));
|
||||||
this._greeter.connect('timed-login-requested',
|
this._greeter.connect('timed-login-requested',
|
||||||
Lang.bind(this, this._onTimedLoginRequested));
|
Lang.bind(this, this._onTimedLoginRequested));
|
||||||
}
|
|
||||||
|
|
||||||
this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient);
|
this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient);
|
||||||
this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion));
|
this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion));
|
||||||
this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage));
|
this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
|
||||||
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
||||||
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint));
|
|
||||||
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint));
|
this._userVerifier.connect('show-fingerprint-prompt', Lang.bind(this, this._showFingerprintPrompt));
|
||||||
|
this._userVerifier.connect('hide-fingerprint-prompt', Lang.bind(this, this._hideFingerprintPrompt));
|
||||||
|
|
||||||
this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
|
this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
|
||||||
|
|
||||||
|
this._settings.connect('changed::' + GdmUtil.LOGO_KEY,
|
||||||
|
Lang.bind(this, this._updateLogo));
|
||||||
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
|
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
|
||||||
Lang.bind(this, this._updateBanner));
|
Lang.bind(this, this._updateBanner));
|
||||||
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_TEXT_KEY,
|
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_TEXT_KEY,
|
||||||
Lang.bind(this, this._updateBanner));
|
Lang.bind(this, this._updateBanner));
|
||||||
|
|
||||||
|
this._logoBox = new St.Bin({ style_class: 'login-dialog-logo-box' });
|
||||||
|
this.contentLayout.add(this._logoBox);
|
||||||
|
this._updateLogo();
|
||||||
|
|
||||||
this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner',
|
this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner',
|
||||||
text: '' });
|
text: '' });
|
||||||
this.contentLayout.add(this._bannerLabel);
|
this.contentLayout.add(this._bannerLabel);
|
||||||
@ -707,23 +724,31 @@ const LoginDialog = new Lang.Class({
|
|||||||
{ y_fill: false,
|
{ y_fill: false,
|
||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
|
|
||||||
this._userList = new UserList();
|
let mainContentBox = new St.BoxLayout({ vertical: false });
|
||||||
this.contentLayout.add(this._userList.actor,
|
this.contentLayout.add(mainContentBox,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
x_fill: true,
|
x_fill: true,
|
||||||
y_fill: true });
|
y_fill: false });
|
||||||
|
|
||||||
|
this._userList = new UserList();
|
||||||
|
mainContentBox.add(this._userList.actor,
|
||||||
|
{ expand: true,
|
||||||
|
x_fill: true,
|
||||||
|
y_fill: true });
|
||||||
|
|
||||||
this.setInitialKeyFocus(this._userList.actor);
|
this.setInitialKeyFocus(this._userList.actor);
|
||||||
|
|
||||||
this._promptBox = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
|
this._promptBox = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
this.contentLayout.add(this._promptBox,
|
mainContentBox.add(this._promptBox,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
x_fill: true,
|
x_fill: true,
|
||||||
y_fill: true,
|
y_fill: true,
|
||||||
x_align: St.Align.START });
|
x_align: St.Align.START });
|
||||||
this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' });
|
this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' });
|
||||||
|
|
||||||
|
this._mainContentBox = mainContentBox;
|
||||||
|
|
||||||
this._promptBox.add(this._promptLabel,
|
this._promptBox.add(this._promptLabel,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
x_fill: true,
|
x_fill: true,
|
||||||
@ -736,13 +761,12 @@ const LoginDialog = new Lang.Class({
|
|||||||
x_fill: true,
|
x_fill: true,
|
||||||
y_fill: false,
|
y_fill: false,
|
||||||
x_align: St.Align.START });
|
x_align: St.Align.START });
|
||||||
|
// Translators: this message is shown below the password entry field
|
||||||
this._promptMessage = new St.Label({ visible: false });
|
// to indicate the user can swipe their finger instead
|
||||||
this._promptBox.add(this._promptMessage, { x_fill: true });
|
this._promptFingerprintMessage = new St.Label({ text: _("(or swipe finger)"),
|
||||||
|
style_class: 'login-dialog-prompt-fingerprint-message' });
|
||||||
this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' });
|
this._promptFingerprintMessage.hide();
|
||||||
this._promptLoginHint.hide();
|
this._promptBox.add(this._promptFingerprintMessage);
|
||||||
this._promptBox.add(this._promptLoginHint);
|
|
||||||
|
|
||||||
this._sessionList = new SessionList();
|
this._sessionList = new SessionList();
|
||||||
this._sessionList.connect('session-activated',
|
this._sessionList.connect('session-activated',
|
||||||
@ -795,6 +819,20 @@ const LoginDialog = new Lang.Class({
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_updateLogo: function() {
|
||||||
|
this._logoBox.child = null;
|
||||||
|
let path = this._settings.get_string(GdmUtil.LOGO_KEY);
|
||||||
|
|
||||||
|
if (path) {
|
||||||
|
let file = Gio.file_new_for_path(path);
|
||||||
|
let uri = file.get_uri();
|
||||||
|
|
||||||
|
let textureCache = St.TextureCache.get_default();
|
||||||
|
this._logoBox.child = textureCache.load_uri_async(uri, -1, _LOGO_ICON_NAME_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
_updateBanner: function() {
|
_updateBanner: function() {
|
||||||
let enabled = this._settings.get_boolean(GdmUtil.BANNER_MESSAGE_KEY);
|
let enabled = this._settings.get_boolean(GdmUtil.BANNER_MESSAGE_KEY);
|
||||||
let text = this._settings.get_string(GdmUtil.BANNER_MESSAGE_TEXT_KEY);
|
let text = this._settings.get_string(GdmUtil.BANNER_MESSAGE_TEXT_KEY);
|
||||||
@ -808,16 +846,15 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onReset: function(client, serviceName) {
|
_onReset: function(client, serviceName) {
|
||||||
this._promptMessage.hide();
|
|
||||||
|
|
||||||
let tasks = [this._hidePrompt,
|
let tasks = [this._hidePrompt,
|
||||||
|
|
||||||
new Batch.ConcurrentBatch(this, [this._fadeInTitleLabel,
|
new Batch.ConcurrentBatch(this, [this._fadeInTitleLabel,
|
||||||
this._fadeInNotListedButton]),
|
this._fadeInNotListedButton,
|
||||||
|
this._fadeInLogo]),
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
this._sessionList.close();
|
this._sessionList.close();
|
||||||
this._promptLoginHint.hide();
|
this._promptFingerprintMessage.hide();
|
||||||
this._userList.actor.show();
|
this._userList.actor.show();
|
||||||
this._userList.actor.opacity = 255;
|
this._userList.actor.opacity = 255;
|
||||||
return this._userList.showItems();
|
return this._userList.showItems();
|
||||||
@ -838,24 +875,12 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._sessionList.setActiveSession(sessionId);
|
this._sessionList.setActiveSession(sessionId);
|
||||||
},
|
},
|
||||||
|
|
||||||
_showMessage: function(userVerifier, message, styleClass) {
|
_showFingerprintPrompt: function() {
|
||||||
if (message) {
|
GdmUtil.fadeInActor(this._promptFingerprintMessage);
|
||||||
this._promptMessage.text = message;
|
|
||||||
this._promptMessage.styleClass = styleClass;
|
|
||||||
GdmUtil.fadeInActor(this._promptMessage);
|
|
||||||
} else {
|
|
||||||
GdmUtil.fadeOutActor(this._promptMessage);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_showLoginHint: function(verifier, message) {
|
_hideFingerprintPrompt: function() {
|
||||||
this._promptLoginHint.set_text(message)
|
GdmUtil.fadeOutActor(this._promptFingerprintMessage);
|
||||||
GdmUtil.fadeInActor(this._promptLoginHint);
|
|
||||||
},
|
|
||||||
|
|
||||||
_hideLoginHint: function() {
|
|
||||||
GdmUtil.fadeOutActor(this._promptLoginHint);
|
|
||||||
this._promptLoginHint.set_text('');
|
|
||||||
},
|
},
|
||||||
|
|
||||||
cancel: function() {
|
cancel: function() {
|
||||||
@ -874,8 +899,8 @@ const LoginDialog = new Lang.Class({
|
|||||||
function() {
|
function() {
|
||||||
// Show it with 0 opacity so we preallocate space for it
|
// Show it with 0 opacity so we preallocate space for it
|
||||||
// in the event we need to fade in the message
|
// in the event we need to fade in the message
|
||||||
this._promptLoginHint.opacity = 0;
|
this._promptFingerprintMessage.opacity = 0;
|
||||||
this._promptLoginHint.show();
|
this._promptFingerprintMessage.show();
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
@ -910,6 +935,15 @@ const LoginDialog = new Lang.Class({
|
|||||||
label: C_("button", "Sign In"),
|
label: C_("button", "Sign In"),
|
||||||
default: true }];
|
default: true }];
|
||||||
|
|
||||||
|
this._promptEntryActivateCallbackId = this._promptEntry.clutter_text.connect('activate',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
hold.release();
|
||||||
|
}));
|
||||||
|
hold.connect('release', Lang.bind(this, function() {
|
||||||
|
this._promptEntry.clutter_text.disconnect(this._promptEntryActivateCallbackId);
|
||||||
|
this._promptEntryActivateCallbackId = null;
|
||||||
|
}));
|
||||||
|
|
||||||
let tasks = [function() {
|
let tasks = [function() {
|
||||||
return this._fadeInPrompt();
|
return this._fadeInPrompt();
|
||||||
},
|
},
|
||||||
@ -926,6 +960,11 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_hidePrompt: function() {
|
_hidePrompt: function() {
|
||||||
|
if (this._promptEntryActivateCallbackId) {
|
||||||
|
this._promptEntry.clutter_text.disconnect(this._promptEntryActivateCallbackId);
|
||||||
|
this._promptEntryActivateCallbackId = null;
|
||||||
|
}
|
||||||
|
|
||||||
this.setButtons([]);
|
this.setButtons([]);
|
||||||
|
|
||||||
let tasks = [function() {
|
let tasks = [function() {
|
||||||
@ -933,8 +972,9 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
this._promptLoginHint.hide();
|
this._promptFingerprintMessage.hide();
|
||||||
this._promptEntry.reactive = true;
|
this._promptEntry.reactive = true;
|
||||||
|
this._promptEntry.remove_style_pseudo_class('insensitive');
|
||||||
this._promptEntry.set_text('');
|
this._promptEntry.set_text('');
|
||||||
}];
|
}];
|
||||||
|
|
||||||
@ -954,6 +994,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
function() {
|
function() {
|
||||||
let _text = this._promptEntry.get_text();
|
let _text = this._promptEntry.get_text();
|
||||||
this._promptEntry.reactive = false;
|
this._promptEntry.reactive = false;
|
||||||
|
this._promptEntry.add_style_pseudo_class('insensitive');
|
||||||
this._userVerifier.answerQuery(serviceName, _text);
|
this._userVerifier.answerQuery(serviceName, _text);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
@ -1089,7 +1130,11 @@ const LoginDialog = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_onNotListedClicked: function() {
|
_onVerificationFailed: function() {
|
||||||
|
this._userVerifier.cancel();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onNotListedClicked: function(user) {
|
||||||
let tasks = [function() {
|
let tasks = [function() {
|
||||||
return this._userList.hideItems();
|
return this._userList.hideItems();
|
||||||
},
|
},
|
||||||
@ -1103,7 +1148,8 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
new Batch.ConcurrentBatch(this, [this._fadeOutTitleLabel,
|
new Batch.ConcurrentBatch(this, [this._fadeOutTitleLabel,
|
||||||
this._fadeOutNotListedButton]),
|
this._fadeOutNotListedButton,
|
||||||
|
this._fadeOutLogo]),
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
let hold = new Batch.Hold();
|
let hold = new Batch.Hold();
|
||||||
@ -1116,6 +1162,14 @@ const LoginDialog = new Lang.Class({
|
|||||||
batch.run();
|
batch.run();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_fadeInLogo: function() {
|
||||||
|
return GdmUtil.fadeInActor(this._logoBox);
|
||||||
|
},
|
||||||
|
|
||||||
|
_fadeOutLogo: function() {
|
||||||
|
return GdmUtil.fadeOutActor(this._logoBox);
|
||||||
|
},
|
||||||
|
|
||||||
_fadeInBanner: function() {
|
_fadeInBanner: function() {
|
||||||
return GdmUtil.fadeInActor(this._bannerLabel);
|
return GdmUtil.fadeInActor(this._bannerLabel);
|
||||||
},
|
},
|
||||||
@ -1163,8 +1217,13 @@ const LoginDialog = new Lang.Class({
|
|||||||
return this._userList.giveUpWhitespace();
|
return this._userList.giveUpWhitespace();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
function() {
|
||||||
|
return activatedItem.fadeOutName();
|
||||||
|
},
|
||||||
|
|
||||||
new Batch.ConcurrentBatch(this, [this._fadeOutTitleLabel,
|
new Batch.ConcurrentBatch(this, [this._fadeOutTitleLabel,
|
||||||
this._fadeOutNotListedButton]),
|
this._fadeOutNotListedButton,
|
||||||
|
this._fadeOutLogo]),
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
return this._userList.shrinkToNaturalHeight();
|
return this._userList.shrinkToNaturalHeight();
|
||||||
@ -1217,7 +1276,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onOpened: function() {
|
_onOpened: function() {
|
||||||
Main.ctrlAltTabManager.addGroup(this.dialogLayout,
|
Main.ctrlAltTabManager.addGroup(this._mainContentBox,
|
||||||
_("Login Window"),
|
_("Login Window"),
|
||||||
'dialog-password',
|
'dialog-password',
|
||||||
{ sortGroup: CtrlAltTab.SortGroup.MIDDLE });
|
{ sortGroup: CtrlAltTab.SortGroup.MIDDLE });
|
||||||
|
@ -18,12 +18,12 @@
|
|||||||
* 02111-1307, USA.
|
* 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const Gio = imports.gi.Gio;
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
|
const UPowerGlib = imports.gi.UPowerGlib;
|
||||||
|
|
||||||
const LoginManager = imports.misc.loginManager;
|
const ConsoleKit = imports.gdm.consoleKit;
|
||||||
|
const Systemd = imports.gdm.systemd;
|
||||||
|
|
||||||
const GdmUtil = imports.gdm.util;
|
|
||||||
const PanelMenu = imports.ui.panelMenu;
|
const PanelMenu = imports.ui.panelMenu;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
|
|
||||||
@ -32,23 +32,20 @@ const PowerMenuButton = new Lang.Class({
|
|||||||
Extends: PanelMenu.SystemStatusButton,
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
/* Translators: accessible name of the power menu in the login screen */
|
this.parent('system-shutdown', null);
|
||||||
this.parent('system-shutdown-symbolic', _("Power"));
|
this._upClient = new UPowerGlib.Client();
|
||||||
|
|
||||||
LoginManager.getLoginManager(Lang.bind(this, function(manager) {
|
if (Systemd.haveSystemd())
|
||||||
this._loginManager = manager;
|
this._systemdLoginManager = new Systemd.SystemdLoginManager();
|
||||||
|
else
|
||||||
this._updateHaveShutdown();
|
this._consoleKitManager = new ConsoleKit.ConsoleKitManager();
|
||||||
this._updateHaveRestart();
|
|
||||||
this._updateHaveSuspend();
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
|
|
||||||
this._settings.connect('changed::disable-restart-buttons',
|
|
||||||
Lang.bind(this, this._updateVisibility));
|
|
||||||
|
|
||||||
this._createSubMenu();
|
this._createSubMenu();
|
||||||
|
|
||||||
|
this._upClient.connect('notify::can-suspend',
|
||||||
|
Lang.bind(this, this._updateHaveSuspend));
|
||||||
|
this._updateHaveSuspend();
|
||||||
|
|
||||||
// ConsoleKit doesn't send notifications when shutdown/reboot
|
// ConsoleKit doesn't send notifications when shutdown/reboot
|
||||||
// are disabled, so we update the menu item each time the menu opens
|
// are disabled, so we update the menu item each time the menu opens
|
||||||
this.menu.connect('open-state-changed', Lang.bind(this,
|
this.menu.connect('open-state-changed', Lang.bind(this,
|
||||||
@ -56,59 +53,75 @@ const PowerMenuButton = new Lang.Class({
|
|||||||
if (open) {
|
if (open) {
|
||||||
this._updateHaveShutdown();
|
this._updateHaveShutdown();
|
||||||
this._updateHaveRestart();
|
this._updateHaveRestart();
|
||||||
this._updateHaveSuspend();
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
this._updateHaveShutdown();
|
this._updateHaveShutdown();
|
||||||
this._updateHaveRestart();
|
this._updateHaveRestart();
|
||||||
this._updateHaveSuspend();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateVisibility: function() {
|
_updateVisibility: function() {
|
||||||
let shouldBeVisible = (this._haveSuspend || this._haveShutdown || this._haveRestart);
|
let shouldBeVisible = (this._haveSuspend || this._haveShutdown || this._haveRestart);
|
||||||
this.actor.visible = shouldBeVisible && !this._settings.get_boolean('disable-restart-buttons');
|
this.actor.visible = shouldBeVisible;
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateHaveShutdown: function() {
|
_updateHaveShutdown: function() {
|
||||||
if (!this._loginManager) {
|
|
||||||
this._haveShutdown = false;
|
|
||||||
this._powerOffItem.actor.visible = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._loginManager.canPowerOff(Lang.bind(this, function(result) {
|
if (Systemd.haveSystemd()) {
|
||||||
this._haveShutdown = result;
|
this._systemdLoginManager.CanPowerOffRemote(Lang.bind(this,
|
||||||
this._powerOffItem.actor.visible = this._haveShutdown;
|
function(result, error) {
|
||||||
this._updateVisibility();
|
if (!error)
|
||||||
}));
|
this._haveShutdown = result[0] != 'no';
|
||||||
|
else
|
||||||
|
this._haveShutdown = false;
|
||||||
|
|
||||||
|
this._powerOffItem.actor.visible = this._haveShutdown;
|
||||||
|
this._updateVisibility();
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
this._consoleKitManager.CanStopRemote(Lang.bind(this,
|
||||||
|
function(result, error) {
|
||||||
|
if (!error)
|
||||||
|
this._haveShutdown = result[0];
|
||||||
|
else
|
||||||
|
this._haveShutdown = false;
|
||||||
|
|
||||||
|
this._powerOffItem.actor.visible = this._haveShutdown;
|
||||||
|
this._updateVisibility();
|
||||||
|
}));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateHaveRestart: function() {
|
_updateHaveRestart: function() {
|
||||||
if (!this._loginManager) {
|
|
||||||
this._haveRestart = false;
|
|
||||||
this._restartItem.actor.visible = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._loginManager.canReboot(Lang.bind(this, function(result) {
|
if (Systemd.haveSystemd()) {
|
||||||
this._haveRestart = result;
|
this._systemdLoginManager.CanRebootRemote(Lang.bind(this,
|
||||||
this._restartItem.actor.visible = this._haveRestart;
|
function(result, error) {
|
||||||
this._updateVisibility();
|
if (!error)
|
||||||
}));
|
this._haveRestart = result[0] != 'no';
|
||||||
|
else
|
||||||
|
this._haveRestart = false;
|
||||||
|
|
||||||
|
this._restartItem.actor.visible = this._haveRestart;
|
||||||
|
this._updateVisibility();
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
this._consoleKitManager.CanRestartRemote(Lang.bind(this,
|
||||||
|
function(result, error) {
|
||||||
|
if (!error)
|
||||||
|
this._haveRestart = result[0];
|
||||||
|
else
|
||||||
|
this._haveRestart = false;
|
||||||
|
|
||||||
|
this._restartItem.actor.visible = this._haveRestart;
|
||||||
|
this._updateVisibility();
|
||||||
|
}));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateHaveSuspend: function() {
|
_updateHaveSuspend: function() {
|
||||||
if (!this._loginManager) {
|
this._haveSuspend = this._upClient.get_can_suspend();
|
||||||
this._haveSuspend = false;
|
this._suspendItem.actor.visible = this._haveSuspend;
|
||||||
this._suspendItem.actor.visible = false;
|
this._updateVisibility();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._loginManager.canSuspend(Lang.bind(this, function(result) {
|
|
||||||
this._haveSuspend = result;
|
|
||||||
this._suspendItem.actor.visible = this._haveSuspend;
|
|
||||||
this._updateVisibility();
|
|
||||||
}));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_createSubMenu: function() {
|
_createSubMenu: function() {
|
||||||
@ -131,23 +144,27 @@ const PowerMenuButton = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onActivateSuspend: function() {
|
_onActivateSuspend: function() {
|
||||||
if (!this._haveSuspend)
|
if (this._haveSuspend)
|
||||||
return;
|
this._upClient.suspend_sync(null);
|
||||||
|
|
||||||
this._loginManager.suspend();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onActivateRestart: function() {
|
_onActivateRestart: function() {
|
||||||
if (!this._haveRestart)
|
if (!this._haveRestart)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._loginManager.reboot();
|
if (Systemd.haveSystemd())
|
||||||
|
this._systemdLoginManager.RebootRemote(true);
|
||||||
|
else
|
||||||
|
this._consoleKitManager.RestartRemote();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onActivatePowerOff: function() {
|
_onActivatePowerOff: function() {
|
||||||
if (!this._haveShutdown)
|
if (!this._haveShutdown)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._loginManager.powerOff();
|
if (Systemd.haveSystemd())
|
||||||
|
this._systemdLoginManager.PowerOffRemote(true);
|
||||||
|
else
|
||||||
|
this._consoleKitManager.StopRemote();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
173
js/gdm/realmd.js
173
js/gdm/realmd.js
@ -1,173 +0,0 @@
|
|||||||
// -*- 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;
|
|
||||||
|
|
||||||
const ProviderIface = <interface name='org.freedesktop.realmd.Provider'>
|
|
||||||
<property name="Name" type="s" access="read"/>
|
|
||||||
<property name="Version" type="s" access="read"/>
|
|
||||||
<property name="Realms" type="ao" access="read"/>
|
|
||||||
<method name="Discover">
|
|
||||||
<arg name="string" type="s" direction="in"/>
|
|
||||||
<arg name="options" type="a{sv}" direction="in"/>
|
|
||||||
<arg name="relevance" type="i" direction="out"/>
|
|
||||||
<arg name="realm" type="ao" direction="out"/>
|
|
||||||
</method>
|
|
||||||
</interface>;
|
|
||||||
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">
|
|
||||||
<arg name="operation" type="s" direction="in"/>
|
|
||||||
</method>
|
|
||||||
<method name="Release" />
|
|
||||||
<method name="SetLocale">
|
|
||||||
<arg name="locale" type="s" direction="in"/>
|
|
||||||
</method>
|
|
||||||
<signal name="Diagnostics">
|
|
||||||
<arg name="data" type="s"/>
|
|
||||||
<arg name="operation" type="s"/>
|
|
||||||
</signal>
|
|
||||||
</interface>;
|
|
||||||
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"/>
|
|
||||||
<property name="Configured" type="s" access="read"/>
|
|
||||||
<property name="Details" type="a(ss)" access="read"/>
|
|
||||||
<property name="LoginFormats" type="as" access="read"/>
|
|
||||||
<property name="LoginPolicy" type="s" access="read"/>
|
|
||||||
<property name="PermittedLogins" type="as" access="read"/>
|
|
||||||
<property name="SupportedInterfaces" type="as" access="read"/>
|
|
||||||
<method name="ChangeLoginPolicy">
|
|
||||||
<arg name="login_policy" type="s" direction="in"/>
|
|
||||||
<arg name="permitted_add" type="as" direction="in"/>
|
|
||||||
<arg name="permitted_remove" type="as" direction="in"/>
|
|
||||||
<arg name="options" type="a{sv}" direction="in"/>
|
|
||||||
</method>
|
|
||||||
<method name="Deconfigure">
|
|
||||||
<arg name="options" type="a{sv}" direction="in"/>
|
|
||||||
</method>
|
|
||||||
</interface>;
|
|
||||||
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 = new Provider();
|
|
||||||
this._realms = {};
|
|
||||||
|
|
||||||
this._aggregateProvider.connect('g-properties-changed',
|
|
||||||
Lang.bind(this, function(proxy, properties) {
|
|
||||||
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() {
|
|
||||||
let realmPaths = this._aggregateProvider.Realms;
|
|
||||||
|
|
||||||
if (!realmPaths)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (let i = 0; i < realmPaths.length; i++) {
|
|
||||||
let realm = new Realm(realmPaths[i]);
|
|
||||||
realm.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, this._onRealmLoaded));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_reloadRealm: function(realm) {
|
|
||||||
if (!realm.Configured) {
|
|
||||||
if (this._realms[realm.get_object_path()])
|
|
||||||
delete this._realms[realm.get_object_path()];
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._realms[realm.get_object_path()] = realm;
|
|
||||||
|
|
||||||
this._updateLoginFormat();
|
|
||||||
},
|
|
||||||
|
|
||||||
_onRealmLoaded: function(realm, result) {
|
|
||||||
try {
|
|
||||||
realm.init_finish(result);
|
|
||||||
} catch(e) { return; }
|
|
||||||
|
|
||||||
this._reloadRealm(realm);
|
|
||||||
|
|
||||||
realm.connect('g-properties-changed',
|
|
||||||
Lang.bind(this, function(proxy, properties) {
|
|
||||||
if ('Configured' in properties.deep_unpack())
|
|
||||||
this._reloadRealm();
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateLoginFormat: function() {
|
|
||||||
let newLoginFormat;
|
|
||||||
|
|
||||||
for (let realmPath in this._realms) {
|
|
||||||
let realm = this._realms[realmPath];
|
|
||||||
if (realm.LoginFormats && realm.LoginFormats.length > 0) {
|
|
||||||
newLoginFormat = realm.LoginFormats[0];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._loginFormat != newLoginFormat) {
|
|
||||||
this._loginFormat = newLoginFormat;
|
|
||||||
this.emit('login-format-changed', newLoginFormat);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
get loginFormat() {
|
|
||||||
if (this._loginFormat !== undefined)
|
|
||||||
return this._loginFormat;
|
|
||||||
|
|
||||||
this._updateLoginFormat();
|
|
||||||
|
|
||||||
return this._loginFormat;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Signals.addSignalMethods(Manager.prototype)
|
|
31
js/gdm/systemd.js
Normal file
31
js/gdm/systemd.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
|
||||||
|
const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager'>
|
||||||
|
<method name='PowerOff'>
|
||||||
|
<arg type='b' direction='in'/>
|
||||||
|
</method>
|
||||||
|
<method name='Reboot'>
|
||||||
|
<arg type='b' direction='in'/>
|
||||||
|
</method>
|
||||||
|
<method name='CanPowerOff'>
|
||||||
|
<arg type='s' direction='out'/>
|
||||||
|
</method>
|
||||||
|
<method name='CanReboot'>
|
||||||
|
<arg type='s' direction='out'/>
|
||||||
|
</method>
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
const SystemdLoginManagerProxy = Gio.DBusProxy.makeProxyWrapper(SystemdLoginManagerIface);
|
||||||
|
|
||||||
|
function SystemdLoginManager() {
|
||||||
|
return new SystemdLoginManagerProxy(Gio.DBus.system,
|
||||||
|
'org.freedesktop.login1',
|
||||||
|
'/org/freedesktop/login1');
|
||||||
|
};
|
||||||
|
|
||||||
|
function haveSystemd() {
|
||||||
|
return GLib.access("/sys/fs/cgroup/systemd", 0) >= 0;
|
||||||
|
}
|
190
js/gdm/util.js
190
js/gdm/util.js
@ -2,12 +2,10 @@
|
|||||||
|
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
|
||||||
const Batch = imports.gdm.batch;
|
const Batch = imports.gdm.batch;
|
||||||
const Fprint = imports.gdm.fingerprint;
|
const Fprint = imports.gdm.fingerprint;
|
||||||
const Realmd = imports.gdm.realmd;
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
@ -20,7 +18,6 @@ const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
|||||||
const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
||||||
const BANNER_MESSAGE_KEY = 'banner-message-enable';
|
const BANNER_MESSAGE_KEY = 'banner-message-enable';
|
||||||
const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
|
const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
|
||||||
const ALLOWED_FAILURES_KEY = 'allowed-failures';
|
|
||||||
|
|
||||||
const LOGO_KEY = 'logo';
|
const LOGO_KEY = 'logo';
|
||||||
|
|
||||||
@ -81,21 +78,16 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
|
|
||||||
this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
|
this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
|
||||||
|
|
||||||
|
this._cancellable = new Gio.Cancellable();
|
||||||
|
|
||||||
this._fprintManager = new Fprint.FprintManager();
|
this._fprintManager = new Fprint.FprintManager();
|
||||||
this._fprintManager.init(null);
|
this._checkForFingerprintReader();
|
||||||
|
|
||||||
this._realmManager = new Realmd.Manager();
|
|
||||||
|
|
||||||
this._failCounter = 0;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
begin: function(userName, hold) {
|
begin: function(userName, hold) {
|
||||||
this._cancellable = new Gio.Cancellable();
|
|
||||||
this._hold = hold;
|
this._hold = hold;
|
||||||
this._userName = userName;
|
this._userName = userName;
|
||||||
|
|
||||||
this._checkForFingerprintReader();
|
|
||||||
|
|
||||||
if (userName) {
|
if (userName) {
|
||||||
// If possible, reauthenticate an already running session,
|
// If possible, reauthenticate an already running session,
|
||||||
// so any session specific credentials get updated appropriately
|
// so any session specific credentials get updated appropriately
|
||||||
@ -107,18 +99,14 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
cancel: function() {
|
cancel: function() {
|
||||||
if (this._cancellable)
|
this._cancellable.cancel();
|
||||||
this._cancellable.cancel();
|
|
||||||
|
|
||||||
if (this._userVerifier)
|
if (this._userVerifier)
|
||||||
this._userVerifier.call_cancel_sync(null);
|
this._userVerifier.call_cancel_sync(null);
|
||||||
},
|
},
|
||||||
|
|
||||||
clear: function() {
|
clear: function() {
|
||||||
if (this._cancellable) {
|
this._cancellable.cancel();
|
||||||
this._cancellable.cancel();
|
|
||||||
this._cancellable = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._userVerifier) {
|
if (this._userVerifier) {
|
||||||
this._userVerifier.run_dispose();
|
this._userVerifier.run_dispose();
|
||||||
@ -127,9 +115,6 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
answerQuery: function(serviceName, answer) {
|
answerQuery: function(serviceName, answer) {
|
||||||
// Clear any previous message
|
|
||||||
this.emit('show-message', null, null);
|
|
||||||
|
|
||||||
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
|
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -139,58 +124,41 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
if (!this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY))
|
if (!this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._fprintManager.GetDefaultDeviceRemote(this._cancellable, Lang.bind(this, function(manager, result) {
|
this._fprintManager.GetDefaultDeviceRemote(Gio.DBusCallFlags.NONE, this._cancellable, Lang.bind(this,
|
||||||
try {
|
function(device, error) {
|
||||||
let device = manager.GetDefaultDeviceFinish(result);
|
if (!error && device)
|
||||||
this._haveFingerprintReader = !!device;
|
this._haveFingerprintReader = true;
|
||||||
} catch(e) {
|
}));
|
||||||
this._haveFingerprintReader = false;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
_reportInitError: function(where, error) {
|
|
||||||
logError(error, where);
|
|
||||||
this._hold.release();
|
|
||||||
|
|
||||||
this.emit('show-message', _("Authentication error"), 'login-dialog-message-warning');
|
|
||||||
this._verificationFailed(false);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_reauthenticationChannelOpened: function(client, result) {
|
_reauthenticationChannelOpened: function(client, result) {
|
||||||
try {
|
try {
|
||||||
this._userVerifier = client.open_reauthentication_channel_finish(result);
|
this._userVerifier = client.open_reauthentication_channel_finish(result);
|
||||||
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
this._connectSignals();
|
||||||
return;
|
this._beginVerification();
|
||||||
} catch(e if e.matches(Gio.DBusError, Gio.DBusError.ACCESS_DENIED) &&
|
|
||||||
!this._reauthOnly) {
|
|
||||||
// Gdm emits org.freedesktop.DBus.Error.AccessDenied when there is
|
|
||||||
// no session to reauthenticate. Fall back to performing verification
|
|
||||||
// from this login session
|
|
||||||
client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot));
|
|
||||||
return;
|
|
||||||
} catch(e) {
|
|
||||||
this._reportInitError('Failed to open reauthentication channel', e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._connectSignals();
|
this._hold.release();
|
||||||
this._beginVerification();
|
} catch (e) {
|
||||||
this._hold.release();
|
if (this._reauthOnly) {
|
||||||
|
logError(e, 'Failed to open reauthentication channel');
|
||||||
|
|
||||||
|
this._hold.release();
|
||||||
|
this.emit('verification-failed');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's no session running, or it otherwise fails, then fall back
|
||||||
|
// to performing verification from this login session
|
||||||
|
client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_userVerifierGot: function(client, result) {
|
_userVerifierGot: function(client, result) {
|
||||||
try {
|
this._userVerifier = client.get_user_verifier_finish(result);
|
||||||
this._userVerifier = client.get_user_verifier_finish(result);
|
|
||||||
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
|
||||||
return;
|
|
||||||
} catch(e) {
|
|
||||||
this._reportInitError('Failed to obtain user verifier', e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._connectSignals();
|
this._connectSignals();
|
||||||
this._beginVerification();
|
this._beginVerification();
|
||||||
|
|
||||||
this._hold.release();
|
this._hold.release();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -212,15 +180,7 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
this._userName,
|
this._userName,
|
||||||
this._cancellable,
|
this._cancellable,
|
||||||
Lang.bind(this, function(obj, result) {
|
Lang.bind(this, function(obj, result) {
|
||||||
try {
|
obj.call_begin_verification_for_user_finish(result);
|
||||||
obj.call_begin_verification_for_user_finish(result);
|
|
||||||
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
|
||||||
return;
|
|
||||||
} catch(e) {
|
|
||||||
this._reportInitError('Failed to start verification for user', e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._hold.release();
|
this._hold.release();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -231,15 +191,7 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
this._userName,
|
this._userName,
|
||||||
this._cancellable,
|
this._cancellable,
|
||||||
Lang.bind(this, function(obj, result) {
|
Lang.bind(this, function(obj, result) {
|
||||||
try {
|
obj.call_begin_verification_for_user_finish(result);
|
||||||
obj.call_begin_verification_for_user_finish(result);
|
|
||||||
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
|
||||||
return;
|
|
||||||
} catch(e) {
|
|
||||||
this._reportInitError('Failed to start fingerprint verification for user', e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._hold.release();
|
this._hold.release();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -247,15 +199,7 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
this._userVerifier.call_begin_verification(PASSWORD_SERVICE_NAME,
|
this._userVerifier.call_begin_verification(PASSWORD_SERVICE_NAME,
|
||||||
this._cancellable,
|
this._cancellable,
|
||||||
Lang.bind(this, function(obj, result) {
|
Lang.bind(this, function(obj, result) {
|
||||||
try {
|
obj.call_begin_verification_finish(result);
|
||||||
obj.call_begin_verification_finish(result);
|
|
||||||
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
|
||||||
return;
|
|
||||||
} catch(e) {
|
|
||||||
this._reportInitError('Failed to start verification', e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._hold.release();
|
this._hold.release();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -267,12 +211,9 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
// as a cue to display our own message.
|
// as a cue to display our own message.
|
||||||
if (serviceName == FINGERPRINT_SERVICE_NAME &&
|
if (serviceName == FINGERPRINT_SERVICE_NAME &&
|
||||||
this._haveFingerprintReader) {
|
this._haveFingerprintReader) {
|
||||||
|
this.emit('show-fingerprint-prompt');
|
||||||
// Translators: this message is shown below the password entry field
|
|
||||||
// to indicate the user can swipe their finger instead
|
|
||||||
this.emit('show-login-hint', _("(or swipe finger)"));
|
|
||||||
} else if (serviceName == PASSWORD_SERVICE_NAME) {
|
} else if (serviceName == PASSWORD_SERVICE_NAME) {
|
||||||
this.emit('show-message', info, 'login-dialog-message-info');
|
Main.notifyError(info);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -281,22 +222,7 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
// users who haven't enrolled their fingerprint.
|
// users who haven't enrolled their fingerprint.
|
||||||
if (serviceName != PASSWORD_SERVICE_NAME)
|
if (serviceName != PASSWORD_SERVICE_NAME)
|
||||||
return;
|
return;
|
||||||
this.emit('show-message', problem, 'login-dialog-message-warning');
|
Main.notifyError(problem);
|
||||||
},
|
|
||||||
|
|
||||||
_showRealmLoginHint: function() {
|
|
||||||
if (this._realmManager.loginFormat) {
|
|
||||||
let hint = this._realmManager.loginFormat;
|
|
||||||
|
|
||||||
hint = hint.replace(/%U/g, 'user');
|
|
||||||
hint = hint.replace(/%D/g, 'DOMAIN');
|
|
||||||
hint = hint.replace(/%[^UD]/g, '');
|
|
||||||
|
|
||||||
// Translators: this message is shown below the username entry field
|
|
||||||
// to clue the user in on how to login to the local network realm
|
|
||||||
this.emit('show-login-hint',
|
|
||||||
_("(e.g., user or %s)").format(hint));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onInfoQuery: function(client, serviceName, question) {
|
_onInfoQuery: function(client, serviceName, question) {
|
||||||
@ -304,10 +230,6 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
if (serviceName != PASSWORD_SERVICE_NAME)
|
if (serviceName != PASSWORD_SERVICE_NAME)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._showRealmLoginHint();
|
|
||||||
this._realmLoginHintSignalId = this._realmManager.connect('login-format-changed',
|
|
||||||
Lang.bind(this, this._showRealmLoginHint));
|
|
||||||
|
|
||||||
this.emit('ask-question', serviceName, question, '');
|
this.emit('ask-question', serviceName, question, '');
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -320,10 +242,10 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onReset: function() {
|
_onReset: function() {
|
||||||
this.clear();
|
this._userVerifier.run_dispose();
|
||||||
|
this._userVerifier = null;
|
||||||
|
|
||||||
// Clear previous attempts to authenticate
|
this._checkForFingerprintReader();
|
||||||
this._failCounter = 0;
|
|
||||||
|
|
||||||
this.emit('reset');
|
this.emit('reset');
|
||||||
},
|
},
|
||||||
@ -332,44 +254,14 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
this.emit('verification-complete');
|
this.emit('verification-complete');
|
||||||
},
|
},
|
||||||
|
|
||||||
_verificationFailed: function(retry) {
|
|
||||||
// For Not Listed / enterprise logins, immediately reset
|
|
||||||
// the dialog
|
|
||||||
// Otherwise, we allow ALLOWED_FAILURES attempts. After that, we
|
|
||||||
// go back to the welcome screen.
|
|
||||||
|
|
||||||
this._failCounter++;
|
|
||||||
let canRetry = retry && this._userName &&
|
|
||||||
this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY);
|
|
||||||
|
|
||||||
if (canRetry) {
|
|
||||||
this.clear();
|
|
||||||
this.begin(this._userName, new Batch.Hold());
|
|
||||||
} else {
|
|
||||||
// Allow some time to see the message, then reset everything
|
|
||||||
Mainloop.timeout_add(3000, Lang.bind(this, function() {
|
|
||||||
this.cancel();
|
|
||||||
|
|
||||||
this._onReset();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emit('verification-failed');
|
|
||||||
},
|
|
||||||
|
|
||||||
_onConversationStopped: function(client, serviceName) {
|
_onConversationStopped: function(client, serviceName) {
|
||||||
// if the password service fails, then cancel everything.
|
// if the password service fails, then cancel everything.
|
||||||
// But if, e.g., fingerprint fails, still give
|
// But if, e.g., fingerprint fails, still give
|
||||||
// password authentication a chance to succeed
|
// password authentication a chance to succeed
|
||||||
if (serviceName == PASSWORD_SERVICE_NAME) {
|
if (serviceName == PASSWORD_SERVICE_NAME) {
|
||||||
this._verificationFailed(true);
|
this.emit('verification-failed');
|
||||||
}
|
} else if (serviceName == FINGERPRINT_SERVICE_NAME) {
|
||||||
|
this.emit('hide-fingerprint-prompt');
|
||||||
this.emit('hide-login-hint');
|
|
||||||
|
|
||||||
if (this._realmLoginHintSignalId) {
|
|
||||||
this._realmManager.disconnect(this._realmLoginHintSignalId);
|
|
||||||
this._realmLoginHintSignalId = 0;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -120,6 +120,11 @@ function createExtensionObject(uuid, dir, type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Encourage people to add this
|
||||||
|
if (!meta.url) {
|
||||||
|
log('Warning: Missing "url" property in %s/metadata.json'.format(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
if (uuid != meta.uuid) {
|
if (uuid != meta.uuid) {
|
||||||
throw new Error('uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"');
|
throw new Error('uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"');
|
||||||
}
|
}
|
||||||
@ -156,8 +161,7 @@ const ExtensionFinder = new Lang.Class({
|
|||||||
try {
|
try {
|
||||||
fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
|
fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
if (e.domain != Gio.io_error_quark() || e.code != Gio.IOErrorEnum.NOT_FOUND)
|
logError(e, 'Could not enumerate extensions directory');
|
||||||
logError(e, 'Could not enumerate extensions directory');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,16 +21,11 @@ const PresenceStatus = {
|
|||||||
IDLE: 3
|
IDLE: 3
|
||||||
};
|
};
|
||||||
|
|
||||||
const Presence = new Gio.DBusProxyClass({
|
var PresenceProxy = Gio.DBusProxy.makeProxyWrapper(PresenceIface);
|
||||||
Name: 'GnomeSessionPresence',
|
function Presence(initCallback, cancellable) {
|
||||||
Interface: PresenceIface,
|
return new PresenceProxy(Gio.DBus.session, 'org.gnome.SessionManager',
|
||||||
|
'/org/gnome/SessionManager/Presence', initCallback, cancellable);
|
||||||
_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
|
// Note inhibitors are immutable objects, so they don't
|
||||||
// change at runtime (changes always come in the form
|
// change at runtime (changes always come in the form
|
||||||
@ -44,16 +39,10 @@ const InhibitorIface = <interface name="org.gnome.SessionManager.Inhibitor">
|
|||||||
</method>
|
</method>
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
const Inhibitor = new Gio.DBusProxyClass({
|
var InhibitorProxy = Gio.DBusProxy.makeProxyWrapper(InhibitorIface);
|
||||||
Name: 'GnomeSessionInhibitor',
|
function Inhibitor(objectPath, initCallback, cancellable) {
|
||||||
Interface: InhibitorIface,
|
return new InhibitorProxy(Gio.DBus.session, 'org.gnome.SessionManager', objectPath, initCallback, cancellable);
|
||||||
|
}
|
||||||
_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
|
// Not the full interface, only the methods we use
|
||||||
const SessionManagerIface = <interface name="org.gnome.SessionManager">
|
const SessionManagerIface = <interface name="org.gnome.SessionManager">
|
||||||
@ -77,14 +66,7 @@ const SessionManagerIface = <interface name="org.gnome.SessionManager">
|
|||||||
</signal>
|
</signal>
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
const SessionManager = new Gio.DBusProxyClass({
|
var SessionManagerProxy = Gio.DBusProxy.makeProxyWrapper(SessionManagerIface);
|
||||||
Name: 'GnomeSessionManager',
|
function SessionManager(initCallback, cancellable) {
|
||||||
Interface: SessionManagerIface,
|
return new SessionManagerProxy(Gio.DBus.session, 'org.gnome.SessionManager', '/org/gnome/SessionManager', initCallback, cancellable);
|
||||||
|
}
|
||||||
_init: function() {
|
|
||||||
this.parent({ g_bus_type: Gio.BusType.SESSION,
|
|
||||||
g_name: 'org.gnome.SessionManager',
|
|
||||||
g_object_path: '/org/gnome/SessionManager' });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
|
@ -41,26 +41,24 @@ const HistoryManager = new Lang.Class({
|
|||||||
this._historyIndex = this._history.length;
|
this._historyIndex = this._history.length;
|
||||||
},
|
},
|
||||||
|
|
||||||
_setPrevItem: function(text) {
|
prevItem: function(text) {
|
||||||
if (this._historyIndex <= 0)
|
if (this._historyIndex <= 0)
|
||||||
return false;
|
return text;
|
||||||
|
|
||||||
if (text)
|
if (text)
|
||||||
this._history[this._historyIndex] = text;
|
this._history[this._historyIndex] = text;
|
||||||
this._historyIndex--;
|
this._historyIndex--;
|
||||||
this._indexChanged();
|
return this._indexChanged();
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_setNextItem: function(text) {
|
nextItem: function(text) {
|
||||||
if (this._historyIndex >= this._history.length)
|
if (this._historyIndex >= this._history.length)
|
||||||
return false;
|
return text;
|
||||||
|
|
||||||
if (text)
|
if (text)
|
||||||
this._history[this._historyIndex] = text;
|
this._history[this._historyIndex] = text;
|
||||||
this._historyIndex++;
|
this._historyIndex++;
|
||||||
this._indexChanged();
|
return this._indexChanged();
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
lastItem: function() {
|
lastItem: function() {
|
||||||
@ -85,9 +83,11 @@ const HistoryManager = new Lang.Class({
|
|||||||
_onEntryKeyPress: function(entry, event) {
|
_onEntryKeyPress: function(entry, event) {
|
||||||
let symbol = event.get_key_symbol();
|
let symbol = event.get_key_symbol();
|
||||||
if (symbol == Clutter.KEY_Up) {
|
if (symbol == Clutter.KEY_Up) {
|
||||||
return this._setPrevItem(entry.get_text());
|
this.prevItem(entry.get_text());
|
||||||
|
return true;
|
||||||
} else if (symbol == Clutter.KEY_Down) {
|
} else if (symbol == Clutter.KEY_Down) {
|
||||||
return this._setNextItem(entry.get_text());
|
this.nextItem(entry.get_text());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
@ -98,6 +98,8 @@ const HistoryManager = new Lang.Class({
|
|||||||
|
|
||||||
if (this._entry)
|
if (this._entry)
|
||||||
this._entry.set_text(current);
|
this._entry.set_text(current);
|
||||||
|
|
||||||
|
return current;
|
||||||
},
|
},
|
||||||
|
|
||||||
_save: function() {
|
_save: function() {
|
||||||
|
@ -1,391 +0,0 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
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;
|
|
||||||
const UPowerGlib = imports.gi.UPowerGlib;
|
|
||||||
|
|
||||||
const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager'>
|
|
||||||
<method name='PowerOff'>
|
|
||||||
<arg type='b' direction='in'/>
|
|
||||||
</method>
|
|
||||||
<method name='Reboot'>
|
|
||||||
<arg type='b' direction='in'/>
|
|
||||||
</method>
|
|
||||||
<method name='Suspend'>
|
|
||||||
<arg type='b' direction='in'/>
|
|
||||||
</method>
|
|
||||||
<method name='CanPowerOff'>
|
|
||||||
<arg type='s' direction='out'/>
|
|
||||||
</method>
|
|
||||||
<method name='CanReboot'>
|
|
||||||
<arg type='s' direction='out'/>
|
|
||||||
</method>
|
|
||||||
<method name='CanSuspend'>
|
|
||||||
<arg type='s' direction='out'/>
|
|
||||||
</method>
|
|
||||||
</interface>;
|
|
||||||
|
|
||||||
const SystemdLoginSessionIface = <interface name='org.freedesktop.login1.Session'>
|
|
||||||
<signal name='Lock' />
|
|
||||||
<signal name='Unlock' />
|
|
||||||
</interface>;
|
|
||||||
|
|
||||||
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'>
|
|
||||||
<arg type='b' direction='out'/>
|
|
||||||
</method>
|
|
||||||
<method name='CanStop'>
|
|
||||||
<arg type='b' direction='out'/>
|
|
||||||
</method>
|
|
||||||
<method name='Restart' />
|
|
||||||
<method name='Stop' />
|
|
||||||
<method name='GetCurrentSession'>
|
|
||||||
<arg type='o' direction='out' />
|
|
||||||
</method>
|
|
||||||
</interface>;
|
|
||||||
|
|
||||||
const ConsoleKitSessionIface = <interface name='org.freedesktop.ConsoleKit.Session'>
|
|
||||||
<method name='IsActive'>
|
|
||||||
<arg type='b' direction='out' />
|
|
||||||
</method>
|
|
||||||
<signal name='ActiveChanged'>
|
|
||||||
<arg type='b' direction='out' />
|
|
||||||
</signal>
|
|
||||||
<signal name='Lock' />
|
|
||||||
<signal name='Unlock' />
|
|
||||||
</interface>;
|
|
||||||
|
|
||||||
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(asyncCallback) {
|
|
||||||
if (_loginManager == null) {
|
|
||||||
if (_pendingAsyncCallbacks.length == 0) {
|
|
||||||
let manager;
|
|
||||||
|
|
||||||
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.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() {
|
|
||||||
return this._currentSession;
|
|
||||||
},
|
|
||||||
|
|
||||||
get sessionActive() {
|
|
||||||
return Shell.session_is_active_for_systemd();
|
|
||||||
},
|
|
||||||
|
|
||||||
canPowerOff: function(asyncCallback) {
|
|
||||||
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(null, function(proxy, result) {
|
|
||||||
let val = false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
val = proxy.CanRebootFinish(result)[0] != 'no';
|
|
||||||
} catch(e) { }
|
|
||||||
|
|
||||||
asyncCallback(val);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
canSuspend: function(asyncCallback) {
|
|
||||||
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, null, null);
|
|
||||||
},
|
|
||||||
|
|
||||||
reboot: function() {
|
|
||||||
this._proxy.RebootRemote(true, null, null);
|
|
||||||
},
|
|
||||||
|
|
||||||
suspend: function() {
|
|
||||||
this._proxy.SuspendRemote(true, null, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const LoginManagerConsoleKit = new Lang.Class({
|
|
||||||
Name: 'LoginManagerConsoleKit',
|
|
||||||
Extends: GObject.Object,
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
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() {
|
|
||||||
return this._currentSession;
|
|
||||||
},
|
|
||||||
|
|
||||||
get sessionActive() {
|
|
||||||
if (this._sessionActive !== undefined)
|
|
||||||
return this._sessionActive;
|
|
||||||
|
|
||||||
let session = this.getCurrentSessionProxy();
|
|
||||||
session.connectSignal('ActiveChanged', Lang.bind(this, function(object, senderName, [isActive]) {
|
|
||||||
this._sessionActive = isActive;
|
|
||||||
}));
|
|
||||||
[this._sessionActive] = session.IsActiveSync(null);
|
|
||||||
|
|
||||||
return this._sessionActive;
|
|
||||||
},
|
|
||||||
|
|
||||||
canPowerOff: function(asyncCallback) {
|
|
||||||
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(null, function(proxy, result) {
|
|
||||||
let val = false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
[val] = proxy.CanRestartFinish(result);
|
|
||||||
} catch(e) { }
|
|
||||||
|
|
||||||
asyncCallback(val);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
canSuspend: function(asyncCallback) {
|
|
||||||
Mainloop.idle_add(Lang.bind(this, function() {
|
|
||||||
asyncCallback(this._upClient.get_can_suspend());
|
|
||||||
return false;
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
powerOff: function() {
|
|
||||||
this._proxy.StopRemote(null, null);
|
|
||||||
},
|
|
||||||
|
|
||||||
reboot: function() {
|
|
||||||
this._proxy.RestartRemote(null, null);
|
|
||||||
},
|
|
||||||
|
|
||||||
suspend: function() {
|
|
||||||
this._upClient.suspend_sync(null);
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,7 +1,6 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
@ -27,16 +26,7 @@ const ModemGsmNetworkInterface = <interface name="org.freedesktop.ModemManager.M
|
|||||||
</signal>
|
</signal>
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
const ModemGsmNetworkProxy = new Gio.DBusProxyClass({
|
const ModemGsmNetworkProxy = Gio.DBusProxy.makeProxyWrapper(ModemGsmNetworkInterface);
|
||||||
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">
|
const ModemCdmaInterface = <interface name="org.freedesktop.ModemManager.Modem.Cdma">
|
||||||
<method name="GetSignalQuality">
|
<method name="GetSignalQuality">
|
||||||
@ -50,16 +40,7 @@ const ModemCdmaInterface = <interface name="org.freedesktop.ModemManager.Modem.C
|
|||||||
</signal>
|
</signal>
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
const ModemCdmaProxy = new Gio.DBusProxyClass({
|
const ModemCdmaProxy = Gio.DBusProxy.makeProxyWrapper(ModemCdmaInterface);
|
||||||
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;
|
let _providersTable;
|
||||||
function _getProvidersTable() {
|
function _getProvidersTable() {
|
||||||
@ -73,18 +54,11 @@ const ModemGsm = new Lang.Class({
|
|||||||
Name: 'ModemGsm',
|
Name: 'ModemGsm',
|
||||||
|
|
||||||
_init: function(path) {
|
_init: function(path) {
|
||||||
this._proxy = new ModemGsmNetworkProxy(path);
|
this._proxy = new ModemGsmNetworkProxy(Gio.DBus.system, 'org.freedesktop.ModemManager', 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.signal_quality = 0;
|
||||||
this.operator_name = null;
|
this.operator_name = null;
|
||||||
},
|
|
||||||
|
|
||||||
_finishInit: function() {
|
|
||||||
// Code is duplicated because the function have different signatures
|
// Code is duplicated because the function have different signatures
|
||||||
this._proxy.connectSignal('SignalQuality', Lang.bind(this, function(proxy, sender, [quality]) {
|
this._proxy.connectSignal('SignalQuality', Lang.bind(this, function(proxy, sender, [quality]) {
|
||||||
this.signal_quality = quality;
|
this.signal_quality = quality;
|
||||||
@ -94,19 +68,24 @@ const ModemGsm = new Lang.Class({
|
|||||||
this.operator_name = this._findOperatorName(name, code);
|
this.operator_name = this._findOperatorName(name, code);
|
||||||
this.emit('notify::operator-name');
|
this.emit('notify::operator-name');
|
||||||
}));
|
}));
|
||||||
this._proxy.GetRegistrationInfoRemote(null, Lang.bind(this, function(proxy, result) {
|
this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function([result], err) {
|
||||||
let [status, code, name] = proxy.GetRegistrationInfoFinish(result);
|
if (err) {
|
||||||
|
log(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let [status, code, name] = result;
|
||||||
this.operator_name = this._findOperatorName(name, code);
|
this.operator_name = this._findOperatorName(name, code);
|
||||||
this.emit('notify::operator-name');
|
this.emit('notify::operator-name');
|
||||||
}));
|
}));
|
||||||
this._proxy.GetSignalQualityRemote(null, Lang.bind(this, function(proxy, result) {
|
this._proxy.GetSignalQualityRemote(Lang.bind(this, function(result, err) {
|
||||||
try {
|
if (err) {
|
||||||
[this.signal_quality] = proxy.GetSignalQualityFinish(result);
|
|
||||||
} catch(e) {
|
|
||||||
// it will return an error if the device is not connected
|
// it will return an error if the device is not connected
|
||||||
this.signal_quality = 0;
|
this.signal_quality = 0;
|
||||||
|
} else {
|
||||||
|
let [quality] = result;
|
||||||
|
this.signal_quality = quality;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit('notify::signal-quality');
|
this.emit('notify::signal-quality');
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
@ -178,18 +157,10 @@ const ModemCdma = new Lang.Class({
|
|||||||
Name: 'ModemCdma',
|
Name: 'ModemCdma',
|
||||||
|
|
||||||
_init: function(path) {
|
_init: function(path) {
|
||||||
this._proxy = new ModemCdmaProxy(path);
|
this._proxy = new ModemCdmaProxy(Gio.DBus.system, 'org.freedesktop.ModemManager', 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.signal_quality = 0;
|
||||||
this.operator_name = null;
|
this.operator_name = null;
|
||||||
},
|
|
||||||
|
|
||||||
_finishInit: function() {
|
|
||||||
this._proxy.connectSignal('SignalQuality', Lang.bind(this, function(proxy, sender, params) {
|
this._proxy.connectSignal('SignalQuality', Lang.bind(this, function(proxy, sender, params) {
|
||||||
this.signal_quality = params[0];
|
this.signal_quality = params[0];
|
||||||
this.emit('notify::signal-quality');
|
this.emit('notify::signal-quality');
|
||||||
@ -199,31 +170,30 @@ const ModemCdma = new Lang.Class({
|
|||||||
if (this.operator_name == null)
|
if (this.operator_name == null)
|
||||||
this._refreshServingSystem();
|
this._refreshServingSystem();
|
||||||
}));
|
}));
|
||||||
this._proxy.GetSignalQualityRemote(null, Lang.bind(this, function(proxy, result) {
|
this._proxy.GetSignalQualityRemote(Lang.bind(this, function(result, err) {
|
||||||
try {
|
if (err) {
|
||||||
[this.signal_quality] = proxy.GetSignalQualityFinish(result);
|
|
||||||
} catch(e) {
|
|
||||||
// it will return an error if the device is not connected
|
// it will return an error if the device is not connected
|
||||||
this.signal_quality = 0;
|
this.signal_quality = 0;
|
||||||
|
} else {
|
||||||
|
let [quality] = result;
|
||||||
|
this.signal_quality = quality;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit('notify::signal-quality');
|
this.emit('notify::signal-quality');
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_refreshServingSystem: function() {
|
_refreshServingSystem: function() {
|
||||||
this._proxy.GetServingSystemRemote(null, Lang.bind(this, function(proxy, result) {
|
this._proxy.GetServingSystemRemote(Lang.bind(this, function([result], err) {
|
||||||
try {
|
if (err) {
|
||||||
let [bandClass, band, name] = proxy.GetServingSystemFinish(result);
|
|
||||||
if (name.length > 0)
|
|
||||||
this.operator_name = this._findProviderForSid(name);
|
|
||||||
else
|
|
||||||
this.operator_name = null;
|
|
||||||
} catch(e) {
|
|
||||||
// it will return an error if the device is not connected
|
// it will return an error if the device is not connected
|
||||||
this.operator_name = null;
|
this.operator_name = null;
|
||||||
|
} else {
|
||||||
|
let [bandClass, band, id] = result;
|
||||||
|
if (name.length > 0)
|
||||||
|
this.operator_name = this._findProviderForSid(id);
|
||||||
|
else
|
||||||
|
this.operator_name = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit('notify::operator-name');
|
this.emit('notify::operator-name');
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
@ -84,7 +84,7 @@ function trySpawn(argv)
|
|||||||
try {
|
try {
|
||||||
[success, pid] = GLib.spawn_async(null, argv, null,
|
[success, pid] = GLib.spawn_async(null, argv, null,
|
||||||
GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
|
GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
|
||||||
null);
|
null, null);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
/* Rewrite the error in case of ENOENT */
|
/* Rewrite the error in case of ENOENT */
|
||||||
if (err.matches(GLib.SpawnError, GLib.SpawnError.NOENT)) {
|
if (err.matches(GLib.SpawnError, GLib.SpawnError.NOENT)) {
|
||||||
|
@ -115,10 +115,10 @@ function run() {
|
|||||||
|
|
||||||
for (let i = 0; i < 2; i++) {
|
for (let i = 0; i < 2; i++) {
|
||||||
Scripting.scriptEvent('applicationsShowStart');
|
Scripting.scriptEvent('applicationsShowStart');
|
||||||
Main.overview._dash.showAppsButton.checked = true;
|
Main.overview._viewSelector.switchTab('applications');
|
||||||
yield Scripting.waitLeisure();
|
yield Scripting.waitLeisure();
|
||||||
Scripting.scriptEvent('applicationsShowDone');
|
Scripting.scriptEvent('applicationsShowDone');
|
||||||
Main.overview._dash.showAppsButton.checked = false;
|
Main.overview._viewSelector.switchTab('windows');
|
||||||
yield Scripting.waitLeisure();
|
yield Scripting.waitLeisure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,11 @@ const Mainloop = imports.mainloop;
|
|||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const Shell = imports.gi.Shell;
|
|
||||||
|
|
||||||
const GnomeSession = imports.misc.gnomeSession;
|
const Shell = imports.gi.Shell;
|
||||||
const LoginManager = imports.misc.loginManager;
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
const ShellMountOperation = imports.ui.shellMountOperation;
|
||||||
|
const GnomeSession = imports.misc.gnomeSession;
|
||||||
|
|
||||||
const GNOME_SESSION_AUTOMOUNT_INHIBIT = 16;
|
const GNOME_SESSION_AUTOMOUNT_INHIBIT = 16;
|
||||||
|
|
||||||
@ -20,6 +19,62 @@ const SETTING_ENABLE_AUTOMOUNT = 'automount';
|
|||||||
|
|
||||||
const AUTORUN_EXPIRE_TIMEOUT_SECS = 10;
|
const AUTORUN_EXPIRE_TIMEOUT_SECS = 10;
|
||||||
|
|
||||||
|
const ConsoleKitSessionIface = <interface name="org.freedesktop.ConsoleKit.Session">
|
||||||
|
<method name="IsActive">
|
||||||
|
<arg type="b" direction="out" />
|
||||||
|
</method>
|
||||||
|
<signal name="ActiveChanged">
|
||||||
|
<arg type="b" direction="out" />
|
||||||
|
</signal>
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
const ConsoleKitSessionProxy = Gio.DBusProxy.makeProxyWrapper(ConsoleKitSessionIface);
|
||||||
|
|
||||||
|
const ConsoleKitManagerIface = <interface name="org.freedesktop.ConsoleKit.Manager">
|
||||||
|
<method name="GetCurrentSession">
|
||||||
|
<arg type="o" direction="out" />
|
||||||
|
</method>
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
const ConsoleKitManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(ConsoleKitManagerIface);
|
||||||
|
|
||||||
|
function ConsoleKitManager() {
|
||||||
|
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.system,
|
||||||
|
g_interface_name: ConsoleKitManagerInfo.name,
|
||||||
|
g_interface_info: ConsoleKitManagerInfo,
|
||||||
|
g_name: 'org.freedesktop.ConsoleKit',
|
||||||
|
g_object_path: '/org/freedesktop/ConsoleKit/Manager',
|
||||||
|
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
|
||||||
|
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
||||||
|
|
||||||
|
self._updateSessionActive = function() {
|
||||||
|
if (self.g_name_owner) {
|
||||||
|
self.GetCurrentSessionRemote(function([session]) {
|
||||||
|
self._ckSession = new ConsoleKitSessionProxy(Gio.DBus.system, 'org.freedesktop.ConsoleKit', session);
|
||||||
|
|
||||||
|
self._ckSession.connectSignal('ActiveChanged', function(object, senderName, [isActive]) {
|
||||||
|
self.sessionActive = isActive;
|
||||||
|
});
|
||||||
|
self._ckSession.IsActiveRemote(function([isActive]) {
|
||||||
|
self.sessionActive = isActive;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.sessionActive = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.connect('notify::g-name-owner',
|
||||||
|
Lang.bind(self, self._updateSessionActive));
|
||||||
|
|
||||||
|
self._updateSessionActive();
|
||||||
|
self.init(null);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
function haveSystemd() {
|
||||||
|
return GLib.access("/sys/fs/cgroup/systemd", 0) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
const AutomountManager = new Lang.Class({
|
const AutomountManager = new Lang.Class({
|
||||||
Name: 'AutomountManager',
|
Name: 'AutomountManager',
|
||||||
|
|
||||||
@ -33,33 +88,30 @@ const AutomountManager = new Lang.Class({
|
|||||||
Lang.bind(this, this._InhibitorsChanged));
|
Lang.bind(this, this._InhibitorsChanged));
|
||||||
this._inhibited = false;
|
this._inhibited = false;
|
||||||
|
|
||||||
LoginManager.getLoginManager(Lang.bind(this, function(manager) {
|
if (!haveSystemd())
|
||||||
this._loginManager = manager;
|
this.ckListener = new ConsoleKitManager();
|
||||||
}));
|
|
||||||
|
Main.screenShield.connect('lock-status-changed', Lang.bind(this, this._lockStatusChanged));
|
||||||
|
|
||||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||||
},
|
|
||||||
|
|
||||||
enable: function() {
|
this._volumeMonitor.connect('volume-added',
|
||||||
this._volumeAddedId = this._volumeMonitor.connect('volume-added', Lang.bind(this, this._onVolumeAdded));
|
Lang.bind(this,
|
||||||
this._volumeRemovedId = this._volumeMonitor.connect('volume-removed', Lang.bind(this, this._onVolumeRemoved));
|
this._onVolumeAdded));
|
||||||
this._driveConnectedId = this._volumeMonitor.connect('drive-connected', Lang.bind(this, this._onDriveConnected));
|
this._volumeMonitor.connect('volume-removed',
|
||||||
this._driveDisconnectedId = this._volumeMonitor.connect('drive-disconnected', Lang.bind(this, this._onDriveDisconnected));
|
Lang.bind(this,
|
||||||
this._driveEjectButtonId = this._volumeMonitor.connect('drive-eject-button', Lang.bind(this, this._onDriveEjectButton));
|
this._onVolumeRemoved));
|
||||||
|
this._volumeMonitor.connect('drive-connected',
|
||||||
|
Lang.bind(this,
|
||||||
|
this._onDriveConnected));
|
||||||
|
this._volumeMonitor.connect('drive-disconnected',
|
||||||
|
Lang.bind(this,
|
||||||
|
this._onDriveDisconnected));
|
||||||
|
this._volumeMonitor.connect('drive-eject-button',
|
||||||
|
Lang.bind(this,
|
||||||
|
this._onDriveEjectButton));
|
||||||
|
|
||||||
this._mountAllId = Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
|
Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
|
||||||
},
|
|
||||||
|
|
||||||
disable: function() {
|
|
||||||
this._volumeMonitor.disconnect(this._volumeAddedId);
|
|
||||||
this._volumeMonitor.disconnect(this._volumeRemovedId);
|
|
||||||
this._volumeMonitor.disconnect(this._driveConnectedId);
|
|
||||||
this._volumeMonitor.disconnect(this._driveDisconnectedId);
|
|
||||||
this._volumeMonitor.disconnect(this._driveEjectButtonId);
|
|
||||||
|
|
||||||
if (this._mountAllId > 0) {
|
|
||||||
Mainloop.source_remove(this._mountAllId);
|
|
||||||
this._mountAllId = 0;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_InhibitorsChanged: function(object, senderName, [inhibtor]) {
|
_InhibitorsChanged: function(object, senderName, [inhibtor]) {
|
||||||
@ -72,6 +124,17 @@ const AutomountManager = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_lockStatusChanged: function(shield, locked) {
|
||||||
|
if (!locked) {
|
||||||
|
this._volumeQueue.forEach(Lang.bind(this, function(volume) {
|
||||||
|
this._checkAndMountVolume(volume);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the queue anyway
|
||||||
|
this._volumeQueue = [];
|
||||||
|
},
|
||||||
|
|
||||||
_startupMountAll: function() {
|
_startupMountAll: function() {
|
||||||
let volumes = this._volumeMonitor.get_volumes();
|
let volumes = this._volumeMonitor.get_volumes();
|
||||||
volumes.forEach(Lang.bind(this, function(volume) {
|
volumes.forEach(Lang.bind(this, function(volume) {
|
||||||
@ -80,14 +143,27 @@ const AutomountManager = new Lang.Class({
|
|||||||
allowAutorun: false });
|
allowAutorun: false });
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._mountAllId = 0;
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isSessionActive: function() {
|
||||||
|
// Return whether the current session is active, using the
|
||||||
|
// right mechanism: either systemd if available or ConsoleKit
|
||||||
|
// as fallback.
|
||||||
|
|
||||||
|
if (haveSystemd())
|
||||||
|
return Shell.session_is_active_for_systemd();
|
||||||
|
|
||||||
|
return this.ckListener.sessionActive;
|
||||||
|
},
|
||||||
|
|
||||||
_onDriveConnected: function() {
|
_onDriveConnected: function() {
|
||||||
// if we're not in the current ConsoleKit session,
|
// if we're not in the current ConsoleKit session,
|
||||||
// or screensaver is active, don't play sounds
|
// or screensaver is active, don't play sounds
|
||||||
if (!this._loginManager || !this._loginManager.sessionActive)
|
if (!this.isSessionActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Main.screenShield.locked)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
global.play_theme_sound(0, 'device-added-media');
|
global.play_theme_sound(0, 'device-added-media');
|
||||||
@ -96,7 +172,10 @@ const AutomountManager = new Lang.Class({
|
|||||||
_onDriveDisconnected: function() {
|
_onDriveDisconnected: function() {
|
||||||
// if we're not in the current ConsoleKit session,
|
// if we're not in the current ConsoleKit session,
|
||||||
// or screensaver is active, don't play sounds
|
// or screensaver is active, don't play sounds
|
||||||
if (!this._loginManager || !this._loginManager.sessionActive)
|
if (!this.isSessionActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Main.screenShield.locked)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
global.play_theme_sound(0, 'device-removed-media');
|
global.play_theme_sound(0, 'device-removed-media');
|
||||||
@ -105,7 +184,7 @@ const AutomountManager = new Lang.Class({
|
|||||||
_onDriveEjectButton: function(monitor, drive) {
|
_onDriveEjectButton: function(monitor, drive) {
|
||||||
// TODO: this code path is not tested, as the GVfs volume monitor
|
// TODO: this code path is not tested, as the GVfs volume monitor
|
||||||
// doesn't emit this signal just yet.
|
// doesn't emit this signal just yet.
|
||||||
if (!this._loginManager || !this._loginManager.sessionActive)
|
if (!this.isSessionActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// we force stop/eject in this case, so we don't have to pass a
|
// we force stop/eject in this case, so we don't have to pass a
|
||||||
@ -145,8 +224,15 @@ const AutomountManager = new Lang.Class({
|
|||||||
if (params.checkSession) {
|
if (params.checkSession) {
|
||||||
// if we're not in the current ConsoleKit session,
|
// if we're not in the current ConsoleKit session,
|
||||||
// don't attempt automount
|
// don't attempt automount
|
||||||
if (!this._loginManager || !this._loginManager.sessionActive)
|
if (!this.isSessionActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (Main.screenShield.locked) {
|
||||||
|
if (this._volumeQueue.indexOf(volume) == -1)
|
||||||
|
this._volumeQueue.push(volume);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._inhibited)
|
if (this._inhibited)
|
||||||
@ -240,4 +326,3 @@ const AutomountManager = new Lang.Class({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const Component = AutomountManager;
|
|
@ -2,10 +2,8 @@
|
|||||||
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
const LoginManager = imports.misc.loginManager;
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
const ShellMountOperation = imports.ui.shellMountOperation;
|
||||||
@ -45,17 +43,6 @@ function isMountRootHidden(root) {
|
|||||||
return (path.indexOf('/.') != -1);
|
return (path.indexOf('/.') != -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isMountNonLocal(mount) {
|
|
||||||
// If the mount doesn't have an associated volume, that means it's
|
|
||||||
// an uninteresting filesystem. Most devices that we care about will
|
|
||||||
// have a mount, like media players and USB sticks.
|
|
||||||
let volume = mount.get_volume();
|
|
||||||
if (volume == null)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return (volume.get_identifier("class") == "network");
|
|
||||||
}
|
|
||||||
|
|
||||||
function startAppForMount(app, mount) {
|
function startAppForMount(app, mount) {
|
||||||
let files = [];
|
let files = [];
|
||||||
let root = mount.get_root();
|
let root = mount.get_root();
|
||||||
@ -83,37 +70,25 @@ const HotplugSnifferIface = <interface name="org.gnome.Shell.HotplugSniffer">
|
|||||||
</method>
|
</method>
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
const HotplugSniffer = new Gio.DBusProxyClass({
|
const HotplugSnifferProxy = Gio.DBusProxy.makeProxyWrapper(HotplugSnifferIface);
|
||||||
Name: 'HotplugSnifferProxy',
|
function HotplugSniffer() {
|
||||||
Interface: HotplugSnifferIface,
|
return new HotplugSnifferProxy(Gio.DBus.session,
|
||||||
|
'org.gnome.Shell.HotplugSniffer',
|
||||||
_init: function() {
|
'/org/gnome/Shell/HotplugSniffer');
|
||||||
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({
|
const ContentTypeDiscoverer = new Lang.Class({
|
||||||
Name: 'ContentTypeDiscoverer',
|
Name: 'ContentTypeDiscoverer',
|
||||||
|
|
||||||
_init: function(callback) {
|
_init: function(callback) {
|
||||||
this._callback = callback;
|
this._callback = callback;
|
||||||
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
|
||||||
},
|
},
|
||||||
|
|
||||||
guessContentTypes: function(mount) {
|
guessContentTypes: function(mount) {
|
||||||
let autorunEnabled = !this._settings.get_boolean(SETTING_DISABLE_AUTORUN);
|
// guess mount's content types using GIO
|
||||||
let shouldScan = autorunEnabled && !isMountNonLocal(mount);
|
mount.guess_content_type(false, null,
|
||||||
|
Lang.bind(this,
|
||||||
if (shouldScan) {
|
this._onContentTypeGuessed));
|
||||||
// guess mount's content types using GIO
|
|
||||||
mount.guess_content_type(false, null,
|
|
||||||
Lang.bind(this,
|
|
||||||
this._onContentTypeGuessed));
|
|
||||||
} else {
|
|
||||||
this._emitCallback(mount, []);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onContentTypeGuessed: function(mount, res) {
|
_onContentTypeGuessed: function(mount, res) {
|
||||||
@ -132,14 +107,10 @@ const ContentTypeDiscoverer = new Lang.Class({
|
|||||||
let root = mount.get_root();
|
let root = mount.get_root();
|
||||||
|
|
||||||
let hotplugSniffer = new HotplugSniffer();
|
let hotplugSniffer = new HotplugSniffer();
|
||||||
hotplugSniffer.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(proxy, result) {
|
hotplugSniffer.SniffURIRemote(root.get_uri(),
|
||||||
proxy.init_finish(result);
|
Lang.bind(this, function([contentTypes]) {
|
||||||
|
this._emitCallback(mount, contentTypes);
|
||||||
proxy.SniffURIRemote(root.get_uri(), null, Lang.bind(this, function(proxy, result) {
|
}));
|
||||||
let [contentTypes] = proxy.SniffURIFinish(result);
|
|
||||||
this._emitCallback(mount, contentTypes);
|
|
||||||
}));
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -171,71 +142,55 @@ const AutorunManager = new Lang.Class({
|
|||||||
Name: 'AutorunManager',
|
Name: 'AutorunManager',
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
LoginManager.getLoginManager(Lang.bind(this, function(manager) {
|
|
||||||
this._loginManager = manager;
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||||
|
|
||||||
this._transDispatcher = new AutorunTransientDispatcher(this);
|
this._volumeMonitor.connect('mount-added',
|
||||||
},
|
Lang.bind(this,
|
||||||
|
this._onMountAdded));
|
||||||
|
this._volumeMonitor.connect('mount-removed',
|
||||||
|
Lang.bind(this,
|
||||||
|
this._onMountRemoved));
|
||||||
|
|
||||||
_ensureResidentSource: function() {
|
this._transDispatcher = new AutorunTransientDispatcher();
|
||||||
if (this._residentSource)
|
this._createResidentSource();
|
||||||
return;
|
|
||||||
|
|
||||||
this._residentSource = new AutorunResidentSource(this);
|
|
||||||
let destroyId = this._residentSource.connect('destroy', Lang.bind(this, function() {
|
|
||||||
this._residentSource.disconnect(destroyId);
|
|
||||||
this._residentSource = null;
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
enable: function() {
|
|
||||||
this._scanMounts();
|
|
||||||
|
|
||||||
this._mountAddedId = this._volumeMonitor.connect('mount-added', Lang.bind(this, this._onMountAdded));
|
|
||||||
this._mountRemovedId = this._volumeMonitor.connect('mount-removed', Lang.bind(this, this._onMountRemoved));
|
|
||||||
},
|
|
||||||
|
|
||||||
disable: function() {
|
|
||||||
if (this._residentSource)
|
|
||||||
this._residentSource.destroy();
|
|
||||||
this._volumeMonitor.disconnect(this._mountAddedId);
|
|
||||||
this._volumeMonitor.disconnect(this._mountRemovedId);
|
|
||||||
},
|
|
||||||
|
|
||||||
_processMount: function(mount, hotplug) {
|
|
||||||
let discoverer = new ContentTypeDiscoverer(Lang.bind(this, function(mount, apps, contentTypes) {
|
|
||||||
this._ensureResidentSource();
|
|
||||||
this._residentSource.addMount(mount, apps);
|
|
||||||
|
|
||||||
if (hotplug)
|
|
||||||
this._transDispatcher.addMount(mount, apps, contentTypes);
|
|
||||||
}));
|
|
||||||
discoverer.guessContentTypes(mount);
|
|
||||||
},
|
|
||||||
|
|
||||||
_scanMounts: function() {
|
|
||||||
let mounts = this._volumeMonitor.get_mounts();
|
let mounts = this._volumeMonitor.get_mounts();
|
||||||
mounts.forEach(Lang.bind(this, function(mount) {
|
|
||||||
this._processMount(mount, false);
|
mounts.forEach(Lang.bind(this, function (mount) {
|
||||||
|
let discoverer = new ContentTypeDiscoverer(Lang.bind (this,
|
||||||
|
function (mount, apps) {
|
||||||
|
this._residentSource.addMount(mount, apps);
|
||||||
|
}));
|
||||||
|
|
||||||
|
discoverer.guessContentTypes(mount);
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_createResidentSource: function() {
|
||||||
|
this._residentSource = new AutorunResidentSource();
|
||||||
|
this._residentSource.connect('destroy',
|
||||||
|
Lang.bind(this,
|
||||||
|
this._createResidentSource));
|
||||||
|
},
|
||||||
|
|
||||||
_onMountAdded: function(monitor, mount) {
|
_onMountAdded: function(monitor, mount) {
|
||||||
// don't do anything if our session is not the currently
|
// don't do anything if our session is not the currently
|
||||||
// active one
|
// active one
|
||||||
if (!this._loginManager || !this._loginManager.sessionActive)
|
if (!Main.automountManager.isSessionActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._processMount(mount, true);
|
let discoverer = new ContentTypeDiscoverer(Lang.bind (this,
|
||||||
|
function (mount, apps, contentTypes) {
|
||||||
|
this._transDispatcher.addMount(mount, apps, contentTypes);
|
||||||
|
this._residentSource.addMount(mount, apps);
|
||||||
|
}));
|
||||||
|
|
||||||
|
discoverer.guessContentTypes(mount);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onMountRemoved: function(monitor, mount) {
|
_onMountRemoved: function(monitor, mount) {
|
||||||
this._transDispatcher.removeMount(mount);
|
this._transDispatcher.removeMount(mount);
|
||||||
if (this._residentSource)
|
this._residentSource.removeMount(mount);
|
||||||
this._residentSource.removeMount(mount);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
ejectMount: function(mount) {
|
ejectMount: function(mount) {
|
||||||
@ -302,18 +257,12 @@ const AutorunResidentSource = new Lang.Class({
|
|||||||
Name: 'AutorunResidentSource',
|
Name: 'AutorunResidentSource',
|
||||||
Extends: MessageTray.Source,
|
Extends: MessageTray.Source,
|
||||||
|
|
||||||
_init: function(manager) {
|
_init: function() {
|
||||||
this.parent(_("Removable Devices"), 'media-removable');
|
this.parent(_("Removable Devices"), 'media-removable', St.IconType.FULLCOLOR);
|
||||||
this.showInLockScreen = false;
|
|
||||||
|
|
||||||
this._mounts = [];
|
this._mounts = [];
|
||||||
|
|
||||||
this._manager = manager;
|
this._notification = new AutorunResidentNotification(this);
|
||||||
this._notification = new AutorunResidentNotification(this._manager, this);
|
|
||||||
},
|
|
||||||
|
|
||||||
buildRightClickMenu: function() {
|
|
||||||
return null;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addMount: function(mount, apps) {
|
addMount: function(mount, apps) {
|
||||||
@ -363,7 +312,7 @@ const AutorunResidentNotification = new Lang.Class({
|
|||||||
Name: 'AutorunResidentNotification',
|
Name: 'AutorunResidentNotification',
|
||||||
Extends: MessageTray.Notification,
|
Extends: MessageTray.Notification,
|
||||||
|
|
||||||
_init: function(manager, source) {
|
_init: function(source) {
|
||||||
this.parent(source, source.title, null, { customContent: true });
|
this.parent(source, source.title, null, { customContent: true });
|
||||||
|
|
||||||
// set the notification as resident
|
// set the notification as resident
|
||||||
@ -371,7 +320,6 @@ const AutorunResidentNotification = new Lang.Class({
|
|||||||
|
|
||||||
this._layout = new St.BoxLayout ({ style_class: 'hotplug-resident-box',
|
this._layout = new St.BoxLayout ({ style_class: 'hotplug-resident-box',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
this._manager = manager;
|
|
||||||
|
|
||||||
this.addActor(this._layout,
|
this.addActor(this._layout,
|
||||||
{ x_expand: true,
|
{ x_expand: true,
|
||||||
@ -419,7 +367,7 @@ const AutorunResidentNotification = new Lang.Class({
|
|||||||
expand: true });
|
expand: true });
|
||||||
|
|
||||||
let ejectIcon =
|
let ejectIcon =
|
||||||
new St.Icon({ icon_name: 'media-eject-symbolic',
|
new St.Icon({ icon_name: 'media-eject',
|
||||||
style_class: 'hotplug-resident-eject-icon' });
|
style_class: 'hotplug-resident-eject-icon' });
|
||||||
|
|
||||||
let ejectButton =
|
let ejectButton =
|
||||||
@ -434,7 +382,7 @@ const AutorunResidentNotification = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
ejectButton.connect('clicked', Lang.bind(this, function() {
|
ejectButton.connect('clicked', Lang.bind(this, function() {
|
||||||
this._manager.ejectMount(mount);
|
Main.autorunManager.ejectMount(mount);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
@ -444,8 +392,7 @@ const AutorunResidentNotification = new Lang.Class({
|
|||||||
const AutorunTransientDispatcher = new Lang.Class({
|
const AutorunTransientDispatcher = new Lang.Class({
|
||||||
Name: 'AutorunTransientDispatcher',
|
Name: 'AutorunTransientDispatcher',
|
||||||
|
|
||||||
_init: function(manager) {
|
_init: function() {
|
||||||
this._manager = manager;
|
|
||||||
this._sources = [];
|
this._sources = [];
|
||||||
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
||||||
},
|
},
|
||||||
@ -488,7 +435,7 @@ const AutorunTransientDispatcher = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// add a new source
|
// add a new source
|
||||||
this._sources.push(new AutorunTransientSource(this._manager, mount, apps));
|
this._sources.push(new AutorunTransientSource(mount, apps));
|
||||||
},
|
},
|
||||||
|
|
||||||
addMount: function(mount, apps, contentTypes) {
|
addMount: function(mount, apps, contentTypes) {
|
||||||
@ -541,22 +488,22 @@ const AutorunTransientSource = new Lang.Class({
|
|||||||
Name: 'AutorunTransientSource',
|
Name: 'AutorunTransientSource',
|
||||||
Extends: MessageTray.Source,
|
Extends: MessageTray.Source,
|
||||||
|
|
||||||
_init: function(manager, mount, apps) {
|
_init: function(mount, apps) {
|
||||||
this._manager = manager;
|
|
||||||
this.mount = mount;
|
this.mount = mount;
|
||||||
this.apps = apps;
|
this.apps = apps;
|
||||||
|
|
||||||
this.parent(mount.get_name());
|
this.parent(mount.get_name());
|
||||||
|
|
||||||
this._notification = new AutorunTransientNotification(this._manager, this);
|
this._notification = new AutorunTransientNotification(this);
|
||||||
|
|
||||||
// add ourselves as a source, and popup the notification
|
// add ourselves as a source, and popup the notification
|
||||||
Main.messageTray.add(this);
|
Main.messageTray.add(this);
|
||||||
this.notify(this._notification);
|
this.notify(this._notification);
|
||||||
},
|
},
|
||||||
|
|
||||||
getIcon: function() {
|
createIcon: function(size) {
|
||||||
return this.mount.get_icon();
|
return new St.Icon({ gicon: this.mount.get_icon(),
|
||||||
|
icon_size: size });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -564,10 +511,9 @@ const AutorunTransientNotification = new Lang.Class({
|
|||||||
Name: 'AutorunTransientNotification',
|
Name: 'AutorunTransientNotification',
|
||||||
Extends: MessageTray.Notification,
|
Extends: MessageTray.Notification,
|
||||||
|
|
||||||
_init: function(manager, source) {
|
_init: function(source) {
|
||||||
this.parent(source, source.title, null, { customContent: true });
|
this.parent(source, source.title, null, { customContent: true });
|
||||||
|
|
||||||
this._manager = manager;
|
|
||||||
this._box = new St.BoxLayout({ style_class: 'hotplug-transient-box',
|
this._box = new St.BoxLayout({ style_class: 'hotplug-transient-box',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
this.addActor(this._box);
|
this.addActor(this._box);
|
||||||
@ -619,7 +565,7 @@ const AutorunTransientNotification = new Lang.Class({
|
|||||||
|
|
||||||
_buttonForEject: function() {
|
_buttonForEject: function() {
|
||||||
let box = new St.BoxLayout();
|
let box = new St.BoxLayout();
|
||||||
let icon = new St.Icon({ icon_name: 'media-eject-symbolic',
|
let icon = new St.Icon({ icon_name: 'media-eject',
|
||||||
style_class: 'hotplug-notification-item-icon' });
|
style_class: 'hotplug-notification-item-icon' });
|
||||||
box.add(icon);
|
box.add(icon);
|
||||||
|
|
||||||
@ -636,11 +582,10 @@ const AutorunTransientNotification = new Lang.Class({
|
|||||||
style_class: 'hotplug-notification-item' });
|
style_class: 'hotplug-notification-item' });
|
||||||
|
|
||||||
button.connect('clicked', Lang.bind(this, function() {
|
button.connect('clicked', Lang.bind(this, function() {
|
||||||
this._manager.ejectMount(this._mount);
|
Main.autorunManager.ejectMount(this._mount);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const Component = AutorunManager;
|
|
@ -141,7 +141,6 @@ const BoxPointer = new Lang.Class({
|
|||||||
|
|
||||||
this._muteInput();
|
this._muteInput();
|
||||||
|
|
||||||
Tweener.removeTweens(this);
|
|
||||||
Tweener.addTween(this, { opacity: fade ? 0 : 255,
|
Tweener.addTween(this, { opacity: fade ? 0 : 255,
|
||||||
xOffset: xOffset,
|
xOffset: xOffset,
|
||||||
yOffset: yOffset,
|
yOffset: yOffset,
|
||||||
@ -275,51 +274,14 @@ const BoxPointer = new Lang.Class({
|
|||||||
let [x1, y1] = [halfBorder, halfBorder];
|
let [x1, y1] = [halfBorder, halfBorder];
|
||||||
let [x2, y2] = [boxWidth - halfBorder, boxHeight - halfBorder];
|
let [x2, y2] = [boxWidth - halfBorder, boxHeight - halfBorder];
|
||||||
|
|
||||||
let skipTopLeft = false;
|
|
||||||
let skipTopRight = false;
|
|
||||||
let skipBottomLeft = false;
|
|
||||||
let skipBottomRight = false;
|
|
||||||
|
|
||||||
switch (this._arrowSide) {
|
|
||||||
case St.Side.TOP:
|
|
||||||
if (this._arrowOrigin == x1)
|
|
||||||
skipTopLeft = true;
|
|
||||||
else if (this._arrowOrigin == x2)
|
|
||||||
skipTopRight = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case St.Side.RIGHT:
|
|
||||||
if (this._arrowOrigin == y1)
|
|
||||||
skipTopRight = true;
|
|
||||||
else if (this._arrowOrigin == y2)
|
|
||||||
skipBottomRight = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case St.Side.BOTTOM:
|
|
||||||
if (this._arrowOrigin == x1)
|
|
||||||
skipBottomLeft = true;
|
|
||||||
else if (this._arrowOrigin == x2)
|
|
||||||
skipBottomRight = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case St.Side.LEFT:
|
|
||||||
if (this._arrowOrigin == y1)
|
|
||||||
skipTopLeft = true;
|
|
||||||
else if (this._arrowOrigin == y2)
|
|
||||||
skipBottomLeft = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cr.moveTo(x1 + borderRadius, y1);
|
cr.moveTo(x1 + borderRadius, y1);
|
||||||
if (this._arrowSide == St.Side.TOP) {
|
if (this._arrowSide == St.Side.TOP) {
|
||||||
if (skipTopLeft) {
|
if (this._arrowOrigin < (x1 + (borderRadius + halfBase))) {
|
||||||
cr.moveTo(x1, y2 - borderRadius);
|
cr.lineTo(this._arrowOrigin, y1 - rise);
|
||||||
cr.lineTo(x1, y1 - rise);
|
cr.lineTo(Math.max(x1 + borderRadius, this._arrowOrigin) + halfBase, y1);
|
||||||
cr.lineTo(x1 + halfBase, y1);
|
} else if (this._arrowOrigin > (x2 - (borderRadius + halfBase))) {
|
||||||
} else if (skipTopRight) {
|
cr.lineTo(Math.min(x2 - borderRadius, this._arrowOrigin) - halfBase, y1);
|
||||||
cr.lineTo(x2 - halfBase, y1);
|
cr.lineTo(this._arrowOrigin, y1 - rise);
|
||||||
cr.lineTo(x2, y1 - rise);
|
|
||||||
cr.lineTo(x2, y1 + borderRadius);
|
|
||||||
} else {
|
} else {
|
||||||
cr.lineTo(this._arrowOrigin - halfBase, y1);
|
cr.lineTo(this._arrowOrigin - halfBase, y1);
|
||||||
cr.lineTo(this._arrowOrigin, y1 - rise);
|
cr.lineTo(this._arrowOrigin, y1 - rise);
|
||||||
@ -327,20 +289,19 @@ const BoxPointer = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skipTopRight) {
|
cr.lineTo(x2 - borderRadius, y1);
|
||||||
cr.lineTo(x2 - borderRadius, y1);
|
|
||||||
cr.arc(x2 - borderRadius, y1 + borderRadius, borderRadius,
|
// top-right corner
|
||||||
3*Math.PI/2, Math.PI*2);
|
cr.arc(x2 - borderRadius, y1 + borderRadius, borderRadius,
|
||||||
}
|
3*Math.PI/2, Math.PI*2);
|
||||||
|
|
||||||
if (this._arrowSide == St.Side.RIGHT) {
|
if (this._arrowSide == St.Side.RIGHT) {
|
||||||
if (skipTopRight) {
|
if (this._arrowOrigin < (y1 + (borderRadius + halfBase))) {
|
||||||
cr.lineTo(x2 + rise, y1);
|
cr.lineTo(x2 + rise, this._arrowOrigin);
|
||||||
cr.lineTo(x2 + rise, y1 + halfBase);
|
cr.lineTo(x2, Math.max(y1 + borderRadius, this._arrowOrigin) + halfBase);
|
||||||
} else if (skipBottomRight) {
|
} else if (this._arrowOrigin > (y2 - (borderRadius + halfBase))) {
|
||||||
cr.lineTo(x2, y2 - halfBase);
|
cr.lineTo(x2, Math.min(y2 - borderRadius, this._arrowOrigin) - halfBase);
|
||||||
cr.lineTo(x2 + rise, y2);
|
cr.lineTo(x2 + rise, this._arrowOrigin);
|
||||||
cr.lineTo(x2 - borderRadius, y2);
|
|
||||||
} else {
|
} else {
|
||||||
cr.lineTo(x2, this._arrowOrigin - halfBase);
|
cr.lineTo(x2, this._arrowOrigin - halfBase);
|
||||||
cr.lineTo(x2 + rise, this._arrowOrigin);
|
cr.lineTo(x2 + rise, this._arrowOrigin);
|
||||||
@ -348,20 +309,19 @@ const BoxPointer = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skipBottomRight) {
|
cr.lineTo(x2, y2 - borderRadius);
|
||||||
cr.lineTo(x2, y2 - borderRadius);
|
|
||||||
cr.arc(x2 - borderRadius, y2 - borderRadius, borderRadius,
|
// bottom-right corner
|
||||||
0, Math.PI/2);
|
cr.arc(x2 - borderRadius, y2 - borderRadius, borderRadius,
|
||||||
}
|
0, Math.PI/2);
|
||||||
|
|
||||||
if (this._arrowSide == St.Side.BOTTOM) {
|
if (this._arrowSide == St.Side.BOTTOM) {
|
||||||
if (skipBottomLeft) {
|
if (this._arrowOrigin < (x1 + (borderRadius + halfBase))) {
|
||||||
cr.lineTo(x1 + halfBase, y2);
|
cr.lineTo(Math.max(x1 + borderRadius, this._arrowOrigin) + halfBase, y2);
|
||||||
cr.lineTo(x1, y2 + rise);
|
cr.lineTo(this._arrowOrigin, y2 + rise);
|
||||||
cr.lineTo(x1, y2 - borderRadius);
|
} else if (this._arrowOrigin > (x2 - (borderRadius + halfBase))) {
|
||||||
} else if (skipBottomRight) {
|
cr.lineTo(this._arrowOrigin, y2 + rise);
|
||||||
cr.lineTo(x2, y2 + rise);
|
cr.lineTo(Math.min(x2 - borderRadius, this._arrowOrigin) - halfBase, y2);
|
||||||
cr.lineTo(x2 - halfBase, y2);
|
|
||||||
} else {
|
} else {
|
||||||
cr.lineTo(this._arrowOrigin + halfBase, y2);
|
cr.lineTo(this._arrowOrigin + halfBase, y2);
|
||||||
cr.lineTo(this._arrowOrigin, y2 + rise);
|
cr.lineTo(this._arrowOrigin, y2 + rise);
|
||||||
@ -369,20 +329,19 @@ const BoxPointer = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skipBottomLeft) {
|
cr.lineTo(x1 + borderRadius, y2);
|
||||||
cr.lineTo(x1 + borderRadius, y2);
|
|
||||||
cr.arc(x1 + borderRadius, y2 - borderRadius, borderRadius,
|
// bottom-left corner
|
||||||
Math.PI/2, Math.PI);
|
cr.arc(x1 + borderRadius, y2 - borderRadius, borderRadius,
|
||||||
}
|
Math.PI/2, Math.PI);
|
||||||
|
|
||||||
if (this._arrowSide == St.Side.LEFT) {
|
if (this._arrowSide == St.Side.LEFT) {
|
||||||
if (skipTopLeft) {
|
if (this._arrowOrigin < (y1 + (borderRadius + halfBase))) {
|
||||||
cr.lineTo(x1, y1 + halfBase);
|
cr.lineTo(x1, Math.max(y1 + borderRadius, this._arrowOrigin) + halfBase);
|
||||||
cr.lineTo(x1 - rise, y1);
|
cr.lineTo(x1 - rise, this._arrowOrigin);
|
||||||
cr.lineTo(x1 + borderRadius, y1);
|
} else if (this._arrowOrigin > (y2 - (borderRadius + halfBase))) {
|
||||||
} else if (skipBottomLeft) {
|
cr.lineTo(x1 - rise, this._arrowOrigin);
|
||||||
cr.lineTo(x1 - rise, y2)
|
cr.lineTo(x1, Math.min(y2 - borderRadius, this._arrowOrigin) - halfBase);
|
||||||
cr.lineTo(x1 - rise, y2 - halfBase);
|
|
||||||
} else {
|
} else {
|
||||||
cr.lineTo(x1, this._arrowOrigin + halfBase);
|
cr.lineTo(x1, this._arrowOrigin + halfBase);
|
||||||
cr.lineTo(x1 - rise, this._arrowOrigin);
|
cr.lineTo(x1 - rise, this._arrowOrigin);
|
||||||
@ -390,11 +349,11 @@ const BoxPointer = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skipTopLeft) {
|
cr.lineTo(x1, y1 + borderRadius);
|
||||||
cr.lineTo(x1, y1 + borderRadius);
|
|
||||||
cr.arc(x1 + borderRadius, y1 + borderRadius, borderRadius,
|
// top-left corner
|
||||||
Math.PI, 3*Math.PI/2);
|
cr.arc(x1 + borderRadius, y1 + borderRadius, borderRadius,
|
||||||
}
|
Math.PI, 3*Math.PI/2);
|
||||||
|
|
||||||
Clutter.cairo_set_source_color(cr, backgroundColor);
|
Clutter.cairo_set_source_color(cr, backgroundColor);
|
||||||
cr.fillPreserve();
|
cr.fillPreserve();
|
||||||
@ -447,9 +406,10 @@ const BoxPointer = new Lang.Class({
|
|||||||
let arrowBase = themeNode.get_length('-arrow-base');
|
let arrowBase = themeNode.get_length('-arrow-base');
|
||||||
let borderRadius = themeNode.get_length('-arrow-border-radius');
|
let borderRadius = themeNode.get_length('-arrow-border-radius');
|
||||||
let margin = (4 * borderRadius + borderWidth + arrowBase);
|
let margin = (4 * borderRadius + borderWidth + arrowBase);
|
||||||
|
let halfMargin = margin / 2;
|
||||||
|
|
||||||
|
let themeNode = this.actor.get_theme_node();
|
||||||
let gap = themeNode.get_length('-boxpointer-gap');
|
let gap = themeNode.get_length('-boxpointer-gap');
|
||||||
let padding = themeNode.get_length('-arrow-rise');
|
|
||||||
|
|
||||||
let resX, resY;
|
let resX, resY;
|
||||||
|
|
||||||
@ -468,66 +428,29 @@ const BoxPointer = new Lang.Class({
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now align and position the pointing axis, making sure it fits on
|
// Now align and position the pointing axis, making sure
|
||||||
// screen. If the arrowOrigin is so close to the edge that the arrow
|
// it fits on screen
|
||||||
// will not be isosceles, we try to compensate as follows:
|
|
||||||
// - We skip the rounded corner and settle for a right angled arrow
|
|
||||||
// as shown below. See _drawBorder for further details.
|
|
||||||
// |\_____
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// - If the arrow was going to be acute angled, we move the position
|
|
||||||
// of the box to maintain the arrow's accuracy.
|
|
||||||
|
|
||||||
let arrowOrigin;
|
|
||||||
let halfBase = Math.floor(arrowBase/2);
|
|
||||||
let halfBorder = borderWidth / 2;
|
|
||||||
let halfMargin = margin / 2;
|
|
||||||
let [x1, y1] = [halfBorder, halfBorder];
|
|
||||||
let [x2, y2] = [natWidth - halfBorder, natHeight - halfBorder];
|
|
||||||
|
|
||||||
switch (this._arrowSide) {
|
switch (this._arrowSide) {
|
||||||
case St.Side.TOP:
|
case St.Side.TOP:
|
||||||
case St.Side.BOTTOM:
|
case St.Side.BOTTOM:
|
||||||
resX = sourceCenterX - (halfMargin + (natWidth - margin) * alignment);
|
resX = sourceCenterX - (halfMargin + (natWidth - margin) * alignment);
|
||||||
|
|
||||||
resX = Math.max(resX, monitor.x + padding);
|
resX = Math.max(resX, monitor.x + 10);
|
||||||
resX = Math.min(resX, monitor.x + monitor.width - (padding + natWidth));
|
resX = Math.min(resX, monitor.x + monitor.width - (10 + natWidth));
|
||||||
|
this.setArrowOrigin(sourceCenterX - resX);
|
||||||
arrowOrigin = sourceCenterX - resX;
|
|
||||||
if (arrowOrigin <= (x1 + (borderRadius + halfBase))) {
|
|
||||||
if (arrowOrigin > x1)
|
|
||||||
resX += (arrowOrigin - x1);
|
|
||||||
arrowOrigin = x1;
|
|
||||||
} else if (arrowOrigin >= (x2 - (borderRadius + halfBase))) {
|
|
||||||
if (arrowOrigin < x2)
|
|
||||||
resX -= (x2 - arrowOrigin);
|
|
||||||
arrowOrigin = x2;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case St.Side.LEFT:
|
case St.Side.LEFT:
|
||||||
case St.Side.RIGHT:
|
case St.Side.RIGHT:
|
||||||
resY = sourceCenterY - (halfMargin + (natHeight - margin) * alignment);
|
resY = sourceCenterY - (halfMargin + (natHeight - margin) * alignment);
|
||||||
|
|
||||||
resY = Math.max(resY, monitor.y + padding);
|
resY = Math.max(resY, monitor.y + 10);
|
||||||
resY = Math.min(resY, monitor.y + monitor.height - (padding + natHeight));
|
resY = Math.min(resY, monitor.y + monitor.height - (10 + natHeight));
|
||||||
|
|
||||||
arrowOrigin = sourceCenterY - resY;
|
this.setArrowOrigin(sourceCenterY - resY);
|
||||||
if (arrowOrigin <= (y1 + (borderRadius + halfBase))) {
|
|
||||||
if (arrowOrigin > y1)
|
|
||||||
resY += (arrowOrigin - y1);
|
|
||||||
arrowOrigin = y1;
|
|
||||||
} else if (arrowOrigin >= (y2 - (borderRadius + halfBase))) {
|
|
||||||
if (arrowOrigin < y2)
|
|
||||||
resX -= (y2 - arrowOrigin);
|
|
||||||
arrowOrigin = y2;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setArrowOrigin(arrowOrigin);
|
|
||||||
|
|
||||||
let parent = this.actor.get_parent();
|
let parent = this.actor.get_parent();
|
||||||
let success, x, y;
|
let success, x, y;
|
||||||
while (!success) {
|
while (!success) {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
@ -201,17 +200,20 @@ const CalendarServerIface = <interface name="org.gnome.Shell.CalendarServer">
|
|||||||
<signal name="Changed" />
|
<signal name="Changed" />
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
const CalendarServer = new Gio.DBusProxyClass({
|
const CalendarServerInfo = Gio.DBusInterfaceInfo.new_for_xml(CalendarServerIface);
|
||||||
Name: 'CalendarServer',
|
|
||||||
Interface: CalendarServerIface,
|
|
||||||
|
|
||||||
_init: function() {
|
function CalendarServer() {
|
||||||
this.parent({ g_bus_type: Gio.BusType.SESSION,
|
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.session,
|
||||||
g_name: 'org.gnome.Shell.CalendarServer',
|
g_interface_name: CalendarServerInfo.name,
|
||||||
g_object_path: '/org/gnome/Shell/CalendarServer',
|
g_interface_info: CalendarServerInfo,
|
||||||
g_flags: Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES });
|
g_name: 'org.gnome.Shell.CalendarServer',
|
||||||
}
|
g_object_path: '/org/gnome/Shell/CalendarServer',
|
||||||
});
|
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
|
||||||
|
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
||||||
|
|
||||||
|
self.init(null);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
function _datesEqual(a, b) {
|
function _datesEqual(a, b) {
|
||||||
if (a < b)
|
if (a < b)
|
||||||
@ -241,15 +243,11 @@ const DBusEventSource = new Lang.Class({
|
|||||||
this._dbusProxy = new CalendarServer();
|
this._dbusProxy = new CalendarServer();
|
||||||
this._dbusProxy.connectSignal('Changed', Lang.bind(this, this._onChanged));
|
this._dbusProxy.connectSignal('Changed', Lang.bind(this, this._onChanged));
|
||||||
|
|
||||||
this._dbusProxy.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(proxy, result) {
|
this._dbusProxy.connect('notify::g-name-owner', Lang.bind(this, function() {
|
||||||
try {
|
if (this._dbusProxy.g_name_owner)
|
||||||
proxy.init_finish(result);
|
this._onNameAppeared();
|
||||||
} catch(e) {
|
else
|
||||||
return;
|
this._onNameVanished();
|
||||||
}
|
|
||||||
|
|
||||||
this._resetCache();
|
|
||||||
this.emit('changed');
|
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -259,32 +257,36 @@ const DBusEventSource = new Lang.Class({
|
|||||||
this._lastRequestEnd = null;
|
this._lastRequestEnd = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onNameAppeared: function(owner) {
|
||||||
|
this._resetCache();
|
||||||
|
this._loadEvents(true);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onNameVanished: function(oldOwner) {
|
||||||
|
this._resetCache();
|
||||||
|
this.emit('changed');
|
||||||
|
},
|
||||||
|
|
||||||
_onChanged: function() {
|
_onChanged: function() {
|
||||||
this._loadEvents(false);
|
this._loadEvents(false);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onEventsReceived: function(proxy, result) {
|
_onEventsReceived: function([appointments]) {
|
||||||
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 = [];
|
let newEvents = [];
|
||||||
for (let n = 0; n < appointments.length; n++) {
|
if (appointments != null) {
|
||||||
let a = appointments[n];
|
for (let n = 0; n < appointments.length; n++) {
|
||||||
let date = new Date(a[4] * 1000);
|
let a = appointments[n];
|
||||||
let end = new Date(a[5] * 1000);
|
let date = new Date(a[4] * 1000);
|
||||||
let summary = a[1];
|
let end = new Date(a[5] * 1000);
|
||||||
let allDay = a[3];
|
let summary = a[1];
|
||||||
let event = new CalendarEvent(date, end, summary, allDay);
|
let allDay = a[3];
|
||||||
newEvents.push(event);
|
let event = new CalendarEvent(date, end, summary, allDay);
|
||||||
|
newEvents.push(event);
|
||||||
|
}
|
||||||
|
newEvents.sort(function(event1, event2) {
|
||||||
|
return event1.date.getTime() - event2.date.getTime();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
newEvents.sort(function(event1, event2) {
|
|
||||||
return event1.date.getTime() - event2.date.getTime();
|
|
||||||
});
|
|
||||||
|
|
||||||
this._events = newEvents;
|
this._events = newEvents;
|
||||||
this.emit('changed');
|
this.emit('changed');
|
||||||
@ -292,19 +294,14 @@ const DBusEventSource = new Lang.Class({
|
|||||||
|
|
||||||
_loadEvents: function(forceReload) {
|
_loadEvents: function(forceReload) {
|
||||||
if (this._curRequestBegin && this._curRequestEnd){
|
if (this._curRequestBegin && this._curRequestEnd){
|
||||||
/* Can't use GetEventsRemote because we need to pass the
|
|
||||||
flags here */
|
|
||||||
let callFlags = Gio.DBusCallFlags.NO_AUTO_START;
|
let callFlags = Gio.DBusCallFlags.NO_AUTO_START;
|
||||||
if (forceReload)
|
if (forceReload)
|
||||||
callFlags = Gio.DBusCallFlags.NONE;
|
callFlags = Gio.DBusCallFlags.NONE;
|
||||||
this._dbusProxy.call("GetEvents",
|
this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
|
||||||
GLib.Variant.new("(xxb)", [this._curRequestBegin.getTime() / 1000,
|
this._curRequestEnd.getTime() / 1000,
|
||||||
this._curRequestEnd.getTime() / 1000,
|
forceReload,
|
||||||
forceReload]),
|
Lang.bind(this, this._onEventsReceived),
|
||||||
callFlags,
|
callFlags);
|
||||||
-1,
|
|
||||||
null,
|
|
||||||
Lang.bind(this, this._onEventsReceived));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -343,10 +340,22 @@ const DBusEventSource = new Lang.Class({
|
|||||||
});
|
});
|
||||||
Signals.addSignalMethods(DBusEventSource.prototype);
|
Signals.addSignalMethods(DBusEventSource.prototype);
|
||||||
|
|
||||||
|
// Calendar:
|
||||||
|
// @eventSource: is an object implementing the EventSource API, e.g. the
|
||||||
|
// requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
|
||||||
const Calendar = new Lang.Class({
|
const Calendar = new Lang.Class({
|
||||||
Name: 'Calendar',
|
Name: 'Calendar',
|
||||||
|
|
||||||
_init: function() {
|
_init: function(eventSource) {
|
||||||
|
if (eventSource) {
|
||||||
|
this._eventSource = eventSource;
|
||||||
|
|
||||||
|
this._eventSource.connect('changed', Lang.bind(this,
|
||||||
|
function() {
|
||||||
|
this._update(false);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
this._weekStart = Shell.util_get_week_start();
|
this._weekStart = Shell.util_get_week_start();
|
||||||
this._weekdate = NaN;
|
this._weekdate = NaN;
|
||||||
this._digitWidth = NaN;
|
this._digitWidth = NaN;
|
||||||
@ -383,23 +392,6 @@ const Calendar = new Lang.Class({
|
|||||||
this._buildHeader ();
|
this._buildHeader ();
|
||||||
},
|
},
|
||||||
|
|
||||||
// @eventSource: is an object implementing the EventSource API, e.g. the
|
|
||||||
// requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
|
|
||||||
setEventSource: function(eventSource) {
|
|
||||||
if (this._eventSource) {
|
|
||||||
this._eventSource.disconnect(this._eventSourceChangedId);
|
|
||||||
this._eventSource = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._eventSource = eventSource;
|
|
||||||
|
|
||||||
if (this._eventSource) {
|
|
||||||
this._eventSourceChangedId = this._eventSource.connect('changed', Lang.bind(this, function() {
|
|
||||||
this._update(false);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Sets the calendar to show a specific date
|
// Sets the calendar to show a specific date
|
||||||
setDate: function(date, forceReload) {
|
setDate: function(date, forceReload) {
|
||||||
if (!_sameDay(date, this._selectedDate)) {
|
if (!_sameDay(date, this._selectedDate)) {
|
||||||
@ -630,25 +622,16 @@ Signals.addSignalMethods(Calendar.prototype);
|
|||||||
const EventsList = new Lang.Class({
|
const EventsList = new Lang.Class({
|
||||||
Name: 'EventsList',
|
Name: 'EventsList',
|
||||||
|
|
||||||
_init: function() {
|
_init: function(eventSource) {
|
||||||
this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'});
|
this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'});
|
||||||
this._date = new Date();
|
this._date = new Date();
|
||||||
|
this._eventSource = eventSource;
|
||||||
|
this._eventSource.connect('changed', Lang.bind(this, this._update));
|
||||||
this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
|
this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
|
||||||
this._desktopSettings.connect('changed', Lang.bind(this, this._update));
|
this._desktopSettings.connect('changed', Lang.bind(this, this._update));
|
||||||
this._weekStart = Shell.util_get_week_start();
|
this._weekStart = Shell.util_get_week_start();
|
||||||
},
|
|
||||||
|
|
||||||
setEventSource: function(eventSource) {
|
this._update();
|
||||||
if (this._eventSource) {
|
|
||||||
this._eventSource.disconnect(this._eventSourceChangedId);
|
|
||||||
this._eventSource = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._eventSource = eventSource;
|
|
||||||
|
|
||||||
if (this._eventSource) {
|
|
||||||
this._eventSourceChangedId = this._eventSource.connect('changed', Lang.bind(this, this._update));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_addEvent: function(dayNameBox, timeBox, eventTitleBox, includeDayName, day, time, desc) {
|
_addEvent: function(dayNameBox, timeBox, eventTitleBox, includeDayName, day, time, desc) {
|
||||||
@ -734,15 +717,13 @@ const EventsList = new Lang.Class({
|
|||||||
let tomorrowEnd = new Date(dayEnd.getTime() + 86400 * 1000);
|
let tomorrowEnd = new Date(dayEnd.getTime() + 86400 * 1000);
|
||||||
this._addPeriod(_("Tomorrow"), tomorrowBegin, tomorrowEnd, false, true);
|
this._addPeriod(_("Tomorrow"), tomorrowBegin, tomorrowEnd, false, true);
|
||||||
|
|
||||||
let dayInWeek = (dayEnd.getDay() - this._weekStart + 7) % 7;
|
if (dayEnd.getDay() <= 4 + this._weekStart) {
|
||||||
|
|
||||||
if (dayInWeek < 5) {
|
|
||||||
/* If now is within the first 5 days we show "This week" and
|
/* If now is within the first 5 days we show "This week" and
|
||||||
* include events up until and including Saturday/Sunday
|
* include events up until and including Saturday/Sunday
|
||||||
* (depending on whether a week starts on Sunday/Monday).
|
* (depending on whether a week starts on Sunday/Monday).
|
||||||
*/
|
*/
|
||||||
let thisWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000);
|
let thisWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000);
|
||||||
let thisWeekEnd = new Date(dayEnd.getTime() + (6 - dayInWeek) * 86400 * 1000);
|
let thisWeekEnd = new Date(dayEnd.getTime() + (6 + this._weekStart - dayEnd.getDay()) * 86400 * 1000);
|
||||||
this._addPeriod(_("This week"), thisWeekBegin, thisWeekEnd, true, false);
|
this._addPeriod(_("This week"), thisWeekBegin, thisWeekEnd, true, false);
|
||||||
} else {
|
} else {
|
||||||
/* otherwise it's one of the two last days of the week ... show
|
/* otherwise it's one of the two last days of the week ... show
|
||||||
@ -750,7 +731,7 @@ const EventsList = new Lang.Class({
|
|||||||
* Saturday/Sunday
|
* Saturday/Sunday
|
||||||
*/
|
*/
|
||||||
let nextWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000);
|
let nextWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000);
|
||||||
let nextWeekEnd = new Date(dayEnd.getTime() + (13 - dayInWeek) * 86400 * 1000);
|
let nextWeekEnd = new Date(dayEnd.getTime() + (13 + this._weekStart - dayEnd.getDay()) * 86400 * 1000);
|
||||||
this._addPeriod(_("Next week"), nextWeekBegin, nextWeekEnd, true, false);
|
this._addPeriod(_("Next week"), nextWeekBegin, nextWeekEnd, true, false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const Main = imports.ui.main;
|
|
||||||
|
|
||||||
const ComponentManager = new Lang.Class({
|
|
||||||
Name: 'ComponentManager',
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this._allComponents = {};
|
|
||||||
this._enabledComponents = [];
|
|
||||||
|
|
||||||
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
|
||||||
this._sessionUpdated();
|
|
||||||
},
|
|
||||||
|
|
||||||
_sessionUpdated: function() {
|
|
||||||
let newEnabledComponents = Main.sessionMode.components;
|
|
||||||
|
|
||||||
newEnabledComponents.filter(Lang.bind(this, function(name) {
|
|
||||||
return this._enabledComponents.indexOf(name) == -1;
|
|
||||||
})).forEach(Lang.bind(this, function(name) {
|
|
||||||
this._enableComponent(name);
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._enabledComponents.filter(Lang.bind(this, function(name) {
|
|
||||||
return newEnabledComponents.indexOf(name) == -1;
|
|
||||||
})).forEach(Lang.bind(this, function(name) {
|
|
||||||
this._disableComponent(name);
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._enabledComponents = newEnabledComponents;
|
|
||||||
},
|
|
||||||
|
|
||||||
_importComponent: function(name) {
|
|
||||||
let module = imports.ui.components[name];
|
|
||||||
return module.Component;
|
|
||||||
},
|
|
||||||
|
|
||||||
_ensureComponent: function(name) {
|
|
||||||
let component = this._allComponents[name];
|
|
||||||
if (component)
|
|
||||||
return component;
|
|
||||||
|
|
||||||
if (Main.sessionMode.isLocked)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
let constructor = this._importComponent(name);
|
|
||||||
component = new constructor();
|
|
||||||
this._allComponents[name] = component;
|
|
||||||
return component;
|
|
||||||
},
|
|
||||||
|
|
||||||
_enableComponent: function(name) {
|
|
||||||
let component = this._ensureComponent(name);
|
|
||||||
if (component)
|
|
||||||
component.enable();
|
|
||||||
},
|
|
||||||
|
|
||||||
_disableComponent: function(name) {
|
|
||||||
let component = this._allComponents[name];
|
|
||||||
if (component == null)
|
|
||||||
return;
|
|
||||||
component.disable();
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,58 +0,0 @@
|
|||||||
|
|
||||||
const Lang = imports.lang;
|
|
||||||
|
|
||||||
const Gio = imports.gi.Gio;
|
|
||||||
const Meta = imports.gi.Meta;
|
|
||||||
const Shell = imports.gi.Shell;
|
|
||||||
|
|
||||||
const Recorder = new Lang.Class({
|
|
||||||
Name: 'Recorder',
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this._recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
|
|
||||||
this._desktopLockdownSettings = new Gio.Settings({ schema: 'org.gnome.desktop.lockdown' });
|
|
||||||
this._bindingSettings = new Gio.Settings({ schema: 'org.gnome.shell.keybindings' });
|
|
||||||
this._recorder = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
enable: function() {
|
|
||||||
global.display.add_keybinding('toggle-recording',
|
|
||||||
this._bindingSettings,
|
|
||||||
Meta.KeyBindingFlags.NONE, Lang.bind(this, this._toggleRecorder));
|
|
||||||
},
|
|
||||||
|
|
||||||
disable: function() {
|
|
||||||
global.display.remove_keybinding('toggle-recording');
|
|
||||||
},
|
|
||||||
|
|
||||||
_ensureRecorder: function() {
|
|
||||||
if (this._recorder == null)
|
|
||||||
this._recorder = new Shell.Recorder({ stage: global.stage });
|
|
||||||
return this._recorder;
|
|
||||||
},
|
|
||||||
|
|
||||||
_toggleRecorder: function() {
|
|
||||||
let recorder = this._ensureRecorder();
|
|
||||||
if (recorder.is_recording()) {
|
|
||||||
recorder.close();
|
|
||||||
Meta.enable_unredirect_for_screen(global.screen);
|
|
||||||
} else if (!this._desktopLockdownSettings.get_boolean('disable-save-to-disk')) {
|
|
||||||
// read the parameters from GSettings always in case they have changed
|
|
||||||
recorder.set_framerate(this._recorderSettings.get_int('framerate'));
|
|
||||||
/* Translators: this is a filename used for screencast recording */
|
|
||||||
// xgettext:no-c-format
|
|
||||||
recorder.set_file_template(_("Screencast from %d %t") + '.' + this._recorderSettings.get_string('file-extension'));
|
|
||||||
let pipeline = this._recorderSettings.get_string('pipeline');
|
|
||||||
|
|
||||||
if (!pipeline.match(/^\s*$/))
|
|
||||||
recorder.set_pipeline(pipeline);
|
|
||||||
else
|
|
||||||
recorder.set_pipeline(null);
|
|
||||||
|
|
||||||
Meta.disable_unredirect_for_screen(global.screen);
|
|
||||||
recorder.record();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const Component = Recorder;
|
|
@ -27,6 +27,7 @@ const CtrlAltTabManager = new Lang.Class({
|
|||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._items = [];
|
this._items = [];
|
||||||
|
this._focusManager = St.FocusManager.get_for_stage(global.stage);
|
||||||
},
|
},
|
||||||
|
|
||||||
addGroup: function(root, name, icon, params) {
|
addGroup: function(root, name, icon, params) {
|
||||||
@ -40,11 +41,11 @@ const CtrlAltTabManager = new Lang.Class({
|
|||||||
|
|
||||||
this._items.push(item);
|
this._items.push(item);
|
||||||
root.connect('destroy', Lang.bind(this, function() { this.removeGroup(root); }));
|
root.connect('destroy', Lang.bind(this, function() { this.removeGroup(root); }));
|
||||||
global.focus_manager.add_group(root);
|
this._focusManager.add_group(root);
|
||||||
},
|
},
|
||||||
|
|
||||||
removeGroup: function(root) {
|
removeGroup: function(root) {
|
||||||
global.focus_manager.remove_group(root);
|
this._focusManager.remove_group(root);
|
||||||
for (let i = 0; i < this._items.length; i++) {
|
for (let i = 0; i < this._items.length; i++) {
|
||||||
if (this._items[i].root == root) {
|
if (this._items[i].root == root) {
|
||||||
this._items.splice(i, 1);
|
this._items.splice(i, 1);
|
||||||
@ -54,17 +55,16 @@ const CtrlAltTabManager = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
focusGroup: function(item) {
|
focusGroup: function(item) {
|
||||||
if (item.window) {
|
if (global.stage_input_mode == Shell.StageInputMode.NONREACTIVE ||
|
||||||
Main.activateWindow(item.window);
|
global.stage_input_mode == Shell.StageInputMode.NORMAL)
|
||||||
} else if (item.focusCallback) {
|
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
|
||||||
item.focusCallback();
|
|
||||||
} else {
|
|
||||||
if (global.stage_input_mode == Shell.StageInputMode.NONREACTIVE ||
|
|
||||||
global.stage_input_mode == Shell.StageInputMode.NORMAL)
|
|
||||||
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
|
|
||||||
|
|
||||||
|
if (item.window)
|
||||||
|
Main.activateWindow(item.window);
|
||||||
|
else if (item.focusCallback)
|
||||||
|
item.focusCallback();
|
||||||
|
else
|
||||||
item.root.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
item.root.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Sort the items into a consistent order; panel first, tray last,
|
// Sort the items into a consistent order; panel first, tray last,
|
||||||
@ -319,6 +319,7 @@ const CtrlAltTabSwitcher = new Lang.Class({
|
|||||||
let icon = item.iconActor;
|
let icon = item.iconActor;
|
||||||
if (!icon) {
|
if (!icon) {
|
||||||
icon = new St.Icon({ icon_name: item.iconName,
|
icon = new St.Icon({ icon_name: item.iconName,
|
||||||
|
icon_type: St.IconType.SYMBOLIC,
|
||||||
icon_size: POPUP_APPICON_SIZE });
|
icon_size: POPUP_APPICON_SIZE });
|
||||||
}
|
}
|
||||||
box.add(icon, { x_fill: false, y_fill: false } );
|
box.add(icon, { x_fill: false, y_fill: false } );
|
||||||
|
248
js/ui/dash.js
248
js/ui/dash.js
@ -21,18 +21,6 @@ const DASH_ITEM_LABEL_SHOW_TIME = 0.15;
|
|||||||
const DASH_ITEM_LABEL_HIDE_TIME = 0.1;
|
const DASH_ITEM_LABEL_HIDE_TIME = 0.1;
|
||||||
const DASH_ITEM_HOVER_TIMEOUT = 300;
|
const DASH_ITEM_HOVER_TIMEOUT = 300;
|
||||||
|
|
||||||
function getAppFromSource(source) {
|
|
||||||
if (source instanceof AppDisplay.AppWellIcon) {
|
|
||||||
let appSystem = Shell.AppSystem.get_default();
|
|
||||||
return appSystem.lookup_app(source.getId());
|
|
||||||
} else if (source.metaWindow) {
|
|
||||||
let tracker = Shell.WindowTracker.get_default();
|
|
||||||
return tracker.get_window_app(source.metaWindow);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A container like StBin, but taking the child's scale into account
|
// A container like StBin, but taking the child's scale into account
|
||||||
// when requesting a size
|
// when requesting a size
|
||||||
const DashItemContainer = new Lang.Class({
|
const DashItemContainer = new Lang.Class({
|
||||||
@ -48,11 +36,7 @@ const DashItemContainer = new Lang.Class({
|
|||||||
Lang.bind(this, this._allocate));
|
Lang.bind(this, this._allocate));
|
||||||
this.actor._delegate = this;
|
this.actor._delegate = this;
|
||||||
|
|
||||||
this._labelText = "";
|
this.label = null;
|
||||||
this.label = new St.Label({ style_class: 'dash-label'});
|
|
||||||
this.label.hide();
|
|
||||||
Main.layoutManager.addChrome(this.label);
|
|
||||||
this.actor.label_actor = this.label;
|
|
||||||
|
|
||||||
this.child = null;
|
this.child = null;
|
||||||
this._childScale = 1;
|
this._childScale = 1;
|
||||||
@ -107,10 +91,9 @@ const DashItemContainer = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
showLabel: function() {
|
showLabel: function() {
|
||||||
if (!this._labelText)
|
if (this.label == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.label.set_text(this._labelText);
|
|
||||||
this.label.opacity = 0;
|
this.label.opacity = 0;
|
||||||
this.label.show();
|
this.label.show();
|
||||||
|
|
||||||
@ -141,7 +124,12 @@ const DashItemContainer = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
setLabelText: function(text) {
|
setLabelText: function(text) {
|
||||||
this._labelText = text;
|
if (this.label == null)
|
||||||
|
this.label = new St.Label({ style_class: 'dash-label'});
|
||||||
|
|
||||||
|
this.label.set_text(text);
|
||||||
|
Main.layoutManager.addChrome(this.label);
|
||||||
|
this.label.hide();
|
||||||
},
|
},
|
||||||
|
|
||||||
hideLabel: function () {
|
hideLabel: function () {
|
||||||
@ -238,77 +226,52 @@ const DashItemContainer = new Lang.Class({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const ShowAppsIcon = new Lang.Class({
|
const RemoveFavoriteIcon = new Lang.Class({
|
||||||
Name: 'ShowAppsIcon',
|
Name: 'RemoveFavoriteIcon',
|
||||||
Extends: DashItemContainer,
|
Extends: DashItemContainer,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent();
|
this.parent();
|
||||||
|
|
||||||
this.toggleButton = new St.Button({ style_class: 'show-apps',
|
this._iconBin = new St.Bin({ style_class: 'remove-favorite' });
|
||||||
track_hover: true,
|
|
||||||
can_focus: true,
|
|
||||||
toggle_mode: true });
|
|
||||||
this._iconActor = null;
|
this._iconActor = null;
|
||||||
this.icon = new IconGrid.BaseIcon(_("Show Applications"),
|
this.icon = new IconGrid.BaseIcon(_("Remove"),
|
||||||
{ setSizeManually: true,
|
{ setSizeManually: true,
|
||||||
showLabel: false,
|
showLabel: false,
|
||||||
createIcon: Lang.bind(this, this._createIcon) });
|
createIcon: Lang.bind(this, this._createIcon) });
|
||||||
this.toggleButton.add_actor(this.icon.actor);
|
this._iconBin.set_child(this.icon.actor);
|
||||||
this.toggleButton._delegate = this;
|
this._iconBin._delegate = this;
|
||||||
|
|
||||||
this.setChild(this.toggleButton);
|
this.setChild(this._iconBin);
|
||||||
this.setDragApp(null);
|
|
||||||
this.toggleButton.label_actor = this.label;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_createIcon: function(size) {
|
_createIcon: function(size) {
|
||||||
this._iconActor = new St.Icon({ icon_name: 'view-grid-symbolic',
|
this._iconActor = new St.Icon({ icon_name: 'user-trash',
|
||||||
icon_size: size,
|
style_class: 'remove-favorite-icon',
|
||||||
style_class: 'show-apps-icon',
|
icon_size: size });
|
||||||
track_hover: true });
|
|
||||||
return this._iconActor;
|
return this._iconActor;
|
||||||
},
|
},
|
||||||
|
|
||||||
_canRemoveApp: function(app) {
|
setHover: function(hovered) {
|
||||||
if (app == null)
|
this._iconBin.set_hover(hovered);
|
||||||
return false;
|
|
||||||
|
|
||||||
let id = app.get_id();
|
|
||||||
let isFavorite = AppFavorites.getAppFavorites().isFavorite(id);
|
|
||||||
return isFavorite;
|
|
||||||
},
|
|
||||||
|
|
||||||
setDragApp: function(app) {
|
|
||||||
let canRemove = this._canRemoveApp(app);
|
|
||||||
|
|
||||||
this.toggleButton.set_hover(canRemove);
|
|
||||||
if (this._iconActor)
|
if (this._iconActor)
|
||||||
this._iconActor.set_hover(canRemove);
|
this._iconActor.set_hover(hovered);
|
||||||
|
|
||||||
if (canRemove)
|
|
||||||
this.setLabelText(_("Remove from Favorites"));
|
|
||||||
else
|
|
||||||
this.setLabelText(_("Show Applications"));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Rely on the dragged item being a favorite
|
||||||
handleDragOver: function(source, actor, x, y, time) {
|
handleDragOver: function(source, actor, x, y, time) {
|
||||||
let app = getAppFromSource(source);
|
|
||||||
if (app == null)
|
|
||||||
return DND.DragMotionResult.NO_DROP;
|
|
||||||
|
|
||||||
let id = app.get_id();
|
|
||||||
let isFavorite = AppFavorites.getAppFavorites().isFavorite(id);
|
|
||||||
if (!isFavorite)
|
|
||||||
return DND.DragMotionResult.NO_DROP;
|
|
||||||
|
|
||||||
return DND.DragMotionResult.MOVE_DROP;
|
return DND.DragMotionResult.MOVE_DROP;
|
||||||
},
|
},
|
||||||
|
|
||||||
acceptDrop: function(source, actor, x, y, time) {
|
acceptDrop: function(source, actor, x, y, time) {
|
||||||
let app = getAppFromSource(source);
|
let app = null;
|
||||||
if (app == null)
|
if (source instanceof AppDisplay.AppWellIcon) {
|
||||||
return false;
|
let appSystem = Shell.AppSystem.get_default();
|
||||||
|
app = appSystem.lookup_app(source.getId());
|
||||||
|
} else if (source.metaWindow) {
|
||||||
|
let tracker = Shell.WindowTracker.get_default();
|
||||||
|
app = tracker.get_window_app(source.metaWindow);
|
||||||
|
}
|
||||||
|
|
||||||
let id = app.get_id();
|
let id = app.get_id();
|
||||||
|
|
||||||
@ -332,39 +295,6 @@ const DragPlaceholderItem = new Lang.Class({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const DashActor = new Lang.Class({
|
|
||||||
Name: 'DashActor',
|
|
||||||
Extends: St.Widget,
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
let layout = new Clutter.BoxLayout({ orientation: Clutter.Orientation.VERTICAL });
|
|
||||||
this.parent({ name: 'dash',
|
|
||||||
layout_manager: layout,
|
|
||||||
clip_to_allocation: true });
|
|
||||||
},
|
|
||||||
|
|
||||||
vfunc_allocate: function(box, flags) {
|
|
||||||
let contentBox = this.get_theme_node().get_content_box(box);
|
|
||||||
let availWidth = contentBox.x2 - contentBox.x1;
|
|
||||||
|
|
||||||
this.set_allocation(box, flags);
|
|
||||||
|
|
||||||
let [appIcons, showAppsButton] = this.get_children();
|
|
||||||
let [showAppsMinHeight, showAppsNatHeight] = showAppsButton.get_preferred_height(availWidth);
|
|
||||||
|
|
||||||
let childBox = new Clutter.ActorBox();
|
|
||||||
childBox.x1 = contentBox.x1;
|
|
||||||
childBox.y1 = contentBox.y1;
|
|
||||||
childBox.x2 = contentBox.x2;
|
|
||||||
childBox.y2 = contentBox.y2 - showAppsNatHeight;
|
|
||||||
appIcons.allocate(childBox, flags);
|
|
||||||
|
|
||||||
childBox.y1 = contentBox.y2 - showAppsNatHeight;
|
|
||||||
childBox.y2 = contentBox.y2;
|
|
||||||
showAppsButton.allocate(childBox, flags);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const Dash = new Lang.Class({
|
const Dash = new Lang.Class({
|
||||||
Name: 'Dash',
|
Name: 'Dash',
|
||||||
|
|
||||||
@ -376,25 +306,17 @@ const Dash = new Lang.Class({
|
|||||||
this._dragPlaceholder = null;
|
this._dragPlaceholder = null;
|
||||||
this._dragPlaceholderPos = -1;
|
this._dragPlaceholderPos = -1;
|
||||||
this._animatingPlaceholdersCount = 0;
|
this._animatingPlaceholdersCount = 0;
|
||||||
|
this._favRemoveTarget = null;
|
||||||
this._showLabelTimeoutId = 0;
|
this._showLabelTimeoutId = 0;
|
||||||
this._resetHoverTimeoutId = 0;
|
this._resetHoverTimeoutId = 0;
|
||||||
this._labelShowing = false;
|
this._labelShowing = false;
|
||||||
|
|
||||||
this._container = new DashActor();
|
this._box = new St.BoxLayout({ name: 'dash',
|
||||||
this._box = new St.BoxLayout({ vertical: true,
|
vertical: true,
|
||||||
clip_to_allocation: true });
|
clip_to_allocation: true });
|
||||||
this._box._delegate = this;
|
this._box._delegate = this;
|
||||||
this._container.add_actor(this._box);
|
|
||||||
|
|
||||||
this._showAppsIcon = new ShowAppsIcon();
|
this.actor = new St.Bin({ y_align: St.Align.START, child: this._box });
|
||||||
this._showAppsIcon.icon.setIconSize(this.iconSize);
|
|
||||||
this._hookUpLabel(this._showAppsIcon);
|
|
||||||
|
|
||||||
this.showAppsButton = this._showAppsIcon.toggleButton;
|
|
||||||
|
|
||||||
this._container.add_actor(this._showAppsIcon.actor);
|
|
||||||
|
|
||||||
this.actor = new St.Bin({ child: this._container });
|
|
||||||
this.actor.connect('notify::height', Lang.bind(this,
|
this.actor.connect('notify::height', Lang.bind(this,
|
||||||
function() {
|
function() {
|
||||||
if (this._maxHeight != this.actor.height)
|
if (this._maxHeight != this.actor.height)
|
||||||
@ -404,6 +326,7 @@ const Dash = new Lang.Class({
|
|||||||
|
|
||||||
this._workId = Main.initializeDeferredWork(this._box, Lang.bind(this, this._redisplay));
|
this._workId = Main.initializeDeferredWork(this._box, Lang.bind(this, this._redisplay));
|
||||||
|
|
||||||
|
this._tracker = Shell.WindowTracker.get_default();
|
||||||
this._appSystem = Shell.AppSystem.get_default();
|
this._appSystem = Shell.AppSystem.get_default();
|
||||||
|
|
||||||
this._appSystem.connect('installed-changed', Lang.bind(this, this._queueRedisplay));
|
this._appSystem.connect('installed-changed', Lang.bind(this, this._queueRedisplay));
|
||||||
@ -446,25 +369,54 @@ const Dash = new Lang.Class({
|
|||||||
|
|
||||||
_endDrag: function() {
|
_endDrag: function() {
|
||||||
this._clearDragPlaceholder();
|
this._clearDragPlaceholder();
|
||||||
this._showAppsIcon.setDragApp(null);
|
if (this._favRemoveTarget) {
|
||||||
|
this._favRemoveTarget.animateOutAndDestroy();
|
||||||
|
this._favRemoveTarget.actor.connect('destroy', Lang.bind(this,
|
||||||
|
function() {
|
||||||
|
this._favRemoveTarget = null;
|
||||||
|
}));
|
||||||
|
this._adjustIconSize();
|
||||||
|
}
|
||||||
DND.removeDragMonitor(this._dragMonitor);
|
DND.removeDragMonitor(this._dragMonitor);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDragMotion: function(dragEvent) {
|
_onDragMotion: function(dragEvent) {
|
||||||
let app = getAppFromSource(dragEvent.source);
|
let app = null;
|
||||||
if (app == null)
|
if (dragEvent.source instanceof AppDisplay.AppWellIcon)
|
||||||
|
app = this._appSystem.lookup_app(dragEvent.source.getId());
|
||||||
|
else if (dragEvent.source.metaWindow)
|
||||||
|
app = this._tracker.get_window_app(dragEvent.source.metaWindow);
|
||||||
|
else
|
||||||
return DND.DragMotionResult.CONTINUE;
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
|
||||||
let showAppsHovered =
|
let id = app.get_id();
|
||||||
this._showAppsIcon.actor.contains(dragEvent.targetActor);
|
|
||||||
|
|
||||||
if (!this._box.contains(dragEvent.targetActor) || showAppsHovered)
|
let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
|
||||||
|
|
||||||
|
let srcIsFavorite = (id in favorites);
|
||||||
|
|
||||||
|
if (srcIsFavorite &&
|
||||||
|
app.get_state() != Shell.AppState.RUNNING &&
|
||||||
|
dragEvent.source.actor &&
|
||||||
|
this.actor.contains (dragEvent.source.actor) &&
|
||||||
|
this._favRemoveTarget == null) {
|
||||||
|
this._favRemoveTarget = new RemoveFavoriteIcon();
|
||||||
|
this._favRemoveTarget.icon.setIconSize(this.iconSize);
|
||||||
|
this._box.add(this._favRemoveTarget.actor);
|
||||||
|
this._adjustIconSize();
|
||||||
|
this._favRemoveTarget.animateIn();
|
||||||
|
}
|
||||||
|
|
||||||
|
let favRemoveHovered = false;
|
||||||
|
if (this._favRemoveTarget)
|
||||||
|
favRemoveHovered =
|
||||||
|
this._favRemoveTarget.actor.contains(dragEvent.targetActor);
|
||||||
|
|
||||||
|
if (!this._box.contains(dragEvent.targetActor) || favRemoveHovered)
|
||||||
this._clearDragPlaceholder();
|
this._clearDragPlaceholder();
|
||||||
|
|
||||||
if (showAppsHovered)
|
if (this._favRemoveTarget)
|
||||||
this._showAppsIcon.setDragApp(app);
|
this._favRemoveTarget.setHover(favRemoveHovered);
|
||||||
else
|
|
||||||
this._showAppsIcon.setDragApp(null);
|
|
||||||
|
|
||||||
return DND.DragMotionResult.CONTINUE;
|
return DND.DragMotionResult.CONTINUE;
|
||||||
},
|
},
|
||||||
@ -480,17 +432,6 @@ const Dash = new Lang.Class({
|
|||||||
Main.queueDeferredWork(this._workId);
|
Main.queueDeferredWork(this._workId);
|
||||||
},
|
},
|
||||||
|
|
||||||
_hookUpLabel: function(item) {
|
|
||||||
item.child.connect('notify::hover', Lang.bind(this, function() {
|
|
||||||
this._onHover(item);
|
|
||||||
}));
|
|
||||||
|
|
||||||
Main.overview.connect('hiding', Lang.bind(this, function() {
|
|
||||||
this._labelShowing = false;
|
|
||||||
item.hideLabel();
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
_createAppItem: function(app) {
|
_createAppItem: function(app) {
|
||||||
let display = new AppDisplay.AppWellIcon(app,
|
let display = new AppDisplay.AppWellIcon(app,
|
||||||
{ setSizeManually: true,
|
{ setSizeManually: true,
|
||||||
@ -510,14 +451,25 @@ const Dash = new Lang.Class({
|
|||||||
item.setLabelText(app.get_name());
|
item.setLabelText(app.get_name());
|
||||||
// Override default AppWellIcon label_actor
|
// Override default AppWellIcon label_actor
|
||||||
display.actor.label_actor = item.label;
|
display.actor.label_actor = item.label;
|
||||||
|
|
||||||
|
|
||||||
display.icon.setIconSize(this.iconSize);
|
display.icon.setIconSize(this.iconSize);
|
||||||
this._hookUpLabel(item);
|
display.actor.connect('notify::hover',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this._onHover(item, display)
|
||||||
|
}));
|
||||||
|
|
||||||
|
Main.overview.connect('hiding',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this._labelShowing = false;
|
||||||
|
item.hideLabel();
|
||||||
|
}));
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onHover: function (item) {
|
_onHover: function (item, display) {
|
||||||
if (item.child.get_hover() && !item.child._delegate.isMenuUp) {
|
if (display.actor.get_hover() && !display.isMenuUp) {
|
||||||
if (this._showLabelTimeoutId == 0) {
|
if (this._showLabelTimeoutId == 0) {
|
||||||
let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT;
|
let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT;
|
||||||
this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
|
this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
|
||||||
@ -558,12 +510,18 @@ const Dash = new Lang.Class({
|
|||||||
!actor._delegate.animatingOut;
|
!actor._delegate.animatingOut;
|
||||||
});
|
});
|
||||||
|
|
||||||
iconChildren.push(this._showAppsIcon.actor);
|
if (iconChildren.length == 0) {
|
||||||
|
this._box.add_style_pseudo_class('empty');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._box.remove_style_pseudo_class('empty');
|
||||||
|
|
||||||
if (this._maxHeight == -1)
|
if (this._maxHeight == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let themeNode = this._container.get_theme_node();
|
|
||||||
|
let themeNode = this._box.get_theme_node();
|
||||||
let maxAllocation = new Clutter.ActorBox({ x1: 0, y1: 0,
|
let maxAllocation = new Clutter.ActorBox({ x1: 0, y1: 0,
|
||||||
x2: 42 /* whatever */,
|
x2: 42 /* whatever */,
|
||||||
y2: this._maxHeight });
|
y2: this._maxHeight });
|
||||||
@ -589,6 +547,7 @@ const Dash = new Lang.Class({
|
|||||||
[minHeight, natHeight] = iconChildren[0].get_preferred_height(-1);
|
[minHeight, natHeight] = iconChildren[0].get_preferred_height(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Subtract icon padding and box spacing from the available height
|
// Subtract icon padding and box spacing from the available height
|
||||||
availHeight -= iconChildren.length * (natHeight - this.iconSize) +
|
availHeight -= iconChildren.length * (natHeight - this.iconSize) +
|
||||||
(iconChildren.length - 1) * spacing;
|
(iconChildren.length - 1) * spacing;
|
||||||
@ -777,7 +736,11 @@ const Dash = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleDragOver : function(source, actor, x, y, time) {
|
handleDragOver : function(source, actor, x, y, time) {
|
||||||
let app = getAppFromSource(source);
|
let app = null;
|
||||||
|
if (source instanceof AppDisplay.AppWellIcon)
|
||||||
|
app = this._appSystem.lookup_app(source.getId());
|
||||||
|
else if (source.metaWindow)
|
||||||
|
app = this._tracker.get_window_app(source.metaWindow);
|
||||||
|
|
||||||
// Don't allow favoriting of transient apps
|
// Don't allow favoriting of transient apps
|
||||||
if (app == null || app.is_window_backed())
|
if (app == null || app.is_window_backed())
|
||||||
@ -858,7 +821,12 @@ const Dash = new Lang.Class({
|
|||||||
|
|
||||||
// Draggable target interface
|
// Draggable target interface
|
||||||
acceptDrop : function(source, actor, x, y, time) {
|
acceptDrop : function(source, actor, x, y, time) {
|
||||||
let app = getAppFromSource(source);
|
let app = null;
|
||||||
|
if (source instanceof AppDisplay.AppWellIcon) {
|
||||||
|
app = this._appSystem.lookup_app(source.getId());
|
||||||
|
} else if (source.metaWindow) {
|
||||||
|
app = this._tracker.get_window_app(source.metaWindow);
|
||||||
|
}
|
||||||
|
|
||||||
// Don't allow favoriting of transient apps
|
// Don't allow favoriting of transient apps
|
||||||
if (app == null || app.is_window_backed()) {
|
if (app == null || app.is_window_backed()) {
|
||||||
|
@ -70,8 +70,16 @@ const DateMenuButton = new Lang.Class({
|
|||||||
this._date.style_class = 'datemenu-date-label';
|
this._date.style_class = 'datemenu-date-label';
|
||||||
vbox.add(this._date);
|
vbox.add(this._date);
|
||||||
|
|
||||||
this._eventList = new Calendar.EventsList();
|
if (Main.sessionMode.showCalendarEvents) {
|
||||||
this._calendar = new Calendar.Calendar();
|
this._eventSource = new Calendar.DBusEventSource();
|
||||||
|
this._eventList = new Calendar.EventsList(this._eventSource);
|
||||||
|
} else {
|
||||||
|
this._eventSource = null;
|
||||||
|
this._eventList = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calendar
|
||||||
|
this._calendar = new Calendar.Calendar(this._eventSource);
|
||||||
|
|
||||||
this._calendar.connect('selected-date-changed',
|
this._calendar.connect('selected-date-changed',
|
||||||
Lang.bind(this, function(calendar, date) {
|
Lang.bind(this, function(calendar, date) {
|
||||||
@ -89,34 +97,31 @@ const DateMenuButton = new Lang.Class({
|
|||||||
separator.setColumnWidths(1);
|
separator.setColumnWidths(1);
|
||||||
vbox.add(separator.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
vbox.add(separator.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
||||||
|
|
||||||
item.actor.show_on_set_parent = false;
|
|
||||||
item.actor.can_focus = false;
|
item.actor.can_focus = false;
|
||||||
item.actor.reparent(vbox);
|
item.actor.reparent(vbox);
|
||||||
this._dateAndTimeSeparator = separator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._separator = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
|
if (Main.sessionMode.showCalendarEvents) {
|
||||||
pseudo_class: 'highlighted' });
|
// Add vertical separator
|
||||||
this._separator.connect('repaint', Lang.bind(this, _onVertSepRepaint));
|
|
||||||
hbox.add(this._separator);
|
|
||||||
|
|
||||||
// Fill up the second column
|
item = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
|
||||||
vbox = new St.BoxLayout({ name: 'calendarEventsArea',
|
pseudo_class: 'highlighted' });
|
||||||
vertical: true });
|
item.connect('repaint', Lang.bind(this, _onVertSepRepaint));
|
||||||
hbox.add(vbox, { expand: true });
|
hbox.add(item);
|
||||||
|
|
||||||
// Event list
|
// Fill up the second column
|
||||||
vbox.add(this._eventList.actor, { expand: true });
|
vbox = new St.BoxLayout({name: 'calendarEventsArea',
|
||||||
|
vertical: true});
|
||||||
|
hbox.add(vbox, { expand: true });
|
||||||
|
|
||||||
this._openCalendarItem = new PopupMenu.PopupMenuItem(_("Open Calendar"));
|
// Event list
|
||||||
this._openCalendarItem.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
|
vbox.add(this._eventList.actor, { expand: true });
|
||||||
this._openCalendarItem.actor.can_focus = false;
|
|
||||||
vbox.add(this._openCalendarItem.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
|
||||||
|
|
||||||
this._calendarSettings = new Gio.Settings({ schema: 'org.gnome.desktop.default-applications.office.calendar' });
|
item = new PopupMenu.PopupMenuItem(_("Open Calendar"));
|
||||||
this._calendarSettings.connect('changed::exec',
|
item.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
|
||||||
Lang.bind(this, this._calendarSettingsChanged));
|
item.actor.can_focus = false;
|
||||||
this._calendarSettingsChanged();
|
vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
||||||
|
}
|
||||||
|
|
||||||
// Whenever the menu is opened, select today
|
// Whenever the menu is opened, select today
|
||||||
this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
|
this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
|
||||||
@ -146,51 +151,6 @@ const DateMenuButton = new Lang.Class({
|
|||||||
this._clock = new GnomeDesktop.WallClock();
|
this._clock = new GnomeDesktop.WallClock();
|
||||||
this._clock.connect('notify::clock', Lang.bind(this, this._updateClockAndDate));
|
this._clock.connect('notify::clock', Lang.bind(this, this._updateClockAndDate));
|
||||||
this._updateClockAndDate();
|
this._updateClockAndDate();
|
||||||
|
|
||||||
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
|
||||||
this._sessionUpdated();
|
|
||||||
},
|
|
||||||
|
|
||||||
_calendarSettingsChanged: function() {
|
|
||||||
let exec = this._calendarSettings.get_string('exec');
|
|
||||||
let fullExec = GLib.find_program_in_path(exec);
|
|
||||||
this._openCalendarItem.actor.visible = fullExec != null;
|
|
||||||
},
|
|
||||||
|
|
||||||
_setEventsVisibility: function(visible) {
|
|
||||||
this._openCalendarItem.actor.visible = visible;
|
|
||||||
this._separator.visible = visible;
|
|
||||||
if (visible) {
|
|
||||||
let alignment = 0.25;
|
|
||||||
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
|
||||||
alignment = 1.0 - alignment;
|
|
||||||
this.menu._arrowAlignment = alignment;
|
|
||||||
this._eventList.actor.get_parent().show();
|
|
||||||
} else {
|
|
||||||
this.menu._arrowAlignment = 0.5;
|
|
||||||
this._eventList.actor.get_parent().hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_setEventSource: function(eventSource) {
|
|
||||||
this._calendar.setEventSource(eventSource);
|
|
||||||
this._eventList.setEventSource(eventSource);
|
|
||||||
},
|
|
||||||
|
|
||||||
_sessionUpdated: function() {
|
|
||||||
let eventSource;
|
|
||||||
let showEvents = Main.sessionMode.showCalendarEvents;
|
|
||||||
if (showEvents) {
|
|
||||||
eventSource = new Calendar.DBusEventSource();
|
|
||||||
} else {
|
|
||||||
eventSource = null;
|
|
||||||
}
|
|
||||||
this._setEventSource(eventSource);
|
|
||||||
this._setEventsVisibility(showEvents);
|
|
||||||
|
|
||||||
// This needs to be handled manually, as the code to
|
|
||||||
// autohide separators doesn't work across the vbox
|
|
||||||
this._dateAndTimeSeparator.actor.visible = Main.sessionMode.allowSettings;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateClockAndDate: function() {
|
_updateClockAndDate: function() {
|
||||||
@ -205,13 +165,14 @@ const DateMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
_onOpenCalendarActivate: function() {
|
_onOpenCalendarActivate: function() {
|
||||||
this.menu.close();
|
this.menu.close();
|
||||||
let tool = this._calendarSettings.get_string('exec');
|
let calendarSettings = new Gio.Settings({ schema: 'org.gnome.desktop.default-applications.office.calendar' });
|
||||||
|
let tool = calendarSettings.get_string('exec');
|
||||||
if (tool.length == 0 || tool.substr(0, 9) == 'evolution') {
|
if (tool.length == 0 || tool.substr(0, 9) == 'evolution') {
|
||||||
// TODO: pass the selected day
|
// TODO: pass the selected day
|
||||||
let app = Shell.AppSystem.get_default().lookup_app('evolution-calendar.desktop');
|
let app = Shell.AppSystem.get_default().lookup_app('evolution-calendar.desktop');
|
||||||
app.activate();
|
app.activate();
|
||||||
} else {
|
} else {
|
||||||
let needTerm = this._calendarSettings.get_boolean('needs-term');
|
let needTerm = calendarSettings.get_boolean('needs-term');
|
||||||
if (needTerm) {
|
if (needTerm) {
|
||||||
let terminalSettings = new Gio.Settings({ schema: 'org.gnome.desktop.default-applications.terminal' });
|
let terminalSettings = new Gio.Settings({ schema: 'org.gnome.desktop.default-applications.terminal' });
|
||||||
let term = terminalSettings.get_string('exec');
|
let term = terminalSettings.get_string('exec');
|
||||||
|
13
js/ui/dnd.js
13
js/ui/dnd.js
@ -235,10 +235,6 @@ const _Draggable = new Lang.Class({
|
|||||||
|
|
||||||
if (this.actor._delegate && this.actor._delegate.getDragActor) {
|
if (this.actor._delegate && this.actor._delegate.getDragActor) {
|
||||||
this._dragActor = this.actor._delegate.getDragActor(this._dragStartX, this._dragStartY);
|
this._dragActor = this.actor._delegate.getDragActor(this._dragStartX, this._dragStartY);
|
||||||
this._dragActor.reparent(Main.uiGroup);
|
|
||||||
this._dragActor.raise_top();
|
|
||||||
Shell.util_set_hidden_from_pick(this._dragActor, true);
|
|
||||||
|
|
||||||
// Drag actor does not always have to be the same as actor. For example drag actor
|
// Drag actor does not always have to be the same as actor. For example drag actor
|
||||||
// can be an image that's part of the actor. So to perform "snap back" correctly we need
|
// can be an image that's part of the actor. So to perform "snap back" correctly we need
|
||||||
// to know what was the drag actor source.
|
// to know what was the drag actor source.
|
||||||
@ -267,17 +263,12 @@ const _Draggable = new Lang.Class({
|
|||||||
this._dragOffsetY = this._dragActor.y - this._dragStartY;
|
this._dragOffsetY = this._dragActor.y - this._dragStartY;
|
||||||
} else {
|
} else {
|
||||||
this._dragActor = this.actor;
|
this._dragActor = this.actor;
|
||||||
|
|
||||||
this._dragActorSource = undefined;
|
this._dragActorSource = undefined;
|
||||||
this._dragOrigParent = this.actor.get_parent();
|
this._dragOrigParent = this.actor.get_parent();
|
||||||
this._dragOrigX = this._dragActor.x;
|
this._dragOrigX = this._dragActor.x;
|
||||||
this._dragOrigY = this._dragActor.y;
|
this._dragOrigY = this._dragActor.y;
|
||||||
this._dragOrigScale = this._dragActor.scale_x;
|
this._dragOrigScale = this._dragActor.scale_x;
|
||||||
|
|
||||||
this._dragActor.reparent(Main.uiGroup);
|
|
||||||
this._dragActor.raise_top();
|
|
||||||
Shell.util_set_hidden_from_pick(this._dragActor, true);
|
|
||||||
|
|
||||||
let [actorStageX, actorStageY] = this.actor.get_transformed_position();
|
let [actorStageX, actorStageY] = this.actor.get_transformed_position();
|
||||||
this._dragOffsetX = actorStageX - this._dragStartX;
|
this._dragOffsetX = actorStageX - this._dragStartX;
|
||||||
this._dragOffsetY = actorStageY - this._dragStartY;
|
this._dragOffsetY = actorStageY - this._dragStartY;
|
||||||
@ -289,6 +280,10 @@ const _Draggable = new Lang.Class({
|
|||||||
scaledHeight / this.actor.height);
|
scaledHeight / this.actor.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._dragActor.reparent(Main.uiGroup);
|
||||||
|
this._dragActor.raise_top();
|
||||||
|
Shell.util_set_hidden_from_pick(this._dragActor, true);
|
||||||
|
|
||||||
this._dragOrigOpacity = this._dragActor.opacity;
|
this._dragOrigOpacity = this._dragActor.opacity;
|
||||||
if (this._dragActorOpacity != undefined)
|
if (this._dragActorOpacity != undefined)
|
||||||
this._dragActor.opacity = this._dragActorOpacity;
|
this._dragActor.opacity = this._dragActorOpacity;
|
||||||
|
@ -34,7 +34,6 @@ const GnomeSession = imports.misc.gnomeSession;
|
|||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
const UserMenu = imports.ui.userMenu;
|
|
||||||
|
|
||||||
let _endSessionDialog = null;
|
let _endSessionDialog = null;
|
||||||
|
|
||||||
@ -90,7 +89,7 @@ const shutdownDialogContent = {
|
|||||||
label: C_("button", "Restart") },
|
label: C_("button", "Restart") },
|
||||||
{ signal: 'ConfirmedShutdown',
|
{ signal: 'ConfirmedShutdown',
|
||||||
label: C_("button", "Power Off") }],
|
label: C_("button", "Power Off") }],
|
||||||
iconName: 'system-shutdown-symbolic',
|
iconName: 'system-shutdown',
|
||||||
iconStyleClass: 'end-session-dialog-shutdown-icon'
|
iconStyleClass: 'end-session-dialog-shutdown-icon'
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -105,7 +104,7 @@ const restartDialogContent = {
|
|||||||
endDescription: _("Restarting the system."),
|
endDescription: _("Restarting the system."),
|
||||||
confirmButtons: [{ signal: 'ConfirmedReboot',
|
confirmButtons: [{ signal: 'ConfirmedReboot',
|
||||||
label: C_("button", "Restart") }],
|
label: C_("button", "Restart") }],
|
||||||
iconName: 'view-refresh-symbolic',
|
iconName: 'system-shutdown',
|
||||||
iconStyleClass: 'end-session-dialog-shutdown-icon'
|
iconStyleClass: 'end-session-dialog-shutdown-icon'
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -161,7 +160,6 @@ const ListItem = new Lang.Class({
|
|||||||
|
|
||||||
this._descriptionLabel = new St.Label({ text: this._reason,
|
this._descriptionLabel = new St.Label({ text: this._reason,
|
||||||
style_class: 'end-session-dialog-app-list-item-description' });
|
style_class: 'end-session-dialog-app-list-item-description' });
|
||||||
this.actor.label_actor = this._nameLabel;
|
|
||||||
textLayout.add(this._descriptionLabel,
|
textLayout.add(this._descriptionLabel,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
x_fill: true });
|
x_fill: true });
|
||||||
@ -218,34 +216,6 @@ function init() {
|
|||||||
_endSessionDialog = new EndSessionDialog();
|
_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({
|
const EndSessionDialog = new Lang.Class({
|
||||||
Name: 'EndSessionDialog',
|
Name: 'EndSessionDialog',
|
||||||
Extends: ModalDialog.ModalDialog,
|
Extends: ModalDialog.ModalDialog,
|
||||||
@ -323,8 +293,8 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
scrollView.hide();
|
scrollView.hide();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._exporter = new EndSessionExporter();
|
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(EndSessionDialogIface, this);
|
||||||
this._exporter.connect('open', Lang.bind(this, this._onOpenRequest));
|
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog');
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDestroy: function() {
|
_onDestroy: function() {
|
||||||
@ -332,6 +302,41 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
this._user.disconnect(this._userChangedId);
|
this._user.disconnect(this._userChangedId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_setIconFromFile: function(iconFile, styleClass) {
|
||||||
|
if (styleClass)
|
||||||
|
this._iconBin.set_style_class_name(styleClass);
|
||||||
|
this._iconBin.set_style(null);
|
||||||
|
|
||||||
|
this._iconBin.child = null;
|
||||||
|
if (iconFile) {
|
||||||
|
this._iconBin.show();
|
||||||
|
this._iconBin.set_style('background-image: url("' + iconFile + '");' +
|
||||||
|
'background-size: contain;');
|
||||||
|
} else {
|
||||||
|
this._iconBin.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_setIconFromName: function(iconName, styleClass) {
|
||||||
|
if (styleClass)
|
||||||
|
this._iconBin.set_style_class_name(styleClass);
|
||||||
|
this._iconBin.set_style(null);
|
||||||
|
|
||||||
|
if (iconName != null) {
|
||||||
|
let textureCache = St.TextureCache.get_default();
|
||||||
|
let icon = textureCache.load_icon_name(this._iconBin.get_theme_node(),
|
||||||
|
iconName,
|
||||||
|
St.IconType.SYMBOLIC,
|
||||||
|
_DIALOG_ICON_SIZE);
|
||||||
|
|
||||||
|
this._iconBin.child = icon;
|
||||||
|
this._iconBin.show();
|
||||||
|
} else {
|
||||||
|
this._iconBin.child = null;
|
||||||
|
this._iconBin.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_updateDescription: function() {
|
_updateDescription: function() {
|
||||||
if (this.state != ModalDialog.State.OPENING &&
|
if (this.state != ModalDialog.State.OPENING &&
|
||||||
this.state != ModalDialog.State.OPENED)
|
this.state != ModalDialog.State.OPENED)
|
||||||
@ -380,16 +385,16 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
let dialogContent = DialogContent[this._type];
|
let dialogContent = DialogContent[this._type];
|
||||||
if (dialogContent.iconName) {
|
|
||||||
this._iconBin.child = new St.Icon({ icon_name: dialogContent.iconName,
|
if (this._user.is_loaded && !dialogContent.iconName) {
|
||||||
icon_size: _DIALOG_ICON_SIZE,
|
let iconFile = this._user.get_icon_file();
|
||||||
style_class: dialogContent.iconStyleClass });
|
if (GLib.file_test(iconFile, GLib.FileTest.EXISTS))
|
||||||
} else {
|
this._setIconFromFile(iconFile, dialogContent.iconStyleClass);
|
||||||
let avatarWidget = new UserMenu.UserAvatarWidget(this._user,
|
else
|
||||||
{ iconSize: _DIALOG_ICON_SIZE,
|
this._setIconFromName('avatar-default', dialogContent.iconStyleClass);
|
||||||
styleClass: dialogContent.iconStyleClass });
|
} else if (dialogContent.iconName) {
|
||||||
this._iconBin.child = avatarWidget.actor;
|
this._setIconFromName(dialogContent.iconName,
|
||||||
avatarWidget.update();
|
dialogContent.iconStyleClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._updateDescription();
|
this._updateDescription();
|
||||||
@ -415,19 +420,19 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
|
|
||||||
close: function() {
|
close: function() {
|
||||||
this.parent();
|
this.parent();
|
||||||
this._exporter.close();
|
this._dbusImpl.emit_signal('Closed', null);
|
||||||
},
|
},
|
||||||
|
|
||||||
cancel: function() {
|
cancel: function() {
|
||||||
this._stopTimer();
|
this._stopTimer();
|
||||||
this._exporter.cancel();
|
this._dbusImpl.emit_signal('Canceled', null);
|
||||||
this.close(global.get_current_time());
|
this.close(global.get_current_time());
|
||||||
},
|
},
|
||||||
|
|
||||||
_confirm: function(signal) {
|
_confirm: function(signal) {
|
||||||
this._fadeOutDialog();
|
this._fadeOutDialog();
|
||||||
this._stopTimer();
|
this._stopTimer();
|
||||||
this._exporter.confirm(signal);
|
this._dbusImpl.emit_signal(signal, null);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onOpened: function() {
|
_onOpened: function() {
|
||||||
@ -480,7 +485,7 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
this._updateContent();
|
this._updateContent();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onOpenRequest: function(exporter, parameters, invocation) {
|
OpenAsync: function(parameters, invocation) {
|
||||||
let [type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths] = parameters;
|
let [type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths] = parameters;
|
||||||
this._totalSecondsToStayOpen = totalSecondsToStayOpen;
|
this._totalSecondsToStayOpen = totalSecondsToStayOpen;
|
||||||
this._inhibitors = [];
|
this._inhibitors = [];
|
||||||
@ -494,10 +499,7 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < inhibitorObjectPaths.length; i++) {
|
for (let i = 0; i < inhibitorObjectPaths.length; i++) {
|
||||||
let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i]);
|
let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i], Lang.bind(this, function(proxy, error) {
|
||||||
inhibitor.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(proxy, result) {
|
|
||||||
proxy.init_finish(result);
|
|
||||||
|
|
||||||
this._onInhibitorLoaded(proxy);
|
this._onInhibitorLoaded(proxy);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ function uninstallExtension(uuid) {
|
|||||||
if (extension.type != ExtensionUtils.ExtensionType.PER_USER)
|
if (extension.type != ExtensionUtils.ExtensionType.PER_USER)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!ExtensionSystem.unloadExtension(extension))
|
if (!ExtensionSystem.unloadExtension(uuid))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
FileUtils.recursivelyDeleteDir(extension.dir, true);
|
FileUtils.recursivelyDeleteDir(extension.dir, true);
|
||||||
@ -82,7 +82,7 @@ function gotExtensionZipFile(session, message, uuid, dir, callback, errback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let [file, stream] = Gio.File.new_tmp('XXXXXX.shell-extension.zip');
|
let [file, stream] = Gio.File.new_tmp('XXXXXX.shell-extension.zip');
|
||||||
let contents = message.response_body.flatten().get_as_bytes();
|
let contents = message.response_body.flatten().as_bytes();
|
||||||
stream.output_stream.write_bytes(contents, null);
|
stream.output_stream.write_bytes(contents, null);
|
||||||
stream.close(null);
|
stream.close(null);
|
||||||
let [success, pid] = GLib.spawn_async(null,
|
let [success, pid] = GLib.spawn_async(null,
|
||||||
@ -124,7 +124,7 @@ function updateExtension(uuid) {
|
|||||||
let oldExtension = ExtensionUtils.extensions[uuid];
|
let oldExtension = ExtensionUtils.extensions[uuid];
|
||||||
let extensionDir = oldExtension.dir;
|
let extensionDir = oldExtension.dir;
|
||||||
|
|
||||||
if (!ExtensionSystem.unloadExtension(oldExtension))
|
if (!ExtensionSystem.unloadExtension(uuid))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FileUtils.recursivelyMoveDir(extensionDir, oldExtensionTmpDir);
|
FileUtils.recursivelyMoveDir(extensionDir, oldExtensionTmpDir);
|
||||||
@ -135,7 +135,7 @@ function updateExtension(uuid) {
|
|||||||
try {
|
try {
|
||||||
ExtensionSystem.loadExtension(extension);
|
ExtensionSystem.loadExtension(extension);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
ExtensionSystem.unloadExtension(extension);
|
ExtensionSystem.unloadExtension(uuid);
|
||||||
|
|
||||||
logError(e, 'Error loading extension %s'.format(uuid));
|
logError(e, 'Error loading extension %s'.format(uuid));
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ const Gio = imports.gi.Gio;
|
|||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
const ExtensionUtils = imports.misc.extensionUtils;
|
||||||
const Main = imports.ui.main;
|
|
||||||
|
|
||||||
const ExtensionState = {
|
const ExtensionState = {
|
||||||
ENABLED: 1,
|
ENABLED: 1,
|
||||||
@ -39,9 +38,6 @@ const disconnect = Lang.bind(_signals, _signals.disconnect);
|
|||||||
|
|
||||||
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
|
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
|
||||||
|
|
||||||
var initted = false;
|
|
||||||
var enabled;
|
|
||||||
|
|
||||||
function disableExtension(uuid) {
|
function disableExtension(uuid) {
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
let extension = ExtensionUtils.extensions[uuid];
|
||||||
if (!extension)
|
if (!extension)
|
||||||
@ -106,6 +102,8 @@ function enableExtension(uuid) {
|
|||||||
|
|
||||||
extensionOrder.push(uuid);
|
extensionOrder.push(uuid);
|
||||||
|
|
||||||
|
extension.stateObj.enable();
|
||||||
|
|
||||||
let stylesheetFile = extension.dir.get_child('stylesheet.css');
|
let stylesheetFile = extension.dir.get_child('stylesheet.css');
|
||||||
if (stylesheetFile.query_exists(null)) {
|
if (stylesheetFile.query_exists(null)) {
|
||||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||||
@ -113,8 +111,6 @@ function enableExtension(uuid) {
|
|||||||
extension.stylesheet = stylesheetFile;
|
extension.stylesheet = stylesheetFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
extension.stateObj.enable();
|
|
||||||
|
|
||||||
extension.state = ExtensionState.ENABLED;
|
extension.state = ExtensionState.ENABLED;
|
||||||
_signals.emit('extension-state-changed', extension);
|
_signals.emit('extension-state-changed', extension);
|
||||||
}
|
}
|
||||||
@ -162,32 +158,23 @@ function loadExtension(extension) {
|
|||||||
_signals.emit('extension-state-changed', extension);
|
_signals.emit('extension-state-changed', extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
function unloadExtension(extension) {
|
function unloadExtension(uuid) {
|
||||||
|
let extension = ExtensionUtils.extensions[uuid];
|
||||||
|
if (!extension)
|
||||||
|
return false;
|
||||||
|
|
||||||
// Try to disable it -- if it's ERROR'd, we can't guarantee that,
|
// Try to disable it -- if it's ERROR'd, we can't guarantee that,
|
||||||
// but it will be removed on next reboot, and hopefully nothing
|
// but it will be removed on next reboot, and hopefully nothing
|
||||||
// broke too much.
|
// broke too much.
|
||||||
disableExtension(extension.uuid);
|
disableExtension(uuid);
|
||||||
|
|
||||||
extension.state = ExtensionState.UNINSTALLED;
|
extension.state = ExtensionState.UNINSTALLED;
|
||||||
_signals.emit('extension-state-changed', extension);
|
_signals.emit('extension-state-changed', extension);
|
||||||
|
|
||||||
delete ExtensionUtils.extensions[extension.uuid];
|
delete ExtensionUtils.extensions[uuid];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function reloadExtension(oldExtension) {
|
|
||||||
// Grab the things we'll need to pass to createExtensionObject
|
|
||||||
// to reload it.
|
|
||||||
let { uuid: uuid, dir: dir, type: type } = oldExtension;
|
|
||||||
|
|
||||||
// Then unload the old extension.
|
|
||||||
unloadExtension(oldExtension);
|
|
||||||
|
|
||||||
// Now, recreate the extension and load it.
|
|
||||||
let newExtension = ExtensionUtils.createExtensionObject(uuid, dir, type);
|
|
||||||
loadExtension(newExtension);
|
|
||||||
}
|
|
||||||
|
|
||||||
function initExtension(uuid) {
|
function initExtension(uuid) {
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
let extension = ExtensionUtils.extensions[uuid];
|
||||||
let dir = extension.dir;
|
let dir = extension.dir;
|
||||||
@ -220,9 +207,6 @@ function initExtension(uuid) {
|
|||||||
function onEnabledExtensionsChanged() {
|
function onEnabledExtensionsChanged() {
|
||||||
let newEnabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
let newEnabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
||||||
|
|
||||||
if (!enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Find and enable all the newly enabled extensions: UUIDs found in the
|
// Find and enable all the newly enabled extensions: UUIDs found in the
|
||||||
// new setting, but not in the old one.
|
// new setting, but not in the old one.
|
||||||
newEnabledExtensions.filter(function(uuid) {
|
newEnabledExtensions.filter(function(uuid) {
|
||||||
@ -250,7 +234,7 @@ function onEnabledExtensionsChanged() {
|
|||||||
enabledExtensions = newEnabledExtensions;
|
enabledExtensions = newEnabledExtensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _loadExtensions() {
|
function loadExtensions() {
|
||||||
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
|
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
|
||||||
enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
||||||
|
|
||||||
@ -264,43 +248,3 @@ function _loadExtensions() {
|
|||||||
});
|
});
|
||||||
finder.scanExtensions();
|
finder.scanExtensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
function enableAllExtensions() {
|
|
||||||
if (enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!initted) {
|
|
||||||
_loadExtensions();
|
|
||||||
initted = true;
|
|
||||||
} else {
|
|
||||||
enabledExtensions.forEach(function(uuid) {
|
|
||||||
enableExtension(uuid);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function disableAllExtensions() {
|
|
||||||
if (!enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (initted) {
|
|
||||||
enabledExtensions.forEach(function(uuid) {
|
|
||||||
disableExtension(uuid);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _sessionUpdated() {
|
|
||||||
if (Main.sessionMode.allowExtensions)
|
|
||||||
enableAllExtensions();
|
|
||||||
else
|
|
||||||
disableAllExtensions();
|
|
||||||
}
|
|
||||||
|
|
||||||
function init() {
|
|
||||||
Main.sessionMode.connect('updated', _sessionUpdated);
|
|
||||||
_sessionUpdated();
|
|
||||||
}
|
|
||||||
|
@ -1,358 +0,0 @@
|
|||||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
|
||||||
const Gtk = imports.gi.Gtk;
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const Meta = imports.gi.Meta;
|
|
||||||
const Shell = imports.gi.Shell;
|
|
||||||
const St = imports.gi.St;
|
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
|
||||||
const Params = imports.misc.params;
|
|
||||||
|
|
||||||
function _navigateActor(actor) {
|
|
||||||
if (!actor)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let needsGrab = true;
|
|
||||||
if (actor instanceof St.Widget)
|
|
||||||
needsGrab = !actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
|
||||||
if (needsGrab)
|
|
||||||
actor.grab_key_focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// GrabHelper:
|
|
||||||
// @owner: the actor that owns the GrabHelper
|
|
||||||
//
|
|
||||||
// Creates a new GrabHelper object, for dealing with keyboard and pointer grabs
|
|
||||||
// associated with a set of actors.
|
|
||||||
//
|
|
||||||
// Note that the grab can be automatically dropped at any time by the user, and
|
|
||||||
// your code just needs to deal with it; you shouldn't adjust behavior directly
|
|
||||||
// after you call ungrab(), but instead pass an 'onUngrab' callback when you
|
|
||||||
// call grab().
|
|
||||||
const GrabHelper = new Lang.Class({
|
|
||||||
Name: 'GrabHelper',
|
|
||||||
|
|
||||||
_init: function(owner) {
|
|
||||||
this._owner = owner;
|
|
||||||
|
|
||||||
this._grabStack = [];
|
|
||||||
|
|
||||||
this._actors = [];
|
|
||||||
this._capturedEventId = 0;
|
|
||||||
this._eventId = 0;
|
|
||||||
this._keyFocusNotifyId = 0;
|
|
||||||
this._focusWindowChangedId = 0;
|
|
||||||
this._ignoreRelease = false;
|
|
||||||
|
|
||||||
this._modalCount = 0;
|
|
||||||
this._grabFocusCount = 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
// addActor:
|
|
||||||
// @actor: an actor
|
|
||||||
//
|
|
||||||
// Adds @actor to the set of actors that are allowed to process events
|
|
||||||
// during a grab.
|
|
||||||
addActor: function(actor) {
|
|
||||||
actor.__grabHelperDestroyId = actor.connect('destroy', Lang.bind(this, function() { this.removeActor(actor); }));
|
|
||||||
this._actors.push(actor);
|
|
||||||
},
|
|
||||||
|
|
||||||
// removeActor:
|
|
||||||
// @actor: an actor
|
|
||||||
//
|
|
||||||
// Removes @actor from the set of actors that are allowed to
|
|
||||||
// process events during a grab.
|
|
||||||
removeActor: function(actor) {
|
|
||||||
let index = this._actors.indexOf(actor);
|
|
||||||
if (index != -1)
|
|
||||||
this._actors.splice(index, 1);
|
|
||||||
if (actor.__grabHelperDestroyId) {
|
|
||||||
actor.disconnect(actor.__grabHelperDestroyId);
|
|
||||||
delete actor.__grabHelperDestroyId;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_isWithinGrabbedActor: function(actor) {
|
|
||||||
while (actor) {
|
|
||||||
if (this._actors.indexOf(actor) != -1)
|
|
||||||
return true;
|
|
||||||
actor = actor.get_parent();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
get currentGrab() {
|
|
||||||
return this._grabStack[this._grabStack.length - 1] || {};
|
|
||||||
},
|
|
||||||
|
|
||||||
_findStackIndex: function(actor) {
|
|
||||||
if (!actor)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
for (let i = 0; i < this._grabStack.length; i++) {
|
|
||||||
if (this._grabStack[i].actor === actor)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
},
|
|
||||||
|
|
||||||
isActorGrabbed: function(actor) {
|
|
||||||
return this._findStackIndex(actor) >= 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
// grab:
|
|
||||||
// @params: A bunch of parameters, see below
|
|
||||||
//
|
|
||||||
// Grabs the mouse and keyboard, according to the GrabHelper's
|
|
||||||
// parameters. If @newFocus is not %null, then the keyboard focus
|
|
||||||
// is moved to the first #StWidget:can-focus widget inside it.
|
|
||||||
//
|
|
||||||
// The grab will automatically be dropped if:
|
|
||||||
// - The user clicks outside the grabbed actors
|
|
||||||
// - The user types Escape
|
|
||||||
// - The keyboard focus is moved outside the grabbed actors
|
|
||||||
// - A window is focused
|
|
||||||
//
|
|
||||||
// If @params.actor is not null, then it will be focused as the
|
|
||||||
// new actor. If you attempt to grab an already focused actor, the
|
|
||||||
// request to be focused will be ignored. The actor will not be
|
|
||||||
// added to the grab stack, so do not call a paired ungrab().
|
|
||||||
//
|
|
||||||
// If @params contains { modal: true }, then grab() will push a modal
|
|
||||||
// on the owner of the GrabHelper. As long as there is at least one
|
|
||||||
// { modal: true } actor on the grab stack, the grab will be kept.
|
|
||||||
// When the last { modal: true } actor is ungrabbed, then the modal
|
|
||||||
// will be dropped. A modal grab can fail if there is already a grab
|
|
||||||
// in effect from aother application; in this case the function returns
|
|
||||||
// false and nothing happens. Non-modal grabs can never fail.
|
|
||||||
//
|
|
||||||
// If @params contains { grabFocus: true }, then if you call grab()
|
|
||||||
// while the shell is outside the overview, it will set the stage
|
|
||||||
// input mode to %Shell.StageInputMode.FOCUSED, and ungrab() will
|
|
||||||
// revert it back, and re-focus the previously-focused window (if
|
|
||||||
// another window hasn't been explicitly focused before then).
|
|
||||||
grab: function(params) {
|
|
||||||
params = Params.parse(params, { actor: null,
|
|
||||||
modal: false,
|
|
||||||
grabFocus: false,
|
|
||||||
onUngrab: null });
|
|
||||||
|
|
||||||
let focus = global.stage.key_focus;
|
|
||||||
let hadFocus = focus && this._isWithinGrabbedActor(focus);
|
|
||||||
let newFocus = params.actor;
|
|
||||||
|
|
||||||
if (this.isActorGrabbed(params.actor))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
params.savedFocus = focus;
|
|
||||||
|
|
||||||
if (params.modal && !this._takeModalGrab())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (params.grabFocus && !this._takeFocusGrab(hadFocus))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (hadFocus || params.grabFocus)
|
|
||||||
_navigateActor(newFocus);
|
|
||||||
|
|
||||||
this._grabStack.push(params);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
_takeModalGrab: function() {
|
|
||||||
let firstGrab = (this._modalCount == 0);
|
|
||||||
if (firstGrab) {
|
|
||||||
if (!Main.pushModal(this._owner))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
|
|
||||||
this._eventId = global.stage.connect('event', Lang.bind(this, this._onEvent));
|
|
||||||
}
|
|
||||||
|
|
||||||
this._modalCount++;
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
_releaseModalGrab: function() {
|
|
||||||
this._modalCount--;
|
|
||||||
if (this._modalCount > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (this._capturedEventId > 0) {
|
|
||||||
global.stage.disconnect(this._capturedEventId);
|
|
||||||
this._capturedEventId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._eventId > 0) {
|
|
||||||
global.stage.disconnect(this._eventId);
|
|
||||||
this._eventId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Main.popModal(this._owner);
|
|
||||||
global.sync_pointer();
|
|
||||||
},
|
|
||||||
|
|
||||||
_takeFocusGrab: function(hadFocus) {
|
|
||||||
let firstGrab = (this._grabFocusCount == 0);
|
|
||||||
if (firstGrab) {
|
|
||||||
let metaDisplay = global.screen.get_display();
|
|
||||||
|
|
||||||
this._grabbedFromKeynav = hadFocus;
|
|
||||||
this._preGrabInputMode = global.stage_input_mode;
|
|
||||||
this._prevFocusedWindow = metaDisplay.focus_window;
|
|
||||||
|
|
||||||
if (this._preGrabInputMode == Shell.StageInputMode.NONREACTIVE ||
|
|
||||||
this._preGrabInputMode == Shell.StageInputMode.NORMAL) {
|
|
||||||
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._keyFocusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
|
|
||||||
this._focusWindowChangedId = metaDisplay.connect('notify::focus-window', Lang.bind(this, this._focusWindowChanged));
|
|
||||||
}
|
|
||||||
|
|
||||||
this._grabFocusCount++;
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
_releaseFocusGrab: function() {
|
|
||||||
this._grabFocusCount--;
|
|
||||||
if (this._grabFocusCount > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (this._keyFocusNotifyId > 0) {
|
|
||||||
global.stage.disconnect(this._keyFocusNotifyId);
|
|
||||||
this._keyFocusNotifyId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._focusWindowChanged > 0) {
|
|
||||||
let metaDisplay = global.screen.get_display();
|
|
||||||
metaDisplay.disconnect(this._focusWindowChangedId);
|
|
||||||
this._focusWindowChangedId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let prePopInputMode = global.stage_input_mode;
|
|
||||||
|
|
||||||
if (this._grabbedFromKeynav) {
|
|
||||||
if (this._preGrabInputMode == Shell.StageInputMode.FOCUSED &&
|
|
||||||
prePopInputMode != Shell.StageInputMode.FULLSCREEN)
|
|
||||||
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._prevFocusedWindow) {
|
|
||||||
let metaDisplay = global.screen.get_display();
|
|
||||||
if (!metaDisplay.focus_window) {
|
|
||||||
metaDisplay.set_input_focus_window(this._prevFocusedWindow,
|
|
||||||
false, global.get_current_time());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// ignoreRelease:
|
|
||||||
//
|
|
||||||
// Make sure that the next button release event evaluated by the
|
|
||||||
// capture event handler returns false. This is designed for things
|
|
||||||
// like the ComboBoxMenu that go away on press, but need to eat
|
|
||||||
// the next release event.
|
|
||||||
ignoreRelease: function() {
|
|
||||||
this._ignoreRelease = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
// ungrab:
|
|
||||||
// @params: The parameters for the grab; see below.
|
|
||||||
//
|
|
||||||
// Pops an actor from the grab stack, potentially dropping the grab.
|
|
||||||
//
|
|
||||||
// If the actor that was popped from the grab stack was not the actor
|
|
||||||
// That was passed in, this call is ignored.
|
|
||||||
ungrab: function(params) {
|
|
||||||
params = Params.parse(params, { actor: this.currentGrab.actor });
|
|
||||||
|
|
||||||
let grabStackIndex = this._findStackIndex(params.actor);
|
|
||||||
if (grabStackIndex < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let focus = global.stage.key_focus;
|
|
||||||
let hadFocus = focus && this._isWithinGrabbedActor(focus);
|
|
||||||
|
|
||||||
let poppedGrabs = this._grabStack.slice(grabStackIndex);
|
|
||||||
// "Pop" all newly ungrabbed actors off the grab stack
|
|
||||||
// by truncating the array.
|
|
||||||
this._grabStack.length = grabStackIndex;
|
|
||||||
|
|
||||||
for (let i = poppedGrabs.length - 1; i >= 0; i--) {
|
|
||||||
let poppedGrab = poppedGrabs[i];
|
|
||||||
|
|
||||||
if (poppedGrab.onUngrab)
|
|
||||||
poppedGrab.onUngrab();
|
|
||||||
|
|
||||||
if (poppedGrab.modal)
|
|
||||||
this._releaseModalGrab();
|
|
||||||
|
|
||||||
if (poppedGrab.grabFocus)
|
|
||||||
this._releaseFocusGrab();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hadFocus) {
|
|
||||||
let poppedGrab = poppedGrabs[0];
|
|
||||||
_navigateActor(poppedGrab.savedFocus);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_onCapturedEvent: function(actor, event) {
|
|
||||||
let type = event.type();
|
|
||||||
let press = type == Clutter.EventType.BUTTON_PRESS;
|
|
||||||
let release = type == Clutter.EventType.BUTTON_RELEASE;
|
|
||||||
let button = press || release;
|
|
||||||
|
|
||||||
if (release && this._ignoreRelease) {
|
|
||||||
this._ignoreRelease = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!button && this._modalCount == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (this._isWithinGrabbedActor(event.get_source()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (Main.keyboard.shouldTakeEvent(event))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (button) {
|
|
||||||
// If we have a press event, ignore the next event,
|
|
||||||
// which should be a release event.
|
|
||||||
if (press)
|
|
||||||
this._ignoreRelease = true;
|
|
||||||
this.ungrab({ actor: this._grabStack[0].actor });
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._modalCount > 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
// We catch 'event' rather than 'key-press-event' so that we get
|
|
||||||
// a chance to run before the overview's own Escape check
|
|
||||||
_onEvent: function(actor, event) {
|
|
||||||
if (event.type() == Clutter.EventType.KEY_PRESS &&
|
|
||||||
event.get_key_symbol() == Clutter.KEY_Escape) {
|
|
||||||
this.ungrab();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
_onKeyFocusChanged: function() {
|
|
||||||
let focus = global.stage.key_focus;
|
|
||||||
if (!focus || !this._isWithinGrabbedActor(focus))
|
|
||||||
this.ungrab();
|
|
||||||
},
|
|
||||||
|
|
||||||
_focusWindowChanged: function() {
|
|
||||||
let metaDisplay = global.screen.get_display();
|
|
||||||
if (metaDisplay.focus_window != null)
|
|
||||||
this.ungrab();
|
|
||||||
}
|
|
||||||
});
|
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
const Caribou = imports.gi.Caribou;
|
const Caribou = imports.gi.Caribou;
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const DBus = imports.dbus;
|
||||||
const Gdk = imports.gi.Gdk;
|
const Gdk = imports.gi.Gdk;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
@ -190,20 +191,17 @@ const Key = new Lang.Class({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const Keyboard = new Gio.DBusImplementerClass({
|
const Keyboard = new Lang.Class({
|
||||||
// HACK: we can't set Name, because it collides with Name dbus property
|
// HACK: we can't set Name, because it collides with Name dbus property
|
||||||
// Name: 'Keyboard',
|
// Name: 'Keyboard',
|
||||||
Interface: CaribouKeyboardIface,
|
|
||||||
|
|
||||||
_init: function () {
|
_init: function () {
|
||||||
this.parent();
|
this._impl = Gio.DBusExportedObject.wrapJSObject(CaribouKeyboardIface, this);
|
||||||
this.export(Gio.DBus.session, '/org/gnome/Caribou/Keyboard');
|
this._impl.export(Gio.DBus.session, '/org/gnome/Caribou/Keyboard');
|
||||||
|
|
||||||
this.actor = null;
|
this.actor = null;
|
||||||
this._focusInTray = false;
|
|
||||||
this._focusInExtendedKeys = false;
|
|
||||||
|
|
||||||
this._timestamp = global.display.get_current_time_roundtrip();
|
this._timestamp = global.get_current_time();
|
||||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._redraw));
|
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._redraw));
|
||||||
|
|
||||||
this._keyboardSettings = new Gio.Settings({ schema: KEYBOARD_SCHEMA });
|
this._keyboardSettings = new Gio.Settings({ schema: KEYBOARD_SCHEMA });
|
||||||
@ -290,15 +288,7 @@ const Keyboard = new Gio.DBusImplementerClass({
|
|||||||
|
|
||||||
// Showing an extended key popup and clicking a key from the extended keys
|
// Showing an extended key popup and clicking a key from the extended keys
|
||||||
// will grab focus, but ignore that
|
// will grab focus, but ignore that
|
||||||
let extendedKeysWereFocused = this._focusInExtendedKeys;
|
if (focus && (focus._extended_keys || (focus._key && focus._key.extended_key)))
|
||||||
this._focusInExtendedKeys = focus && (focus._extended_keys || focus.extended_key);
|
|
||||||
if (this._focusInExtendedKeys || extendedKeysWereFocused)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Ignore focus changes caused by message tray showing/hiding
|
|
||||||
let trayWasFocused = this._focusInTray;
|
|
||||||
this._focusInTray = (focus && Main.messageTray.actor.contains(focus));
|
|
||||||
if (this._focusInTray || trayWasFocused)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let time = global.get_current_time();
|
let time = global.get_current_time();
|
||||||
@ -349,13 +339,6 @@ const Keyboard = new Gio.DBusImplementerClass({
|
|||||||
trayButton.reactive = true;
|
trayButton.reactive = true;
|
||||||
trayButton.remove_style_pseudo_class('grayed');
|
trayButton.remove_style_pseudo_class('grayed');
|
||||||
}));
|
}));
|
||||||
Main.sessionMode.connect('updated', Lang.bind(this, function() {
|
|
||||||
trayButton.reactive = !Main.sessionMode.isLocked;
|
|
||||||
if (Main.sessionMode.isLocked)
|
|
||||||
trayButton.add_style_pseudo_class('grayed');
|
|
||||||
else
|
|
||||||
trayButton.remove_style_pseudo_class('grayed');
|
|
||||||
}));
|
|
||||||
|
|
||||||
return trayButton;
|
return trayButton;
|
||||||
},
|
},
|
||||||
@ -485,12 +468,6 @@ const Keyboard = new Gio.DBusImplementerClass({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
shouldTakeEvent: function(event) {
|
|
||||||
let actor = event.get_source();
|
|
||||||
return Main.layoutManager.keyboardBox.contains(actor) ||
|
|
||||||
actor._extended_keys || actor.extended_key;
|
|
||||||
},
|
|
||||||
|
|
||||||
show: function () {
|
show: function () {
|
||||||
this._redraw();
|
this._redraw();
|
||||||
|
|
||||||
@ -517,30 +494,15 @@ const Keyboard = new Gio.DBusImplementerClass({
|
|||||||
this._moveTemporarily();
|
this._moveTemporarily();
|
||||||
},
|
},
|
||||||
|
|
||||||
// _compareTimestamp:
|
|
||||||
//
|
|
||||||
// Compare two timestamps taking into account
|
|
||||||
// CURRENT_TIME (0)
|
|
||||||
_compareTimestamp: function(one, two) {
|
|
||||||
if (one == two)
|
|
||||||
return 0;
|
|
||||||
if (one == Clutter.CURRENT_TIME)
|
|
||||||
return 1;
|
|
||||||
if (two == Clutter.CURRENT_TIME)
|
|
||||||
return -1;
|
|
||||||
return one - two;
|
|
||||||
},
|
|
||||||
|
|
||||||
// D-Bus methods
|
// D-Bus methods
|
||||||
Show: function(timestamp) {
|
Show: function(timestamp) {
|
||||||
if (!this._enableKeyboard)
|
if (!this._enableKeyboard)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (this._compareTimestamp(timestamp, this._timestamp) < 0)
|
if (timestamp - this._timestamp < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (timestamp != Clutter.CURRENT_TIME)
|
this._timestamp = timestamp;
|
||||||
this._timestamp = timestamp;
|
|
||||||
this.show();
|
this.show();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -548,11 +510,10 @@ const Keyboard = new Gio.DBusImplementerClass({
|
|||||||
if (!this._enableKeyboard)
|
if (!this._enableKeyboard)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (this._compareTimestamp(timestamp, this._timestamp) < 0)
|
if (timestamp - this._timestamp < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (timestamp != Clutter.CURRENT_TIME)
|
this._timestamp = timestamp;
|
||||||
this._timestamp = timestamp;
|
|
||||||
this.hide();
|
this.hide();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -581,8 +542,7 @@ const KeyboardSource = new Lang.Class({
|
|||||||
|
|
||||||
_init: function(keyboard) {
|
_init: function(keyboard) {
|
||||||
this._keyboard = keyboard;
|
this._keyboard = keyboard;
|
||||||
this.parent(_("Keyboard"), 'input-keyboard-symbolic');
|
this.parent(_("Keyboard"), 'input-keyboard', St.IconType.SYMBOLIC);
|
||||||
this.keepTrayOnSummaryClick = true;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handleSummaryClick: function() {
|
handleSummaryClick: function() {
|
||||||
|
@ -84,10 +84,7 @@ const KeyringDialog = new Lang.Class({
|
|||||||
if (this.prompt.password_visible) {
|
if (this.prompt.password_visible) {
|
||||||
let label = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
|
let label = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
|
||||||
label.set_text(_("Password:"));
|
label.set_text(_("Password:"));
|
||||||
table.add(label, { row: row, col: 0,
|
table.add(label, { row: row, col: 0, x_expand: false, x_fill: true, x_align: St.Align.START });
|
||||||
x_expand: false, x_fill: true,
|
|
||||||
x_align: St.Align.START,
|
|
||||||
y_fill: false, y_align: St.Align.MIDDLE });
|
|
||||||
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||||||
text: '',
|
text: '',
|
||||||
can_focus: true});
|
can_focus: true});
|
||||||
@ -103,10 +100,7 @@ const KeyringDialog = new Lang.Class({
|
|||||||
if (this.prompt.confirm_visible) {
|
if (this.prompt.confirm_visible) {
|
||||||
var label = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
|
var label = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
|
||||||
label.set_text(_("Type again:"));
|
label.set_text(_("Type again:"));
|
||||||
table.add(label, { row: row, col: 0,
|
table.add(label, { row: row, col: 0, x_expand: false, x_fill: true, x_align: St.Align.START });
|
||||||
x_expand: false, x_fill: true,
|
|
||||||
x_align: St.Align.START,
|
|
||||||
y_fill: false, y_align: St.Align.MIDDLE });
|
|
||||||
this._confirmEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
this._confirmEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||||||
text: '',
|
text: '',
|
||||||
can_focus: true});
|
can_focus: true});
|
||||||
@ -192,36 +186,23 @@ const KeyringDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onContinueButton: function() {
|
_onContinueButton: function() {
|
||||||
this.prompt.complete();
|
this.prompt.complete()
|
||||||
},
|
},
|
||||||
|
|
||||||
_onCancelButton: function() {
|
_onCancelButton: function() {
|
||||||
this.prompt.cancel();
|
this.prompt.cancel()
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const KeyringPrompter = new Lang.Class({
|
function init() {
|
||||||
Name: 'KeyringPrompter',
|
prompter = new Gcr.SystemPrompter();
|
||||||
|
prompter.connect('new-prompt', function(prompter) {
|
||||||
|
let dialog = new KeyringDialog();
|
||||||
|
return dialog.prompt;
|
||||||
|
});
|
||||||
|
|
||||||
_init: function() {
|
let connection = Gio.DBus.session;
|
||||||
this._prompter = new Gcr.SystemPrompter();
|
prompter.register(connection);
|
||||||
this._prompter.connect('new-prompt', function(prompter) {
|
Gio.bus_own_name_on_connection (connection, 'org.gnome.keyring.SystemPrompter',
|
||||||
let dialog = new KeyringDialog();
|
Gio.BusNameOwnerFlags.REPLACE, null, null);
|
||||||
return dialog.prompt;
|
}
|
||||||
});
|
|
||||||
this._dbusId = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
enable: function() {
|
|
||||||
this._prompter.register(Gio.DBus.session);
|
|
||||||
this._dbusId = Gio.DBus.session.own_name('org.gnome.keyring.SystemPrompter',
|
|
||||||
Gio.BusNameOwnerFlags.REPLACE, null, null);
|
|
||||||
},
|
|
||||||
|
|
||||||
disable: function() {
|
|
||||||
this._prompter.unregister(false);
|
|
||||||
Gio.DBus.session.unown_name(this._dbusId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const Component = KeyringPrompter;
|
|
146
js/ui/layout.js
146
js/ui/layout.js
@ -1,7 +1,6 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const GObject = imports.gi.GObject;
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
@ -17,83 +16,6 @@ const Tweener = imports.ui.tweener;
|
|||||||
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
|
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
|
||||||
const STARTUP_ANIMATION_TIME = 0.2;
|
const STARTUP_ANIMATION_TIME = 0.2;
|
||||||
const KEYBOARD_ANIMATION_TIME = 0.5;
|
const KEYBOARD_ANIMATION_TIME = 0.5;
|
||||||
const PLYMOUTH_TRANSITION_TIME = 1;
|
|
||||||
|
|
||||||
const MonitorConstraint = new Lang.Class({
|
|
||||||
Name: 'MonitorConstraint',
|
|
||||||
Extends: Clutter.Constraint,
|
|
||||||
Properties: {'primary': GObject.ParamSpec.boolean('primary',
|
|
||||||
'Primary', 'Track primary monitor',
|
|
||||||
GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
|
|
||||||
false),
|
|
||||||
'index': GObject.ParamSpec.int('index',
|
|
||||||
'Monitor index', 'Track specific monitor',
|
|
||||||
GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
|
|
||||||
-1, 64, -1)},
|
|
||||||
|
|
||||||
_init: function(props) {
|
|
||||||
this._primary = false;
|
|
||||||
this._index = -1;
|
|
||||||
|
|
||||||
this.parent(props);
|
|
||||||
},
|
|
||||||
|
|
||||||
get primary() {
|
|
||||||
return this._primary;
|
|
||||||
},
|
|
||||||
|
|
||||||
set primary(v) {
|
|
||||||
if (v)
|
|
||||||
this._index = -1;
|
|
||||||
this._primary = v;
|
|
||||||
if (this.actor)
|
|
||||||
this.actor.queue_relayout();
|
|
||||||
this.notify('primary');
|
|
||||||
},
|
|
||||||
|
|
||||||
get index() {
|
|
||||||
return this._index;
|
|
||||||
},
|
|
||||||
|
|
||||||
set index(v) {
|
|
||||||
this._primary = false;
|
|
||||||
this._index = v;
|
|
||||||
if (this.actor)
|
|
||||||
this.actor.queue_relayout();
|
|
||||||
this.notify('index');
|
|
||||||
},
|
|
||||||
|
|
||||||
vfunc_set_actor: function(actor) {
|
|
||||||
if (actor) {
|
|
||||||
if (!this._monitorsChangedId) {
|
|
||||||
this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', Lang.bind(this, function() {
|
|
||||||
this.actor.queue_relayout();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this._monitorsChangedId)
|
|
||||||
Main.layoutManager.disconnect(this._monitorsChangedId);
|
|
||||||
this._monitorsChangedId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.parent(actor);
|
|
||||||
},
|
|
||||||
|
|
||||||
vfunc_update_allocation: function(actor, actorBox) {
|
|
||||||
if (!this._primary && this._index < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let monitor;
|
|
||||||
if (this._primary) {
|
|
||||||
monitor = Main.layoutManager.primaryMonitor;
|
|
||||||
} else {
|
|
||||||
let index = Math.min(this._index, Main.layoutManager.monitors.length - 1);
|
|
||||||
monitor = Main.layoutManager.monitors[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
actorBox.init_rect(monitor.x, monitor.y, monitor.width, monitor.height);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const LayoutManager = new Lang.Class({
|
const LayoutManager = new Lang.Class({
|
||||||
Name: 'LayoutManager',
|
Name: 'LayoutManager',
|
||||||
@ -104,7 +26,6 @@ const LayoutManager = new Lang.Class({
|
|||||||
this.primaryMonitor = null;
|
this.primaryMonitor = null;
|
||||||
this.primaryIndex = -1;
|
this.primaryIndex = -1;
|
||||||
this._hotCorners = [];
|
this._hotCorners = [];
|
||||||
this._background = null;
|
|
||||||
this._leftPanelBarrier = 0;
|
this._leftPanelBarrier = 0;
|
||||||
this._rightPanelBarrier = 0;
|
this._rightPanelBarrier = 0;
|
||||||
this._trayBarrier = 0;
|
this._trayBarrier = 0;
|
||||||
@ -114,7 +35,6 @@ const LayoutManager = new Lang.Class({
|
|||||||
this.screenShieldGroup = new St.Widget({ name: 'screenShieldGroup',
|
this.screenShieldGroup = new St.Widget({ name: 'screenShieldGroup',
|
||||||
visible: false,
|
visible: false,
|
||||||
clip_to_allocation: true,
|
clip_to_allocation: true,
|
||||||
layout_manager: new Clutter.BinLayout(),
|
|
||||||
});
|
});
|
||||||
this.addChrome(this.screenShieldGroup);
|
this.addChrome(this.screenShieldGroup);
|
||||||
|
|
||||||
@ -125,8 +45,7 @@ const LayoutManager = new Lang.Class({
|
|||||||
this.panelBox.connect('allocation-changed',
|
this.panelBox.connect('allocation-changed',
|
||||||
Lang.bind(this, this._updatePanelBarriers));
|
Lang.bind(this, this._updatePanelBarriers));
|
||||||
|
|
||||||
this.trayBox = new St.Widget({ name: 'trayBox',
|
this.trayBox = new St.BoxLayout({ name: 'trayBox' });
|
||||||
layout_manager: new Clutter.BinLayout() });
|
|
||||||
this.addChrome(this.trayBox);
|
this.addChrome(this.trayBox);
|
||||||
this.trayBox.connect('allocation-changed',
|
this.trayBox.connect('allocation-changed',
|
||||||
Lang.bind(this, this._updateTrayBarrier));
|
Lang.bind(this, this._updateTrayBarrier));
|
||||||
@ -320,45 +239,14 @@ const LayoutManager = new Lang.Class({
|
|||||||
|
|
||||||
get currentMonitor() {
|
get currentMonitor() {
|
||||||
let index = global.screen.get_current_monitor();
|
let index = global.screen.get_current_monitor();
|
||||||
return this.monitors[index];
|
return Main.layoutManager.monitors[index];
|
||||||
},
|
},
|
||||||
|
|
||||||
_startupAnimation: function() {
|
_startupAnimation: function() {
|
||||||
this.panelBox.anchor_y = this.panelBox.height;
|
|
||||||
|
|
||||||
let plymouthTransitionRunning = false;
|
|
||||||
|
|
||||||
// If we're the greeter, put up the xrootpmap actor
|
|
||||||
// and fade it out to have a nice transition from plymouth
|
|
||||||
// to the greeter. Otherwise, we'll just animate the panel,
|
|
||||||
// as usual.
|
|
||||||
if (Main.sessionMode.isGreeter) {
|
|
||||||
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
|
|
||||||
if (this._background != null) {
|
|
||||||
Main.uiGroup.add_actor(this._background);
|
|
||||||
Tweener.addTween(this._background,
|
|
||||||
{ opacity: 0,
|
|
||||||
time: PLYMOUTH_TRANSITION_TIME,
|
|
||||||
transition: 'linear',
|
|
||||||
onComplete: this._fadeBackgroundComplete,
|
|
||||||
onCompleteScope: this });
|
|
||||||
plymouthTransitionRunning = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!plymouthTransitionRunning)
|
|
||||||
this._fadeBackgroundComplete();
|
|
||||||
},
|
|
||||||
|
|
||||||
_fadeBackgroundComplete: function() {
|
|
||||||
// Don't animate the strut
|
// Don't animate the strut
|
||||||
this._chrome.freezeUpdateRegions();
|
this._chrome.freezeUpdateRegions();
|
||||||
|
|
||||||
if (this._background != null) {
|
this.panelBox.anchor_y = this.panelBox.height;
|
||||||
this._background.destroy();
|
|
||||||
this._background = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Tweener.addTween(this.panelBox,
|
Tweener.addTween(this.panelBox,
|
||||||
{ anchor_y: 0,
|
{ anchor_y: 0,
|
||||||
time: STARTUP_ANIMATION_TIME,
|
time: STARTUP_ANIMATION_TIME,
|
||||||
@ -373,6 +261,7 @@ const LayoutManager = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
showKeyboard: function () {
|
showKeyboard: function () {
|
||||||
|
Main.messageTray.hide();
|
||||||
this.keyboardBox.raise_top();
|
this.keyboardBox.raise_top();
|
||||||
Tweener.addTween(this.keyboardBox,
|
Tweener.addTween(this.keyboardBox,
|
||||||
{ anchor_y: this.keyboardBox.height,
|
{ anchor_y: this.keyboardBox.height,
|
||||||
@ -386,8 +275,6 @@ const LayoutManager = new Lang.Class({
|
|||||||
time: KEYBOARD_ANIMATION_TIME,
|
time: KEYBOARD_ANIMATION_TIME,
|
||||||
transition: 'easeOutQuad'
|
transition: 'easeOutQuad'
|
||||||
});
|
});
|
||||||
|
|
||||||
this.emit('keyboard-visible-changed', true);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_showKeyboardComplete: function() {
|
_showKeyboardComplete: function() {
|
||||||
@ -402,6 +289,7 @@ const LayoutManager = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
hideKeyboard: function (immediate) {
|
hideKeyboard: function (immediate) {
|
||||||
|
Main.messageTray.hide();
|
||||||
if (this._keyboardHeightNotifyId) {
|
if (this._keyboardHeightNotifyId) {
|
||||||
this.keyboardBox.disconnect(this._keyboardHeightNotifyId);
|
this.keyboardBox.disconnect(this._keyboardHeightNotifyId);
|
||||||
this._keyboardHeightNotifyId = 0;
|
this._keyboardHeightNotifyId = 0;
|
||||||
@ -418,8 +306,6 @@ const LayoutManager = new Lang.Class({
|
|||||||
time: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
|
time: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
|
||||||
transition: 'easeOutQuad'
|
transition: 'easeOutQuad'
|
||||||
});
|
});
|
||||||
|
|
||||||
this.emit('keyboard-visible-changed', false);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_hideKeyboardComplete: function() {
|
_hideKeyboardComplete: function() {
|
||||||
@ -678,6 +564,7 @@ const Chrome = new Lang.Class({
|
|||||||
|
|
||||||
this._monitors = [];
|
this._monitors = [];
|
||||||
this._inOverview = false;
|
this._inOverview = false;
|
||||||
|
this._isLocked = false;
|
||||||
this._updateRegionIdle = 0;
|
this._updateRegionIdle = 0;
|
||||||
this._freezeUpdateCount = 0;
|
this._freezeUpdateCount = 0;
|
||||||
|
|
||||||
@ -696,9 +583,12 @@ const Chrome = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
init: function() {
|
init: function() {
|
||||||
Main.overview.connect('showing', Lang.bind(this, this._overviewShowing));
|
Main.overview.connect('showing',
|
||||||
Main.overview.connect('hidden', Lang.bind(this, this._overviewHidden));
|
Lang.bind(this, this._overviewShowing));
|
||||||
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
Main.overview.connect('hidden',
|
||||||
|
Lang.bind(this, this._overviewHidden));
|
||||||
|
Main.screenShield.connect('lock-status-changed',
|
||||||
|
Lang.bind(this, this._lockStatusChanged));
|
||||||
},
|
},
|
||||||
|
|
||||||
addActor: function(actor, params) {
|
addActor: function(actor, params) {
|
||||||
@ -784,13 +674,10 @@ const Chrome = new Lang.Class({
|
|||||||
|
|
||||||
_actorReparented: function(actor, oldParent) {
|
_actorReparented: function(actor, oldParent) {
|
||||||
let newParent = actor.get_parent();
|
let newParent = actor.get_parent();
|
||||||
if (!newParent) {
|
if (!newParent)
|
||||||
this._untrackActor(actor);
|
this._untrackActor(actor);
|
||||||
} else {
|
else
|
||||||
let i = this._findActor(actor);
|
|
||||||
let actorData = this._trackedActors[i];
|
|
||||||
actorData.isToplevel = (newParent == Main.uiGroup);
|
actorData.isToplevel = (newParent == Main.uiGroup);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateVisibility: function() {
|
_updateVisibility: function() {
|
||||||
@ -801,7 +688,7 @@ const Chrome = new Lang.Class({
|
|||||||
if (!actorData.isToplevel)
|
if (!actorData.isToplevel)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (this._inOverview || !Main.sessionMode.hasWindows)
|
if (this._inOverview || this._isLocked)
|
||||||
visible = true;
|
visible = true;
|
||||||
else if (this.findMonitorForActor(actorData.actor).inFullscreen)
|
else if (this.findMonitorForActor(actorData.actor).inFullscreen)
|
||||||
visible = false;
|
visible = false;
|
||||||
@ -823,7 +710,8 @@ const Chrome = new Lang.Class({
|
|||||||
this._queueUpdateRegions();
|
this._queueUpdateRegions();
|
||||||
},
|
},
|
||||||
|
|
||||||
_sessionUpdated: function() {
|
_lockStatusChanged: function(shield, locked) {
|
||||||
|
this._isLocked = locked;
|
||||||
this._updateVisibility();
|
this._updateVisibility();
|
||||||
this._queueUpdateRegions();
|
this._queueUpdateRegions();
|
||||||
},
|
},
|
||||||
|
@ -38,6 +38,7 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
|
|||||||
/* Utility functions...we should probably be able to use these
|
/* Utility functions...we should probably be able to use these
|
||||||
* in the shell core code too. */
|
* in the shell core code too. */
|
||||||
'const stage = global.stage; ' +
|
'const stage = global.stage; ' +
|
||||||
|
'const color = function(pixel) { let c= new Clutter.Color(); c.from_pixel(pixel); return c; }; ' +
|
||||||
/* Special lookingGlass functions */
|
/* Special lookingGlass functions */
|
||||||
'const it = Main.lookingGlass.getIt(); ' +
|
'const it = Main.lookingGlass.getIt(); ' +
|
||||||
'const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); ';
|
'const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); ';
|
||||||
@ -371,8 +372,7 @@ const ObjInspector = new Lang.Class({
|
|||||||
|
|
||||||
this._parentList = [];
|
this._parentList = [];
|
||||||
|
|
||||||
this.actor = new St.ScrollView({ pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }),
|
this.actor = new St.ScrollView({ x_fill: true, y_fill: true });
|
||||||
x_fill: true, y_fill: true });
|
|
||||||
this.actor.get_hscroll_bar().hide();
|
this.actor.get_hscroll_bar().hide();
|
||||||
this._container = new St.BoxLayout({ name: 'LookingGlassPropertyInspector',
|
this._container = new St.BoxLayout({ name: 'LookingGlassPropertyInspector',
|
||||||
style_class: 'lg-dialog',
|
style_class: 'lg-dialog',
|
||||||
@ -444,6 +444,10 @@ const ObjInspector = new Lang.Class({
|
|||||||
this.actor.show();
|
this.actor.show();
|
||||||
if (sourceActor) {
|
if (sourceActor) {
|
||||||
this.actor.set_scale(0, 0);
|
this.actor.set_scale(0, 0);
|
||||||
|
let [sourceX, sourceY] = sourceActor.get_transformed_position();
|
||||||
|
let [sourceWidth, sourceHeight] = sourceActor.get_transformed_size();
|
||||||
|
this.actor.move_anchor_point(Math.floor(sourceX + sourceWidth / 2),
|
||||||
|
Math.floor(sourceY + sourceHeight / 2));
|
||||||
Tweener.addTween(this.actor, { scale_x: 1, scale_y: 1,
|
Tweener.addTween(this.actor, { scale_x: 1, scale_y: 1,
|
||||||
transition: 'easeOutQuad',
|
transition: 'easeOutQuad',
|
||||||
time: 0.2 });
|
time: 0.2 });
|
||||||
@ -865,6 +869,7 @@ const LookingGlass = new Lang.Class({
|
|||||||
let toolbar = new St.BoxLayout({ name: 'Toolbar' });
|
let toolbar = new St.BoxLayout({ name: 'Toolbar' });
|
||||||
this.actor.add_actor(toolbar);
|
this.actor.add_actor(toolbar);
|
||||||
let inspectIcon = new St.Icon({ icon_name: 'gtk-color-picker',
|
let inspectIcon = new St.Icon({ icon_name: 'gtk-color-picker',
|
||||||
|
icon_type: St.IconType.FULLCOLOR,
|
||||||
icon_size: 24 });
|
icon_size: 24 });
|
||||||
toolbar.add_actor(inspectIcon);
|
toolbar.add_actor(inspectIcon);
|
||||||
inspectIcon.reactive = true;
|
inspectIcon.reactive = true;
|
||||||
@ -1089,8 +1094,8 @@ const LookingGlass = new Lang.Class({
|
|||||||
this.actor.width = myWidth;
|
this.actor.width = myWidth;
|
||||||
this.actor.height = myHeight;
|
this.actor.height = myHeight;
|
||||||
this._objInspector.actor.set_size(Math.floor(myWidth * 0.8), Math.floor(myHeight * 0.8));
|
this._objInspector.actor.set_size(Math.floor(myWidth * 0.8), Math.floor(myHeight * 0.8));
|
||||||
this._objInspector.actor.set_position(primary.x + this.actor.x + Math.floor(myWidth * 0.1),
|
this._objInspector.actor.set_position(this.actor.x + Math.floor(myWidth * 0.1),
|
||||||
primary.y + this._targetY + Math.floor(myHeight * 0.1));
|
this._targetY + Math.floor(myHeight * 0.1));
|
||||||
},
|
},
|
||||||
|
|
||||||
insertObject: function(obj) {
|
insertObject: function(obj) {
|
||||||
|
@ -12,7 +12,7 @@ const Signals = imports.signals;
|
|||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const MagnifierDBus = imports.ui.magnifierDBus;
|
const MagnifierDBus = imports.ui.magnifierDBus;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const PointerWatcher = imports.ui.pointerWatcher;
|
|
||||||
|
|
||||||
const MOUSE_POLL_FREQUENCY = 50;
|
const MOUSE_POLL_FREQUENCY = 50;
|
||||||
const CROSSHAIRS_CLIP_SIZE = [100, 100];
|
const CROSSHAIRS_CLIP_SIZE = [100, 100];
|
||||||
@ -56,7 +56,7 @@ const Magnifier = new Lang.Class({
|
|||||||
let xfixesCursor = Shell.XFixesCursor.get_for_stage(global.stage);
|
let xfixesCursor = Shell.XFixesCursor.get_for_stage(global.stage);
|
||||||
this._mouseSprite = new Clutter.Texture();
|
this._mouseSprite = new Clutter.Texture();
|
||||||
xfixesCursor.update_texture_image(this._mouseSprite);
|
xfixesCursor.update_texture_image(this._mouseSprite);
|
||||||
this._cursorRoot = new Clutter.Actor();
|
this._cursorRoot = new Clutter.Group();
|
||||||
this._cursorRoot.add_actor(this._mouseSprite);
|
this._cursorRoot.add_actor(this._mouseSprite);
|
||||||
|
|
||||||
// Create the first ZoomRegion and initialize it according to the
|
// Create the first ZoomRegion and initialize it according to the
|
||||||
@ -136,8 +136,11 @@ const Magnifier = new Lang.Class({
|
|||||||
* Turn on mouse tracking, if not already doing so.
|
* Turn on mouse tracking, if not already doing so.
|
||||||
*/
|
*/
|
||||||
startTrackingMouse: function() {
|
startTrackingMouse: function() {
|
||||||
if (!this._pointerWatch)
|
if (!this._mouseTrackingId)
|
||||||
this._pointerWatch = PointerWatcher.getPointerWatcher().addWatch(MOUSE_POLL_FREQUENCY, Lang.bind(this, this.scrollToMousePos));
|
this._mouseTrackingId = Mainloop.timeout_add(
|
||||||
|
MOUSE_POLL_FREQUENCY,
|
||||||
|
Lang.bind(this, this.scrollToMousePos)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,10 +148,10 @@ const Magnifier = new Lang.Class({
|
|||||||
* Turn off mouse tracking, if not already doing so.
|
* Turn off mouse tracking, if not already doing so.
|
||||||
*/
|
*/
|
||||||
stopTrackingMouse: function() {
|
stopTrackingMouse: function() {
|
||||||
if (this._pointerWatch)
|
if (this._mouseTrackingId)
|
||||||
this._pointerWatch.remove();
|
Mainloop.source_remove(this._mouseTrackingId);
|
||||||
|
|
||||||
this._pointerWatch = null;
|
this._mouseTrackingId = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -300,7 +303,8 @@ const Magnifier = new Lang.Class({
|
|||||||
*/
|
*/
|
||||||
setCrosshairsColor: function(color) {
|
setCrosshairsColor: function(color) {
|
||||||
if (this._crossHairs) {
|
if (this._crossHairs) {
|
||||||
let [res, clutterColor] = Clutter.Color.from_string(color);
|
let clutterColor = new Clutter.Color();
|
||||||
|
clutterColor.from_string(color);
|
||||||
this._crossHairs.setColor(clutterColor);
|
this._crossHairs.setColor(clutterColor);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1077,21 +1081,21 @@ const ZoomRegion = new Lang.Class({
|
|||||||
// hide the magnified region from CLUTTER_PICK_ALL
|
// hide the magnified region from CLUTTER_PICK_ALL
|
||||||
Shell.util_set_hidden_from_pick (this._magView, true);
|
Shell.util_set_hidden_from_pick (this._magView, true);
|
||||||
|
|
||||||
// Add a group to clip the contents of the magnified view.
|
// Append a Clutter.Group to clip the contents of the magnified view.
|
||||||
let mainGroup = new Clutter.Actor({ clip_to_allocation: true });
|
let mainGroup = new Clutter.Group({ clip_to_allocation: true });
|
||||||
this._magView.set_child(mainGroup);
|
this._magView.set_child(mainGroup);
|
||||||
|
|
||||||
// Add a background for when the magnified uiGroup is scrolled
|
// Add a background for when the magnified uiGroup is scrolled
|
||||||
// out of view (don't want to see desktop showing through).
|
// out of view (don't want to see desktop showing through).
|
||||||
this._background = new Clutter.Actor({ background_color: Main.DEFAULT_BACKGROUND_COLOR,
|
this._background = new Clutter.Rectangle({ color: Main.DEFAULT_BACKGROUND_COLOR });
|
||||||
width: global.screen_width,
|
|
||||||
height: global.screen_height });
|
|
||||||
mainGroup.add_actor(this._background);
|
mainGroup.add_actor(this._background);
|
||||||
|
|
||||||
// Clone the group that contains all of UI on the screen. This is the
|
// Clone the group that contains all of UI on the screen. This is the
|
||||||
// chrome, the windows, etc.
|
// chrome, the windows, etc.
|
||||||
this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup });
|
this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup });
|
||||||
mainGroup.add_actor(this._uiGroupClone);
|
mainGroup.add_actor(this._uiGroupClone);
|
||||||
|
Main.uiGroup.set_size(global.screen_width, global.screen_height);
|
||||||
|
this._background.set_size(global.screen_width, global.screen_height);
|
||||||
|
|
||||||
// Add either the given mouseSourceActor to the ZoomRegion, or a clone of
|
// Add either the given mouseSourceActor to the ZoomRegion, or a clone of
|
||||||
// it.
|
// it.
|
||||||
@ -1325,7 +1329,7 @@ const ZoomRegion = new Lang.Class({
|
|||||||
this._mouseActor.set_scale(this._xMagFactor, this._yMagFactor);
|
this._mouseActor.set_scale(this._xMagFactor, this._yMagFactor);
|
||||||
|
|
||||||
let [x, y] = this._screenToViewPort(0, 0);
|
let [x, y] = this._screenToViewPort(0, 0);
|
||||||
this._uiGroupClone.set_position(Math.round(x), Math.round(y));
|
this._uiGroupClone.set_position(x, y);
|
||||||
|
|
||||||
this._updateMousePosition();
|
this._updateMousePosition();
|
||||||
},
|
},
|
||||||
@ -1353,6 +1357,7 @@ const ZoomRegion = new Lang.Class({
|
|||||||
if (!this.isActive())
|
if (!this.isActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Main.uiGroup.set_size(global.screen_width, global.screen_height);
|
||||||
this._background.set_size(global.screen_width, global.screen_height);
|
this._background.set_size(global.screen_width, global.screen_height);
|
||||||
|
|
||||||
if (this._screenPosition == GDesktopEnums.MagnifierScreenPosition.NONE)
|
if (this._screenPosition == GDesktopEnums.MagnifierScreenPosition.NONE)
|
||||||
@ -1376,15 +1381,15 @@ const Crosshairs = new Lang.Class({
|
|||||||
let groupWidth = global.screen_width * 3;
|
let groupWidth = global.screen_width * 3;
|
||||||
let groupHeight = global.screen_height * 3;
|
let groupHeight = global.screen_height * 3;
|
||||||
|
|
||||||
this._actor = new Clutter.Actor({
|
this._actor = new Clutter.Group({
|
||||||
clip_to_allocation: false,
|
clip_to_allocation: false,
|
||||||
width: groupWidth,
|
width: groupWidth,
|
||||||
height: groupHeight
|
height: groupHeight
|
||||||
});
|
});
|
||||||
this._horizLeftHair = new Clutter.Actor();
|
this._horizLeftHair = new Clutter.Rectangle();
|
||||||
this._horizRightHair = new Clutter.Actor();
|
this._horizRightHair = new Clutter.Rectangle();
|
||||||
this._vertTopHair = new Clutter.Actor();
|
this._vertTopHair = new Clutter.Rectangle();
|
||||||
this._vertBottomHair = new Clutter.Actor();
|
this._vertBottomHair = new Clutter.Rectangle();
|
||||||
this._actor.add_actor(this._horizLeftHair);
|
this._actor.add_actor(this._horizLeftHair);
|
||||||
this._actor.add_actor(this._horizRightHair);
|
this._actor.add_actor(this._horizRightHair);
|
||||||
this._actor.add_actor(this._vertTopHair);
|
this._actor.add_actor(this._vertTopHair);
|
||||||
@ -1455,10 +1460,10 @@ const Crosshairs = new Lang.Class({
|
|||||||
* @clutterColor: The color as a Clutter.Color.
|
* @clutterColor: The color as a Clutter.Color.
|
||||||
*/
|
*/
|
||||||
setColor: function(clutterColor) {
|
setColor: function(clutterColor) {
|
||||||
this._horizLeftHair.background_color = clutterColor;
|
this._horizLeftHair.set_color(clutterColor);
|
||||||
this._horizRightHair.background_color = clutterColor;
|
this._horizRightHair.set_color(clutterColor);
|
||||||
this._vertTopHair.background_color = clutterColor;
|
this._vertTopHair.set_color(clutterColor);
|
||||||
this._vertBottomHair.background_color = clutterColor;
|
this._vertBottomHair.set_color(clutterColor);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1467,7 +1472,9 @@ const Crosshairs = new Lang.Class({
|
|||||||
* @color: The color as a Clutter.Color.
|
* @color: The color as a Clutter.Color.
|
||||||
*/
|
*/
|
||||||
getColor: function() {
|
getColor: function() {
|
||||||
return this._horizLeftHair.get_color();
|
let clutterColor = new Clutter.Color();
|
||||||
|
this._horizLeftHair.get_color(clutterColor);
|
||||||
|
return clutterColor;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,15 +96,14 @@ const ZoomRegionIface = <interface name={ZOOM_SERVICE_NAME}>
|
|||||||
// '/org/gnome/Magnifier/ZoomRegion/zoomer1', etc.
|
// '/org/gnome/Magnifier/ZoomRegion/zoomer1', etc.
|
||||||
let _zoomRegionInstanceCount = 0;
|
let _zoomRegionInstanceCount = 0;
|
||||||
|
|
||||||
const ShellMagnifier = new Gio.DBusImplementerClass({
|
const ShellMagnifier = new Lang.Class({
|
||||||
Name: 'ShellMagnifier',
|
Name: 'ShellMagnifier',
|
||||||
Interface: MagnifierIface,
|
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent();
|
|
||||||
this.export(Gio.DBus.session, MAG_SERVICE_PATH);
|
|
||||||
|
|
||||||
this._zoomers = {};
|
this._zoomers = {};
|
||||||
|
|
||||||
|
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(MagnifierIface, this);
|
||||||
|
this._dbusImpl.export(Gio.DBus.session, MAG_SERVICE_PATH);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -333,15 +332,14 @@ const ShellMagnifier = new Gio.DBusImplementerClass({
|
|||||||
* @zoomerObjectPath: String that is the path to a DBus ZoomRegion.
|
* @zoomerObjectPath: String that is the path to a DBus ZoomRegion.
|
||||||
* @zoomRegion: The actual zoom region associated with the object path.
|
* @zoomRegion: The actual zoom region associated with the object path.
|
||||||
*/
|
*/
|
||||||
const ShellMagnifierZoomRegion = new Gio.DBusImplementerClass({
|
const ShellMagnifierZoomRegion = new Lang.Class({
|
||||||
Name: 'ShellMagnifierZoomRegion',
|
Name: 'ShellMagnifierZoomRegion',
|
||||||
Interface: ZoomRegionIface,
|
|
||||||
|
|
||||||
_init: function(zoomerObjectPath, zoomRegion) {
|
_init: function(zoomerObjectPath, zoomRegion) {
|
||||||
this.parent();
|
|
||||||
this.export(Gio.DBus.session, zoomerObjectPath);
|
|
||||||
|
|
||||||
this._zoomRegion = zoomRegion;
|
this._zoomRegion = zoomRegion;
|
||||||
|
|
||||||
|
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ZoomRegionIface, this);
|
||||||
|
this._dbusImpl.export(Gio.DBus.session, zoomerObjectPath);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -419,6 +417,6 @@ const ShellMagnifierZoomRegion = new Gio.DBusImplementerClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
this.unexport();
|
this._dbusImpl.unexport();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
154
js/ui/main.js
154
js/ui/main.js
@ -10,9 +10,12 @@ const Meta = imports.gi.Meta;
|
|||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
const Components = imports.ui.components;
|
const AutomountManager = imports.ui.automountManager;
|
||||||
|
const AutorunManager = imports.ui.autorunManager;
|
||||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||||
const EndSessionDialog = imports.ui.endSessionDialog;
|
const EndSessionDialog = imports.ui.endSessionDialog;
|
||||||
|
const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent;
|
||||||
|
const KeyringPrompt = imports.ui.keyringPrompt;
|
||||||
const Environment = imports.ui.environment;
|
const Environment = imports.ui.environment;
|
||||||
const ExtensionSystem = imports.ui.extensionSystem;
|
const ExtensionSystem = imports.ui.extensionSystem;
|
||||||
const ExtensionDownloader = imports.ui.extensionDownloader;
|
const ExtensionDownloader = imports.ui.extensionDownloader;
|
||||||
@ -20,9 +23,11 @@ const Keyboard = imports.ui.keyboard;
|
|||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
const Overview = imports.ui.overview;
|
const Overview = imports.ui.overview;
|
||||||
const Panel = imports.ui.panel;
|
const Panel = imports.ui.panel;
|
||||||
|
const PlaceDisplay = imports.ui.placeDisplay;
|
||||||
const RunDialog = imports.ui.runDialog;
|
const RunDialog = imports.ui.runDialog;
|
||||||
const Layout = imports.ui.layout;
|
const Layout = imports.ui.layout;
|
||||||
const LookingGlass = imports.ui.lookingGlass;
|
const LookingGlass = imports.ui.lookingGlass;
|
||||||
|
const NetworkAgent = imports.ui.networkAgent;
|
||||||
const NotificationDaemon = imports.ui.notificationDaemon;
|
const NotificationDaemon = imports.ui.notificationDaemon;
|
||||||
const WindowAttentionHandler = imports.ui.windowAttentionHandler;
|
const WindowAttentionHandler = imports.ui.windowAttentionHandler;
|
||||||
const ScreenShield = imports.ui.screenShield;
|
const ScreenShield = imports.ui.screenShield;
|
||||||
@ -30,6 +35,7 @@ const Scripting = imports.ui.scripting;
|
|||||||
const SessionMode = imports.ui.sessionMode;
|
const SessionMode = imports.ui.sessionMode;
|
||||||
const ShellDBus = imports.ui.shellDBus;
|
const ShellDBus = imports.ui.shellDBus;
|
||||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
const ShellMountOperation = imports.ui.shellMountOperation;
|
||||||
|
const TelepathyClient = imports.ui.telepathyClient;
|
||||||
const UnlockDialog = imports.ui.unlockDialog;
|
const UnlockDialog = imports.ui.unlockDialog;
|
||||||
const WindowManager = imports.ui.windowManager;
|
const WindowManager = imports.ui.windowManager;
|
||||||
const Magnifier = imports.ui.magnifier;
|
const Magnifier = imports.ui.magnifier;
|
||||||
@ -37,10 +43,13 @@ const XdndHandler = imports.ui.xdndHandler;
|
|||||||
const Util = imports.misc.util;
|
const Util = imports.misc.util;
|
||||||
|
|
||||||
const OVERRIDES_SCHEMA = 'org.gnome.shell.overrides';
|
const OVERRIDES_SCHEMA = 'org.gnome.shell.overrides';
|
||||||
const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
|
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
|
||||||
|
DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
|
||||||
|
|
||||||
let componentManager = null;
|
let automountManager = null;
|
||||||
|
let autorunManager = null;
|
||||||
let panel = null;
|
let panel = null;
|
||||||
|
let hotCorners = [];
|
||||||
let overview = null;
|
let overview = null;
|
||||||
let runDialog = null;
|
let runDialog = null;
|
||||||
let lookingGlass = null;
|
let lookingGlass = null;
|
||||||
@ -49,7 +58,9 @@ let messageTray = null;
|
|||||||
let screenShield = null;
|
let screenShield = null;
|
||||||
let notificationDaemon = null;
|
let notificationDaemon = null;
|
||||||
let windowAttentionHandler = null;
|
let windowAttentionHandler = null;
|
||||||
|
let telepathyClient = null;
|
||||||
let ctrlAltTabManager = null;
|
let ctrlAltTabManager = null;
|
||||||
|
let recorder = null;
|
||||||
let sessionMode = null;
|
let sessionMode = null;
|
||||||
let shellDBusService = null;
|
let shellDBusService = null;
|
||||||
let shellMountOpDBusService = null;
|
let shellMountOpDBusService = null;
|
||||||
@ -61,6 +72,7 @@ let magnifier = null;
|
|||||||
let xdndHandler = null;
|
let xdndHandler = null;
|
||||||
let keyboard = null;
|
let keyboard = null;
|
||||||
let layoutManager = null;
|
let layoutManager = null;
|
||||||
|
let networkAgent = null;
|
||||||
let _startDate;
|
let _startDate;
|
||||||
let _defaultCssStylesheet = null;
|
let _defaultCssStylesheet = null;
|
||||||
let _cssStylesheet = null;
|
let _cssStylesheet = null;
|
||||||
@ -68,10 +80,73 @@ let _overridesSettings = null;
|
|||||||
|
|
||||||
let background = null;
|
let background = null;
|
||||||
|
|
||||||
function _sessionUpdated() {
|
function createUserSession() {
|
||||||
Meta.keybindings_set_custom_handler('panel-run-dialog', sessionMode.hasRunDialog ? openRunDialog : null);
|
// Load the calendar server. Note that we are careful about
|
||||||
if (sessionMode.isGreeter)
|
// not loading any events until the user presses the clock
|
||||||
screenShield.showDialog();
|
global.launch_calendar_server();
|
||||||
|
|
||||||
|
telepathyClient = new TelepathyClient.Client();
|
||||||
|
automountManager = new AutomountManager.AutomountManager();
|
||||||
|
autorunManager = new AutorunManager.AutorunManager();
|
||||||
|
networkAgent = new NetworkAgent.NetworkAgent();
|
||||||
|
|
||||||
|
_initRecorder();
|
||||||
|
}
|
||||||
|
|
||||||
|
function createGDMSession() {
|
||||||
|
screenShield.showDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
function createGDMLoginDialog(parentActor) {
|
||||||
|
// We do this this here instead of at the top to prevent GDM
|
||||||
|
// related code from getting loaded in normal user sessions
|
||||||
|
const LoginDialog = imports.gdm.loginDialog;
|
||||||
|
|
||||||
|
let loginDialog = new LoginDialog.LoginDialog(parentActor);
|
||||||
|
return [loginDialog, true];
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSessionUnlockDialog(parentActor) {
|
||||||
|
let dialog = new UnlockDialog.UnlockDialog(parentActor);
|
||||||
|
return [dialog, false];
|
||||||
|
}
|
||||||
|
|
||||||
|
function createInitialSetupSession() {
|
||||||
|
networkAgent = new NetworkAgent.NetworkAgent();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _initRecorder() {
|
||||||
|
let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
|
||||||
|
let desktopLockdownSettings = new Gio.Settings({ schema: 'org.gnome.desktop.lockdown' });
|
||||||
|
let bindingSettings = new Gio.Settings({ schema: 'org.gnome.shell.keybindings' });
|
||||||
|
|
||||||
|
global.display.add_keybinding('toggle-recording',
|
||||||
|
bindingSettings,
|
||||||
|
Meta.KeyBindingFlags.NONE, function() {
|
||||||
|
if (recorder == null) {
|
||||||
|
recorder = new Shell.Recorder({ stage: global.stage });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recorder.is_recording()) {
|
||||||
|
recorder.close();
|
||||||
|
Meta.enable_unredirect_for_screen(global.screen);
|
||||||
|
} else if (!desktopLockdownSettings.get_boolean('disable-save-to-disk')) {
|
||||||
|
// read the parameters from GSettings always in case they have changed
|
||||||
|
recorder.set_framerate(recorderSettings.get_int('framerate'));
|
||||||
|
/* Translators: this is a filename used for screencast recording */
|
||||||
|
// xgettext:no-c-format
|
||||||
|
recorder.set_filename(_("Screencast from %d %t") + '.' + recorderSettings.get_string('file-extension'));
|
||||||
|
let pipeline = recorderSettings.get_string('pipeline');
|
||||||
|
|
||||||
|
if (!pipeline.match(/^\s*$/))
|
||||||
|
recorder.set_pipeline(pipeline);
|
||||||
|
else
|
||||||
|
recorder.set_pipeline(null);
|
||||||
|
|
||||||
|
Meta.disable_unredirect_for_screen(global.screen);
|
||||||
|
recorder.record();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function start() {
|
function start() {
|
||||||
@ -137,34 +212,57 @@ function start() {
|
|||||||
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
|
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
|
||||||
overview = new Overview.Overview();
|
overview = new Overview.Overview();
|
||||||
magnifier = new Magnifier.Magnifier();
|
magnifier = new Magnifier.Magnifier();
|
||||||
if (UnlockDialog.isSupported())
|
screenShield = new ScreenShield.ScreenShield();
|
||||||
screenShield = new ScreenShield.ScreenShield();
|
screenSaverDBus = new ShellDBus.ScreenSaverDBus();
|
||||||
else
|
|
||||||
screenShield = new ScreenShield.ScreenShieldFallback();
|
|
||||||
panel = new Panel.Panel();
|
panel = new Panel.Panel();
|
||||||
wm = new WindowManager.WindowManager();
|
wm = new WindowManager.WindowManager();
|
||||||
messageTray = new MessageTray.MessageTray();
|
messageTray = new MessageTray.MessageTray();
|
||||||
keyboard = new Keyboard.Keyboard();
|
keyboard = new Keyboard.Keyboard();
|
||||||
notificationDaemon = new NotificationDaemon.NotificationDaemon();
|
notificationDaemon = new NotificationDaemon.NotificationDaemon();
|
||||||
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
|
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
|
||||||
componentManager = new Components.ComponentManager();
|
|
||||||
|
sessionMode.createSession();
|
||||||
|
|
||||||
|
panel.startStatusArea();
|
||||||
|
|
||||||
layoutManager.init();
|
layoutManager.init();
|
||||||
keyboard.init();
|
keyboard.init();
|
||||||
overview.init();
|
overview.init();
|
||||||
|
|
||||||
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
|
if (sessionMode.hasWorkspaces)
|
||||||
false, -1, 1);
|
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
|
||||||
Meta.keybindings_set_custom_handler('panel-main-menu', Lang.bind(overview, overview.toggle));
|
false, -1, 1);
|
||||||
global.display.connect('overlay-key', Lang.bind(overview, overview.toggle));
|
|
||||||
|
|
||||||
sessionMode.connect('update', _sessionUpdated);
|
if (sessionMode.allowExtensions) {
|
||||||
_sessionUpdated();
|
ExtensionDownloader.init();
|
||||||
|
ExtensionSystem.loadExtensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sessionMode.hasRunDialog) {
|
||||||
|
Meta.keybindings_set_custom_handler('panel-run-dialog', function() {
|
||||||
|
getRunDialog().open();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sessionMode.hasOverview) {
|
||||||
|
Meta.keybindings_set_custom_handler('panel-main-menu', function () {
|
||||||
|
overview.toggle();
|
||||||
|
});
|
||||||
|
|
||||||
|
global.display.connect('overlay-key',
|
||||||
|
Lang.bind(overview, overview.toggle));
|
||||||
|
}
|
||||||
|
|
||||||
// Provide the bus object for gnome-session to
|
// Provide the bus object for gnome-session to
|
||||||
// initiate logouts.
|
// initiate logouts.
|
||||||
EndSessionDialog.init();
|
EndSessionDialog.init();
|
||||||
|
|
||||||
|
// Attempt to become a PolicyKit authentication agent
|
||||||
|
PolkitAuthenticationAgent.init()
|
||||||
|
|
||||||
|
// Become a prompter for gnome keyring
|
||||||
|
KeyringPrompt.init();
|
||||||
|
|
||||||
_startDate = new Date();
|
_startDate = new Date();
|
||||||
|
|
||||||
global.stage.connect('captured-event', _globalKeyPressHandler);
|
global.stage.connect('captured-event', _globalKeyPressHandler);
|
||||||
@ -188,9 +286,6 @@ function start() {
|
|||||||
global.screen.connect('restacked', _windowsRestacked);
|
global.screen.connect('restacked', _windowsRestacked);
|
||||||
|
|
||||||
_nWorkspacesChanged();
|
_nWorkspacesChanged();
|
||||||
|
|
||||||
ExtensionDownloader.init();
|
|
||||||
ExtensionSystem.init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let _workspaces = [];
|
let _workspaces = [];
|
||||||
@ -414,6 +509,9 @@ function loadTheme() {
|
|||||||
|
|
||||||
let theme = new St.Theme ({ application_stylesheet: cssStylesheet });
|
let theme = new St.Theme ({ application_stylesheet: cssStylesheet });
|
||||||
|
|
||||||
|
if (sessionMode.extraStylesheet)
|
||||||
|
theme.load_stylesheet(sessionMode.extraStylesheet);
|
||||||
|
|
||||||
if (previousTheme) {
|
if (previousTheme) {
|
||||||
let customStylesheets = previousTheme.get_custom_stylesheets();
|
let customStylesheets = previousTheme.get_custom_stylesheets();
|
||||||
|
|
||||||
@ -434,6 +532,7 @@ function notify(msg, details) {
|
|||||||
messageTray.add(source);
|
messageTray.add(source);
|
||||||
let notification = new MessageTray.Notification(source, msg, details);
|
let notification = new MessageTray.Notification(source, msg, details);
|
||||||
notification.setTransient(true);
|
notification.setTransient(true);
|
||||||
|
notification.setShowWhenLocked(true);
|
||||||
source.notify(notification);
|
source.notify(notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,6 +588,12 @@ function _globalKeyPressHandler(actor, event) {
|
|||||||
// This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType
|
// This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType
|
||||||
let action = global.display.get_keybinding_action(keyCode, modifierState);
|
let action = global.display.get_keybinding_action(keyCode, modifierState);
|
||||||
|
|
||||||
|
// This isn't a Meta.KeyBindingAction yet
|
||||||
|
if (symbol == Clutter.Super_L || symbol == Clutter.Super_R) {
|
||||||
|
overview.hide();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (action == Meta.KeyBindingAction.SWITCH_PANELS) {
|
if (action == Meta.KeyBindingAction.SWITCH_PANELS) {
|
||||||
ctrlAltTabManager.popup(modifierState & Clutter.ModifierType.SHIFT_MASK,
|
ctrlAltTabManager.popup(modifierState & Clutter.ModifierType.SHIFT_MASK,
|
||||||
modifierState);
|
modifierState);
|
||||||
@ -528,10 +633,9 @@ function _globalKeyPressHandler(actor, event) {
|
|||||||
if (!sessionMode.hasRunDialog)
|
if (!sessionMode.hasRunDialog)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
openRunDialog();
|
getRunDialog().open();
|
||||||
return true;
|
return true;
|
||||||
case Meta.KeyBindingAction.PANEL_MAIN_MENU:
|
case Meta.KeyBindingAction.PANEL_MAIN_MENU:
|
||||||
case Meta.KeyBindingAction.OVERLAY_KEY:
|
|
||||||
overview.hide();
|
overview.hide();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -674,11 +778,11 @@ function createLookingGlass() {
|
|||||||
return lookingGlass;
|
return lookingGlass;
|
||||||
}
|
}
|
||||||
|
|
||||||
function openRunDialog() {
|
function getRunDialog() {
|
||||||
if (runDialog == null) {
|
if (runDialog == null) {
|
||||||
runDialog = new RunDialog.RunDialog();
|
runDialog = new RunDialog.RunDialog();
|
||||||
}
|
}
|
||||||
runDialog.open();
|
return runDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
1365
js/ui/messageTray.js
1365
js/ui/messageTray.js
File diff suppressed because it is too large
Load Diff
@ -14,12 +14,12 @@ const Atk = imports.gi.Atk;
|
|||||||
|
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
|
|
||||||
const Layout = imports.ui.layout;
|
|
||||||
const Lightbox = imports.ui.lightbox;
|
const Lightbox = imports.ui.lightbox;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
const OPEN_AND_CLOSE_TIME = 0.1;
|
const OPEN_AND_CLOSE_TIME = 0.1;
|
||||||
|
const FADE_IN_BUTTONS_TIME = 0.33;
|
||||||
const FADE_OUT_DIALOG_TIME = 1.0;
|
const FADE_OUT_DIALOG_TIME = 1.0;
|
||||||
|
|
||||||
const State = {
|
const State = {
|
||||||
@ -36,13 +36,12 @@ const ModalDialog = new Lang.Class({
|
|||||||
_init: function(params) {
|
_init: function(params) {
|
||||||
params = Params.parse(params, { shellReactive: false,
|
params = Params.parse(params, { shellReactive: false,
|
||||||
styleClass: null,
|
styleClass: null,
|
||||||
parentActor: Main.uiGroup,
|
parentActor: Main.uiGroup
|
||||||
shouldFadeIn: true });
|
});
|
||||||
|
|
||||||
this.state = State.CLOSED;
|
this.state = State.CLOSED;
|
||||||
this._hasModal = false;
|
this._hasModal = false;
|
||||||
this._shellReactive = params.shellReactive;
|
this._shellReactive = params.shellReactive;
|
||||||
this._shouldFadeIn = params.shouldFadeIn;
|
|
||||||
|
|
||||||
this._group = new St.Widget({ visible: false,
|
this._group = new St.Widget({ visible: false,
|
||||||
x: 0,
|
x: 0,
|
||||||
@ -60,14 +59,12 @@ const ModalDialog = new Lang.Class({
|
|||||||
this._group.connect('key-release-event', Lang.bind(this, this._onKeyReleaseEvent));
|
this._group.connect('key-release-event', Lang.bind(this, this._onKeyReleaseEvent));
|
||||||
|
|
||||||
this._backgroundBin = new St.Bin();
|
this._backgroundBin = new St.Bin();
|
||||||
this._monitorConstraint = new Layout.MonitorConstraint();
|
|
||||||
this._backgroundBin.add_constraint(this._monitorConstraint);
|
|
||||||
this._group.add_actor(this._backgroundBin);
|
this._group.add_actor(this._backgroundBin);
|
||||||
|
|
||||||
this.dialogLayout = new St.BoxLayout({ style_class: 'modal-dialog',
|
this._dialogLayout = new St.BoxLayout({ style_class: 'modal-dialog',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
if (params.styleClass != null) {
|
if (params.styleClass != null) {
|
||||||
this.dialogLayout.add_style_class_name(params.styleClass);
|
this._dialogLayout.add_style_class_name(params.styleClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._shellReactive) {
|
if (!this._shellReactive) {
|
||||||
@ -80,29 +77,29 @@ const ModalDialog = new Lang.Class({
|
|||||||
|
|
||||||
this._eventBlocker = new Clutter.Group({ reactive: true });
|
this._eventBlocker = new Clutter.Group({ reactive: true });
|
||||||
stack.add_actor(this._eventBlocker);
|
stack.add_actor(this._eventBlocker);
|
||||||
stack.add_actor(this.dialogLayout);
|
stack.add_actor(this._dialogLayout);
|
||||||
} else {
|
} else {
|
||||||
this._backgroundBin.child = this.dialogLayout;
|
this._backgroundBin.child = this._dialogLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.contentLayout = new St.BoxLayout({ vertical: true });
|
this.contentLayout = new St.BoxLayout({ vertical: true });
|
||||||
this.dialogLayout.add(this.contentLayout,
|
this._dialogLayout.add(this.contentLayout,
|
||||||
{ x_fill: true,
|
{ x_fill: true,
|
||||||
y_fill: true,
|
y_fill: true,
|
||||||
x_align: St.Align.MIDDLE,
|
x_align: St.Align.MIDDLE,
|
||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
|
|
||||||
this._buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box',
|
this._buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box',
|
||||||
visible: false,
|
visible: false,
|
||||||
vertical: false });
|
vertical: false });
|
||||||
this.dialogLayout.add(this._buttonLayout,
|
this._dialogLayout.add(this._buttonLayout,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
x_align: St.Align.MIDDLE,
|
x_align: St.Align.MIDDLE,
|
||||||
y_align: St.Align.END });
|
y_align: St.Align.END });
|
||||||
|
|
||||||
global.focus_manager.add_group(this.dialogLayout);
|
global.focus_manager.add_group(this._dialogLayout);
|
||||||
this._initialKeyFocus = this.dialogLayout;
|
this._initialKeyFocus = this._dialogLayout;
|
||||||
this._initialKeyFocusDestroyId = 0;
|
this._initialKeyFocusDestroyId = 0;
|
||||||
this._savedKeyFocus = null;
|
this._savedKeyFocus = null;
|
||||||
},
|
},
|
||||||
@ -116,6 +113,8 @@ const ModalDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
setButtons: function(buttons) {
|
setButtons: function(buttons) {
|
||||||
|
let hadChildren = this._buttonLayout.get_children() > 0;
|
||||||
|
|
||||||
this._buttonLayout.destroy_all_children();
|
this._buttonLayout.destroy_all_children();
|
||||||
this._actionKeys = {};
|
this._actionKeys = {};
|
||||||
|
|
||||||
@ -128,11 +127,8 @@ const ModalDialog = new Lang.Class({
|
|||||||
let key = buttonInfo['key'];
|
let key = buttonInfo['key'];
|
||||||
let isDefault = buttonInfo['default'];
|
let isDefault = buttonInfo['default'];
|
||||||
|
|
||||||
if (isDefault && !key) {
|
if (isDefault && !key)
|
||||||
this._actionKeys[Clutter.KEY_KP_Enter] = action;
|
|
||||||
this._actionKeys[Clutter.KEY_ISO_Enter] = action;
|
|
||||||
key = Clutter.KEY_Return;
|
key = Clutter.KEY_Return;
|
||||||
}
|
|
||||||
|
|
||||||
buttonInfo.button = new St.Button({ style_class: 'modal-dialog-button',
|
buttonInfo.button = new St.Button({ style_class: 'modal-dialog-button',
|
||||||
reactive: true,
|
reactive: true,
|
||||||
@ -166,7 +162,21 @@ const ModalDialog = new Lang.Class({
|
|||||||
this._actionKeys[key] = action;
|
this._actionKeys[key] = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit('buttons-set');
|
// Fade in buttons if there weren't any before
|
||||||
|
if (!hadChildren && buttons.length > 0) {
|
||||||
|
this._buttonLayout.opacity = 0;
|
||||||
|
Tweener.addTween(this._buttonLayout,
|
||||||
|
{ opacity: 255,
|
||||||
|
time: FADE_IN_BUTTONS_TIME,
|
||||||
|
transition: 'easeOutQuad',
|
||||||
|
onComplete: Lang.bind(this, function() {
|
||||||
|
this.emit('buttons-set');
|
||||||
|
})
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.emit('buttons-set');
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onKeyReleaseEvent: function(object, event) {
|
_onKeyReleaseEvent: function(object, event) {
|
||||||
@ -185,22 +195,22 @@ const ModalDialog = new Lang.Class({
|
|||||||
this.emit('destroy');
|
this.emit('destroy');
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeOpen: function(onPrimary) {
|
_fadeOpen: function() {
|
||||||
if (onPrimary)
|
let monitor = Main.layoutManager.currentMonitor;
|
||||||
this._monitorConstraint.primary = true;
|
|
||||||
else
|
this._backgroundBin.set_position(monitor.x, monitor.y);
|
||||||
this._monitorConstraint.index = global.screen.get_current_monitor();
|
this._backgroundBin.set_size(monitor.width, monitor.height);
|
||||||
|
|
||||||
this.state = State.OPENING;
|
this.state = State.OPENING;
|
||||||
|
|
||||||
this.dialogLayout.opacity = 255;
|
this._dialogLayout.opacity = 255;
|
||||||
if (this._lightbox)
|
if (this._lightbox)
|
||||||
this._lightbox.show();
|
this._lightbox.show();
|
||||||
this._group.opacity = 0;
|
this._group.opacity = 0;
|
||||||
this._group.show();
|
this._group.show();
|
||||||
Tweener.addTween(this._group,
|
Tweener.addTween(this._group,
|
||||||
{ opacity: 255,
|
{ opacity: 255,
|
||||||
time: this._shouldFadeIn ? OPEN_AND_CLOSE_TIME : 0,
|
time: OPEN_AND_CLOSE_TIME,
|
||||||
transition: 'easeOutQuad',
|
transition: 'easeOutQuad',
|
||||||
onComplete: Lang.bind(this,
|
onComplete: Lang.bind(this,
|
||||||
function() {
|
function() {
|
||||||
@ -217,19 +227,19 @@ const ModalDialog = new Lang.Class({
|
|||||||
this._initialKeyFocus = actor;
|
this._initialKeyFocus = actor;
|
||||||
|
|
||||||
this._initialKeyFocusDestroyId = actor.connect('destroy', Lang.bind(this, function() {
|
this._initialKeyFocusDestroyId = actor.connect('destroy', Lang.bind(this, function() {
|
||||||
this._initialKeyFocus = this.dialogLayout;
|
this._initialKeyFocus = this._dialogLayout;
|
||||||
this._initialKeyFocusDestroyId = 0;
|
this._initialKeyFocusDestroyId = 0;
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
open: function(timestamp, onPrimary) {
|
open: function(timestamp) {
|
||||||
if (this.state == State.OPENED || this.state == State.OPENING)
|
if (this.state == State.OPENED || this.state == State.OPENING)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!this.pushModal(timestamp))
|
if (!this.pushModal(timestamp))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
this._fadeOpen(onPrimary);
|
this._fadeOpen();
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -310,7 +320,7 @@ const ModalDialog = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
this.popModal(timestamp);
|
this.popModal(timestamp);
|
||||||
Tweener.addTween(this.dialogLayout,
|
Tweener.addTween(this._dialogLayout,
|
||||||
{ opacity: 0,
|
{ opacity: 0,
|
||||||
time: FADE_OUT_DIALOG_TIME,
|
time: FADE_OUT_DIALOG_TIME,
|
||||||
transition: 'easeOutQuad',
|
transition: 'easeOutQuad',
|
||||||
|
@ -1,4 +1,23 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Giovanni Campagna <scampa.giovanni@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
@ -116,10 +135,7 @@ const NetworkSecretDialog = new Lang.Class({
|
|||||||
} else
|
} else
|
||||||
secret.valid = true;
|
secret.valid = true;
|
||||||
|
|
||||||
secretTable.add(label, { row: pos, col: 0,
|
secretTable.add(label, { row: pos, col: 0, x_expand: false, x_fill: true, x_align: St.Align.START, y_align: St.Align.START });
|
||||||
x_expand: false, x_fill: true,
|
|
||||||
x_align: St.Align.START,
|
|
||||||
y_fill: false, y_align: St.Align.MIDDLE });
|
|
||||||
secretTable.add(secret.entry, { row: pos, col: 1, x_expand: true, x_fill: true, y_align: St.Align.END });
|
secretTable.add(secret.entry, { row: pos, col: 1, x_expand: true, x_fill: true, y_align: St.Align.END });
|
||||||
pos++;
|
pos++;
|
||||||
|
|
||||||
@ -149,7 +165,6 @@ const NetworkSecretDialog = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._okButton.button.reactive = valid;
|
this._okButton.button.reactive = valid;
|
||||||
this._okButton.button.can_focus = valid;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onOk: function() {
|
_onOk: function() {
|
||||||
@ -408,10 +423,7 @@ const VPNRequestHandler = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
cancel: function(respond) {
|
cancel: function() {
|
||||||
if (respond)
|
|
||||||
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.USER_CANCELED);
|
|
||||||
|
|
||||||
if (this._newStylePlugin && this._shellDialog) {
|
if (this._newStylePlugin && this._shellDialog) {
|
||||||
this._shellDialog.close(global.get_current_time());
|
this._shellDialog.close(global.get_current_time());
|
||||||
this._shellDialog.destroy();
|
this._shellDialog.destroy();
|
||||||
@ -587,7 +599,7 @@ const NetworkAgent = new Lang.Class({
|
|||||||
Name: 'NetworkAgent',
|
Name: 'NetworkAgent',
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._native = new Shell.NetworkAgent({ auto_register: false,
|
this._native = new Shell.NetworkAgent({ auto_register: true,
|
||||||
identifier: 'org.gnome.Shell.NetworkAgent' });
|
identifier: 'org.gnome.Shell.NetworkAgent' });
|
||||||
|
|
||||||
this._dialogs = { };
|
this._dialogs = { };
|
||||||
@ -597,24 +609,6 @@ const NetworkAgent = new Lang.Class({
|
|||||||
this._native.connect('cancel-request', Lang.bind(this, this._cancelRequest));
|
this._native.connect('cancel-request', Lang.bind(this, this._cancelRequest));
|
||||||
},
|
},
|
||||||
|
|
||||||
enable: function() {
|
|
||||||
this._native.register();
|
|
||||||
},
|
|
||||||
|
|
||||||
disable: function() {
|
|
||||||
let requestId;
|
|
||||||
|
|
||||||
for (requestId in this._dialogs)
|
|
||||||
this._dialogs[requestId].cancel();
|
|
||||||
this._dialogs = { };
|
|
||||||
|
|
||||||
for (requestId in this._vpnRequests)
|
|
||||||
this._vpnRequests[requestId].cancel(true);
|
|
||||||
this._vpnRequests = { };
|
|
||||||
|
|
||||||
this._native.unregister();
|
|
||||||
},
|
|
||||||
|
|
||||||
_newRequest: function(agent, requestId, connection, settingName, hints, flags) {
|
_newRequest: function(agent, requestId, connection, settingName, hints, flags) {
|
||||||
if (settingName == 'vpn') {
|
if (settingName == 'vpn') {
|
||||||
this._vpnRequest(requestId, connection, hints, flags);
|
this._vpnRequest(requestId, connection, hints, flags);
|
||||||
@ -635,7 +629,7 @@ const NetworkAgent = new Lang.Class({
|
|||||||
this._dialogs[requestId].destroy();
|
this._dialogs[requestId].destroy();
|
||||||
delete this._dialogs[requestId];
|
delete this._dialogs[requestId];
|
||||||
} else if (this._vpnRequests[requestId]) {
|
} else if (this._vpnRequests[requestId]) {
|
||||||
this._vpnRequests[requestId].cancel(false);
|
this._vpnRequests[requestId].cancel();
|
||||||
delete this._vpnRequests[requestId];
|
delete this._vpnRequests[requestId];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -704,4 +698,3 @@ const NetworkAgent = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const Component = NetworkAgent;
|
|
@ -25,19 +25,10 @@ const BusIface = <interface name="org.freedesktop.DBus">
|
|||||||
</method>
|
</method>
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
const Bus = new Gio.DBusProxyClass({
|
var BusProxy = Gio.DBusProxy.makeProxyWrapper(BusIface);
|
||||||
Name: 'SessionBusProxy',
|
function Bus() {
|
||||||
Interface: BusIface,
|
return new BusProxy(Gio.DBus.session, 'org.freedesktop.DBus', '/org/freedesktop/DBus');
|
||||||
|
}
|
||||||
_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">
|
const NotificationDaemonIface = <interface name="org.freedesktop.Notifications">
|
||||||
<method name="Notify">
|
<method name="Notify">
|
||||||
@ -112,24 +103,21 @@ const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
|
|||||||
'ibus-ui-gtk': 'keyboard'
|
'ibus-ui-gtk': 'keyboard'
|
||||||
};
|
};
|
||||||
|
|
||||||
const NotificationDaemon = new Gio.DBusImplementerClass({
|
const NotificationDaemon = new Lang.Class({
|
||||||
Name: 'NotificationDaemon',
|
Name: 'NotificationDaemon',
|
||||||
Interface: NotificationDaemonIface,
|
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent();
|
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(NotificationDaemonIface, this);
|
||||||
this.export(Gio.DBus.session, '/org/freedesktop/Notifications');
|
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
|
||||||
|
|
||||||
this._sources = [];
|
this._sources = [];
|
||||||
this._senderToPid = {};
|
this._senderToPid = {};
|
||||||
this._notifications = {};
|
this._notifications = {};
|
||||||
this._busProxy = new Bus();
|
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._trayManager = new Shell.TrayManager();
|
||||||
this._trayIconAddedId = this._trayManager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
this._trayManager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
||||||
this._trayIconRemovedId = this._trayManager.connect('tray-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
|
this._trayManager.connect('tray-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
|
||||||
|
|
||||||
Shell.WindowTracker.get_default().connect('notify::focus-app',
|
Shell.WindowTracker.get_default().connect('notify::focus-app',
|
||||||
Lang.bind(this, this._onFocusAppChanged));
|
Lang.bind(this, this._onFocusAppChanged));
|
||||||
@ -268,7 +256,6 @@ const NotificationDaemon = new Gio.DBusImplementerClass({
|
|||||||
Mainloop.idle_add(Lang.bind(this,
|
Mainloop.idle_add(Lang.bind(this,
|
||||||
function () {
|
function () {
|
||||||
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
|
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
|
||||||
return false;
|
|
||||||
}));
|
}));
|
||||||
return invocation.return_value(GLib.Variant.new('(u)', [id]));
|
return invocation.return_value(GLib.Variant.new('(u)', [id]));
|
||||||
}
|
}
|
||||||
@ -328,20 +315,18 @@ const NotificationDaemon = new Gio.DBusImplementerClass({
|
|||||||
return invocation.return_value(GLib.Variant.new('(u)', [id]));;
|
return invocation.return_value(GLib.Variant.new('(u)', [id]));;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._busProxy.GetConnectionUnixProcessIDRemote(sender, null, Lang.bind(this, function (proxy, result) {
|
this._busProxy.GetConnectionUnixProcessIDRemote(sender, Lang.bind(this, function (result, excp) {
|
||||||
// The app may have updated or removed the notification
|
// The app may have updated or removed the notification
|
||||||
ndata = this._notifications[id];
|
ndata = this._notifications[id];
|
||||||
if (!ndata)
|
if (!ndata)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let pid;
|
if (excp) {
|
||||||
try {
|
|
||||||
[pid] = proxy.GetConnectionUnixProcessIDFinish(result);
|
|
||||||
} catch(excp) {
|
|
||||||
logError(excp, 'Call to GetConnectionUnixProcessID failed');
|
logError(excp, 'Call to GetConnectionUnixProcessID failed');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let [pid] = result;
|
||||||
source = this._getSource(appName, pid, ndata, sender, null);
|
source = this._getSource(appName, pid, ndata, sender, null);
|
||||||
|
|
||||||
// We only store sender-pid entries for persistent sources.
|
// We only store sender-pid entries for persistent sources.
|
||||||
@ -370,10 +355,13 @@ const NotificationDaemon = new Gio.DBusImplementerClass({
|
|||||||
ndata.actions, ndata.hints, ndata.notification];
|
ndata.actions, ndata.hints, ndata.notification];
|
||||||
|
|
||||||
let gicon = this._iconForNotificationData(icon, hints);
|
let gicon = this._iconForNotificationData(icon, hints);
|
||||||
|
let iconActor = new St.Icon({ gicon: gicon,
|
||||||
|
icon_type: St.IconType.FULLCOLOR,
|
||||||
|
icon_size: source.ICON_SIZE });
|
||||||
|
|
||||||
if (notification == null) {
|
if (notification == null) {
|
||||||
notification = new MessageTray.Notification(source, summary, body,
|
notification = new MessageTray.Notification(source, summary, body,
|
||||||
{ gicon: gicon,
|
{ icon: iconActor,
|
||||||
bannerMarkup: true });
|
bannerMarkup: true });
|
||||||
ndata.notification = notification;
|
ndata.notification = notification;
|
||||||
notification.connect('destroy', Lang.bind(this,
|
notification.connect('destroy', Lang.bind(this,
|
||||||
@ -398,7 +386,7 @@ const NotificationDaemon = new Gio.DBusImplementerClass({
|
|||||||
this._emitActionInvoked(ndata.id, actionId);
|
this._emitActionInvoked(ndata.id, actionId);
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
notification.update(summary, body, { gicon: gicon,
|
notification.update(summary, body, { icon: iconActor,
|
||||||
bannerMarkup: true,
|
bannerMarkup: true,
|
||||||
clear: true });
|
clear: true });
|
||||||
}
|
}
|
||||||
@ -501,15 +489,17 @@ const NotificationDaemon = new Gio.DBusImplementerClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_emitNotificationClosed: function(id, reason) {
|
_emitNotificationClosed: function(id, reason) {
|
||||||
this.emit_signal('NotificationClosed', id, reason);
|
this._dbusImpl.emit_signal('NotificationClosed',
|
||||||
|
GLib.Variant.new('(uu)', [id, reason]));
|
||||||
},
|
},
|
||||||
|
|
||||||
_emitActionInvoked: function(id, action) {
|
_emitActionInvoked: function(id, action) {
|
||||||
this.emit_signal('ActionInvoked', id, action);
|
this._dbusImpl.emit_signal('ActionInvoked',
|
||||||
|
GLib.Variant.new('(us)', [id, action]));
|
||||||
},
|
},
|
||||||
|
|
||||||
_onTrayIconAdded: function(o, icon) {
|
_onTrayIconAdded: function(o, icon) {
|
||||||
let wmClass = icon.wm_class ? icon.wm_class.toLowerCase() : '';
|
let wmClass = icon.wm_class.toLowerCase();
|
||||||
if (STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass] !== undefined)
|
if (STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass] !== undefined)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -593,12 +583,18 @@ const Source = new Lang.Class({
|
|||||||
this.notifications.length > 0)
|
this.notifications.length > 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
let id = global.connect('notify::stage-input-mode', Lang.bind(this, function () {
|
if (Main.overview.visible) {
|
||||||
global.disconnect(id);
|
// We can't just connect to Main.overview's 'hidden' signal,
|
||||||
|
// because it's emitted *before* it calls popModal()...
|
||||||
|
let id = global.connect('notify::stage-input-mode', Lang.bind(this,
|
||||||
|
function () {
|
||||||
|
global.disconnect(id);
|
||||||
|
this.trayIcon.click(event);
|
||||||
|
}));
|
||||||
|
Main.overview.hide();
|
||||||
|
} else {
|
||||||
this.trayIcon.click(event);
|
this.trayIcon.click(event);
|
||||||
}));
|
}
|
||||||
|
|
||||||
Main.overview.hide();
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -634,16 +630,6 @@ const Source = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setTitle: function(title) {
|
|
||||||
// Do nothing if .app is set, we don't want to override the
|
|
||||||
// app name with whatever is provided through libnotify (usually
|
|
||||||
// garbage)
|
|
||||||
if (this.app)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.parent(title);
|
|
||||||
},
|
|
||||||
|
|
||||||
open: function(notification) {
|
open: function(notification) {
|
||||||
this.destroyNonResidentNotifications();
|
this.destroyNonResidentNotifications();
|
||||||
this.openApp();
|
this.openApp();
|
||||||
|
@ -10,21 +10,26 @@ const St = imports.gi.St;
|
|||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Gdk = imports.gi.Gdk;
|
const Gdk = imports.gi.Gdk;
|
||||||
|
|
||||||
|
const AppDisplay = imports.ui.appDisplay;
|
||||||
const Dash = imports.ui.dash;
|
const Dash = imports.ui.dash;
|
||||||
const DND = imports.ui.dnd;
|
const DND = imports.ui.dnd;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
const Panel = imports.ui.panel;
|
const Panel = imports.ui.panel;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
|
const PlaceDisplay = imports.ui.placeDisplay;
|
||||||
|
const RemoteSearch = imports.ui.remoteSearch;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
const ViewSelector = imports.ui.viewSelector;
|
const ViewSelector = imports.ui.viewSelector;
|
||||||
|
const Wanda = imports.ui.wanda;
|
||||||
|
const WorkspacesView = imports.ui.workspacesView;
|
||||||
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
|
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
|
||||||
|
|
||||||
// Time for initial animation going into Overview mode
|
// Time for initial animation going into Overview mode
|
||||||
const ANIMATION_TIME = 0.25;
|
const ANIMATION_TIME = 0.25;
|
||||||
|
|
||||||
// XXX -- grab this automatically. Hard to do.
|
// We split the screen vertically between the dash and the view selector.
|
||||||
const DASH_MAX_WIDTH = 96;
|
const DASH_SPLIT_FRACTION = 0.1;
|
||||||
|
|
||||||
const DND_WINDOW_SWITCH_TIMEOUT = 1250;
|
const DND_WINDOW_SWITCH_TIMEOUT = 1250;
|
||||||
|
|
||||||
@ -70,12 +75,14 @@ const ShellInfo = new Lang.Class({
|
|||||||
let notification = null;
|
let notification = null;
|
||||||
if (this._source.notifications.length == 0) {
|
if (this._source.notifications.length == 0) {
|
||||||
notification = new MessageTray.Notification(this._source, text, null);
|
notification = new MessageTray.Notification(this._source, text, null);
|
||||||
notification.setTransient(true);
|
notification.setShowWhenLocked(true);
|
||||||
} else {
|
} else {
|
||||||
notification = this._source.notifications[0];
|
notification = this._source.notifications[0];
|
||||||
notification.update(text, null, { clear: true });
|
notification.update(text, null, { clear: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
notification.setTransient(true);
|
||||||
|
|
||||||
this._undoCallback = undoCallback;
|
this._undoCallback = undoCallback;
|
||||||
if (undoCallback) {
|
if (undoCallback) {
|
||||||
notification.addButton('system-undo',
|
notification.addButton('system-undo',
|
||||||
@ -91,21 +98,16 @@ const ShellInfo = new Lang.Class({
|
|||||||
const Overview = new Lang.Class({
|
const Overview = new Lang.Class({
|
||||||
Name: 'Overview',
|
Name: 'Overview',
|
||||||
|
|
||||||
_init: function() {
|
_init : function() {
|
||||||
this._overviewCreated = false;
|
this.isDummy = !Main.sessionMode.hasOverview;
|
||||||
|
|
||||||
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
// We only have an overview in user sessions, so
|
||||||
this._sessionUpdated();
|
// create a dummy overview in other cases
|
||||||
},
|
if (this.isDummy) {
|
||||||
|
this.animationInProgress = false;
|
||||||
_createOverview: function() {
|
this.visible = false;
|
||||||
if (this._overviewCreated)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (this.isDummy)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._overviewCreated = true;
|
|
||||||
|
|
||||||
// The main BackgroundActor is inside global.window_group which is
|
// The main BackgroundActor is inside global.window_group which is
|
||||||
// hidden when displaying the overview, so we create a new
|
// hidden when displaying the overview, so we create a new
|
||||||
@ -142,6 +144,8 @@ const Overview = new Lang.Class({
|
|||||||
this._capturedEventId = 0;
|
this._capturedEventId = 0;
|
||||||
this._buttonPressId = 0;
|
this._buttonPressId = 0;
|
||||||
|
|
||||||
|
this._workspacesDisplay = null;
|
||||||
|
|
||||||
this.visible = false; // animating to overview, in overview, animating out
|
this.visible = false; // animating to overview, in overview, animating out
|
||||||
this._shown = false; // show() and not hide()
|
this._shown = false; // show() and not hide()
|
||||||
this._shownTemporarily = false; // showTemporarily() and not hideTemporarily()
|
this._shownTemporarily = false; // showTemporarily() and not hideTemporarily()
|
||||||
@ -178,11 +182,6 @@ const Overview = new Lang.Class({
|
|||||||
this._needsFakePointerEvent = false;
|
this._needsFakePointerEvent = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
_sessionUpdated: function() {
|
|
||||||
this.isDummy = !Main.sessionMode.hasOverview;
|
|
||||||
this._createOverview();
|
|
||||||
},
|
|
||||||
|
|
||||||
// The members we construct that are implemented in JS might
|
// The members we construct that are implemented in JS might
|
||||||
// want to access the overview as Main.overview to connect
|
// want to access the overview as Main.overview to connect
|
||||||
// signal handlers and so forth. So we create them after
|
// signal handlers and so forth. So we create them after
|
||||||
@ -193,23 +192,29 @@ const Overview = new Lang.Class({
|
|||||||
|
|
||||||
this._shellInfo = new ShellInfo();
|
this._shellInfo = new ShellInfo();
|
||||||
|
|
||||||
this._searchEntry = new St.Entry({ name: 'searchEntry',
|
this._viewSelector = new ViewSelector.ViewSelector();
|
||||||
/* Translators: this is the text displayed
|
|
||||||
in the search entry when no search is
|
|
||||||
active; it should not exceed ~30
|
|
||||||
characters. */
|
|
||||||
hint_text: _("Type to search..."),
|
|
||||||
track_hover: true,
|
|
||||||
can_focus: true });
|
|
||||||
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._viewSelector.actor);
|
||||||
this._group.add_actor(this._dash.actor);
|
|
||||||
|
this._workspacesDisplay = new WorkspacesView.WorkspacesDisplay();
|
||||||
|
this._viewSelector.addViewTab('windows', _("Windows"), this._workspacesDisplay.actor, 'text-x-generic');
|
||||||
|
|
||||||
|
let appView = new AppDisplay.AllAppDisplay();
|
||||||
|
this._viewSelector.addViewTab('applications', _("Applications"), appView.actor, 'system-run');
|
||||||
|
|
||||||
|
// Default search providers
|
||||||
|
// Wanda comes obviously first
|
||||||
|
this.addSearchProvider(new Wanda.WandaSearchProvider());
|
||||||
|
this.addSearchProvider(new AppDisplay.AppSearchProvider());
|
||||||
|
this.addSearchProvider(new AppDisplay.SettingsSearchProvider());
|
||||||
|
this.addSearchProvider(new PlaceDisplay.PlaceSearchProvider());
|
||||||
|
|
||||||
|
// Load remote search providers provided by applications
|
||||||
|
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
|
||||||
|
|
||||||
// TODO - recalculate everything when desktop size changes
|
// 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.constrainY);
|
||||||
this._dash.actor.add_constraint(this._viewSelector.constrainHeight);
|
this._dash.actor.add_constraint(this._viewSelector.constrainHeight);
|
||||||
this.dashIconSize = this._dash.iconSize;
|
this.dashIconSize = this._dash.iconSize;
|
||||||
this._dash.connect('icon-size-changed',
|
this._dash.connect('icon-size-changed',
|
||||||
@ -219,7 +224,7 @@ const Overview = new Lang.Class({
|
|||||||
|
|
||||||
// Translators: this is the name of the dock/favorites area on
|
// Translators: this is the name of the dock/favorites area on
|
||||||
// the left of the overview
|
// the left of the overview
|
||||||
Main.ctrlAltTabManager.addGroup(this._dash.actor, _("Dash"), 'user-bookmarks-symbolic');
|
Main.ctrlAltTabManager.addGroup(this._dash.actor, _("Dash"), 'user-bookmarks');
|
||||||
|
|
||||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._relayout));
|
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._relayout));
|
||||||
this._relayout();
|
this._relayout();
|
||||||
@ -470,9 +475,7 @@ const Overview = new Lang.Class({
|
|||||||
if (windows.length == 0)
|
if (windows.length == 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
let window = windows[0];
|
let clone = new Clutter.Clone({ source: windows[0].get_texture() });
|
||||||
let clone = new Clutter.Clone({ source: window.get_texture(),
|
|
||||||
x: window.x, y: window.y });
|
|
||||||
clone.source.connect('destroy', Lang.bind(this, function() {
|
clone.source.connect('destroy', Lang.bind(this, function() {
|
||||||
clone.destroy();
|
clone.destroy();
|
||||||
}));
|
}));
|
||||||
@ -497,13 +500,13 @@ const Overview = new Lang.Class({
|
|||||||
this._coverPane.set_position(0, contentY);
|
this._coverPane.set_position(0, contentY);
|
||||||
this._coverPane.set_size(primary.width, contentHeight);
|
this._coverPane.set_size(primary.width, contentHeight);
|
||||||
|
|
||||||
let searchWidth = this._searchEntry.get_width();
|
let dashWidth = Math.round(DASH_SPLIT_FRACTION * primary.width);
|
||||||
let searchHeight = this._searchEntry.get_height();
|
let viewWidth = primary.width - dashWidth - this._spacing;
|
||||||
let searchX = (primary.width - searchWidth) / 2;
|
let viewHeight = contentHeight - 2 * this._spacing;
|
||||||
let searchY = contentY + this._spacing;
|
let viewY = contentY + this._spacing;
|
||||||
|
let viewX = rtl ? 0 : dashWidth + this._spacing;
|
||||||
|
|
||||||
let dashWidth = DASH_MAX_WIDTH;
|
// Set the dash's x position - y is handled by a constraint
|
||||||
let dashY = searchY + searchHeight + this._spacing;
|
|
||||||
let dashX;
|
let dashX;
|
||||||
if (rtl) {
|
if (rtl) {
|
||||||
this._dash.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
this._dash.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
||||||
@ -511,14 +514,8 @@ const Overview = new Lang.Class({
|
|||||||
} else {
|
} else {
|
||||||
dashX = 0;
|
dashX = 0;
|
||||||
}
|
}
|
||||||
|
this._dash.actor.set_x(dashX);
|
||||||
|
|
||||||
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_position(viewX, viewY);
|
||||||
this._viewSelector.actor.set_size(viewWidth, viewHeight);
|
this._viewSelector.actor.set_size(viewWidth, viewHeight);
|
||||||
},
|
},
|
||||||
@ -568,28 +565,6 @@ const Overview = new Lang.Class({
|
|||||||
Lang.bind(this, this._onButtonPress));
|
Lang.bind(this, this._onButtonPress));
|
||||||
},
|
},
|
||||||
|
|
||||||
fadeInDesktop: function() {
|
|
||||||
this._desktopFade.opacity = 0;
|
|
||||||
this._desktopFade.show();
|
|
||||||
Tweener.addTween(this._desktopFade,
|
|
||||||
{ opacity: 255,
|
|
||||||
time: ANIMATION_TIME,
|
|
||||||
transition: 'easeOutQuad' });
|
|
||||||
},
|
|
||||||
|
|
||||||
fadeOutDesktop: function() {
|
|
||||||
if (!this._desktopFade.child)
|
|
||||||
this._desktopFade.child = this._getDesktopClone();
|
|
||||||
|
|
||||||
this._desktopFade.opacity = 255;
|
|
||||||
this._desktopFade.show();
|
|
||||||
Tweener.addTween(this._desktopFade,
|
|
||||||
{ opacity: 0,
|
|
||||||
time: ANIMATION_TIME,
|
|
||||||
transition: 'easeOutQuad'
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_animateVisible: function() {
|
_animateVisible: function() {
|
||||||
if (this.visible || this.animationInProgress)
|
if (this.visible || this.animationInProgress)
|
||||||
return;
|
return;
|
||||||
@ -610,7 +585,21 @@ const Overview = new Lang.Class({
|
|||||||
global.window_group.hide();
|
global.window_group.hide();
|
||||||
this._group.show();
|
this._group.show();
|
||||||
this._background.show();
|
this._background.show();
|
||||||
this._viewSelector.show();
|
|
||||||
|
this._workspacesDisplay.show();
|
||||||
|
|
||||||
|
if (!this._desktopFade.child)
|
||||||
|
this._desktopFade.child = this._getDesktopClone();
|
||||||
|
|
||||||
|
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows()) {
|
||||||
|
this._desktopFade.opacity = 255;
|
||||||
|
this._desktopFade.show();
|
||||||
|
Tweener.addTween(this._desktopFade,
|
||||||
|
{ opacity: 0,
|
||||||
|
time: ANIMATION_TIME,
|
||||||
|
transition: 'easeOutQuad'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this._group.opacity = 0;
|
this._group.opacity = 0;
|
||||||
Tweener.addTween(this._group,
|
Tweener.addTween(this._group,
|
||||||
@ -737,7 +726,16 @@ const Overview = new Lang.Class({
|
|||||||
this.animationInProgress = true;
|
this.animationInProgress = true;
|
||||||
this._hideInProgress = true;
|
this._hideInProgress = true;
|
||||||
|
|
||||||
this._viewSelector.zoomFromOverview();
|
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows()) {
|
||||||
|
this._desktopFade.opacity = 0;
|
||||||
|
this._desktopFade.show();
|
||||||
|
Tweener.addTween(this._desktopFade,
|
||||||
|
{ opacity: 255,
|
||||||
|
time: ANIMATION_TIME,
|
||||||
|
transition: 'easeOutQuad' });
|
||||||
|
}
|
||||||
|
|
||||||
|
this._workspacesDisplay.zoomFromOverview();
|
||||||
|
|
||||||
// Make other elements fade out.
|
// Make other elements fade out.
|
||||||
Tweener.addTween(this._group,
|
Tweener.addTween(this._group,
|
||||||
@ -779,7 +777,8 @@ const Overview = new Lang.Class({
|
|||||||
|
|
||||||
global.window_group.show();
|
global.window_group.show();
|
||||||
|
|
||||||
this._viewSelector.hide();
|
this._workspacesDisplay.hide();
|
||||||
|
|
||||||
this._desktopFade.hide();
|
this._desktopFade.hide();
|
||||||
this._background.hide();
|
this._background.hide();
|
||||||
this._group.hide();
|
this._group.hide();
|
||||||
|
262
js/ui/panel.js
262
js/ui/panel.js
@ -14,14 +14,13 @@ const St = imports.gi.St;
|
|||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const Atk = imports.gi.Atk;
|
const Atk = imports.gi.Atk;
|
||||||
|
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
|
||||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||||
const DND = imports.ui.dnd;
|
const DND = imports.ui.dnd;
|
||||||
const Layout = imports.ui.layout;
|
const Layout = imports.ui.layout;
|
||||||
const Overview = imports.ui.overview;
|
const Overview = imports.ui.overview;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
const PanelMenu = imports.ui.panelMenu;
|
const PanelMenu = imports.ui.panelMenu;
|
||||||
|
const DateMenu = imports.ui.dateMenu;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
@ -222,14 +221,14 @@ const AppMenuButton = new Lang.Class({
|
|||||||
Name: 'AppMenuButton',
|
Name: 'AppMenuButton',
|
||||||
Extends: PanelMenu.Button,
|
Extends: PanelMenu.Button,
|
||||||
|
|
||||||
_init: function(panel) {
|
_init: function(menuManager) {
|
||||||
this.parent(0.0, null, true);
|
this.parent(0.0, null, true);
|
||||||
|
|
||||||
this.actor.accessible_role = Atk.Role.MENU;
|
this.actor.accessible_role = Atk.Role.MENU;
|
||||||
|
|
||||||
this._startingApps = [];
|
this._startingApps = [];
|
||||||
|
|
||||||
this._menuManager = panel.menuManager;
|
this._menuManager = menuManager;
|
||||||
this._targetApp = null;
|
this._targetApp = null;
|
||||||
this._appMenuNotifyId = 0;
|
this._appMenuNotifyId = 0;
|
||||||
this._actionGroupNotifyId = 0;
|
this._actionGroupNotifyId = 0;
|
||||||
@ -247,10 +246,6 @@ const AppMenuButton = new Lang.Class({
|
|||||||
this._container.connect('get-preferred-height', Lang.bind(this, this._getContentPreferredHeight));
|
this._container.connect('get-preferred-height', Lang.bind(this, this._getContentPreferredHeight));
|
||||||
this._container.connect('allocate', Lang.bind(this, this._contentAllocate));
|
this._container.connect('allocate', Lang.bind(this, this._contentAllocate));
|
||||||
|
|
||||||
let textureCache = St.TextureCache.get_default();
|
|
||||||
textureCache.connect('icon-theme-changed',
|
|
||||||
Lang.bind(this, this._onIconThemeChanged));
|
|
||||||
|
|
||||||
this._iconBox = new Shell.Slicer({ name: 'appMenuIcon' });
|
this._iconBox = new Shell.Slicer({ name: 'appMenuIcon' });
|
||||||
this._iconBox.connect('style-changed',
|
this._iconBox.connect('style-changed',
|
||||||
Lang.bind(this, this._onIconBoxStyleChanged));
|
Lang.bind(this, this._onIconBoxStyleChanged));
|
||||||
@ -290,7 +285,7 @@ const AppMenuButton = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
show: function() {
|
show: function() {
|
||||||
if (this._visible || Main.screenShield.locked)
|
if (this._visible)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._visible = true;
|
this._visible = true;
|
||||||
@ -336,15 +331,6 @@ const AppMenuButton = new Lang.Class({
|
|||||||
this._updateIconBoxClip();
|
this._updateIconBoxClip();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onIconThemeChanged: function() {
|
|
||||||
if (this._iconBox.child == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._iconBox.child.destroy();
|
|
||||||
let icon = this._targetApp.get_faded_icon(2 * PANEL_ICON_SIZE);
|
|
||||||
this._iconBox.set_child(icon);
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateIconBoxClip: function() {
|
_updateIconBoxClip: function() {
|
||||||
let allocation = this._iconBox.allocation;
|
let allocation = this._iconBox.allocation;
|
||||||
if (this._iconBottomClip > 0)
|
if (this._iconBottomClip > 0)
|
||||||
@ -481,6 +467,13 @@ const AppMenuButton = new Lang.Class({
|
|||||||
this._sync();
|
this._sync();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setLockedState: function(locked) {
|
||||||
|
if (locked)
|
||||||
|
this.hide();
|
||||||
|
else
|
||||||
|
this._sync();
|
||||||
|
},
|
||||||
|
|
||||||
_sync: function() {
|
_sync: function() {
|
||||||
let tracker = Shell.WindowTracker.get_default();
|
let tracker = Shell.WindowTracker.get_default();
|
||||||
let focusedApp = tracker.focus_app;
|
let focusedApp = tracker.focus_app;
|
||||||
@ -614,8 +607,8 @@ const ActivitiesButton = new Lang.Class({
|
|||||||
|
|
||||||
this.actor.label_actor = this._label;
|
this.actor.label_actor = this._label;
|
||||||
|
|
||||||
this.hotCorner = new Layout.HotCorner();
|
this._hotCorner = new Layout.HotCorner();
|
||||||
container.add_actor(this.hotCorner.actor);
|
container.add_actor(this._hotCorner.actor);
|
||||||
|
|
||||||
// Hack up our menu...
|
// Hack up our menu...
|
||||||
this.menu.open = Lang.bind(this, this._onMenuOpenRequest);
|
this.menu.open = Lang.bind(this, this._onMenuOpenRequest);
|
||||||
@ -665,10 +658,10 @@ const ActivitiesButton = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
hotBox.x1 = Math.round(x);
|
hotBox.x1 = Math.round(x);
|
||||||
hotBox.x2 = hotBox.x1 + this.hotCorner.actor.width;
|
hotBox.x2 = hotBox.x1 + this._hotCorner.actor.width;
|
||||||
hotBox.y1 = Math.round(y);
|
hotBox.y1 = Math.round(y);
|
||||||
hotBox.y2 = hotBox.y1 + this.hotCorner.actor.height;
|
hotBox.y2 = hotBox.y1 + this._hotCorner.actor.height;
|
||||||
this.hotCorner.actor.allocate(hotBox, flags);
|
this._hotCorner.actor.allocate(hotBox, flags);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleDragOver: function(source, actor, x, y, time) {
|
handleDragOver: function(source, actor, x, y, time) {
|
||||||
@ -690,7 +683,7 @@ const ActivitiesButton = new Lang.Class({
|
|||||||
|
|
||||||
_onCapturedEvent: function(actor, event) {
|
_onCapturedEvent: function(actor, event) {
|
||||||
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
|
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
|
||||||
if (!this.hotCorner.shouldToggleOverviewOnClick())
|
if (!this._hotCorner.shouldToggleOverviewOnClick())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -906,30 +899,6 @@ const PanelCorner = new Lang.Class({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const PANEL_ITEM_IMPLEMENTATIONS = {
|
|
||||||
'activities': ActivitiesButton,
|
|
||||||
'appMenu': AppMenuButton,
|
|
||||||
'dateMenu': imports.ui.dateMenu.DateMenuButton,
|
|
||||||
'a11y': imports.ui.status.accessibility.ATIndicator,
|
|
||||||
'volume': imports.ui.status.volume.Indicator,
|
|
||||||
'battery': imports.ui.status.power.Indicator,
|
|
||||||
'lockScreen': imports.ui.status.lockScreenMenu.Indicator,
|
|
||||||
'logo': imports.gdm.loginDialog.LogoMenuButton,
|
|
||||||
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
|
|
||||||
'powerMenu': imports.gdm.powerMenu.PowerMenuButton,
|
|
||||||
'userMenu': imports.ui.userMenu.UserMenuButton
|
|
||||||
};
|
|
||||||
|
|
||||||
if (Config.HAVE_BLUETOOTH)
|
|
||||||
PANEL_ITEM_IMPLEMENTATIONS['bluetooth'] =
|
|
||||||
imports.ui.status.bluetooth.Indicator;
|
|
||||||
|
|
||||||
try {
|
|
||||||
PANEL_ITEM_IMPLEMENTATIONS['network'] =
|
|
||||||
imports.ui.status.network.NMApplet;
|
|
||||||
} catch(e) {
|
|
||||||
log('NMApplet is not supported. It is possible that your NetworkManager version is too old');
|
|
||||||
}
|
|
||||||
|
|
||||||
const Panel = new Lang.Class({
|
const Panel = new Lang.Class({
|
||||||
Name: 'Panel',
|
Name: 'Panel',
|
||||||
@ -939,7 +908,7 @@ const Panel = new Lang.Class({
|
|||||||
reactive: true });
|
reactive: true });
|
||||||
this.actor._delegate = this;
|
this.actor._delegate = this;
|
||||||
|
|
||||||
this.statusArea = {};
|
this._statusArea = {};
|
||||||
|
|
||||||
Main.overview.connect('shown', Lang.bind(this, function () {
|
Main.overview.connect('shown', Lang.bind(this, function () {
|
||||||
this.actor.add_style_class_name('in-overview');
|
this.actor.add_style_class_name('in-overview');
|
||||||
@ -948,7 +917,9 @@ const Panel = new Lang.Class({
|
|||||||
this.actor.remove_style_class_name('in-overview');
|
this.actor.remove_style_class_name('in-overview');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.menuManager = new PopupMenu.PopupMenuManager(this);
|
Main.screenShield.connect('lock-status-changed', Lang.bind(this, this._onLockStateChanged));
|
||||||
|
|
||||||
|
this._menus = new PopupMenu.PopupMenuManager(this);
|
||||||
|
|
||||||
this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
|
this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
|
||||||
this.actor.add_actor(this._leftBox);
|
this.actor.add_actor(this._leftBox);
|
||||||
@ -975,12 +946,30 @@ const Panel = new Lang.Class({
|
|||||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||||
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
||||||
|
|
||||||
Main.layoutManager.panelBox.add(this.actor);
|
/* Button on the left side of the panel. */
|
||||||
Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'start-here-symbolic',
|
if (Main.sessionMode.hasOverview) {
|
||||||
{ sortGroup: CtrlAltTab.SortGroup.TOP });
|
this._activitiesButton = new ActivitiesButton();
|
||||||
|
this._activities = this._activitiesButton.actor;
|
||||||
|
this._leftBox.add(this._activities);
|
||||||
|
|
||||||
Main.sessionMode.connect('updated', Lang.bind(this, this._updatePanel));
|
// The activities button has a pretend menu, so as to integrate
|
||||||
this._updatePanel();
|
// more cleanly with the rest of the panel
|
||||||
|
this._menus.addMenu(this._activitiesButton.menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Main.sessionMode.hasAppMenu) {
|
||||||
|
this._appMenu = new AppMenuButton(this._menus);
|
||||||
|
this._leftBox.add(this._appMenu.actor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* center */
|
||||||
|
this._dateMenu = new DateMenu.DateMenuButton();
|
||||||
|
this._centerBox.add(this._dateMenu.actor, { y_fill: true });
|
||||||
|
this._menus.addMenu(this._dateMenu.menu);
|
||||||
|
|
||||||
|
Main.layoutManager.panelBox.add(this.actor);
|
||||||
|
Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'start-here',
|
||||||
|
{ sortGroup: CtrlAltTab.SortGroup.TOP });
|
||||||
},
|
},
|
||||||
|
|
||||||
_getPreferredWidth: function(actor, forHeight, alloc) {
|
_getPreferredWidth: function(actor, forHeight, alloc) {
|
||||||
@ -1040,19 +1029,16 @@ const Panel = new Lang.Class({
|
|||||||
}
|
}
|
||||||
this._rightBox.allocate(childBox, flags);
|
this._rightBox.allocate(childBox, flags);
|
||||||
|
|
||||||
let cornerMinWidth, cornerMinHeight;
|
let [cornerMinWidth, cornerWidth] = this._leftCorner.actor.get_preferred_width(-1);
|
||||||
let cornerWidth, cornerHeight;
|
let [cornerMinHeight, cornerHeight] = this._leftCorner.actor.get_preferred_width(-1);
|
||||||
|
|
||||||
[cornerMinWidth, cornerWidth] = this._leftCorner.actor.get_preferred_width(-1);
|
|
||||||
[cornerMinHeight, cornerHeight] = this._leftCorner.actor.get_preferred_height(-1);
|
|
||||||
childBox.x1 = 0;
|
childBox.x1 = 0;
|
||||||
childBox.x2 = cornerWidth;
|
childBox.x2 = cornerWidth;
|
||||||
childBox.y1 = allocHeight;
|
childBox.y1 = allocHeight;
|
||||||
childBox.y2 = allocHeight + cornerHeight;
|
childBox.y2 = allocHeight + cornerHeight;
|
||||||
this._leftCorner.actor.allocate(childBox, flags);
|
this._leftCorner.actor.allocate(childBox, flags);
|
||||||
|
|
||||||
[cornerMinWidth, cornerWidth] = this._rightCorner.actor.get_preferred_width(-1);
|
let [cornerMinWidth, cornerWidth] = this._rightCorner.actor.get_preferred_width(-1);
|
||||||
[cornerMinHeight, cornerHeight] = this._rightCorner.actor.get_preferred_height(-1);
|
let [cornerMinHeight, cornerHeight] = this._rightCorner.actor.get_preferred_width(-1);
|
||||||
childBox.x1 = allocWidth - cornerWidth;
|
childBox.x1 = allocWidth - cornerWidth;
|
||||||
childBox.x2 = allocWidth;
|
childBox.x2 = allocWidth;
|
||||||
childBox.y1 = allocHeight;
|
childBox.y1 = allocHeight;
|
||||||
@ -1100,126 +1086,76 @@ const Panel = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
openAppMenu: function() {
|
openAppMenu: function() {
|
||||||
let indicator = this.statusArea.appMenu;
|
let menu = this._appMenu.menu;
|
||||||
if (!indicator) // appMenu not supported by current session mode
|
if (!this._appMenu.actor.reactive || menu.isOpen)
|
||||||
return;
|
|
||||||
|
|
||||||
let menu = indicator.menu;
|
|
||||||
if (!indicator.actor.reactive || menu.isOpen)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
menu.open();
|
menu.open();
|
||||||
menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||||
},
|
},
|
||||||
|
|
||||||
set boxOpacity(value) {
|
startStatusArea: function() {
|
||||||
let isReactive = value > 0;
|
for (let i = 0; i < Main.sessionMode.statusArea.order.length; i++) {
|
||||||
|
let role = Main.sessionMode.statusArea.order[i];
|
||||||
this._leftBox.opacity = value;
|
let constructor = Main.sessionMode.statusArea.implementation[role];
|
||||||
this._leftBox.reactive = isReactive;
|
|
||||||
this._centerBox.opacity = value;
|
|
||||||
this._centerBox.reactive = isReactive;
|
|
||||||
this._rightBox.opacity = value;
|
|
||||||
this._rightBox.reactive = isReactive;
|
|
||||||
},
|
|
||||||
|
|
||||||
get boxOpacity() {
|
|
||||||
return this._leftBox.opacity;
|
|
||||||
},
|
|
||||||
|
|
||||||
_updatePanel: function() {
|
|
||||||
let panel = Main.sessionMode.panel;
|
|
||||||
this._hideIndicators();
|
|
||||||
this._updateBox(panel.left, this._leftBox);
|
|
||||||
this._updateBox(panel.center, this._centerBox);
|
|
||||||
this._updateBox(panel.right, this._rightBox);
|
|
||||||
},
|
|
||||||
|
|
||||||
_initBox: function(elements, box) {
|
|
||||||
for (let i = 0; i < elements.length; i++) {
|
|
||||||
let role = elements[i];
|
|
||||||
let constructor = PANEL_ITEM_IMPLEMENTATIONS[role];
|
|
||||||
if (!constructor) {
|
|
||||||
// panel icon is not supported (can happen for
|
|
||||||
// bluetooth or network)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_hideIndicators: function() {
|
|
||||||
for (let role in PANEL_ITEM_IMPLEMENTATIONS) {
|
|
||||||
let indicator = this.statusArea[role];
|
|
||||||
if (!indicator)
|
|
||||||
continue;
|
|
||||||
if (indicator.menu)
|
|
||||||
indicator.menu.close();
|
|
||||||
indicator.container.hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_ensureIndicator: function(role) {
|
|
||||||
let indicator = this.statusArea[role];
|
|
||||||
if (!indicator) {
|
|
||||||
let constructor = PANEL_ITEM_IMPLEMENTATIONS[role];
|
|
||||||
if (!constructor) {
|
if (!constructor) {
|
||||||
// This icon is not implemented (this is a bug)
|
// This icon is not implemented (this is a bug)
|
||||||
return null;
|
|
||||||
}
|
|
||||||
indicator = new constructor(this);
|
|
||||||
this.statusArea[role] = indicator;
|
|
||||||
}
|
|
||||||
return indicator;
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateBox: function(elements, box) {
|
|
||||||
let nChildren = box.get_n_children();
|
|
||||||
|
|
||||||
for (let i = 0; i < elements.length; i++) {
|
|
||||||
let role = elements[i];
|
|
||||||
let indicator = this._ensureIndicator(role);
|
|
||||||
if (indicator == null)
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
this._addToPanelBox(role, indicator, i + nChildren, box);
|
let indicator = new constructor();
|
||||||
|
this.addToStatusArea(role, indicator, i);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_addToPanelBox: function(role, indicator, position, box) {
|
_insertStatusItem: function(actor, position) {
|
||||||
let container = indicator.container;
|
let children = this._rightBox.get_children();
|
||||||
container.show();
|
let i;
|
||||||
|
for (i = children.length - 1; i >= 0; i--) {
|
||||||
let parent = container.get_parent();
|
let rolePosition = children[i]._rolePosition;
|
||||||
if (parent)
|
if (position > rolePosition) {
|
||||||
parent.remove_actor(container);
|
this._rightBox.insert_child_at_index(actor, i + 1);
|
||||||
|
break;
|
||||||
box.insert_child_at_index(container, position);
|
}
|
||||||
if (indicator.menu)
|
}
|
||||||
this.menuManager.addMenu(indicator.menu);
|
if (i == -1) {
|
||||||
this.statusArea[role] = indicator;
|
// If we didn't find a position, we must be first
|
||||||
let destroyId = indicator.connect('destroy', Lang.bind(this, function(emitter) {
|
this._rightBox.insert_child_at_index(actor, 0);
|
||||||
delete this.statusArea[role];
|
}
|
||||||
emitter.disconnect(destroyId);
|
actor._rolePosition = position;
|
||||||
container.destroy();
|
|
||||||
}));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addToStatusArea: function(role, indicator, position, box) {
|
addToStatusArea: function(role, indicator, position) {
|
||||||
if (this.statusArea[role])
|
if (this._statusArea[role])
|
||||||
throw new Error('Extension point conflict: there is already a status indicator for role ' + role);
|
throw new Error('Extension point conflict: there is already a status indicator for role ' + role);
|
||||||
|
|
||||||
if (!(indicator instanceof PanelMenu.Button))
|
if (!(indicator instanceof PanelMenu.Button))
|
||||||
throw new TypeError('Status indicator must be an instance of PanelMenu.Button');
|
throw new TypeError('Status indicator must be an instance of PanelMenu.Button');
|
||||||
|
|
||||||
position = position || 0;
|
if (!position)
|
||||||
let boxes = {
|
position = 0;
|
||||||
left: this._leftBox,
|
this._insertStatusItem(indicator.actor, position);
|
||||||
center: this._centerBox,
|
if (indicator.menu)
|
||||||
right: this._rightBox
|
this._menus.addMenu(indicator.menu);
|
||||||
};
|
|
||||||
let boxContainer = boxes[box] || this._rightBox;
|
this._statusArea[role] = indicator;
|
||||||
this.statusArea[role] = indicator;
|
let destroyId = indicator.connect('destroy', Lang.bind(this, function(emitter) {
|
||||||
this._addToPanelBox(role, indicator, position, boxContainer);
|
delete this._statusArea[role];
|
||||||
|
emitter.disconnect(destroyId);
|
||||||
|
}));
|
||||||
|
|
||||||
return indicator;
|
return indicator;
|
||||||
}
|
},
|
||||||
|
|
||||||
|
_onLockStateChanged: function(shield, locked) {
|
||||||
|
if (this._activitiesButton)
|
||||||
|
this._activitiesButton.setLockedState(locked);
|
||||||
|
if (this._appMenu)
|
||||||
|
this._appMenu.setLockedState(locked);
|
||||||
|
if (this._dateMenu)
|
||||||
|
this._dateMenu.setLockedState(locked);
|
||||||
|
|
||||||
|
for (let id in this._statusArea)
|
||||||
|
this._statusArea[id].setLockedState(locked);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gio = imports.gi.Gio;
|
|
||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
@ -21,10 +20,6 @@ const ButtonBox = new Lang.Class({
|
|||||||
this.actor = new Shell.GenericContainer(params);
|
this.actor = new Shell.GenericContainer(params);
|
||||||
this.actor._delegate = this;
|
this.actor._delegate = this;
|
||||||
|
|
||||||
this.container = new St.Bin({ y_fill: true,
|
|
||||||
x_fill: true,
|
|
||||||
child: this.actor });
|
|
||||||
|
|
||||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
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('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||||
@ -119,12 +114,6 @@ const Button = new Lang.Class({
|
|||||||
this.setName(nameText);
|
this.setName(nameText);
|
||||||
},
|
},
|
||||||
|
|
||||||
setSensitive: function(sensitive) {
|
|
||||||
this.actor.reactive = sensitive;
|
|
||||||
this.actor.can_focus = sensitive;
|
|
||||||
this.actor.track_hover = sensitive;
|
|
||||||
},
|
|
||||||
|
|
||||||
setName: function(text) {
|
setName: function(text) {
|
||||||
if (text != null) {
|
if (text != null) {
|
||||||
// This is the easiest way to provide a accessible name to
|
// This is the easiest way to provide a accessible name to
|
||||||
@ -156,6 +145,13 @@ const Button = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setLockedState: function(locked) {
|
||||||
|
// default behaviour is to hide completely
|
||||||
|
if (locked)
|
||||||
|
this.menu.close();
|
||||||
|
this.actor.visible = !locked;
|
||||||
|
},
|
||||||
|
|
||||||
_onButtonPress: function(actor, event) {
|
_onButtonPress: function(actor, event) {
|
||||||
if (!this.menu)
|
if (!this.menu)
|
||||||
return;
|
return;
|
||||||
@ -186,7 +182,8 @@ const Button = new Lang.Class({
|
|||||||
_onMenuKeyPress: function(actor, event) {
|
_onMenuKeyPress: function(actor, event) {
|
||||||
let symbol = event.get_key_symbol();
|
let symbol = event.get_key_symbol();
|
||||||
if (symbol == Clutter.KEY_Left || symbol == Clutter.KEY_Right) {
|
if (symbol == Clutter.KEY_Left || symbol == Clutter.KEY_Right) {
|
||||||
let group = global.focus_manager.get_group(this.actor);
|
let focusManager = St.FocusManager.get_for_stage(global.stage);
|
||||||
|
let group = focusManager.get_group(this.actor);
|
||||||
if (group) {
|
if (group) {
|
||||||
let direction = (symbol == Clutter.KEY_Left) ? Gtk.DirectionType.LEFT : Gtk.DirectionType.RIGHT;
|
let direction = (symbol == Clutter.KEY_Left) ? Gtk.DirectionType.LEFT : Gtk.DirectionType.RIGHT;
|
||||||
group.navigate_focus(this.actor, direction, false);
|
group.navigate_focus(this.actor, direction, false);
|
||||||
@ -214,8 +211,7 @@ const Button = new Lang.Class({
|
|||||||
destroy: function() {
|
destroy: function() {
|
||||||
this.actor._delegate = null;
|
this.actor._delegate = null;
|
||||||
|
|
||||||
if (this.menu)
|
this.menu.destroy();
|
||||||
this.menu.destroy();
|
|
||||||
this.actor.destroy();
|
this.actor.destroy();
|
||||||
|
|
||||||
this.emit('destroy');
|
this.emit('destroy');
|
||||||
@ -235,36 +231,19 @@ const SystemStatusButton = new Lang.Class({
|
|||||||
|
|
||||||
_init: function(iconName, nameText) {
|
_init: function(iconName, nameText) {
|
||||||
this.parent(0.0, nameText);
|
this.parent(0.0, nameText);
|
||||||
|
|
||||||
|
this._iconActor = new St.Icon({ icon_name: iconName,
|
||||||
|
icon_type: St.IconType.SYMBOLIC,
|
||||||
|
style_class: 'system-status-icon' });
|
||||||
|
this.actor.add_actor(this._iconActor);
|
||||||
this.actor.add_style_class_name('panel-status-button');
|
this.actor.add_style_class_name('panel-status-button');
|
||||||
|
|
||||||
this._box = new St.BoxLayout({ style_class: 'panel-status-button-box' });
|
|
||||||
this.actor.add_actor(this._box);
|
|
||||||
|
|
||||||
if (iconName)
|
|
||||||
this.setIcon(iconName);
|
|
||||||
},
|
|
||||||
|
|
||||||
addIcon: function(gicon) {
|
|
||||||
let icon = new St.Icon({ gicon: gicon,
|
|
||||||
style_class: 'system-status-icon' });
|
|
||||||
this._box.add_actor(icon);
|
|
||||||
|
|
||||||
return icon;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setIcon: function(iconName) {
|
setIcon: function(iconName) {
|
||||||
// Need to first add a NULL GIcon and then set icon_name, to ensure
|
this._iconActor.icon_name = iconName;
|
||||||
// compatibility with -symbolic fallbacks
|
|
||||||
|
|
||||||
if (!this.mainIcon)
|
|
||||||
this.mainIcon = this.addIcon(null);
|
|
||||||
this.mainIcon.icon_name = iconName;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setGIcon: function(gicon) {
|
setGIcon: function(gicon) {
|
||||||
if (this.mainIcon)
|
this._iconActor.gicon = gicon;
|
||||||
this.mainIcon.gicon = gicon;
|
|
||||||
else
|
|
||||||
this.mainIcon = this.addIcon(gicon);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
430
js/ui/placeDisplay.js
Normal file
430
js/ui/placeDisplay.js
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Mainloop = imports.mainloop;
|
||||||
|
const Signals = imports.signals;
|
||||||
|
const St = imports.gi.St;
|
||||||
|
|
||||||
|
const DND = imports.ui.dnd;
|
||||||
|
const Main = imports.ui.main;
|
||||||
|
const Params = imports.misc.params;
|
||||||
|
const Search = imports.ui.search;
|
||||||
|
const Util = imports.misc.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a place object, which is most normally a bookmark entry,
|
||||||
|
* a mount/volume, or a special place like the Home Folder, Computer, and Network.
|
||||||
|
*
|
||||||
|
* @name: String title
|
||||||
|
* @iconFactory: A JavaScript callback which will create an icon texture given a size parameter
|
||||||
|
* @launch: A JavaScript callback to launch the entry
|
||||||
|
*/
|
||||||
|
const PlaceInfo = new Lang.Class({
|
||||||
|
Name: 'PlaceInfo',
|
||||||
|
|
||||||
|
_init: function(id, name, iconFactory, launch) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this._lowerName = name.toLowerCase();
|
||||||
|
this.iconFactory = iconFactory;
|
||||||
|
this.launch = launch;
|
||||||
|
},
|
||||||
|
|
||||||
|
matchTerms: function(terms) {
|
||||||
|
let mtype = Search.MatchType.NONE;
|
||||||
|
for (let i = 0; i < terms.length; i++) {
|
||||||
|
let term = terms[i];
|
||||||
|
let idx = this._lowerName.indexOf(term);
|
||||||
|
if (idx == 0) {
|
||||||
|
mtype = Search.MatchType.PREFIX;
|
||||||
|
} else if (idx > 0) {
|
||||||
|
if (mtype == Search.MatchType.NONE)
|
||||||
|
mtype = Search.MatchType.SUBSTRING;
|
||||||
|
} else {
|
||||||
|
return Search.MatchType.NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mtype;
|
||||||
|
},
|
||||||
|
|
||||||
|
isRemovable: function() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Helper function to translate launch parameters into a GAppLaunchContext
|
||||||
|
function _makeLaunchContext(params)
|
||||||
|
{
|
||||||
|
params = Params.parse(params, { workspace: -1,
|
||||||
|
timestamp: 0 });
|
||||||
|
|
||||||
|
let launchContext = global.create_app_launch_context();
|
||||||
|
if (params.workspace != -1)
|
||||||
|
launchContext.set_desktop(params.workspace);
|
||||||
|
if (params.timestamp != 0)
|
||||||
|
launchContext.set_timestamp(params.timestamp);
|
||||||
|
|
||||||
|
return launchContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PlaceDeviceInfo = new Lang.Class({
|
||||||
|
Name: 'PlaceDeviceInfo',
|
||||||
|
Extends: PlaceInfo,
|
||||||
|
|
||||||
|
_init: function(mount) {
|
||||||
|
this._mount = mount;
|
||||||
|
this.name = mount.get_name();
|
||||||
|
this._lowerName = this.name.toLowerCase();
|
||||||
|
this.id = 'mount:' + mount.get_root().get_uri();
|
||||||
|
},
|
||||||
|
|
||||||
|
iconFactory: function(size) {
|
||||||
|
let icon = this._mount.get_icon();
|
||||||
|
return St.TextureCache.get_default().load_gicon(null, icon, size);
|
||||||
|
},
|
||||||
|
|
||||||
|
launch: function(params) {
|
||||||
|
Gio.app_info_launch_default_for_uri(this._mount.get_root().get_uri(),
|
||||||
|
_makeLaunchContext(params));
|
||||||
|
},
|
||||||
|
|
||||||
|
isRemovable: function() {
|
||||||
|
return this._mount.can_unmount();
|
||||||
|
},
|
||||||
|
|
||||||
|
remove: function() {
|
||||||
|
if (!this.isRemovable())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this._mount.can_eject())
|
||||||
|
this._mount.eject(0, null, Lang.bind(this, this._removeFinish));
|
||||||
|
else
|
||||||
|
this._mount.unmount(0, null, Lang.bind(this, this._removeFinish));
|
||||||
|
},
|
||||||
|
|
||||||
|
_removeFinish: function(o, res, data) {
|
||||||
|
try {
|
||||||
|
if (this._mount.can_eject())
|
||||||
|
this._mount.eject_finish(res);
|
||||||
|
else
|
||||||
|
this._mount.unmount_finish(res);
|
||||||
|
} catch (e) {
|
||||||
|
let message = _("Failed to unmount '%s'").format(o.get_name());
|
||||||
|
Main.overview.setMessage(message,
|
||||||
|
Lang.bind(this, this.remove),
|
||||||
|
_("Retry"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const PlacesManager = new Lang.Class({
|
||||||
|
Name: 'PlacesManager',
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
this._defaultPlaces = [];
|
||||||
|
this._mounts = [];
|
||||||
|
this._bookmarks = [];
|
||||||
|
|
||||||
|
let homeFile = Gio.file_new_for_path (GLib.get_home_dir());
|
||||||
|
let homeUri = homeFile.get_uri();
|
||||||
|
let homeLabel = Shell.util_get_label_for_uri (homeUri);
|
||||||
|
let homeIcon = Shell.util_get_icon_for_uri (homeUri);
|
||||||
|
this._home = new PlaceInfo('special:home', homeLabel,
|
||||||
|
function(size) {
|
||||||
|
return St.TextureCache.get_default().load_gicon(null, homeIcon, size);
|
||||||
|
},
|
||||||
|
function(params) {
|
||||||
|
Gio.app_info_launch_default_for_uri(homeUri, _makeLaunchContext(params));
|
||||||
|
});
|
||||||
|
|
||||||
|
let desktopPath = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP);
|
||||||
|
let desktopFile = Gio.file_new_for_path (desktopPath);
|
||||||
|
let desktopUri = desktopFile.get_uri();
|
||||||
|
let desktopLabel = Shell.util_get_label_for_uri (desktopUri);
|
||||||
|
let desktopIcon = Shell.util_get_icon_for_uri (desktopUri);
|
||||||
|
this._desktopMenu = new PlaceInfo('special:desktop', desktopLabel,
|
||||||
|
function(size) {
|
||||||
|
return St.TextureCache.get_default().load_gicon(null, desktopIcon, size);
|
||||||
|
},
|
||||||
|
function(params) {
|
||||||
|
Gio.app_info_launch_default_for_uri(desktopUri, _makeLaunchContext(params));
|
||||||
|
});
|
||||||
|
|
||||||
|
this._connect = new PlaceInfo('special:connect', _("Connect to..."),
|
||||||
|
function (size) {
|
||||||
|
// do NOT use St.Icon here, it crashes the shell
|
||||||
|
// see wanda.js for details
|
||||||
|
return St.TextureCache.get_default().load_icon_name(null,
|
||||||
|
'applications-internet',
|
||||||
|
St.IconType.FULLCOLOR,
|
||||||
|
size);
|
||||||
|
},
|
||||||
|
function (params) {
|
||||||
|
// BUG: nautilus-connect-server doesn't have a desktop file, so we can't
|
||||||
|
// launch it with the workspace from params. It's probably pretty rare
|
||||||
|
// and odd to drag this place onto a workspace in any case
|
||||||
|
|
||||||
|
Util.spawn(['nautilus-connect-server']);
|
||||||
|
});
|
||||||
|
|
||||||
|
this._defaultPlaces.push(this._home);
|
||||||
|
this._defaultPlaces.push(this._desktopMenu);
|
||||||
|
this._defaultPlaces.push(this._connect);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show devices, code more or less ported from nautilus-places-sidebar.c
|
||||||
|
*/
|
||||||
|
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||||
|
this._volumeMonitor.connect('volume-added', Lang.bind(this, this._updateDevices));
|
||||||
|
this._volumeMonitor.connect('volume-removed',Lang.bind(this, this._updateDevices));
|
||||||
|
this._volumeMonitor.connect('volume-changed', Lang.bind(this, this._updateDevices));
|
||||||
|
this._volumeMonitor.connect('mount-added', Lang.bind(this, this._updateDevices));
|
||||||
|
this._volumeMonitor.connect('mount-removed', Lang.bind(this, this._updateDevices));
|
||||||
|
this._volumeMonitor.connect('mount-changed', Lang.bind(this, this._updateDevices));
|
||||||
|
this._volumeMonitor.connect('drive-connected', Lang.bind(this, this._updateDevices));
|
||||||
|
this._volumeMonitor.connect('drive-disconnected', Lang.bind(this, this._updateDevices));
|
||||||
|
this._volumeMonitor.connect('drive-changed', Lang.bind(this, this._updateDevices));
|
||||||
|
this._updateDevices();
|
||||||
|
|
||||||
|
this._bookmarksPath = GLib.build_filenamev([GLib.get_user_config_dir(), 'gtk-3.0', 'bookmarks']);
|
||||||
|
this._bookmarksFile = Gio.file_new_for_path(this._bookmarksPath);
|
||||||
|
this._monitor = this._bookmarksFile.monitor_file(Gio.FileMonitorFlags.NONE, null);
|
||||||
|
this._bookmarkTimeoutId = 0;
|
||||||
|
this._monitor.connect('changed', Lang.bind(this, function () {
|
||||||
|
if (this._bookmarkTimeoutId > 0)
|
||||||
|
return;
|
||||||
|
/* Defensive event compression */
|
||||||
|
this._bookmarkTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function () {
|
||||||
|
this._bookmarkTimeoutId = 0;
|
||||||
|
this._reloadBookmarks();
|
||||||
|
return false;
|
||||||
|
}));
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._reloadBookmarks();
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateDevices: function() {
|
||||||
|
this._mounts = [];
|
||||||
|
|
||||||
|
/* first go through all connected drives */
|
||||||
|
let drives = this._volumeMonitor.get_connected_drives();
|
||||||
|
for (let i = 0; i < drives.length; i++) {
|
||||||
|
let volumes = drives[i].get_volumes();
|
||||||
|
for(let j = 0; j < volumes.length; j++) {
|
||||||
|
let mount = volumes[j].get_mount();
|
||||||
|
if(mount != null) {
|
||||||
|
this._addMount(mount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add all volumes that is not associated with a drive */
|
||||||
|
let volumes = this._volumeMonitor.get_volumes();
|
||||||
|
for(let i = 0; i < volumes.length; i++) {
|
||||||
|
if(volumes[i].get_drive() != null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let mount = volumes[i].get_mount();
|
||||||
|
if(mount != null) {
|
||||||
|
this._addMount(mount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add mounts that have no volume (/etc/mtab mounts, ftp, sftp,...) */
|
||||||
|
let mounts = this._volumeMonitor.get_mounts();
|
||||||
|
for(let i = 0; i < mounts.length; i++) {
|
||||||
|
if(mounts[i].is_shadowed())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(mounts[i].get_volume())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
this._addMount(mounts[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We emit two signals, one for a generic 'all places' update
|
||||||
|
* and the other for one specific to mounts. We do this because
|
||||||
|
* clients like PlaceDisplay may only care about places in general
|
||||||
|
* being updated while clients like DashPlaceDisplay care which
|
||||||
|
* specific type of place got updated.
|
||||||
|
*/
|
||||||
|
this.emit('mounts-updated');
|
||||||
|
this.emit('places-updated');
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
_reloadBookmarks: function() {
|
||||||
|
|
||||||
|
this._bookmarks = [];
|
||||||
|
|
||||||
|
if (!GLib.file_test(this._bookmarksPath, GLib.FileTest.EXISTS))
|
||||||
|
return;
|
||||||
|
|
||||||
|
let bookmarksContent = Shell.get_file_contents_utf8_sync(this._bookmarksPath);
|
||||||
|
|
||||||
|
let bookmarks = bookmarksContent.split('\n');
|
||||||
|
|
||||||
|
let bookmarksToLabel = {};
|
||||||
|
let bookmarksOrder = [];
|
||||||
|
for (let i = 0; i < bookmarks.length; i++) {
|
||||||
|
let bookmarkLine = bookmarks[i];
|
||||||
|
let components = bookmarkLine.split(' ');
|
||||||
|
let bookmark = components[0];
|
||||||
|
if (bookmark in bookmarksToLabel)
|
||||||
|
continue;
|
||||||
|
let label = null;
|
||||||
|
if (components.length > 1)
|
||||||
|
label = components.slice(1).join(' ');
|
||||||
|
bookmarksToLabel[bookmark] = label;
|
||||||
|
bookmarksOrder.push(bookmark);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < bookmarksOrder.length; i++) {
|
||||||
|
let bookmark = bookmarksOrder[i];
|
||||||
|
let label = bookmarksToLabel[bookmark];
|
||||||
|
let file = Gio.file_new_for_uri(bookmark);
|
||||||
|
if (!file.query_exists(null))
|
||||||
|
continue;
|
||||||
|
if (label == null)
|
||||||
|
label = Shell.util_get_label_for_uri(bookmark);
|
||||||
|
if (label == null)
|
||||||
|
continue;
|
||||||
|
let icon = Shell.util_get_icon_for_uri(bookmark);
|
||||||
|
|
||||||
|
let item = new PlaceInfo('bookmark:' + bookmark, label,
|
||||||
|
function(size) {
|
||||||
|
return St.TextureCache.get_default().load_gicon(null, icon, size);
|
||||||
|
},
|
||||||
|
function(params) {
|
||||||
|
Gio.app_info_launch_default_for_uri(bookmark, _makeLaunchContext(params));
|
||||||
|
});
|
||||||
|
this._bookmarks.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See comment in _updateDevices for explanation why there are two signals. */
|
||||||
|
this.emit('bookmarks-updated');
|
||||||
|
this.emit('places-updated');
|
||||||
|
},
|
||||||
|
|
||||||
|
_addMount: function(mount) {
|
||||||
|
let devItem = new PlaceDeviceInfo(mount);
|
||||||
|
this._mounts.push(devItem);
|
||||||
|
},
|
||||||
|
|
||||||
|
getAllPlaces: function () {
|
||||||
|
return this.getDefaultPlaces().concat(this.getBookmarks(), this.getMounts());
|
||||||
|
},
|
||||||
|
|
||||||
|
getDefaultPlaces: function () {
|
||||||
|
return this._defaultPlaces;
|
||||||
|
},
|
||||||
|
|
||||||
|
getBookmarks: function () {
|
||||||
|
return this._bookmarks;
|
||||||
|
},
|
||||||
|
|
||||||
|
getMounts: function () {
|
||||||
|
return this._mounts;
|
||||||
|
},
|
||||||
|
|
||||||
|
_lookupIndexById: function(sourceArray, id) {
|
||||||
|
for (let i = 0; i < sourceArray.length; i++) {
|
||||||
|
let place = sourceArray[i];
|
||||||
|
if (place.id == id)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
},
|
||||||
|
|
||||||
|
lookupPlaceById: function(id) {
|
||||||
|
let colonIdx = id.indexOf(':');
|
||||||
|
let type = id.substring(0, colonIdx);
|
||||||
|
let sourceArray = null;
|
||||||
|
if (type == 'special')
|
||||||
|
sourceArray = this._defaultPlaces;
|
||||||
|
else if (type == 'mount')
|
||||||
|
sourceArray = this._mounts;
|
||||||
|
else if (type == 'bookmark')
|
||||||
|
sourceArray = this._bookmarks;
|
||||||
|
return sourceArray[this._lookupIndexById(sourceArray, id)];
|
||||||
|
},
|
||||||
|
|
||||||
|
_removeById: function(sourceArray, id) {
|
||||||
|
sourceArray.splice(this._lookupIndexById(sourceArray, id), 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(PlacesManager.prototype);
|
||||||
|
|
||||||
|
const PlaceSearchProvider = new Lang.Class({
|
||||||
|
Name: 'PlaceSearchProvider',
|
||||||
|
Extends: Search.SearchProvider,
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
this.parent(_("PLACES & DEVICES"));
|
||||||
|
this.placesManager = new PlacesManager();
|
||||||
|
},
|
||||||
|
|
||||||
|
getResultMetas: function(resultIds, callback) {
|
||||||
|
let metas = [];
|
||||||
|
for (let i = 0; i < resultIds.length; i++) {
|
||||||
|
let placeInfo = this.placesManager.lookupPlaceById(resultIds[i]);
|
||||||
|
if (!placeInfo)
|
||||||
|
metas.push(null);
|
||||||
|
else
|
||||||
|
metas.push({ 'id': resultIds[i],
|
||||||
|
'name': placeInfo.name,
|
||||||
|
'createIcon': function(size) {
|
||||||
|
return placeInfo.iconFactory(size);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
callback(metas);
|
||||||
|
},
|
||||||
|
|
||||||
|
activateResult: function(id, params) {
|
||||||
|
let placeInfo = this.placesManager.lookupPlaceById(id);
|
||||||
|
placeInfo.launch(params);
|
||||||
|
},
|
||||||
|
|
||||||
|
_compareResultMeta: function (idA, idB) {
|
||||||
|
let infoA = this.placesManager.lookupPlaceById(idA);
|
||||||
|
let infoB = this.placesManager.lookupPlaceById(idB);
|
||||||
|
return infoA.name.localeCompare(infoB.name);
|
||||||
|
},
|
||||||
|
|
||||||
|
_searchPlaces: function(places, terms) {
|
||||||
|
let prefixResults = [];
|
||||||
|
let substringResults = [];
|
||||||
|
|
||||||
|
terms = terms.map(String.toLowerCase);
|
||||||
|
|
||||||
|
for (let i = 0; i < places.length; i++) {
|
||||||
|
let place = places[i];
|
||||||
|
let mtype = place.matchTerms(terms);
|
||||||
|
if (mtype == Search.MatchType.PREFIX)
|
||||||
|
prefixResults.push(place.id);
|
||||||
|
else if (mtype == Search.MatchType.SUBSTRING)
|
||||||
|
substringResults.push(place.id);
|
||||||
|
}
|
||||||
|
prefixResults.sort(Lang.bind(this, this._compareResultMeta));
|
||||||
|
substringResults.sort(Lang.bind(this, this._compareResultMeta));
|
||||||
|
|
||||||
|
this.searchSystem.pushResults(this, prefixResults.concat(substringResults));
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialResultSet: function(terms) {
|
||||||
|
let places = this.placesManager.getAllPlaces();
|
||||||
|
this._searchPlaces(places, terms);
|
||||||
|
},
|
||||||
|
|
||||||
|
getSubsearchResultSet: function(previousResults, terms) {
|
||||||
|
let places = previousResults.map(Lang.bind(this, function(id) {
|
||||||
|
return this.placesManager.lookupPlaceById(id);
|
||||||
|
}));
|
||||||
|
this._searchPlaces(places, terms);
|
||||||
|
}
|
||||||
|
});
|
@ -1,130 +0,0 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const Mainloop = imports.mainloop;
|
|
||||||
const GnomeDesktop = imports.gi.GnomeDesktop;
|
|
||||||
const Shell = imports.gi.Shell;
|
|
||||||
|
|
||||||
// We stop polling if the user is idle for more than this amount of time
|
|
||||||
const IDLE_TIME = 1000;
|
|
||||||
|
|
||||||
// This file implements a reasonably efficient system for tracking the position
|
|
||||||
// of the mouse pointer. We simply query the pointer from the X server in a loop,
|
|
||||||
// but we turn off the polling when the user is idle.
|
|
||||||
|
|
||||||
let _pointerWatcher = null;
|
|
||||||
function getPointerWatcher() {
|
|
||||||
if (_pointerWatcher == null)
|
|
||||||
_pointerWatcher = new PointerWatcher();
|
|
||||||
|
|
||||||
return _pointerWatcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PointerWatch = new Lang.Class({
|
|
||||||
Name: 'PointerWatch',
|
|
||||||
|
|
||||||
_init: function(watcher, interval, callback) {
|
|
||||||
this.watcher = watcher;
|
|
||||||
this.interval = interval;
|
|
||||||
this.callback = callback;
|
|
||||||
},
|
|
||||||
|
|
||||||
// remove:
|
|
||||||
// remove this watch. This function may safely be called
|
|
||||||
// while the callback is executing.
|
|
||||||
remove: function() {
|
|
||||||
this.watcher._removeWatch(this);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const PointerWatcher = new Lang.Class({
|
|
||||||
Name: 'PointerWatcher',
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
let idleMonitor = new GnomeDesktop.IdleMonitor();
|
|
||||||
idleMonitor.connect('became-active', Lang.bind(this, this._onIdleMonitorBecameActive));
|
|
||||||
idleMonitor.add_watch(IDLE_TIME, Lang.bind(this, this._onIdleMonitorBecameIdle));
|
|
||||||
this._idle = idleMonitor.get_idletime() > IDLE_TIME;
|
|
||||||
this._watches = [];
|
|
||||||
this.pointerX = null;
|
|
||||||
this.pointerY = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
// addWatch:
|
|
||||||
// @interval: hint as to the time resolution needed. When the user is
|
|
||||||
// not idle, the position of the pointer will be queried at least
|
|
||||||
// once every this many milliseconds.
|
|
||||||
// @callback: function to call when the pointer position changes - takes
|
|
||||||
// two arguments, X and Y.
|
|
||||||
//
|
|
||||||
// Set up a watch on the position of the mouse pointer. Returns a
|
|
||||||
// PointerWatch object which has a remove() method to remove the watch.
|
|
||||||
addWatch: function(interval, callback) {
|
|
||||||
// Avoid unreliably calling the watch for the current position
|
|
||||||
this._updatePointer();
|
|
||||||
|
|
||||||
let watch = new PointerWatch(this, interval, callback);
|
|
||||||
this._watches.push(watch);
|
|
||||||
this._updateTimeout();
|
|
||||||
return watch;
|
|
||||||
},
|
|
||||||
|
|
||||||
_removeWatch: function(watch) {
|
|
||||||
for (let i = 0; i < this._watches.length; i++) {
|
|
||||||
if (this._watches[i] == watch) {
|
|
||||||
this._watches.splice(i, 1);
|
|
||||||
this._updateTimeout();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_onIdleMonitorBecameActive: function(monitor) {
|
|
||||||
this._idle = false;
|
|
||||||
this._updatePointer();
|
|
||||||
this._updateTimeout();
|
|
||||||
},
|
|
||||||
|
|
||||||
_onIdleMonitorBecameIdle: function(monitor) {
|
|
||||||
this._idle = true;
|
|
||||||
this._updateTimeout();
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateTimeout: function() {
|
|
||||||
if (this._timeoutId) {
|
|
||||||
Mainloop.source_remove(this._timeoutId);
|
|
||||||
this._timeoutId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._idle || this._watches.length == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let minInterval = this._watches[0].interval;
|
|
||||||
for (let i = 1; i < this._watches.length; i++)
|
|
||||||
minInterval = Math.min(this._watches[i].interval, minInterval);
|
|
||||||
|
|
||||||
this._timeoutId = Mainloop.timeout_add(minInterval,
|
|
||||||
Lang.bind(this, this._onTimeout));
|
|
||||||
},
|
|
||||||
|
|
||||||
_onTimeout: function() {
|
|
||||||
this._updatePointer();
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
_updatePointer: function() {
|
|
||||||
let [x, y, mods] = global.get_pointer();
|
|
||||||
if (this.pointerX == x && this.pointerY == y)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.pointerX = x;
|
|
||||||
this.pointerY = y;
|
|
||||||
|
|
||||||
for (let i = 0; i < this._watches.length;) {
|
|
||||||
let watch = this._watches[i];
|
|
||||||
watch.callback(x, y);
|
|
||||||
if (watch == this._watches[i]) // guard against self-removal
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,4 +1,24 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
/*
|
||||||
|
* Copyright 2010 Red Hat, Inc
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Author: David Zeuthen <davidz@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
@ -13,12 +33,8 @@ const Mainloop = imports.mainloop;
|
|||||||
const Polkit = imports.gi.Polkit;
|
const Polkit = imports.gi.Polkit;
|
||||||
const PolkitAgent = imports.gi.PolkitAgent;
|
const PolkitAgent = imports.gi.PolkitAgent;
|
||||||
|
|
||||||
const Components = imports.ui.components;
|
|
||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
const UserMenu = imports.ui.userMenu;
|
|
||||||
|
|
||||||
const DIALOG_ICON_SIZE = 48;
|
|
||||||
|
|
||||||
const AuthenticationDialog = new Lang.Class({
|
const AuthenticationDialog = new Lang.Class({
|
||||||
Name: 'AuthenticationDialog',
|
Name: 'AuthenticationDialog',
|
||||||
@ -101,11 +117,9 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
let userBox = new St.BoxLayout({ style_class: 'polkit-dialog-user-layout',
|
let userBox = new St.BoxLayout({ style_class: 'polkit-dialog-user-layout',
|
||||||
vertical: false });
|
vertical: false });
|
||||||
messageBox.add(userBox);
|
messageBox.add(userBox);
|
||||||
this._userAvatar = new UserMenu.UserAvatarWidget(this._user,
|
this._userIcon = new St.Icon();
|
||||||
{ iconSize: DIALOG_ICON_SIZE,
|
this._userIcon.hide();
|
||||||
styleClass: 'polkit-dialog-user-icon' });
|
userBox.add(this._userIcon,
|
||||||
this._userAvatar.actor.hide();
|
|
||||||
userBox.add(this._userAvatar.actor,
|
|
||||||
{ x_fill: true,
|
{ x_fill: true,
|
||||||
y_fill: false,
|
y_fill: false,
|
||||||
x_align: St.Align.END,
|
x_align: St.Align.END,
|
||||||
@ -299,9 +313,19 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onUserChanged: function() {
|
_onUserChanged: function() {
|
||||||
if (this._user.is_loaded && this._userAvatar) {
|
if (this._user.is_loaded) {
|
||||||
this._userAvatar.update();
|
if (this._userIcon) {
|
||||||
this._userAvatar.actor.show();
|
let iconFileName = this._user.get_icon_file();
|
||||||
|
let iconFile = Gio.file_new_for_path(iconFileName);
|
||||||
|
let icon;
|
||||||
|
if (iconFile.query_exists(null)) {
|
||||||
|
icon = new Gio.FileIcon({file: iconFile});
|
||||||
|
} else {
|
||||||
|
icon = new Gio.ThemedIcon({name: 'avatar-default'});
|
||||||
|
}
|
||||||
|
this._userIcon.set_gicon (icon);
|
||||||
|
this._userIcon.show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -317,20 +341,11 @@ const AuthenticationAgent = new Lang.Class({
|
|||||||
Name: 'AuthenticationAgent',
|
Name: 'AuthenticationAgent',
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._currentDialog = null;
|
|
||||||
this._isCompleting = false;
|
|
||||||
this._handle = null;
|
|
||||||
this._native = new Shell.PolkitAuthenticationAgent();
|
this._native = new Shell.PolkitAuthenticationAgent();
|
||||||
this._native.connect('initiate', Lang.bind(this, this._onInitiate));
|
this._native.connect('initiate', Lang.bind(this, this._onInitiate));
|
||||||
this._native.connect('cancel', Lang.bind(this, this._onCancel));
|
this._native.connect('cancel', Lang.bind(this, this._onCancel));
|
||||||
},
|
this._currentDialog = null;
|
||||||
|
this._isCompleting = false;
|
||||||
enable: function() {
|
|
||||||
this._native.register();
|
|
||||||
},
|
|
||||||
|
|
||||||
disable: function() {
|
|
||||||
this._native.unregister();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onInitiate: function(nativeAgent, actionId, message, iconName, cookie, userNames) {
|
_onInitiate: function(nativeAgent, actionId, message, iconName, cookie, userNames) {
|
||||||
@ -388,4 +403,6 @@ const AuthenticationAgent = new Lang.Class({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const Component = AuthenticationAgent;
|
function init() {
|
||||||
|
let agent = new AuthenticationAgent();
|
||||||
|
}
|
@ -37,13 +37,12 @@ const PopupBaseMenuItem = new Lang.Class({
|
|||||||
activate: true,
|
activate: true,
|
||||||
hover: true,
|
hover: true,
|
||||||
sensitive: true,
|
sensitive: true,
|
||||||
style_class: null,
|
style_class: null
|
||||||
can_focus: true
|
|
||||||
});
|
});
|
||||||
this.actor = new Shell.GenericContainer({ style_class: 'popup-menu-item',
|
this.actor = new Shell.GenericContainer({ style_class: 'popup-menu-item',
|
||||||
reactive: params.reactive,
|
reactive: params.reactive,
|
||||||
track_hover: params.reactive,
|
track_hover: params.reactive,
|
||||||
can_focus: params.can_focus,
|
can_focus: params.reactive,
|
||||||
accessible_role: Atk.Role.MENU_ITEM});
|
accessible_role: Atk.Role.MENU_ITEM});
|
||||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
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('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||||
@ -61,9 +60,6 @@ const PopupBaseMenuItem = new Lang.Class({
|
|||||||
|
|
||||||
this.setSensitive(this.sensitive);
|
this.setSensitive(this.sensitive);
|
||||||
|
|
||||||
if (!this._activatable)
|
|
||||||
this.actor.add_style_class_name('popup-inactive-menu-item');
|
|
||||||
|
|
||||||
if (params.style_class)
|
if (params.style_class)
|
||||||
this.actor.add_style_class_name(params.style_class);
|
this.actor.add_style_class_name(params.style_class);
|
||||||
|
|
||||||
@ -73,9 +69,10 @@ const PopupBaseMenuItem = new Lang.Class({
|
|||||||
}
|
}
|
||||||
if (params.reactive && params.hover)
|
if (params.reactive && params.hover)
|
||||||
this.actor.connect('notify::hover', Lang.bind(this, this._onHoverChanged));
|
this.actor.connect('notify::hover', Lang.bind(this, this._onHoverChanged));
|
||||||
|
if (params.reactive) {
|
||||||
this.actor.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
|
this.actor.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
|
||||||
this.actor.connect('key-focus-out', Lang.bind(this, this._onKeyFocusOut));
|
this.actor.connect('key-focus-out', Lang.bind(this, this._onKeyFocusOut));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onStyleChanged: function (actor) {
|
_onStyleChanged: function (actor) {
|
||||||
@ -137,7 +134,6 @@ const PopupBaseMenuItem = new Lang.Class({
|
|||||||
|
|
||||||
this.sensitive = sensitive;
|
this.sensitive = sensitive;
|
||||||
this.actor.reactive = sensitive;
|
this.actor.reactive = sensitive;
|
||||||
this.actor.can_focus = sensitive;
|
|
||||||
|
|
||||||
this.emit('sensitive-changed', sensitive);
|
this.emit('sensitive-changed', sensitive);
|
||||||
},
|
},
|
||||||
@ -183,14 +179,12 @@ const PopupBaseMenuItem = new Lang.Class({
|
|||||||
this._dot = new St.DrawingArea({ style_class: 'popup-menu-item-dot' });
|
this._dot = new St.DrawingArea({ style_class: 'popup-menu-item-dot' });
|
||||||
this._dot.connect('repaint', Lang.bind(this, this._onRepaintDot));
|
this._dot.connect('repaint', Lang.bind(this, this._onRepaintDot));
|
||||||
this.actor.add_actor(this._dot);
|
this.actor.add_actor(this._dot);
|
||||||
this.actor.add_accessible_state (Atk.StateType.CHECKED);
|
|
||||||
} else {
|
} else {
|
||||||
if (!this._dot)
|
if (!this._dot)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._dot.destroy();
|
this._dot.destroy();
|
||||||
this._dot = null;
|
this._dot = null;
|
||||||
this.actor.remove_accessible_state (Atk.StateType.CHECKED);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -401,8 +395,7 @@ const PopupSeparatorMenuItem = new Lang.Class({
|
|||||||
Extends: PopupBaseMenuItem,
|
Extends: PopupBaseMenuItem,
|
||||||
|
|
||||||
_init: function () {
|
_init: function () {
|
||||||
this.parent({ reactive: false,
|
this.parent({ reactive: false });
|
||||||
can_focus: false});
|
|
||||||
|
|
||||||
this._drawingArea = new St.DrawingArea({ style_class: 'popup-separator-menu-item' });
|
this._drawingArea = new St.DrawingArea({ style_class: 'popup-separator-menu-item' });
|
||||||
this.addActor(this._drawingArea, { span: -1, expand: true });
|
this.addActor(this._drawingArea, { span: -1, expand: true });
|
||||||
@ -721,8 +714,7 @@ const Switch = new Lang.Class({
|
|||||||
|
|
||||||
_init: function(state) {
|
_init: function(state) {
|
||||||
this.actor = new St.Bin({ style_class: 'toggle-switch',
|
this.actor = new St.Bin({ style_class: 'toggle-switch',
|
||||||
accessible_role: Atk.Role.CHECK_BOX,
|
accessible_role: Atk.Role.CHECK_BOX});
|
||||||
can_focus: true });
|
|
||||||
// Translators: this MUST be either "toggle-switch-us"
|
// Translators: this MUST be either "toggle-switch-us"
|
||||||
// (for toggle switches containing the English words
|
// (for toggle switches containing the English words
|
||||||
// "ON" and "OFF") or "toggle-switch-intl" (for toggle
|
// "ON" and "OFF") or "toggle-switch-intl" (for toggle
|
||||||
@ -766,7 +758,7 @@ const PopupSwitchMenuItem = new Lang.Class({
|
|||||||
{ expand: true, span: -1, align: St.Align.END });
|
{ expand: true, span: -1, align: St.Align.END });
|
||||||
|
|
||||||
this._statusLabel = new St.Label({ text: '',
|
this._statusLabel = new St.Label({ text: '',
|
||||||
style_class: 'popup-status-menu-item'
|
style_class: 'popup-inactive-menu-item'
|
||||||
});
|
});
|
||||||
this._statusBin.child = this._switch.actor;
|
this._statusBin.child = this._switch.actor;
|
||||||
},
|
},
|
||||||
@ -870,15 +862,13 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
// for the menu which causes its prelight state to freeze
|
// for the menu which causes its prelight state to freeze
|
||||||
this.blockSourceEvents = false;
|
this.blockSourceEvents = false;
|
||||||
|
|
||||||
|
// Can be set while a menu is up to let all events through without special
|
||||||
|
// menu handling useful for scrollbars in menus, and probably not otherwise.
|
||||||
|
this.passEvents = false;
|
||||||
|
|
||||||
this._activeMenuItem = null;
|
this._activeMenuItem = null;
|
||||||
this._childMenus = [];
|
this._childMenus = [];
|
||||||
this._settingsActions = { };
|
this._settingsActions = { };
|
||||||
|
|
||||||
this._sessionUpdatedId = Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
|
||||||
},
|
|
||||||
|
|
||||||
_sessionUpdated: function() {
|
|
||||||
this._setSettingsVisibility(Main.sessionMode.allowSettings);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addAction: function(title, callback) {
|
addAction: function(title, callback) {
|
||||||
@ -892,6 +882,9 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
addSettingsAction: function(title, desktopFile) {
|
addSettingsAction: function(title, desktopFile) {
|
||||||
|
if (!Main.sessionMode.allowSettings)
|
||||||
|
return null;
|
||||||
|
|
||||||
let menuItem = this.addAction(title, function() {
|
let menuItem = this.addAction(title, function() {
|
||||||
let app = Shell.AppSystem.get_default().lookup_setting(desktopFile);
|
let app = Shell.AppSystem.get_default().lookup_setting(desktopFile);
|
||||||
|
|
||||||
@ -904,13 +897,12 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
app.activate();
|
app.activate();
|
||||||
});
|
});
|
||||||
|
|
||||||
menuItem.actor.visible = Main.sessionMode.allowSettings;
|
|
||||||
this._settingsActions[desktopFile] = menuItem;
|
this._settingsActions[desktopFile] = menuItem;
|
||||||
|
|
||||||
return menuItem;
|
return menuItem;
|
||||||
},
|
},
|
||||||
|
|
||||||
_setSettingsVisibility: function(visible) {
|
setSettingsVisibility: function(visible) {
|
||||||
for (let id in this._settingsActions) {
|
for (let id in this._settingsActions) {
|
||||||
let item = this._settingsActions[id];
|
let item = this._settingsActions[id];
|
||||||
item.actor.visible = visible;
|
item.actor.visible = visible;
|
||||||
@ -1059,17 +1051,14 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
|
|
||||||
if (menuItem instanceof PopupMenuSection) {
|
if (menuItem instanceof PopupMenuSection) {
|
||||||
this._connectSubMenuSignals(menuItem, menuItem);
|
this._connectSubMenuSignals(menuItem, menuItem);
|
||||||
menuItem._parentOpenStateChangedId = this.connect('open-state-changed',
|
menuItem._closingId = this.connect('open-state-changed',
|
||||||
function(self, open) {
|
function(self, open) {
|
||||||
if (open)
|
if (!open)
|
||||||
menuItem.open();
|
menuItem.close(BoxPointer.PopupAnimation.FADE);
|
||||||
else
|
|
||||||
menuItem.close();
|
|
||||||
});
|
});
|
||||||
menuItem.connect('destroy', Lang.bind(this, function() {
|
menuItem.connect('destroy', Lang.bind(this, function() {
|
||||||
menuItem.disconnect(menuItem._subMenuActivateId);
|
menuItem.disconnect(menuItem._subMenuActivateId);
|
||||||
menuItem.disconnect(menuItem._subMenuActiveChangeId);
|
menuItem.disconnect(menuItem._subMenuActiveChangeId);
|
||||||
this.disconnect(menuItem._parentOpenStateChangedId);
|
|
||||||
|
|
||||||
this.length--;
|
this.length--;
|
||||||
}));
|
}));
|
||||||
@ -1104,8 +1093,7 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
let columnWidths = [];
|
let columnWidths = [];
|
||||||
let items = this.box.get_children();
|
let items = this.box.get_children();
|
||||||
for (let i = 0; i < items.length; i++) {
|
for (let i = 0; i < items.length; i++) {
|
||||||
if (!items[i].visible &&
|
if (!items[i].visible)
|
||||||
!(items[i]._delegate instanceof PopupSubMenu && items[i-1].visible))
|
|
||||||
continue;
|
continue;
|
||||||
if (items[i]._delegate instanceof PopupBaseMenuItem || items[i]._delegate instanceof PopupMenuBase) {
|
if (items[i]._delegate instanceof PopupBaseMenuItem || items[i]._delegate instanceof PopupMenuBase) {
|
||||||
let itemColumnWidths = items[i]._delegate.getColumnWidths();
|
let itemColumnWidths = items[i]._delegate.getColumnWidths();
|
||||||
@ -1180,9 +1168,6 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
this.actor.destroy();
|
this.actor.destroy();
|
||||||
|
|
||||||
this.emit('destroy');
|
this.emit('destroy');
|
||||||
|
|
||||||
Main.sessionMode.disconnect(this._sessionUpdatedId);
|
|
||||||
this._sessionUpdatedId = 0;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(PopupMenuBase.prototype);
|
Signals.addSignalMethods(PopupMenuBase.prototype);
|
||||||
@ -1269,14 +1254,13 @@ const PopupMenu = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
close: function(animate) {
|
close: function(animate) {
|
||||||
|
if (!this.isOpen)
|
||||||
|
return;
|
||||||
|
|
||||||
if (this._activeMenuItem)
|
if (this._activeMenuItem)
|
||||||
this._activeMenuItem.setActive(false);
|
this._activeMenuItem.setActive(false);
|
||||||
|
|
||||||
if (this._boxPointer.actor.visible)
|
this._boxPointer.hide(animate);
|
||||||
this._boxPointer.hide(animate);
|
|
||||||
|
|
||||||
if (!this.isOpen)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.isOpen = false;
|
this.isOpen = false;
|
||||||
this.emit('open-state-changed', false);
|
this.emit('open-state-changed', false);
|
||||||
@ -1300,6 +1284,24 @@ const PopupSubMenu = new Lang.Class({
|
|||||||
hscrollbar_policy: Gtk.PolicyType.NEVER,
|
hscrollbar_policy: Gtk.PolicyType.NEVER,
|
||||||
vscrollbar_policy: Gtk.PolicyType.NEVER });
|
vscrollbar_policy: Gtk.PolicyType.NEVER });
|
||||||
|
|
||||||
|
// StScrollbar plays dirty tricks with events, calling
|
||||||
|
// clutter_set_motion_events_enabled (FALSE) during the scroll; this
|
||||||
|
// confuses our event tracking, so we just turn it off during the
|
||||||
|
// scroll.
|
||||||
|
let vscroll = this.actor.get_vscroll_bar();
|
||||||
|
vscroll.connect('scroll-start',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
let topMenu = this._getTopMenu();
|
||||||
|
if (topMenu)
|
||||||
|
topMenu.passEvents = true;
|
||||||
|
}));
|
||||||
|
vscroll.connect('scroll-stop',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
let topMenu = this._getTopMenu();
|
||||||
|
if (topMenu)
|
||||||
|
topMenu.passEvents = false;
|
||||||
|
}));
|
||||||
|
|
||||||
this.actor.add_actor(this.box);
|
this.actor.add_actor(this.box);
|
||||||
this.actor._delegate = this;
|
this.actor._delegate = this;
|
||||||
this.actor.clip_to_allocation = true;
|
this.actor.clip_to_allocation = true;
|
||||||
@ -1349,11 +1351,6 @@ const PopupSubMenu = new Lang.Class({
|
|||||||
this.actor.vscrollbar_policy =
|
this.actor.vscrollbar_policy =
|
||||||
needsScrollbar ? Gtk.PolicyType.AUTOMATIC : Gtk.PolicyType.NEVER;
|
needsScrollbar ? Gtk.PolicyType.AUTOMATIC : Gtk.PolicyType.NEVER;
|
||||||
|
|
||||||
if (needsScrollbar)
|
|
||||||
this.actor.add_style_pseudo_class('scrolled');
|
|
||||||
else
|
|
||||||
this.actor.remove_style_pseudo_class('scrolled');
|
|
||||||
|
|
||||||
// It looks funny if we animate with a scrollbar (at what point is
|
// It looks funny if we animate with a scrollbar (at what point is
|
||||||
// the scrollbar added?) so just skip that case
|
// the scrollbar added?) so just skip that case
|
||||||
if (animate && needsScrollbar)
|
if (animate && needsScrollbar)
|
||||||
@ -1460,7 +1457,7 @@ const PopupMenuSection = new Lang.Class({
|
|||||||
|
|
||||||
// deliberately ignore any attempt to open() or close(), but emit the
|
// deliberately ignore any attempt to open() or close(), but emit the
|
||||||
// corresponding signal so children can still pick it up
|
// corresponding signal so children can still pick it up
|
||||||
open: function() { this.emit('open-state-changed', true); },
|
open: function(animate) { this.emit('open-state-changed', true); },
|
||||||
close: function() { this.emit('open-state-changed', false); },
|
close: function() { this.emit('open-state-changed', false); },
|
||||||
|
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
@ -1898,7 +1895,7 @@ const RemoteMenu = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
item.actor.reactive = item.actor.can_focus = action.enabled;
|
item.actor.reactive = action.enabled;
|
||||||
|
|
||||||
destroyId = item.connect('destroy', Lang.bind(this, function() {
|
destroyId = item.connect('destroy', Lang.bind(this, function() {
|
||||||
item.disconnect(destroyId);
|
item.disconnect(destroyId);
|
||||||
@ -2030,7 +2027,7 @@ const RemoteMenu = new Lang.Class({
|
|||||||
if (action.items.length) {
|
if (action.items.length) {
|
||||||
for (let i = 0; i < action.items.length; i++) {
|
for (let i = 0; i < action.items.length; i++) {
|
||||||
let item = action.items[i];
|
let item = action.items[i];
|
||||||
item.actor.reactive = item.actor.can_focus = action.enabled;
|
item.actor.reactive = action.enabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2058,9 +2055,6 @@ const PopupMenuManager = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
addMenu: function(menu, position) {
|
addMenu: function(menu, position) {
|
||||||
if (this._findMenu(menu) > -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let menudata = {
|
let menudata = {
|
||||||
menu: menu,
|
menu: menu,
|
||||||
openStateChangeId: menu.connect('open-state-changed', Lang.bind(this, this._onMenuOpenState)),
|
openStateChangeId: menu.connect('open-state-changed', Lang.bind(this, this._onMenuOpenState)),
|
||||||
@ -2284,6 +2278,9 @@ const PopupMenuManager = new Lang.Class({
|
|||||||
this._owner.menuEventFilter(event))
|
this._owner.menuEventFilter(event))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (this._activeMenu != null && this._activeMenu.passEvents)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (this._didPop) {
|
if (this._didPop) {
|
||||||
this._didPop = false;
|
this._didPop = false;
|
||||||
return true;
|
return true;
|
||||||
|
@ -29,29 +29,21 @@ const SearchProviderIface = <interface name="org.gnome.Shell.SearchProvider">
|
|||||||
</method>
|
</method>
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
var SearchProviderProxy = new Gio.DBusProxyClass({
|
var SearchProviderProxy = Gio.DBusProxy.makeProxyWrapper(SearchProviderIface);
|
||||||
Name: 'SearchProviderProxy',
|
|
||||||
Interface: SearchProviderIface,
|
|
||||||
|
|
||||||
_init: function(params) {
|
|
||||||
params.g_bus_type = Gio.BusType.SESSION;
|
|
||||||
this.parent(params);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function loadRemoteSearchProviders(addProviderCallback) {
|
function loadRemoteSearchProviders(addProviderCallback) {
|
||||||
let dataDirs = GLib.get_system_data_dirs();
|
let dataDirs = GLib.get_system_data_dirs();
|
||||||
let loadedProviders = {};
|
|
||||||
for (let i = 0; i < dataDirs.length; i++) {
|
for (let i = 0; i < dataDirs.length; i++) {
|
||||||
let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', 'search-providers']);
|
let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', 'search-providers']);
|
||||||
let dir = Gio.file_new_for_path(path);
|
let dir = Gio.file_new_for_path(path);
|
||||||
if (!dir.query_exists(null))
|
if (!dir.query_exists(null))
|
||||||
continue;
|
continue;
|
||||||
loadRemoteSearchProvidersFromDir(dir, loadedProviders, addProviderCallback);
|
loadRemoteSearchProvidersFromDir(dir, addProviderCallback);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function loadRemoteSearchProvidersFromDir(dir, loadedProviders, addProviderCallback) {
|
function loadRemoteSearchProvidersFromDir(dir, addProviderCallback) {
|
||||||
let dirPath = dir.get_path();
|
let dirPath = dir.get_path();
|
||||||
FileUtils.listDirAsync(dir, Lang.bind(this, function(files) {
|
FileUtils.listDirAsync(dir, Lang.bind(this, function(files) {
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
@ -73,9 +65,6 @@ function loadRemoteSearchProvidersFromDir(dir, loadedProviders, addProviderCallb
|
|||||||
let busName = keyfile.get_string(group, 'BusName');
|
let busName = keyfile.get_string(group, 'BusName');
|
||||||
let objectPath = keyfile.get_string(group, 'ObjectPath');
|
let objectPath = keyfile.get_string(group, 'ObjectPath');
|
||||||
|
|
||||||
if (loadedProviders[objectPath])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
let appInfo = null;
|
let appInfo = null;
|
||||||
try {
|
try {
|
||||||
let desktopId = keyfile.get_string(group, 'DesktopId');
|
let desktopId = keyfile.get_string(group, 'DesktopId');
|
||||||
@ -97,22 +86,12 @@ function loadRemoteSearchProvidersFromDir(dir, loadedProviders, addProviderCallb
|
|||||||
icon,
|
icon,
|
||||||
busName,
|
busName,
|
||||||
objectPath);
|
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) {
|
} catch(e) {
|
||||||
log('Failed to add search provider "%s": %s'.format(title, e.toString()));
|
log('Failed to add search provider "%s": %s'.format(title, e.toString()));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addProviderCallback(remoteProvider);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -123,45 +102,18 @@ const RemoteSearchProvider = new Lang.Class({
|
|||||||
Extends: Search.SearchProvider,
|
Extends: Search.SearchProvider,
|
||||||
|
|
||||||
_init: function(title, icon, dbusName, dbusPath) {
|
_init: function(title, icon, dbusName, dbusPath) {
|
||||||
|
this._proxy = new SearchProviderProxy(Gio.DBus.session,
|
||||||
|
dbusName, dbusPath);
|
||||||
|
|
||||||
this.parent(title.toUpperCase());
|
this.parent(title.toUpperCase());
|
||||||
|
|
||||||
this._proxy = new SearchProviderProxy({ g_name: dbusName,
|
|
||||||
g_object_path: dbusPath });
|
|
||||||
this._cancellable = new Gio.Cancellable();
|
this._cancellable = new Gio.Cancellable();
|
||||||
},
|
},
|
||||||
|
|
||||||
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) {
|
createIcon: function(size, meta) {
|
||||||
if (meta['gicon']) {
|
if (meta['gicon']) {
|
||||||
return new St.Icon({ gicon: Gio.icon_new_for_string(meta['gicon']),
|
return new St.Icon({ gicon: Gio.icon_new_for_string(meta['gicon']),
|
||||||
icon_size: size });
|
icon_size: size,
|
||||||
|
icon_type: St.IconType.FULLCOLOR });
|
||||||
} else if (meta['icon-data']) {
|
} else if (meta['icon-data']) {
|
||||||
let [width, height, rowStride, hasAlpha,
|
let [width, height, rowStride, hasAlpha,
|
||||||
bitsPerSample, nChannels, data] = meta['icon-data'];
|
bitsPerSample, nChannels, data] = meta['icon-data'];
|
||||||
@ -172,20 +124,14 @@ const RemoteSearchProvider = new Lang.Class({
|
|||||||
|
|
||||||
// Ugh, but we want to fall back to something ...
|
// Ugh, but we want to fall back to something ...
|
||||||
return new St.Icon({ icon_name: 'text-x-generic',
|
return new St.Icon({ icon_name: 'text-x-generic',
|
||||||
icon_size: size });
|
icon_size: size,
|
||||||
|
icon_type: St.IconType.FULLCOLOR });
|
||||||
},
|
},
|
||||||
|
|
||||||
_getResultsFinished: function(proxy, result) {
|
_getResultsFinished: function(results, error) {
|
||||||
try {
|
if (error)
|
||||||
// We rely on a small implementation detail of the
|
return;
|
||||||
// GDBus bindings here: all *Finish are equal
|
this.searchSystem.pushResults(this, results[0]);
|
||||||
|
|
||||||
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) {
|
getInitialResultSet: function(terms) {
|
||||||
@ -193,8 +139,8 @@ const RemoteSearchProvider = new Lang.Class({
|
|||||||
this._cancellable.reset();
|
this._cancellable.reset();
|
||||||
try {
|
try {
|
||||||
this._proxy.GetInitialResultSetRemote(terms,
|
this._proxy.GetInitialResultSetRemote(terms,
|
||||||
this._cancellable,
|
Lang.bind(this, this._getResultsFinished),
|
||||||
Lang.bind(this, this._getResultsFinished));
|
this._cancellable);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
log('Error calling GetInitialResultSet for provider %s: %s'.format( this.title, e.toString()));
|
log('Error calling GetInitialResultSet for provider %s: %s'.format( this.title, e.toString()));
|
||||||
this.searchSystem.pushResults(this, []);
|
this.searchSystem.pushResults(this, []);
|
||||||
@ -206,30 +152,30 @@ const RemoteSearchProvider = new Lang.Class({
|
|||||||
this._cancellable.reset();
|
this._cancellable.reset();
|
||||||
try {
|
try {
|
||||||
this._proxy.GetSubsearchResultSetRemote(previousResults, newTerms,
|
this._proxy.GetSubsearchResultSetRemote(previousResults, newTerms,
|
||||||
this._cancellable,
|
Lang.bind(this, this._getResultsFinished),
|
||||||
Lang.bind(this, this._getResultsFinished))
|
this._cancellable);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
log('Error calling GetSubsearchResultSet for provider %s: %s'.format(this.title, e.toString()));
|
log('Error calling GetSubsearchResultSet for provider %s: %s'.format(this.title, e.toString()));
|
||||||
this.searchSystem.pushResults(this, []);
|
this.searchSystem.pushResults(this, []);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_getResultMetasFinished: function(proxy, result, callback) {
|
_getResultMetasFinished: function(results, error, callback) {
|
||||||
try {
|
if (error) {
|
||||||
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([]);
|
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) {
|
getResultMetas: function(ids, callback) {
|
||||||
@ -237,8 +183,8 @@ const RemoteSearchProvider = new Lang.Class({
|
|||||||
this._cancellable.reset();
|
this._cancellable.reset();
|
||||||
try {
|
try {
|
||||||
this._proxy.GetResultMetasRemote(ids,
|
this._proxy.GetResultMetasRemote(ids,
|
||||||
this._cancellable,
|
Lang.bind(this, this._getResultMetasFinished, callback),
|
||||||
Lang.bind(this, this._getResultMetasFinished, callback));
|
this._cancellable);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
log('Error calling GetResultMetas for provider %s: %s'.format(this.title, e.toString()));
|
log('Error calling GetResultMetas for provider %s: %s'.format(this.title, e.toString()));
|
||||||
callback([]);
|
callback([]);
|
||||||
@ -246,7 +192,7 @@ const RemoteSearchProvider = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
activateResult: function(id) {
|
activateResult: function(id) {
|
||||||
this._proxy.ActivateResultRemote(id, null, null);
|
this._proxy.ActivateResultRemote(id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -202,12 +202,11 @@ const RunDialog = new Lang.Class({
|
|||||||
|
|
||||||
|
|
||||||
let label = new St.Label({ style_class: 'run-dialog-label',
|
let label = new St.Label({ style_class: 'run-dialog-label',
|
||||||
text: _("Enter a Command") });
|
text: _("Please enter a command:") });
|
||||||
|
|
||||||
this.contentLayout.add(label, { y_align: St.Align.START });
|
this.contentLayout.add(label, { y_align: St.Align.START });
|
||||||
|
|
||||||
let entry = new St.Entry({ style_class: 'run-dialog-entry',
|
let entry = new St.Entry({ style_class: 'run-dialog-entry' });
|
||||||
can_focus: true });
|
|
||||||
ShellEntry.addContextMenu(entry);
|
ShellEntry.addContextMenu(entry);
|
||||||
|
|
||||||
entry.label_actor = label;
|
entry.label_actor = label;
|
||||||
@ -220,9 +219,7 @@ const RunDialog = new Lang.Class({
|
|||||||
|
|
||||||
this.contentLayout.add(this._errorBox, { expand: true });
|
this.contentLayout.add(this._errorBox, { expand: true });
|
||||||
|
|
||||||
let errorIcon = new St.Icon({ icon_name: 'dialog-error-symbolic',
|
let errorIcon = new St.Icon({ icon_name: 'dialog-error', icon_size: 24, style_class: 'run-dialog-error-icon' });
|
||||||
icon_size: 24,
|
|
||||||
style_class: 'run-dialog-error-icon' });
|
|
||||||
|
|
||||||
this._errorBox.add(errorIcon, { y_align: St.Align.MIDDLE });
|
this._errorBox.add(errorIcon, { y_align: St.Align.MIDDLE });
|
||||||
|
|
||||||
@ -237,10 +234,6 @@ const RunDialog = new Lang.Class({
|
|||||||
|
|
||||||
this._errorBox.hide();
|
this._errorBox.hide();
|
||||||
|
|
||||||
this.setButtons([{ action: Lang.bind(this, this.close),
|
|
||||||
label: _("Close"),
|
|
||||||
key: Clutter.Escape }]);
|
|
||||||
|
|
||||||
this._pathCompleter = new Gio.FilenameCompleter();
|
this._pathCompleter = new Gio.FilenameCompleter();
|
||||||
this._commandCompleter = new CommandCompleter();
|
this._commandCompleter = new CommandCompleter();
|
||||||
this._group.connect('notify::visible', Lang.bind(this._commandCompleter, this._commandCompleter.update));
|
this._group.connect('notify::visible', Lang.bind(this._commandCompleter, this._commandCompleter.update));
|
||||||
@ -251,12 +244,20 @@ const RunDialog = new Lang.Class({
|
|||||||
let symbol = e.get_key_symbol();
|
let symbol = e.get_key_symbol();
|
||||||
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
||||||
this.popModal();
|
this.popModal();
|
||||||
this._run(o.get_text(),
|
if (e.get_state() & Clutter.ModifierType.CONTROL_MASK)
|
||||||
e.get_state() & Clutter.ModifierType.CONTROL_MASK);
|
this._run(o.get_text(), true);
|
||||||
if (!this._commandError ||
|
else
|
||||||
!this.pushModal())
|
this._run(o.get_text(), false);
|
||||||
|
if (!this._commandError)
|
||||||
this.close();
|
this.close();
|
||||||
|
else {
|
||||||
|
if (!this.pushModal())
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (symbol == Clutter.Escape) {
|
||||||
|
this.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (symbol == Clutter.slash) {
|
if (symbol == Clutter.slash) {
|
||||||
|
@ -1,40 +1,26 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Cairo = imports.cairo;
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const GnomeDesktop = imports.gi.GnomeDesktop;
|
const GnomeDesktop = imports.gi.GnomeDesktop;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
|
||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const TweenerEquations = imports.tweener.equations;
|
|
||||||
|
|
||||||
const GnomeSession = imports.misc.gnomeSession;
|
const GnomeSession = imports.misc.gnomeSession;
|
||||||
const Layout = imports.ui.layout;
|
|
||||||
const LoginManager = imports.misc.loginManager;
|
|
||||||
const Lightbox = imports.ui.lightbox;
|
const Lightbox = imports.ui.lightbox;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Overview = imports.ui.overview;
|
|
||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
const ShellDBus = imports.ui.shellDBus;
|
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
const Util = imports.misc.util;
|
|
||||||
|
|
||||||
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
|
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
|
||||||
const LOCK_ENABLED_KEY = 'lock-enabled';
|
const LOCK_ENABLED_KEY = 'lock-enabled';
|
||||||
|
|
||||||
const CURTAIN_SLIDE_TIME = 0.3;
|
const CURTAIN_SLIDE_TIME = 0.8;
|
||||||
// fraction of screen height the arrow must reach before completing
|
// fraction of screen height the arrow must reach before completing
|
||||||
// the slide up automatically
|
// the slide up automatically
|
||||||
const ARROW_DRAG_THRESHOLD = 0.1;
|
const ARROW_DRAG_TRESHOLD = 0.1;
|
||||||
|
|
||||||
// Parameters for the arrow animation
|
|
||||||
const N_ARROWS = 3;
|
|
||||||
const ARROW_ANIMATION_TIME = 0.6;
|
|
||||||
const ARROW_ANIMATION_PEAK_OPACITY = 0.4;
|
|
||||||
|
|
||||||
// The distance in px that the lock screen will move to when pressing
|
// The distance in px that the lock screen will move to when pressing
|
||||||
// a key that has no effect in the lock screen (bumping it)
|
// a key that has no effect in the lock screen (bumping it)
|
||||||
@ -47,7 +33,7 @@ const SUMMARY_ICON_SIZE = 48;
|
|||||||
// STANDARD_FADE_TIME is used when the session goes idle, while
|
// STANDARD_FADE_TIME is used when the session goes idle, while
|
||||||
// SHORT_FADE_TIME is used when requesting lock explicitly from the user menu
|
// SHORT_FADE_TIME is used when requesting lock explicitly from the user menu
|
||||||
const STANDARD_FADE_TIME = 10;
|
const STANDARD_FADE_TIME = 10;
|
||||||
const SHORT_FADE_TIME = 0.3;
|
const SHORT_FADE_TIME = 0.8;
|
||||||
|
|
||||||
const Clock = new Lang.Class({
|
const Clock = new Lang.Class({
|
||||||
Name: 'ScreenShieldClock',
|
Name: 'ScreenShieldClock',
|
||||||
@ -91,24 +77,23 @@ const NotificationsBox = new Lang.Class({
|
|||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.actor = new St.BoxLayout({ vertical: true,
|
this.actor = new St.BoxLayout({ vertical: true,
|
||||||
name: 'screenShieldNotifications',
|
name: 'screenShieldNotifications',
|
||||||
style_class: 'screen-shield-notifications-box' });
|
style_class: 'screen-shield-notifications-box' });
|
||||||
|
|
||||||
this._residentNotificationBox = new St.BoxLayout({ vertical: true,
|
this._residentNotificationBox = new St.BoxLayout({ vertical: true,
|
||||||
style_class: 'screen-shield-notifications-box' });
|
style_class: 'screen-shield-notifications-box' });
|
||||||
let scrollView = new St.ScrollView({ x_fill: false, x_align: St.Align.START });
|
let scrollView = new St.ScrollView({ x_fill: false, x_align: St.Align.MIDDLE });
|
||||||
this._persistentNotificationBox = new St.BoxLayout({ vertical: true,
|
this._persistentNotificationBox = new St.BoxLayout({ vertical: true,
|
||||||
style_class: 'screen-shield-notifications-box' });
|
style_class: 'screen-shield-notifications-box' });
|
||||||
scrollView.add_actor(this._persistentNotificationBox);
|
scrollView.add_actor(this._persistentNotificationBox);
|
||||||
|
|
||||||
this.actor.add(this._residentNotificationBox, { x_fill: true });
|
this.actor.add(this._residentNotificationBox, { x_fill: true });
|
||||||
this.actor.add(scrollView, { x_fill: true, x_align: St.Align.START });
|
this.actor.add(scrollView, { x_fill: true, x_align: St.Align.MIDDLE });
|
||||||
|
|
||||||
this._items = [];
|
this._items = [];
|
||||||
Main.messageTray.getSummaryItems().forEach(Lang.bind(this, function(item) {
|
Main.messageTray.getSummaryItems().forEach(Lang.bind(this, function(item) {
|
||||||
this._summaryItemAdded(Main.messageTray, item, true);
|
this._summaryItemAdded(Main.messageTray, item);
|
||||||
}));
|
}));
|
||||||
this._updateVisibility();
|
|
||||||
|
|
||||||
this._summaryAddedId = Main.messageTray.connect('summary-item-added', Lang.bind(this, this._summaryItemAdded));
|
this._summaryAddedId = Main.messageTray.connect('summary-item-added', Lang.bind(this, this._summaryItemAdded));
|
||||||
},
|
},
|
||||||
@ -127,23 +112,24 @@ const NotificationsBox = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_updateVisibility: function() {
|
_updateVisibility: function() {
|
||||||
this._residentNotificationBox.visible = this._residentNotificationBox.get_n_children() > 0;
|
if (this._residentNotificationBox.get_n_children() > 0) {
|
||||||
this._persistentNotificationBox.visible = this._persistentNotificationBox.get_children().some(function(a) {
|
this.actor.show();
|
||||||
return a.visible;
|
return;
|
||||||
});
|
}
|
||||||
|
|
||||||
this.actor.visible = this._residentNotificationBox.visible || this._persistentNotificationBox.visible;
|
let children = this._persistentNotificationBox.get_children()
|
||||||
|
this.actor.visible = children.some(function(a) { return a.visible; });
|
||||||
},
|
},
|
||||||
|
|
||||||
_sourceIsResident: function(source) {
|
_sourceIsResident: function(source) {
|
||||||
return source.hasResidentNotification() && !source.isChat;
|
return source.hasResidentNotification() && !source.isChat;
|
||||||
},
|
},
|
||||||
|
|
||||||
_makeNotificationCountText: function(count, isChat) {
|
_makeNotificationCountText: function(source) {
|
||||||
if (isChat)
|
if (source.isChat)
|
||||||
return ngettext("%d new message", "%d new messages", count).format(count);
|
return ngettext("%d new message", "%d new messages", source.count).format(source.count);
|
||||||
else
|
else
|
||||||
return ngettext("%d new notification", "%d new notifications", count).format(count);
|
return ngettext("%d new notification", "%d new notifications", source.count).format(source.count);
|
||||||
},
|
},
|
||||||
|
|
||||||
_makeNotificationSource: function(source) {
|
_makeNotificationSource: function(source) {
|
||||||
@ -153,25 +139,23 @@ const NotificationsBox = new Lang.Class({
|
|||||||
box.add(sourceActor.actor, { y_fill: true });
|
box.add(sourceActor.actor, { y_fill: true });
|
||||||
|
|
||||||
let textBox = new St.BoxLayout({ vertical: true });
|
let textBox = new St.BoxLayout({ vertical: true });
|
||||||
box.add(textBox, { y_fill: false, y_align: St.Align.START });
|
box.add(textBox);
|
||||||
|
|
||||||
let label = new St.Label({ text: source.title,
|
let label = new St.Label({ text: source.title,
|
||||||
style_class: 'screen-shield-notification-label' });
|
style_class: 'screen-shield-notification-label' });
|
||||||
textBox.add(label);
|
textBox.add(label);
|
||||||
|
|
||||||
let count = source.unseenCount;
|
let countLabel = new St.Label({ text: this._makeNotificationCountText(source),
|
||||||
let countLabel = new St.Label({ text: this._makeNotificationCountText(count, source.isChat),
|
|
||||||
style_class: 'screen-shield-notification-count-text' });
|
style_class: 'screen-shield-notification-count-text' });
|
||||||
textBox.add(countLabel);
|
textBox.add(countLabel);
|
||||||
|
|
||||||
box.visible = count != 0;
|
box.visible = source.count != 0;
|
||||||
return [box, countLabel];
|
return [box, countLabel];
|
||||||
},
|
},
|
||||||
|
|
||||||
_summaryItemAdded: function(tray, item, dontUpdateVisibility) {
|
_summaryItemAdded: function(tray, item) {
|
||||||
// Ignore transient sources, or sources explicitly marked not to show
|
// Ignore transient sources
|
||||||
// in the lock screen
|
if (item.source.isTransient)
|
||||||
if (item.source.isTransient || !item.source.showInLockScreen)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let obj = {
|
let obj = {
|
||||||
@ -185,22 +169,20 @@ const NotificationsBox = new Lang.Class({
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (obj.resident) {
|
if (obj.resident) {
|
||||||
this._residentNotificationBox.add(item.notificationStackWidget);
|
|
||||||
item.closeButton.hide();
|
|
||||||
item.prepareNotificationStackForShowing();
|
item.prepareNotificationStackForShowing();
|
||||||
|
this._residentNotificationBox.add(item.notificationStackView);
|
||||||
} else {
|
} else {
|
||||||
[obj.sourceBox, obj.countLabel] = this._makeNotificationSource(item.source);
|
[obj.sourceBox, obj.countLabel] = this._makeNotificationSource(item.source);
|
||||||
this._persistentNotificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.START });
|
this._persistentNotificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.MIDDLE });
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.contentUpdatedId = item.connect('content-updated', Lang.bind(this, this._onItemContentUpdated));
|
obj.contentUpdatedId = item.connect('content-updated', Lang.bind(this, this._onItemContentUpdated));
|
||||||
obj.sourceCountChangedId = item.source.connect('count-updated', Lang.bind(this, this._onSourceChanged));
|
obj.sourceCountChangedId = item.source.connect('count-changed', Lang.bind(this, this._onSourceChanged));
|
||||||
obj.sourceTitleChangedId = item.source.connect('title-changed', Lang.bind(this, this._onSourceChanged));
|
obj.sourceTitleChangedId = item.source.connect('title-changed', Lang.bind(this, this._onSourceChanged));
|
||||||
obj.sourceDestroyId = item.source.connect('destroy', Lang.bind(this, this._onSourceDestroy));
|
obj.sourceDestroyId = item.source.connect('destroy', Lang.bind(this, this._onSourceDestroy));
|
||||||
this._items.push(obj);
|
this._items.push(obj);
|
||||||
|
|
||||||
if (!dontUpdateVisibility)
|
this._updateVisibility();
|
||||||
this._updateVisibility();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_findSource: function(source) {
|
_findSource: function(source) {
|
||||||
@ -232,25 +214,21 @@ const NotificationsBox = new Lang.Class({
|
|||||||
|
|
||||||
if (obj.resident && !itemShouldBeResident) {
|
if (obj.resident && !itemShouldBeResident) {
|
||||||
// make into a regular item
|
// make into a regular item
|
||||||
obj.item.doneShowingNotificationStack();
|
this._residentNotificationBox.remove_actor(obj.item.notificationStackView);
|
||||||
this._residentNotificationBox.remove_actor(obj.item.notificationStackWidget);
|
|
||||||
|
|
||||||
[obj.sourceBox, obj.countLabel] = this._makeNotificationSource(obj.source);
|
[obj.sourceBox, obj.countLabel] = this._makeNotificationSource(obj.source);
|
||||||
this._persistentNotificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.START });
|
this._persistentNotificationBox.add(obj.sourceBox);
|
||||||
} else if (itemShouldBeResident && !obj.resident) {
|
} else if (itemShouldBeResident && !obj.resident) {
|
||||||
// make into a resident item
|
// make into a resident item
|
||||||
obj.sourceBox.destroy();
|
obj.sourceBox.destroy();
|
||||||
obj.sourceBox = obj.countLabel = null;
|
obj.sourceBox = obj.countLabel = null;
|
||||||
obj.resident = true;
|
|
||||||
|
|
||||||
this._residentNotificationBox.add(obj.item.notificationStackWidget);
|
|
||||||
obj.item.closeButton.hide();
|
|
||||||
obj.item.prepareNotificationStackForShowing();
|
obj.item.prepareNotificationStackForShowing();
|
||||||
|
this._residentNotificationBox.add(obj.item.notificationStackView);
|
||||||
} else {
|
} else {
|
||||||
// just update the counter
|
// just update the counter
|
||||||
let count = obj.source.unseenCount;
|
obj.countLabel.text = this._makeNotificationCountText(obj.item.source);
|
||||||
obj.countLabel.text = this._makeNotificationCountText(count, obj.source.isChat);
|
obj.sourceBox.visible = obj.source.count != 0;
|
||||||
obj.sourceBox.visible = count != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._updateVisibility();
|
this._updateVisibility();
|
||||||
@ -267,8 +245,8 @@ const NotificationsBox = new Lang.Class({
|
|||||||
|
|
||||||
_removeItem: function(obj) {
|
_removeItem: function(obj) {
|
||||||
if (obj.resident) {
|
if (obj.resident) {
|
||||||
|
this._residentNotificationBox.remove_actor(obj.item.notificationStackView);
|
||||||
obj.item.doneShowingNotificationStack();
|
obj.item.doneShowingNotificationStack();
|
||||||
this._residentNotificationBox.remove_actor(obj.item.notificationStackWidget);
|
|
||||||
} else {
|
} else {
|
||||||
obj.sourceBox.destroy();
|
obj.sourceBox.destroy();
|
||||||
}
|
}
|
||||||
@ -279,62 +257,6 @@ const NotificationsBox = new Lang.Class({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const Arrow = new Lang.Class({
|
|
||||||
Name: 'Arrow',
|
|
||||||
Extends: St.Bin,
|
|
||||||
|
|
||||||
_init: function(params) {
|
|
||||||
this.parent(params);
|
|
||||||
this.x_fill = this.y_fill = true;
|
|
||||||
this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
|
|
||||||
|
|
||||||
this._drawingArea = new St.DrawingArea();
|
|
||||||
this._drawingArea.connect('repaint', Lang.bind(this, this._drawArrow));
|
|
||||||
this.child = this._drawingArea;
|
|
||||||
|
|
||||||
this._shadowHelper = null;
|
|
||||||
this._shadowWidth = this._shadowHeight = 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
_drawArrow: function(arrow) {
|
|
||||||
let cr = arrow.get_context();
|
|
||||||
let [w, h] = arrow.get_surface_size();
|
|
||||||
let node = this.get_theme_node();
|
|
||||||
let thickness = node.get_length('-arrow-thickness');
|
|
||||||
|
|
||||||
Clutter.cairo_set_source_color(cr, node.get_foreground_color());
|
|
||||||
|
|
||||||
cr.setLineCap(Cairo.LineCap.ROUND);
|
|
||||||
cr.setLineWidth(thickness);
|
|
||||||
|
|
||||||
cr.moveTo(thickness / 2, h - thickness / 2);
|
|
||||||
cr.lineTo(w/2, thickness);
|
|
||||||
cr.lineTo(w - thickness / 2, h - thickness / 2);
|
|
||||||
cr.stroke();
|
|
||||||
},
|
|
||||||
|
|
||||||
vfunc_style_changed: function() {
|
|
||||||
let node = this.get_theme_node();
|
|
||||||
this._shadow = node.get_shadow('-arrow-shadow');
|
|
||||||
if (this._shadow)
|
|
||||||
this._shadowHelper = St.ShadowHelper.new(this._shadow);
|
|
||||||
else
|
|
||||||
this._shadowHelper = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
vfunc_paint: function() {
|
|
||||||
if (this._shadowHelper) {
|
|
||||||
this._shadowHelper.update(this._drawingArea);
|
|
||||||
|
|
||||||
let allocation = this._drawingArea.get_allocation_box();
|
|
||||||
let paintOpacity = this._drawingArea.get_paint_opacity();
|
|
||||||
this._shadowHelper.paint(allocation, paintOpacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._drawingArea.paint();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To test screen shield, make sure to kill gnome-screensaver.
|
* To test screen shield, make sure to kill gnome-screensaver.
|
||||||
*
|
*
|
||||||
@ -351,55 +273,38 @@ const ScreenShield = new Lang.Class({
|
|||||||
_init: function() {
|
_init: function() {
|
||||||
this.actor = Main.layoutManager.screenShieldGroup;
|
this.actor = Main.layoutManager.screenShieldGroup;
|
||||||
|
|
||||||
this._lockScreenState = MessageTray.State.HIDDEN;
|
|
||||||
this._lockScreenGroup = new St.Widget({ x_expand: true,
|
this._lockScreenGroup = new St.Widget({ x_expand: true,
|
||||||
y_expand: true,
|
y_expand: true,
|
||||||
reactive: true,
|
reactive: true,
|
||||||
can_focus: true,
|
can_focus: true,
|
||||||
name: 'lockScreenGroup',
|
layout_manager: new Clutter.BinLayout()
|
||||||
});
|
});
|
||||||
this._lockScreenGroup.connect('key-release-event',
|
|
||||||
Lang.bind(this, this._onLockScreenKeyRelease));
|
|
||||||
this._lockScreenGroup.connect('scroll-event',
|
|
||||||
Lang.bind(this, this._onLockScreenScroll));
|
|
||||||
|
|
||||||
this._lockScreenContents = new St.Widget({ layout_manager: new Clutter.BinLayout(),
|
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
|
||||||
name: 'lockScreenContents' });
|
this._background.add_effect(new Clutter.BlurEffect());
|
||||||
this._lockScreenContents.add_constraint(new Layout.MonitorConstraint({ primary: true }));
|
this._background.add_effect(new Clutter.DesaturateEffect({ factor: 0.6 }));
|
||||||
|
|
||||||
this._background = new St.Bin({ style_class: 'screen-shield-background',
|
|
||||||
child: Meta.BackgroundActor.new_for_screen(global.screen) });
|
|
||||||
this._lockScreenGroup.add_actor(this._background);
|
this._lockScreenGroup.add_actor(this._background);
|
||||||
this._lockScreenGroup.add_actor(this._lockScreenContents);
|
|
||||||
|
|
||||||
this._arrowContainer = new St.BoxLayout({ style_class: 'screen-shield-arrows',
|
this._arrow = new St.DrawingArea({ style_class: 'arrow',
|
||||||
vertical: true,
|
reactive: true,
|
||||||
x_align: Clutter.ActorAlign.CENTER,
|
x_align: Clutter.ActorAlign.CENTER,
|
||||||
y_align: Clutter.ActorAlign.END,
|
y_align: Clutter.ActorAlign.END,
|
||||||
// HACK: without these, ClutterBinLayout
|
// HACK: without these, ClutterBinLayout
|
||||||
// ignores alignment properties on the actor
|
// ignores alignment properties on the actor
|
||||||
x_expand: true,
|
x_expand: true,
|
||||||
y_expand: true });
|
y_expand: true
|
||||||
|
});
|
||||||
|
this._arrow.connect('repaint', Lang.bind(this, this._drawArrow));
|
||||||
|
this._lockScreenGroup.add_actor(this._arrow);
|
||||||
|
|
||||||
for (let i = 0; i < N_ARROWS; i++) {
|
let action = new Clutter.DragAction({ drag_axis: Clutter.DragAxis.Y_AXIS });
|
||||||
let arrow = new Arrow({ opacity: 0 });
|
|
||||||
this._arrowContainer.add_actor(arrow);
|
|
||||||
}
|
|
||||||
this._lockScreenContents.add_actor(this._arrowContainer);
|
|
||||||
|
|
||||||
let dragArea = new Clutter.Rect({ origin: new Clutter.Point({ x: 0, y: -global.screen_height, }),
|
|
||||||
size: new Clutter.Size({ width: global.screen_width,
|
|
||||||
height: global.screen_height }) });
|
|
||||||
let action = new Clutter.DragAction({ drag_axis: Clutter.DragAxis.Y_AXIS,
|
|
||||||
drag_area: dragArea });
|
|
||||||
action.connect('drag-begin', Lang.bind(this, this._onDragBegin));
|
action.connect('drag-begin', Lang.bind(this, this._onDragBegin));
|
||||||
action.connect('drag-end', Lang.bind(this, this._onDragEnd));
|
action.connect('drag-end', Lang.bind(this, this._onDragEnd));
|
||||||
this._lockScreenGroup.add_action(action);
|
this._lockScreenGroup.add_action(action);
|
||||||
|
|
||||||
this._lockDialogGroup = new St.Widget({ x_expand: true,
|
this._lockDialogGroup = new St.Widget({ x_expand: true,
|
||||||
y_expand: true,
|
y_expand: true });
|
||||||
pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }),
|
|
||||||
name: 'lockDialogGroup' });
|
|
||||||
|
|
||||||
this.actor.add_actor(this._lockDialogGroup);
|
this.actor.add_actor(this._lockDialogGroup);
|
||||||
this.actor.add_actor(this._lockScreenGroup);
|
this.actor.add_actor(this._lockScreenGroup);
|
||||||
@ -416,22 +321,11 @@ const ScreenShield = new Lang.Class({
|
|||||||
this._onStatusChanged(status);
|
this._onStatusChanged(status);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this);
|
|
||||||
|
|
||||||
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 });
|
this._settings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
|
||||||
|
|
||||||
this._isModal = false;
|
this._isModal = false;
|
||||||
|
this._isLocked = false;
|
||||||
this._hasLockScreen = false;
|
this._hasLockScreen = false;
|
||||||
this._isGreeter = false;
|
|
||||||
this._isActive = false;
|
|
||||||
this._inUnlockAnimation = false;
|
|
||||||
this._activationTime = 0;
|
|
||||||
|
|
||||||
this._lightbox = new Lightbox.Lightbox(Main.uiGroup,
|
this._lightbox = new Lightbox.Lightbox(Main.uiGroup,
|
||||||
{ inhibitEvents: true,
|
{ inhibitEvents: true,
|
||||||
@ -439,25 +333,12 @@ const ScreenShield = new Lang.Class({
|
|||||||
fadeFactor: 1 });
|
fadeFactor: 1 });
|
||||||
},
|
},
|
||||||
|
|
||||||
_onLockScreenKeyRelease: function(actor, event) {
|
_onStageKeyRelease: function(actor, event) {
|
||||||
let symbol = event.get_key_symbol();
|
if (!this._isLocked)
|
||||||
|
|
||||||
// Do nothing if the lock screen is not fully shown.
|
|
||||||
// This avoids reusing the previous (and stale) unlock
|
|
||||||
// dialog if esc is pressed while the curtain is going
|
|
||||||
// down after cancel.
|
|
||||||
// Similarly, don't bump if the lock screen is not showing or is
|
|
||||||
// animating, as the bump overrides the animation and would
|
|
||||||
// remove any onComplete handler.
|
|
||||||
|
|
||||||
if (this._lockScreenState != MessageTray.State.SHOWN)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (symbol == Clutter.KEY_Escape ||
|
if (event.get_key_symbol() == Clutter.KEY_Escape) {
|
||||||
symbol == Clutter.KEY_Return ||
|
this._showUnlockDialog(true);
|
||||||
symbol == Clutter.KEY_KP_Enter) {
|
|
||||||
this._ensureUnlockDialog(true);
|
|
||||||
this._hideLockScreen(true);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,59 +346,27 @@ const ScreenShield = new Lang.Class({
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onLockScreenScroll: function(actor, event) {
|
_drawArrow: function() {
|
||||||
if (this._lockScreenState != MessageTray.State.SHOWN)
|
let cr = this._arrow.get_context();
|
||||||
return false;
|
let [w, h] = this._arrow.get_surface_size();
|
||||||
|
let node = this._arrow.get_theme_node();
|
||||||
|
|
||||||
let delta = 0;
|
Clutter.cairo_set_source_color(cr, node.get_foreground_color());
|
||||||
if (event.get_scroll_direction() == Clutter.ScrollDirection.UP)
|
|
||||||
delta = 5;
|
|
||||||
else if (event.get_scroll_direction() == Clutter.ScrollDirection.SMOOTH)
|
|
||||||
delta = Math.max(0, event.get_scroll_delta()[0]);
|
|
||||||
|
|
||||||
this._lockScreenScrollCounter += delta;
|
cr.moveTo(0, h);
|
||||||
|
cr.lineTo(w/2, 0);
|
||||||
// 7 standard scrolls to lift up
|
cr.lineTo(w, h);
|
||||||
if (this._lockScreenScrollCounter > 35) {
|
cr.fill();
|
||||||
this._ensureUnlockDialog(false);
|
|
||||||
this._hideLockScreen(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
_animateArrows: function() {
|
|
||||||
let arrows = this._arrowContainer.get_children();
|
|
||||||
let unitaryDelay = ARROW_ANIMATION_TIME / (arrows.length + 1);
|
|
||||||
let maxOpacity = 255 * ARROW_ANIMATION_PEAK_OPACITY;
|
|
||||||
for (let i = 0; i < arrows.length; i++) {
|
|
||||||
arrows.opacity = 0;
|
|
||||||
Tweener.addTween(arrows[i],
|
|
||||||
{ opacity: 0,
|
|
||||||
delay: unitaryDelay * (N_ARROWS - (i + 1)),
|
|
||||||
time: ARROW_ANIMATION_TIME,
|
|
||||||
transition: function(t, b, c, d) {
|
|
||||||
if (t < d/2)
|
|
||||||
return TweenerEquations.easeOutQuad(t, 0, maxOpacity, d/2);
|
|
||||||
else
|
|
||||||
return TweenerEquations.easeInQuad(t - d/2, maxOpacity, -maxOpacity, d/2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDragBegin: function() {
|
_onDragBegin: function() {
|
||||||
Tweener.removeTweens(this._lockScreenGroup);
|
Tweener.removeTweens(this._lockScreenGroup);
|
||||||
this._lockScreenState = MessageTray.State.HIDING;
|
|
||||||
this._ensureUnlockDialog(false);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDragEnd: function(action, actor, eventX, eventY, modifiers) {
|
_onDragEnd: function(action, actor, eventX, eventY, modifiers) {
|
||||||
if (this._lockScreenGroup.y < -(ARROW_DRAG_THRESHOLD * global.stage.height)) {
|
if (this._lockScreenGroup.y < -(ARROW_DRAG_TRESHOLD * global.stage.height)) {
|
||||||
// Complete motion automatically
|
// Complete motion automatically
|
||||||
this._hideLockScreen(true);
|
this._showUnlockDialog(true);
|
||||||
} else {
|
} else {
|
||||||
// restore the lock screen to its original place
|
// restore the lock screen to its original place
|
||||||
// try to use the same speed as the normal animation
|
// try to use the same speed as the normal animation
|
||||||
@ -527,21 +376,11 @@ const ScreenShield = new Lang.Class({
|
|||||||
Tweener.addTween(this._lockScreenGroup,
|
Tweener.addTween(this._lockScreenGroup,
|
||||||
{ y: 0,
|
{ y: 0,
|
||||||
time: time,
|
time: time,
|
||||||
transition: 'easeInQuad',
|
transition: 'linear',
|
||||||
onComplete: function() {
|
onComplete: function() {
|
||||||
this._lockScreenGroup.fixed_position_set = false;
|
this.fixed_position_set = false;
|
||||||
this._lockScreenState = MessageTray.State.SHOWN;
|
}
|
||||||
},
|
|
||||||
onCompleteScope: this,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// If we have a unlock dialog, cancel it
|
|
||||||
if (this._dialog) {
|
|
||||||
this._dialog.cancel();
|
|
||||||
if (!this._isGreeter) {
|
|
||||||
this._dialog = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -549,7 +388,7 @@ const ScreenShield = new Lang.Class({
|
|||||||
if (status == GnomeSession.PresenceStatus.IDLE) {
|
if (status == GnomeSession.PresenceStatus.IDLE) {
|
||||||
if (this._dialog) {
|
if (this._dialog) {
|
||||||
this._dialog.cancel();
|
this._dialog.cancel();
|
||||||
if (!this._isGreeter) {
|
if (!this._keepDialog) {
|
||||||
this._dialog = null;
|
this._dialog = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -559,18 +398,14 @@ const ScreenShield = new Lang.Class({
|
|||||||
this._isModal = true;
|
this._isModal = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._isActive) {
|
if (!this._isLocked)
|
||||||
this._lightbox.show();
|
this._lightbox.show();
|
||||||
|
|
||||||
if (this._activationTime == 0)
|
|
||||||
this._activationTime = GLib.get_monotonic_time();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let lightboxWasShown = this._lightbox.shown;
|
let lightboxWasShown = this._lightbox.shown;
|
||||||
this._lightbox.hide();
|
this._lightbox.hide();
|
||||||
|
|
||||||
let shouldLock = lightboxWasShown && this._settings.get_boolean(LOCK_ENABLED_KEY);
|
let shouldLock = lightboxWasShown && this._settings.get_boolean(LOCK_ENABLED_KEY);
|
||||||
if (shouldLock || this._isActive) {
|
if (shouldLock || this._isLocked) {
|
||||||
this.lock(false);
|
this.lock(false);
|
||||||
} else if (this._isModal) {
|
} else if (this._isModal) {
|
||||||
this.unlock();
|
this.unlock();
|
||||||
@ -579,21 +414,8 @@ const ScreenShield = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
showDialog: function() {
|
showDialog: function() {
|
||||||
// Ensure that the stage window is mapped, before taking a grab
|
this.lock(true);
|
||||||
// otherwise X errors out
|
this._showUnlockDialog(false);
|
||||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
|
||||||
if (!this._isModal) {
|
|
||||||
Main.pushModal(this.actor);
|
|
||||||
this._isModal = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}));
|
|
||||||
|
|
||||||
this.actor.show();
|
|
||||||
this._isGreeter = Main.sessionMode.isGreeter;
|
|
||||||
this._ensureUnlockDialog(true);
|
|
||||||
this._hideLockScreen(false);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_bumpLockScreen: function() {
|
_bumpLockScreen: function() {
|
||||||
@ -611,9 +433,7 @@ const ScreenShield = new Lang.Class({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_hideLockScreen: function(animate) {
|
_showUnlockDialog: function(animate) {
|
||||||
this._lockScreenState = MessageTray.State.HIDING;
|
|
||||||
|
|
||||||
if (animate) {
|
if (animate) {
|
||||||
// Tween the lock screen out of screen
|
// Tween the lock screen out of screen
|
||||||
// try to use the same speed regardless of original position
|
// try to use the same speed regardless of original position
|
||||||
@ -623,35 +443,23 @@ const ScreenShield = new Lang.Class({
|
|||||||
Tweener.addTween(this._lockScreenGroup,
|
Tweener.addTween(this._lockScreenGroup,
|
||||||
{ y: -h,
|
{ y: -h,
|
||||||
time: time,
|
time: time,
|
||||||
transition: 'easeInQuad',
|
transition: 'linear',
|
||||||
onComplete: function() {
|
onComplete: Lang.bind(this, this._hideLockScreen),
|
||||||
this._lockScreenState = MessageTray.State.HIDDEN;
|
|
||||||
this._lockScreenGroup.hide();
|
|
||||||
},
|
|
||||||
onCompleteScope: this,
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this._lockScreenState = MessageTray.State.HIDDEN;
|
this._hideLockScreen();
|
||||||
this._lockScreenGroup.hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Main.sessionMode.currentMode == 'lock-screen')
|
|
||||||
Main.sessionMode.popMode('lock-screen');
|
|
||||||
},
|
|
||||||
|
|
||||||
_ensureUnlockDialog: function(onPrimary) {
|
|
||||||
if (!this._dialog) {
|
if (!this._dialog) {
|
||||||
let constructor = Main.sessionMode.unlockDialog;
|
[this._dialog, this._keepDialog] = Main.sessionMode.createUnlockDialog(this._lockDialogGroup);
|
||||||
this._dialog = new constructor(this._lockDialogGroup);
|
|
||||||
if (!this._dialog) {
|
if (!this._dialog) {
|
||||||
// This session mode has no locking capabilities
|
// This session mode has no locking capabilities
|
||||||
this.unlock();
|
this.unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let time = global.get_current_time();
|
|
||||||
this._dialog.connect('loaded', Lang.bind(this, function() {
|
this._dialog.connect('loaded', Lang.bind(this, function() {
|
||||||
if (!this._dialog.open(time, onPrimary)) {
|
if (!this._dialog.open()) {
|
||||||
log('Could not open login dialog: failed to acquire grab');
|
log('Could not open login dialog: failed to acquire grab');
|
||||||
this.unlock();
|
this.unlock();
|
||||||
}
|
}
|
||||||
@ -660,93 +468,73 @@ const ScreenShield = new Lang.Class({
|
|||||||
this._dialog.connect('failed', Lang.bind(this, this._onUnlockFailed));
|
this._dialog.connect('failed', Lang.bind(this, this._onUnlockFailed));
|
||||||
this._dialog.connect('unlocked', Lang.bind(this, this._onUnlockSucceded));
|
this._dialog.connect('unlocked', Lang.bind(this, this._onUnlockSucceded));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._keepDialog) {
|
||||||
|
// Notify the other components that even though we are showing the
|
||||||
|
// screenshield, we're not in a locked state
|
||||||
|
// (this happens for the gdm greeter)
|
||||||
|
|
||||||
|
this._isLocked = false;
|
||||||
|
this.emit('lock-status-changed', false);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onUnlockFailed: function() {
|
_onUnlockFailed: function() {
|
||||||
this._resetLockScreen(true, false);
|
this._dialog.destroy();
|
||||||
|
this._dialog = null;
|
||||||
|
|
||||||
|
this._resetLockScreen(false);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onUnlockSucceded: function() {
|
_onUnlockSucceded: function() {
|
||||||
this._tweenUnlocked();
|
this.unlock();
|
||||||
},
|
},
|
||||||
|
|
||||||
_resetLockScreen: function(animateLockScreen, animateLockDialog) {
|
_hideLockScreen: function() {
|
||||||
this._ensureLockScreen();
|
this._arrow.hide();
|
||||||
this._lockDialogGroup.scale_x = 1;
|
this._lockScreenGroup.hide();
|
||||||
this._lockDialogGroup.scale_y = 1;
|
},
|
||||||
|
|
||||||
|
_resetLockScreen: function(animate) {
|
||||||
this._lockScreenGroup.show();
|
this._lockScreenGroup.show();
|
||||||
this._lockScreenState = MessageTray.State.SHOWING;
|
this._arrow.show();
|
||||||
|
|
||||||
if (animateLockScreen) {
|
if (animate) {
|
||||||
this._lockScreenGroup.y = -global.screen_height;
|
this._lockScreenGroup.y = -global.screen_height;
|
||||||
Tweener.removeTweens(this._lockScreenGroup);
|
Tweener.removeTweens(this._lockScreenGroup);
|
||||||
Tweener.addTween(this._lockScreenGroup,
|
Tweener.addTween(this._lockScreenGroup,
|
||||||
{ y: 0,
|
{ y: 0,
|
||||||
time: SHORT_FADE_TIME,
|
time: SHORT_FADE_TIME,
|
||||||
transition: 'easeOutQuad',
|
transition: 'linear',
|
||||||
onComplete: function() {
|
onComplete: function() {
|
||||||
this._lockScreenShown();
|
this._lockScreenGroup.fixed_position_set = false;
|
||||||
|
this.emit('lock-screen-shown');
|
||||||
},
|
},
|
||||||
onCompleteScope: this
|
onCompleteScope: this
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this._lockScreenGroup.fixed_position_set = false;
|
this._lockScreenGroup.fixed_position_set = false;
|
||||||
this._lockScreenShown();
|
this.emit('lock-screen-shown');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (animateLockDialog) {
|
if (!this._stageKeyHandler)
|
||||||
this._lockDialogGroup.opacity = 0;
|
this._stageKeyHandler = global.stage.connect('key-release-event',
|
||||||
Tweener.removeTweens(this._lockDialogGroup);
|
Lang.bind(this, this._onStageKeyRelease));
|
||||||
Tweener.addTween(this._lockDialogGroup,
|
|
||||||
{ opacity: 255,
|
|
||||||
time: SHORT_FADE_TIME,
|
|
||||||
transition: 'easeOutQuad' });
|
|
||||||
} else {
|
|
||||||
this._lockDialogGroup.opacity = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._lockScreenGroup.grab_key_focus();
|
|
||||||
|
|
||||||
if (Main.sessionMode.currentMode != 'lock-screen')
|
|
||||||
Main.sessionMode.pushMode('lock-screen');
|
|
||||||
},
|
|
||||||
|
|
||||||
_lockScreenShown: function() {
|
|
||||||
if (this._dialog && !this._isGreeter) {
|
|
||||||
this._dialog.destroy();
|
|
||||||
this._dialog = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._arrowAnimationId)
|
|
||||||
Mainloop.source_remove(this._arrowAnimationId);
|
|
||||||
this._arrowAnimationId = Mainloop.timeout_add(6000, Lang.bind(this, this._animateArrows));
|
|
||||||
this._animateArrows();
|
|
||||||
|
|
||||||
this._lockScreenState = MessageTray.State.SHOWN;
|
|
||||||
this._lockScreenGroup.fixed_position_set = false;
|
|
||||||
this._lockScreenScrollCounter = 0;
|
|
||||||
|
|
||||||
this.emit('lock-screen-shown');
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Some of the actors in the lock screen are heavy in
|
// Some of the actors in the lock screen are heavy in
|
||||||
// resources, so we only create them when needed
|
// resources, so we only create them when needed
|
||||||
_ensureLockScreen: function() {
|
_prepareLockScreen: function() {
|
||||||
if (this._hasLockScreen)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._lockScreenContentsBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.CENTER,
|
this._lockScreenContentsBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.CENTER,
|
||||||
y_align: Clutter.ActorAlign.CENTER,
|
y_align: Clutter.ActorAlign.CENTER,
|
||||||
x_expand: true,
|
x_expand: true,
|
||||||
y_expand: true,
|
y_expand: true,
|
||||||
vertical: true,
|
vertical: true });
|
||||||
style_class: 'screen-shield-contents-box' });
|
|
||||||
this._clock = new Clock();
|
this._clock = new Clock();
|
||||||
this._lockScreenContentsBox.add(this._clock.actor, { x_fill: true,
|
this._lockScreenContentsBox.add(this._clock.actor, { x_fill: true,
|
||||||
y_fill: true });
|
y_fill: true });
|
||||||
|
|
||||||
this._lockScreenContents.add_actor(this._lockScreenContentsBox);
|
this._lockScreenGroup.add_actor(this._lockScreenContentsBox);
|
||||||
|
|
||||||
if (this._settings.get_boolean('show-notifications')) {
|
if (this._settings.get_boolean('show-notifications')) {
|
||||||
this._notificationsBox = new NotificationsBox();
|
this._notificationsBox = new NotificationsBox();
|
||||||
@ -769,153 +557,60 @@ const ScreenShield = new Lang.Class({
|
|||||||
|
|
||||||
this._lockScreenContentsBox.destroy();
|
this._lockScreenContentsBox.destroy();
|
||||||
|
|
||||||
if (this._arrowAnimationId) {
|
|
||||||
Mainloop.source_remove(this._arrowAnimationId);
|
|
||||||
this._arrowAnimationId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._hasLockScreen = false;
|
this._hasLockScreen = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
get locked() {
|
get locked() {
|
||||||
return this._isActive;
|
return this._isLocked;
|
||||||
},
|
|
||||||
|
|
||||||
get activationTime() {
|
|
||||||
return this._activationTime;
|
|
||||||
},
|
|
||||||
|
|
||||||
_tweenUnlocked: function() {
|
|
||||||
this._inUnlockAnimation = true;
|
|
||||||
this.unlock();
|
|
||||||
Tweener.addTween(this._lockDialogGroup, {
|
|
||||||
scale_x: 0,
|
|
||||||
scale_y: 0,
|
|
||||||
time: Overview.ANIMATION_TIME,
|
|
||||||
transition: 'easeOutQuad',
|
|
||||||
onComplete: function() {
|
|
||||||
if (this._dialog) {
|
|
||||||
this._dialog.destroy();
|
|
||||||
this._dialog = null;
|
|
||||||
}
|
|
||||||
this.actor.hide();
|
|
||||||
this._inUnlockAnimation = false;
|
|
||||||
},
|
|
||||||
onCompleteScope: this
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
unlock: function() {
|
unlock: function() {
|
||||||
if (this._hasLockScreen)
|
if (this._hasLockScreen)
|
||||||
this._clearLockScreen();
|
this._clearLockScreen();
|
||||||
|
|
||||||
if (this._dialog && !this._isGreeter) {
|
if (this._stageKeyHandler) {
|
||||||
|
global.stage.disconnect(this._stageKeyHandler);
|
||||||
|
this._stageKeyHandler = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._keepDialog) {
|
||||||
|
// The dialog must be kept alive,
|
||||||
|
// so immediately go back to it
|
||||||
|
// This will also reset _isLocked
|
||||||
|
this._showUnlockDialog(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._dialog) {
|
||||||
this._dialog.destroy();
|
this._dialog.destroy();
|
||||||
this._dialog = null;
|
this._dialog = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._lightbox.hide();
|
this._lightbox.hide();
|
||||||
|
|
||||||
if (this._isModal) {
|
Main.popModal(this.actor);
|
||||||
Main.popModal(this.actor);
|
this.actor.hide();
|
||||||
this._isModal = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._inUnlockAnimation)
|
this._isModal = false;
|
||||||
this.actor.hide();
|
this._isLocked = false;
|
||||||
|
|
||||||
if (Main.sessionMode.currentMode == 'lock-screen')
|
this.emit('lock-status-changed', false);
|
||||||
Main.sessionMode.popMode('lock-screen');
|
|
||||||
if (Main.sessionMode.currentMode == 'unlock-dialog')
|
|
||||||
Main.sessionMode.popMode('unlock-dialog');
|
|
||||||
|
|
||||||
this._activationTime = 0;
|
|
||||||
this._isActive = false;
|
|
||||||
this.emit('lock-status-changed');
|
|
||||||
},
|
},
|
||||||
|
|
||||||
lock: function(animate) {
|
lock: function(animate) {
|
||||||
|
if (!this._hasLockScreen)
|
||||||
|
this._prepareLockScreen();
|
||||||
|
|
||||||
if (!this._isModal) {
|
if (!this._isModal) {
|
||||||
Main.pushModal(this.actor);
|
Main.pushModal(this.actor);
|
||||||
this._isModal = true;
|
this._isModal = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._activationTime == 0)
|
this._isLocked = true;
|
||||||
this._activationTime = GLib.get_monotonic_time();
|
|
||||||
|
|
||||||
this.actor.show();
|
this.actor.show();
|
||||||
|
this._resetLockScreen(animate);
|
||||||
|
|
||||||
if (Main.sessionMode.currentMode != 'unlock-dialog' &&
|
this.emit('lock-status-changed', true);
|
||||||
Main.sessionMode.currentMode != 'lock-screen') {
|
|
||||||
this._isGreeter = Main.sessionMode.isGreeter;
|
|
||||||
if (!this._isGreeter)
|
|
||||||
Main.sessionMode.pushMode('unlock-dialog');
|
|
||||||
}
|
|
||||||
|
|
||||||
this._resetLockScreen(animate, animate);
|
|
||||||
|
|
||||||
this._isActive = true;
|
|
||||||
this.emit('lock-status-changed');
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(ScreenShield.prototype);
|
Signals.addSignalMethods(ScreenShield.prototype);
|
||||||
|
|
||||||
/* Fallback code to handle session locking using gnome-screensaver,
|
|
||||||
in case the required GDM dependency is not there
|
|
||||||
*/
|
|
||||||
const ScreenShieldFallback = new Lang.Class({
|
|
||||||
Name: 'ScreenShieldFallback',
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
Util.spawn(['gnome-screensaver']);
|
|
||||||
|
|
||||||
this._proxy = new Gio.DBusProxy({ g_connection: Gio.DBus.session,
|
|
||||||
g_name: 'org.gnome.ScreenSaver',
|
|
||||||
g_object_path: '/org/gnome/ScreenSaver',
|
|
||||||
g_interface_name: 'org.gnome.ScreenSaver',
|
|
||||||
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));
|
|
||||||
this._proxy.connect('notify::g-name-owner', Lang.bind(this, this._onNameOwnerChanged));
|
|
||||||
},
|
|
||||||
|
|
||||||
_onNameOwnerChanged: function(object, pspec) {
|
|
||||||
if (this._proxy.g_name_owner)
|
|
||||||
[this._locked] = this._proxy.call_sync('GetActive', null,
|
|
||||||
Gio.DBusCallFlags.NONE, -1, null).deep_unpack();
|
|
||||||
else
|
|
||||||
this._locked = false;
|
|
||||||
|
|
||||||
this.emit('lock-status-changed', this._locked);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onSignal: function(proxy, senderName, signalName, params) {
|
|
||||||
if (signalName == 'ActiveChanged') {
|
|
||||||
[this._locked] = params.deep_unpack();
|
|
||||||
this.emit('lock-status-changed', this._locked);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
get locked() {
|
|
||||||
return this._locked;
|
|
||||||
},
|
|
||||||
|
|
||||||
lock: function() {
|
|
||||||
this._proxy.call('Lock', null, Gio.DBusCallFlags.NONE, -1, null,
|
|
||||||
Lang.bind(this, function(proxy, result) {
|
|
||||||
proxy.call_finish(result);
|
|
||||||
|
|
||||||
this.emit('lock-screen-shown');
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
unlock: function() {
|
|
||||||
this._proxy.call('SetActive', GLib.Variant.new('(b)', false),
|
|
||||||
Gio.DBusCallFlags.NONE, -1, null, null);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
Signals.addSignalMethods(ScreenShieldFallback.prototype);
|
|
||||||
|
@ -80,23 +80,15 @@ const PerfHelperIface = <interface name="org.gnome.Shell.PerfHelper">
|
|||||||
<method name="DestroyWindows" />
|
<method name="DestroyWindows" />
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
const PerfHelper = new Gio.DBusProxyClass({
|
var PerfHelperProxy = Gio.DBusProxy.makeProxyWrapper(PerfHelperIface);
|
||||||
Name: 'PerfHelperProxy',
|
function PerfHelper() {
|
||||||
Interface: PerfHelperIface,
|
return new PerfHelperProxy(Gio.DBus.session, 'org.gnome.Shell.PerfHelper', '/org/gnome/Shell/PerfHelper');
|
||||||
|
}
|
||||||
_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;
|
let _perfHelper = null;
|
||||||
function _getPerfHelper() {
|
function _getPerfHelper() {
|
||||||
if (_perfHelper == null) {
|
if (_perfHelper == null)
|
||||||
_perfHelper = new PerfHelper();
|
_perfHelper = new PerfHelper();
|
||||||
_perfHelper.init(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _perfHelper;
|
return _perfHelper;
|
||||||
}
|
}
|
||||||
@ -119,8 +111,7 @@ function createTestWindow(width, height, alpha, maximized) {
|
|||||||
let perfHelper = _getPerfHelper();
|
let perfHelper = _getPerfHelper();
|
||||||
|
|
||||||
perfHelper.CreateWindowRemote(width, height, alpha, maximized,
|
perfHelper.CreateWindowRemote(width, height, alpha, maximized,
|
||||||
null,
|
function(result, excp) {
|
||||||
function(proxy, result) {
|
|
||||||
if (cb)
|
if (cb)
|
||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
@ -140,7 +131,7 @@ function waitTestWindows() {
|
|||||||
let cb;
|
let cb;
|
||||||
let perfHelper = _getPerfHelper();
|
let perfHelper = _getPerfHelper();
|
||||||
|
|
||||||
perfHelper.WaitWindowsRemote(null, function(proxy, result) {
|
perfHelper.WaitWindowsRemote(function(result, excp) {
|
||||||
if (cb)
|
if (cb)
|
||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
@ -163,7 +154,7 @@ function destroyTestWindows() {
|
|||||||
let cb;
|
let cb;
|
||||||
let perfHelper = _getPerfHelper();
|
let perfHelper = _getPerfHelper();
|
||||||
|
|
||||||
perfHelper.DestroyWindowsRemote(null, function(proxy, result) {
|
perfHelper.DestroyWindowsRemote(function(result, excp) {
|
||||||
if (cb)
|
if (cb)
|
||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
const GObject = imports.gi.GObject;
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
@ -11,6 +10,8 @@ const Util = imports.misc.util;
|
|||||||
const FileUtils = imports.misc.fileUtils;
|
const FileUtils = imports.misc.fileUtils;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
|
const DISABLED_OPEN_SEARCH_PROVIDERS_KEY = 'disabled-open-search-providers';
|
||||||
|
|
||||||
// Not currently referenced by the search API, but
|
// Not currently referenced by the search API, but
|
||||||
// this enumeration can be useful for provider
|
// this enumeration can be useful for provider
|
||||||
// implementations.
|
// implementations.
|
||||||
@ -76,8 +77,6 @@ const SearchProvider = new Lang.Class({
|
|||||||
Name: 'SearchProvider',
|
Name: 'SearchProvider',
|
||||||
|
|
||||||
_init: function(title) {
|
_init: function(title) {
|
||||||
this.parent();
|
|
||||||
|
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.searchSystem = null;
|
this.searchSystem = null;
|
||||||
},
|
},
|
||||||
@ -170,6 +169,99 @@ const SearchProvider = new Lang.Class({
|
|||||||
});
|
});
|
||||||
Signals.addSignalMethods(SearchProvider.prototype);
|
Signals.addSignalMethods(SearchProvider.prototype);
|
||||||
|
|
||||||
|
const OpenSearchSystem = new Lang.Class({
|
||||||
|
Name: 'OpenSearchSystem',
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
this._providers = [];
|
||||||
|
global.settings.connect('changed::' + DISABLED_OPEN_SEARCH_PROVIDERS_KEY, Lang.bind(this, this._refresh));
|
||||||
|
this._refresh();
|
||||||
|
},
|
||||||
|
|
||||||
|
getProviders: function() {
|
||||||
|
let res = [];
|
||||||
|
for (let i = 0; i < this._providers.length; i++)
|
||||||
|
res.push({ id: i, name: this._providers[i].name });
|
||||||
|
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
|
||||||
|
setSearchTerms: function(terms) {
|
||||||
|
this._terms = terms;
|
||||||
|
},
|
||||||
|
|
||||||
|
_checkSupportedProviderLanguage: function(provider) {
|
||||||
|
if (provider.url.search(/{language}/) == -1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
let langs = GLib.get_language_names();
|
||||||
|
|
||||||
|
langs.push('en');
|
||||||
|
let lang = null;
|
||||||
|
for (let i = 0; i < langs.length; i++) {
|
||||||
|
for (let k = 0; k < provider.langs.length; k++) {
|
||||||
|
if (langs[i] == provider.langs[k])
|
||||||
|
lang = langs[i];
|
||||||
|
}
|
||||||
|
if (lang)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
provider.lang = lang;
|
||||||
|
return lang != null;
|
||||||
|
},
|
||||||
|
|
||||||
|
activateResult: function(id, params) {
|
||||||
|
let searchTerms = this._terms.join(' ');
|
||||||
|
|
||||||
|
let url = this._providers[id].url.replace('{searchTerms}', encodeURIComponent(searchTerms));
|
||||||
|
if (url.match('{language}'))
|
||||||
|
url = url.replace('{language}', this._providers[id].lang);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context());
|
||||||
|
} catch (e) {
|
||||||
|
// TODO: remove this after glib will be removed from moduleset
|
||||||
|
// In the default jhbuild, gio is in our prefix but gvfs is not
|
||||||
|
Util.spawn(['gvfs-open', url])
|
||||||
|
}
|
||||||
|
|
||||||
|
Main.overview.hide();
|
||||||
|
},
|
||||||
|
|
||||||
|
_addProvider: function(fileName) {
|
||||||
|
let path = global.datadir + '/open-search-providers/' + fileName;
|
||||||
|
let source = Shell.get_file_contents_utf8_sync(path);
|
||||||
|
let [success, name, url, langs, icon_uri] = Shell.parse_search_provider(source);
|
||||||
|
let provider ={ name: name,
|
||||||
|
url: url,
|
||||||
|
id: this._providers.length,
|
||||||
|
icon_uri: icon_uri,
|
||||||
|
langs: langs };
|
||||||
|
if (this._checkSupportedProviderLanguage(provider)) {
|
||||||
|
this._providers.push(provider);
|
||||||
|
this.emit('changed');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_refresh: function() {
|
||||||
|
this._providers = [];
|
||||||
|
let names = global.settings.get_strv(DISABLED_OPEN_SEARCH_PROVIDERS_KEY);
|
||||||
|
let file = Gio.file_new_for_path(global.datadir + '/open-search-providers');
|
||||||
|
FileUtils.listDirAsync(file, Lang.bind(this, function(files) {
|
||||||
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
let enabled = true;
|
||||||
|
let name = files[i].get_name();
|
||||||
|
for (let k = 0; k < names.length; k++)
|
||||||
|
if (names[k] == name)
|
||||||
|
enabled = false;
|
||||||
|
if (enabled)
|
||||||
|
this._addProvider(name);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(OpenSearchSystem.prototype);
|
||||||
|
|
||||||
const SearchSystem = new Lang.Class({
|
const SearchSystem = new Lang.Class({
|
||||||
Name: 'SearchSystem',
|
Name: 'SearchSystem',
|
||||||
|
|
||||||
|
@ -173,9 +173,10 @@ const GridSearchResults = new Lang.Class({
|
|||||||
const SearchResults = new Lang.Class({
|
const SearchResults = new Lang.Class({
|
||||||
Name: 'SearchResults',
|
Name: 'SearchResults',
|
||||||
|
|
||||||
_init: function(searchSystem) {
|
_init: function(searchSystem, openSearchSystem) {
|
||||||
this._searchSystem = searchSystem;
|
this._searchSystem = searchSystem;
|
||||||
this._searchSystem.connect('search-updated', Lang.bind(this, this._updateResults));
|
this._searchSystem.connect('search-updated', Lang.bind(this, this._updateResults));
|
||||||
|
this._openSearchSystem = openSearchSystem;
|
||||||
|
|
||||||
this.actor = new St.BoxLayout({ name: 'searchResults',
|
this.actor = new St.BoxLayout({ name: 'searchResults',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
@ -190,7 +191,7 @@ const SearchResults = new Lang.Class({
|
|||||||
scrollView.add_actor(this._content);
|
scrollView.add_actor(this._content);
|
||||||
|
|
||||||
this.actor.add(scrollView, { x_fill: true,
|
this.actor.add(scrollView, { x_fill: true,
|
||||||
y_fill: true,
|
y_fill: false,
|
||||||
expand: true,
|
expand: true,
|
||||||
x_align: St.Align.START,
|
x_align: St.Align.START,
|
||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
@ -205,26 +206,70 @@ const SearchResults = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
this._statusText = new St.Label({ style_class: 'search-statustext' });
|
this._statusText = new St.Label({ style_class: 'search-statustext' });
|
||||||
this._statusBin = new St.Bin({ x_align: St.Align.MIDDLE,
|
this._content.add(this._statusText);
|
||||||
y_align: St.Align.MIDDLE });
|
|
||||||
this._content.add(this._statusBin, { expand: true });
|
|
||||||
this._statusBin.add_actor(this._statusText);
|
|
||||||
this._providers = this._searchSystem.getProviders();
|
this._providers = this._searchSystem.getProviders();
|
||||||
this._providerMeta = [];
|
this._providerMeta = [];
|
||||||
for (let i = 0; i < this._providers.length; i++) {
|
for (let i = 0; i < this._providers.length; i++) {
|
||||||
this.createProviderMeta(this._providers[i]);
|
this.createProviderMeta(this._providers[i]);
|
||||||
}
|
}
|
||||||
|
this._searchProvidersBox = new St.BoxLayout({ style_class: 'search-providers-box' });
|
||||||
|
this.actor.add(this._searchProvidersBox);
|
||||||
|
|
||||||
|
this._openSearchProviders = [];
|
||||||
|
this._openSearchSystem.connect('changed', Lang.bind(this, this._updateOpenSearchProviderButtons));
|
||||||
|
this._updateOpenSearchProviderButtons();
|
||||||
|
|
||||||
this._highlightDefault = false;
|
this._highlightDefault = false;
|
||||||
this._defaultResult = null;
|
this._defaultResult = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_updateOpenSearchProviderButtons: function() {
|
||||||
|
for (let i = 0; i < this._openSearchProviders.length; i++)
|
||||||
|
this._openSearchProviders[i].actor.destroy();
|
||||||
|
this._openSearchProviders = this._openSearchSystem.getProviders();
|
||||||
|
for (let i = 0; i < this._openSearchProviders.length; i++)
|
||||||
|
this._createOpenSearchProviderButton(this._openSearchProviders[i]);
|
||||||
|
},
|
||||||
|
|
||||||
|
_createOpenSearchProviderButton: function(provider) {
|
||||||
|
let button = new St.Button({ style_class: 'dash-search-button',
|
||||||
|
reactive: true,
|
||||||
|
can_focus: true,
|
||||||
|
x_fill: true,
|
||||||
|
y_align: St.Align.MIDDLE });
|
||||||
|
let bin = new St.Bin({ x_fill: false,
|
||||||
|
x_align:St.Align.MIDDLE });
|
||||||
|
button.connect('clicked', Lang.bind(this, function() {
|
||||||
|
this._openSearchSystem.activateResult(provider.id);
|
||||||
|
}));
|
||||||
|
let title = new St.Label({ text: provider.name,
|
||||||
|
style_class: 'dash-search-button-label' });
|
||||||
|
|
||||||
|
button.label_actor = title;
|
||||||
|
bin.set_child(title);
|
||||||
|
button.set_child(bin);
|
||||||
|
provider.actor = button;
|
||||||
|
|
||||||
|
button.setSelected = function(selected) {
|
||||||
|
if (selected)
|
||||||
|
button.add_style_pseudo_class('selected');
|
||||||
|
else
|
||||||
|
button.remove_style_pseudo_class('selected');
|
||||||
|
};
|
||||||
|
button.activate = Lang.bind(this, function() {
|
||||||
|
this._openSearchSystem.activateResult(provider.id);
|
||||||
|
});
|
||||||
|
button.actor = button;
|
||||||
|
|
||||||
|
this._searchProvidersBox.add(button);
|
||||||
|
},
|
||||||
|
|
||||||
createProviderMeta: function(provider) {
|
createProviderMeta: function(provider) {
|
||||||
let providerBox = new St.BoxLayout({ style_class: 'search-section',
|
let providerBox = new St.BoxLayout({ style_class: 'search-section',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
let title = new St.Label({ style_class: 'search-section-header',
|
let title = new St.Label({ style_class: 'search-section-header',
|
||||||
text: provider.title });
|
text: provider.title });
|
||||||
providerBox.add(title, { x_fill: false, x_align: St.Align.START });
|
providerBox.add(title);
|
||||||
|
|
||||||
let resultDisplayBin = new St.Bin({ style_class: 'search-section-results',
|
let resultDisplayBin = new St.Bin({ style_class: 'search-section-results',
|
||||||
x_fill: true,
|
x_fill: true,
|
||||||
@ -266,18 +311,20 @@ const SearchResults = new Lang.Class({
|
|||||||
|
|
||||||
reset: function() {
|
reset: function() {
|
||||||
this._searchSystem.reset();
|
this._searchSystem.reset();
|
||||||
this._statusBin.hide();
|
this._statusText.hide();
|
||||||
this._clearDisplay();
|
this._clearDisplay();
|
||||||
},
|
},
|
||||||
|
|
||||||
startingSearch: function() {
|
startingSearch: function() {
|
||||||
this.reset();
|
this.reset();
|
||||||
this._statusText.set_text(_("Searching..."));
|
this._statusText.set_text(_("Searching..."));
|
||||||
this._statusBin.show();
|
this._statusText.show();
|
||||||
},
|
},
|
||||||
|
|
||||||
doSearch: function (searchString) {
|
doSearch: function (searchString) {
|
||||||
this._searchSystem.updateSearch(searchString);
|
this._searchSystem.updateSearch(searchString);
|
||||||
|
let terms = this._searchSystem.getTerms();
|
||||||
|
this._openSearchSystem.setSearchTerms(terms);
|
||||||
},
|
},
|
||||||
|
|
||||||
_metaForProvider: function(provider) {
|
_metaForProvider: function(provider) {
|
||||||
@ -300,6 +347,9 @@ const SearchResults = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!newDefaultResult)
|
||||||
|
newDefaultResult = this._searchProvidersBox.get_first_child();
|
||||||
|
|
||||||
if (newDefaultResult != this._defaultResult) {
|
if (newDefaultResult != this._defaultResult) {
|
||||||
if (this._defaultResult)
|
if (this._defaultResult)
|
||||||
this._defaultResult.setSelected(false);
|
this._defaultResult.setSelected(false);
|
||||||
@ -320,10 +370,10 @@ const SearchResults = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!haveResults) {
|
if (!haveResults) {
|
||||||
this._statusText.set_text(_("No results."));
|
this._statusText.set_text(_("No matching results."));
|
||||||
this._statusBin.show();
|
this._statusText.show();
|
||||||
} else {
|
} else {
|
||||||
this._statusBin.hide();
|
this._statusText.hide();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,160 +1,135 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Signals = imports.signals;
|
|
||||||
|
|
||||||
|
const Config = imports.misc.config;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
|
|
||||||
const DEFAULT_MODE = 'restrictive';
|
|
||||||
|
const STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION = {
|
||||||
|
'a11y': imports.ui.status.accessibility.ATIndicator,
|
||||||
|
'volume': imports.ui.status.volume.Indicator,
|
||||||
|
'battery': imports.ui.status.power.Indicator,
|
||||||
|
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
|
||||||
|
'userMenu': imports.ui.userMenu.UserMenuButton
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Config.HAVE_BLUETOOTH)
|
||||||
|
STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION['bluetooth'] =
|
||||||
|
imports.ui.status.bluetooth.Indicator;
|
||||||
|
|
||||||
|
try {
|
||||||
|
STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION['network'] =
|
||||||
|
imports.ui.status.network.NMApplet;
|
||||||
|
} catch(e) {
|
||||||
|
log('NMApplet is not supported. It is possible that your NetworkManager version is too old');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const DEFAULT_MODE = 'user';
|
||||||
|
|
||||||
const _modes = {
|
const _modes = {
|
||||||
'restrictive': {
|
'gdm': { hasOverview: false,
|
||||||
hasOverview: false,
|
hasAppMenu: false,
|
||||||
showCalendarEvents: false,
|
showCalendarEvents: false,
|
||||||
allowSettings: false,
|
allowSettings: false,
|
||||||
allowExtensions: false,
|
allowExtensions: false,
|
||||||
allowKeybindingsWhenModal: false,
|
allowKeybindingsWhenModal: true,
|
||||||
hasRunDialog: false,
|
hasRunDialog: false,
|
||||||
hasWorkspaces: false,
|
hasWorkspaces: false,
|
||||||
hasWindows: false,
|
createSession: Main.createGDMSession,
|
||||||
hasNotifications: false,
|
createUnlockDialog: Main.createGDMLoginDialog,
|
||||||
isLocked: false,
|
extraStylesheet: null,
|
||||||
isGreeter: false,
|
statusArea: {
|
||||||
isPrimary: false,
|
order: [
|
||||||
unlockDialog: null,
|
'a11y', 'display', 'keyboard',
|
||||||
components: [],
|
'volume', 'battery', 'powerMenu'
|
||||||
panel: {
|
],
|
||||||
left: [],
|
implementation: {
|
||||||
center: [],
|
'a11y': imports.ui.status.accessibility.ATIndicator,
|
||||||
right: []
|
'volume': imports.ui.status.volume.Indicator,
|
||||||
},
|
'battery': imports.ui.status.power.Indicator,
|
||||||
},
|
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
|
||||||
|
'powerMenu': imports.gdm.powerMenu.PowerMenuButton
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
'gdm': {
|
'initial-setup': { hasOverview: false,
|
||||||
allowKeybindingsWhenModal: true,
|
hasAppMenu: false,
|
||||||
hasNotifications: true,
|
showCalendarEvents: false,
|
||||||
isGreeter: true,
|
allowSettings: false,
|
||||||
isPrimary: true,
|
allowExtensions: false,
|
||||||
unlockDialog: imports.gdm.loginDialog.LoginDialog,
|
allowKeybindingsWhenModal: false,
|
||||||
components: ['polkitAgent'],
|
hasRunDialog: false,
|
||||||
panel: {
|
hasWorkspaces: false,
|
||||||
left: ['logo'],
|
createSession: Main.createInitialSetupSession,
|
||||||
center: ['dateMenu'],
|
extraStylesheet: null,
|
||||||
right: ['a11y', 'display', 'keyboard',
|
statusArea: {
|
||||||
'volume', 'battery', 'powerMenu']
|
order: [
|
||||||
}
|
'a11y', 'keyboard', 'volume'
|
||||||
},
|
],
|
||||||
|
implementation: {
|
||||||
|
'a11y': imports.ui.status.accessibility.ATIndicator,
|
||||||
|
'keyboard': imports.ui.status.keyboard.XKBIndicator,
|
||||||
|
'volume': imports.ui.status.volume.Indicator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
'lock-screen': {
|
'user': { hasOverview: true,
|
||||||
isLocked: true,
|
hasAppMenu: true,
|
||||||
isGreeter: undefined,
|
showCalendarEvents: true,
|
||||||
unlockDialog: undefined,
|
allowSettings: true,
|
||||||
components: ['polkitAgent', 'telepathyClient'],
|
allowExtensions: true,
|
||||||
panel: {
|
allowKeybindingsWhenModal: false,
|
||||||
left: ['userMenu'],
|
hasRunDialog: true,
|
||||||
center: [],
|
hasWorkspaces: true,
|
||||||
right: ['lockScreen']
|
createSession: Main.createUserSession,
|
||||||
},
|
createUnlockDialog: Main.createSessionUnlockDialog,
|
||||||
},
|
extraStylesheet: null,
|
||||||
|
statusArea: {
|
||||||
'unlock-dialog': {
|
order: [
|
||||||
isLocked: true,
|
'input-method', 'a11y', 'keyboard', 'volume', 'bluetooth',
|
||||||
unlockDialog: undefined,
|
'network', 'battery', 'userMenu'
|
||||||
components: ['polkitAgent', 'telepathyClient'],
|
],
|
||||||
panel: {
|
implementation: STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION
|
||||||
left: ['userMenu'],
|
}
|
||||||
center: [],
|
}
|
||||||
right: ['a11y', 'keyboard', 'lockScreen']
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
'initial-setup': {
|
|
||||||
isPrimary: true,
|
|
||||||
components: ['keyring'],
|
|
||||||
panel: {
|
|
||||||
left: [],
|
|
||||||
center: ['dateMenu'],
|
|
||||||
right: ['a11y', 'keyboard', 'volume']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
'user': {
|
|
||||||
hasOverview: true,
|
|
||||||
showCalendarEvents: true,
|
|
||||||
allowSettings: true,
|
|
||||||
allowExtensions: true,
|
|
||||||
hasRunDialog: true,
|
|
||||||
hasWorkspaces: true,
|
|
||||||
hasWindows: true,
|
|
||||||
hasNotifications: true,
|
|
||||||
isLocked: false,
|
|
||||||
isPrimary: true,
|
|
||||||
unlockDialog: imports.ui.unlockDialog.UnlockDialog,
|
|
||||||
components: ['networkAgent', 'polkitAgent', 'telepathyClient',
|
|
||||||
'keyring', 'recorder', 'autorunManager', 'automountManager'],
|
|
||||||
panel: {
|
|
||||||
left: ['activities', 'appMenu'],
|
|
||||||
center: ['dateMenu'],
|
|
||||||
right: ['a11y', 'keyboard', 'volume', 'bluetooth',
|
|
||||||
'network', 'battery', 'userMenu']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function listModes() {
|
function listModes() {
|
||||||
let modes = Object.getOwnPropertyNames(_modes);
|
let modes = Object.getOwnPropertyNames(_modes);
|
||||||
for (let i = 0; i < modes.length; i++)
|
for (let i = 0; i < modes.length; i++)
|
||||||
if (_modes[modes[i]].isPrimary)
|
print(modes[i]);
|
||||||
print(modes[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const SessionMode = new Lang.Class({
|
const SessionMode = new Lang.Class({
|
||||||
Name: 'SessionMode',
|
Name: 'SessionMode',
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
global.connect('notify::session-mode', Lang.bind(this, this._sync));
|
let params = _modes[global.session_mode];
|
||||||
let mode = _modes[global.session_mode].isPrimary ? global.session_mode
|
|
||||||
: 'user';
|
|
||||||
this._modeStack = [mode];
|
|
||||||
this._sync();
|
|
||||||
},
|
|
||||||
|
|
||||||
pushMode: function(mode) {
|
|
||||||
this._modeStack.push(mode);
|
|
||||||
this._sync();
|
|
||||||
},
|
|
||||||
|
|
||||||
popMode: function(mode) {
|
|
||||||
if (this.currentMode != mode || this._modeStack.length === 1)
|
|
||||||
throw new Error("Invalid SessionMode.popMode");
|
|
||||||
this._modeStack.pop();
|
|
||||||
this._sync();
|
|
||||||
},
|
|
||||||
|
|
||||||
switchMode: function(to) {
|
|
||||||
if (this.currentMode == to)
|
|
||||||
return;
|
|
||||||
this._modeStack[this._modeStack.length - 1] = to;
|
|
||||||
this._sync();
|
|
||||||
},
|
|
||||||
|
|
||||||
get currentMode() {
|
|
||||||
return this._modeStack[this._modeStack.length - 1];
|
|
||||||
},
|
|
||||||
|
|
||||||
_sync: function() {
|
|
||||||
let params = _modes[this.currentMode];
|
|
||||||
params = Params.parse(params, _modes[DEFAULT_MODE]);
|
params = Params.parse(params, _modes[DEFAULT_MODE]);
|
||||||
|
|
||||||
// A simplified version of Lang.copyProperties, handles
|
this._createSession = params.createSession;
|
||||||
// undefined as a special case for "no change / inherit from previous mode"
|
delete params.createSession;
|
||||||
for (let prop in params) {
|
this._createUnlockDialog = params.createUnlockDialog;
|
||||||
if (params[prop] !== undefined)
|
delete params.createUnlockDialog;
|
||||||
this[prop] = params[prop];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emit('updated');
|
Lang.copyProperties(params, this);
|
||||||
}
|
},
|
||||||
|
|
||||||
|
createSession: function() {
|
||||||
|
if (this._createSession)
|
||||||
|
this._createSession();
|
||||||
|
},
|
||||||
|
|
||||||
|
createUnlockDialog: function() {
|
||||||
|
if (this._createUnlockDialog)
|
||||||
|
return this._createUnlockDialog.apply(this, arguments);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(SessionMode.prototype);
|
|
||||||
|
@ -57,26 +57,21 @@ const ScreenSaverIface = <interface name="org.gnome.ScreenSaver">
|
|||||||
<arg name="active" direction="out" type="b" />
|
<arg name="active" direction="out" type="b" />
|
||||||
</method>
|
</method>
|
||||||
<method name="SetActive">
|
<method name="SetActive">
|
||||||
<arg name="value" direction="in" type="b" />
|
<arg name="value" direction="in" type="u" />
|
||||||
</method>
|
|
||||||
<method name="GetActiveTime">
|
|
||||||
<arg name="value" direction="out" type="u" />
|
|
||||||
</method>
|
</method>
|
||||||
<signal name="ActiveChanged">
|
<signal name="ActiveChanged">
|
||||||
<arg name="new_value" type="b" />
|
<arg name="new_value" type="b" />
|
||||||
</signal>
|
</signal>
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
const GnomeShell = new Gio.DBusImplementerClass({
|
const GnomeShell = new Lang.Class({
|
||||||
Name: 'GnomeShellDBus',
|
Name: 'GnomeShellDBus',
|
||||||
Interface: GnomeShellIface,
|
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent();
|
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellIface, this);
|
||||||
|
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
|
||||||
|
|
||||||
this.export(Gio.DBus.session, '/org/gnome/Shell');
|
this._extensionsSerivce = new GnomeShellExtensions();
|
||||||
|
|
||||||
this._extensionsService = new GnomeShellExtensions();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -238,14 +233,12 @@ const GnomeShellExtensionsIface = <interface name="org.gnome.Shell.Extensions">
|
|||||||
<property name="ShellVersion" type="s" access="read" />
|
<property name="ShellVersion" type="s" access="read" />
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
const GnomeShellExtensions = new Gio.DBusImplementerClass({
|
const GnomeShellExtensions = new Lang.Class({
|
||||||
Name: 'GnomeShellExtensionsDBus',
|
Name: 'GnomeShellExtensionsDBus',
|
||||||
Interface: GnomeShellExtensionsIface,
|
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent();
|
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellExtensionsIface, this);
|
||||||
|
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
|
||||||
this.export(Gio.DBus.session, '/org/gnome/Shell');
|
|
||||||
ExtensionSystem.connect('extension-state-changed',
|
ExtensionSystem.connect('extension-state-changed',
|
||||||
Lang.bind(this, this._extensionStateChanged));
|
Lang.bind(this, this._extensionStateChanged));
|
||||||
},
|
},
|
||||||
@ -325,11 +318,8 @@ const GnomeShellExtensions = new Gio.DBusImplementerClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
ReloadExtension: function(uuid) {
|
ReloadExtension: function(uuid) {
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
ExtensionSystem.unloadExtension(uuid);
|
||||||
if (!extension)
|
ExtensionSystem.loadExtension(uuid);
|
||||||
return;
|
|
||||||
|
|
||||||
ExtensionSystem.reloadExtension(extension);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
CheckForUpdates: function() {
|
CheckForUpdates: function() {
|
||||||
@ -339,52 +329,37 @@ const GnomeShellExtensions = new Gio.DBusImplementerClass({
|
|||||||
ShellVersion: Config.PACKAGE_VERSION,
|
ShellVersion: Config.PACKAGE_VERSION,
|
||||||
|
|
||||||
_extensionStateChanged: function(_, newState) {
|
_extensionStateChanged: function(_, newState) {
|
||||||
this.emit_signal('ExtensionStatusChanged', newState.uuid, newState.state, newState.error);
|
this._dbusImpl.emit_signal('ExtensionStatusChanged',
|
||||||
|
GLib.Variant.new('(sis)', [newState.uuid, newState.state, newState.error]));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const ScreenSaverDBus = new Gio.DBusImplementerClass({
|
const ScreenSaverDBus = new Lang.Class({
|
||||||
Name: 'ScreenSaverDBus',
|
Name: 'ScreenSaverDBus',
|
||||||
Interface: ScreenSaverIface,
|
|
||||||
|
|
||||||
_init: function(screenShield) {
|
_init: function() {
|
||||||
this.parent();
|
this.parent();
|
||||||
|
|
||||||
this._screenShield = screenShield;
|
Main.screenShield.connect('lock-status-changed', Lang.bind(this, function(shield, locked) {
|
||||||
screenShield.connect('lock-status-changed', Lang.bind(this, function(shield) {
|
this._dbusImpl.emit_signal('ActiveChanged', GLib.Variant.new('(b)', [locked]));
|
||||||
this.emit_signal('ActiveChanged', shield.locked);
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.export(Gio.DBus.session, '/org/gnome/ScreenSaver');
|
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreenSaverIface, this);
|
||||||
Gio.DBus.session.own_name('org.gnome.ScreenSaver', Gio.BusNameOwnerFlags.REPLACE, null, null);
|
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/ScreenSaver');
|
||||||
},
|
},
|
||||||
|
|
||||||
LockAsync: function(parameters, invocation) {
|
Lock: function() {
|
||||||
let tmpId = this._screenShield.connect('lock-screen-shown', Lang.bind(this, function() {
|
Main.screenShield.lock(true);
|
||||||
this._screenShield.disconnect(tmpId);
|
|
||||||
|
|
||||||
invocation.return_value(null);
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._screenShield.lock(true);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
SetActive: function(active) {
|
SetActive: function(active) {
|
||||||
if (active)
|
if (active)
|
||||||
this._screenShield.lock(true);
|
Main.screenShield.lock(true);
|
||||||
else
|
else
|
||||||
this._screenShield.unlock();
|
Main.screenShield.unlock();
|
||||||
},
|
},
|
||||||
|
|
||||||
GetActive: function() {
|
GetActive: function() {
|
||||||
return this._screenShield.locked;
|
return Main.screenShield.locked;
|
||||||
},
|
}
|
||||||
|
|
||||||
GetActiveTime: function() {
|
|
||||||
let started = this._screenShield.activationTime;
|
|
||||||
if (started > 0)
|
|
||||||
return Math.floor((GLib.get_monotonic_time() - started) / 1000000);
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
@ -76,12 +76,6 @@ const EntryMenu = new Lang.Class({
|
|||||||
this.actor.grab_key_focus();
|
this.actor.grab_key_focus();
|
||||||
|
|
||||||
this.parent();
|
this.parent();
|
||||||
this._entry.add_style_pseudo_class('focus');
|
|
||||||
},
|
|
||||||
|
|
||||||
close: function() {
|
|
||||||
this._entry.grab_key_focus();
|
|
||||||
this.parent();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateCopyItem: function() {
|
_updateCopyItem: function() {
|
||||||
@ -132,20 +126,34 @@ function _setMenuAlignment(entry, stageX) {
|
|||||||
entry.menu.setSourceAlignment(entryX / entry.width);
|
entry.menu.setSourceAlignment(entryX / entry.width);
|
||||||
};
|
};
|
||||||
|
|
||||||
function _onButtonPressEvent(actor, event, entry) {
|
function _onClicked(action, actor) {
|
||||||
|
let entry = actor.menu ? actor : actor.get_parent();
|
||||||
|
|
||||||
if (entry.menu.isOpen) {
|
if (entry.menu.isOpen) {
|
||||||
entry.menu.close();
|
entry.menu.close();
|
||||||
return true;
|
} else if (action.get_button() == 3) {
|
||||||
} else if (event.get_button() == 3) {
|
let [stageX, stageY] = action.get_coords();
|
||||||
let [stageX, stageY] = event.get_coords();
|
_setMenuAlignment(entry, stageX);
|
||||||
|
entry.menu.open();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function _onLongPress(action, actor, state) {
|
||||||
|
let entry = actor.menu ? actor : actor.get_parent();
|
||||||
|
|
||||||
|
if (state == Clutter.LongPressState.QUERY)
|
||||||
|
return action.get_button() == 1 && !entry.menu.isOpen;
|
||||||
|
|
||||||
|
if (state == Clutter.LongPressState.ACTIVATE) {
|
||||||
|
let [stageX, stageY] = action.get_coords();
|
||||||
_setMenuAlignment(entry, stageX);
|
_setMenuAlignment(entry, stageX);
|
||||||
entry.menu.open();
|
entry.menu.open();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
function _onPopup(actor, entry) {
|
function _onPopup(actor) {
|
||||||
|
let entry = actor.menu ? actor : actor.get_parent();
|
||||||
let [success, textX, textY, lineHeight] = entry.clutter_text.position_to_coords(-1);
|
let [success, textX, textY, lineHeight] = entry.clutter_text.position_to_coords(-1);
|
||||||
if (success)
|
if (success)
|
||||||
entry.menu.setSourceAlignment(textX / entry.width);
|
entry.menu.setSourceAlignment(textX / entry.width);
|
||||||
@ -160,11 +168,20 @@ function addContextMenu(entry, params) {
|
|||||||
entry._menuManager = new PopupMenu.PopupMenuManager({ actor: entry });
|
entry._menuManager = new PopupMenu.PopupMenuManager({ actor: entry });
|
||||||
entry._menuManager.addMenu(entry.menu);
|
entry._menuManager.addMenu(entry.menu);
|
||||||
|
|
||||||
// Add an event handler to both the entry and its clutter_text; the former
|
let clickAction;
|
||||||
|
|
||||||
|
// Add a click action to both the entry and its clutter_text; the former
|
||||||
// so padding is included in the clickable area, the latter because the
|
// so padding is included in the clickable area, the latter because the
|
||||||
// event processing of ClutterText prevents event-bubbling.
|
// event processing of ClutterText prevents event-bubbling.
|
||||||
entry.clutter_text.connect('button-press-event', Lang.bind(null, _onButtonPressEvent, entry));
|
clickAction = new Clutter.ClickAction();
|
||||||
entry.connect('button-press-event', Lang.bind(null, _onButtonPressEvent, entry));
|
clickAction.connect('clicked', _onClicked);
|
||||||
|
clickAction.connect('long-press', _onLongPress);
|
||||||
|
entry.clutter_text.add_action(clickAction);
|
||||||
|
|
||||||
entry.connect('popup-menu', Lang.bind(null, _onPopup, entry));
|
clickAction = new Clutter.ClickAction();
|
||||||
|
clickAction.connect('clicked', _onClicked);
|
||||||
|
clickAction.connect('long-press', _onLongPress);
|
||||||
|
entry.add_action(clickAction);
|
||||||
|
|
||||||
|
entry.connect('popup-menu', _onPopup);
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,7 @@ const ShellUnmountNotifier = new Lang.Class({
|
|||||||
Extends: MessageTray.Source,
|
Extends: MessageTray.Source,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('', 'media-removable');
|
this.parent('', 'media-removable', St.IconType.FULLCOLOR);
|
||||||
|
|
||||||
this._notification = null;
|
this._notification = null;
|
||||||
Main.messageTray.add(this);
|
Main.messageTray.add(this);
|
||||||
@ -361,12 +361,12 @@ const ShellMountPasswordDialog = new Lang.Class({
|
|||||||
if (strings[1])
|
if (strings[1])
|
||||||
description.set_text(strings[1]);
|
description.set_text(strings[1]);
|
||||||
|
|
||||||
this._passwordBox = new St.BoxLayout({ vertical: false, style_class: 'prompt-dialog-password-box' });
|
this._passwordBox = new St.BoxLayout({ vertical: false });
|
||||||
this._messageBox.add(this._passwordBox);
|
this._messageBox.add(this._passwordBox);
|
||||||
|
|
||||||
this._passwordLabel = new St.Label(({ style_class: 'prompt-dialog-password-label',
|
this._passwordLabel = new St.Label(({ style_class: 'prompt-dialog-password-label',
|
||||||
text: _("Password") }));
|
text: _("Passphrase") }));
|
||||||
this._passwordBox.add(this._passwordLabel, { y_fill: false, y_align: St.Align.MIDDLE });
|
this._passwordBox.add(this._passwordLabel);
|
||||||
|
|
||||||
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||||||
text: "",
|
text: "",
|
||||||
@ -386,7 +386,7 @@ const ShellMountPasswordDialog = new Lang.Class({
|
|||||||
|
|
||||||
if (flags & Gio.AskPasswordFlags.SAVING_SUPPORTED) {
|
if (flags & Gio.AskPasswordFlags.SAVING_SUPPORTED) {
|
||||||
this._rememberChoice = new CheckBox.CheckBox();
|
this._rememberChoice = new CheckBox.CheckBox();
|
||||||
this._rememberChoice.getLabelActor().text = _("Remember Password");
|
this._rememberChoice.getLabelActor().text = _("Remember Passphrase");
|
||||||
this._rememberChoice.actor.checked = true;
|
this._rememberChoice.actor.checked = true;
|
||||||
this._messageBox.add(this._rememberChoice.actor);
|
this._messageBox.add(this._rememberChoice.actor);
|
||||||
} else {
|
} else {
|
||||||
@ -554,16 +554,14 @@ const ShellMountOperationType = {
|
|||||||
SHOW_PROCESSES: 3
|
SHOW_PROCESSES: 3
|
||||||
};
|
};
|
||||||
|
|
||||||
const GnomeShellMountOpHandler = new Gio.DBusImplementerClass({
|
const GnomeShellMountOpHandler = new Lang.Class({
|
||||||
Name: 'GnomeShellMountOpHandler',
|
Name: 'GnomeShellMountOpHandler',
|
||||||
Interface: GnomeShellMountOpIface,
|
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent();
|
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellMountOpIface, this);
|
||||||
|
this._dbusImpl.export(Gio.DBus.session, '/org/gtk/MountOperationHandler');
|
||||||
this.export(Gio.DBus.session, '/org/gtk/MountOperationHandler');
|
Gio.bus_own_name_on_connection(Gio.DBus.session, 'org.gtk.MountOperationHandler',
|
||||||
Gio.DBus.session.own_name('org.gtk.MountOperationHandler',
|
Gio.BusNameOwnerFlags.REPLACE, null, null);
|
||||||
Gio.BusNameOwnerFlags.REPLACE, null, null);
|
|
||||||
|
|
||||||
this._dialog = null;
|
this._dialog = null;
|
||||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||||
|
@ -36,7 +36,7 @@ const ATIndicator = new Lang.Class({
|
|||||||
Extends: PanelMenu.SystemStatusButton,
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('preferences-desktop-accessibility-symbolic', _("Accessibility"));
|
this.parent('preferences-desktop-accessibility', _("Accessibility"));
|
||||||
|
|
||||||
let highContrast = this._buildHCItem();
|
let highContrast = this._buildHCItem();
|
||||||
this.menu.addMenuItem(highContrast);
|
this.menu.addMenuItem(highContrast);
|
||||||
@ -75,6 +75,10 @@ const ATIndicator = new Lang.Class({
|
|||||||
this.menu.addSettingsAction(_("Universal Access Settings"), 'gnome-universal-access-panel.desktop');
|
this.menu.addSettingsAction(_("Universal Access Settings"), 'gnome-universal-access-panel.desktop');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setLockedState: function(locked) {
|
||||||
|
this.menu.setSettingsVisibility(!locked);
|
||||||
|
},
|
||||||
|
|
||||||
_buildItemExtended: function(string, initial_value, writable, on_set) {
|
_buildItemExtended: function(string, initial_value, writable, on_set) {
|
||||||
let widget = new PopupMenu.PopupSwitchMenuItem(string, initial_value);
|
let widget = new PopupMenu.PopupSwitchMenuItem(string, initial_value);
|
||||||
if (!writable)
|
if (!writable)
|
||||||
|
@ -24,7 +24,7 @@ const Indicator = new Lang.Class({
|
|||||||
Extends: PanelMenu.SystemStatusButton,
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('bluetooth-disabled-symbolic', _("Bluetooth"));
|
this.parent('bluetooth-disabled', _("Bluetooth"));
|
||||||
|
|
||||||
this._applet = new GnomeBluetoothApplet.Applet();
|
this._applet = new GnomeBluetoothApplet.Applet();
|
||||||
|
|
||||||
@ -88,6 +88,11 @@ const Indicator = new Lang.Class({
|
|||||||
this._applet.connect('cancel-request', Lang.bind(this, this._cancelRequest));
|
this._applet.connect('cancel-request', Lang.bind(this, this._cancelRequest));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setLockedState: function(locked) {
|
||||||
|
this._isLocked = locked;
|
||||||
|
this._updateKillswitch();
|
||||||
|
},
|
||||||
|
|
||||||
_updateKillswitch: function() {
|
_updateKillswitch: function() {
|
||||||
let current_state = this._applet.killswitch_state;
|
let current_state = this._applet.killswitch_state;
|
||||||
let on = current_state == GnomeBluetooth.KillswitchState.UNBLOCKED;
|
let on = current_state == GnomeBluetooth.KillswitchState.UNBLOCKED;
|
||||||
@ -102,14 +107,14 @@ const Indicator = new Lang.Class({
|
|||||||
/* TRANSLATORS: this means that bluetooth was disabled by hardware rfkill */
|
/* TRANSLATORS: this means that bluetooth was disabled by hardware rfkill */
|
||||||
this._killswitch.setStatus(_("hardware disabled"));
|
this._killswitch.setStatus(_("hardware disabled"));
|
||||||
|
|
||||||
this.actor.visible = has_adapter;
|
this.actor.visible = !this._isLocked && has_adapter;
|
||||||
|
|
||||||
if (on) {
|
if (on) {
|
||||||
this._discoverable.actor.show();
|
this._discoverable.actor.show();
|
||||||
this.setIcon('bluetooth-active-symbolic');
|
this.setIcon('bluetooth-active');
|
||||||
} else {
|
} else {
|
||||||
this._discoverable.actor.hide();
|
this._discoverable.actor.hide();
|
||||||
this.setIcon('bluetooth-disabled-symbolic');
|
this.setIcon('bluetooth-disabled');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -301,7 +306,7 @@ const Indicator = new Lang.Class({
|
|||||||
|
|
||||||
_ensureSource: function() {
|
_ensureSource: function() {
|
||||||
if (!this._source) {
|
if (!this._source) {
|
||||||
this._source = new MessageTray.Source(_("Bluetooth"), 'bluetooth-active');
|
this._source = new MessageTray.Source(_("Bluetooth"), 'bluetooth-active', St.IconType.SYMBOLIC);
|
||||||
Main.messageTray.add(this._source);
|
Main.messageTray.add(this._source);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -456,10 +461,7 @@ const PinNotification = new Lang.Class({
|
|||||||
|
|
||||||
_canActivateOkButton: function() {
|
_canActivateOkButton: function() {
|
||||||
// PINs have a fixed length of 6
|
// PINs have a fixed length of 6
|
||||||
if (this._numeric)
|
return this._entry.clutter_text.text.length == 6;
|
||||||
return this._entry.clutter_text.text.length == 6;
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
grabFocus: function(lockTray) {
|
grabFocus: function(lockTray) {
|
||||||
|
@ -5,7 +5,6 @@ const GLib = imports.gi.GLib;
|
|||||||
const GnomeDesktop = imports.gi.GnomeDesktop;
|
const GnomeDesktop = imports.gi.GnomeDesktop;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -46,7 +45,6 @@ const IBusManager = new Lang.Class({
|
|||||||
this._panelService = null;
|
this._panelService = null;
|
||||||
this._engines = {};
|
this._engines = {};
|
||||||
this._ready = false;
|
this._ready = false;
|
||||||
this._registerPropertiesId = 0;
|
|
||||||
|
|
||||||
this._nameWatcherId = Gio.DBus.session.watch_name(IBus.SERVICE_IBUS,
|
this._nameWatcherId = Gio.DBus.session.watch_name(IBus.SERVICE_IBUS,
|
||||||
Gio.BusNameWatcherFlags.NONE,
|
Gio.BusNameWatcherFlags.NONE,
|
||||||
@ -65,7 +63,6 @@ const IBusManager = new Lang.Class({
|
|||||||
this._candidatePopup.setPanelService(null);
|
this._candidatePopup.setPanelService(null);
|
||||||
this._engines = {};
|
this._engines = {};
|
||||||
this._ready = false;
|
this._ready = false;
|
||||||
this._registerPropertiesId = 0;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onNameAppeared: function() {
|
_onNameAppeared: function() {
|
||||||
@ -103,11 +100,6 @@ const IBusManager = new Lang.Class({
|
|||||||
this._panelService = new IBus.PanelService({ connection: this._ibus.get_connection(),
|
this._panelService = new IBus.PanelService({ connection: this._ibus.get_connection(),
|
||||||
object_path: IBus.PATH_PANEL });
|
object_path: IBus.PATH_PANEL });
|
||||||
this._candidatePopup.setPanelService(this._panelService);
|
this._candidatePopup.setPanelService(this._panelService);
|
||||||
// Need to set this to get 'global-engine-changed' emitions
|
|
||||||
this._ibus.set_watch_ibus_signal(true);
|
|
||||||
this._ibus.connect('global-engine-changed', Lang.bind(this, this._resetProperties));
|
|
||||||
this._panelService.connect('update-property', Lang.bind(this, this._updateProperty));
|
|
||||||
this._resetProperties();
|
|
||||||
} else {
|
} else {
|
||||||
this._clear();
|
this._clear();
|
||||||
return;
|
return;
|
||||||
@ -124,39 +116,6 @@ const IBusManager = new Lang.Class({
|
|||||||
this._readyCallback();
|
this._readyCallback();
|
||||||
},
|
},
|
||||||
|
|
||||||
_resetProperties: function() {
|
|
||||||
this.emit('properties-registered', null);
|
|
||||||
|
|
||||||
if (this._registerPropertiesId != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._registerPropertiesId =
|
|
||||||
this._panelService.connect('register-properties', Lang.bind(this, function(p, props) {
|
|
||||||
if (!props.get(0))
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._panelService.disconnect(this._registerPropertiesId);
|
|
||||||
this._registerPropertiesId = 0;
|
|
||||||
|
|
||||||
this.emit('properties-registered', props);
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateProperty: function(panel, prop) {
|
|
||||||
this.emit('property-updated', prop);
|
|
||||||
},
|
|
||||||
|
|
||||||
activateProperty: function(key, state) {
|
|
||||||
this._panelService.property_activate(key, state);
|
|
||||||
},
|
|
||||||
|
|
||||||
hasProperties: function(id) {
|
|
||||||
if (id == 'anthy')
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
getEngineDesc: function(id) {
|
getEngineDesc: function(id) {
|
||||||
if (!IBus || !this._ready)
|
if (!IBus || !this._ready)
|
||||||
return null;
|
return null;
|
||||||
@ -164,7 +123,6 @@ const IBusManager = new Lang.Class({
|
|||||||
return this._engines[id];
|
return this._engines[id];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(IBusManager.prototype);
|
|
||||||
|
|
||||||
const LayoutMenuItem = new Lang.Class({
|
const LayoutMenuItem = new Lang.Class({
|
||||||
Name: 'LayoutMenuItem',
|
Name: 'LayoutMenuItem',
|
||||||
@ -177,7 +135,6 @@ const LayoutMenuItem = new Lang.Class({
|
|||||||
this.indicator = new St.Label({ text: shortName });
|
this.indicator = new St.Label({ text: shortName });
|
||||||
this.addActor(this.label);
|
this.addActor(this.label);
|
||||||
this.addActor(this.indicator);
|
this.addActor(this.indicator);
|
||||||
this.actor.label_actor = this.label;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -185,12 +142,6 @@ const InputSourceIndicator = new Lang.Class({
|
|||||||
Name: 'InputSourceIndicator',
|
Name: 'InputSourceIndicator',
|
||||||
Extends: PanelMenu.Button,
|
Extends: PanelMenu.Button,
|
||||||
|
|
||||||
_propertiesWhitelist: [
|
|
||||||
'InputMode',
|
|
||||||
'TypingMode',
|
|
||||||
'DictMode'
|
|
||||||
],
|
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent(0.0, _("Keyboard"));
|
this.parent(0.0, _("Keyboard"));
|
||||||
|
|
||||||
@ -211,73 +162,54 @@ const InputSourceIndicator = new Lang.Class({
|
|||||||
this._currentSourceIndex = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE);
|
this._currentSourceIndex = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE);
|
||||||
this._xkbInfo = new GnomeDesktop.XkbInfo();
|
this._xkbInfo = new GnomeDesktop.XkbInfo();
|
||||||
|
|
||||||
this._propSeparator = new PopupMenu.PopupSeparatorMenuItem();
|
|
||||||
this.menu.addMenuItem(this._propSeparator);
|
|
||||||
this._propSection = new PopupMenu.PopupMenuSection();
|
|
||||||
this.menu.addMenuItem(this._propSection);
|
|
||||||
this._propSection.actor.hide();
|
|
||||||
|
|
||||||
this._properties = null;
|
|
||||||
|
|
||||||
this._ibusManager = new IBusManager(Lang.bind(this, this._inputSourcesChanged));
|
this._ibusManager = new IBusManager(Lang.bind(this, this._inputSourcesChanged));
|
||||||
this._ibusManager.connect('properties-registered', Lang.bind(this, this._ibusPropertiesRegistered));
|
|
||||||
this._ibusManager.connect('property-updated', Lang.bind(this, this._ibusPropertyUpdated));
|
|
||||||
this._inputSourcesChanged();
|
this._inputSourcesChanged();
|
||||||
|
|
||||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
||||||
this._showLayoutItem = this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, this._showLayout));
|
|
||||||
|
|
||||||
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
|
||||||
this._sessionUpdated();
|
|
||||||
|
|
||||||
this.menu.addSettingsAction(_("Region and Language Settings"), 'gnome-region-panel.desktop');
|
|
||||||
},
|
|
||||||
|
|
||||||
_sessionUpdated: function() {
|
|
||||||
// re-using "allowSettings" for the keyboard layout is a bit shady,
|
// re-using "allowSettings" for the keyboard layout is a bit shady,
|
||||||
// but at least for now it is used as "allow popping up windows
|
// but at least for now it is used as "allow popping up windows
|
||||||
// from shell menus"; we can always add a separate sessionMode
|
// from shell menus"; we can always add a separate sessionMode
|
||||||
// option if need arises.
|
// option if need arises.
|
||||||
this._showLayoutItem.actor.visible = Main.sessionMode.allowSettings;
|
if (Main.sessionMode.allowSettings) {
|
||||||
|
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||||
|
this._showLayoutItem = this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, this._showLayout));
|
||||||
|
}
|
||||||
|
this.menu.addSettingsAction(_("Region and Language Settings"), 'gnome-region-panel.desktop');
|
||||||
|
},
|
||||||
|
|
||||||
|
setLockedState: function(locked) {
|
||||||
|
this._showLayoutItem.actor.visible = !locked;
|
||||||
|
this.menu.setSettingsVisibility(!locked);
|
||||||
},
|
},
|
||||||
|
|
||||||
_currentInputSourceChanged: function() {
|
_currentInputSourceChanged: function() {
|
||||||
let nVisibleSources = Object.keys(this._layoutItems).length;
|
let nVisibleSources = Object.keys(this._layoutItems).length;
|
||||||
|
if (nVisibleSources < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let nSources = this._settings.get_value(KEY_INPUT_SOURCES).n_children();
|
||||||
let newCurrentSourceIndex = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE);
|
let newCurrentSourceIndex = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE);
|
||||||
let newLayoutItem = this._layoutItems[newCurrentSourceIndex];
|
if (newCurrentSourceIndex >= nSources)
|
||||||
let hasProperties;
|
return;
|
||||||
|
|
||||||
if (newLayoutItem)
|
if (!this._layoutItems[newCurrentSourceIndex]) {
|
||||||
hasProperties = this._ibusManager.hasProperties(newLayoutItem.ibusEngineId);
|
// This source index is invalid as we weren't able to
|
||||||
else
|
// build a menu item for it, so we hide ourselves since we
|
||||||
hasProperties = false;
|
// can't fix it here. *shrug*
|
||||||
|
|
||||||
if (!newLayoutItem || (nVisibleSources < 2 && !hasProperties)) {
|
|
||||||
// This source index might be invalid if we weren't able
|
|
||||||
// to build a menu item for it, so we hide ourselves since
|
|
||||||
// we can't fix it here. *shrug*
|
|
||||||
|
|
||||||
// We also hide if we have only one visible source unless
|
|
||||||
// it's an IBus source with properties.
|
|
||||||
this.menu.close();
|
this.menu.close();
|
||||||
this.actor.hide();
|
this.actor.hide();
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
this.actor.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.actor.show();
|
|
||||||
|
|
||||||
if (this._layoutItems[this._currentSourceIndex]) {
|
if (this._layoutItems[this._currentSourceIndex]) {
|
||||||
this._layoutItems[this._currentSourceIndex].setShowDot(false);
|
this._layoutItems[this._currentSourceIndex].setShowDot(false);
|
||||||
this._container.set_skip_paint(this._labelActors[this._currentSourceIndex], true);
|
this._container.set_skip_paint(this._labelActors[this._currentSourceIndex], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
newLayoutItem.setShowDot(true);
|
this._layoutItems[newCurrentSourceIndex].setShowDot(true);
|
||||||
|
this._container.set_skip_paint(this._labelActors[newCurrentSourceIndex], false);
|
||||||
let newLabelActor = this._labelActors[newCurrentSourceIndex];
|
|
||||||
this._container.set_skip_paint(newLabelActor, false);
|
|
||||||
|
|
||||||
if (hasProperties)
|
|
||||||
newLabelActor.set_text(newLayoutItem.indicator.get_text());
|
|
||||||
|
|
||||||
this._currentSourceIndex = newCurrentSourceIndex;
|
this._currentSourceIndex = newCurrentSourceIndex;
|
||||||
},
|
},
|
||||||
@ -308,12 +240,9 @@ const InputSourceIndicator = new Lang.Class({
|
|||||||
} else if (type == INPUT_SOURCE_TYPE_IBUS) {
|
} else if (type == INPUT_SOURCE_TYPE_IBUS) {
|
||||||
let engineDesc = this._ibusManager.getEngineDesc(id);
|
let engineDesc = this._ibusManager.getEngineDesc(id);
|
||||||
if (engineDesc) {
|
if (engineDesc) {
|
||||||
let language = IBus.get_language_name(engineDesc.get_language());
|
|
||||||
|
|
||||||
info.exists = true;
|
info.exists = true;
|
||||||
info.displayName = language + ' (' + engineDesc.get_longname() + ')';
|
info.displayName = engineDesc.get_longname();
|
||||||
info.shortName = this._makeEngineShortName(engineDesc);
|
info.shortName = engineDesc.get_symbol();
|
||||||
info.ibusEngineId = id;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,6 +257,13 @@ const InputSourceIndicator = new Lang.Class({
|
|||||||
infos.push(info);
|
infos.push(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (infos.length > 1) {
|
||||||
|
this.actor.show();
|
||||||
|
} else {
|
||||||
|
this.menu.close();
|
||||||
|
this.actor.hide();
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < infos.length; i++) {
|
for (let i = 0; i < infos.length; i++) {
|
||||||
let info = infos[i];
|
let info = infos[i];
|
||||||
if (infosByShortName[info.shortName].length > 1) {
|
if (infosByShortName[info.shortName].length > 1) {
|
||||||
@ -336,7 +272,6 @@ const InputSourceIndicator = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
let item = new LayoutMenuItem(info.displayName, info.shortName);
|
let item = new LayoutMenuItem(info.displayName, info.shortName);
|
||||||
item.ibusEngineId = info.ibusEngineId;
|
|
||||||
this._layoutItems[info.sourceIndex] = item;
|
this._layoutItems[info.sourceIndex] = item;
|
||||||
this.menu.addMenuItem(item, i);
|
this.menu.addMenuItem(item, i);
|
||||||
item.connect('activate', Lang.bind(this, function() {
|
item.connect('activate', Lang.bind(this, function() {
|
||||||
@ -382,146 +317,6 @@ const InputSourceIndicator = new Lang.Class({
|
|||||||
Util.spawn(['gkbd-keyboard-display', '-l', description]);
|
Util.spawn(['gkbd-keyboard-display', '-l', description]);
|
||||||
},
|
},
|
||||||
|
|
||||||
_makeEngineShortName: function(engineDesc) {
|
|
||||||
let symbol = engineDesc.get_symbol();
|
|
||||||
if (symbol && symbol[0])
|
|
||||||
return symbol;
|
|
||||||
|
|
||||||
let langCode = engineDesc.get_language().split('_', 1)[0];
|
|
||||||
if (langCode.length == 2 || langCode.length == 3)
|
|
||||||
return langCode.toLowerCase();
|
|
||||||
|
|
||||||
return String.fromCharCode(0x2328); // keyboard glyph
|
|
||||||
},
|
|
||||||
|
|
||||||
_propertyWhitelisted: function(prop) {
|
|
||||||
for (let i = 0; i < this._propertiesWhitelist.length; ++i) {
|
|
||||||
let key = prop.get_key();
|
|
||||||
if (key.substr(0, this._propertiesWhitelist[i].length) == this._propertiesWhitelist[i])
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
_ibusPropertiesRegistered: function(im, props) {
|
|
||||||
this._properties = props;
|
|
||||||
this._buildPropSection();
|
|
||||||
},
|
|
||||||
|
|
||||||
_ibusPropertyUpdated: function(im, prop) {
|
|
||||||
if (!this._propertyWhitelisted(prop))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (this._updateSubProperty(this._properties, prop))
|
|
||||||
this._buildPropSection();
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateSubProperty: function(props, prop) {
|
|
||||||
if (!props)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
let p;
|
|
||||||
for (let i = 0; (p = props.get(i)) != null; ++i) {
|
|
||||||
if (p.get_key() == prop.get_key() && p.get_prop_type() == prop.get_prop_type()) {
|
|
||||||
p.update(prop);
|
|
||||||
return true;
|
|
||||||
} else if (p.get_prop_type() == IBus.PropType.MENU) {
|
|
||||||
if (this._updateSubProperty(p.get_sub_props(), prop))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateIndicatorLabel: function(text) {
|
|
||||||
let layoutItem = this._layoutItems[this._currentSourceIndex];
|
|
||||||
let hasProperties;
|
|
||||||
|
|
||||||
if (layoutItem)
|
|
||||||
hasProperties = this._ibusManager.hasProperties(layoutItem.ibusEngineId);
|
|
||||||
else
|
|
||||||
hasProperties = false;
|
|
||||||
|
|
||||||
if (hasProperties)
|
|
||||||
this._labelActors[this._currentSourceIndex].set_text(text);
|
|
||||||
},
|
|
||||||
|
|
||||||
_buildPropSection: function() {
|
|
||||||
this._propSeparator.actor.hide();
|
|
||||||
this._propSection.actor.hide();
|
|
||||||
this._propSection.removeAll();
|
|
||||||
|
|
||||||
this._buildPropSubMenu(this._propSection, this._properties);
|
|
||||||
|
|
||||||
if (!this._propSection.isEmpty()) {
|
|
||||||
this._propSection.actor.show();
|
|
||||||
this._propSeparator.actor.show();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_buildPropSubMenu: function(menu, props) {
|
|
||||||
if (!props)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let radioGroup = [];
|
|
||||||
let p;
|
|
||||||
for (let i = 0; (p = props.get(i)) != null; ++i) {
|
|
||||||
let prop = p;
|
|
||||||
|
|
||||||
if (!this._propertyWhitelisted(prop) ||
|
|
||||||
!prop.get_visible())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (prop.get_key() == 'InputMode') {
|
|
||||||
let text;
|
|
||||||
if (prop.get_symbol)
|
|
||||||
text = prop.get_symbol().get_text();
|
|
||||||
else
|
|
||||||
text = prop.get_label().get_text();
|
|
||||||
|
|
||||||
if (text && text.length > 0 && text.length < 3)
|
|
||||||
this._updateIndicatorLabel(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
let item;
|
|
||||||
let type = prop.get_prop_type();
|
|
||||||
if (type == IBus.PropType.MENU) {
|
|
||||||
item = new PopupMenu.PopupSubMenuMenuItem(prop.get_label().get_text());
|
|
||||||
this._buildPropSubMenu(item.menu, prop.get_sub_props());
|
|
||||||
} else if (type == IBus.PropType.RADIO) {
|
|
||||||
item = new PopupMenu.PopupMenuItem(prop.get_label().get_text());
|
|
||||||
item.prop = prop;
|
|
||||||
radioGroup.push(item);
|
|
||||||
item.radioGroup = radioGroup;
|
|
||||||
item.setShowDot(prop.get_state() == IBus.PropState.CHECKED);
|
|
||||||
item.connect('activate', Lang.bind(this, function() {
|
|
||||||
if (item.prop.get_state() == IBus.PropState.CHECKED)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let group = item.radioGroup;
|
|
||||||
for (let i = 0; i < group.length; ++i) {
|
|
||||||
if (group[i] == item) {
|
|
||||||
item.setShowDot(true);
|
|
||||||
item.prop.set_state(IBus.PropState.CHECKED);
|
|
||||||
this._ibusManager.activateProperty(item.prop.get_key(),
|
|
||||||
IBus.PropState.CHECKED);
|
|
||||||
} else {
|
|
||||||
group[i].setShowDot(false);
|
|
||||||
group[i].prop.set_state(IBus.PropState.UNCHECKED);
|
|
||||||
this._ibusManager.activateProperty(group[i].prop.get_key(),
|
|
||||||
IBus.PropState.UNCHECKED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
item.setSensitive(prop.get_sensitive());
|
|
||||||
menu.addMenuItem(item);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_containerGetPreferredWidth: function(container, for_height, alloc) {
|
_containerGetPreferredWidth: function(container, for_height, alloc) {
|
||||||
// Here, and in _containerGetPreferredHeight, we need to query
|
// Here, and in _containerGetPreferredHeight, we need to query
|
||||||
// for the height of all children, but we ignore the results
|
// for the height of all children, but we ignore the results
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
|
||||||
const GObject = imports.gi.GObject;
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const St = imports.gi.St;
|
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
|
||||||
const PanelMenu = imports.ui.panelMenu;
|
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
|
||||||
const VolumeMenu = imports.ui.status.volume;
|
|
||||||
|
|
||||||
const Indicator = new Lang.Class({
|
|
||||||
Name: 'LockScreenMenuIndicator',
|
|
||||||
Extends: PanelMenu.SystemStatusButton,
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this.parent(null, _("Volume, network, battery"));
|
|
||||||
|
|
||||||
this._volume = Main.panel.statusArea.volume;
|
|
||||||
if (this._volume) {
|
|
||||||
this._volumeIcon = this.addIcon(null);
|
|
||||||
this._volume.mainIcon.bind_property('gicon', this._volumeIcon, 'gicon',
|
|
||||||
GObject.BindingFlags.SYNC_CREATE);
|
|
||||||
this._volume.mainIcon.bind_property('visible', this._volumeIcon, 'visible',
|
|
||||||
GObject.BindingFlags.SYNC_CREATE);
|
|
||||||
|
|
||||||
this._volumeControl = VolumeMenu.getMixerControl();
|
|
||||||
this._volumeMenu = new VolumeMenu.VolumeMenu(this._volumeControl);
|
|
||||||
this.menu.addMenuItem(this._volumeMenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._network = Main.panel.statusArea.network;
|
|
||||||
if (this._network) {
|
|
||||||
this._networkIcon = this.addIcon(null);
|
|
||||||
this._network.mainIcon.bind_property('gicon', this._networkIcon, 'gicon',
|
|
||||||
GObject.BindingFlags.SYNC_CREATE);
|
|
||||||
this._network.mainIcon.bind_property('visible', this._networkIcon, 'visible',
|
|
||||||
GObject.BindingFlags.SYNC_CREATE);
|
|
||||||
|
|
||||||
this._networkSecondaryIcon = this.addIcon(null);
|
|
||||||
this._network.secondaryIcon.bind_property('gicon', this._networkSecondaryIcon, 'gicon',
|
|
||||||
GObject.BindingFlags.SYNC_CREATE);
|
|
||||||
this._network.secondaryIcon.bind_property('visible', this._networkSecondaryIcon, 'visible',
|
|
||||||
GObject.BindingFlags.SYNC_CREATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._battery = Main.panel.statusArea.battery;
|
|
||||||
if (this._battery) {
|
|
||||||
this._batteryIcon = this.addIcon(null);
|
|
||||||
this._battery.mainIcon.bind_property('gicon', this._batteryIcon, 'gicon',
|
|
||||||
GObject.BindingFlags.SYNC_CREATE);
|
|
||||||
this._battery.mainIcon.bind_property('visible', this._batteryIcon, 'visible',
|
|
||||||
GObject.BindingFlags.SYNC_CREATE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,6 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
@ -46,25 +45,16 @@ const PowerManagerInterface = <interface name="org.gnome.SettingsDaemon.Power">
|
|||||||
<property name="Icon" type="s" access="read" />
|
<property name="Icon" type="s" access="read" />
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
const PowerManagerProxy = new Gio.DBusProxyClass({
|
const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(PowerManagerInterface);
|
||||||
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({
|
const Indicator = new Lang.Class({
|
||||||
Name: 'PowerIndicator',
|
Name: 'PowerIndicator',
|
||||||
Extends: PanelMenu.SystemStatusButton,
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('battery-missing-symbolic', _("Battery"));
|
this.parent('battery-missing', _("Battery"));
|
||||||
|
|
||||||
this._proxy = new PowerManagerProxy();
|
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
|
||||||
|
|
||||||
this._deviceItems = [ ];
|
this._deviceItems = [ ];
|
||||||
this._hasPrimary = false;
|
this._hasPrimary = false;
|
||||||
@ -83,26 +73,24 @@ const Indicator = new Lang.Class({
|
|||||||
|
|
||||||
this._proxy.connect('g-properties-changed',
|
this._proxy.connect('g-properties-changed',
|
||||||
Lang.bind(this, this._devicesChanged));
|
Lang.bind(this, this._devicesChanged));
|
||||||
this._proxy.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(proxy, result) {
|
this._devicesChanged();
|
||||||
proxy.init_finish(result);
|
},
|
||||||
|
|
||||||
this._devicesChanged();
|
setLockedState: function(locked) {
|
||||||
}));
|
if (locked)
|
||||||
|
this.menu.close();
|
||||||
|
this.actor.reactive = !locked;
|
||||||
},
|
},
|
||||||
|
|
||||||
_readPrimaryDevice: function() {
|
_readPrimaryDevice: function() {
|
||||||
this._proxy.GetPrimaryDeviceRemote(null, Lang.bind(this, function(proxy, result) {
|
this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(result, error) {
|
||||||
let device_id, device_type, icon, percentage, state, seconds;
|
if (error) {
|
||||||
try {
|
|
||||||
[[device_id, device_type, icon, percentage, state, seconds]] =
|
|
||||||
proxy.GetPrimaryDeviceFinish(result);
|
|
||||||
} catch(e) {
|
|
||||||
this._hasPrimary = false;
|
this._hasPrimary = false;
|
||||||
this._primaryDeviceId = null;
|
this._primaryDeviceId = null;
|
||||||
this._batteryItem.actor.hide();
|
this._batteryItem.actor.hide();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let [[device_id, device_type, icon, percentage, state, seconds]] = result;
|
||||||
if (device_type == UPDeviceType.BATTERY) {
|
if (device_type == UPDeviceType.BATTERY) {
|
||||||
this._hasPrimary = true;
|
this._hasPrimary = true;
|
||||||
let time = Math.round(seconds / 60);
|
let time = Math.round(seconds / 60);
|
||||||
@ -139,18 +127,16 @@ const Indicator = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_readOtherDevices: function() {
|
_readOtherDevices: function() {
|
||||||
this._proxy.GetDevicesRemote(null, Lang.bind(this, function(proxy, result) {
|
this._proxy.GetDevicesRemote(Lang.bind(this, function(result, error) {
|
||||||
this._deviceItems.forEach(function(i) { i.destroy(); });
|
this._deviceItems.forEach(function(i) { i.destroy(); });
|
||||||
this._deviceItems = [];
|
this._deviceItems = [];
|
||||||
|
|
||||||
let devices;
|
if (error) {
|
||||||
try {
|
|
||||||
[devices] = proxy.GetDevicesFinish(result);
|
|
||||||
} catch(e) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let position = 0;
|
let position = 0;
|
||||||
|
let [devices] = result;
|
||||||
for (let i = 0; i < devices.length; i++) {
|
for (let i = 0; i < devices.length; i++) {
|
||||||
let [device_id, device_type] = devices[i];
|
let [device_id, device_type] = devices[i];
|
||||||
if (device_type == UPDeviceType.AC_POWER || device_id == this._primaryDeviceId)
|
if (device_type == UPDeviceType.AC_POWER || device_id == this._primaryDeviceId)
|
||||||
@ -164,21 +150,16 @@ const Indicator = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_syncIcon: function() {
|
_devicesChanged: function() {
|
||||||
let icon = this._proxy.Icon;
|
let icon = this._proxy.Icon;
|
||||||
let hasIcon = false;
|
|
||||||
|
|
||||||
if (icon) {
|
if (icon) {
|
||||||
let gicon = Gio.icon_new_for_string(icon);
|
let gicon = Gio.icon_new_for_string(icon);
|
||||||
this.setGIcon(gicon);
|
this.setGIcon(gicon);
|
||||||
hasIcon = true;
|
this.actor.show();
|
||||||
|
} else {
|
||||||
|
this.menu.close();
|
||||||
|
this.actor.hide();
|
||||||
}
|
}
|
||||||
this.mainIcon.visible = hasIcon;
|
|
||||||
this.actor.visible = hasIcon;
|
|
||||||
},
|
|
||||||
|
|
||||||
_devicesChanged: function() {
|
|
||||||
this._syncIcon();
|
|
||||||
this._readPrimaryDevice();
|
this._readPrimaryDevice();
|
||||||
this._readOtherDevices();
|
this._readOtherDevices();
|
||||||
}
|
}
|
||||||
@ -197,6 +178,7 @@ const DeviceItem = new Lang.Class({
|
|||||||
this._label = new St.Label({ text: this._deviceTypeToString(device_type) });
|
this._label = new St.Label({ text: this._deviceTypeToString(device_type) });
|
||||||
|
|
||||||
this._icon = new St.Icon({ gicon: Gio.icon_new_for_string(icon),
|
this._icon = new St.Icon({ gicon: Gio.icon_new_for_string(icon),
|
||||||
|
icon_type: St.IconType.SYMBOLIC,
|
||||||
style_class: 'popup-menu-icon' });
|
style_class: 'popup-menu-icon' });
|
||||||
|
|
||||||
this._box.add_actor(this._icon);
|
this._box.add_actor(this._icon);
|
||||||
@ -205,8 +187,6 @@ const DeviceItem = new Lang.Class({
|
|||||||
|
|
||||||
let percentLabel = new St.Label({ text: C_("percent of battery remaining", "%d%%").format(Math.round(percentage)) });
|
let percentLabel = new St.Label({ text: C_("percent of battery remaining", "%d%%").format(Math.round(percentage)) });
|
||||||
this.addActor(percentLabel, { align: St.Align.END });
|
this.addActor(percentLabel, { align: St.Align.END });
|
||||||
//FIXME: ideally we would like to expose this._label and percentLabel
|
|
||||||
this.actor.label_actor = percentLabel;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_deviceTypeToString: function(type) {
|
_deviceTypeToString: function(type) {
|
||||||
|
@ -12,27 +12,14 @@ const VOLUME_ADJUSTMENT_STEP = 0.05; /* Volume adjustment step in % */
|
|||||||
|
|
||||||
const VOLUME_NOTIFY_ID = 1;
|
const VOLUME_NOTIFY_ID = 1;
|
||||||
|
|
||||||
// Each Gvc.MixerControl is a connection to PulseAudio,
|
const Indicator = new Lang.Class({
|
||||||
// so it's better to make it a singleton
|
Name: 'VolumeIndicator',
|
||||||
let _mixerControl;
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
function getMixerControl() {
|
|
||||||
if (_mixerControl)
|
|
||||||
return _mixerControl;
|
|
||||||
|
|
||||||
_mixerControl = new Gvc.MixerControl({ name: 'GNOME Shell Volume Control' });
|
_init: function() {
|
||||||
_mixerControl.open();
|
this.parent('audio-volume-muted', _("Volume"));
|
||||||
|
|
||||||
return _mixerControl;
|
this._control = new Gvc.MixerControl({ name: 'GNOME Shell Volume Control' });
|
||||||
}
|
|
||||||
|
|
||||||
const VolumeMenu = new Lang.Class({
|
|
||||||
Name: 'VolumeMenu',
|
|
||||||
Extends: PopupMenu.PopupMenuSection,
|
|
||||||
|
|
||||||
_init: function(control) {
|
|
||||||
this.parent();
|
|
||||||
|
|
||||||
this._control = control;
|
|
||||||
this._control.connect('state-changed', Lang.bind(this, this._onControlStateChanged));
|
this._control.connect('state-changed', Lang.bind(this, this._onControlStateChanged));
|
||||||
this._control.connect('default-sink-changed', Lang.bind(this, this._readOutput));
|
this._control.connect('default-sink-changed', Lang.bind(this, this._readOutput));
|
||||||
this._control.connect('default-source-changed', Lang.bind(this, this._readInput));
|
this._control.connect('default-source-changed', Lang.bind(this, this._readInput));
|
||||||
@ -48,10 +35,10 @@ const VolumeMenu = new Lang.Class({
|
|||||||
this._outputSlider = new PopupMenu.PopupSliderMenuItem(0);
|
this._outputSlider = new PopupMenu.PopupSliderMenuItem(0);
|
||||||
this._outputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_output'));
|
this._outputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_output'));
|
||||||
this._outputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
|
this._outputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
|
||||||
this.addMenuItem(this._outputTitle);
|
this.menu.addMenuItem(this._outputTitle);
|
||||||
this.addMenuItem(this._outputSlider);
|
this.menu.addMenuItem(this._outputSlider);
|
||||||
|
|
||||||
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||||
|
|
||||||
this._input = null;
|
this._input = null;
|
||||||
this._inputVolumeId = 0;
|
this._inputVolumeId = 0;
|
||||||
@ -60,13 +47,22 @@ const VolumeMenu = new Lang.Class({
|
|||||||
this._inputSlider = new PopupMenu.PopupSliderMenuItem(0);
|
this._inputSlider = new PopupMenu.PopupSliderMenuItem(0);
|
||||||
this._inputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_input'));
|
this._inputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_input'));
|
||||||
this._inputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
|
this._inputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
|
||||||
this.addMenuItem(this._inputTitle);
|
this.menu.addMenuItem(this._inputTitle);
|
||||||
this.addMenuItem(this._inputSlider);
|
this.menu.addMenuItem(this._inputSlider);
|
||||||
|
|
||||||
this._onControlStateChanged();
|
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||||
|
this.menu.addSettingsAction(_("Sound Settings"), 'gnome-sound-panel.desktop');
|
||||||
|
|
||||||
|
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
||||||
|
this._control.open();
|
||||||
},
|
},
|
||||||
|
|
||||||
scroll: function(direction) {
|
setLockedState: function(locked) {
|
||||||
|
this.menu.setSettingsVisibility(!locked);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onScrollEvent: function(actor, event) {
|
||||||
|
let direction = event.get_scroll_direction();
|
||||||
let currentVolume = this._output.volume;
|
let currentVolume = this._output.volume;
|
||||||
|
|
||||||
if (direction == Clutter.ScrollDirection.DOWN) {
|
if (direction == Clutter.ScrollDirection.DOWN) {
|
||||||
@ -92,9 +88,9 @@ const VolumeMenu = new Lang.Class({
|
|||||||
if (this._control.get_state() == Gvc.MixerControlState.READY) {
|
if (this._control.get_state() == Gvc.MixerControlState.READY) {
|
||||||
this._readOutput();
|
this._readOutput();
|
||||||
this._readInput();
|
this._readInput();
|
||||||
this._maybeShowInput();
|
this.actor.show();
|
||||||
} else {
|
} else {
|
||||||
this.emit('icon-changed', null);
|
this.actor.hide();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -113,7 +109,7 @@ const VolumeMenu = new Lang.Class({
|
|||||||
this._volumeChanged (null, null, '_output');
|
this._volumeChanged (null, null, '_output');
|
||||||
} else {
|
} else {
|
||||||
this._outputSlider.setValue(0);
|
this._outputSlider.setValue(0);
|
||||||
this.emit('icon-changed', 'audio-volume-muted-symbolic');
|
this.setIcon('audio-volume-muted-symbolic');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -159,14 +155,14 @@ const VolumeMenu = new Lang.Class({
|
|||||||
|
|
||||||
_volumeToIcon: function(volume) {
|
_volumeToIcon: function(volume) {
|
||||||
if (volume <= 0) {
|
if (volume <= 0) {
|
||||||
return 'audio-volume-muted-symbolic';
|
return 'audio-volume-muted';
|
||||||
} else {
|
} else {
|
||||||
let n = Math.floor(3 * volume / this._volumeMax) + 1;
|
let n = Math.floor(3 * volume / this._volumeMax) + 1;
|
||||||
if (n < 2)
|
if (n < 2)
|
||||||
return 'audio-volume-low-symbolic';
|
return 'audio-volume-low';
|
||||||
if (n >= 3)
|
if (n >= 3)
|
||||||
return 'audio-volume-high-symbolic';
|
return 'audio-volume-high';
|
||||||
return 'audio-volume-medium-symbolic';
|
return 'audio-volume-medium';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -200,48 +196,15 @@ const VolumeMenu = new Lang.Class({
|
|||||||
slider.setValue(muted ? 0 : (this[property].volume / this._volumeMax));
|
slider.setValue(muted ? 0 : (this[property].volume / this._volumeMax));
|
||||||
if (property == '_output') {
|
if (property == '_output') {
|
||||||
if (muted)
|
if (muted)
|
||||||
this.emit('icon-changed', 'audio-volume-muted-symbolic');
|
this.setIcon('audio-volume-muted');
|
||||||
else
|
else
|
||||||
this.emit('icon-changed', this._volumeToIcon(this._output.volume));
|
this.setIcon(this._volumeToIcon(this._output.volume));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_volumeChanged: function(object, param_spec, property) {
|
_volumeChanged: function(object, param_spec, property) {
|
||||||
this[property+'Slider'].setValue(this[property].volume / this._volumeMax);
|
this[property+'Slider'].setValue(this[property].volume / this._volumeMax);
|
||||||
if (property == '_output' && !this._output.is_muted)
|
if (property == '_output' && !this._output.is_muted)
|
||||||
this.emit('icon-changed', this._volumeToIcon(this._output.volume));
|
this.setIcon(this._volumeToIcon(this._output.volume));
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const Indicator = new Lang.Class({
|
|
||||||
Name: 'VolumeIndicator',
|
|
||||||
Extends: PanelMenu.SystemStatusButton,
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this.parent('audio-volume-muted-symbolic', _("Volume"));
|
|
||||||
|
|
||||||
this._control = getMixerControl();
|
|
||||||
this._volumeMenu = new VolumeMenu(this._control);
|
|
||||||
this._volumeMenu.connect('icon-changed', Lang.bind(this, function(menu, icon) {
|
|
||||||
this._hasPulseAudio = (icon != null);
|
|
||||||
this.setIcon(icon);
|
|
||||||
this._syncVisibility();
|
|
||||||
}));
|
|
||||||
|
|
||||||
this.menu.addMenuItem(this._volumeMenu);
|
|
||||||
|
|
||||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
||||||
this.menu.addSettingsAction(_("Sound Settings"), 'gnome-sound-panel.desktop');
|
|
||||||
|
|
||||||
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
|
||||||
},
|
|
||||||
|
|
||||||
_syncVisibility: function() {
|
|
||||||
this.actor.visible = this._hasPulseAudio;
|
|
||||||
this.mainIcon.visible = this._hasPulseAudio;
|
|
||||||
},
|
|
||||||
|
|
||||||
_onScrollEvent: function(actor, event) {
|
|
||||||
this._volumeMenu.scroll(event.get_scroll_direction());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -11,10 +11,10 @@ const Tpl = imports.gi.TelepathyLogger;
|
|||||||
const Tp = imports.gi.TelepathyGLib;
|
const Tp = imports.gi.TelepathyGLib;
|
||||||
|
|
||||||
const History = imports.misc.history;
|
const History = imports.misc.history;
|
||||||
|
const Params = imports.misc.params;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
const Params = imports.misc.params;
|
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
|
||||||
|
|
||||||
// See Notification.appendMessage
|
// See Notification.appendMessage
|
||||||
const SCROLLBACK_IMMEDIATE_TIME = 60; // 1 minute
|
const SCROLLBACK_IMMEDIATE_TIME = 60; // 1 minute
|
||||||
@ -63,10 +63,10 @@ function makeMessageFromTplEvent(event) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const TelepathyClient = new Lang.Class({
|
const Client = new Lang.Class({
|
||||||
Name: 'TelepathyClient',
|
Name: 'Client',
|
||||||
|
|
||||||
_init: function() {
|
_init : function() {
|
||||||
// channel path -> ChatSource
|
// channel path -> ChatSource
|
||||||
this._chatSources = {};
|
this._chatSources = {};
|
||||||
this._chatState = Tp.ChannelChatState.ACTIVE;
|
this._chatState = Tp.ChannelChatState.ACTIVE;
|
||||||
@ -89,9 +89,9 @@ const TelepathyClient = new Lang.Class({
|
|||||||
// channel matching its filters is detected.
|
// channel matching its filters is detected.
|
||||||
// The second argument, recover, means _observeChannels will be run
|
// The second argument, recover, means _observeChannels will be run
|
||||||
// for any existing channel as well.
|
// for any existing channel as well.
|
||||||
this._tpClient = new Shell.TpClient({ name: 'GnomeShell',
|
this._tpClient = new Shell.TpClient({ 'account-manager': this._accountManager,
|
||||||
account_manager: this._accountManager,
|
'name': 'GnomeShell',
|
||||||
uniquify_name: true });
|
'uniquify-name': true })
|
||||||
this._tpClient.set_observe_channels_func(
|
this._tpClient.set_observe_channels_func(
|
||||||
Lang.bind(this, this._observeChannels));
|
Lang.bind(this, this._observeChannels));
|
||||||
this._tpClient.set_approve_channels_func(
|
this._tpClient.set_approve_channels_func(
|
||||||
@ -99,10 +99,6 @@ const TelepathyClient = new Lang.Class({
|
|||||||
this._tpClient.set_handle_channels_func(
|
this._tpClient.set_handle_channels_func(
|
||||||
Lang.bind(this, this._handleChannels));
|
Lang.bind(this, this._handleChannels));
|
||||||
|
|
||||||
// Watch subscription requests and connection errors
|
|
||||||
this._subscriptionSource = null;
|
|
||||||
this._accountSource = null;
|
|
||||||
|
|
||||||
// Workaround for gjs not supporting GPtrArray in signals.
|
// Workaround for gjs not supporting GPtrArray in signals.
|
||||||
// See BGO bug #653941 for context.
|
// See BGO bug #653941 for context.
|
||||||
this._tpClient.set_contact_list_changed_func(
|
this._tpClient.set_contact_list_changed_func(
|
||||||
@ -112,26 +108,21 @@ const TelepathyClient = new Lang.Class({
|
|||||||
// needed
|
// needed
|
||||||
this._tpClient.set_delegated_channels_callback(
|
this._tpClient.set_delegated_channels_callback(
|
||||||
Lang.bind(this, this._delegatedChannelsCb));
|
Lang.bind(this, this._delegatedChannelsCb));
|
||||||
},
|
|
||||||
|
|
||||||
enable: function() {
|
|
||||||
try {
|
try {
|
||||||
this._tpClient.register();
|
this._tpClient.register();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
|
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._accountManagerValidityChangedId = this._accountManager.connect('account-validity-changed',
|
// Watch subscription requests and connection errors
|
||||||
Lang.bind(this, this._accountValidityChanged));
|
this._subscriptionSource = null;
|
||||||
|
this._accountSource = null;
|
||||||
|
|
||||||
if (!this._accountManager.is_prepared(Tp.AccountManager.get_feature_quark_core()))
|
this._accountManager.connect('account-validity-changed',
|
||||||
this._accountManager.prepare_async(null, Lang.bind(this, this._accountManagerPrepared));
|
Lang.bind(this, this._accountValidityChanged));
|
||||||
},
|
|
||||||
|
|
||||||
disable: function() {
|
this._accountManager.prepare_async(null, Lang.bind(this, this._accountManagerPrepared));
|
||||||
this._tpClient.unregister();
|
|
||||||
this._accountManager.disconnect(this._accountManagerValidityChangedId);
|
|
||||||
this._accountManagerValidityChangedId = 0;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_observeChannels: function(observer, account, conn, channels,
|
_observeChannels: function(observer, account, conn, channels,
|
||||||
@ -141,7 +132,7 @@ const TelepathyClient = new Lang.Class({
|
|||||||
let channel = channels[i];
|
let channel = channels[i];
|
||||||
let [targetHandle, targetHandleType] = channel.get_handle();
|
let [targetHandle, targetHandleType] = channel.get_handle();
|
||||||
|
|
||||||
if (channel.get_invalidated())
|
if (Shell.is_channel_invalidated(channel))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Only observe contact text channels */
|
/* Only observe contact text channels */
|
||||||
@ -193,7 +184,7 @@ const TelepathyClient = new Lang.Class({
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel.get_invalidated())
|
if (Shell.is_channel_invalidated(channel))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// 'notify' will be true when coming from an actual HandleChannels
|
// 'notify' will be true when coming from an actual HandleChannels
|
||||||
@ -220,15 +211,13 @@ const TelepathyClient = new Lang.Class({
|
|||||||
// We can only approve the rooms if we have been invited to it
|
// We can only approve the rooms if we have been invited to it
|
||||||
let selfContact = channel.group_get_self_contact();
|
let selfContact = channel.group_get_self_contact();
|
||||||
if (selfContact == null) {
|
if (selfContact == null) {
|
||||||
context.fail(new Tp.Error({ code: Tp.Error.INVALID_ARGUMENT,
|
Shell.decline_dispatch_op(context, 'Not invited to the room');
|
||||||
message: 'Not invited to the room' }));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let [invited, inviter, reason, msg] = channel.group_get_local_pending_contact_info(selfContact);
|
let [invited, inviter, reason, msg] = channel.group_get_local_pending_contact_info(selfContact);
|
||||||
if (!invited) {
|
if (!invited) {
|
||||||
context.fail(new Tp.Error({ code: Tp.Error.INVALID_ARGUMENT,
|
Shell.decline_dispatch_op(context, 'Not invited to the room');
|
||||||
message: 'Not invited to the room' }));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,9 +237,8 @@ const TelepathyClient = new Lang.Class({
|
|||||||
let channel = channels[0];
|
let channel = channels[0];
|
||||||
let chanType = channel.get_channel_type();
|
let chanType = channel.get_channel_type();
|
||||||
|
|
||||||
if (channel.get_invalidated()) {
|
if (Shell.is_channel_invalidated(channel)) {
|
||||||
context.fail(new Tp.Error({ code: Tp.Error.INVALID_ARGUMENT,
|
Shell.decline_dispatch_op(context, 'Channel is invalidated');
|
||||||
message: 'Channel is invalidated' }));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,8 +249,7 @@ const TelepathyClient = new Lang.Class({
|
|||||||
else if (chanType == Tp.IFACE_CHANNEL_TYPE_FILE_TRANSFER)
|
else if (chanType == Tp.IFACE_CHANNEL_TYPE_FILE_TRANSFER)
|
||||||
this._approveFileTransfer(account, conn, channel, dispatchOp, context);
|
this._approveFileTransfer(account, conn, channel, dispatchOp, context);
|
||||||
else
|
else
|
||||||
context.fail(new Tp.Error({ code: Tp.Error.INVALID_ARGUMENT,
|
Shell.decline_dispatch_op(context, 'Unsupported channel type');
|
||||||
message: 'Unsupported channel type' }));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_approveTextChannel: function(account, conn, channel, dispatchOp, context) {
|
_approveTextChannel: function(account, conn, channel, dispatchOp, context) {
|
||||||
@ -392,7 +379,8 @@ const TelepathyClient = new Lang.Class({
|
|||||||
_ensureSubscriptionSource: function() {
|
_ensureSubscriptionSource: function() {
|
||||||
if (this._subscriptionSource == null) {
|
if (this._subscriptionSource == null) {
|
||||||
this._subscriptionSource = new MessageTray.Source(_("Subscription request"),
|
this._subscriptionSource = new MessageTray.Source(_("Subscription request"),
|
||||||
'gtk-dialog-question');
|
'gtk-dialog-question',
|
||||||
|
St.IconType.FULLCOLOR);
|
||||||
Main.messageTray.add(this._subscriptionSource);
|
Main.messageTray.add(this._subscriptionSource);
|
||||||
this._subscriptionSource.connect('destroy', Lang.bind(this, function () {
|
this._subscriptionSource.connect('destroy', Lang.bind(this, function () {
|
||||||
this._subscriptionSource = null;
|
this._subscriptionSource = null;
|
||||||
@ -428,7 +416,8 @@ const TelepathyClient = new Lang.Class({
|
|||||||
_ensureAccountSource: function() {
|
_ensureAccountSource: function() {
|
||||||
if (this._accountSource == null) {
|
if (this._accountSource == null) {
|
||||||
this._accountSource = new MessageTray.Source(_("Connection error"),
|
this._accountSource = new MessageTray.Source(_("Connection error"),
|
||||||
'gtk-dialog-error');
|
'gtk-dialog-error',
|
||||||
|
St.IconType.FULLCOLOR);
|
||||||
Main.messageTray.add(this._accountSource);
|
Main.messageTray.add(this._accountSource);
|
||||||
this._accountSource.connect('destroy', Lang.bind(this, function () {
|
this._accountSource.connect('destroy', Lang.bind(this, function () {
|
||||||
this._accountSource = null;
|
this._accountSource = null;
|
||||||
@ -482,22 +471,6 @@ const ChatSource = new Lang.Class({
|
|||||||
this._getLogMessages();
|
this._getLogMessages();
|
||||||
},
|
},
|
||||||
|
|
||||||
buildRightClickMenu: function() {
|
|
||||||
let item;
|
|
||||||
|
|
||||||
let rightClickMenu = this.parent();
|
|
||||||
item = new PopupMenu.PopupMenuItem('');
|
|
||||||
item.actor.connect('notify::mapped', Lang.bind(this, function() {
|
|
||||||
item.label.set_text(this.isMuted ? _("Unmute") : _("Mute"));
|
|
||||||
}));
|
|
||||||
item.connect('activate', Lang.bind(this, function() {
|
|
||||||
this.setMuted(!this.isMuted);
|
|
||||||
this.emit('done-displaying-content');
|
|
||||||
}));
|
|
||||||
rightClickMenu.add(item.actor);
|
|
||||||
return rightClickMenu;
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateAlias: function() {
|
_updateAlias: function() {
|
||||||
let oldAlias = this.title;
|
let oldAlias = this.title;
|
||||||
let newAlias = this._contact.get_alias();
|
let newAlias = this._contact.get_alias();
|
||||||
@ -509,42 +482,53 @@ const ChatSource = new Lang.Class({
|
|||||||
this._notification.appendAliasChange(oldAlias, newAlias);
|
this._notification.appendAliasChange(oldAlias, newAlias);
|
||||||
},
|
},
|
||||||
|
|
||||||
getIcon: function() {
|
createIcon: function(size) {
|
||||||
|
this._iconBox = new St.Bin({ style_class: 'avatar-box' });
|
||||||
|
this._iconBox._size = size;
|
||||||
|
let textureCache = St.TextureCache.get_default();
|
||||||
let file = this._contact.get_avatar_file();
|
let file = this._contact.get_avatar_file();
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
return new Gio.FileIcon({ file: file });
|
let uri = file.get_uri();
|
||||||
|
this._iconBox.child = textureCache.load_uri_async(uri, this._iconBox._size, this._iconBox._size);
|
||||||
} else {
|
} else {
|
||||||
return new Gio.ThemedIcon({ name: 'avatar-default' });
|
this._iconBox.child = new St.Icon({ icon_name: 'avatar-default',
|
||||||
|
icon_type: St.IconType.FULLCOLOR,
|
||||||
|
icon_size: this._iconBox._size });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this._iconBox;
|
||||||
},
|
},
|
||||||
|
|
||||||
getSecondaryIcon: function() {
|
createSecondaryIcon: function() {
|
||||||
let iconName;
|
let iconBox = new St.Bin();
|
||||||
|
iconBox.child = new St.Icon({ style_class: 'secondary-icon',
|
||||||
|
icon_type: St.IconType.FULLCOLOR });
|
||||||
let presenceType = this._contact.get_presence_type();
|
let presenceType = this._contact.get_presence_type();
|
||||||
|
|
||||||
switch (presenceType) {
|
switch (presenceType) {
|
||||||
case Tp.ConnectionPresenceType.AVAILABLE:
|
case Tp.ConnectionPresenceType.AVAILABLE:
|
||||||
iconName = 'user-available';
|
iconBox.child.icon_name = 'user-available';
|
||||||
break;
|
break;
|
||||||
case Tp.ConnectionPresenceType.BUSY:
|
case Tp.ConnectionPresenceType.BUSY:
|
||||||
iconName = 'user-busy';
|
iconBox.child.icon_name = 'user-busy';
|
||||||
break;
|
break;
|
||||||
case Tp.ConnectionPresenceType.OFFLINE:
|
case Tp.ConnectionPresenceType.OFFLINE:
|
||||||
iconName = 'user-offline';
|
iconBox.child.icon_name = 'user-offline';
|
||||||
break;
|
break;
|
||||||
case Tp.ConnectionPresenceType.HIDDEN:
|
case Tp.ConnectionPresenceType.HIDDEN:
|
||||||
iconName = 'user-invisible';
|
iconBox.child.icon_name = 'user-invisible';
|
||||||
break;
|
break;
|
||||||
case Tp.ConnectionPresenceType.AWAY:
|
case Tp.ConnectionPresenceType.AWAY:
|
||||||
iconName = 'user-away';
|
iconBox.child.icon_name = 'user-away';
|
||||||
break;
|
break;
|
||||||
case Tp.ConnectionPresenceType.EXTENDED_AWAY:
|
case Tp.ConnectionPresenceType.EXTENDED_AWAY:
|
||||||
iconName = 'user-idle';
|
iconBox.child.icon_name = 'user-idle';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
iconName = 'user-offline';
|
iconBox.child.icon_name = 'user-offline';
|
||||||
}
|
}
|
||||||
return new Gio.ThemedIcon({ name: iconName });
|
return iconBox;
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateAvatarIcon: function() {
|
_updateAvatarIcon: function() {
|
||||||
@ -555,9 +539,7 @@ const ChatSource = new Lang.Class({
|
|||||||
open: function(notification) {
|
open: function(notification) {
|
||||||
if (this._client.is_handling_channel(this._channel)) {
|
if (this._client.is_handling_channel(this._channel)) {
|
||||||
// We are handling the channel, try to pass it to Empathy
|
// We are handling the channel, try to pass it to Empathy
|
||||||
this._client.delegate_channels_async([this._channel],
|
this._client.delegate_channels_async([this._channel], global.get_current_time(), '', null);
|
||||||
global.get_current_time(),
|
|
||||||
'org.freedesktop.Telepathy.Client.Empathy.Chat', null);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// We are not the handler, just ask to present the channel
|
// We are not the handler, just ask to present the channel
|
||||||
@ -596,7 +578,7 @@ const ChatSource = new Lang.Class({
|
|||||||
this._pendingMessages.push(message);
|
this._pendingMessages.push(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.countUpdated();
|
this._updateCount();
|
||||||
|
|
||||||
let showTimestamp = false;
|
let showTimestamp = false;
|
||||||
|
|
||||||
@ -642,17 +624,8 @@ const ChatSource = new Lang.Class({
|
|||||||
this.destroy();
|
this.destroy();
|
||||||
},
|
},
|
||||||
|
|
||||||
/* All messages are new messages for Telepathy sources */
|
_updateCount: function() {
|
||||||
get count() {
|
this._setCount(this._pendingMessages.length, this._pendingMessages.length > 0);
|
||||||
return this._pendingMessages.length;
|
|
||||||
},
|
|
||||||
|
|
||||||
get unseenCount() {
|
|
||||||
return this.count;
|
|
||||||
},
|
|
||||||
|
|
||||||
get countVisible() {
|
|
||||||
return this.count > 0;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_messageReceived: function(channel, message) {
|
_messageReceived: function(channel, message) {
|
||||||
@ -660,7 +633,7 @@ const ChatSource = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
this._pendingMessages.push(message);
|
this._pendingMessages.push(message);
|
||||||
this.countUpdated();
|
this._updateCount();
|
||||||
|
|
||||||
message = makeMessageFromTpMessage(message, NotificationDirection.RECEIVED);
|
message = makeMessageFromTpMessage(message, NotificationDirection.RECEIVED);
|
||||||
this._notification.appendMessage(message);
|
this._notification.appendMessage(message);
|
||||||
@ -726,7 +699,7 @@ const ChatSource = new Lang.Class({
|
|||||||
|
|
||||||
title = GLib.markup_escape_text(this.title, -1);
|
title = GLib.markup_escape_text(this.title, -1);
|
||||||
|
|
||||||
this._notification.update(this._notification.title, null, { customContent: true, secondaryGIcon: this.getSecondaryIcon() });
|
this._notification.update(this._notification.title, null, { customContent: true, secondaryIcon: this.createSecondaryIcon() });
|
||||||
|
|
||||||
if (message)
|
if (message)
|
||||||
msg += ' <i>(' + GLib.markup_escape_text(message, -1) + ')</i>';
|
msg += ' <i>(' + GLib.markup_escape_text(message, -1) + ')</i>';
|
||||||
@ -737,8 +710,10 @@ const ChatSource = new Lang.Class({
|
|||||||
|
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
this._pendingMessages.splice(idx, 1);
|
this._pendingMessages.splice(idx, 1);
|
||||||
this.countUpdated();
|
this._updateCount();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
throw new Error('Message not in our pending list: ' + message);
|
||||||
},
|
},
|
||||||
|
|
||||||
_ackMessages: function() {
|
_ackMessages: function() {
|
||||||
@ -754,7 +729,7 @@ const ChatNotification = new Lang.Class({
|
|||||||
Extends: MessageTray.Notification,
|
Extends: MessageTray.Notification,
|
||||||
|
|
||||||
_init: function(source) {
|
_init: function(source) {
|
||||||
this.parent(source, source.title, null, { customContent: true, secondaryGIcon: source.getSecondaryIcon() });
|
this.parent(source, source.title, null, { customContent: true, secondaryIcon: source.createSecondaryIcon() });
|
||||||
this.setResident(true);
|
this.setResident(true);
|
||||||
|
|
||||||
this._responseEntry = new St.Entry({ style_class: 'chat-response',
|
this._responseEntry = new St.Entry({ style_class: 'chat-response',
|
||||||
@ -763,14 +738,6 @@ const ChatNotification = new Lang.Class({
|
|||||||
this._responseEntry.clutter_text.connect('text-changed', Lang.bind(this, this._onEntryChanged));
|
this._responseEntry.clutter_text.connect('text-changed', Lang.bind(this, this._onEntryChanged));
|
||||||
this.setActionArea(this._responseEntry);
|
this.setActionArea(this._responseEntry);
|
||||||
|
|
||||||
this._responseEntry.clutter_text.connect('key-focus-in', Lang.bind(this, function() {
|
|
||||||
this.focused = true;
|
|
||||||
}));
|
|
||||||
this._responseEntry.clutter_text.connect('key-focus-out', Lang.bind(this, function() {
|
|
||||||
this.focused = false;
|
|
||||||
this.emit('unfocused');
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._oldMaxScrollAdjustment = 0;
|
this._oldMaxScrollAdjustment = 0;
|
||||||
this._createScrollArea();
|
this._createScrollArea();
|
||||||
this._lastGroup = null;
|
this._lastGroup = null;
|
||||||
@ -932,32 +899,24 @@ const ChatNotification = new Lang.Class({
|
|||||||
|
|
||||||
let format;
|
let format;
|
||||||
|
|
||||||
// Show only the hour if date is on today
|
|
||||||
if(daysAgo < 1){
|
|
||||||
format = "<b>%H:%M</b>";
|
|
||||||
}
|
|
||||||
// Show the word "Yesterday" and time if date is on yesterday
|
|
||||||
else if(daysAgo <2){
|
|
||||||
/* Translators: this is a time format string followed by the word "Yesterday". i.e. "14:30 on Yesterday"*/
|
|
||||||
// xgettext:no-c-format
|
|
||||||
format = _("<b>%H:%M</b> on Yesterday");
|
|
||||||
}
|
|
||||||
// Show a week day and time if date is in the last week
|
// Show a week day and time if date is in the last week
|
||||||
else if (daysAgo < 7) {
|
if (daysAgo < 1 || (daysAgo < 7 && now.getDay() != date.getDay())) {
|
||||||
/* Translators: this is a time format string followed by a week day name. i.e. "14:30 on Monday*/
|
/* Translators: this is a time format string followed by a date.
|
||||||
|
If applicable, replace %X with a strftime format valid for your
|
||||||
|
locale, without seconds. */
|
||||||
// xgettext:no-c-format
|
// xgettext:no-c-format
|
||||||
format = _("<b>%H:%M</b> on <b>%A</b>");
|
format = _("Sent at <b>%X</b> on <b>%A</b>");
|
||||||
|
|
||||||
} else if (date.getYear() == now.getYear()) {
|
} else if (date.getYear() == now.getYear()) {
|
||||||
/* Translators: this is a time format in the style of "14:30 on Wednesday, May 25",
|
/* Translators: this is a time format in the style of "Wednesday, May 25",
|
||||||
shown when you get a chat message in the same year */
|
shown when you get a chat message in the same year. */
|
||||||
// xgettext:no-c-format
|
// xgettext:no-c-format
|
||||||
format = _("<b>%H:%M</b> on <b>%A</b>, <b>%B</b> <b>%d</b>");
|
format = _("Sent on <b>%A</b>, <b>%B %d</b>");
|
||||||
} else {
|
} else {
|
||||||
/* Translators: this is a time format in the style of "14:30 on Wednesday, May 25, 2012",
|
/* Translators: this is a time format in the style of "Wednesday, May 25, 2012",
|
||||||
shown when you get a chat message in a different year */
|
shown when you get a chat message in a different year. */
|
||||||
// xgettext:no-c-format
|
// xgettext:no-c-format
|
||||||
format = _("<b>%H:%M</b> on <b>%A</b>, <b>%B</b> <b>%d</b>, %Y");
|
format = _("Sent on <b>%A</b>, <b>%B %d</b>, %Y");
|
||||||
}
|
}
|
||||||
|
|
||||||
return date.toLocaleFormat(format);
|
return date.toLocaleFormat(format);
|
||||||
@ -970,7 +929,8 @@ const ChatNotification = new Lang.Class({
|
|||||||
let timeLabel = this._append({ body: this._formatTimestamp(lastMessageDate),
|
let timeLabel = this._append({ body: this._formatTimestamp(lastMessageDate),
|
||||||
group: 'meta',
|
group: 'meta',
|
||||||
styles: ['chat-meta-message'],
|
styles: ['chat-meta-message'],
|
||||||
childProps: { expand: true, x_fill: false },
|
childProps: { expand: true, x_fill: false,
|
||||||
|
x_align: St.Align.END },
|
||||||
noTimestamp: true,
|
noTimestamp: true,
|
||||||
timestamp: lastMessageTime });
|
timestamp: lastMessageTime });
|
||||||
|
|
||||||
@ -1071,8 +1031,9 @@ const ApproverSource = new Lang.Class({
|
|||||||
this.parent();
|
this.parent();
|
||||||
},
|
},
|
||||||
|
|
||||||
getIcon: function() {
|
createIcon: function(size) {
|
||||||
return this._gicon;
|
return new St.Icon({ gicon: this._gicon,
|
||||||
|
icon_size: size });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1223,6 +1184,7 @@ const SubscriptionRequestNotification = new Lang.Class({
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
iconBox.child = new St.Icon({ icon_name: 'avatar-default',
|
iconBox.child = new St.Icon({ icon_name: 'avatar-default',
|
||||||
|
icon_type: St.IconType.FULLCOLOR,
|
||||||
icon_size: iconBox._size });
|
icon_size: iconBox._size });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1367,14 +1329,15 @@ const AccountNotification = new Lang.Class({
|
|||||||
case 'reconnect':
|
case 'reconnect':
|
||||||
// If it fails again, a new notification should pop up with the
|
// If it fails again, a new notification should pop up with the
|
||||||
// new error.
|
// new error.
|
||||||
account.reconnect_async(null);
|
account.reconnect_async(null, null);
|
||||||
break;
|
break;
|
||||||
case 'edit':
|
case 'edit':
|
||||||
let cmd = '/usr/bin/empathy-accounts'
|
let cmd = '/usr/bin/empathy-accounts'
|
||||||
+ ' --select-account=%s'
|
+ ' --select-account=%s'
|
||||||
.format(account.get_path_suffix());
|
.format(account.get_path_suffix());
|
||||||
let app_info = Gio.app_info_create_from_commandline(cmd, null, 0);
|
let app_info = Gio.app_info_create_from_commandline(cmd, null, 0,
|
||||||
app_info.launch([], global.create_app_launch_context());
|
null);
|
||||||
|
app_info.launch([], null, null);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this.destroy();
|
this.destroy();
|
||||||
@ -1429,4 +1392,3 @@ const AccountNotification = new Lang.Class({
|
|||||||
this.parent();
|
this.parent();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const Component = TelepathyClient;
|
|
@ -2,10 +2,9 @@
|
|||||||
|
|
||||||
const AccountsService = imports.gi.AccountsService;
|
const AccountsService = imports.gi.AccountsService;
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gdm = imports.gi.Gdm;
|
const Gdm = imports.gi.Gdm;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
const GnomeDesktop = imports.gi.GnomeDesktop;
|
|
||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
@ -21,38 +20,6 @@ const UserMenu = imports.ui.userMenu;
|
|||||||
const Batch = imports.gdm.batch;
|
const Batch = imports.gdm.batch;
|
||||||
const GdmUtil = imports.gdm.util;
|
const GdmUtil = imports.gdm.util;
|
||||||
|
|
||||||
// The timeout before going back automatically to the lock screen (in seconds)
|
|
||||||
const IDLE_TIMEOUT = 2 * 60;
|
|
||||||
|
|
||||||
function versionCompare(required, reference) {
|
|
||||||
required = required.split('.');
|
|
||||||
reference = reference.split('.');
|
|
||||||
|
|
||||||
for (let i = 0; i < required.length; i++) {
|
|
||||||
if (required[i] != reference[i])
|
|
||||||
return required[i] < reference[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isSupported() {
|
|
||||||
try {
|
|
||||||
let params = GLib.Variant.new('(ss)', ['org.gnome.DisplayManager.Manager', 'Version']);
|
|
||||||
let result = Gio.DBus.system.call_sync('org.gnome.DisplayManager',
|
|
||||||
'/org/gnome/DisplayManager/Manager',
|
|
||||||
'org.freedesktop.DBus.Properties',
|
|
||||||
'Get', params, null,
|
|
||||||
Gio.DBusCallFlags.NONE,
|
|
||||||
-1, null);
|
|
||||||
|
|
||||||
let version = result.deep_unpack()[0].deep_unpack();
|
|
||||||
return versionCompare('3.5.91', version);
|
|
||||||
} catch(e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A widget showing the user avatar and name
|
// A widget showing the user avatar and name
|
||||||
const UserWidget = new Lang.Class({
|
const UserWidget = new Lang.Class({
|
||||||
Name: 'UserWidget',
|
Name: 'UserWidget',
|
||||||
@ -71,7 +38,6 @@ const UserWidget = new Lang.Class({
|
|||||||
this.actor.add(this._label,
|
this.actor.add(this._label,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
x_fill: true,
|
x_fill: true,
|
||||||
y_fill: false,
|
|
||||||
y_align: St.Align.MIDDLE });
|
y_align: St.Align.MIDDLE });
|
||||||
|
|
||||||
this._userLoadedId = this._user.connect('notify::is-loaded',
|
this._userLoadedId = this._user.connect('notify::is-loaded',
|
||||||
@ -120,26 +86,22 @@ const UnlockDialog = new Lang.Class({
|
|||||||
this._userName = GLib.get_user_name();
|
this._userName = GLib.get_user_name();
|
||||||
this._user = this._userManager.get_user(this._userName);
|
this._user = this._userManager.get_user(this._userName);
|
||||||
|
|
||||||
this._failCounter = 0;
|
|
||||||
this._firstQuestion = true;
|
|
||||||
|
|
||||||
this._greeterClient = new Gdm.Client();
|
this._greeterClient = new Gdm.Client();
|
||||||
this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true });
|
this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true });
|
||||||
|
|
||||||
|
this._userVerifier.connect('reset', Lang.bind(this, this._reset));
|
||||||
this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion));
|
this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion));
|
||||||
this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage));
|
|
||||||
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
|
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
|
||||||
this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
|
this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
|
||||||
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
|
||||||
|
|
||||||
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint));
|
this._userVerifier.connect('show-fingerprint-prompt', Lang.bind(this, this._showFingerprintPrompt));
|
||||||
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint));
|
this._userVerifier.connect('hide-fingerprint-prompt', Lang.bind(this, this._hideFingerprintPrompt));
|
||||||
|
|
||||||
this._userWidget = new UserWidget(this._user);
|
this._userWidget = new UserWidget(this._user);
|
||||||
this.contentLayout.add_actor(this._userWidget.actor);
|
this.contentLayout.add_actor(this._userWidget.actor);
|
||||||
|
|
||||||
this._promptLayout = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
|
this._promptLayout = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
|
||||||
vertical: true });
|
vertical: false });
|
||||||
|
|
||||||
this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' });
|
this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' });
|
||||||
this._promptLayout.add(this._promptLabel,
|
this._promptLayout.add(this._promptLabel,
|
||||||
@ -147,8 +109,7 @@ const UnlockDialog = new Lang.Class({
|
|||||||
|
|
||||||
this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
|
this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
|
||||||
can_focus: true });
|
can_focus: true });
|
||||||
this._promptEntry.clutter_text.set_password_char('\u25cf');
|
ShellEntry.addContextMenu(this._promptEntry);
|
||||||
ShellEntry.addContextMenu(this._promptEntry, { isPassword: true });
|
|
||||||
this.setInitialKeyFocus(this._promptEntry);
|
this.setInitialKeyFocus(this._promptEntry);
|
||||||
this._promptEntry.clutter_text.connect('activate', Lang.bind(this, this._doUnlock));
|
this._promptEntry.clutter_text.connect('activate', Lang.bind(this, this._doUnlock));
|
||||||
|
|
||||||
@ -158,24 +119,14 @@ const UnlockDialog = new Lang.Class({
|
|||||||
|
|
||||||
this.contentLayout.add_actor(this._promptLayout);
|
this.contentLayout.add_actor(this._promptLayout);
|
||||||
|
|
||||||
this._promptMessage = new St.Label({ visible: false });
|
// Translators: this message is shown below the password entry field
|
||||||
this.contentLayout.add(this._promptMessage, { x_fill: true });
|
// to indicate the user can swipe their finger instead
|
||||||
|
this._promptFingerprintMessage = new St.Label({ text: _("(or swipe finger)"),
|
||||||
|
style_class: 'login-dialog-prompt-fingerprint-message' });
|
||||||
|
this._promptFingerprintMessage.hide();
|
||||||
|
this.contentLayout.add_actor(this._promptFingerprintMessage);
|
||||||
|
|
||||||
this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint' });
|
let otherUserLabel = new St.Label({ text: _("Login as another user"),
|
||||||
this._promptLoginHint.hide();
|
|
||||||
this.contentLayout.add_actor(this._promptLoginHint);
|
|
||||||
|
|
||||||
let cancelButton = { label: _("Cancel"),
|
|
||||||
action: Lang.bind(this, this._escape),
|
|
||||||
key: Clutter.KEY_Escape };
|
|
||||||
this._okButton = { label: _("Unlock"),
|
|
||||||
action: Lang.bind(this, this._doUnlock),
|
|
||||||
default: true };
|
|
||||||
this.setButtons([cancelButton, this._okButton]);
|
|
||||||
|
|
||||||
this._updateSensitivity(true);
|
|
||||||
|
|
||||||
let otherUserLabel = new St.Label({ text: _("Log in as another user"),
|
|
||||||
style_class: 'login-dialog-not-listed-label' });
|
style_class: 'login-dialog-not-listed-label' });
|
||||||
this._otherUserButton = new St.Button({ style_class: 'login-dialog-not-listed-button',
|
this._otherUserButton = new St.Button({ style_class: 'login-dialog-not-listed-button',
|
||||||
can_focus: true,
|
can_focus: true,
|
||||||
@ -184,87 +135,60 @@ const UnlockDialog = new Lang.Class({
|
|||||||
x_align: St.Align.START,
|
x_align: St.Align.START,
|
||||||
x_fill: true });
|
x_fill: true });
|
||||||
this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked));
|
this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked));
|
||||||
this.dialogLayout.add(this._otherUserButton,
|
this.contentLayout.add(this._otherUserButton,
|
||||||
{ x_align: St.Align.START,
|
{ x_align: St.Align.START,
|
||||||
x_fill: false });
|
x_fill: false });
|
||||||
|
|
||||||
let batch = new Batch.Hold();
|
this._okButton = { label: _("Unlock"),
|
||||||
this._userVerifier.begin(this._userName, batch);
|
action: Lang.bind(this, this._doUnlock),
|
||||||
|
default: true };
|
||||||
|
this.setButtons([this._okButton]);
|
||||||
|
this.setActionKey(Clutter.KEY_Escape, Lang.bind(this, this._escape));
|
||||||
|
|
||||||
|
this._updateOkButton(false);
|
||||||
|
this._reset();
|
||||||
|
|
||||||
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
|
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
|
||||||
this.emit('loaded');
|
this.emit('loaded');
|
||||||
return false;
|
return false;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._idleMonitor = new GnomeDesktop.IdleMonitor();
|
|
||||||
this._idleWatchId = this._idleMonitor.add_watch(IDLE_TIMEOUT * 1000, Lang.bind(this, this._escape));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateSensitivity: function(sensitive) {
|
_updateOkButton: function(sensitive) {
|
||||||
this._promptEntry.reactive = sensitive;
|
|
||||||
this._promptEntry.clutter_text.editable = sensitive;
|
|
||||||
this._okButton.button.reactive = sensitive;
|
this._okButton.button.reactive = sensitive;
|
||||||
this._okButton.button.can_focus = sensitive;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_showMessage: function(userVerifier, message, styleClass) {
|
_reset: function() {
|
||||||
if (message) {
|
this._userVerifier.begin(this._userName, new Batch.Hold());
|
||||||
this._promptMessage.text = message;
|
|
||||||
this._promptMessage.styleClass = styleClass;
|
|
||||||
GdmUtil.fadeInActor(this._promptMessage);
|
|
||||||
} else {
|
|
||||||
GdmUtil.fadeOutActor(this._promptMessage);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onAskQuestion: function(verifier, serviceName, question, passwordChar) {
|
_onAskQuestion: function(verifier, serviceName, question, passwordChar) {
|
||||||
if (this._firstQuestion && this._firstQuestionAnswer) {
|
|
||||||
this._userVerifier.answerQuery(serviceName, this._firstQuestionAnswer);
|
|
||||||
this._firstQuestionAnswer = null;
|
|
||||||
this._firstQuestion = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._promptLabel.text = question;
|
this._promptLabel.text = question;
|
||||||
|
|
||||||
if (!this._firstQuestion)
|
this._promptEntry.text = '';
|
||||||
this._promptEntry.text = '';
|
|
||||||
else
|
|
||||||
this._firstQuestion = false;
|
|
||||||
|
|
||||||
this._promptEntry.clutter_text.set_password_char(passwordChar);
|
this._promptEntry.clutter_text.set_password_char(passwordChar);
|
||||||
this._promptEntry.menu.isPassword = passwordChar != '';
|
this._promptEntry.menu.isPassword = passwordChar != '';
|
||||||
|
|
||||||
this._currentQuery = serviceName;
|
this._currentQuery = serviceName;
|
||||||
this._updateSensitivity(true);
|
this._updateOkButton(true);
|
||||||
},
|
},
|
||||||
|
|
||||||
_showLoginHint: function(verifier, message) {
|
_showFingerprintPrompt: function() {
|
||||||
this._promptLoginHint.set_text(message)
|
GdmUtil.fadeInActor(this._promptFingerprintMessage);
|
||||||
GdmUtil.fadeInActor(this._promptLoginHint);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_hideLoginHint: function() {
|
_hideFingerprintPrompt: function() {
|
||||||
GdmUtil.fadeOutActor(this._promptLoginHint);
|
GdmUtil.fadeOutActor(this._promptFingerprintMessage);
|
||||||
},
|
},
|
||||||
|
|
||||||
_doUnlock: function() {
|
_doUnlock: function() {
|
||||||
if (this._firstQuestion) {
|
|
||||||
// we haven't received a query yet, so stash the answer
|
|
||||||
// and make ourself non-reactive
|
|
||||||
// the actual reply to GDM will be sent as soon as asked
|
|
||||||
this._firstQuestionAnswer = this._promptEntry.text;
|
|
||||||
this._updateSensitivity(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._currentQuery)
|
if (!this._currentQuery)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let query = this._currentQuery;
|
let query = this._currentQuery;
|
||||||
this._currentQuery = null;
|
this._currentQuery = null;
|
||||||
|
|
||||||
this._updateSensitivity(false);
|
this._updateOkButton(false);
|
||||||
|
|
||||||
this._userVerifier.answerQuery(query, this._promptEntry.text);
|
this._userVerifier.answerQuery(query, this._promptEntry.text);
|
||||||
},
|
},
|
||||||
@ -274,28 +198,17 @@ const UnlockDialog = new Lang.Class({
|
|||||||
this.emit('unlocked');
|
this.emit('unlocked');
|
||||||
},
|
},
|
||||||
|
|
||||||
_onReset: function() {
|
|
||||||
this.emit('failed');
|
|
||||||
},
|
|
||||||
|
|
||||||
_onVerificationFailed: function() {
|
_onVerificationFailed: function() {
|
||||||
this._currentQuery = null;
|
|
||||||
this._firstQuestion = true;
|
|
||||||
|
|
||||||
this._promptEntry.text = '';
|
|
||||||
this._promptEntry.clutter_text.set_password_char('\u25cf');
|
|
||||||
this._promptEntry.menu.isPassword = true;
|
|
||||||
|
|
||||||
this._updateSensitivity(false);
|
|
||||||
},
|
|
||||||
|
|
||||||
_escape: function() {
|
|
||||||
this._userVerifier.cancel();
|
this._userVerifier.cancel();
|
||||||
this.emit('failed');
|
this.emit('failed');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_escape: function() {
|
||||||
|
this._onVerificationFailed();
|
||||||
|
},
|
||||||
|
|
||||||
_otherUserClicked: function(button, event) {
|
_otherUserClicked: function(button, event) {
|
||||||
Gdm.goto_login_session_sync(null);
|
this._userManager.goto_login_session();
|
||||||
|
|
||||||
this._userVerifier.cancel();
|
this._userVerifier.cancel();
|
||||||
this.emit('failed');
|
this.emit('failed');
|
||||||
@ -303,12 +216,6 @@ const UnlockDialog = new Lang.Class({
|
|||||||
|
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
this._userVerifier.clear();
|
this._userVerifier.clear();
|
||||||
|
|
||||||
if (this._idleWatchId) {
|
|
||||||
this._idleMonitor.remove_watch(this._idleWatchId);
|
|
||||||
this._idleWatchId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.parent();
|
this.parent();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -9,24 +9,19 @@ const Pango = imports.gi.Pango;
|
|||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Tp = imports.gi.TelepathyGLib;
|
const Tp = imports.gi.TelepathyGLib;
|
||||||
|
const UPowerGlib = imports.gi.UPowerGlib;
|
||||||
const Atk = imports.gi.Atk;
|
const Atk = imports.gi.Atk;
|
||||||
|
|
||||||
const BoxPointer = imports.ui.boxpointer;
|
|
||||||
const GnomeSession = imports.misc.gnomeSession;
|
const GnomeSession = imports.misc.gnomeSession;
|
||||||
const LoginManager = imports.misc.loginManager;
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const PanelMenu = imports.ui.panelMenu;
|
const PanelMenu = imports.ui.panelMenu;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
const Params = imports.misc.params;
|
|
||||||
const Util = imports.misc.util;
|
const Util = imports.misc.util;
|
||||||
|
|
||||||
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
|
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
|
||||||
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
|
|
||||||
const DISABLE_USER_SWITCH_KEY = 'disable-user-switching';
|
const DISABLE_USER_SWITCH_KEY = 'disable-user-switching';
|
||||||
const DISABLE_LOCK_SCREEN_KEY = 'disable-lock-screen';
|
const DISABLE_LOCK_SCREEN_KEY = 'disable-lock-screen';
|
||||||
const DISABLE_LOG_OUT_KEY = 'disable-log-out';
|
const DISABLE_LOG_OUT_KEY = 'disable-log-out';
|
||||||
const LOCK_ENABLED_KEY = 'lock-enabled';
|
|
||||||
const ALWAYS_SHOW_LOG_OUT_KEY = 'always-show-log-out';
|
|
||||||
|
|
||||||
const DIALOG_ICON_SIZE = 64;
|
const DIALOG_ICON_SIZE = 64;
|
||||||
|
|
||||||
@ -48,21 +43,12 @@ const IMStatus = {
|
|||||||
const UserAvatarWidget = new Lang.Class({
|
const UserAvatarWidget = new Lang.Class({
|
||||||
Name: 'UserAvatarWidget',
|
Name: 'UserAvatarWidget',
|
||||||
|
|
||||||
_init: function(user, params) {
|
_init: function(user) {
|
||||||
this._user = user;
|
this._user = user;
|
||||||
params = Params.parse(params, { reactive: false,
|
|
||||||
iconSize: DIALOG_ICON_SIZE,
|
|
||||||
styleClass: 'status-chooser-user-icon' });
|
|
||||||
this._iconSize = params.iconSize;
|
|
||||||
|
|
||||||
this.actor = new St.Bin({ style_class: params.styleClass,
|
this.actor = new St.Bin({ style_class: 'status-chooser-user-icon',
|
||||||
track_hover: params.reactive,
|
track_hover: true,
|
||||||
reactive: params.reactive });
|
reactive: true });
|
||||||
},
|
|
||||||
|
|
||||||
setSensitive: function(sensitive) {
|
|
||||||
this.actor.can_focus = sensitive;
|
|
||||||
this.actor.reactive = sensitive;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
update: function() {
|
update: function() {
|
||||||
@ -76,8 +62,9 @@ const UserAvatarWidget = new Lang.Class({
|
|||||||
this.actor.style = 'background-image: url("%s");'.format(iconFile);
|
this.actor.style = 'background-image: url("%s");'.format(iconFile);
|
||||||
} else {
|
} else {
|
||||||
this.actor.style = null;
|
this.actor.style = null;
|
||||||
this.actor.child = new St.Icon({ icon_name: 'avatar-default-symbolic',
|
this.actor.child = new St.Icon({ icon_name: 'avatar-default',
|
||||||
icon_size: this._iconSize });
|
icon_type: St.IconType.SYMBOLIC,
|
||||||
|
icon_size: DIALOG_ICON_SIZE });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -109,7 +96,6 @@ const IMUserNameItem = new Lang.Class({
|
|||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent({ reactive: false,
|
this.parent({ reactive: false,
|
||||||
can_focus: false,
|
|
||||||
style_class: 'status-chooser-user-name' });
|
style_class: 'status-chooser-user-name' });
|
||||||
|
|
||||||
this._wrapper = new Shell.GenericContainer();
|
this._wrapper = new Shell.GenericContainer();
|
||||||
@ -147,13 +133,12 @@ const IMStatusChooserItem = new Lang.Class({
|
|||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent({ reactive: false,
|
this.parent({ reactive: false,
|
||||||
can_focus: false,
|
|
||||||
style_class: 'status-chooser' });
|
style_class: 'status-chooser' });
|
||||||
|
|
||||||
this._userManager = AccountsService.UserManager.get_default();
|
this._userManager = AccountsService.UserManager.get_default();
|
||||||
this._user = this._userManager.get_user(GLib.get_user_name());
|
this._user = this._userManager.get_user(GLib.get_user_name());
|
||||||
|
|
||||||
this._avatar = new UserAvatarWidget(this._user, { reactive: true });
|
this._avatar = new UserAvatarWidget(this._user);
|
||||||
this._iconBin = new St.Button({ child: this._avatar.actor });
|
this._iconBin = new St.Button({ child: this._avatar.actor });
|
||||||
this.addActor(this._iconBin);
|
this.addActor(this._iconBin);
|
||||||
|
|
||||||
@ -173,34 +158,30 @@ const IMStatusChooserItem = new Lang.Class({
|
|||||||
|
|
||||||
let item;
|
let item;
|
||||||
|
|
||||||
item = new IMStatusItem(_("Available"), 'user-available-symbolic');
|
item = new IMStatusItem(_("Available"), 'user-available');
|
||||||
this._combo.addMenuItem(item, IMStatus.AVAILABLE);
|
this._combo.addMenuItem(item, IMStatus.AVAILABLE);
|
||||||
|
|
||||||
item = new IMStatusItem(_("Busy"), 'user-busy-symbolic');
|
item = new IMStatusItem(_("Busy"), 'user-busy');
|
||||||
this._combo.addMenuItem(item, IMStatus.BUSY);
|
this._combo.addMenuItem(item, IMStatus.BUSY);
|
||||||
|
|
||||||
item = new IMStatusItem(_("Invisible"), 'user-invisible-symbolic');
|
item = new IMStatusItem(_("Invisible"), 'user-invisible');
|
||||||
this._combo.addMenuItem(item, IMStatus.HIDDEN);
|
this._combo.addMenuItem(item, IMStatus.HIDDEN);
|
||||||
|
|
||||||
item = new IMStatusItem(_("Away"), 'user-away-symbolic');
|
item = new IMStatusItem(_("Away"), 'user-away');
|
||||||
this._combo.addMenuItem(item, IMStatus.AWAY);
|
this._combo.addMenuItem(item, IMStatus.AWAY);
|
||||||
|
|
||||||
item = new IMStatusItem(_("Idle"), 'user-idle-symbolic');
|
item = new IMStatusItem(_("Idle"), 'user-idle');
|
||||||
this._combo.addMenuItem(item, IMStatus.IDLE);
|
this._combo.addMenuItem(item, IMStatus.IDLE);
|
||||||
|
|
||||||
item = new IMStatusItem(_("Offline"), 'user-offline-symbolic');
|
item = new IMStatusItem(_("Unavailable"), 'user-offline');
|
||||||
this._combo.addMenuItem(item, IMStatus.OFFLINE);
|
this._combo.addMenuItem(item, IMStatus.OFFLINE);
|
||||||
|
|
||||||
this._combo.connect('active-item-changed',
|
this._combo.connect('active-item-changed',
|
||||||
Lang.bind(this, this._changeIMStatus));
|
Lang.bind(this, this._changeIMStatus));
|
||||||
|
|
||||||
this._presence = new GnomeSession.Presence();
|
this._presence = new GnomeSession.Presence();
|
||||||
this._presence.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(obj, result) {
|
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
|
||||||
obj.init_finish(result);
|
this._sessionStatusChanged(status);
|
||||||
|
|
||||||
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
|
|
||||||
this._sessionStatusChanged(status);
|
|
||||||
}));
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._sessionPresenceRestored = false;
|
this._sessionPresenceRestored = false;
|
||||||
@ -220,21 +201,20 @@ const IMStatusChooserItem = new Lang.Class({
|
|||||||
Lang.bind(this, this._IMAccountsChanged));
|
Lang.bind(this, this._IMAccountsChanged));
|
||||||
this._accountMgr.prepare_async(null, Lang.bind(this,
|
this._accountMgr.prepare_async(null, Lang.bind(this,
|
||||||
function(mgr) {
|
function(mgr) {
|
||||||
|
let [presence, status, msg] = mgr.get_most_available_presence();
|
||||||
|
|
||||||
|
let savedPresence = global.settings.get_int('saved-im-presence');
|
||||||
|
|
||||||
this._IMAccountsChanged(mgr);
|
this._IMAccountsChanged(mgr);
|
||||||
|
|
||||||
if (this._networkMonitor.network_available)
|
if (savedPresence == presence) {
|
||||||
this._restorePresence();
|
this._IMStatusChanged(mgr, presence, status, msg);
|
||||||
else
|
} else {
|
||||||
this._setComboboxPresence(Tp.ConnectionPresenceType.OFFLINE);
|
this._setComboboxPresence(savedPresence);
|
||||||
}));
|
status = this._statusForPresence(savedPresence);
|
||||||
|
msg = msg ? msg : '';
|
||||||
this._networkMonitor = Gio.NetworkMonitor.get_default();
|
mgr.set_all_requested_presences(savedPresence, status, msg);
|
||||||
this._networkMonitor.connect('network-changed',
|
}
|
||||||
Lang.bind(this, function(monitor, available) {
|
|
||||||
this._IMAccountsChanged(this._accountMgr);
|
|
||||||
|
|
||||||
if (available && !this._imPresenceRestored)
|
|
||||||
this._restorePresence();
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._userLoadedId = this._user.connect('notify::is-loaded',
|
this._userLoadedId = this._user.connect('notify::is-loaded',
|
||||||
@ -247,25 +227,6 @@ const IMStatusChooserItem = new Lang.Class({
|
|||||||
if (this.actor.mapped)
|
if (this.actor.mapped)
|
||||||
this._updateUser();
|
this._updateUser();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.connect('sensitive-changed', function(sensitive) {
|
|
||||||
this._avatar.setSensitive(sensitive);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_restorePresence: function() {
|
|
||||||
let [presence, status, msg] = this._accountMgr.get_most_available_presence();
|
|
||||||
|
|
||||||
let savedPresence = global.settings.get_int('saved-im-presence');
|
|
||||||
|
|
||||||
if (savedPresence == presence) {
|
|
||||||
this._IMStatusChanged(this._accountMgr, presence, status, msg);
|
|
||||||
} else {
|
|
||||||
this._setComboboxPresence(savedPresence);
|
|
||||||
status = this._statusForPresence(savedPresence);
|
|
||||||
msg = msg ? msg : '';
|
|
||||||
this._accountMgr.set_all_requested_presences(savedPresence, status, msg);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
@ -324,8 +285,7 @@ const IMStatusChooserItem = new Lang.Class({
|
|||||||
let accounts = mgr.get_valid_accounts().filter(function(account) {
|
let accounts = mgr.get_valid_accounts().filter(function(account) {
|
||||||
return account.enabled;
|
return account.enabled;
|
||||||
});
|
});
|
||||||
let sensitive = accounts.length > 0 && this._networkMonitor.network_available;
|
this._combo.setSensitive(accounts.length > 0);
|
||||||
this._combo.setSensitive(sensitive);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_IMStatusChanged: function(accountMgr, presence, status, message) {
|
_IMStatusChanged: function(accountMgr, presence, status, message) {
|
||||||
@ -478,61 +438,38 @@ const UserMenuButton = new Lang.Class({
|
|||||||
let box = new St.BoxLayout({ name: 'panelUserMenu' });
|
let box = new St.BoxLayout({ name: 'panelUserMenu' });
|
||||||
this.actor.add_actor(box);
|
this.actor.add_actor(box);
|
||||||
|
|
||||||
this._screenSaverSettings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
|
|
||||||
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
|
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
|
||||||
|
|
||||||
this._userManager = AccountsService.UserManager.get_default();
|
this._userManager = AccountsService.UserManager.get_default();
|
||||||
|
|
||||||
this._user = this._userManager.get_user(GLib.get_user_name());
|
this._user = this._userManager.get_user(GLib.get_user_name());
|
||||||
|
|
||||||
this._presence = new GnomeSession.Presence();
|
this._presence = new GnomeSession.Presence();
|
||||||
this._presence.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(proxy, result) {
|
this._session = new GnomeSession.SessionManager();
|
||||||
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._haveShutdown = true;
|
||||||
this._haveSuspend = true;
|
|
||||||
|
|
||||||
this._accountMgr = Tp.AccountManager.dup();
|
this._accountMgr = Tp.AccountManager.dup();
|
||||||
|
|
||||||
LoginManager.getLoginManager(Lang.bind(this, function(manager) {
|
this._upClient = new UPowerGlib.Client();
|
||||||
this._loginManager = manager;
|
|
||||||
}));
|
|
||||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||||
|
|
||||||
this._iconBox = new St.Bin();
|
this._iconBox = new St.Bin();
|
||||||
box.add(this._iconBox, { y_align: St.Align.MIDDLE, y_fill: false });
|
box.add(this._iconBox, { y_align: St.Align.MIDDLE, y_fill: false });
|
||||||
|
|
||||||
let textureCache = St.TextureCache.get_default();
|
let textureCache = St.TextureCache.get_default();
|
||||||
this._offlineIcon = new St.Icon({ icon_name: 'user-offline-symbolic',
|
this._offlineIcon = new St.Icon({ icon_name: 'user-offline',
|
||||||
style_class: 'popup-menu-icon' });
|
style_class: 'popup-menu-icon' });
|
||||||
this._availableIcon = new St.Icon({ icon_name: 'user-available-symbolic',
|
this._availableIcon = new St.Icon({ icon_name: 'user-available',
|
||||||
style_class: 'popup-menu-icon' });
|
style_class: 'popup-menu-icon' });
|
||||||
this._busyIcon = new St.Icon({ icon_name: 'user-busy-symbolic',
|
this._busyIcon = new St.Icon({ icon_name: 'user-busy',
|
||||||
style_class: 'popup-menu-icon' });
|
style_class: 'popup-menu-icon' });
|
||||||
this._invisibleIcon = new St.Icon({ icon_name: 'user-invisible-symbolic',
|
this._invisibleIcon = new St.Icon({ icon_name: 'user-invisible',
|
||||||
style_class: 'popup-menu-icon' });
|
style_class: 'popup-menu-icon' });
|
||||||
this._awayIcon = new St.Icon({ icon_name: 'user-away-symbolic',
|
this._awayIcon = new St.Icon({ icon_name: 'user-away',
|
||||||
style_class: 'popup-menu-icon' });
|
style_class: 'popup-menu-icon' });
|
||||||
this._idleIcon = new St.Icon({ icon_name: 'user-idle-symbolic',
|
this._idleIcon = new St.Icon({ icon_name: 'user-idle',
|
||||||
style_class: 'popup-menu-icon' });
|
style_class: 'popup-menu-icon' });
|
||||||
this._pendingIcon = new St.Icon({ icon_name: 'user-status-pending-symbolic',
|
this._pendingIcon = new St.Icon({ icon_name: 'user-status-pending',
|
||||||
style_class: 'popup-menu-icon' });
|
style_class: 'popup-menu-icon' });
|
||||||
this._lockedIcon = new St.Icon({ icon_name: 'changes-prevent-symbolic',
|
|
||||||
style_class: 'popup-menu-icon' });
|
|
||||||
|
|
||||||
this._accountMgr.connect('most-available-presence-changed',
|
this._accountMgr.connect('most-available-presence-changed',
|
||||||
Lang.bind(this, this._updatePresenceIcon));
|
Lang.bind(this, this._updatePresenceIcon));
|
||||||
@ -556,6 +493,11 @@ const UserMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
this._createSubMenu();
|
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',
|
this._userManager.connect('notify::is-loaded',
|
||||||
Lang.bind(this, this._updateMultiUser));
|
Lang.bind(this, this._updateMultiUser));
|
||||||
this._userManager.connect('notify::has-multiple-users',
|
this._userManager.connect('notify::has-multiple-users',
|
||||||
@ -585,28 +527,19 @@ const UserMenuButton = new Lang.Class({
|
|||||||
// the lockdown setting changes, which should be close enough.
|
// the lockdown setting changes, which should be close enough.
|
||||||
this.menu.connect('open-state-changed', Lang.bind(this,
|
this.menu.connect('open-state-changed', Lang.bind(this,
|
||||||
function(menu, open) {
|
function(menu, open) {
|
||||||
if (!open)
|
if (open)
|
||||||
return;
|
this._updateHaveShutdown();
|
||||||
|
|
||||||
this._updateHaveShutdown();
|
|
||||||
this._updateHaveSuspend();
|
|
||||||
}));
|
}));
|
||||||
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
|
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
|
||||||
Lang.bind(this, this._updateHaveShutdown));
|
Lang.bind(this, this._updateHaveShutdown));
|
||||||
|
|
||||||
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
this._upClient.connect('notify::can-suspend', Lang.bind(this, this._updateSuspendOrPowerOff));
|
||||||
this._sessionUpdated();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_sessionUpdated: function() {
|
setLockedState: function(locked) {
|
||||||
this.actor.visible = !Main.sessionMode.isGreeter;
|
if (locked)
|
||||||
|
this.menu.close();
|
||||||
let allowSettings = Main.sessionMode.allowSettings;
|
this.actor.reactive = !locked;
|
||||||
this._statusChooser.setSensitive(allowSettings);
|
|
||||||
this._systemSettings.visible = allowSettings;
|
|
||||||
|
|
||||||
this.setSensitive(!Main.sessionMode.isLocked);
|
|
||||||
this._updatePresenceIcon();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDestroy: function() {
|
_onDestroy: function() {
|
||||||
@ -629,19 +562,19 @@ const UserMenuButton = new Lang.Class({
|
|||||||
_updateSwitchUser: function() {
|
_updateSwitchUser: function() {
|
||||||
let allowSwitch = !this._lockdownSettings.get_boolean(DISABLE_USER_SWITCH_KEY);
|
let allowSwitch = !this._lockdownSettings.get_boolean(DISABLE_USER_SWITCH_KEY);
|
||||||
let multiUser = this._userManager.can_switch() && this._userManager.has_multiple_users;
|
let multiUser = this._userManager.can_switch() && this._userManager.has_multiple_users;
|
||||||
|
let multiSession = Gdm.get_session_ids().length > 1;
|
||||||
|
|
||||||
this._loginScreenItem.actor.visible = allowSwitch && multiUser;
|
this._loginScreenItem.label.set_text(multiUser ? _("Switch User")
|
||||||
|
: _("Switch Session"));
|
||||||
|
this._loginScreenItem.actor.visible = allowSwitch && (multiUser || multiSession);
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateLogout: function() {
|
_updateLogout: function() {
|
||||||
let allowLogout = !this._lockdownSettings.get_boolean(DISABLE_LOG_OUT_KEY);
|
let allowLogout = !this._lockdownSettings.get_boolean(DISABLE_LOG_OUT_KEY);
|
||||||
let alwaysShow = global.settings.get_boolean(ALWAYS_SHOW_LOG_OUT_KEY);
|
|
||||||
let systemAccount = this._user.system_account;
|
|
||||||
let localAccount = this._user.local_account;
|
|
||||||
let multiUser = this._userManager.has_multiple_users;
|
let multiUser = this._userManager.has_multiple_users;
|
||||||
let multiSession = Gdm.get_session_ids().length > 1;
|
let multiSession = Gdm.get_session_ids().length > 1;
|
||||||
|
|
||||||
this._logoutItem.actor.visible = allowLogout && (alwaysShow || multiUser || multiSession || systemAccount || !localAccount);
|
this._logoutItem.actor.visible = allowLogout && (multiUser || multiSession);
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateLockScreen: function() {
|
_updateLockScreen: function() {
|
||||||
@ -655,37 +588,19 @@ const UserMenuButton = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_updateHaveShutdown: function() {
|
_updateHaveShutdown: function() {
|
||||||
if (!this._session) {
|
this._session.CanShutdownRemote(Lang.bind(this,
|
||||||
this._haveShutdown = false;
|
function(result, error) {
|
||||||
return;
|
if (!error) {
|
||||||
}
|
this._haveShutdown = result[0];
|
||||||
|
this._updateInstallUpdates();
|
||||||
this._session.CanShutdownRemote(null, Lang.bind(this, function(proxy, result) {
|
this._updateSuspendOrPowerOff();
|
||||||
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;
|
|
||||||
this._updateSuspendOrPowerOff();
|
|
||||||
}));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateSuspendOrPowerOff: function() {
|
_updateSuspendOrPowerOff: function() {
|
||||||
|
this._haveSuspend = this._upClient.get_can_suspend();
|
||||||
|
|
||||||
if (!this._suspendOrPowerOffItem)
|
if (!this._suspendOrPowerOffItem)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -708,9 +623,7 @@ const UserMenuButton = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_updatePresenceIcon: function(accountMgr, presence, status, message) {
|
_updatePresenceIcon: function(accountMgr, presence, status, message) {
|
||||||
if (Main.sessionMode.isLocked)
|
if (presence == Tp.ConnectionPresenceType.AVAILABLE)
|
||||||
this._iconBox.child = this._lockedIcon;
|
|
||||||
else if (presence == Tp.ConnectionPresenceType.AVAILABLE)
|
|
||||||
this._iconBox.child = this._availableIcon;
|
this._iconBox.child = this._availableIcon;
|
||||||
else if (presence == Tp.ConnectionPresenceType.BUSY)
|
else if (presence == Tp.ConnectionPresenceType.BUSY)
|
||||||
this._iconBox.child = this._busyIcon;
|
this._iconBox.child = this._busyIcon;
|
||||||
@ -741,10 +654,8 @@ const UserMenuButton = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onAccountRemoved: function(accountMgr, account) {
|
_onAccountRemoved: function(accountMgr, account) {
|
||||||
if (account._changingId) {
|
account.disconnect(account._changingId);
|
||||||
account.disconnect(account._changingId);
|
account._changingId = 0;
|
||||||
account._changingId = 0;
|
|
||||||
}
|
|
||||||
this._updateChangingPresence();
|
this._updateChangingPresence();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -770,7 +681,8 @@ const UserMenuButton = new Lang.Class({
|
|||||||
let item;
|
let item;
|
||||||
|
|
||||||
item = new IMStatusChooserItem();
|
item = new IMStatusChooserItem();
|
||||||
item.connect('activate', Lang.bind(this, this._onMyAccountActivate));
|
if (Main.sessionMode.allowSettings)
|
||||||
|
item.connect('activate', Lang.bind(this, this._onMyAccountActivate));
|
||||||
this.menu.addMenuItem(item);
|
this.menu.addMenuItem(item);
|
||||||
this._statusChooser = item;
|
this._statusChooser = item;
|
||||||
|
|
||||||
@ -782,10 +694,11 @@ const UserMenuButton = new Lang.Class({
|
|||||||
item = new PopupMenu.PopupSeparatorMenuItem();
|
item = new PopupMenu.PopupSeparatorMenuItem();
|
||||||
this.menu.addMenuItem(item);
|
this.menu.addMenuItem(item);
|
||||||
|
|
||||||
item = new PopupMenu.PopupMenuItem(_("System Settings"));
|
if (Main.sessionMode.allowSettings) {
|
||||||
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
|
item = new PopupMenu.PopupMenuItem(_("System Settings"));
|
||||||
this.menu.addMenuItem(item);
|
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
|
||||||
this._systemSettings = item;
|
this.menu.addMenuItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
item = new PopupMenu.PopupSeparatorMenuItem();
|
item = new PopupMenu.PopupSeparatorMenuItem();
|
||||||
this.menu.addMenuItem(item);
|
this.menu.addMenuItem(item);
|
||||||
@ -853,31 +766,26 @@ const UserMenuButton = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onLockScreenActivate: function() {
|
_onLockScreenActivate: function() {
|
||||||
this.menu.close(BoxPointer.PopupAnimation.NONE);
|
|
||||||
Main.overview.hide();
|
Main.overview.hide();
|
||||||
Main.screenShield.lock(true);
|
Main.screenShield.lock(true);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onLoginScreenActivate: function() {
|
_onLoginScreenActivate: function() {
|
||||||
this.menu.close(BoxPointer.PopupAnimation.NONE);
|
|
||||||
Main.overview.hide();
|
Main.overview.hide();
|
||||||
Main.screenShield.lock(false);
|
Main.screenShield.lock(false);
|
||||||
Gdm.goto_login_session_sync(null);
|
this._userManager.goto_login_session();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onQuitSessionActivate: function() {
|
_onQuitSessionActivate: function() {
|
||||||
Main.overview.hide();
|
Main.overview.hide();
|
||||||
|
this._session.LogoutRemote(0);
|
||||||
if (this._session)
|
|
||||||
this._session.LogoutRemote(0, null, null);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onInstallUpdatesActivate: function() {
|
_onInstallUpdatesActivate: function() {
|
||||||
Main.overview.hide();
|
Main.overview.hide();
|
||||||
Util.spawn(['pkexec', '/usr/libexec/pk-trigger-offline-update']);
|
Util.spawn(['pkexec', '/usr/libexec/pk-trigger-offline-update']);
|
||||||
|
|
||||||
if (this._haveShutdown)
|
this._session.RebootRemote();
|
||||||
this._session.RebootRemote(null, null);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onSuspendOrPowerOffActivate: function() {
|
_onSuspendOrPowerOffActivate: function() {
|
||||||
@ -885,20 +793,15 @@ const UserMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
if (this._haveShutdown &&
|
if (this._haveShutdown &&
|
||||||
this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
|
this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
|
||||||
this._session.ShutdownRemote(null, null);
|
this._session.ShutdownRemote();
|
||||||
} else if (this._haveSuspend) {
|
} else {
|
||||||
if (this._screenSaverSettings.get_boolean(LOCK_ENABLED_KEY)) {
|
let tmpId = Main.screenShield.connect('lock-screen-shown', Lang.bind(this, function() {
|
||||||
let tmpId = Main.screenShield.connect('lock-screen-shown', Lang.bind(this, function() {
|
Main.screenShield.disconnect(tmpId);
|
||||||
Main.screenShield.disconnect(tmpId);
|
|
||||||
|
|
||||||
this._loginManager.suspend();
|
this._upClient.suspend_sync(null);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.menu.close(BoxPointer.PopupAnimation.NONE);
|
Main.screenShield.lock(true);
|
||||||
Main.screenShield.lock(true);
|
|
||||||
} else {
|
|
||||||
this._loginManager.suspend();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gio = imports.gi.Gio;
|
|
||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
@ -10,267 +9,176 @@ const Lang = imports.lang;
|
|||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
const AppDisplay = imports.ui.appDisplay;
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const RemoteSearch = imports.ui.remoteSearch;
|
|
||||||
const Search = imports.ui.search;
|
const Search = imports.ui.search;
|
||||||
const SearchDisplay = imports.ui.searchDisplay;
|
const SearchDisplay = imports.ui.searchDisplay;
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
const Wanda = imports.ui.wanda;
|
|
||||||
const WorkspacesView = imports.ui.workspacesView;
|
|
||||||
|
|
||||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
const BaseTab = new Lang.Class({
|
||||||
|
Name: 'BaseTab',
|
||||||
|
|
||||||
const FocusTrap = new Lang.Class({
|
_init: function(titleActor, pageActor, name, a11yIcon) {
|
||||||
Name: 'FocusTrap',
|
this.title = titleActor;
|
||||||
Extends: St.Widget,
|
this.page = new St.Bin({ child: pageActor,
|
||||||
|
x_align: St.Align.START,
|
||||||
|
y_align: St.Align.START,
|
||||||
|
x_fill: true,
|
||||||
|
y_fill: true,
|
||||||
|
style_class: 'view-tab-page' });
|
||||||
|
|
||||||
vfunc_navigate_focus: function(from, direction) {
|
if (this.title.can_focus) {
|
||||||
if (direction == Gtk.DirectionType.TAB_FORWARD ||
|
Main.ctrlAltTabManager.addGroup(this.title, name, a11yIcon);
|
||||||
direction == Gtk.DirectionType.TAB_BACKWARD)
|
} else {
|
||||||
return this.parent(from, direction);
|
Main.ctrlAltTabManager.addGroup(this.page, name, a11yIcon,
|
||||||
return false;
|
{ proxy: this.title,
|
||||||
|
focusCallback: Lang.bind(this, this._a11yFocus) });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.visible = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
show: function(animate) {
|
||||||
|
this.visible = true;
|
||||||
|
this.page.show();
|
||||||
|
|
||||||
|
if (!animate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.page.opacity = 0;
|
||||||
|
Tweener.addTween(this.page,
|
||||||
|
{ opacity: 255,
|
||||||
|
time: 0.1,
|
||||||
|
transition: 'easeOutQuad' });
|
||||||
|
},
|
||||||
|
|
||||||
|
hide: function() {
|
||||||
|
this.visible = false;
|
||||||
|
Tweener.addTween(this.page,
|
||||||
|
{ opacity: 0,
|
||||||
|
time: 0.1,
|
||||||
|
transition: 'easeOutQuad',
|
||||||
|
onComplete: Lang.bind(this,
|
||||||
|
function() {
|
||||||
|
this.page.hide();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_a11yFocus: function() {
|
||||||
|
this._activate();
|
||||||
|
this.page.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
_activate: function() {
|
||||||
|
this.emit('activated');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(BaseTab.prototype);
|
||||||
|
|
||||||
|
|
||||||
|
const ViewTab = new Lang.Class({
|
||||||
|
Name: 'ViewTab',
|
||||||
|
Extends: BaseTab,
|
||||||
|
|
||||||
|
_init: function(id, label, pageActor, a11yIcon) {
|
||||||
|
this.id = id;
|
||||||
|
|
||||||
|
let titleActor = new St.Button({ label: label,
|
||||||
|
style_class: 'view-tab-title' });
|
||||||
|
titleActor.connect('clicked', Lang.bind(this, this._activate));
|
||||||
|
|
||||||
|
this.parent(titleActor, pageActor, label, a11yIcon);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const ViewSelector = new Lang.Class({
|
const SearchTab = new Lang.Class({
|
||||||
Name: 'ViewSelector',
|
Name: 'SearchTab',
|
||||||
|
Extends: BaseTab,
|
||||||
_init : function(searchEntry, showAppsButton) {
|
|
||||||
this.actor = new St.BoxLayout({ name: 'viewSelector',
|
|
||||||
vertical: true });
|
|
||||||
|
|
||||||
this._showAppsButton = showAppsButton;
|
|
||||||
this._showAppsButton.connect('notify::checked', Lang.bind(this, this._onShowAppsButtonToggled));
|
|
||||||
|
|
||||||
this._pageArea = new Shell.Stack();
|
|
||||||
this.actor.add(this._pageArea, { x_fill: true,
|
|
||||||
y_fill: true,
|
|
||||||
expand: true });
|
|
||||||
|
|
||||||
this._activePage = null;
|
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
this.active = false;
|
this.active = false;
|
||||||
this._searchPending = false;
|
this._searchPending = false;
|
||||||
this._searchTimeoutId = 0;
|
this._searchTimeoutId = 0;
|
||||||
|
|
||||||
this._searchSystem = new Search.SearchSystem();
|
this._searchSystem = new Search.SearchSystem();
|
||||||
|
this._openSearchSystem = new Search.OpenSearchSystem();
|
||||||
|
|
||||||
this._entry = searchEntry;
|
this._entry = new St.Entry({ name: 'searchEntry',
|
||||||
|
/* Translators: this is the text displayed
|
||||||
|
in the search entry when no search is
|
||||||
|
active; it should not exceed ~30
|
||||||
|
characters. */
|
||||||
|
hint_text: _("Type to search..."),
|
||||||
|
track_hover: true,
|
||||||
|
can_focus: true });
|
||||||
ShellEntry.addContextMenu(this._entry);
|
ShellEntry.addContextMenu(this._entry);
|
||||||
|
|
||||||
this._text = this._entry.clutter_text;
|
this._text = this._entry.clutter_text;
|
||||||
this._text.connect('text-changed', Lang.bind(this, this._onTextChanged));
|
|
||||||
this._text.connect('key-press-event', Lang.bind(this, this._onKeyPress));
|
this._text.connect('key-press-event', Lang.bind(this, this._onKeyPress));
|
||||||
|
|
||||||
|
this._inactiveIcon = new St.Icon({ style_class: 'search-entry-icon',
|
||||||
|
icon_name: 'edit-find',
|
||||||
|
icon_type: St.IconType.SYMBOLIC });
|
||||||
|
this._activeIcon = new St.Icon({ style_class: 'search-entry-icon',
|
||||||
|
icon_name: 'edit-clear',
|
||||||
|
icon_type: St.IconType.SYMBOLIC });
|
||||||
|
this._entry.set_secondary_icon(this._inactiveIcon);
|
||||||
|
|
||||||
|
this._iconClickedId = 0;
|
||||||
|
|
||||||
|
this._searchResults = new SearchDisplay.SearchResults(this._searchSystem, this._openSearchSystem);
|
||||||
|
this.parent(this._entry, this._searchResults.actor, _("Search"), 'edit-find');
|
||||||
|
|
||||||
|
this._text.connect('text-changed', Lang.bind(this, this._onTextChanged));
|
||||||
|
this._text.connect('key-press-event', Lang.bind(this, function (o, e) {
|
||||||
|
// We can't connect to 'activate' here because search providers
|
||||||
|
// might want to do something with the modifiers in activateDefault.
|
||||||
|
let symbol = e.get_key_symbol();
|
||||||
|
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
||||||
|
if (this._searchTimeoutId > 0) {
|
||||||
|
Mainloop.source_remove(this._searchTimeoutId);
|
||||||
|
this._doSearch();
|
||||||
|
}
|
||||||
|
this._searchResults.activateDefault();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._entry.connect('notify::mapped', Lang.bind(this, this._onMapped));
|
||||||
|
|
||||||
|
global.stage.connect('notify::key-focus', Lang.bind(this, this._onStageKeyFocusChanged));
|
||||||
|
|
||||||
|
this._capturedEventId = 0;
|
||||||
|
|
||||||
this._text.connect('key-focus-in', Lang.bind(this, function() {
|
this._text.connect('key-focus-in', Lang.bind(this, function() {
|
||||||
this._searchResults.highlightDefault(true);
|
this._searchResults.highlightDefault(true);
|
||||||
}));
|
}));
|
||||||
this._text.connect('key-focus-out', Lang.bind(this, function() {
|
this._text.connect('key-focus-out', Lang.bind(this, function() {
|
||||||
this._searchResults.highlightDefault(false);
|
this._searchResults.highlightDefault(false);
|
||||||
}));
|
}));
|
||||||
this._entry.connect('notify::mapped', Lang.bind(this, this._onMapped));
|
|
||||||
global.stage.connect('notify::key-focus', Lang.bind(this, this._onStageKeyFocusChanged));
|
|
||||||
|
|
||||||
this._inactiveIcon = new St.Icon({ style_class: 'search-entry-icon',
|
|
||||||
icon_name: 'edit-find-symbolic' });
|
|
||||||
this._activeIcon = new St.Icon({ style_class: 'search-entry-icon',
|
|
||||||
icon_name: 'edit-clear-symbolic' });
|
|
||||||
this._entry.set_secondary_icon(this._inactiveIcon);
|
|
||||||
|
|
||||||
this._iconClickedId = 0;
|
|
||||||
this._capturedEventId = 0;
|
|
||||||
|
|
||||||
this._workspacesDisplay = new WorkspacesView.WorkspacesDisplay();
|
|
||||||
this._workspacesPage = this._addPage(this._workspacesDisplay.actor, null,
|
|
||||||
_("Windows"), 'text-x-generic-symbolic');
|
|
||||||
|
|
||||||
this._appDisplay = new AppDisplay.AllAppDisplay();
|
|
||||||
this._appsPage = this._addPage(this._appDisplay.actor, null,
|
|
||||||
_("Applications"), 'system-run-symbolic');
|
|
||||||
|
|
||||||
this._searchResults = new SearchDisplay.SearchResults(this._searchSystem);
|
|
||||||
this._searchPage = this._addPage(this._searchResults.actor, this._entry,
|
|
||||||
_("Search"), 'edit-find-symbolic');
|
|
||||||
|
|
||||||
// Default search providers
|
|
||||||
// Wanda comes obviously first
|
|
||||||
this.addSearchProvider(new Wanda.WandaSearchProvider());
|
|
||||||
this.addSearchProvider(new AppDisplay.AppSearchProvider());
|
|
||||||
this.addSearchProvider(new AppDisplay.SettingsSearchProvider());
|
|
||||||
|
|
||||||
// Load remote search providers provided by applications
|
|
||||||
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
|
|
||||||
|
|
||||||
// Since the entry isn't inside the results container we install this
|
// Since the entry isn't inside the results container we install this
|
||||||
// dummy widget as the last results container child so that we can
|
// dummy widget as the last results container child so that we can
|
||||||
// include the entry in the keynav tab path
|
// include the entry in the keynav tab path...
|
||||||
this._focusTrap = new FocusTrap({ can_focus: true });
|
this._focusTrap = new St.Bin({ can_focus: true });
|
||||||
this._focusTrap.connect('key-focus-in', Lang.bind(this, function() {
|
this._focusTrap.connect('key-focus-in', Lang.bind(this, function() {
|
||||||
this._entry.grab_key_focus();
|
this._entry.grab_key_focus();
|
||||||
}));
|
}));
|
||||||
|
// ... but make it unfocusable using arrow keys keynav by making its
|
||||||
|
// bounding box always contain the possible focus source's bounding
|
||||||
|
// box since StWidget's keynav logic won't ever select it as a target
|
||||||
|
// in that case.
|
||||||
|
this._focusTrap.add_constraint(new Clutter.BindConstraint({ source: this._searchResults.actor,
|
||||||
|
coordinate: Clutter.BindCoordinate.ALL }));
|
||||||
this._searchResults.actor.add_actor(this._focusTrap);
|
this._searchResults.actor.add_actor(this._focusTrap);
|
||||||
|
|
||||||
global.focus_manager.add_group(this._searchResults.actor);
|
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 () {
|
|
||||||
this._resetShowAppsButton();
|
|
||||||
this._stageKeyPressId = global.stage.connect('key-press-event',
|
|
||||||
Lang.bind(this, this._onStageKeyPress));
|
|
||||||
}));
|
|
||||||
Main.overview.connect('hiding', Lang.bind(this,
|
|
||||||
function () {
|
|
||||||
this._resetShowAppsButton();
|
|
||||||
if (this._stageKeyPressId != 0) {
|
|
||||||
global.stage.disconnect(this._stageKeyPressId);
|
|
||||||
this._stageKeyPressId = 0;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
Lang.bind(this, this._showWithAppsPage));
|
|
||||||
},
|
|
||||||
|
|
||||||
_showWithAppsPage: function() {
|
|
||||||
Main.overview.show();
|
|
||||||
this._showAppsButton.set_checked(true);
|
|
||||||
},
|
|
||||||
|
|
||||||
show: function() {
|
|
||||||
this._activePage = this._workspacesPage;
|
|
||||||
|
|
||||||
this._appsPage.hide();
|
|
||||||
this._searchPage.hide();
|
|
||||||
this._workspacesDisplay.show();
|
|
||||||
|
|
||||||
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
|
|
||||||
Main.overview.fadeOutDesktop();
|
|
||||||
|
|
||||||
this._showPage(this._workspacesPage);
|
|
||||||
},
|
|
||||||
|
|
||||||
zoomFromOverview: function() {
|
|
||||||
this._workspacesDisplay.zoomFromOverview();
|
|
||||||
|
|
||||||
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
|
|
||||||
Main.overview.fadeInDesktop();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
hide: function() {
|
hide: function() {
|
||||||
this._workspacesDisplay.hide();
|
this.parent();
|
||||||
},
|
|
||||||
|
|
||||||
_addPage: function(actor, a11yFocus, name, a11yIcon) {
|
|
||||||
let page = new St.Bin({ child: actor,
|
|
||||||
x_align: St.Align.START,
|
|
||||||
y_align: St.Align.START,
|
|
||||||
x_fill: true,
|
|
||||||
y_fill: true });
|
|
||||||
if (a11yFocus)
|
|
||||||
Main.ctrlAltTabManager.addGroup(a11yFocus, name, a11yIcon);
|
|
||||||
else
|
|
||||||
Main.ctrlAltTabManager.addGroup(actor, name, a11yIcon,
|
|
||||||
{ proxy: this.actor,
|
|
||||||
focusCallback: Lang.bind(this,
|
|
||||||
function() {
|
|
||||||
this._a11yFocusPage(page);
|
|
||||||
})
|
|
||||||
});;
|
|
||||||
this._pageArea.add_actor(page);
|
|
||||||
return page
|
|
||||||
},
|
|
||||||
|
|
||||||
_showPage: function(page) {
|
|
||||||
if(page == this._activePage)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(this._activePage) {
|
|
||||||
Tweener.addTween(this._activePage,
|
|
||||||
{ opacity: 0,
|
|
||||||
time: 0.1,
|
|
||||||
transition: 'easeOutQuad',
|
|
||||||
onComplete: Lang.bind(this,
|
|
||||||
function() {
|
|
||||||
this._activePage.hide();
|
|
||||||
this._activePage = page;
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
page.show();
|
|
||||||
Tweener.addTween(page,
|
|
||||||
{ opacity: 255,
|
|
||||||
time: 0.1,
|
|
||||||
transition: 'easeOutQuad'
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_a11yFocusPage: function(page) {
|
|
||||||
this._showAppsButton.checked = page == this._appsPage;
|
|
||||||
page.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onShowAppsButtonToggled: function() {
|
|
||||||
if (this.active)
|
|
||||||
this.reset();
|
|
||||||
else
|
|
||||||
this._showPage(this._showAppsButton.checked ? this._appsPage
|
|
||||||
: this._workspacesPage);
|
|
||||||
},
|
|
||||||
|
|
||||||
_resetShowAppsButton: function() {
|
|
||||||
this._showAppsButton.checked = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
_onStageKeyPress: function(actor, event) {
|
|
||||||
let modifiers = event.get_state();
|
|
||||||
let symbol = event.get_key_symbol();
|
|
||||||
|
|
||||||
if (symbol == Clutter.Escape) {
|
|
||||||
if (this.active)
|
|
||||||
this.reset();
|
|
||||||
else if (this._showAppsButton.checked)
|
|
||||||
this._resetShowAppsButton();
|
|
||||||
else
|
|
||||||
Main.overview.hide();
|
|
||||||
return true;
|
|
||||||
} else if (Clutter.keysym_to_unicode(symbol) ||
|
|
||||||
(symbol == Clutter.BackSpace && this.active)) {
|
|
||||||
this.startSearch(event);
|
|
||||||
} else if (!this.active) {
|
|
||||||
if (symbol == Clutter.Tab || symbol == Clutter.Down) {
|
|
||||||
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
|
||||||
return true;
|
|
||||||
} else if (symbol == Clutter.ISO_Left_Tab) {
|
|
||||||
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_BACKWARD, false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
_searchCancelled: function() {
|
|
||||||
this._showPage(this._showAppsButton.checked ? this._appsPage
|
|
||||||
: this._workspacesPage);
|
|
||||||
|
|
||||||
// Leave the entry focused when it doesn't have any text;
|
// Leave the entry focused when it doesn't have any text;
|
||||||
// when replacing a selected search term, Clutter emits
|
// when replacing a selected search term, Clutter emits
|
||||||
@ -319,9 +227,19 @@ const ViewSelector = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
addSearchProvider: function(provider) {
|
||||||
|
this._searchSystem.registerProvider(provider);
|
||||||
|
this._searchResults.createProviderMeta(provider);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeSearchProvider: function(provider) {
|
||||||
|
this._searchSystem.unregisterProvider(provider);
|
||||||
|
this._searchResults.destroyProviderMeta(provider);
|
||||||
|
},
|
||||||
|
|
||||||
startSearch: function(event) {
|
startSearch: function(event) {
|
||||||
global.stage.set_key_focus(this._text);
|
global.stage.set_key_focus(this._text);
|
||||||
this._text.event(event, true);
|
this._text.event(event, false);
|
||||||
},
|
},
|
||||||
|
|
||||||
// the entry does not show the hint
|
// the entry does not show the hint
|
||||||
@ -345,13 +263,14 @@ const ViewSelector = new Lang.Class({
|
|||||||
this.reset();
|
this.reset();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
this._activate();
|
||||||
} else {
|
} else {
|
||||||
if (this._iconClickedId > 0)
|
if (this._iconClickedId > 0)
|
||||||
this._entry.disconnect(this._iconClickedId);
|
this._entry.disconnect(this._iconClickedId);
|
||||||
this._iconClickedId = 0;
|
this._iconClickedId = 0;
|
||||||
|
|
||||||
this._entry.set_secondary_icon(this._inactiveIcon);
|
this._entry.set_secondary_icon(this._inactiveIcon);
|
||||||
this._searchCancelled();
|
this.emit('search-cancelled');
|
||||||
}
|
}
|
||||||
if (!this.active) {
|
if (!this.active) {
|
||||||
if (this._searchTimeoutId > 0) {
|
if (this._searchTimeoutId > 0) {
|
||||||
@ -372,15 +291,6 @@ const ViewSelector = new Lang.Class({
|
|||||||
this.reset();
|
this.reset();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
|
||||||
// We can't connect to 'activate' here because search providers
|
|
||||||
// might want to do something with the modifiers in activateDefault.
|
|
||||||
if (this._searchTimeoutId > 0) {
|
|
||||||
Mainloop.source_remove(this._searchTimeoutId);
|
|
||||||
this._doSearch();
|
|
||||||
}
|
|
||||||
this._searchResults.activateDefault();
|
|
||||||
return true;
|
|
||||||
} else if (this.active) {
|
} else if (this.active) {
|
||||||
let arrowNext, nextDirection;
|
let arrowNext, nextDirection;
|
||||||
if (entry.get_text_direction() == Clutter.TextDirection.RTL) {
|
if (entry.get_text_direction() == Clutter.TextDirection.RTL) {
|
||||||
@ -430,17 +340,259 @@ const ViewSelector = new Lang.Class({
|
|||||||
let text = this._text.get_text().replace(/^\s+/g, '').replace(/\s+$/g, '');
|
let text = this._text.get_text().replace(/^\s+/g, '').replace(/\s+$/g, '');
|
||||||
this._searchResults.doSearch(text);
|
this._searchResults.doSearch(text);
|
||||||
|
|
||||||
this._showPage(this._searchPage);
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const ViewSelector = new Lang.Class({
|
||||||
|
Name: 'ViewSelector',
|
||||||
|
|
||||||
|
_init : function() {
|
||||||
|
this.actor = new St.BoxLayout({ name: 'viewSelector',
|
||||||
|
vertical: true });
|
||||||
|
|
||||||
|
// The tab bar is located at the top of the view selector and
|
||||||
|
// holds both "normal" tab labels and the search entry. The former
|
||||||
|
// is left aligned, the latter right aligned - unless the text
|
||||||
|
// direction is RTL, in which case the order is reversed.
|
||||||
|
this._tabBar = new Shell.GenericContainer();
|
||||||
|
this._tabBar.connect('get-preferred-width',
|
||||||
|
Lang.bind(this, this._getPreferredTabBarWidth));
|
||||||
|
this._tabBar.connect('get-preferred-height',
|
||||||
|
Lang.bind(this, this._getPreferredTabBarHeight));
|
||||||
|
this._tabBar.connect('allocate',
|
||||||
|
Lang.bind(this, this._allocateTabBar));
|
||||||
|
this.actor.add(this._tabBar);
|
||||||
|
|
||||||
|
// Box to hold "normal" tab labels
|
||||||
|
this._tabBox = new St.BoxLayout({ name: 'viewSelectorTabBar' });
|
||||||
|
this._tabBar.add_actor(this._tabBox);
|
||||||
|
|
||||||
|
// The searchArea just holds the entry
|
||||||
|
this._searchArea = new St.Bin({ name: 'searchArea' });
|
||||||
|
this._tabBar.add_actor(this._searchArea);
|
||||||
|
|
||||||
|
// The page area holds the tab pages. Every page is given the
|
||||||
|
// area's full allocation, so that the pages would appear on top
|
||||||
|
// of each other if the inactive ones weren't hidden.
|
||||||
|
this._pageArea = new Shell.Stack();
|
||||||
|
this.actor.add(this._pageArea, { x_fill: true,
|
||||||
|
y_fill: true,
|
||||||
|
expand: true });
|
||||||
|
|
||||||
|
this._tabs = [];
|
||||||
|
this._activeTab = null;
|
||||||
|
|
||||||
|
this._searchTab = new SearchTab();
|
||||||
|
this._searchArea.set_child(this._searchTab.title);
|
||||||
|
this._addTab(this._searchTab);
|
||||||
|
|
||||||
|
this._searchTab.connect('search-cancelled', Lang.bind(this,
|
||||||
|
function() {
|
||||||
|
this._switchTab(this._activeTab);
|
||||||
|
}));
|
||||||
|
|
||||||
|
Main.overview.connect('item-drag-begin',
|
||||||
|
Lang.bind(this, this._switchDefaultTab));
|
||||||
|
|
||||||
|
this._stageKeyPressId = 0;
|
||||||
|
Main.overview.connect('showing', Lang.bind(this,
|
||||||
|
function () {
|
||||||
|
this._switchDefaultTab();
|
||||||
|
this._stageKeyPressId = global.stage.connect('key-press-event',
|
||||||
|
Lang.bind(this, this._onStageKeyPress));
|
||||||
|
}));
|
||||||
|
Main.overview.connect('hiding', Lang.bind(this,
|
||||||
|
function () {
|
||||||
|
this._switchDefaultTab();
|
||||||
|
if (this._stageKeyPressId != 0) {
|
||||||
|
global.stage.disconnect(this._stageKeyPressId);
|
||||||
|
this._stageKeyPressId = 0;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 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.constrainY = new Clutter.BindConstraint({ source: this._pageArea,
|
||||||
|
coordinate: Clutter.BindCoordinate.Y });
|
||||||
|
this.constrainHeight = new Clutter.BindConstraint({ source: this._pageArea,
|
||||||
|
coordinate: Clutter.BindCoordinate.HEIGHT });
|
||||||
|
},
|
||||||
|
|
||||||
|
_addTab: function(tab) {
|
||||||
|
tab.page.hide();
|
||||||
|
this._pageArea.add_actor(tab.page);
|
||||||
|
tab.connect('activated', Lang.bind(this, function(tab) {
|
||||||
|
this._switchTab(tab);
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
addViewTab: function(id, title, pageActor, a11yIcon) {
|
||||||
|
let viewTab = new ViewTab(id, title, pageActor, a11yIcon);
|
||||||
|
this._tabs.push(viewTab);
|
||||||
|
this._tabBox.add(viewTab.title);
|
||||||
|
this._addTab(viewTab);
|
||||||
|
},
|
||||||
|
|
||||||
|
_switchTab: function(tab) {
|
||||||
|
let firstSwitch = this._activeTab == null;
|
||||||
|
|
||||||
|
if (this._activeTab && this._activeTab.visible) {
|
||||||
|
if (this._activeTab == tab)
|
||||||
|
return;
|
||||||
|
this._activeTab.title.remove_style_pseudo_class('selected');
|
||||||
|
this._activeTab.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tab != this._searchTab) {
|
||||||
|
tab.title.add_style_pseudo_class('selected');
|
||||||
|
this._activeTab = tab;
|
||||||
|
if (this._searchTab.visible) {
|
||||||
|
this._searchTab.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only fade when switching between tabs,
|
||||||
|
// not when setting the initially selected one.
|
||||||
|
if (!tab.visible)
|
||||||
|
tab.show(!firstSwitch);
|
||||||
|
},
|
||||||
|
|
||||||
|
switchTab: function(id) {
|
||||||
|
for (let i = 0; i < this._tabs.length; i++)
|
||||||
|
if (this._tabs[i].id == id) {
|
||||||
|
this._switchTab(this._tabs[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_switchDefaultTab: function() {
|
||||||
|
if (this._tabs.length > 0)
|
||||||
|
this._switchTab(this._tabs[0]);
|
||||||
|
},
|
||||||
|
|
||||||
|
_nextTab: function() {
|
||||||
|
if (this._tabs.length == 0 ||
|
||||||
|
this._tabs[this._tabs.length - 1] == this._activeTab)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (let i = 0; i < this._tabs.length; i++)
|
||||||
|
if (this._tabs[i] == this._activeTab) {
|
||||||
|
this._switchTab(this._tabs[i + 1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_prevTab: function() {
|
||||||
|
if (this._tabs.length == 0 || this._tabs[0] == this._activeTab)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (let i = 0; i < this._tabs.length; i++)
|
||||||
|
if (this._tabs[i] == this._activeTab) {
|
||||||
|
this._switchTab(this._tabs[i - 1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_getPreferredTabBarWidth: function(box, forHeight, alloc) {
|
||||||
|
let children = box.get_children();
|
||||||
|
for (let i = 0; i < children.length; i++) {
|
||||||
|
let [childMin, childNat] = children[i].get_preferred_width(forHeight);
|
||||||
|
alloc.min_size += childMin;
|
||||||
|
alloc.natural_size += childNat;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_getPreferredTabBarHeight: function(box, forWidth, alloc) {
|
||||||
|
let children = box.get_children();
|
||||||
|
for (let i = 0; i < children.length; i++) {
|
||||||
|
let [childMin, childNatural] = children[i].get_preferred_height(forWidth);
|
||||||
|
if (childMin > alloc.min_size)
|
||||||
|
alloc.min_size = childMin;
|
||||||
|
if (childNatural > alloc.natural_size)
|
||||||
|
alloc.natural_size = childNatural;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_allocateTabBar: function(container, box, flags) {
|
||||||
|
let allocWidth = box.x2 - box.x1;
|
||||||
|
let allocHeight = box.y2 - box.y1;
|
||||||
|
|
||||||
|
let [searchMinWidth, searchNatWidth] = this._searchArea.get_preferred_width(-1);
|
||||||
|
let [barMinWidth, barNatWidth] = this._tabBox.get_preferred_width(-1);
|
||||||
|
let childBox = new Clutter.ActorBox();
|
||||||
|
childBox.y1 = 0;
|
||||||
|
childBox.y2 = allocHeight;
|
||||||
|
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL) {
|
||||||
|
childBox.x1 = allocWidth - barNatWidth;
|
||||||
|
childBox.x2 = allocWidth;
|
||||||
|
} else {
|
||||||
|
childBox.x1 = 0;
|
||||||
|
childBox.x2 = barNatWidth;
|
||||||
|
}
|
||||||
|
this._tabBox.allocate(childBox, flags);
|
||||||
|
|
||||||
|
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL) {
|
||||||
|
childBox.x1 = 0;
|
||||||
|
childBox.x2 = searchNatWidth;
|
||||||
|
} else {
|
||||||
|
childBox.x1 = allocWidth - searchNatWidth;
|
||||||
|
childBox.x2 = allocWidth;
|
||||||
|
}
|
||||||
|
this._searchArea.allocate(childBox, flags);
|
||||||
|
|
||||||
|
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
|
||||||
|
function() {
|
||||||
|
this.constrainY.offset = this.actor.y;
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_onStageKeyPress: function(actor, event) {
|
||||||
|
let modifiers = event.get_state();
|
||||||
|
let symbol = event.get_key_symbol();
|
||||||
|
|
||||||
|
if (symbol == Clutter.Escape) {
|
||||||
|
if (this._searchTab.active)
|
||||||
|
this._searchTab.reset();
|
||||||
|
else
|
||||||
|
Main.overview.hide();
|
||||||
|
return true;
|
||||||
|
} else if (Clutter.keysym_to_unicode(symbol) ||
|
||||||
|
(symbol == Clutter.BackSpace && this._searchTab.active)) {
|
||||||
|
this._searchTab.startSearch(event);
|
||||||
|
} else if (!this._searchTab.active) {
|
||||||
|
if (modifiers & Clutter.ModifierType.CONTROL_MASK) {
|
||||||
|
if (symbol == Clutter.Page_Up) {
|
||||||
|
this._prevTab();
|
||||||
|
return true;
|
||||||
|
} else if (symbol == Clutter.Page_Down) {
|
||||||
|
this._nextTab();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (symbol == Clutter.Tab) {
|
||||||
|
this._activeTab.page.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||||
|
return true;
|
||||||
|
} else if (symbol == Clutter.ISO_Left_Tab) {
|
||||||
|
this._activeTab.page.navigate_focus(null, Gtk.DirectionType.TAB_BACKWARD, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
addSearchProvider: function(provider) {
|
addSearchProvider: function(provider) {
|
||||||
this._searchSystem.registerProvider(provider);
|
this._searchTab.addSearchProvider(provider);
|
||||||
this._searchResults.createProviderMeta(provider);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
removeSearchProvider: function(provider) {
|
removeSearchProvider: function(provider) {
|
||||||
this._searchSystem.unregisterProvider(provider);
|
this._searchTab.removeSearchProvider(provider);
|
||||||
this._searchResults.destroyProviderMeta(provider);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(ViewSelector.prototype);
|
Signals.addSignalMethods(ViewSelector.prototype);
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Clutter = imports.gi.Clutter;
|
||||||
const GdkPixbuf = imports.gi.GdkPixbuf;
|
const GdkPixbuf = imports.gi.GdkPixbuf;
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
const Gio = imports.gi.Gio;
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
const Signals = imports.signals;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
const IconGrid = imports.ui.iconGrid;
|
const IconGrid = imports.ui.iconGrid;
|
||||||
const Layout = imports.ui.layout;
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Search = imports.ui.search;
|
const Search = imports.ui.search;
|
||||||
|
|
||||||
@ -48,12 +49,23 @@ const WandaIcon = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
createIcon: function(iconSize) {
|
createIcon: function(iconSize) {
|
||||||
|
if (this._animations)
|
||||||
|
this._animations.destroy();
|
||||||
|
|
||||||
if (!this._imageFile) {
|
if (!this._imageFile) {
|
||||||
return new St.Icon({ icon_name: 'face-smile',
|
return new St.Icon({ icon_name: 'face-smile',
|
||||||
icon_size: iconSize });
|
icon_type: St.IconType.FULLCOLOR,
|
||||||
|
icon_size: iconSize
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this._animations = St.TextureCache.get_default().load_sliced_image(this._imageFile, this._imgWidth, this._imgHeight);
|
this._animations = St.TextureCache.get_default().load_sliced_image(this._imageFile, this._imgWidth, this._imgHeight);
|
||||||
|
this._animations.connect('destroy', Lang.bind(this, function() {
|
||||||
|
if (this._timeoutId)
|
||||||
|
GLib.source_remove(this._timeoutId);
|
||||||
|
this._timeoutId = 0;
|
||||||
|
this._animations = null;
|
||||||
|
}));
|
||||||
this._animations.connect('notify::mapped', Lang.bind(this, function() {
|
this._animations.connect('notify::mapped', Lang.bind(this, function() {
|
||||||
if (this._animations.mapped && !this._timeoutId) {
|
if (this._animations.mapped && !this._timeoutId) {
|
||||||
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, FISH_SPEED, Lang.bind(this, this._update));
|
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, FISH_SPEED, Lang.bind(this, this._update));
|
||||||
@ -66,16 +78,11 @@ const WandaIcon = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this._i = 0;
|
||||||
|
|
||||||
return this._animations;
|
return this._animations;
|
||||||
},
|
},
|
||||||
|
|
||||||
_createIconTexture: function(size) {
|
|
||||||
if (size == this.iconSize)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.parent(size);
|
|
||||||
},
|
|
||||||
|
|
||||||
_update: function() {
|
_update: function() {
|
||||||
let n = this._animations.get_n_children();
|
let n = this._animations.get_n_children();
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
@ -135,18 +142,17 @@ const FortuneDialog = new Lang.Class({
|
|||||||
this._button.connect('clicked', Lang.bind(this, this.destroy));
|
this._button.connect('clicked', Lang.bind(this, this.destroy));
|
||||||
this._button.child = this._box;
|
this._button.child = this._box;
|
||||||
|
|
||||||
this._bin = new St.Bin({ x_align: St.Align.MIDDLE,
|
let monitor = Main.layoutManager.primaryMonitor;
|
||||||
y_align: St.Align.MIDDLE });
|
|
||||||
this._bin.add_constraint(new Layout.MonitorConstraint({ primary: true }));
|
|
||||||
this._bin.add_actor(this._button);
|
|
||||||
|
|
||||||
Main.layoutManager.addChrome(this._bin);
|
Main.layoutManager.addChrome(this._button);
|
||||||
|
this._button.set_position(Math.floor(monitor.width / 2 - this._button.width / 2),
|
||||||
|
Math.floor(monitor.height / 2 - this._button.height / 2));
|
||||||
|
|
||||||
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 10, Lang.bind(this, this.destroy));
|
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 10, Lang.bind(this, this.destroy));
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
this._bin.destroy();
|
this._button.destroy();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -167,8 +173,16 @@ const WandaSearchProvider = new Lang.Class({
|
|||||||
// only one which speaks the truth!
|
// only one which speaks the truth!
|
||||||
'name': capitalize(fish[0]),
|
'name': capitalize(fish[0]),
|
||||||
'createIcon': function(iconSize) {
|
'createIcon': function(iconSize) {
|
||||||
return new St.Icon({ gicon: Gio.icon_new_for_string('face-smile'),
|
// for DND only (maybe could be improved)
|
||||||
icon_size: iconSize });
|
// DON'T use St.Icon here, it crashes the shell
|
||||||
|
// (dnd.js code assumes it can query the actor size
|
||||||
|
// without parenting it, while StWidget accesses
|
||||||
|
// StThemeNode in get_preferred_width/height, which
|
||||||
|
// triggers an assertion failure)
|
||||||
|
return St.TextureCache.get_default().load_icon_name(null,
|
||||||
|
'face-smile',
|
||||||
|
St.IconType.FULLCOLOR,
|
||||||
|
iconSize);
|
||||||
}
|
}
|
||||||
}]);
|
}]);
|
||||||
},
|
},
|
||||||
|
@ -15,7 +15,8 @@ const Tweener = imports.ui.tweener;
|
|||||||
|
|
||||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
||||||
const WINDOW_ANIMATION_TIME = 0.25;
|
const WINDOW_ANIMATION_TIME = 0.25;
|
||||||
const DIM_BRIGHTNESS = -0.3;
|
const DIM_DESATURATION = 0.6;
|
||||||
|
const DIM_BRIGHTNESS = -0.1;
|
||||||
const DIM_TIME = 0.500;
|
const DIM_TIME = 0.500;
|
||||||
const UNDIM_TIME = 0.250;
|
const UNDIM_TIME = 0.250;
|
||||||
|
|
||||||
@ -24,27 +25,23 @@ const WindowDimmer = new Lang.Class({
|
|||||||
Name: 'WindowDimmer',
|
Name: 'WindowDimmer',
|
||||||
|
|
||||||
_init: function(actor) {
|
_init: function(actor) {
|
||||||
|
this._desaturateEffect = new Clutter.DesaturateEffect();
|
||||||
this._brightnessEffect = new Clutter.BrightnessContrastEffect();
|
this._brightnessEffect = new Clutter.BrightnessContrastEffect();
|
||||||
|
actor.add_effect(this._desaturateEffect);
|
||||||
actor.add_effect(this._brightnessEffect);
|
actor.add_effect(this._brightnessEffect);
|
||||||
this.actor = actor;
|
this.actor = actor;
|
||||||
this._enabled = true;
|
|
||||||
this._dimFactor = 0.0;
|
this._dimFactor = 0.0;
|
||||||
this._syncEnabled();
|
|
||||||
},
|
|
||||||
|
|
||||||
_syncEnabled: function() {
|
|
||||||
this._brightnessEffect.enabled = (this._enabled && this._dimFactor > 0);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setEnabled: function(enabled) {
|
setEnabled: function(enabled) {
|
||||||
this._enabled = enabled;
|
this._desaturateEffect.enabled = enabled;
|
||||||
this._syncEnabled();
|
this._brightnessEffect.enabled = enabled;
|
||||||
},
|
},
|
||||||
|
|
||||||
set dimFactor(factor) {
|
set dimFactor(factor) {
|
||||||
this._dimFactor = factor;
|
this._dimFactor = factor;
|
||||||
|
this._desaturateEffect.set_factor(factor * DIM_DESATURATION);
|
||||||
this._brightnessEffect.set_brightness(factor * DIM_BRIGHTNESS);
|
this._brightnessEffect.set_brightness(factor * DIM_BRIGHTNESS);
|
||||||
this._syncEnabled();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
get dimFactor() {
|
get dimFactor() {
|
||||||
@ -53,17 +50,10 @@ const WindowDimmer = new Lang.Class({
|
|||||||
});
|
});
|
||||||
|
|
||||||
function getWindowDimmer(actor) {
|
function getWindowDimmer(actor) {
|
||||||
let enabled = Meta.prefs_get_attach_modal_dialogs();
|
if (!actor._windowDimmer)
|
||||||
if (actor._windowDimmer)
|
actor._windowDimmer = new WindowDimmer(actor);
|
||||||
actor._windowDimmer.setEnabled(enabled);
|
|
||||||
|
|
||||||
if (enabled) {
|
return actor._windowDimmer;
|
||||||
if (!actor._windowDimmer)
|
|
||||||
actor._windowDimmer = new WindowDimmer(actor);
|
|
||||||
return actor._windowDimmer;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const WindowManager = new Lang.Class({
|
const WindowManager = new Lang.Class({
|
||||||
@ -270,7 +260,9 @@ const WindowManager = new Lang.Class({
|
|||||||
if (!actor)
|
if (!actor)
|
||||||
return;
|
return;
|
||||||
let dimmer = getWindowDimmer(actor);
|
let dimmer = getWindowDimmer(actor);
|
||||||
if (!dimmer)
|
let enabled = Meta.prefs_get_attach_modal_dialogs();
|
||||||
|
dimmer.setEnabled(enabled);
|
||||||
|
if (!enabled)
|
||||||
return;
|
return;
|
||||||
Tweener.addTween(dimmer,
|
Tweener.addTween(dimmer,
|
||||||
{ dimFactor: 1.0,
|
{ dimFactor: 1.0,
|
||||||
@ -284,12 +276,15 @@ const WindowManager = new Lang.Class({
|
|||||||
if (!actor)
|
if (!actor)
|
||||||
return;
|
return;
|
||||||
let dimmer = getWindowDimmer(actor);
|
let dimmer = getWindowDimmer(actor);
|
||||||
if (!dimmer)
|
let enabled = Meta.prefs_get_attach_modal_dialogs();
|
||||||
|
dimmer.setEnabled(enabled);
|
||||||
|
if (!enabled)
|
||||||
return;
|
return;
|
||||||
Tweener.addTween(dimmer,
|
Tweener.addTween(dimmer,
|
||||||
{ dimFactor: 0.0,
|
{ dimFactor: 0.0,
|
||||||
time: UNDIM_TIME,
|
time: UNDIM_TIME,
|
||||||
transition: 'linear' });
|
transition: 'linear'
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_mapWindow : function(shellwm, actor) {
|
_mapWindow : function(shellwm, actor) {
|
||||||
@ -309,29 +304,12 @@ const WindowManager = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
if (actor.meta_window.is_attached_dialog()) {
|
if (actor.meta_window.is_attached_dialog()) {
|
||||||
this._checkDimming(actor.get_meta_window().get_transient_for());
|
this._checkDimming(actor.get_meta_window().get_transient_for());
|
||||||
if (this._shouldAnimate()) {
|
|
||||||
actor.set_scale(1.0, 0.0);
|
|
||||||
actor.scale_gravity = Clutter.Gravity.CENTER;
|
|
||||||
actor.show();
|
|
||||||
this._mapping.push(actor);
|
|
||||||
|
|
||||||
Tweener.addTween(actor,
|
if (!this._shouldAnimate()) {
|
||||||
{ scale_y: 1,
|
shellwm.completed_map(actor);
|
||||||
time: WINDOW_ANIMATION_TIME,
|
|
||||||
transition: "easeOutQuad",
|
|
||||||
onComplete: this._mapWindowDone,
|
|
||||||
onCompleteScope: this,
|
|
||||||
onCompleteParams: [shellwm, actor],
|
|
||||||
onOverwrite: this._mapWindowOverwrite,
|
|
||||||
onOverwriteScope: this,
|
|
||||||
onOverwriteParams: [shellwm, actor]
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
shellwm.completed_map(actor);
|
} else if (!this._shouldAnimateActor(actor)) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this._shouldAnimateActor(actor)) {
|
|
||||||
shellwm.completed_map(actor);
|
shellwm.completed_map(actor);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -387,8 +365,7 @@ const WindowManager = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
actor.set_scale(1.0, 1.0);
|
actor.opacity = 255;
|
||||||
actor.scale_gravity = Clutter.Gravity.CENTER;
|
|
||||||
actor.show();
|
actor.show();
|
||||||
this._destroying.push(actor);
|
this._destroying.push(actor);
|
||||||
|
|
||||||
@ -398,7 +375,7 @@ const WindowManager = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
Tweener.addTween(actor,
|
Tweener.addTween(actor,
|
||||||
{ scale_y: 0,
|
{ opacity: 0,
|
||||||
time: WINDOW_ANIMATION_TIME,
|
time: WINDOW_ANIMATION_TIME,
|
||||||
transition: "easeOutQuad",
|
transition: "easeOutQuad",
|
||||||
onComplete: this._destroyWindowDone,
|
onComplete: this._destroyWindowDone,
|
||||||
|
@ -33,13 +33,21 @@ const DRAGGING_WINDOW_OPACITY = 100;
|
|||||||
const BUTTON_LAYOUT_SCHEMA = 'org.gnome.shell.overrides';
|
const BUTTON_LAYOUT_SCHEMA = 'org.gnome.shell.overrides';
|
||||||
const BUTTON_LAYOUT_KEY = 'button-layout';
|
const BUTTON_LAYOUT_KEY = 'button-layout';
|
||||||
|
|
||||||
// When calculating a layout, we calculate the scale of windows and the percent
|
// Define a layout scheme for small window counts. For larger
|
||||||
// of the available area the new layout uses. If the values for the new layout,
|
// counts we fall back to an algorithm. We need more schemes here
|
||||||
// when weighted with the values as below, are worse than the previous layout's,
|
// unless we have a really good algorithm.
|
||||||
// we stop looking for a new layout and use the previous layout.
|
|
||||||
// Otherwise, we keep looking for a new layout.
|
// Each triplet is [xCenter, yCenter, scale] where the scale
|
||||||
const LAYOUT_SCALE_WEIGHT = 1;
|
// is relative to the width of the workspace.
|
||||||
const LAYOUT_SPACE_WEIGHT = 0.1;
|
const POSITIONS = {
|
||||||
|
1: [[0.5, 0.5, 0.95]],
|
||||||
|
2: [[0.25, 0.5, 0.48], [0.75, 0.5, 0.48]],
|
||||||
|
3: [[0.25, 0.25, 0.48], [0.75, 0.25, 0.48], [0.5, 0.75, 0.48]],
|
||||||
|
4: [[0.25, 0.25, 0.47], [0.75, 0.25, 0.47], [0.75, 0.75, 0.47], [0.25, 0.75, 0.47]],
|
||||||
|
5: [[0.165, 0.25, 0.32], [0.495, 0.25, 0.32], [0.825, 0.25, 0.32], [0.25, 0.75, 0.32], [0.75, 0.75, 0.32]]
|
||||||
|
};
|
||||||
|
// Used in _orderWindowsPermutations, 5! = 120 which is probably the highest we can go
|
||||||
|
const POSITIONING_PERMUTATIONS_MAX = 5;
|
||||||
|
|
||||||
function _interpolate(start, end, step) {
|
function _interpolate(start, end, step) {
|
||||||
return start + (end - start) * step;
|
return start + (end - start) * step;
|
||||||
@ -159,24 +167,6 @@ const WindowClone = new Lang.Class({
|
|||||||
this._selected = false;
|
this._selected = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
get slot() {
|
|
||||||
let x, y, w, h;
|
|
||||||
|
|
||||||
if (this.inDrag) {
|
|
||||||
x = this.dragOrigX;
|
|
||||||
y = this.dragOrigY;
|
|
||||||
w = this.actor.width * this.dragOrigScale;
|
|
||||||
h = this.actor.height * this.dragOrigScale;
|
|
||||||
} else {
|
|
||||||
x = this.actor.x;
|
|
||||||
y = this.actor.y;
|
|
||||||
w = this.actor.width * this.actor.scale_x;
|
|
||||||
h = this.actor.height * this.actor.scale_y;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [x, y, w, h];
|
|
||||||
},
|
|
||||||
|
|
||||||
setStackAbove: function (actor) {
|
setStackAbove: function (actor) {
|
||||||
this._stackAbove = actor;
|
this._stackAbove = actor;
|
||||||
if (this.inDrag || this._zooming)
|
if (this.inDrag || this._zooming)
|
||||||
@ -453,11 +443,6 @@ const WindowOverlay = new Lang.Class({
|
|||||||
this._updateCaptionId = metaWindow.connect('notify::title',
|
this._updateCaptionId = metaWindow.connect('notify::title',
|
||||||
Lang.bind(this, function(w) {
|
Lang.bind(this, function(w) {
|
||||||
this.title.text = w.title;
|
this.title.text = w.title;
|
||||||
// we need this for the next call to get_preferred_width
|
|
||||||
// to return useful results
|
|
||||||
this.title.set_size(-1, -1);
|
|
||||||
|
|
||||||
this._repositionSelf();
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let button = new St.Button({ style_class: 'window-close' });
|
let button = new St.Button({ style_class: 'window-close' });
|
||||||
@ -514,19 +499,18 @@ const WindowOverlay = new Lang.Class({
|
|||||||
this.title.opacity = 0;
|
this.title.opacity = 0;
|
||||||
this._parentActor.raise_top();
|
this._parentActor.raise_top();
|
||||||
Tweener.addTween(this.title,
|
Tweener.addTween(this.title,
|
||||||
{ opacity: 255,
|
{ opacity: 255,
|
||||||
time: CLOSE_BUTTON_FADE_TIME,
|
time: CLOSE_BUTTON_FADE_TIME,
|
||||||
transition: 'easeOutQuad' });
|
transition: 'easeOutQuad' });
|
||||||
|
},
|
||||||
|
|
||||||
|
chromeWidth: function () {
|
||||||
|
return this.closeButton.width - this.closeButton._overlap;
|
||||||
},
|
},
|
||||||
|
|
||||||
chromeHeights: function () {
|
chromeHeights: function () {
|
||||||
return [this.closeButton.height - this.closeButton._overlap,
|
return [this.closeButton.height - this.closeButton._overlap,
|
||||||
this.title.height + this.title._spacing];
|
this.title.height + this.title._spacing];
|
||||||
},
|
|
||||||
|
|
||||||
_repositionSelf: function() {
|
|
||||||
let [cloneX, cloneY, cloneWidth, cloneHeight] = this._windowClone.slot;
|
|
||||||
this.updatePositions(cloneX, cloneY, cloneWidth, cloneHeight, false);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -566,8 +550,9 @@ const WindowOverlay = new Lang.Class({
|
|||||||
else
|
else
|
||||||
button.set_position(Math.floor(buttonX), Math.floor(buttonY));
|
button.set_position(Math.floor(buttonX), Math.floor(buttonY));
|
||||||
|
|
||||||
let [titleMinWidth, titleNatWidth] = title.get_preferred_width(-1);
|
if (!title.fullWidth)
|
||||||
let titleWidth = Math.max(titleMinWidth, Math.min(titleNatWidth, cloneWidth));
|
title.fullWidth = title.width;
|
||||||
|
let titleWidth = Math.min(title.fullWidth, cloneWidth);
|
||||||
|
|
||||||
let titleX = cloneX + (cloneWidth - titleWidth) / 2;
|
let titleX = cloneX + (cloneWidth - titleWidth) / 2;
|
||||||
let titleY = cloneY + cloneHeight + title._spacing;
|
let titleY = cloneY + cloneHeight + title._spacing;
|
||||||
@ -683,280 +668,6 @@ const WindowPositionFlags = {
|
|||||||
ANIMATE: 1 << 1
|
ANIMATE: 1 << 1
|
||||||
};
|
};
|
||||||
|
|
||||||
const LayoutStrategy = new Lang.Class({
|
|
||||||
Name: 'LayoutStrategy',
|
|
||||||
Abstract: true,
|
|
||||||
|
|
||||||
_init: function(monitor, rowSpacing, columnSpacing, bottomPadding) {
|
|
||||||
this._monitor = monitor;
|
|
||||||
this._rowSpacing = rowSpacing;
|
|
||||||
this._columnSpacing = columnSpacing;
|
|
||||||
this._bottomPadding = bottomPadding;
|
|
||||||
},
|
|
||||||
|
|
||||||
_newRow: function() {
|
|
||||||
// Row properties:
|
|
||||||
//
|
|
||||||
// * x, y are the position of row, relative to area
|
|
||||||
//
|
|
||||||
// * width, height are the scaled versions of fullWidth, fullHeight
|
|
||||||
//
|
|
||||||
// * width also has the spacing in between windows. It's not in
|
|
||||||
// fullWidth, as the spacing is constant, whereas fullWidth is
|
|
||||||
// meant to be scaled
|
|
||||||
//
|
|
||||||
// * neither height/fullHeight have any sort of spacing or padding
|
|
||||||
//
|
|
||||||
// * if cellWidth is present, all windows in the row will occupy
|
|
||||||
// the space of cellWidth, centered.
|
|
||||||
return { x: 0, y: 0,
|
|
||||||
width: 0, height: 0,
|
|
||||||
fullWidth: 0, fullHeight: 0,
|
|
||||||
cellWidth: 0,
|
|
||||||
windows: [] };
|
|
||||||
},
|
|
||||||
|
|
||||||
// Compute the size and fancy scale for @window using the
|
|
||||||
// base scale, @scale.
|
|
||||||
//
|
|
||||||
// Returns a list structure: [ scaledWidth, scaledHeight, fancyScale ]
|
|
||||||
// where scaledWidth and scaledHeight are the window's
|
|
||||||
// width and height, scaled by fancyScale for convenience.
|
|
||||||
_computeWindowSizeAndScale: function(window, scale) {
|
|
||||||
let width = window.actor.width;
|
|
||||||
let height = window.actor.height;
|
|
||||||
let ratio;
|
|
||||||
|
|
||||||
if (width > height)
|
|
||||||
ratio = width / this._monitor.width;
|
|
||||||
else
|
|
||||||
ratio = height / this._monitor.height;
|
|
||||||
|
|
||||||
let fancyScale = (2 / (1 + ratio)) * scale;
|
|
||||||
return [width * fancyScale, height * fancyScale, fancyScale];
|
|
||||||
},
|
|
||||||
|
|
||||||
// Compute the size of each row, by assigning to the properties
|
|
||||||
// row.width, row.height, row.fullWidth, row.fullHeight, and
|
|
||||||
// (optionally) row.cellWidth, for each row in @layout.rows.
|
|
||||||
// This method is intended to be called by subclasses.
|
|
||||||
_computeRowSizes: function(layout) {
|
|
||||||
throw new Error('_computeRowSizes not implemented');
|
|
||||||
},
|
|
||||||
|
|
||||||
// Compute strategy-specific window slots for each window in
|
|
||||||
// @windows, given the @layout. The strategy may also use @layout
|
|
||||||
// as strategy-specific storage.
|
|
||||||
//
|
|
||||||
// This must calculate:
|
|
||||||
// * maxColumns - The maximum number of columns used by the layout.
|
|
||||||
// * gridWidth - The total width used by the grid, unscaled, unspaced.
|
|
||||||
// * gridHeight - The totial height used by the grid, unscaled, unspaced.
|
|
||||||
// * rows - A list of rows, which should be instantiated by _newRow.
|
|
||||||
computeLayout: function(windows, layout) {
|
|
||||||
throw new Error('computeLayout not implemented');
|
|
||||||
},
|
|
||||||
|
|
||||||
// Given @layout, compute the overall scale and space of the layout.
|
|
||||||
// The scale is the individual, non-fancy scale of each window, and
|
|
||||||
// the space is the percentage of the available area eventually
|
|
||||||
// used by the layout.
|
|
||||||
|
|
||||||
// This method does not return anything, but instead installs
|
|
||||||
// the properties "scale" and "space" on @layout directly.
|
|
||||||
//
|
|
||||||
// Make sure to call this methods before calling computeWindowSlots(),
|
|
||||||
// as it depends on the scale property installed in @layout here.
|
|
||||||
computeScaleAndSpace: function(layout) {
|
|
||||||
let area = layout.area;
|
|
||||||
|
|
||||||
let hspacing = (layout.maxColumns - 1) * this._columnSpacing;
|
|
||||||
let vspacing = (layout.numRows - 1) * this._rowSpacing + this._bottomPadding;
|
|
||||||
|
|
||||||
let spacedWidth = area.width - hspacing;
|
|
||||||
let spacedHeight = area.height - vspacing;
|
|
||||||
|
|
||||||
let horizontalScale = spacedWidth / layout.gridWidth;
|
|
||||||
let verticalScale = spacedHeight / layout.gridHeight;
|
|
||||||
|
|
||||||
// Thumbnails should be less than 70% of the original size
|
|
||||||
let scale = Math.min(horizontalScale, verticalScale, WINDOW_CLONE_MAXIMUM_SCALE);
|
|
||||||
|
|
||||||
let scaledLayoutWidth = layout.gridWidth * scale + hspacing;
|
|
||||||
let scaledLayoutHeight = layout.gridHeight * scale + vspacing;
|
|
||||||
let space = (scaledLayoutWidth * scaledLayoutHeight) / (area.width * area.height);
|
|
||||||
|
|
||||||
layout.scale = scale;
|
|
||||||
layout.space = space;
|
|
||||||
},
|
|
||||||
|
|
||||||
computeWindowSlots: function(layout, area) {
|
|
||||||
this._computeRowSizes(layout);
|
|
||||||
|
|
||||||
let { rows: rows, scale: scale, state: state } = layout;
|
|
||||||
|
|
||||||
let slots = [];
|
|
||||||
|
|
||||||
let y = 0;
|
|
||||||
for (let i = 0; i < rows.length; i++) {
|
|
||||||
let row = rows[i];
|
|
||||||
row.x = area.x + (area.width - row.width) / 2;
|
|
||||||
row.y = area.y + y;
|
|
||||||
y += row.height + this._rowSpacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
let height = y - this._rowSpacing + this._bottomPadding;
|
|
||||||
let baseY = (area.height - height) / 2;
|
|
||||||
|
|
||||||
for (let i = 0; i < rows.length; i++) {
|
|
||||||
let row = rows[i];
|
|
||||||
row.y += baseY;
|
|
||||||
let baseX = row.x;
|
|
||||||
for (let j = 0; j < row.windows.length; j++) {
|
|
||||||
let window = row.windows[j];
|
|
||||||
|
|
||||||
let [width, height, s] = this._computeWindowSizeAndScale(window, scale);
|
|
||||||
let y = row.y + row.height - height;
|
|
||||||
|
|
||||||
let x = baseX;
|
|
||||||
if (row.cellWidth) {
|
|
||||||
x += (row.cellWidth - width) / 2;
|
|
||||||
width = row.cellWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
slots.push([x, y, s]);
|
|
||||||
baseX += width + this._columnSpacing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return slots;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const UnalignedLayoutStrategy = new Lang.Class({
|
|
||||||
Name: 'UnalignedLayoutStrategy',
|
|
||||||
Extends: LayoutStrategy,
|
|
||||||
|
|
||||||
_computeRowSizes: function(layout) {
|
|
||||||
let { rows: rows, scale: scale } = layout;
|
|
||||||
for (let i = 0; i < rows.length; i++) {
|
|
||||||
let row = rows[i];
|
|
||||||
row.width = row.fullWidth * scale + (row.windows.length - 1) * this._columnSpacing;
|
|
||||||
row.height = row.fullHeight * scale;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_keepSameRow: function(row, window, width, idealRowWidth) {
|
|
||||||
if (row.fullWidth + width <= idealRowWidth)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
let oldRatio = row.fullWidth / idealRowWidth;
|
|
||||||
let newRatio = (row.fullWidth + width) / idealRowWidth;
|
|
||||||
|
|
||||||
if (Math.abs(1 - newRatio) < Math.abs(1 - oldRatio))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
computeLayout: function(windows, layout) {
|
|
||||||
let numRows = layout.numRows;
|
|
||||||
|
|
||||||
let rows = [];
|
|
||||||
let totalWidth = 0;
|
|
||||||
for (let i = 0; i < windows.length; i++) {
|
|
||||||
totalWidth += windows[i].actor.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
let idealRowWidth = totalWidth / numRows;
|
|
||||||
let windowIdx = 0;
|
|
||||||
for (let i = 0; i < numRows; i++) {
|
|
||||||
let col = 0;
|
|
||||||
let row = this._newRow();
|
|
||||||
rows.push(row);
|
|
||||||
|
|
||||||
for (; windowIdx < windows.length; windowIdx++) {
|
|
||||||
let window = windows[windowIdx];
|
|
||||||
let [width, height] = this._computeWindowSizeAndScale(window, 1);
|
|
||||||
row.fullHeight = Math.max(row.fullHeight, height);
|
|
||||||
|
|
||||||
// either new width is < idealWidth or new width is nearer from idealWidth then oldWidth
|
|
||||||
if (this._keepSameRow(row, window, width, idealRowWidth) || (i == numRows - 1)) {
|
|
||||||
row.windows.push(window);
|
|
||||||
row.fullWidth += width;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let gridHeight = 0;
|
|
||||||
let maxRow;
|
|
||||||
for (let i = 0; i < numRows; i++) {
|
|
||||||
let row = rows[i];
|
|
||||||
if (!maxRow || row.fullWidth > maxRow.fullWidth)
|
|
||||||
maxRow = row;
|
|
||||||
gridHeight += row.fullHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
layout.rows = rows;
|
|
||||||
layout.maxColumns = maxRow.windows.length;
|
|
||||||
layout.gridWidth = maxRow.fullWidth;
|
|
||||||
layout.gridHeight = gridHeight;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const GridLayoutStrategy = new Lang.Class({
|
|
||||||
Name: 'GridLayoutStrategy',
|
|
||||||
Extends: LayoutStrategy,
|
|
||||||
|
|
||||||
_computeRowSizes: function(layout) {
|
|
||||||
let { rows: rows, scale: scale } = layout;
|
|
||||||
|
|
||||||
let gridWidth = layout.numColumns * layout.maxWindowWidth;
|
|
||||||
let hspacing = (layout.numColumns - 1) * this._columnSpacing;
|
|
||||||
for (let i = 0; i < rows.length; i++) {
|
|
||||||
let row = rows[i];
|
|
||||||
row.fullWidth = layout.gridWidth;
|
|
||||||
row.fullHeight = layout.maxWindowHeight;
|
|
||||||
|
|
||||||
row.width = row.fullWidth * scale + hspacing;
|
|
||||||
row.height = row.fullHeight * scale;
|
|
||||||
row.cellWidth = layout.maxWindowWidth * scale;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
computeLayout: function(windows, layout) {
|
|
||||||
let { numRows: numRows, numColumns: numColumns } = layout;
|
|
||||||
let rows = [];
|
|
||||||
let windowIdx = 0;
|
|
||||||
|
|
||||||
let maxWindowWidth = 0;
|
|
||||||
let maxWindowHeight = 0;
|
|
||||||
for (let i = 0; i < numRows; i++) {
|
|
||||||
let row = this._newRow();
|
|
||||||
rows.push(row);
|
|
||||||
for (; windowIdx < windows.length; windowIdx++) {
|
|
||||||
if (row.windows.length >= numColumns)
|
|
||||||
break;
|
|
||||||
|
|
||||||
let window = windows[windowIdx];
|
|
||||||
row.windows.push(window);
|
|
||||||
|
|
||||||
let [width, height] = this._computeWindowSizeAndScale(window, 1);
|
|
||||||
maxWindowWidth = Math.max(maxWindowWidth, width);
|
|
||||||
maxWindowHeight = Math.max(maxWindowHeight, height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
layout.rows = rows;
|
|
||||||
layout.maxColumns = numColumns;
|
|
||||||
layout.gridWidth = numColumns * maxWindowWidth;
|
|
||||||
layout.gridHeight = numRows * maxWindowHeight;
|
|
||||||
layout.maxWindowWidth = maxWindowWidth;
|
|
||||||
layout.maxWindowHeight = maxWindowHeight;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @metaWorkspace: a #Meta.Workspace, or null
|
* @metaWorkspace: a #Meta.Workspace, or null
|
||||||
*/
|
*/
|
||||||
@ -978,7 +689,7 @@ const Workspace = new Lang.Class({
|
|||||||
// Without this the drop area will be overlapped.
|
// Without this the drop area will be overlapped.
|
||||||
this._windowOverlaysGroup.set_size(0, 0);
|
this._windowOverlaysGroup.set_size(0, 0);
|
||||||
|
|
||||||
this.actor = new St.Widget({ style_class: 'window-picker' });
|
this.actor = new Clutter.Group();
|
||||||
this.actor.set_size(0, 0);
|
this.actor.set_size(0, 0);
|
||||||
|
|
||||||
this._dropRect = new Clutter.Rectangle({ opacity: 0 });
|
this._dropRect = new Clutter.Rectangle({ opacity: 0 });
|
||||||
@ -1009,17 +720,12 @@ const Workspace = new Lang.Class({
|
|||||||
Lang.bind(this, this._windowRemoved));
|
Lang.bind(this, this._windowRemoved));
|
||||||
}
|
}
|
||||||
this._windowEnteredMonitorId = global.screen.connect('window-entered-monitor',
|
this._windowEnteredMonitorId = global.screen.connect('window-entered-monitor',
|
||||||
Lang.bind(this, this._windowEnteredMonitor));
|
Lang.bind(this, this._windowEnteredMonitor));
|
||||||
this._windowLeftMonitorId = global.screen.connect('window-left-monitor',
|
this._windowLeftMonitorId = global.screen.connect('window-left-monitor',
|
||||||
Lang.bind(this, this._windowLeftMonitor));
|
Lang.bind(this, this._windowLeftMonitor));
|
||||||
this._repositionWindowsId = 0;
|
this._repositionWindowsId = 0;
|
||||||
|
|
||||||
this.leavingOverview = false;
|
this.leavingOverview = false;
|
||||||
|
|
||||||
this._positionWindowsFlags = 0;
|
|
||||||
this._positionWindowsId = 0;
|
|
||||||
|
|
||||||
this._currentLayout = null;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setGeometry: function(x, y, width, height) {
|
setGeometry: function(x, y, width, height) {
|
||||||
@ -1028,13 +734,15 @@ const Workspace = new Lang.Class({
|
|||||||
this._width = width;
|
this._width = width;
|
||||||
this._height = height;
|
this._height = height;
|
||||||
|
|
||||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
// This is sometimes called during allocation, so we do this later
|
||||||
this._dropRect.set_position(x, y);
|
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
|
||||||
this._dropRect.set_size(width, height);
|
function () {
|
||||||
return false;
|
this._dropRect.set_position(x, y);
|
||||||
}));
|
this._dropRect.set_size(width, height);
|
||||||
|
this.positionWindows(WindowPositionFlags.ANIMATE);
|
||||||
|
return false;
|
||||||
|
}));
|
||||||
|
|
||||||
this.positionWindows(WindowPositionFlags.ANIMATE);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_lookupIndex: function (metaWindow) {
|
_lookupIndex: function (metaWindow) {
|
||||||
@ -1054,15 +762,238 @@ const Workspace = new Lang.Class({
|
|||||||
return this._windows.length == 0;
|
return this._windows.length == 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Only use this for n <= 20 say
|
||||||
|
_factorial: function(n) {
|
||||||
|
let result = 1;
|
||||||
|
for (let i = 2; i <= n; i++)
|
||||||
|
result *= i;
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _permutation:
|
||||||
|
* @permutationIndex: An integer from [0, list.length!)
|
||||||
|
* @list: (inout): Array of objects to permute; will be modified in place
|
||||||
|
*
|
||||||
|
* Given an integer between 0 and length of array, re-order the array in-place
|
||||||
|
* into a permutation denoted by the index.
|
||||||
|
*/
|
||||||
|
_permutation: function(permutationIndex, list) {
|
||||||
|
for (let j = 2; j <= list.length; j++) {
|
||||||
|
let firstIndex = (permutationIndex % j);
|
||||||
|
let secondIndex = j - 1;
|
||||||
|
// Swap
|
||||||
|
let tmp = list[firstIndex];
|
||||||
|
list[firstIndex] = list[secondIndex];
|
||||||
|
list[secondIndex] = tmp;
|
||||||
|
permutationIndex = Math.floor(permutationIndex / j);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _forEachPermutations:
|
||||||
|
* @list: Array
|
||||||
|
* @func: Function which takes a single array argument
|
||||||
|
*
|
||||||
|
* Call @func with each permutation of @list as an argument.
|
||||||
|
*/
|
||||||
|
_forEachPermutations: function(list, func) {
|
||||||
|
let nCombinations = this._factorial(list.length);
|
||||||
|
for (let i = 0; i < nCombinations; i++) {
|
||||||
|
let listCopy = list.concat();
|
||||||
|
this._permutation(i, listCopy);
|
||||||
|
func(listCopy);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _computeWindowMotion:
|
||||||
|
* @actor: A #WindowClone's #ClutterActor
|
||||||
|
* @slot: An element of #POSITIONS
|
||||||
|
* @slotGeometry: Layout of @slot
|
||||||
|
*
|
||||||
|
* Returns a number corresponding to how much perceived motion
|
||||||
|
* would be involved in moving the window to the given slot.
|
||||||
|
* Currently this is the square of the distance between the
|
||||||
|
* centers.
|
||||||
|
*/
|
||||||
|
_computeWindowMotion: function (actor, slot) {
|
||||||
|
let [xCenter, yCenter, fraction] = slot;
|
||||||
|
let xDelta, yDelta, distanceSquared;
|
||||||
|
let actorWidth, actorHeight;
|
||||||
|
|
||||||
|
let x = actor.x;
|
||||||
|
let y = actor.y;
|
||||||
|
let scale = actor.scale_x;
|
||||||
|
|
||||||
|
if (actor._delegate.inDrag) {
|
||||||
|
x = actor._delegate.dragOrigX;
|
||||||
|
y = actor._delegate.dragOrigY;
|
||||||
|
scale = actor._delegate.dragOrigScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
actorWidth = actor.width * scale;
|
||||||
|
actorHeight = actor.height * scale;
|
||||||
|
xDelta = x + actorWidth / 2.0 - xCenter * this._width - this._x;
|
||||||
|
yDelta = y + actorHeight / 2.0 - yCenter * this._height - this._y;
|
||||||
|
distanceSquared = xDelta * xDelta + yDelta * yDelta;
|
||||||
|
|
||||||
|
return distanceSquared;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _orderWindowsPermutations:
|
||||||
|
*
|
||||||
|
* Iterate over all permutations of the windows, and determine the
|
||||||
|
* permutation which has the least total motion.
|
||||||
|
*/
|
||||||
|
_orderWindowsPermutations: function (clones, slots) {
|
||||||
|
let minimumMotionPermutation = null;
|
||||||
|
let minimumMotion = -1;
|
||||||
|
let permIndex = 0;
|
||||||
|
this._forEachPermutations(clones, Lang.bind(this, function (permutation) {
|
||||||
|
let motion = 0;
|
||||||
|
for (let i = 0; i < permutation.length; i++) {
|
||||||
|
let cloneActor = permutation[i].actor;
|
||||||
|
let slot = slots[i];
|
||||||
|
|
||||||
|
let delta = this._computeWindowMotion(cloneActor, slot);
|
||||||
|
|
||||||
|
motion += delta;
|
||||||
|
|
||||||
|
// Bail out early if we're already larger than the
|
||||||
|
// previous best
|
||||||
|
if (minimumMotionPermutation != null &&
|
||||||
|
motion > minimumMotion)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minimumMotionPermutation == null || motion < minimumMotion) {
|
||||||
|
minimumMotionPermutation = permutation;
|
||||||
|
minimumMotion = motion;
|
||||||
|
}
|
||||||
|
permIndex++;
|
||||||
|
}));
|
||||||
|
return minimumMotionPermutation;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _orderWindowsGreedy:
|
||||||
|
*
|
||||||
|
* Iterate over available slots in order, placing into each one the window
|
||||||
|
* we find with the smallest motion to that slot.
|
||||||
|
*/
|
||||||
|
_orderWindowsGreedy: function(clones, slots) {
|
||||||
|
let result = [];
|
||||||
|
let slotIndex = 0;
|
||||||
|
// Copy since we mutate below
|
||||||
|
let clonesCopy = clones.concat();
|
||||||
|
for (let i = 0; i < slots.length; i++) {
|
||||||
|
let slot = slots[i];
|
||||||
|
let minimumMotionIndex = -1;
|
||||||
|
let minimumMotion = -1;
|
||||||
|
for (let j = 0; j < clonesCopy.length; j++) {
|
||||||
|
let cloneActor = clonesCopy[j].actor;
|
||||||
|
let delta = this._computeWindowMotion(cloneActor, slot);
|
||||||
|
if (minimumMotionIndex == -1 || delta < minimumMotion) {
|
||||||
|
minimumMotionIndex = j;
|
||||||
|
minimumMotion = delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.push(clonesCopy[minimumMotionIndex]);
|
||||||
|
clonesCopy.splice(minimumMotionIndex, 1);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _orderWindowsByMotionAndStartup:
|
||||||
|
* @windows: Array of #MetaWindow
|
||||||
|
* @slots: Array of slots
|
||||||
|
*
|
||||||
|
* Returns a copy of @windows, ordered in such a way that they require least motion
|
||||||
|
* to move to the final screen coordinates of @slots. Ties are broken in a stable
|
||||||
|
* fashion by the order in which the windows were created.
|
||||||
|
*/
|
||||||
|
_orderWindowsByMotionAndStartup: function(clones, slots) {
|
||||||
|
clones.sort(function(w1, w2) {
|
||||||
|
return w2.metaWindow.get_stable_sequence() - w1.metaWindow.get_stable_sequence();
|
||||||
|
});
|
||||||
|
if (clones.length <= POSITIONING_PERMUTATIONS_MAX)
|
||||||
|
return this._orderWindowsPermutations(clones, slots);
|
||||||
|
else
|
||||||
|
return this._orderWindowsGreedy(clones, slots);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _getSlotGeometry:
|
||||||
|
* @slot: A layout slot
|
||||||
|
*
|
||||||
|
* Returns: the screen-relative [x, y, width, height]
|
||||||
|
* of a given window layout slot.
|
||||||
|
*/
|
||||||
|
_getSlotGeometry: function(slot) {
|
||||||
|
let [xCenter, yCenter, fraction] = slot;
|
||||||
|
|
||||||
|
let width = this._width * fraction;
|
||||||
|
let height = this._height * fraction;
|
||||||
|
|
||||||
|
let x = this._x + xCenter * this._width - width / 2 ;
|
||||||
|
let y = this._y + yCenter * this._height - height / 2;
|
||||||
|
|
||||||
|
return [x, y, width, height];
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _computeWindowLayout:
|
||||||
|
* @metaWindow: A #MetaWindow
|
||||||
|
* @slot: A layout slot
|
||||||
|
*
|
||||||
|
* Given a window and slot to fit it in, compute its
|
||||||
|
* screen-relative [x, y, scale] where scale applies
|
||||||
|
* to both X and Y directions.
|
||||||
|
*/
|
||||||
|
_computeWindowLayout: function(metaWindow, slot) {
|
||||||
|
let [x, y, width, height] = this._getSlotGeometry(slot);
|
||||||
|
|
||||||
|
let rect = metaWindow.get_outer_rect();
|
||||||
|
let buttonOuterHeight, captionHeight;
|
||||||
|
let buttonOuterWidth = 0;
|
||||||
|
|
||||||
|
if (this._windowOverlays[0]) {
|
||||||
|
[buttonOuterHeight, captionHeight] = this._windowOverlays[0].chromeHeights();
|
||||||
|
buttonOuterWidth = this._windowOverlays[0].chromeWidth();
|
||||||
|
} else
|
||||||
|
[buttonOuterHeight, captionHeight] = [0, 0];
|
||||||
|
|
||||||
|
let scale = Math.min((width - buttonOuterWidth) / rect.width,
|
||||||
|
(height - buttonOuterHeight - captionHeight) / rect.height,
|
||||||
|
WINDOW_CLONE_MAXIMUM_SCALE);
|
||||||
|
|
||||||
|
x = Math.floor(x + (width - scale * rect.width) / 2);
|
||||||
|
|
||||||
|
// We want to center the window in case we have just one
|
||||||
|
if (metaWindow.get_workspace().n_windows == 1)
|
||||||
|
y = Math.floor(y + (height - scale * rect.height) / 2);
|
||||||
|
else
|
||||||
|
y = Math.floor(y + height - rect.height * scale - captionHeight);
|
||||||
|
|
||||||
|
return [x, y, scale];
|
||||||
|
},
|
||||||
|
|
||||||
setReservedSlot: function(clone) {
|
setReservedSlot: function(clone) {
|
||||||
if (this._reservedSlot == clone)
|
if (this._reservedSlot == clone)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (clone && this.containsMetaWindow(clone.metaWindow))
|
if (clone && this.containsMetaWindow(clone.metaWindow)) {
|
||||||
clone = null;
|
this._reservedSlot = null;
|
||||||
|
this.positionWindows(WindowPositionFlags.ANIMATE);
|
||||||
this._reservedSlot = clone;
|
return;
|
||||||
this._currentLayout = null;
|
}
|
||||||
|
if (clone)
|
||||||
|
this._reservedSlot = clone;
|
||||||
|
else
|
||||||
|
this._reservedSlot = null;
|
||||||
this.positionWindows(WindowPositionFlags.ANIMATE);
|
this.positionWindows(WindowPositionFlags.ANIMATE);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1072,32 +1003,13 @@ const Workspace = new Lang.Class({
|
|||||||
* INITIAL - this is the initial positioning of the windows.
|
* INITIAL - this is the initial positioning of the windows.
|
||||||
* ANIMATE - Indicates that we need animate changing position.
|
* ANIMATE - Indicates that we need animate changing position.
|
||||||
*/
|
*/
|
||||||
positionWindows: function(flags) {
|
positionWindows : function(flags) {
|
||||||
this._positionWindowsFlags |= flags;
|
|
||||||
|
|
||||||
if (this._positionWindowsId > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._positionWindowsId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
|
||||||
this._realPositionWindows(this._positionWindowsFlags);
|
|
||||||
this._positionWindowsFlags = 0;
|
|
||||||
this._positionWindowsId = 0;
|
|
||||||
return false;
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
_realPositionWindows : function(flags) {
|
|
||||||
if (this._repositionWindowsId > 0) {
|
if (this._repositionWindowsId > 0) {
|
||||||
Mainloop.source_remove(this._repositionWindowsId);
|
Mainloop.source_remove(this._repositionWindowsId);
|
||||||
this._repositionWindowsId = 0;
|
this._repositionWindowsId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let clones = this._windows.slice();
|
let clones = this._windows.slice();
|
||||||
|
|
||||||
clones.sort(function(a, b) {
|
|
||||||
return a.metaWindow.get_stable_sequence() - b.metaWindow.get_stable_sequence();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this._reservedSlot)
|
if (this._reservedSlot)
|
||||||
clones.push(this._reservedSlot);
|
clones.push(this._reservedSlot);
|
||||||
|
|
||||||
@ -1105,7 +1017,8 @@ const Workspace = new Lang.Class({
|
|||||||
let animate = flags & WindowPositionFlags.ANIMATE;
|
let animate = flags & WindowPositionFlags.ANIMATE;
|
||||||
|
|
||||||
// Start the animations
|
// Start the animations
|
||||||
let slots = this._computeAllWindowSlots(clones);
|
let slots = this._computeAllWindowSlots(clones.length);
|
||||||
|
clones = this._orderWindowsByMotionAndStartup(clones, slots);
|
||||||
|
|
||||||
let currentWorkspace = global.screen.get_active_workspace();
|
let currentWorkspace = global.screen.get_active_workspace();
|
||||||
let isOnCurrentWorkspace = this.metaWorkspace == null || this.metaWorkspace == currentWorkspace;
|
let isOnCurrentWorkspace = this.metaWorkspace == null || this.metaWorkspace == currentWorkspace;
|
||||||
@ -1122,36 +1035,33 @@ const Workspace = new Lang.Class({
|
|||||||
if (clone.inDrag)
|
if (clone.inDrag)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
let [x, y, scale] = slot;
|
let [x, y, scale] = this._computeWindowLayout(metaWindow, slot);
|
||||||
|
|
||||||
if (overlay && initialPositioning)
|
if (overlay && initialPositioning)
|
||||||
overlay.hide();
|
overlay.hide();
|
||||||
|
|
||||||
if (animate && isOnCurrentWorkspace) {
|
if (animate && isOnCurrentWorkspace) {
|
||||||
if (!metaWindow.showing_on_its_workspace()) {
|
if (!metaWindow.showing_on_its_workspace()) {
|
||||||
/* Hidden windows should fade in and grow
|
/* Hidden windows should fade in and grow
|
||||||
* therefore we need to resize them now so they
|
* therefore we need to resize them now so they
|
||||||
* can be scaled up later */
|
* can be scaled up later */
|
||||||
if (initialPositioning) {
|
if (initialPositioning) {
|
||||||
clone.actor.opacity = 0;
|
clone.actor.opacity = 0;
|
||||||
clone.actor.scale_x = 0;
|
clone.actor.scale_x = 0;
|
||||||
clone.actor.scale_y = 0;
|
clone.actor.scale_y = 0;
|
||||||
clone.actor.x = x;
|
clone.actor.x = x;
|
||||||
clone.actor.y = y;
|
clone.actor.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the window slightly transparent to indicate it's hidden
|
// Make the window slightly transparent to indicate it's hidden
|
||||||
Tweener.addTween(clone.actor,
|
Tweener.addTween(clone.actor,
|
||||||
{ opacity: 255,
|
{ opacity: 255,
|
||||||
time: Overview.ANIMATION_TIME,
|
time: Overview.ANIMATION_TIME,
|
||||||
transition: 'easeInQuad'
|
transition: 'easeInQuad'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this._animateClone(clone, overlay, x, y, scale, initialPositioning);
|
this._animateClone(clone, overlay, x, y, scale, initialPositioning);
|
||||||
} else {
|
} else {
|
||||||
// cancel any active tweens (otherwise they might override our changes)
|
|
||||||
Tweener.removeTweens(clone.actor);
|
|
||||||
clone.actor.set_position(x, y);
|
clone.actor.set_position(x, y);
|
||||||
clone.actor.set_scale(scale, scale);
|
clone.actor.set_scale(scale, scale);
|
||||||
this._updateWindowOverlayPositions(clone, overlay, x, y, scale, false);
|
this._updateWindowOverlayPositions(clone, overlay, x, y, scale, false);
|
||||||
@ -1178,26 +1088,26 @@ const Workspace = new Lang.Class({
|
|||||||
|
|
||||||
_animateClone: function(clone, overlay, x, y, scale, initialPositioning) {
|
_animateClone: function(clone, overlay, x, y, scale, initialPositioning) {
|
||||||
Tweener.addTween(clone.actor,
|
Tweener.addTween(clone.actor,
|
||||||
{ x: x,
|
{ x: x,
|
||||||
y: y,
|
y: y,
|
||||||
scale_x: scale,
|
scale_x: scale,
|
||||||
scale_y: scale,
|
scale_y: scale,
|
||||||
time: Overview.ANIMATION_TIME,
|
time: Overview.ANIMATION_TIME,
|
||||||
transition: 'easeOutQuad',
|
transition: 'easeOutQuad',
|
||||||
onComplete: Lang.bind(this, function() {
|
onComplete: Lang.bind(this, function() {
|
||||||
this._showWindowOverlay(clone, overlay, true);
|
this._showWindowOverlay(clone, overlay, true);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
this._updateWindowOverlayPositions(clone, overlay, x, y, scale, true);
|
this._updateWindowOverlayPositions(clone, overlay, x, y, scale, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateWindowOverlayPositions: function(clone, overlay, x, y, scale, animate) {
|
_updateWindowOverlayPositions: function(clone, overlay, x, y, scale, animate) {
|
||||||
if (!overlay)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let [cloneWidth, cloneHeight] = clone.actor.get_size();
|
let [cloneWidth, cloneHeight] = clone.actor.get_size();
|
||||||
overlay.updatePositions(x, y, cloneWidth * scale, cloneHeight * scale, animate);
|
cloneWidth = scale * cloneWidth;
|
||||||
|
cloneHeight = scale * cloneHeight;
|
||||||
|
if (overlay)
|
||||||
|
overlay.updatePositions(x, y, cloneWidth, cloneHeight, animate);
|
||||||
},
|
},
|
||||||
|
|
||||||
_showWindowOverlay: function(clone, overlay, fade) {
|
_showWindowOverlay: function(clone, overlay, fade) {
|
||||||
@ -1291,7 +1201,6 @@ const Workspace = new Lang.Class({
|
|||||||
this._cursorX = x;
|
this._cursorX = x;
|
||||||
this._cursorY = y;
|
this._cursorY = y;
|
||||||
|
|
||||||
this._currentLayout = null;
|
|
||||||
this._repositionWindowsId = Mainloop.timeout_add(750,
|
this._repositionWindowsId = Mainloop.timeout_add(750,
|
||||||
Lang.bind(this, this._delayedWindowRepositioning));
|
Lang.bind(this, this._delayedWindowRepositioning));
|
||||||
},
|
},
|
||||||
@ -1344,7 +1253,6 @@ const Workspace = new Lang.Class({
|
|||||||
clone.actor.set_position (this._x, this._y);
|
clone.actor.set_position (this._x, this._y);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._currentLayout = null;
|
|
||||||
this.positionWindows(WindowPositionFlags.ANIMATE);
|
this.positionWindows(WindowPositionFlags.ANIMATE);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1382,8 +1290,6 @@ const Workspace = new Lang.Class({
|
|||||||
|
|
||||||
// Animate the full-screen to Overview transition.
|
// Animate the full-screen to Overview transition.
|
||||||
zoomToOverview : function() {
|
zoomToOverview : function() {
|
||||||
this._currentLayout = null;
|
|
||||||
|
|
||||||
// Position and scale the windows.
|
// Position and scale the windows.
|
||||||
if (Main.overview.animationInProgress)
|
if (Main.overview.animationInProgress)
|
||||||
this.positionWindows(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
|
this.positionWindows(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
|
||||||
@ -1466,9 +1372,6 @@ const Workspace = new Lang.Class({
|
|||||||
if (this._repositionWindowsId > 0)
|
if (this._repositionWindowsId > 0)
|
||||||
Mainloop.source_remove(this._repositionWindowsId);
|
Mainloop.source_remove(this._repositionWindowsId);
|
||||||
|
|
||||||
if (this._positionWindowsId > 0)
|
|
||||||
Meta.later_remove(this._positionWindowsId);
|
|
||||||
|
|
||||||
// Usually, the windows will be destroyed automatically with
|
// Usually, the windows will be destroyed automatically with
|
||||||
// their parent (this.actor), but we might have a zoomed window
|
// their parent (this.actor), but we might have a zoomed window
|
||||||
// which has been reparented to the stage - _windows[0] holds
|
// which has been reparented to the stage - _windows[0] holds
|
||||||
@ -1548,108 +1451,29 @@ const Workspace = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_isBetterLayout: function(oldLayout, newLayout) {
|
_computeWindowSlot : function(windowIndex, numberOfWindows) {
|
||||||
if (oldLayout.scale === undefined)
|
if (numberOfWindows in POSITIONS)
|
||||||
return true;
|
return POSITIONS[numberOfWindows][windowIndex];
|
||||||
|
|
||||||
let spacePower = (newLayout.space - oldLayout.space) * LAYOUT_SPACE_WEIGHT;
|
// If we don't have a predefined scheme for this window count,
|
||||||
let scalePower = (newLayout.scale - oldLayout.scale) * LAYOUT_SCALE_WEIGHT;
|
// arrange the windows in a grid pattern.
|
||||||
|
let gridWidth = Math.ceil(Math.sqrt(numberOfWindows));
|
||||||
|
let gridHeight = Math.ceil(numberOfWindows / gridWidth);
|
||||||
|
|
||||||
if (newLayout.scale > oldLayout.scale && newLayout.space > oldLayout.space) {
|
let fraction = 0.95 * (1. / gridWidth);
|
||||||
// Win win -- better scale and better space
|
|
||||||
return true;
|
let xCenter = (.5 / gridWidth) + ((windowIndex) % gridWidth) / gridWidth;
|
||||||
} else if (newLayout.scale > oldLayout.scale && newLayout.space <= oldLayout.space) {
|
let yCenter = (.5 / gridHeight) + Math.floor((windowIndex / gridWidth)) / gridHeight;
|
||||||
// Keep new layout only if scale gain outweights aspect space loss
|
|
||||||
return scalePower > spacePower;
|
return [xCenter, yCenter, fraction];
|
||||||
} else if (newLayout.scale <= oldLayout.scale && newLayout.space > oldLayout.space) {
|
|
||||||
// Keep new layout only if aspect space gain outweights scale loss
|
|
||||||
return spacePower > scalePower;
|
|
||||||
} else {
|
|
||||||
// Lose -- worse scale and space
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_computeLayout: function(windows, area, rowSpacing, columnSpacing, bottomPadding) {
|
_computeAllWindowSlots: function(totalWindows) {
|
||||||
// We look for the largest scale that allows us to fit the
|
let slots = [];
|
||||||
// largest row/tallest column on the workspace.
|
for (let i = 0; i < totalWindows; i++) {
|
||||||
|
slots.push(this._computeWindowSlot(i, totalWindows));
|
||||||
let lastLayout = {};
|
|
||||||
|
|
||||||
for (let numRows = 1; ; numRows++) {
|
|
||||||
let numColumns = Math.ceil(windows.length / numRows);
|
|
||||||
|
|
||||||
// If adding a new row does not change column count just stop
|
|
||||||
// (for instance: 9 windows, with 3 rows -> 3 columns, 4 rows ->
|
|
||||||
// 3 columns as well => just use 3 rows then)
|
|
||||||
if (numColumns == lastLayout.numColumns)
|
|
||||||
break;
|
|
||||||
|
|
||||||
let strategyClass = numRows > 2 ? GridLayoutStrategy : UnalignedLayoutStrategy;
|
|
||||||
let strategy = new strategyClass(this._monitor, rowSpacing, columnSpacing, bottomPadding);
|
|
||||||
|
|
||||||
let layout = { area: area, strategy: strategy, numRows: numRows, numColumns: numColumns };
|
|
||||||
strategy.computeLayout(windows, layout);
|
|
||||||
strategy.computeScaleAndSpace(layout);
|
|
||||||
|
|
||||||
if (!this._isBetterLayout(lastLayout, layout))
|
|
||||||
break;
|
|
||||||
|
|
||||||
lastLayout = layout;
|
|
||||||
}
|
}
|
||||||
|
return slots;
|
||||||
return lastLayout;
|
|
||||||
},
|
|
||||||
|
|
||||||
_rectEqual: function(one, two) {
|
|
||||||
if (one == two)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return (one.x == two.x &&
|
|
||||||
one.y == two.y &&
|
|
||||||
one.width == two.width &&
|
|
||||||
one.height == two.height);
|
|
||||||
},
|
|
||||||
|
|
||||||
_computeAllWindowSlots: function(windows) {
|
|
||||||
let totalWindows = windows.length;
|
|
||||||
let node = this.actor.get_theme_node();
|
|
||||||
|
|
||||||
// Window grid spacing
|
|
||||||
let columnSpacing = node.get_length('-horizontal-spacing');
|
|
||||||
let rowSpacing = node.get_length('-vertical-spacing');
|
|
||||||
|
|
||||||
if (!totalWindows)
|
|
||||||
return [];
|
|
||||||
|
|
||||||
let closeButtonHeight, captionHeight;
|
|
||||||
if (this._windowOverlays.length) {
|
|
||||||
// All of the overlays have the same chrome sizes,
|
|
||||||
// so just pick the first one.
|
|
||||||
let overlay = this._windowOverlays[0];
|
|
||||||
[closeButtonHeight, captionHeight] = overlay.chromeHeights();
|
|
||||||
} else {
|
|
||||||
[closeButtonHeight, captionHeight] = [0, 0];
|
|
||||||
}
|
|
||||||
|
|
||||||
rowSpacing += captionHeight;
|
|
||||||
|
|
||||||
let area = { x: this._x, y: this._y, width: this._width, height: this._height };
|
|
||||||
area.y += closeButtonHeight;
|
|
||||||
area.height -= closeButtonHeight;
|
|
||||||
|
|
||||||
if (!this._currentLayout)
|
|
||||||
this._currentLayout = this._computeLayout(windows, area, rowSpacing, columnSpacing, captionHeight);
|
|
||||||
|
|
||||||
let layout = this._currentLayout;
|
|
||||||
let strategy = layout.strategy;
|
|
||||||
|
|
||||||
if (!this._rectEqual(area, layout.area)) {
|
|
||||||
layout.area = area;
|
|
||||||
strategy.computeScaleAndSpace(layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
return strategy.computeWindowSlots(layout, area);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onCloneSelected : function (clone, time) {
|
_onCloneSelected : function (clone, time) {
|
||||||
|
@ -620,7 +620,9 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
if (!source.realWindow && !source.shellWorkspaceLaunch && source != Main.xdndHandler)
|
if (!source.realWindow && !source.shellWorkspaceLaunch && source != Main.xdndHandler)
|
||||||
return DND.DragMotionResult.CONTINUE;
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
|
||||||
let canCreateWorkspaces = Meta.prefs_get_dynamic_workspaces();
|
if (!Meta.prefs_get_dynamic_workspaces())
|
||||||
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
|
||||||
let spacing = this.actor.get_theme_node().get_length('spacing');
|
let spacing = this.actor.get_theme_node().get_length('spacing');
|
||||||
|
|
||||||
this._dropWorkspace = -1;
|
this._dropWorkspace = -1;
|
||||||
@ -645,7 +647,7 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
if (i == this._dropPlaceholderPos)
|
if (i == this._dropPlaceholderPos)
|
||||||
targetBottom += this._dropPlaceholder.get_height();
|
targetBottom += this._dropPlaceholder.get_height();
|
||||||
|
|
||||||
if (y > targetTop && y <= targetBottom && source != Main.xdndHandler && canCreateWorkspaces) {
|
if (y > targetTop && y <= targetBottom && source != Main.xdndHandler) {
|
||||||
placeholderPos = i;
|
placeholderPos = i;
|
||||||
break;
|
break;
|
||||||
} else if (y > targetBottom && y <= nextTargetTop) {
|
} else if (y > targetBottom && y <= nextTargetTop) {
|
||||||
@ -783,7 +785,7 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
this._indicator.raise_top();
|
this._indicator.raise_top();
|
||||||
},
|
},
|
||||||
|
|
||||||
removeThumbnails: function(start, count) {
|
removeThumbmails: function(start, count) {
|
||||||
let currentPos = 0;
|
let currentPos = 0;
|
||||||
for (let k = 0; k < this._thumbnails.length; k++) {
|
for (let k = 0; k < this._thumbnails.length; k++) {
|
||||||
let thumbnail = this._thumbnails[k];
|
let thumbnail = this._thumbnails[k];
|
||||||
@ -1043,16 +1045,9 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
childBox.y2 = box.y2;
|
childBox.y2 = box.y2;
|
||||||
this._background.allocate(childBox, flags);
|
this._background.allocate(childBox, flags);
|
||||||
|
|
||||||
let indicatorY1 = this._indicatorY;
|
let indicatorY = this._indicatorY;
|
||||||
let indicatorY2;
|
|
||||||
// when not animating, the workspace position overrides this._indicatorY
|
// when not animating, the workspace position overrides this._indicatorY
|
||||||
let indicatorWorkspace = !this._animatingIndicator ? global.screen.get_active_workspace() : null;
|
let indicatorWorkspace = !this._animatingIndicator ? global.screen.get_active_workspace() : null;
|
||||||
let indicatorThemeNode = this._indicator.get_theme_node();
|
|
||||||
|
|
||||||
let indicatorTopFullBorder = indicatorThemeNode.get_padding(St.Side.TOP) + indicatorThemeNode.get_border_width(St.Side.TOP);
|
|
||||||
let indicatorBottomFullBorder = indicatorThemeNode.get_padding(St.Side.BOTTOM) + indicatorThemeNode.get_border_width(St.Side.BOTTOM);
|
|
||||||
let indicatorLeftFullBorder = indicatorThemeNode.get_padding(St.Side.LEFT) + indicatorThemeNode.get_border_width(St.Side.LEFT);
|
|
||||||
let indicatorRightFullBorder = indicatorThemeNode.get_padding(St.Side.RIGHT) + indicatorThemeNode.get_border_width(St.Side.RIGHT);
|
|
||||||
|
|
||||||
let y = contentBox.y1;
|
let y = contentBox.y1;
|
||||||
|
|
||||||
@ -1098,10 +1093,8 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
let y2 = Math.round(y + thumbnailHeight);
|
let y2 = Math.round(y + thumbnailHeight);
|
||||||
let roundedVScale = (y2 - y1) / portholeHeight;
|
let roundedVScale = (y2 - y1) / portholeHeight;
|
||||||
|
|
||||||
if (thumbnail.metaWorkspace == indicatorWorkspace) {
|
if (thumbnail.metaWorkspace == indicatorWorkspace)
|
||||||
indicatorY1 = y1;
|
indicatorY = y1;
|
||||||
indicatorY2 = y2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocating a scaled actor is funny - x1/y1 correspond to the origin
|
// Allocating a scaled actor is funny - x1/y1 correspond to the origin
|
||||||
// of the actor, but x2/y2 are increased by the *unscaled* size.
|
// of the actor, but x2/y2 are increased by the *unscaled* size.
|
||||||
@ -1126,10 +1119,8 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
childBox.x1 = contentBox.x2 - thumbnailWidth;
|
childBox.x1 = contentBox.x2 - thumbnailWidth;
|
||||||
childBox.x2 = contentBox.x2;
|
childBox.x2 = contentBox.x2;
|
||||||
}
|
}
|
||||||
childBox.x1 -= indicatorLeftFullBorder;
|
childBox.y1 = indicatorY;
|
||||||
childBox.x2 += indicatorRightFullBorder;
|
childBox.y2 = childBox.y1 + thumbnailHeight;
|
||||||
childBox.y1 = indicatorY1 - indicatorTopFullBorder;
|
|
||||||
childBox.y2 = (indicatorY2 ? indicatorY2 : (indicatorY1 + thumbnailHeight)) + indicatorBottomFullBorder;
|
|
||||||
this._indicator.allocate(childBox, flags);
|
this._indicator.allocate(childBox, flags);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1144,9 +1135,7 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._animatingIndicator = true;
|
this._animatingIndicator = true;
|
||||||
let indicatorThemeNode = this._indicator.get_theme_node();
|
this.indicatorY = this._indicator.allocation.y1;
|
||||||
let indicatorTopFullBorder = indicatorThemeNode.get_padding(St.Side.TOP) + indicatorThemeNode.get_border_width(St.Side.TOP);
|
|
||||||
this.indicatorY = this._indicator.allocation.y1 + indicatorTopFullBorder;
|
|
||||||
Tweener.addTween(this,
|
Tweener.addTween(this,
|
||||||
{ indicatorY: thumbnail.actor.allocation.y1,
|
{ indicatorY: thumbnail.actor.allocation.y1,
|
||||||
time: WorkspacesView.WORKSPACE_SWITCH_TIME,
|
time: WorkspacesView.WORKSPACE_SWITCH_TIME,
|
||||||
|
@ -51,6 +51,7 @@ const WorkspacesView = new Lang.Class({
|
|||||||
this._clipY = 0;
|
this._clipY = 0;
|
||||||
this._clipWidth = 0;
|
this._clipWidth = 0;
|
||||||
this._clipHeight = 0;
|
this._clipHeight = 0;
|
||||||
|
this._workspaceRatioSpacing = 0;
|
||||||
this._spacing = 0;
|
this._spacing = 0;
|
||||||
this._animating = false; // tweening
|
this._animating = false; // tweening
|
||||||
this._scrolling = false; // swipe-scrolling
|
this._scrolling = false; // swipe-scrolling
|
||||||
@ -71,7 +72,6 @@ const WorkspacesView = new Lang.Class({
|
|||||||
this._workspaces[w].actor.reparent(this.actor);
|
this._workspaces[w].actor.reparent(this.actor);
|
||||||
this._workspaces[activeWorkspaceIndex].actor.raise_top();
|
this._workspaces[activeWorkspaceIndex].actor.raise_top();
|
||||||
|
|
||||||
this._extraWorkspaces = [];
|
|
||||||
this._updateExtraWorkspaces();
|
this._updateExtraWorkspaces();
|
||||||
|
|
||||||
// Position/scale the desktop windows and their children after the
|
// Position/scale the desktop windows and their children after the
|
||||||
@ -83,6 +83,8 @@ const WorkspacesView = new Lang.Class({
|
|||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
for (let w = 0; w < this._workspaces.length; w++)
|
for (let w = 0; w < this._workspaces.length; w++)
|
||||||
this._workspaces[w].zoomToOverview();
|
this._workspaces[w].zoomToOverview();
|
||||||
|
if (!this._extraWorkspaces)
|
||||||
|
return;
|
||||||
for (let w = 0; w < this._extraWorkspaces.length; w++)
|
for (let w = 0; w < this._extraWorkspaces.length; w++)
|
||||||
this._extraWorkspaces[w].zoomToOverview();
|
this._extraWorkspaces[w].zoomToOverview();
|
||||||
}));
|
}));
|
||||||
@ -122,6 +124,7 @@ const WorkspacesView = new Lang.Class({
|
|||||||
if (!this._settings.get_boolean('workspaces-only-on-primary'))
|
if (!this._settings.get_boolean('workspaces-only-on-primary'))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
this._extraWorkspaces = [];
|
||||||
let monitors = Main.layoutManager.monitors;
|
let monitors = Main.layoutManager.monitors;
|
||||||
for (let i = 0; i < monitors.length; i++) {
|
for (let i = 0; i < monitors.length; i++) {
|
||||||
if (i == Main.layoutManager.primaryIndex)
|
if (i == Main.layoutManager.primaryIndex)
|
||||||
@ -136,20 +139,23 @@ const WorkspacesView = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_destroyExtraWorkspaces: function() {
|
_destroyExtraWorkspaces: function() {
|
||||||
|
if (!this._extraWorkspaces)
|
||||||
|
return;
|
||||||
|
|
||||||
for (let m = 0; m < this._extraWorkspaces.length; m++)
|
for (let m = 0; m < this._extraWorkspaces.length; m++)
|
||||||
this._extraWorkspaces[m].destroy();
|
this._extraWorkspaces[m].destroy();
|
||||||
this._extraWorkspaces = [];
|
this._extraWorkspaces = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
setGeometry: function(x, y, width, height) {
|
setGeometry: function(x, y, width, height, spacing) {
|
||||||
if (this._x == x && this._y == y &&
|
if (this._x == x && this._y == y &&
|
||||||
this._width == width && this._height == height)
|
this._width == width && this._height == height)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._width = width;
|
this._width = width;
|
||||||
this._height = height;
|
this._height = height;
|
||||||
this._x = x;
|
this._x = x;
|
||||||
this._y = y;
|
this._y = y;
|
||||||
|
this._workspaceRatioSpacing = spacing;
|
||||||
|
|
||||||
for (let i = 0; i < this._workspaces.length; i++)
|
for (let i = 0; i < this._workspaces.length; i++)
|
||||||
this._workspaces[i].setGeometry(x, y, width, height);
|
this._workspaces[i].setGeometry(x, y, width, height);
|
||||||
@ -185,6 +191,8 @@ const WorkspacesView = new Lang.Class({
|
|||||||
|
|
||||||
for (let w = 0; w < this._workspaces.length; w++)
|
for (let w = 0; w < this._workspaces.length; w++)
|
||||||
this._workspaces[w].zoomFromOverview();
|
this._workspaces[w].zoomFromOverview();
|
||||||
|
if (!this._extraWorkspaces)
|
||||||
|
return;
|
||||||
for (let w = 0; w < this._extraWorkspaces.length; w++)
|
for (let w = 0; w < this._extraWorkspaces.length; w++)
|
||||||
this._extraWorkspaces[w].zoomFromOverview();
|
this._extraWorkspaces[w].zoomFromOverview();
|
||||||
},
|
},
|
||||||
@ -196,6 +204,8 @@ const WorkspacesView = new Lang.Class({
|
|||||||
syncStacking: function(stackIndices) {
|
syncStacking: function(stackIndices) {
|
||||||
for (let i = 0; i < this._workspaces.length; i++)
|
for (let i = 0; i < this._workspaces.length; i++)
|
||||||
this._workspaces[i].syncStacking(stackIndices);
|
this._workspaces[i].syncStacking(stackIndices);
|
||||||
|
if (!this._extraWorkspaces)
|
||||||
|
return;
|
||||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
||||||
this._extraWorkspaces[i].syncStacking(stackIndices);
|
this._extraWorkspaces[i].syncStacking(stackIndices);
|
||||||
},
|
},
|
||||||
@ -224,7 +234,7 @@ const WorkspacesView = new Lang.Class({
|
|||||||
|
|
||||||
Tweener.removeTweens(workspace.actor);
|
Tweener.removeTweens(workspace.actor);
|
||||||
|
|
||||||
let y = (w - active) * (this._height + this._spacing);
|
let y = (w - active) * (this._height + this._spacing + this._workspaceRatioSpacing);
|
||||||
|
|
||||||
if (showAnimation) {
|
if (showAnimation) {
|
||||||
let params = { y: y,
|
let params = { y: y,
|
||||||
@ -307,6 +317,8 @@ const WorkspacesView = new Lang.Class({
|
|||||||
|
|
||||||
this._updateWorkspaceActors(false);
|
this._updateWorkspaceActors(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._scrollToActive(true);
|
||||||
},
|
},
|
||||||
|
|
||||||
_activeWorkspaceChanged: function(wm, from, to, direction) {
|
_activeWorkspaceChanged: function(wm, from, to, direction) {
|
||||||
@ -366,6 +378,9 @@ const WorkspacesView = new Lang.Class({
|
|||||||
this._firstDragMotion = false;
|
this._firstDragMotion = false;
|
||||||
for (let i = 0; i < this._workspaces.length; i++)
|
for (let i = 0; i < this._workspaces.length; i++)
|
||||||
this._workspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
this._workspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
||||||
|
if (!this._extraWorkspaces)
|
||||||
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
|
||||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
||||||
this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
||||||
}
|
}
|
||||||
@ -379,6 +394,9 @@ const WorkspacesView = new Lang.Class({
|
|||||||
|
|
||||||
for (let i = 0; i < this._workspaces.length; i++)
|
for (let i = 0; i < this._workspaces.length; i++)
|
||||||
this._workspaces[i].setReservedSlot(null);
|
this._workspaces[i].setReservedSlot(null);
|
||||||
|
|
||||||
|
if (!this._extraWorkspaces)
|
||||||
|
return;
|
||||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
||||||
this._extraWorkspaces[i].setReservedSlot(null);
|
this._extraWorkspaces[i].setReservedSlot(null);
|
||||||
},
|
},
|
||||||
@ -525,16 +543,6 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
this._notifyOpacityId = 0;
|
this._notifyOpacityId = 0;
|
||||||
this._swipeScrollBeginId = 0;
|
this._swipeScrollBeginId = 0;
|
||||||
this._swipeScrollEndId = 0;
|
this._swipeScrollEndId = 0;
|
||||||
|
|
||||||
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
|
|
||||||
this._settings.connect('changed::dynamic-workspaces',
|
|
||||||
Lang.bind(this, this._updateSwitcherVisibility));
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateSwitcherVisibility: function() {
|
|
||||||
this._thumbnailsBox.actor.visible =
|
|
||||||
this._settings.get_boolean('dynamic-workspaces') ||
|
|
||||||
global.screen.n_workspaces > 1;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
show: function() {
|
show: function() {
|
||||||
@ -557,7 +565,6 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
|
|
||||||
this._controls.show();
|
this._controls.show();
|
||||||
this._thumbnailsBox.show();
|
this._thumbnailsBox.show();
|
||||||
this._updateSwitcherVisibility();
|
|
||||||
|
|
||||||
this._updateWorkspacesViews();
|
this._updateWorkspacesViews();
|
||||||
|
|
||||||
@ -859,15 +866,24 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
|
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
|
||||||
|
|
||||||
let clipWidth = width - controlsVisible;
|
let clipWidth = width - controlsVisible;
|
||||||
let clipHeight = fullHeight;
|
let clipHeight = (fullHeight / fullWidth) * clipWidth;
|
||||||
let clipX = rtl ? x + controlsVisible : x;
|
let clipX = rtl ? x + controlsVisible : x;
|
||||||
let clipY = y + (fullHeight - clipHeight) / 2;
|
let clipY = y + (fullHeight - clipHeight) / 2;
|
||||||
|
|
||||||
let widthAdjust = this._zoomOut ? controlsNatural : controlsVisible;
|
if (this._zoomOut) {
|
||||||
widthAdjust += Main.overview._spacing;
|
width -= controlsNatural;
|
||||||
width -= widthAdjust;
|
if (rtl)
|
||||||
if (rtl)
|
x += controlsNatural;
|
||||||
x += widthAdjust;
|
} else {
|
||||||
|
width -= controlsVisible;
|
||||||
|
if (rtl)
|
||||||
|
x += controlsVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
height = (fullHeight / fullWidth) * width;
|
||||||
|
let difference = fullHeight - height;
|
||||||
|
y += difference / 2;
|
||||||
|
|
||||||
|
|
||||||
let monitors = Main.layoutManager.monitors;
|
let monitors = Main.layoutManager.monitors;
|
||||||
let m = 0;
|
let m = 0;
|
||||||
@ -875,7 +891,8 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
if (i == this._primaryIndex) {
|
if (i == this._primaryIndex) {
|
||||||
this._workspacesViews[m].setClipRect(clipX, clipY,
|
this._workspacesViews[m].setClipRect(clipX, clipY,
|
||||||
clipWidth, clipHeight);
|
clipWidth, clipHeight);
|
||||||
this._workspacesViews[m].setGeometry(x, y, width, height);
|
this._workspacesViews[m].setGeometry(x, y, width, height,
|
||||||
|
difference);
|
||||||
m++;
|
m++;
|
||||||
} else if (!this._workspacesOnlyOnPrimary) {
|
} else if (!this._workspacesOnlyOnPrimary) {
|
||||||
this._workspacesViews[m].setClipRect(monitors[i].x,
|
this._workspacesViews[m].setClipRect(monitors[i].x,
|
||||||
@ -885,7 +902,7 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
this._workspacesViews[m].setGeometry(monitors[i].x,
|
this._workspacesViews[m].setGeometry(monitors[i].x,
|
||||||
monitors[i].y,
|
monitors[i].y,
|
||||||
monitors[i].width,
|
monitors[i].width,
|
||||||
monitors[i].height);
|
monitors[i].height, 0);
|
||||||
m++;
|
m++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -922,17 +939,16 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
let monitors = Main.layoutManager.monitors;
|
let monitors = Main.layoutManager.monitors;
|
||||||
let m = 0;
|
let m = 0;
|
||||||
for (let i = 0; i < monitors.length; i++) {
|
for (let i = 0; i < monitors.length; i++) {
|
||||||
if (this._workspacesOnlyOnPrimary &&
|
if (this._workspacesOnlyOnPrimaryChanged &&
|
||||||
i != this._primaryIndex)
|
i != this._primaryIndex)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Assume workspaces are only added at the end
|
// Assume workspaces are only added at the end
|
||||||
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
|
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
|
||||||
let metaWorkspace = global.screen.get_workspace_by_index(w);
|
let metaWorkspace = global.screen.get_workspace_by_index(w);
|
||||||
this._workspaces[m][w] =
|
this._workspaces[m++][w] =
|
||||||
new Workspace.Workspace(metaWorkspace, i);
|
new Workspace.Workspace(metaWorkspace, i);
|
||||||
}
|
}
|
||||||
m++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._thumbnailsBox.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces);
|
this._thumbnailsBox.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces);
|
||||||
@ -959,13 +975,12 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._thumbnailsBox.removeThumbnails(removedIndex, removedNum);
|
this._thumbnailsBox.removeThumbmails(removedIndex, removedNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < this._workspacesViews.length; i++)
|
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||||
this._workspacesViews[i].updateWorkspaces(oldNumWorkspaces,
|
this._workspacesViews[i].updateWorkspaces(oldNumWorkspaces,
|
||||||
newNumWorkspaces);
|
newNumWorkspaces);
|
||||||
this._updateSwitcherVisibility();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateZoom : function() {
|
_updateZoom : function() {
|
||||||
|
@ -34,7 +34,6 @@ kk
|
|||||||
kn
|
kn
|
||||||
ko
|
ko
|
||||||
ku
|
ku
|
||||||
ky
|
|
||||||
lt
|
lt
|
||||||
lv
|
lv
|
||||||
ml
|
ml
|
||||||
|
@ -1,47 +1,42 @@
|
|||||||
data/50-gnome-shell-screenshot.xml.in
|
|
||||||
data/50-gnome-shell-system.xml.in
|
|
||||||
data/gnome-shell.desktop.in.in
|
data/gnome-shell.desktop.in.in
|
||||||
data/gnome-shell-extension-prefs.desktop.in.in
|
data/gnome-shell-extension-prefs.desktop.in.in
|
||||||
data/org.gnome.shell.gschema.xml.in.in
|
data/org.gnome.shell.gschema.xml.in.in
|
||||||
js/extensionPrefs/main.js
|
js/extensionPrefs/main.js
|
||||||
js/gdm/loginDialog.js
|
js/gdm/loginDialog.js
|
||||||
js/gdm/powerMenu.js
|
js/gdm/powerMenu.js
|
||||||
js/gdm/util.js
|
|
||||||
js/misc/util.js
|
js/misc/util.js
|
||||||
js/ui/appDisplay.js
|
js/ui/appDisplay.js
|
||||||
js/ui/appFavorites.js
|
js/ui/appFavorites.js
|
||||||
|
js/ui/autorunManager.js
|
||||||
js/ui/calendar.js
|
js/ui/calendar.js
|
||||||
js/ui/components/autorunManager.js
|
|
||||||
js/ui/components/keyring.js
|
|
||||||
js/ui/components/networkAgent.js
|
|
||||||
js/ui/components/polkitAgent.js
|
|
||||||
js/ui/components/recorder.js
|
|
||||||
js/ui/components/telepathyClient.js
|
|
||||||
js/ui/dash.js
|
js/ui/dash.js
|
||||||
js/ui/dateMenu.js
|
js/ui/dateMenu.js
|
||||||
js/ui/endSessionDialog.js
|
js/ui/endSessionDialog.js
|
||||||
js/ui/extensionDownloader.js
|
js/ui/extensionDownloader.js
|
||||||
js/ui/extensionSystem.js
|
js/ui/extensionSystem.js
|
||||||
js/ui/keyboard.js
|
js/ui/keyboard.js
|
||||||
|
js/ui/keyringPrompt.js
|
||||||
js/ui/lookingGlass.js
|
js/ui/lookingGlass.js
|
||||||
js/ui/main.js
|
js/ui/main.js
|
||||||
js/ui/messageTray.js
|
js/ui/messageTray.js
|
||||||
|
js/ui/networkAgent.js
|
||||||
js/ui/notificationDaemon.js
|
js/ui/notificationDaemon.js
|
||||||
js/ui/overview.js
|
js/ui/overview.js
|
||||||
js/ui/panel.js
|
js/ui/panel.js
|
||||||
|
js/ui/placeDisplay.js
|
||||||
|
js/ui/polkitAuthenticationAgent.js
|
||||||
js/ui/popupMenu.js
|
js/ui/popupMenu.js
|
||||||
js/ui/runDialog.js
|
js/ui/runDialog.js
|
||||||
js/ui/screenShield.js
|
|
||||||
js/ui/searchDisplay.js
|
js/ui/searchDisplay.js
|
||||||
js/ui/shellEntry.js
|
js/ui/shellEntry.js
|
||||||
js/ui/shellMountOperation.js
|
js/ui/shellMountOperation.js
|
||||||
js/ui/status/accessibility.js
|
js/ui/status/accessibility.js
|
||||||
js/ui/status/bluetooth.js
|
js/ui/status/bluetooth.js
|
||||||
js/ui/status/keyboard.js
|
js/ui/status/keyboard.js
|
||||||
js/ui/status/lockScreenMenu.js
|
|
||||||
js/ui/status/network.js
|
js/ui/status/network.js
|
||||||
js/ui/status/power.js
|
js/ui/status/power.js
|
||||||
js/ui/status/volume.js
|
js/ui/status/volume.js
|
||||||
|
js/ui/telepathyClient.js
|
||||||
js/ui/unlockDialog.js
|
js/ui/unlockDialog.js
|
||||||
js/ui/userMenu.js
|
js/ui/userMenu.js
|
||||||
js/ui/viewSelector.js
|
js/ui/viewSelector.js
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user