Compare commits
509 Commits
Author | SHA1 | Date | |
---|---|---|---|
3fd70e37bd | |||
5580cfaf63 | |||
17c46c2452 | |||
0996174b3d | |||
d6b6f814d3 | |||
987099ea55 | |||
b356aa8e3b | |||
566bdb50c2 | |||
2b57603271 | |||
c3528f5b6b | |||
4c7cc94cdc | |||
5ff2285707 | |||
d714dfd82e | |||
b1064cbe50 | |||
8d3e5ea507 | |||
001b6afc7e | |||
55d6c5ea8f | |||
fa2ff8158f | |||
97e7ea0b5d | |||
65dec2b72a | |||
5fd3ca8d09 | |||
dc9a8d505d | |||
fc8d13f4bd | |||
d1aa7de5d0 | |||
e279ef1c7c | |||
b88657ab83 | |||
d20e646ed6 | |||
8678b87120 | |||
960571a589 | |||
d856338f86 | |||
2b6b2d93a9 | |||
363bd04166 | |||
9bc1a68fe4 | |||
2c2729f7be | |||
9011959356 | |||
c79b8bbe7e | |||
da59eebf8e | |||
7854024326 | |||
a9ab8784c4 | |||
de5b00fd52 | |||
6547f75b12 | |||
827bf506a7 | |||
adc187c32e | |||
5350302b09 | |||
167ca75388 | |||
46cea67258 | |||
463e0919d4 | |||
98906c1da3 | |||
b71e66c335 | |||
2b6c5bb416 | |||
628e59894b | |||
703d2ead33 | |||
43f53a708f | |||
07e7331e7b | |||
c516af3130 | |||
39727d1156 | |||
85cd189a69 | |||
a8e35422f2 | |||
3941961f8b | |||
d9c6485cbf | |||
c52ccc76a3 | |||
be1c4f26b5 | |||
a6ee6739e0 | |||
54a8ad8bc6 | |||
2541bfcdf2 | |||
d7d5da0301 | |||
d2bd9efc25 | |||
779b18bf48 | |||
618a53b34f | |||
f4eaadb948 | |||
ea061b0f46 | |||
3652e42699 | |||
398489f661 | |||
70fc13500d | |||
18541c447e | |||
3294a6e1a7 | |||
38563c38e8 | |||
a465c5f996 | |||
1760ba1279 | |||
3d3c9546a2 | |||
203c5db5eb | |||
cf44234323 | |||
cc94076ffb | |||
8d137eae5b | |||
51fa9ae513 | |||
9951c92459 | |||
ee77e5d582 | |||
d74721f229 | |||
1aa97b19f7 | |||
95de48e986 | |||
a147d0428d | |||
90b3f7b7f6 | |||
c80acfda08 | |||
8a39145e3c | |||
b62f5ef07d | |||
bd5c6c5cd6 | |||
f874a57439 | |||
6a4525e554 | |||
d553a5bdc0 | |||
80076965a7 | |||
84e8d38d4c | |||
33f3f9d997 | |||
be72b1d066 | |||
dc5d2b83ef | |||
3dabe645c2 | |||
e9ede362dc | |||
01357aca35 | |||
c944dd6768 | |||
ff01ed5e4b | |||
d23c374326 | |||
a69ebc8a68 | |||
f4d8a35b9d | |||
2b140f8fb7 | |||
ab603bdbbf | |||
44e2f7f555 | |||
fd1b3b4fee | |||
4ae2a0b2a5 | |||
0cb415b3bd | |||
c1fa9a82e6 | |||
dde124ab5a | |||
668920cec4 | |||
9b38c5b304 | |||
e63c2da433 | |||
38c768fdb3 | |||
0dd4584157 | |||
b7bf712b97 | |||
615723d8df | |||
de352a309d | |||
c573e7f9a1 | |||
d59fd1a75d | |||
18d69d7032 | |||
5d25716cee | |||
840e79c18c | |||
ddf562e306 | |||
20a6ce7003 | |||
8c43298af0 | |||
4bb48e56d2 | |||
338ba10ca2 | |||
36eb745ecc | |||
b07e45e214 | |||
bba5198e63 | |||
9e2bab008a | |||
5ea032bbf7 | |||
897fadfb40 | |||
b05f71eb9b | |||
4ce0e80956 | |||
577ccc4d56 | |||
39d12351ba | |||
e37bc6d7f0 | |||
9593ff3582 | |||
ad8dfd7b04 | |||
ca5ab20f67 | |||
0eab448221 | |||
a26a77f9db | |||
c3df6bb8bd | |||
ce3a26cf37 | |||
04482c23c4 | |||
ff20fe856e | |||
12e3921f81 | |||
928fbee15b | |||
a103c028f9 | |||
775347d865 | |||
6d0be86a4e | |||
a4b69db8af | |||
790b9d3371 | |||
adef2009a5 | |||
1721db6d8d | |||
6d95e8b988 | |||
b07f9932db | |||
9439da81c4 | |||
6257e64d03 | |||
ba110f2d2e | |||
6bdf621d05 | |||
1c4db98c95 | |||
dadac957e4 | |||
cf3976d496 | |||
82ed80c9c3 | |||
67222525ad | |||
fff0861773 | |||
13ffe41498 | |||
96e0528a7b | |||
3df30fbd57 | |||
b57d8b336b | |||
3169b2c440 | |||
6bc34e0f32 | |||
cecb1a41fb | |||
b9069df85c | |||
aee3c6f041 | |||
c427bba9f1 | |||
da83ad561b | |||
85520e34ab | |||
d0edd970e1 | |||
8529ca70af | |||
1a8d78212f | |||
4270a2806d | |||
4333bdc709 | |||
75b824d032 | |||
7bc2573d85 | |||
67b7b7a950 | |||
786cfbd397 | |||
9df8b583cf | |||
8e32290dc9 | |||
23478f3336 | |||
2e244ecb63 | |||
e307680206 | |||
6bb1a3e2c4 | |||
8a1ac6b13f | |||
61b8af2252 | |||
c99afed012 | |||
2947b92148 | |||
39c5d23a87 | |||
d839670f54 | |||
0d1b7e15d1 | |||
ac678f63ee | |||
d862c0879b | |||
23a4d4c69e | |||
472b20d933 | |||
492dd718fb | |||
0d5618fdd1 | |||
503508af41 | |||
4ec5e55122 | |||
8daca865ca | |||
f9b37a21e8 | |||
c398f319fc | |||
1e049f88b8 | |||
4831d9c3a3 | |||
f13f5bc1bb | |||
4e114107ed | |||
0ccb280008 | |||
28c3e0693e | |||
c321c8a02f | |||
2407ec7b47 | |||
70eeb75716 | |||
751d250471 | |||
c28217db80 | |||
0968e556fa | |||
130f2cf808 | |||
4eec7413c7 | |||
efc3246d26 | |||
9930dbc0ff | |||
754f87dac3 | |||
51139bd096 | |||
6e0119d620 | |||
a3528bf973 | |||
77c36af588 | |||
69c0a52a33 | |||
a7442cd0a5 | |||
d47a013931 | |||
745f9c0e6e | |||
414f49fd80 | |||
e49a595f54 | |||
77485c2a04 | |||
e9b28634e5 | |||
b43dcb8876 | |||
f0c1eeece8 | |||
1e6b824ede | |||
1e2d16273c | |||
32dc24c59b | |||
7a8a189c48 | |||
6aa411fecc | |||
9c76318df8 | |||
6510904711 | |||
a9817f4832 | |||
9067689839 | |||
4e9e91fdce | |||
73cc91ba60 | |||
0ab0d0860f | |||
337b399a75 | |||
46f21e81e3 | |||
c1300ddbbc | |||
8bd5b1e696 | |||
40c5db397d | |||
8b52919b4d | |||
2859f23038 | |||
00384ccb47 | |||
0191cc589a | |||
dae6db9b51 | |||
4d912c9feb | |||
07c4b46466 | |||
e9cdce49a3 | |||
84c3ce8778 | |||
d5a32a7fe4 | |||
cc4dfda21b | |||
703b37aa7b | |||
b433de9022 | |||
0c1a22ff95 | |||
4d526e40c3 | |||
4586c7b36b | |||
3d60b73b60 | |||
4ef5cd8ef6 | |||
6959bd19f1 | |||
17e4ce5ea8 | |||
33094b4988 | |||
a8fdcffd44 | |||
5adb5411fa | |||
ff0d11c89c | |||
5f6dce2b5c | |||
a7405e8b39 | |||
d87c520bad | |||
24959f8d34 | |||
6d1432e166 | |||
2c7ba2c125 | |||
a0ba664c64 | |||
131da5f523 | |||
7c6144450a | |||
4c7369db16 | |||
f4355de896 | |||
4a3db9f44d | |||
6c0a9ff9cc | |||
57b1695fcf | |||
045c6546cc | |||
ce5bd954bf | |||
6ef00a4a3b | |||
569d9718a0 | |||
00a3a8697f | |||
c93444e390 | |||
5e5788ab14 | |||
abf57e6362 | |||
74c2074d5a | |||
b74606312e | |||
0c849df4d5 | |||
38690d4a09 | |||
b64c237cb3 | |||
3fbee8e027 | |||
a68e6e3c63 | |||
db5a72774d | |||
966f90f24a | |||
eaa664c023 | |||
e9282c3987 | |||
ed1f8ed339 | |||
5d0d637eb8 | |||
7e70dfdf4c | |||
3f61f39ae3 | |||
371f623a3e | |||
566d566f26 | |||
fb30822860 | |||
526a53bdd4 | |||
3833124d66 | |||
e5e1b52abf | |||
82fc66305d | |||
05e0d5066f | |||
ce2dc84e49 | |||
eb14ed32ea | |||
f97987d0d8 | |||
d23d9c3b05 | |||
3ebf6e3bea | |||
9f41f5c740 | |||
ae00f86887 | |||
ab67c0f8b0 | |||
ed7d4928e5 | |||
f23239a923 | |||
d949920e68 | |||
a1def85c18 | |||
dc624f65e4 | |||
361652d028 | |||
92024b7e54 | |||
4e4ce0dd21 | |||
bc0c490ec3 | |||
6d92af17fd | |||
2140a498a2 | |||
28349d362c | |||
e7af9f98e3 | |||
dd6053c5e1 | |||
37726a4cb6 | |||
4352cc231e | |||
824220356f | |||
247ad9d7ab | |||
09fe12d0c1 | |||
127ef8383b | |||
82eccb566c | |||
543b29efe7 | |||
0f4ce5dd4e | |||
c23919df15 | |||
2b2a8b4747 | |||
2e48dbf6ee | |||
207917ba45 | |||
f824b97f3a | |||
a5ff2fc68f | |||
4906806c0b | |||
d98336a906 | |||
9ddd11cdb8 | |||
554ad4ef05 | |||
45d8550044 | |||
f2b44c1494 | |||
bdb28e87a9 | |||
8b9592e53e | |||
84f89648a6 | |||
1174992099 | |||
391a220dc1 | |||
43f1d0578b | |||
d3e35028ca | |||
61c7d87003 | |||
20f2fa84a4 | |||
17e269b96c | |||
6a57ac92ba | |||
07ad03556f | |||
04c33230c8 | |||
083dac630f | |||
6375724196 | |||
922957c1ae | |||
cbf7d0e738 | |||
fb81efeecf | |||
8466198626 | |||
33718ef7a5 | |||
a94a62764d | |||
12c98df3db | |||
81909a406f | |||
d291aaa4f2 | |||
da36d87e46 | |||
42bc09a7ef | |||
d0defc592e | |||
700f7fbaf3 | |||
74f2d02ac3 | |||
c865d96f4b | |||
cd7b9e108c | |||
f54b82f64c | |||
36bfe8c533 | |||
a40d063cb8 | |||
ac88a88bfb | |||
d89c9b4556 | |||
a07056f5e2 | |||
f91bea3ea5 | |||
9fbd79316a | |||
6d89d0b02a | |||
0febcbfa2a | |||
f2f2898fe3 | |||
f65826b3ba | |||
a869007180 | |||
b5fa48f485 | |||
36d564526c | |||
063f34b5d3 | |||
9486ca5975 | |||
63ead272a9 | |||
9dfa2ad84e | |||
523e431ece | |||
768c4a0dd5 | |||
fd25cf30ff | |||
1d14488a4f | |||
6e32c97c43 | |||
020fe35d98 | |||
e0cf946611 | |||
a42ae6fe3a | |||
196ab6a7c3 | |||
f3235882f3 | |||
0518d69b72 | |||
c9ba94d4d8 | |||
50e4a40bb2 | |||
351421c158 | |||
c3ac2df9ca | |||
7c4f632e06 | |||
a4eb3c17eb | |||
e81cee3949 | |||
e943dcafa4 | |||
a324c390f0 | |||
1cf64b5471 | |||
234a4f3a1b | |||
e69d561e8e | |||
b8f2abcbfa | |||
189617dfb2 | |||
c4bfb1e400 | |||
7db92ad5d9 | |||
fa593a3e15 | |||
8424236daa | |||
5c14be28f3 | |||
9ef80f6ac6 | |||
daf81b5cae | |||
7b407dda91 | |||
4c50293f06 | |||
02b8804b96 | |||
7928f90cf6 | |||
d5e6ea6ebd | |||
52273b6c03 | |||
b3d663b758 | |||
c0028694d4 | |||
3b0110849c | |||
7b1deba590 | |||
7a91f318f0 | |||
2dfde89008 | |||
23146c00ba | |||
cdd95fbbdc | |||
01064af20e | |||
01a9c3fc8e | |||
c1734b279b | |||
b00dc31b55 | |||
c5f8c8c77b | |||
9361c7223d | |||
b43cc22704 | |||
8af4fd64c1 | |||
5b39b87199 | |||
092338a4c7 | |||
7907b19e28 | |||
5790309e88 | |||
9496b64c86 | |||
f7fb6b2160 | |||
98649f9397 | |||
45a1ceaa54 | |||
6496205081 | |||
e2898bea5c | |||
563221698c | |||
92a85071bc | |||
9ae8d90be4 | |||
caade78e79 | |||
4f22c61b16 | |||
5e220e9e47 | |||
857cb9c501 | |||
09fa5d98c2 | |||
268fe464de | |||
27095d1a02 | |||
dd061fed38 |
13
.gitignore
vendored
13
.gitignore
vendored
@ -21,6 +21,19 @@ data/gnome-shell.desktop.in
|
||||
data/gschemas.compiled
|
||||
data/org.gnome.shell.gschema.xml
|
||||
data/org.gnome.shell.gschema.valid
|
||||
docs/reference/*/*.args
|
||||
docs/reference/*/*.bak
|
||||
docs/reference/*/*.hierarchy
|
||||
docs/reference/*/*.interfaces
|
||||
docs/reference/*/*.prerequisites
|
||||
docs/reference/*/*.sgml
|
||||
docs/reference/*/*.signals
|
||||
docs/reference/*/*.stamp
|
||||
docs/reference/*/*.txt
|
||||
docs/reference/*/*.types
|
||||
docs/reference/*/html/
|
||||
docs/reference/*/xml/
|
||||
gtk-doc.make
|
||||
js/misc/config.js
|
||||
intltool-extract.in
|
||||
intltool-merge.in
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Point to our macro directory and pick up user flags from the environment
|
||||
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
|
||||
|
||||
SUBDIRS = data js src tests po man
|
||||
SUBDIRS = data js src browser-plugin tests po man docs
|
||||
|
||||
EXTRA_DIST = \
|
||||
.project \
|
||||
@ -19,3 +19,5 @@ DIST_EXCLUDE = \
|
||||
distcheck-hook:
|
||||
@echo "Checking disted files against files in git"
|
||||
@$(srcdir)/tools/check-for-missing.py $(srcdir) $(distdir) $(DIST_EXCLUDE)
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc
|
||||
|
255
NEWS
255
NEWS
@ -1,3 +1,258 @@
|
||||
3.3.2
|
||||
=====
|
||||
* Port D-Bus usage in the shell to GDBus [Giovanni, Marc-Antoine, Florian,
|
||||
Jasper, Matthias; #648651, #658078, #663902, #663941]
|
||||
* Message tray
|
||||
- Add right-click option to chats to mute the conversation [Ana; #659962]
|
||||
- Don't steal the focus when popping up under the pointer [Rui; #661358]
|
||||
* Looking Glass
|
||||
- Add alt-Tab completion [Jason; #661054]
|
||||
- Show errors from extensions in the extensions tab [Jasper; #660546]
|
||||
- Allow switching tabs with <Control>PageUp/PageDown
|
||||
- Theme consistently with the rest of the shell [Jason; 650900]
|
||||
* Extension system
|
||||
- Don't try to load disabled extensions at all [Jasper; #661815, #662704]
|
||||
- Enable and disable plugins in a consistent order [Jasper; #661815, #662704]
|
||||
- Add options to enable/disable extensions to gnome-shell-extension-tool
|
||||
[Jasper; #661815]
|
||||
* Adapt to Mutter change to GSettings [Florian, Matthias; #663429]
|
||||
* Allow creating a new workspace by dragging a window or launcher in the
|
||||
middle of two existing ones [Jasper; #646409]
|
||||
* Allow using Alt-Tab while during drag-and-drop and other operations
|
||||
that grab the pointer [Adel; #660457]
|
||||
* Do a better job of finding the right user to authenticate
|
||||
as when showing a PolKit dialog [Matthias; #651547]
|
||||
* Control the D-Bus Eval() method by the developer-tools GSetting which
|
||||
is used for looking glass and screen recorder. [Jasper; #662891]
|
||||
* Fix browser plugin to work under WebKit-based browser [Jasper; #663823]
|
||||
* Fix certain stacking issues with alt-Tab [Jasper; #660650]
|
||||
* Fixes for GLib deprecations [Jasper; #662011]p
|
||||
* Fixes for GTK+ deprecations [Florian, Rico; #662245]p
|
||||
* Fixes for Clutter deprecations [Jasper; #662627]
|
||||
* Visual improvements and UI tweaks [Florian, Jakub, Jasper;
|
||||
#662800, #658096, #662226]
|
||||
* Hard-code "Home" as the name for the home dir, rather than looking
|
||||
it up via GSettings; avoids schema dependency [Cosimo; #559895]
|
||||
* Don't show "Switch User" on single user machines [Florian; #657011]
|
||||
* Generate documentation for St toolkit [Florian]
|
||||
* Improve marking of strings for translation [Matthias, Piotr; #658664]
|
||||
* Networking menu bug fixes [Giovanni; #650007, #651378, #659277, #663278]
|
||||
* Code cleanups and leak fixes to StTextureCache
|
||||
[Jasper, Florian; #660968, #662998]
|
||||
* Code cleanups [Adel, Florian, Jasper; #662238, #663584]
|
||||
* Build fixes [Adel, Colin, Florian, Ming Han]
|
||||
* Misc bug fixes [Adel, Florian, "Fry", Jasper, Giovanni, Ray, Rui, Stefan;
|
||||
#660520, #661029, #661231, #661623, #661921, #662235, #662236, #662502,
|
||||
#662394, #662799, #662969, #663175, #663277, #663815, #663891, #662967]
|
||||
|
||||
Contributors:
|
||||
Giovanni Campagna, Cosimo Cecchi, Matthias Clasen, Piotr Drąg, Adel Gadllah,
|
||||
Rui Matos, Florian Müllner, Marc-Antoine Perennou, Ana Risteska,
|
||||
Jason Siefken, Jakub Steiner, Ray Strode, Jasper St. Pierre, Ming Han Teh,
|
||||
Rico Tzschichholz, Colin Walters, Stefan Zwanenburg
|
||||
|
||||
Translation:
|
||||
Alexander Shopov [bg], Marek Černocký [cs], Mario Blättermann [de],
|
||||
Kostas Papadimas [el], Bruce Cowan [en_GB], Kristjan Schmidt [eo],
|
||||
Jorge González, Daniel Mustieles, Benjamín Valero Espinosa [es],
|
||||
Mattias Põldaru [et], Arash Mousavi [fa], Ville-Pekka Vainio [fi],
|
||||
Fran Diéguez [gl], Yaron Shahrabani [he], Hideki Yamane [ja],
|
||||
Algimantas Margevičius [lt], Kjartan Maraas [nb], Daniel Nylander [se],
|
||||
Matej Urbančič [sl], Praveen Illa [te], Muhammet Kara [tr],
|
||||
Nguyễn Thái Ngọc Duy [vi], Cheng-Chia Tseng [zh_HK, zh_TW]
|
||||
|
||||
3.2.1
|
||||
=====
|
||||
* Restore the IM state on startup - if you were available in when you logged
|
||||
out, then you'll be set available again when you log in.
|
||||
[Florian; #65902, #661485]
|
||||
* Improve searching for contacts in the overview: search more fields,
|
||||
show a more meaningful name, require that all search terms match.
|
||||
[Florian, Matthias; #660580]
|
||||
* Improve search for applications in the overview: take frequency into
|
||||
account and tweak match algorithm [Florian; #623372]
|
||||
* Remove the "Show Password" switch from network password prompts, and
|
||||
move the functionality to a right-click menu [Florian; #658948]
|
||||
* Add context menus with Cut/Paste options to most entries [Florian; #659275]
|
||||
* On screen keyboard:
|
||||
- Show the keyboard immediately when it's turned enabled [Dan; #659743]
|
||||
- Fix problem where keyboard would hide when starting to type
|
||||
in the search entry [Nohemi; #661340]
|
||||
- Fix problem with keyboard hiding when selected accented characters
|
||||
[Nohemi; 661707]
|
||||
* Login mode:
|
||||
- Allow hitting Enter to select the first user [Ray; #657996]
|
||||
- Fix flicker of a fingerprint prompt that could show up [Ray; #660492]
|
||||
- Fix password bullets vanishing during login [Ray; #657894]
|
||||
- Misc bug fixes and visual tweaks [Ray; #659763, #660919, #661479]
|
||||
* Display a caps-lock warning in password entries [Florian; #660806]
|
||||
* Show the state of installed extensions in Looking Glass [Jasper; #660494]
|
||||
* Load user extensions after system ones [Jasper; #661815]
|
||||
* Fix problem with many applications showing extra-large icons in
|
||||
notifications [Marina; #659158]
|
||||
* Fix a problem where alt-Tab had trouble tracking the current
|
||||
application with certain applications such as Emacs. [Dan; #645026]
|
||||
* Fix confusion between different users avatar images [Florian; #660585]
|
||||
* Remove behavior where you could switch workspaces by bumping
|
||||
a dragged window in the overview against a screen edge; it was
|
||||
leftover and just confusing. [Florian; #660838]
|
||||
* Fix long-standing bug where the Dash in the overview could end up mis-sized
|
||||
and run off the screen [Florian; #649248]
|
||||
* Fix automatic launching of applications when media is inserted
|
||||
[Cosimo; #660821]
|
||||
* Fix handling of vertically stacked monitors with NVIDIA drivers
|
||||
[Florian; #661387]
|
||||
* Translation marking fixes [Jasper, Wouter; #660600]
|
||||
* Code cleanups and warning fixes [Adel, Dan, Florian, Jasper;
|
||||
#659822, #659940, #660122, #660358, #660968, #661231]
|
||||
* Small memory leak fixes [Florian, Jasper; #661231]
|
||||
* Misc bug fixes [Adel, Florian, Jasper; #659274, #659861, #660166, #660310,
|
||||
#660397, #660608, #660606, #660674, #660774. #660848, #661151, #661617]
|
||||
|
||||
Contributors:
|
||||
Wouter Bolsterlee, Cosimo Cecchi, Matthias Clasen, Nohemi Fernandez,
|
||||
Adel Gadllah, Florian Müllner, Jasper St. Pierre, Ray Strode, Dan Winship,
|
||||
Marina Zhurakhinskaya
|
||||
|
||||
Translations:
|
||||
Tiffany Antopolski [eo], Xandru Armesto [ast], Alexander Shopov,
|
||||
Ivaylo Valkov [bg], Gil Forcada [ca], Carles Ferrando [ca@valencia],
|
||||
Mario Blättermann, Paul Seyfert [de], Bruce Cowan [en_GB],
|
||||
Jorge González, Daniel Mustieles [es], Arash Mousavi [fa], Bruno Brouard [fr],
|
||||
Seán de Búrca [ga], Fran Diéguez [gl], Gabor Kelemen [hu], Luca Ferretti [it],
|
||||
Takayuki Kusano [ja], Changwoo Ryu [ko], Erdal Ronahi [ku],
|
||||
Algimantas Margevičius [lt], Rudolfs Mazurs [lv], Wouter Bolsterlee [nl],
|
||||
Piotr Drąg [pl], Adorilson Bezerra [pt_BR], Yuri Myasoedov [ru],
|
||||
Matej Urbančič [sl], Daniel Nylander [sv], Miroslav Nikolić [sr, sr@latin],
|
||||
Tirumurti Vasudevan [ta], Krishnababu Krothapalli [te], Daniel Korostil [uk],
|
||||
Nguyễn Thái Ngọc Duy [vi], YunQiang Su [zh_CN]
|
||||
|
||||
3.2.0
|
||||
=====
|
||||
* Prevent the fallback on-screen keyboard from showing up while
|
||||
GNOME Shell is running [Dan, #659865]
|
||||
* Disable code to reposition windows around the on-screen keyboard;
|
||||
it wasn't finished or working properly. [Dan; #659643]
|
||||
* Fix interaction between on-screen keyboard and notifications
|
||||
[Dan; #658603]
|
||||
* Fix menu-sizing problems in right-to-left locales. [Florian; #659827]
|
||||
* Update chat icons in the message tray when an avatar image changes
|
||||
[Marina; #659768]
|
||||
* Fix problem with empty notification bubbles being left [Marina; #659862]
|
||||
* Fix problem with chat notifications bouncing when new messages come in.
|
||||
[Marina; #659768]
|
||||
* Fix bug that was causing SIP calls to automatically be accepted in some
|
||||
circumstances [Guillaume; #660084]
|
||||
* Fix string that should have been marked translatable [Frédéric]
|
||||
* Fix a crash that could happen during CSS transitions [Florian; #659676]
|
||||
* Build fixes [Colin, Florian]
|
||||
|
||||
Contributors:
|
||||
Guillaume Desmottes, Florian Müllner, Frédéric Péters, Colin Walters,
|
||||
Dan Winship, Marina Zhurakhinskaya
|
||||
|
||||
Translations:
|
||||
Friedel Wolff [af], Nilamdyuti Goswami [as], Ihar Hrachyshka [be],
|
||||
Ivaylo Valkov [bg], Gil Forcada [ca], Carles Ferrando [ca@valencia],
|
||||
Petr Kovar [cz], Mario Blättermann [de], Kris Thomsen [dk],
|
||||
Tiffany Antopolski, Kristjan Schmidt [eo], Daniel Mustieles [es],
|
||||
Inaki Larranaga Murgoitio [eu], Tommi Vainikainen [fi], Bruno Brouard [fr],
|
||||
Fran Dieguez [gl], Yaron Shahrabani [he], Gabor Kelemen [hu],
|
||||
Andika Triwidada [id], Jiro Matsuzawa [ja], Changwoo Ryu [ko],
|
||||
Rudolfs Mazurs [lv], Aurimas Černius [lt], Kjartan Maraas [nb],
|
||||
A S Alam [pa], Piotr Drąg [pl], Duarte Loreto [pt], Djavan Fagundes,
|
||||
Rodolfo Ribeiro Gomes, Gabriel F. Vilar [pt_BR], Yuri Myasoedov [ru],
|
||||
Daniel Nylander [se], Martin Srebotnjak [sl], Michal Štrba [sv],
|
||||
Krishnababu Krothapalli, Praveen Illa [te], Cheng-Chia Tseng [zh_KH, zh_TW]
|
||||
|
||||
3.1.92
|
||||
======
|
||||
|
||||
* Login screen
|
||||
- Add the ability to set a logo at the top of the user list [Ray; #658062]
|
||||
- Add fingerprint reader support [Ray; #657823]
|
||||
- Add a power button offering the choice of Suspend/Restart/Power off
|
||||
[Ray; #657822]
|
||||
- Remove the option to view the current keyboad layout [Matthias; #659164]
|
||||
- Make Control-Alt-Tab work for full keyboard access [Ray; #659177]
|
||||
* Frequently initiate a full garbage collection; Spidermonkey isn't very good
|
||||
at tracking the amount of resources we have allocated so this hopefully will
|
||||
improve memory usage without affecting performance too much [Colin; #659254]
|
||||
* Stop adding a notification when the network connection is lost
|
||||
[Colin; #658954]
|
||||
* When disabling notifications; display a notification
|
||||
"Your chat status will be set to busy" [Florian; #652718]
|
||||
* Fix keynav in network dialogs [Florian; #659133]
|
||||
* Improve calendar styling [Sean; #641135, #651299]
|
||||
* Shrink padding around panel buttons for narrow screens [Dan; #651299]
|
||||
* Allow enabling the onscreen keyboard through the accessibility menu
|
||||
[Dan; #612662]
|
||||
* Fix problem that was causing VPN secret dialogs to be delayed before showing
|
||||
[Florian; #658484]
|
||||
* Make custom-keybindings for the window switcher that don't use alt
|
||||
work correctly [Florian; #645200]
|
||||
* Fix duplicate application icons in the Activities Overview [Colin; #659351]
|
||||
* Bug fixes for dimming windows with attached modal dialogs
|
||||
[Jasper, Owen; #659302, 659634]
|
||||
* Add build-time support for BROWSER_PLUGIN_DIR environment variable
|
||||
[Vincent; #659123]
|
||||
* Build fixes [Vincent; #659194]
|
||||
* Code cleanups and test cases
|
||||
[Adel, Dan, Florian, Jasper; #651299, #658092, #658939]
|
||||
* Misc bug fixes
|
||||
[Adel, Colin, Cosimo, Dan, Florian, Giovanni, Jasper, Ray, Xavier;
|
||||
#651299, #652837, #657249, #658004, #658150, #658239, #658469, #658598,
|
||||
#658605, #659050, #659159, #659210, #659270, #659370, #659633]
|
||||
|
||||
Contributors:
|
||||
Giovanni Campagna, Cosimo Cecchi, Xavier Claessens, Matthias Clasen,
|
||||
Rui Matos, Florian Müllner, Jasper St. Pierre, Owen Taylor,
|
||||
Vincent Untz, Colin Walters, Sean Wilson, Dan Winship
|
||||
|
||||
Translations:
|
||||
Ihar Hrachyshka [be], Alexander Shopov, Ivaylo Valkov [bg],
|
||||
Mario Blättermann [de], Jorge González, Daniel Mustieles [es],
|
||||
Arash Mousavi [fa], Ville-Pekka Vainio [fi], Fran Dieguez [gl],
|
||||
Sweta Kothari [gu], Gabor Kelemen [hu], Jiro Matsuzawa [ja],
|
||||
Luca Ferretti [it], Rudolfs Mazurs [lv], Kjartan Maraas [nb], A S Alam [pa],
|
||||
Piotr Drąg [pl], Duarte Loreto [pt], Yuri Myasoedov [ru],
|
||||
Daniel Nylander [se], Matej Urbančič [sl], Miroslav Nikolić [sr, sr@latin],
|
||||
Michal Štrba [sv], Tirumurti Vasudevan [ta], Phương Lê Hoàng [vi],
|
||||
Aron Xu [zh_CN], Chao-Hsiung Liao [zh_HK, zh_TW]
|
||||
|
||||
3.1.91.1
|
||||
========
|
||||
|
||||
* Add a browser plugin - this plugin, tied to extensions.gnome.org,
|
||||
allows users to download and install shell extensions, and enable,
|
||||
disable, and uninstall extensions they already have installed.
|
||||
[Jasper; #658070, #658612]
|
||||
* Improve adding links to URLs in notifications [Dan; #636252]
|
||||
* Remove "connection lost" notifications after reconnecting [Giovanni; #658049]
|
||||
* Hide the onscreen keyboard when leaving a text entry [Dan; #658591]
|
||||
* Fixes for translated strings [Florian; #639987, #644097, #645037]
|
||||
* Bug fixes for network menu [Florian; #658492]
|
||||
* Code cleanup [Dan; #646934]
|
||||
* Build fixes [Javier, Rico]
|
||||
* Misc bug fixes [Emmanuele, Florian, Jasper, Marina, Matthias, Ray;
|
||||
#652837, #658423, #658503, #658525, #658562, #658624, #658640, #658983]
|
||||
|
||||
Conributors:
|
||||
Emmanuele Bassi, Giovanni Campagna, Matthias Clasen, Javier Jardón,
|
||||
Florian Muellner, Jasper St. Pierre, Ray Strode, Rico Tzschichholz,
|
||||
Dan Winship, Marina Zhurakhinskaya
|
||||
|
||||
Translations:
|
||||
Ihar Hrachyshka [be], Bruce Cowan [en_GB], Jorge González,
|
||||
Daniel Mustieles [es], Timo Jyrinki [fi], Bruno Brouard, Luc Guillemin,
|
||||
Claude Paroz, Luc Pionchon [fr], Fran Dieguez [gl], Rajesh Ranjan [hi],
|
||||
Andika Triwidada [id], Luca Ferretti [it], Changwoo Ryu [ko],
|
||||
Rudolfs Mazurs [lt], Kjartan Maraas [nb], Manoj Kumar Giri [or],
|
||||
A S Alam [pa], Piotr Drąg [pl], Duarte Loreto [pt], Henrique P. Machado,
|
||||
Gabriel F. Vilar [pt_BR], Daniel Nylander [se], Matej Urbančič [sl],
|
||||
Tirumurti Vasudevan [ta], Yinghua Wang [zh_CN],
|
||||
Chao-Hsiung Liao [zh_HK, zh_TW]
|
||||
|
||||
3.1.91
|
||||
======
|
||||
|
||||
|
21
browser-plugin/Makefile.am
Normal file
21
browser-plugin/Makefile.am
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
mozillalibdir = $(BROWSER_PLUGIN_DIR)
|
||||
|
||||
mozillalib_LTLIBRARIES = libgnome-shell-browser-plugin.la
|
||||
|
||||
libgnome_shell_browser_plugin_la_LDFLAGS = -module -avoid-version -no-undefined
|
||||
|
||||
libgnome_shell_browser_plugin_la_LIBADD = \
|
||||
$(BROWSER_PLUGIN_LIBS)
|
||||
|
||||
libgnome_shell_browser_plugin_la_SOURCES = \
|
||||
browser-plugin.c \
|
||||
npapi/npapi.h \
|
||||
npapi/npfunctions.h \
|
||||
npapi/npruntime.h \
|
||||
npapi/nptypes.h
|
||||
|
||||
libgnome_shell_browser_plugin_la_CFLAGS = \
|
||||
$(BROWSER_PLUGIN_CFLAGS) \
|
||||
-DG_DISABLE_DEPRECATED \
|
||||
-DG_LOG_DOMAIN=\"GnomeShellBrowserPlugin\"
|
17
browser-plugin/README
Normal file
17
browser-plugin/README
Normal file
@ -0,0 +1,17 @@
|
||||
The GNOME Shell Browser Plugin provides integration with gnome-shell and the
|
||||
corresponding extensions repository, codenamed "SweetTooth". The plugin allows
|
||||
the extensions repository to provide good integration, letting the website
|
||||
know which extensions are enabled and disabled, and allowing the website to
|
||||
enable, disable and install them.
|
||||
|
||||
Bugs should be reported at http://bugzilla.gnome.org against the 'gnome-shell'
|
||||
product.
|
||||
|
||||
License
|
||||
=======
|
||||
The GNOME Shell Browser Plugin, like GNOME Shell itself is distributed under
|
||||
the GNU General Public License, version 2 or later. The plugin also contains
|
||||
header files from the "NPAPI SDK" project, tri-licensed under MPL 1.1, GPL 2.0
|
||||
and LGPL 2.1. These headers are third-party sources and can be retrieved from:
|
||||
|
||||
http://code.google.com/p/npapi-sdk/
|
826
browser-plugin/browser-plugin.c
Normal file
826
browser-plugin/browser-plugin.c
Normal file
@ -0,0 +1,826 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat
|
||||
*
|
||||
* 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 of the
|
||||
* License, 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.
|
||||
*
|
||||
* Authors:
|
||||
* Jasper St. Pierre <jstpierre@mecheye.net>
|
||||
* Giovanni Campagna <scampa.giovanni@gmail.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define XP_UNIX 1
|
||||
|
||||
#include "npapi/npapi.h"
|
||||
#include "npapi/npruntime.h"
|
||||
#include "npapi/npfunctions.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <gio/gio.h>
|
||||
#include <json-glib/json-glib.h>
|
||||
|
||||
#define ORIGIN "extensions.gnome.org"
|
||||
#define PLUGIN_NAME "Gnome Shell Integration"
|
||||
#define PLUGIN_DESCRIPTION "This plugin provides integration with Gnome Shell " \
|
||||
"for live extension enabling and disabling. " \
|
||||
"It can be used only by extensions.gnome.org"
|
||||
#define PLUGIN_MIME_STRING "application/x-gnome-shell-integration::Gnome Shell Integration Dummy Content-Type";
|
||||
|
||||
#define PLUGIN_API_VERSION 1
|
||||
|
||||
typedef struct {
|
||||
GDBusProxy *proxy;
|
||||
} PluginData;
|
||||
|
||||
static NPNetscapeFuncs funcs;
|
||||
|
||||
static inline gchar *
|
||||
get_string_property (NPP instance,
|
||||
NPObject *obj,
|
||||
const char *name)
|
||||
{
|
||||
NPVariant result = { NPVariantType_Void };
|
||||
NPString result_str;
|
||||
gchar *result_copy;
|
||||
|
||||
result_copy = NULL;
|
||||
|
||||
if (!funcs.getproperty (instance, obj,
|
||||
funcs.getstringidentifier (name),
|
||||
&result))
|
||||
goto out;
|
||||
|
||||
if (!NPVARIANT_IS_STRING (result))
|
||||
goto out;
|
||||
|
||||
result_str = NPVARIANT_TO_STRING (result);
|
||||
result_copy = g_strndup (result_str.UTF8Characters, result_str.UTF8Length);
|
||||
|
||||
out:
|
||||
funcs.releasevariantvalue (&result);
|
||||
return result_copy;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_origin_and_protocol (NPP instance)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
NPError error;
|
||||
NPObject *window = NULL;
|
||||
NPVariant document = { NPVariantType_Void };
|
||||
NPVariant location = { NPVariantType_Void };
|
||||
gchar *hostname = NULL;
|
||||
gchar *protocol = NULL;
|
||||
|
||||
error = funcs.getvalue (instance, NPNVWindowNPObject, &window);
|
||||
if (error != NPERR_NO_ERROR)
|
||||
goto out;
|
||||
|
||||
if (!funcs.getproperty (instance, window,
|
||||
funcs.getstringidentifier ("document"),
|
||||
&document))
|
||||
goto out;
|
||||
|
||||
if (!NPVARIANT_IS_OBJECT (document))
|
||||
goto out;
|
||||
|
||||
if (!funcs.getproperty (instance, NPVARIANT_TO_OBJECT (document),
|
||||
funcs.getstringidentifier ("location"),
|
||||
&location))
|
||||
goto out;
|
||||
|
||||
if (!NPVARIANT_IS_OBJECT (document))
|
||||
goto out;
|
||||
|
||||
hostname = get_string_property (instance,
|
||||
NPVARIANT_TO_OBJECT (location),
|
||||
"hostname");
|
||||
|
||||
if (g_strcmp0 (hostname, ORIGIN))
|
||||
{
|
||||
g_debug ("origin does not match, is %s",
|
||||
hostname);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
protocol = get_string_property (instance,
|
||||
NPVARIANT_TO_OBJECT (location),
|
||||
"protocol");
|
||||
|
||||
if (g_strcmp0 (protocol, "https:") != 0)
|
||||
{
|
||||
g_debug ("protocol does not match, is %s",
|
||||
protocol);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
g_free (protocol);
|
||||
g_free (hostname);
|
||||
|
||||
funcs.releasevariantvalue (&location);
|
||||
funcs.releasevariantvalue (&document);
|
||||
|
||||
if (window != NULL)
|
||||
funcs.releaseobject (window);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* =============== public entry points =================== */
|
||||
|
||||
NPError
|
||||
NP_Initialize(NPNetscapeFuncs *pfuncs, NPPluginFuncs *plugin)
|
||||
{
|
||||
/* global initialization routine, called once when plugin
|
||||
is loaded */
|
||||
|
||||
g_debug ("plugin loaded");
|
||||
|
||||
memcpy (&funcs, pfuncs, sizeof (funcs));
|
||||
|
||||
plugin->size = sizeof(NPPluginFuncs);
|
||||
plugin->newp = NPP_New;
|
||||
plugin->destroy = NPP_Destroy;
|
||||
plugin->getvalue = NPP_GetValue;
|
||||
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
NPError
|
||||
NP_Shutdown(void)
|
||||
{
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
const char*
|
||||
NP_GetMIMEDescription(void)
|
||||
{
|
||||
return PLUGIN_MIME_STRING;
|
||||
}
|
||||
|
||||
NPError
|
||||
NP_GetValue(void *instance,
|
||||
NPPVariable variable,
|
||||
void *value)
|
||||
{
|
||||
switch (variable) {
|
||||
case NPPVpluginNameString:
|
||||
*(char**)value = PLUGIN_NAME;
|
||||
break;
|
||||
case NPPVpluginDescriptionString:
|
||||
*(char**)value = PLUGIN_DESCRIPTION;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
NPError
|
||||
NPP_New(NPMIMEType mimetype,
|
||||
NPP instance,
|
||||
uint16_t mode,
|
||||
int16_t argc,
|
||||
char **argn,
|
||||
char **argv,
|
||||
NPSavedData *saved)
|
||||
{
|
||||
/* instance initialization function */
|
||||
PluginData *data;
|
||||
GError *error = NULL;
|
||||
|
||||
g_debug ("plugin created");
|
||||
|
||||
if (!check_origin_and_protocol (instance))
|
||||
return NPERR_GENERIC_ERROR;
|
||||
|
||||
data = g_slice_new (PluginData);
|
||||
instance->pdata = data;
|
||||
|
||||
data->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
NULL, /* interface info */
|
||||
"org.gnome.Shell",
|
||||
"/org/gnome/Shell",
|
||||
"org.gnome.Shell",
|
||||
NULL, /* GCancellable */
|
||||
&error);
|
||||
if (!data->proxy)
|
||||
{
|
||||
/* ignore error if the shell is not running, otherwise warn */
|
||||
if (error->domain != G_DBUS_ERROR ||
|
||||
error->code != G_DBUS_ERROR_NAME_HAS_NO_OWNER)
|
||||
{
|
||||
g_warning ("Failed to set up Shell proxy: %s", error->message);
|
||||
}
|
||||
g_clear_error (&error);
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
g_debug ("plugin created successfully");
|
||||
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
NPError
|
||||
NPP_Destroy(NPP instance,
|
||||
NPSavedData **saved)
|
||||
{
|
||||
/* instance finalization function */
|
||||
|
||||
PluginData *data = instance->pdata;
|
||||
|
||||
g_debug ("plugin destroyed");
|
||||
|
||||
g_object_unref (data->proxy);
|
||||
|
||||
g_slice_free (PluginData, data);
|
||||
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
/* =================== scripting interface =================== */
|
||||
|
||||
typedef struct {
|
||||
NPObject parent;
|
||||
NPP instance;
|
||||
GDBusProxy *proxy;
|
||||
NPObject *listener;
|
||||
gint signal_id;
|
||||
} PluginObject;
|
||||
|
||||
static void
|
||||
on_shell_signal (GDBusProxy *proxy,
|
||||
gchar *sender_name,
|
||||
gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
PluginObject *obj = user_data;
|
||||
|
||||
if (strcmp (signal_name, "ExtensionStatusChanged") == 0)
|
||||
{
|
||||
gchar *uuid;
|
||||
gint32 status;
|
||||
gchar *error;
|
||||
NPVariant args[3];
|
||||
NPVariant result;
|
||||
|
||||
g_variant_get (parameters, "(sis)", &uuid, &status, &error);
|
||||
STRINGZ_TO_NPVARIANT (uuid, args[0]);
|
||||
INT32_TO_NPVARIANT (status, args[1]);
|
||||
STRINGZ_TO_NPVARIANT (error, args[2]);
|
||||
|
||||
funcs.invokeDefault (obj->instance, obj->listener,
|
||||
args, 3, &result);
|
||||
|
||||
funcs.releasevariantvalue (&result);
|
||||
g_free (uuid);
|
||||
g_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
static NPObject *
|
||||
plugin_object_allocate (NPP instance,
|
||||
NPClass *klass)
|
||||
{
|
||||
PluginData *data = instance->pdata;
|
||||
PluginObject *obj = g_slice_new0 (PluginObject);
|
||||
|
||||
obj->instance = instance;
|
||||
obj->proxy = g_object_ref (data->proxy);
|
||||
obj->signal_id = g_signal_connect (obj->proxy, "g-signal",
|
||||
G_CALLBACK (on_shell_signal), obj);
|
||||
|
||||
g_debug ("plugin object created");
|
||||
|
||||
return (NPObject*)obj;
|
||||
}
|
||||
|
||||
static void
|
||||
plugin_object_deallocate (NPObject *npobj)
|
||||
{
|
||||
PluginObject *obj = (PluginObject*)npobj;
|
||||
|
||||
g_signal_handler_disconnect (obj->proxy, obj->signal_id);
|
||||
g_object_unref (obj->proxy);
|
||||
|
||||
if (obj->listener)
|
||||
funcs.releaseobject (obj->listener);
|
||||
|
||||
g_debug ("plugin object destroyed");
|
||||
|
||||
g_slice_free (PluginObject, obj);
|
||||
}
|
||||
|
||||
static NPIdentifier api_version_id;
|
||||
static NPIdentifier shell_version_id;
|
||||
static NPIdentifier get_info_id;
|
||||
static NPIdentifier list_extensions_id;
|
||||
static NPIdentifier enable_extension_id;
|
||||
static NPIdentifier install_extension_id;
|
||||
static NPIdentifier uninstall_extension_id;
|
||||
static NPIdentifier onextension_changed_id;
|
||||
static NPIdentifier get_errors_id;
|
||||
|
||||
static bool
|
||||
plugin_object_has_method (NPObject *npobj,
|
||||
NPIdentifier name)
|
||||
{
|
||||
return (name == get_info_id ||
|
||||
name == list_extensions_id ||
|
||||
name == enable_extension_id ||
|
||||
name == install_extension_id ||
|
||||
name == uninstall_extension_id ||
|
||||
name == get_errors_id);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
uuid_is_valid (const gchar *uuid)
|
||||
{
|
||||
gsize i;
|
||||
|
||||
for (i = 0; uuid[i]; i ++)
|
||||
{
|
||||
gchar c = uuid[i];
|
||||
if (c < 32 || c >= 127)
|
||||
return FALSE;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '&':
|
||||
case '<':
|
||||
case '>':
|
||||
case '/':
|
||||
case '\\':
|
||||
return FALSE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
jsonify_variant (GVariant *variant,
|
||||
NPVariant *result)
|
||||
{
|
||||
gboolean ret;
|
||||
GVariant *real_value;
|
||||
JsonNode *root;
|
||||
JsonGenerator *generator;
|
||||
gsize json_length;
|
||||
gchar *json;
|
||||
gchar *buffer;
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
/* DBus methods can return multiple values,
|
||||
* but we're only interested in the first. */
|
||||
g_variant_get (variant, "(@*)", &real_value);
|
||||
|
||||
root = json_gvariant_serialize (real_value);
|
||||
|
||||
generator = json_generator_new ();
|
||||
json_generator_set_root (generator, root);
|
||||
json = json_generator_to_data (generator, &json_length);
|
||||
|
||||
buffer = funcs.memalloc (json_length + 1);
|
||||
if (!buffer)
|
||||
{
|
||||
ret = FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
strcpy (buffer, json);
|
||||
|
||||
STRINGN_TO_NPVARIANT (buffer, json_length, *result);
|
||||
|
||||
out:
|
||||
g_variant_unref (variant);
|
||||
g_variant_unref (real_value);
|
||||
json_node_free (root);
|
||||
g_free (json);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plugin_list_extensions (PluginObject *obj,
|
||||
NPVariant *result)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GVariant *res;
|
||||
|
||||
res = g_dbus_proxy_call_sync (obj->proxy,
|
||||
"ListExtensions",
|
||||
NULL, /* parameters */
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1, /* timeout */
|
||||
NULL, /* cancellable */
|
||||
&error);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
g_warning ("Failed to retrieve extension list: %s", error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return jsonify_variant (res, result);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plugin_enable_extension (PluginObject *obj,
|
||||
NPString uuid,
|
||||
gboolean enabled)
|
||||
{
|
||||
const gchar *uuid_str = uuid.UTF8Characters;
|
||||
if (!uuid_is_valid (uuid_str))
|
||||
return FALSE;
|
||||
|
||||
g_dbus_proxy_call (obj->proxy,
|
||||
(enabled ? "EnableExtension" : "DisableExtension"),
|
||||
g_variant_new ("(s)", uuid_str),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1, /* timeout */
|
||||
NULL, /* cancellable */
|
||||
NULL, /* callback */
|
||||
NULL /* user_data */);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plugin_install_extension (PluginObject *obj,
|
||||
NPString uuid,
|
||||
NPString version_tag)
|
||||
{
|
||||
const gchar *uuid_str = uuid.UTF8Characters;
|
||||
if (!uuid_is_valid (uuid_str))
|
||||
return FALSE;
|
||||
|
||||
g_dbus_proxy_call (obj->proxy,
|
||||
"InstallRemoteExtension",
|
||||
g_variant_new ("(ss)",
|
||||
uuid_str,
|
||||
version_tag.UTF8Characters),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1, /* timeout */
|
||||
NULL, /* cancellable */
|
||||
NULL, /* callback */
|
||||
NULL /* user_data */);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plugin_uninstall_extension (PluginObject *obj,
|
||||
NPString uuid,
|
||||
NPVariant *result)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GVariant *res;
|
||||
const gchar *uuid_str;
|
||||
|
||||
uuid_str = uuid.UTF8Characters;
|
||||
if (!uuid_is_valid (uuid_str))
|
||||
return FALSE;
|
||||
|
||||
res = g_dbus_proxy_call_sync (obj->proxy,
|
||||
"UninstallExtension",
|
||||
g_variant_new ("(s)",
|
||||
uuid_str),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1, /* timeout */
|
||||
NULL, /* cancellable */
|
||||
&error);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
g_warning ("Failed to uninstall extension: %s", error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return jsonify_variant (res, result);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plugin_get_info (PluginObject *obj,
|
||||
NPString uuid,
|
||||
NPVariant *result)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GVariant *res;
|
||||
const gchar *uuid_str;
|
||||
|
||||
uuid_str = uuid.UTF8Characters;
|
||||
if (!uuid_is_valid (uuid_str))
|
||||
return FALSE;
|
||||
|
||||
res = g_dbus_proxy_call_sync (obj->proxy,
|
||||
"GetExtensionInfo",
|
||||
g_variant_new ("(s)", uuid_str),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1, /* timeout */
|
||||
NULL, /* cancellable */
|
||||
&error);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
g_warning ("Failed to retrieve extension metadata: %s", error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return jsonify_variant (res, result);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plugin_get_errors (PluginObject *obj,
|
||||
NPString uuid,
|
||||
NPVariant *result)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GVariant *res;
|
||||
const gchar *uuid_str;
|
||||
|
||||
uuid_str = uuid.UTF8Characters;
|
||||
if (!uuid_is_valid (uuid_str))
|
||||
return FALSE;
|
||||
|
||||
res = g_dbus_proxy_call_sync (obj->proxy,
|
||||
"GetExtensionErrors",
|
||||
g_variant_new ("(s)", uuid_str),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1, /* timeout */
|
||||
NULL, /* cancellable */
|
||||
&error);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
g_warning ("Failed to retrieve errors: %s", error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return jsonify_variant (res, result);
|
||||
}
|
||||
|
||||
static int
|
||||
plugin_get_api_version (PluginObject *obj,
|
||||
NPVariant *result)
|
||||
{
|
||||
INT32_TO_NPVARIANT (PLUGIN_API_VERSION, *result);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plugin_get_shell_version (PluginObject *obj,
|
||||
NPVariant *result)
|
||||
{
|
||||
GVariant *res;
|
||||
const gchar *version;
|
||||
gsize length;
|
||||
gchar *buffer;
|
||||
gboolean ret;
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
res = g_dbus_proxy_get_cached_property (obj->proxy,
|
||||
"ShellVersion");
|
||||
|
||||
if (res == NULL)
|
||||
{
|
||||
g_warning ("Failed to grab shell version.");
|
||||
version = "-1";
|
||||
}
|
||||
else
|
||||
{
|
||||
g_variant_get (res, "&s", &version);
|
||||
}
|
||||
|
||||
length = strlen (version);
|
||||
buffer = funcs.memalloc (length + 1);
|
||||
if (!buffer)
|
||||
{
|
||||
ret = FALSE;
|
||||
goto out;
|
||||
}
|
||||
strcpy (buffer, version);
|
||||
|
||||
STRINGN_TO_NPVARIANT (buffer, length, *result);
|
||||
|
||||
out:
|
||||
g_variant_unref (res);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
plugin_object_invoke (NPObject *npobj,
|
||||
NPIdentifier name,
|
||||
const NPVariant *args,
|
||||
uint32_t argc,
|
||||
NPVariant *result)
|
||||
{
|
||||
PluginObject *obj;
|
||||
|
||||
g_debug ("invoking plugin object method");
|
||||
|
||||
obj = (PluginObject*) npobj;
|
||||
|
||||
VOID_TO_NPVARIANT (*result);
|
||||
|
||||
if (!plugin_object_has_method (npobj, name))
|
||||
return FALSE;
|
||||
|
||||
if (name == list_extensions_id)
|
||||
return plugin_list_extensions (obj, result);
|
||||
else if (name == get_info_id)
|
||||
{
|
||||
if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
|
||||
|
||||
return plugin_get_info (obj, NPVARIANT_TO_STRING(args[0]), result);
|
||||
}
|
||||
else if (name == enable_extension_id)
|
||||
{
|
||||
if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
|
||||
if (!NPVARIANT_IS_BOOLEAN(args[1])) return FALSE;
|
||||
|
||||
return plugin_enable_extension (obj,
|
||||
NPVARIANT_TO_STRING(args[0]),
|
||||
NPVARIANT_TO_BOOLEAN(args[1]));
|
||||
}
|
||||
else if (name == install_extension_id)
|
||||
{
|
||||
if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
|
||||
if (!NPVARIANT_IS_STRING(args[1])) return FALSE;
|
||||
|
||||
return plugin_install_extension (obj,
|
||||
NPVARIANT_TO_STRING(args[0]),
|
||||
NPVARIANT_TO_STRING(args[1]));
|
||||
}
|
||||
else if (name == uninstall_extension_id)
|
||||
{
|
||||
if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
|
||||
|
||||
return plugin_uninstall_extension (obj,
|
||||
NPVARIANT_TO_STRING(args[0]),
|
||||
result);
|
||||
}
|
||||
else if (name == get_errors_id)
|
||||
{
|
||||
if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
|
||||
|
||||
return plugin_get_errors (obj,
|
||||
NPVARIANT_TO_STRING(args[0]),
|
||||
result);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool
|
||||
plugin_object_has_property (NPObject *npobj,
|
||||
NPIdentifier name)
|
||||
{
|
||||
return (name == onextension_changed_id ||
|
||||
name == api_version_id ||
|
||||
name == shell_version_id);
|
||||
}
|
||||
|
||||
static bool
|
||||
plugin_object_get_property (NPObject *npobj,
|
||||
NPIdentifier name,
|
||||
NPVariant *result)
|
||||
{
|
||||
PluginObject *obj;
|
||||
|
||||
if (!plugin_object_has_property (npobj, name))
|
||||
return FALSE;
|
||||
|
||||
obj = (PluginObject*) npobj;
|
||||
if (name == api_version_id)
|
||||
return plugin_get_api_version (obj, result);
|
||||
else if (name == shell_version_id)
|
||||
return plugin_get_shell_version (obj, result);
|
||||
else if (name == onextension_changed_id)
|
||||
{
|
||||
if (obj->listener)
|
||||
OBJECT_TO_NPVARIANT (obj->listener, *result);
|
||||
else
|
||||
NULL_TO_NPVARIANT (*result);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool
|
||||
plugin_object_set_property (NPObject *npobj,
|
||||
NPIdentifier name,
|
||||
const NPVariant *value)
|
||||
{
|
||||
PluginObject *obj;
|
||||
|
||||
if (!plugin_object_has_property (npobj, name))
|
||||
return FALSE;
|
||||
|
||||
if (name == onextension_changed_id)
|
||||
{
|
||||
obj = (PluginObject*) npobj;
|
||||
if (obj->listener)
|
||||
funcs.releaseobject (obj->listener);
|
||||
|
||||
obj->listener = NULL;
|
||||
if (NPVARIANT_IS_OBJECT (*value))
|
||||
{
|
||||
obj->listener = NPVARIANT_TO_OBJECT (*value);
|
||||
funcs.retainobject (obj->listener);
|
||||
return TRUE;
|
||||
}
|
||||
else if (NPVARIANT_IS_NULL (*value))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static NPClass plugin_class = {
|
||||
NP_CLASS_STRUCT_VERSION,
|
||||
plugin_object_allocate,
|
||||
plugin_object_deallocate,
|
||||
NULL, /* invalidate */
|
||||
plugin_object_has_method,
|
||||
plugin_object_invoke,
|
||||
NULL, /* invoke default */
|
||||
plugin_object_has_property,
|
||||
plugin_object_get_property,
|
||||
plugin_object_set_property,
|
||||
NULL, /* remove property */
|
||||
NULL, /* enumerate */
|
||||
NULL, /* construct */
|
||||
};
|
||||
|
||||
static void
|
||||
init_methods_and_properties (void)
|
||||
{
|
||||
/* this is the JS public API; it is manipulated through NPIdentifiers for speed */
|
||||
api_version_id = funcs.getstringidentifier ("apiVersion");
|
||||
shell_version_id = funcs.getstringidentifier ("shellVersion");
|
||||
|
||||
get_info_id = funcs.getstringidentifier ("getExtensionInfo");
|
||||
list_extensions_id = funcs.getstringidentifier ("listExtensions");
|
||||
enable_extension_id = funcs.getstringidentifier ("setExtensionEnabled");
|
||||
install_extension_id = funcs.getstringidentifier ("installExtension");
|
||||
uninstall_extension_id = funcs.getstringidentifier ("uninstallExtension");
|
||||
get_errors_id = funcs.getstringidentifier ("getExtensionErrors");
|
||||
|
||||
onextension_changed_id = funcs.getstringidentifier ("onchange");
|
||||
}
|
||||
|
||||
NPError
|
||||
NPP_GetValue(NPP instance,
|
||||
NPPVariable variable,
|
||||
void *value)
|
||||
{
|
||||
g_debug ("NPP_GetValue called");
|
||||
|
||||
switch (variable) {
|
||||
case NPPVpluginScriptableNPObject:
|
||||
g_debug ("creating scriptable object");
|
||||
init_methods_and_properties ();
|
||||
|
||||
*(NPObject**)value = funcs.createobject (instance, &plugin_class);
|
||||
break;
|
||||
|
||||
case NPPVpluginNeedsXEmbed:
|
||||
*(bool *)value = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
893
browser-plugin/npapi/npapi.h
Normal file
893
browser-plugin/npapi/npapi.h
Normal file
@ -0,0 +1,893 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef npapi_h_
|
||||
#define npapi_h_
|
||||
|
||||
#if defined(__OS2__)
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
#include "nptypes.h"
|
||||
|
||||
#if defined(__OS2__) || defined(OS2)
|
||||
#ifndef XP_OS2
|
||||
#define XP_OS2 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(__SYMBIAN32__)
|
||||
#include <windef.h>
|
||||
#ifndef XP_WIN
|
||||
#define XP_WIN 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__SYMBIAN32__)
|
||||
#ifndef XP_SYMBIAN
|
||||
#define XP_SYMBIAN 1
|
||||
#undef XP_WIN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE_CC__) && !defined(XP_UNIX)
|
||||
#ifndef XP_MACOSX
|
||||
#define XP_MACOSX 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX) && defined(__LP64__)
|
||||
#define NP_NO_QUICKDRAW
|
||||
#define NP_NO_CARBON
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#ifndef NP_NO_CARBON
|
||||
#include <Carbon/Carbon.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(XP_UNIX)
|
||||
#include <stdio.h>
|
||||
#if defined(MOZ_X11)
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(XP_SYMBIAN)
|
||||
#include <QEvent>
|
||||
#include <QRegion>
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Plugin Version Constants */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
#define NP_VERSION_MAJOR 0
|
||||
#define NP_VERSION_MINOR 27
|
||||
|
||||
|
||||
/* The OS/2 version of Netscape uses RC_DATA to define the
|
||||
mime types, file extensions, etc that are required.
|
||||
Use a vertical bar to separate types, end types with \0.
|
||||
FileVersion and ProductVersion are 32bit ints, all other
|
||||
entries are strings that MUST be terminated with a \0.
|
||||
|
||||
AN EXAMPLE:
|
||||
|
||||
RCDATA NP_INFO_ProductVersion { 1,0,0,1,}
|
||||
|
||||
RCDATA NP_INFO_MIMEType { "video/x-video|",
|
||||
"video/x-flick\0" }
|
||||
RCDATA NP_INFO_FileExtents { "avi|",
|
||||
"flc\0" }
|
||||
RCDATA NP_INFO_FileOpenName{ "MMOS2 video player(*.avi)|",
|
||||
"MMOS2 Flc/Fli player(*.flc)\0" }
|
||||
|
||||
RCDATA NP_INFO_FileVersion { 1,0,0,1 }
|
||||
RCDATA NP_INFO_CompanyName { "Netscape Communications\0" }
|
||||
RCDATA NP_INFO_FileDescription { "NPAVI32 Extension DLL\0"
|
||||
RCDATA NP_INFO_InternalName { "NPAVI32\0" )
|
||||
RCDATA NP_INFO_LegalCopyright { "Copyright Netscape Communications \251 1996\0"
|
||||
RCDATA NP_INFO_OriginalFilename { "NVAPI32.DLL" }
|
||||
RCDATA NP_INFO_ProductName { "NPAVI32 Dynamic Link Library\0" }
|
||||
*/
|
||||
/* RC_DATA types for version info - required */
|
||||
#define NP_INFO_ProductVersion 1
|
||||
#define NP_INFO_MIMEType 2
|
||||
#define NP_INFO_FileOpenName 3
|
||||
#define NP_INFO_FileExtents 4
|
||||
/* RC_DATA types for version info - used if found */
|
||||
#define NP_INFO_FileDescription 5
|
||||
#define NP_INFO_ProductName 6
|
||||
/* RC_DATA types for version info - optional */
|
||||
#define NP_INFO_CompanyName 7
|
||||
#define NP_INFO_FileVersion 8
|
||||
#define NP_INFO_InternalName 9
|
||||
#define NP_INFO_LegalCopyright 10
|
||||
#define NP_INFO_OriginalFilename 11
|
||||
|
||||
#ifndef RC_INVOKED
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Definition of Basic Types */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
typedef unsigned char NPBool;
|
||||
typedef int16_t NPError;
|
||||
typedef int16_t NPReason;
|
||||
typedef char* NPMIMEType;
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Structures and definitions */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
#if !defined(__LP64__)
|
||||
#if defined(XP_MACOSX)
|
||||
#pragma options align=mac68k
|
||||
#endif
|
||||
#endif /* __LP64__ */
|
||||
|
||||
/*
|
||||
* NPP is a plug-in's opaque instance handle
|
||||
*/
|
||||
typedef struct _NPP
|
||||
{
|
||||
void* pdata; /* plug-in private data */
|
||||
void* ndata; /* netscape private data */
|
||||
} NPP_t;
|
||||
|
||||
typedef NPP_t* NPP;
|
||||
|
||||
typedef struct _NPStream
|
||||
{
|
||||
void* pdata; /* plug-in private data */
|
||||
void* ndata; /* netscape private data */
|
||||
const char* url;
|
||||
uint32_t end;
|
||||
uint32_t lastmodified;
|
||||
void* notifyData;
|
||||
const char* headers; /* Response headers from host.
|
||||
* Exists only for >= NPVERS_HAS_RESPONSE_HEADERS.
|
||||
* Used for HTTP only; NULL for non-HTTP.
|
||||
* Available from NPP_NewStream onwards.
|
||||
* Plugin should copy this data before storing it.
|
||||
* Includes HTTP status line and all headers,
|
||||
* preferably verbatim as received from server,
|
||||
* headers formatted as in HTTP ("Header: Value"),
|
||||
* and newlines (\n, NOT \r\n) separating lines.
|
||||
* Terminated by \n\0 (NOT \n\n\0). */
|
||||
} NPStream;
|
||||
|
||||
typedef struct _NPByteRange
|
||||
{
|
||||
int32_t offset; /* negative offset means from the end */
|
||||
uint32_t length;
|
||||
struct _NPByteRange* next;
|
||||
} NPByteRange;
|
||||
|
||||
typedef struct _NPSavedData
|
||||
{
|
||||
int32_t len;
|
||||
void* buf;
|
||||
} NPSavedData;
|
||||
|
||||
typedef struct _NPRect
|
||||
{
|
||||
uint16_t top;
|
||||
uint16_t left;
|
||||
uint16_t bottom;
|
||||
uint16_t right;
|
||||
} NPRect;
|
||||
|
||||
typedef struct _NPSize
|
||||
{
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
} NPSize;
|
||||
|
||||
typedef enum {
|
||||
NPFocusNext = 0,
|
||||
NPFocusPrevious = 1
|
||||
} NPFocusDirection;
|
||||
|
||||
/* Return values for NPP_HandleEvent */
|
||||
#define kNPEventNotHandled 0
|
||||
#define kNPEventHandled 1
|
||||
/* Exact meaning must be spec'd in event model. */
|
||||
#define kNPEventStartIME 2
|
||||
|
||||
#if defined(XP_UNIX)
|
||||
/*
|
||||
* Unix specific structures and definitions
|
||||
*/
|
||||
|
||||
/*
|
||||
* Callback Structures.
|
||||
*
|
||||
* These are used to pass additional platform specific information.
|
||||
*/
|
||||
enum {
|
||||
NP_SETWINDOW = 1,
|
||||
NP_PRINT
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t type;
|
||||
} NPAnyCallbackStruct;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t type;
|
||||
#if defined(MOZ_X11)
|
||||
Display* display;
|
||||
Visual* visual;
|
||||
Colormap colormap;
|
||||
unsigned int depth;
|
||||
#endif
|
||||
} NPSetWindowCallbackStruct;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t type;
|
||||
FILE* fp;
|
||||
} NPPrintCallbackStruct;
|
||||
|
||||
#endif /* XP_UNIX */
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
typedef enum {
|
||||
#ifndef NP_NO_QUICKDRAW
|
||||
NPDrawingModelQuickDraw = 0,
|
||||
#endif
|
||||
NPDrawingModelCoreGraphics = 1,
|
||||
NPDrawingModelOpenGL = 2,
|
||||
NPDrawingModelCoreAnimation = 3,
|
||||
NPDrawingModelInvalidatingCoreAnimation = 4
|
||||
} NPDrawingModel;
|
||||
|
||||
typedef enum {
|
||||
#ifndef NP_NO_CARBON
|
||||
NPEventModelCarbon = 0,
|
||||
#endif
|
||||
NPEventModelCocoa = 1
|
||||
} NPEventModel;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following masks are applied on certain platforms to NPNV and
|
||||
* NPPV selectors that pass around pointers to COM interfaces. Newer
|
||||
* compilers on some platforms may generate vtables that are not
|
||||
* compatible with older compilers. To prevent older plugins from
|
||||
* not understanding a new browser's ABI, these masks change the
|
||||
* values of those selectors on those platforms. To remain backwards
|
||||
* compatible with different versions of the browser, plugins can
|
||||
* use these masks to dynamically determine and use the correct C++
|
||||
* ABI that the browser is expecting. This does not apply to Windows
|
||||
* as Microsoft's COM ABI will likely not change.
|
||||
*/
|
||||
|
||||
#define NP_ABI_GCC3_MASK 0x10000000
|
||||
/*
|
||||
* gcc 3.x generated vtables on UNIX and OSX are incompatible with
|
||||
* previous compilers.
|
||||
*/
|
||||
#if (defined(XP_UNIX) && defined(__GNUC__) && (__GNUC__ >= 3))
|
||||
#define _NP_ABI_MIXIN_FOR_GCC3 NP_ABI_GCC3_MASK
|
||||
#else
|
||||
#define _NP_ABI_MIXIN_FOR_GCC3 0
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#define NP_ABI_MACHO_MASK 0x01000000
|
||||
#define _NP_ABI_MIXIN_FOR_MACHO NP_ABI_MACHO_MASK
|
||||
#else
|
||||
#define _NP_ABI_MIXIN_FOR_MACHO 0
|
||||
#endif
|
||||
|
||||
#define NP_ABI_MASK (_NP_ABI_MIXIN_FOR_GCC3 | _NP_ABI_MIXIN_FOR_MACHO)
|
||||
|
||||
/*
|
||||
* List of variable names for which NPP_GetValue shall be implemented
|
||||
*/
|
||||
typedef enum {
|
||||
NPPVpluginNameString = 1,
|
||||
NPPVpluginDescriptionString,
|
||||
NPPVpluginWindowBool,
|
||||
NPPVpluginTransparentBool,
|
||||
NPPVjavaClass,
|
||||
NPPVpluginWindowSize,
|
||||
NPPVpluginTimerInterval,
|
||||
NPPVpluginScriptableInstance = (10 | NP_ABI_MASK),
|
||||
NPPVpluginScriptableIID = 11,
|
||||
NPPVjavascriptPushCallerBool = 12,
|
||||
NPPVpluginKeepLibraryInMemory = 13,
|
||||
NPPVpluginNeedsXEmbed = 14,
|
||||
|
||||
/* Get the NPObject for scripting the plugin. Introduced in NPAPI minor version 14.
|
||||
*/
|
||||
NPPVpluginScriptableNPObject = 15,
|
||||
|
||||
/* Get the plugin value (as \0-terminated UTF-8 string data) for
|
||||
* form submission if the plugin is part of a form. Use
|
||||
* NPN_MemAlloc() to allocate memory for the string data. Introduced
|
||||
* in NPAPI minor version 15.
|
||||
*/
|
||||
NPPVformValue = 16,
|
||||
|
||||
NPPVpluginUrlRequestsDisplayedBool = 17,
|
||||
|
||||
/* Checks if the plugin is interested in receiving the http body of
|
||||
* all http requests (including failed ones, http status != 200).
|
||||
*/
|
||||
NPPVpluginWantsAllNetworkStreams = 18,
|
||||
|
||||
/* Browsers can retrieve a native ATK accessibility plug ID via this variable. */
|
||||
NPPVpluginNativeAccessibleAtkPlugId = 19,
|
||||
|
||||
/* Checks to see if the plug-in would like the browser to load the "src" attribute. */
|
||||
NPPVpluginCancelSrcStream = 20,
|
||||
|
||||
NPPVsupportsAdvancedKeyHandling = 21,
|
||||
|
||||
NPPVpluginUsesDOMForCursorBool = 22
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
/* Used for negotiating drawing models */
|
||||
, NPPVpluginDrawingModel = 1000
|
||||
/* Used for negotiating event models */
|
||||
, NPPVpluginEventModel = 1001
|
||||
/* In the NPDrawingModelCoreAnimation drawing model, the browser asks the plug-in for a Core Animation layer. */
|
||||
, NPPVpluginCoreAnimationLayer = 1003
|
||||
#endif
|
||||
|
||||
#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
|
||||
, NPPVpluginWindowlessLocalBool = 2002
|
||||
#endif
|
||||
} NPPVariable;
|
||||
|
||||
/*
|
||||
* List of variable names for which NPN_GetValue should be implemented.
|
||||
*/
|
||||
typedef enum {
|
||||
NPNVxDisplay = 1,
|
||||
NPNVxtAppContext,
|
||||
NPNVnetscapeWindow,
|
||||
NPNVjavascriptEnabledBool,
|
||||
NPNVasdEnabledBool,
|
||||
NPNVisOfflineBool,
|
||||
|
||||
NPNVserviceManager = (10 | NP_ABI_MASK),
|
||||
NPNVDOMElement = (11 | NP_ABI_MASK),
|
||||
NPNVDOMWindow = (12 | NP_ABI_MASK),
|
||||
NPNVToolkit = (13 | NP_ABI_MASK),
|
||||
NPNVSupportsXEmbedBool = 14,
|
||||
|
||||
/* Get the NPObject wrapper for the browser window. */
|
||||
NPNVWindowNPObject = 15,
|
||||
|
||||
/* Get the NPObject wrapper for the plugins DOM element. */
|
||||
NPNVPluginElementNPObject = 16,
|
||||
|
||||
NPNVSupportsWindowless = 17,
|
||||
|
||||
NPNVprivateModeBool = 18,
|
||||
|
||||
NPNVsupportsAdvancedKeyHandling = 21
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
/* Used for negotiating drawing models */
|
||||
, NPNVpluginDrawingModel = 1000
|
||||
#ifndef NP_NO_QUICKDRAW
|
||||
, NPNVsupportsQuickDrawBool = 2000
|
||||
#endif
|
||||
, NPNVsupportsCoreGraphicsBool = 2001
|
||||
, NPNVsupportsOpenGLBool = 2002
|
||||
, NPNVsupportsCoreAnimationBool = 2003
|
||||
, NPNVsupportsInvalidatingCoreAnimationBool = 2004
|
||||
#ifndef NP_NO_CARBON
|
||||
, NPNVsupportsCarbonBool = 3000 /* TRUE if the browser supports the Carbon event model */
|
||||
#endif
|
||||
, NPNVsupportsCocoaBool = 3001 /* TRUE if the browser supports the Cocoa event model */
|
||||
, NPNVsupportsUpdatedCocoaTextInputBool = 3002 /* TRUE if the browser supports the updated
|
||||
Cocoa text input specification. */
|
||||
, NPNVsupportsCompositingCoreAnimationPluginsBool = 74656 /* TRUE if the browser supports
|
||||
CA model compositing */
|
||||
#endif
|
||||
#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
|
||||
, NPNVSupportsWindowlessLocal = 2002
|
||||
#endif
|
||||
} NPNVariable;
|
||||
|
||||
typedef enum {
|
||||
NPNURLVCookie = 501,
|
||||
NPNURLVProxy
|
||||
} NPNURLVariable;
|
||||
|
||||
/*
|
||||
* The type of Toolkit the widgets use
|
||||
*/
|
||||
typedef enum {
|
||||
NPNVGtk12 = 1,
|
||||
NPNVGtk2
|
||||
} NPNToolkitType;
|
||||
|
||||
/*
|
||||
* The type of a NPWindow - it specifies the type of the data structure
|
||||
* returned in the window field.
|
||||
*/
|
||||
typedef enum {
|
||||
NPWindowTypeWindow = 1,
|
||||
NPWindowTypeDrawable
|
||||
} NPWindowType;
|
||||
|
||||
typedef struct _NPWindow
|
||||
{
|
||||
void* window; /* Platform specific window handle */
|
||||
/* OS/2: x - Position of bottom left corner */
|
||||
/* OS/2: y - relative to visible netscape window */
|
||||
int32_t x; /* Position of top left corner relative */
|
||||
int32_t y; /* to a netscape page. */
|
||||
uint32_t width; /* Maximum window size */
|
||||
uint32_t height;
|
||||
NPRect clipRect; /* Clipping rectangle in port coordinates */
|
||||
#if (defined(XP_UNIX) || defined(XP_SYMBIAN)) && !defined(XP_MACOSX)
|
||||
void * ws_info; /* Platform-dependent additional data */
|
||||
#endif /* XP_UNIX */
|
||||
NPWindowType type; /* Is this a window or a drawable? */
|
||||
} NPWindow;
|
||||
|
||||
typedef struct _NPImageExpose
|
||||
{
|
||||
char* data; /* image pointer */
|
||||
int32_t stride; /* Stride of data image pointer */
|
||||
int32_t depth; /* Depth of image pointer */
|
||||
int32_t x; /* Expose x */
|
||||
int32_t y; /* Expose y */
|
||||
uint32_t width; /* Expose width */
|
||||
uint32_t height; /* Expose height */
|
||||
NPSize dataSize; /* Data buffer size */
|
||||
float translateX; /* translate X matrix value */
|
||||
float translateY; /* translate Y matrix value */
|
||||
float scaleX; /* scale X matrix value */
|
||||
float scaleY; /* scale Y matrix value */
|
||||
} NPImageExpose;
|
||||
|
||||
typedef struct _NPFullPrint
|
||||
{
|
||||
NPBool pluginPrinted;/* Set TRUE if plugin handled fullscreen printing */
|
||||
NPBool printOne; /* TRUE if plugin should print one copy to default
|
||||
printer */
|
||||
void* platformPrint; /* Platform-specific printing info */
|
||||
} NPFullPrint;
|
||||
|
||||
typedef struct _NPEmbedPrint
|
||||
{
|
||||
NPWindow window;
|
||||
void* platformPrint; /* Platform-specific printing info */
|
||||
} NPEmbedPrint;
|
||||
|
||||
typedef struct _NPPrint
|
||||
{
|
||||
uint16_t mode; /* NP_FULL or NP_EMBED */
|
||||
union
|
||||
{
|
||||
NPFullPrint fullPrint; /* if mode is NP_FULL */
|
||||
NPEmbedPrint embedPrint; /* if mode is NP_EMBED */
|
||||
} print;
|
||||
} NPPrint;
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#ifndef NP_NO_CARBON
|
||||
typedef EventRecord NPEvent;
|
||||
#endif
|
||||
#elif defined(XP_SYMBIAN)
|
||||
typedef QEvent NPEvent;
|
||||
#elif defined(XP_WIN)
|
||||
typedef struct _NPEvent
|
||||
{
|
||||
uint16_t event;
|
||||
uintptr_t wParam;
|
||||
uintptr_t lParam;
|
||||
} NPEvent;
|
||||
#elif defined(XP_OS2)
|
||||
typedef struct _NPEvent
|
||||
{
|
||||
uint32_t event;
|
||||
uint32_t wParam;
|
||||
uint32_t lParam;
|
||||
} NPEvent;
|
||||
#elif defined(XP_UNIX) && defined(MOZ_X11)
|
||||
typedef XEvent NPEvent;
|
||||
#else
|
||||
typedef void* NPEvent;
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
typedef void* NPRegion;
|
||||
#ifndef NP_NO_QUICKDRAW
|
||||
typedef RgnHandle NPQDRegion;
|
||||
#endif
|
||||
typedef CGPathRef NPCGRegion;
|
||||
#elif defined(XP_WIN)
|
||||
typedef HRGN NPRegion;
|
||||
#elif defined(XP_UNIX) && defined(MOZ_X11)
|
||||
typedef Region NPRegion;
|
||||
#elif defined(XP_SYMBIAN)
|
||||
typedef QRegion* NPRegion;
|
||||
#else
|
||||
typedef void *NPRegion;
|
||||
#endif
|
||||
|
||||
typedef struct _NPNSString NPNSString;
|
||||
typedef struct _NPNSWindow NPNSWindow;
|
||||
typedef struct _NPNSMenu NPNSMenu;
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
typedef NPNSMenu NPMenu;
|
||||
#else
|
||||
typedef void *NPMenu;
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
NPCoordinateSpacePlugin = 1,
|
||||
NPCoordinateSpaceWindow,
|
||||
NPCoordinateSpaceFlippedWindow,
|
||||
NPCoordinateSpaceScreen,
|
||||
NPCoordinateSpaceFlippedScreen
|
||||
} NPCoordinateSpace;
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
|
||||
#ifndef NP_NO_QUICKDRAW
|
||||
typedef struct NP_Port
|
||||
{
|
||||
CGrafPtr port;
|
||||
int32_t portx; /* position inside the topmost window */
|
||||
int32_t porty;
|
||||
} NP_Port;
|
||||
#endif /* NP_NO_QUICKDRAW */
|
||||
|
||||
/*
|
||||
* NP_CGContext is the type of the NPWindow's 'window' when the plugin specifies NPDrawingModelCoreGraphics
|
||||
* as its drawing model.
|
||||
*/
|
||||
|
||||
typedef struct NP_CGContext
|
||||
{
|
||||
CGContextRef context;
|
||||
void *window; /* A WindowRef under the Carbon event model. */
|
||||
} NP_CGContext;
|
||||
|
||||
/*
|
||||
* NP_GLContext is the type of the NPWindow's 'window' when the plugin specifies NPDrawingModelOpenGL as its
|
||||
* drawing model.
|
||||
*/
|
||||
|
||||
typedef struct NP_GLContext
|
||||
{
|
||||
CGLContextObj context;
|
||||
#ifdef NP_NO_CARBON
|
||||
NPNSWindow *window;
|
||||
#else
|
||||
void *window; /* Can be either an NSWindow or a WindowRef depending on the event model */
|
||||
#endif
|
||||
} NP_GLContext;
|
||||
|
||||
typedef enum {
|
||||
NPCocoaEventDrawRect = 1,
|
||||
NPCocoaEventMouseDown,
|
||||
NPCocoaEventMouseUp,
|
||||
NPCocoaEventMouseMoved,
|
||||
NPCocoaEventMouseEntered,
|
||||
NPCocoaEventMouseExited,
|
||||
NPCocoaEventMouseDragged,
|
||||
NPCocoaEventKeyDown,
|
||||
NPCocoaEventKeyUp,
|
||||
NPCocoaEventFlagsChanged,
|
||||
NPCocoaEventFocusChanged,
|
||||
NPCocoaEventWindowFocusChanged,
|
||||
NPCocoaEventScrollWheel,
|
||||
NPCocoaEventTextInput
|
||||
} NPCocoaEventType;
|
||||
|
||||
typedef struct _NPCocoaEvent {
|
||||
NPCocoaEventType type;
|
||||
uint32_t version;
|
||||
union {
|
||||
struct {
|
||||
uint32_t modifierFlags;
|
||||
double pluginX;
|
||||
double pluginY;
|
||||
int32_t buttonNumber;
|
||||
int32_t clickCount;
|
||||
double deltaX;
|
||||
double deltaY;
|
||||
double deltaZ;
|
||||
} mouse;
|
||||
struct {
|
||||
uint32_t modifierFlags;
|
||||
NPNSString *characters;
|
||||
NPNSString *charactersIgnoringModifiers;
|
||||
NPBool isARepeat;
|
||||
uint16_t keyCode;
|
||||
} key;
|
||||
struct {
|
||||
CGContextRef context;
|
||||
double x;
|
||||
double y;
|
||||
double width;
|
||||
double height;
|
||||
} draw;
|
||||
struct {
|
||||
NPBool hasFocus;
|
||||
} focus;
|
||||
struct {
|
||||
NPNSString *text;
|
||||
} text;
|
||||
} data;
|
||||
} NPCocoaEvent;
|
||||
|
||||
#ifndef NP_NO_CARBON
|
||||
/* Non-standard event types that can be passed to HandleEvent */
|
||||
enum NPEventType {
|
||||
NPEventType_GetFocusEvent = (osEvt + 16),
|
||||
NPEventType_LoseFocusEvent,
|
||||
NPEventType_AdjustCursorEvent,
|
||||
NPEventType_MenuCommandEvent,
|
||||
NPEventType_ClippingChangedEvent,
|
||||
NPEventType_ScrollingBeginsEvent = 1000,
|
||||
NPEventType_ScrollingEndsEvent
|
||||
};
|
||||
#endif /* NP_NO_CARBON */
|
||||
|
||||
#endif /* XP_MACOSX */
|
||||
|
||||
/*
|
||||
* Values for mode passed to NPP_New:
|
||||
*/
|
||||
#define NP_EMBED 1
|
||||
#define NP_FULL 2
|
||||
|
||||
/*
|
||||
* Values for stream type passed to NPP_NewStream:
|
||||
*/
|
||||
#define NP_NORMAL 1
|
||||
#define NP_SEEK 2
|
||||
#define NP_ASFILE 3
|
||||
#define NP_ASFILEONLY 4
|
||||
|
||||
#define NP_MAXREADY (((unsigned)(~0)<<1)>>1)
|
||||
|
||||
/*
|
||||
* Flags for NPP_ClearSiteData.
|
||||
*/
|
||||
#define NP_CLEAR_ALL 0
|
||||
#define NP_CLEAR_CACHE (1 << 0)
|
||||
|
||||
#if !defined(__LP64__)
|
||||
#if defined(XP_MACOSX)
|
||||
#pragma options align=reset
|
||||
#endif
|
||||
#endif /* __LP64__ */
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Error and Reason Code definitions */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Values of type NPError:
|
||||
*/
|
||||
#define NPERR_BASE 0
|
||||
#define NPERR_NO_ERROR (NPERR_BASE + 0)
|
||||
#define NPERR_GENERIC_ERROR (NPERR_BASE + 1)
|
||||
#define NPERR_INVALID_INSTANCE_ERROR (NPERR_BASE + 2)
|
||||
#define NPERR_INVALID_FUNCTABLE_ERROR (NPERR_BASE + 3)
|
||||
#define NPERR_MODULE_LOAD_FAILED_ERROR (NPERR_BASE + 4)
|
||||
#define NPERR_OUT_OF_MEMORY_ERROR (NPERR_BASE + 5)
|
||||
#define NPERR_INVALID_PLUGIN_ERROR (NPERR_BASE + 6)
|
||||
#define NPERR_INVALID_PLUGIN_DIR_ERROR (NPERR_BASE + 7)
|
||||
#define NPERR_INCOMPATIBLE_VERSION_ERROR (NPERR_BASE + 8)
|
||||
#define NPERR_INVALID_PARAM (NPERR_BASE + 9)
|
||||
#define NPERR_INVALID_URL (NPERR_BASE + 10)
|
||||
#define NPERR_FILE_NOT_FOUND (NPERR_BASE + 11)
|
||||
#define NPERR_NO_DATA (NPERR_BASE + 12)
|
||||
#define NPERR_STREAM_NOT_SEEKABLE (NPERR_BASE + 13)
|
||||
#define NPERR_TIME_RANGE_NOT_SUPPORTED (NPERR_BASE + 14)
|
||||
#define NPERR_MALFORMED_SITE (NPERR_BASE + 15)
|
||||
|
||||
/*
|
||||
* Values of type NPReason:
|
||||
*/
|
||||
#define NPRES_BASE 0
|
||||
#define NPRES_DONE (NPRES_BASE + 0)
|
||||
#define NPRES_NETWORK_ERR (NPRES_BASE + 1)
|
||||
#define NPRES_USER_BREAK (NPRES_BASE + 2)
|
||||
|
||||
/*
|
||||
* Don't use these obsolete error codes any more.
|
||||
*/
|
||||
#define NP_NOERR NP_NOERR_is_obsolete_use_NPERR_NO_ERROR
|
||||
#define NP_EINVAL NP_EINVAL_is_obsolete_use_NPERR_GENERIC_ERROR
|
||||
#define NP_EABORT NP_EABORT_is_obsolete_use_NPRES_USER_BREAK
|
||||
|
||||
/*
|
||||
* Version feature information
|
||||
*/
|
||||
#define NPVERS_HAS_STREAMOUTPUT 8
|
||||
#define NPVERS_HAS_NOTIFICATION 9
|
||||
#define NPVERS_HAS_LIVECONNECT 9
|
||||
#define NPVERS_68K_HAS_LIVECONNECT 11
|
||||
#define NPVERS_HAS_WINDOWLESS 11
|
||||
#define NPVERS_HAS_XPCONNECT_SCRIPTING 13
|
||||
#define NPVERS_HAS_NPRUNTIME_SCRIPTING 14
|
||||
#define NPVERS_HAS_FORM_VALUES 15
|
||||
#define NPVERS_HAS_POPUPS_ENABLED_STATE 16
|
||||
#define NPVERS_HAS_RESPONSE_HEADERS 17
|
||||
#define NPVERS_HAS_NPOBJECT_ENUM 18
|
||||
#define NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL 19
|
||||
#define NPVERS_HAS_ALL_NETWORK_STREAMS 20
|
||||
#define NPVERS_HAS_URL_AND_AUTH_INFO 21
|
||||
#define NPVERS_HAS_PRIVATE_MODE 22
|
||||
#define NPVERS_MACOSX_HAS_COCOA_EVENTS 23
|
||||
#define NPVERS_HAS_ADVANCED_KEY_HANDLING 25
|
||||
#define NPVERS_HAS_URL_REDIRECT_HANDLING 26
|
||||
#define NPVERS_HAS_CLEAR_SITE_DATA 27
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Function Prototypes */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
#if defined(__OS2__)
|
||||
#define NP_LOADDS _System
|
||||
#else
|
||||
#define NP_LOADDS
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* NPP_* functions are provided by the plugin and called by the navigator. */
|
||||
|
||||
#if defined(XP_UNIX)
|
||||
const char* NPP_GetMIMEDescription(void);
|
||||
#endif
|
||||
|
||||
NPError NP_LOADDS NPP_New(NPMIMEType pluginType, NPP instance,
|
||||
uint16_t mode, int16_t argc, char* argn[],
|
||||
char* argv[], NPSavedData* saved);
|
||||
NPError NP_LOADDS NPP_Destroy(NPP instance, NPSavedData** save);
|
||||
NPError NP_LOADDS NPP_SetWindow(NPP instance, NPWindow* window);
|
||||
NPError NP_LOADDS NPP_NewStream(NPP instance, NPMIMEType type,
|
||||
NPStream* stream, NPBool seekable,
|
||||
uint16_t* stype);
|
||||
NPError NP_LOADDS NPP_DestroyStream(NPP instance, NPStream* stream,
|
||||
NPReason reason);
|
||||
int32_t NP_LOADDS NPP_WriteReady(NPP instance, NPStream* stream);
|
||||
int32_t NP_LOADDS NPP_Write(NPP instance, NPStream* stream, int32_t offset,
|
||||
int32_t len, void* buffer);
|
||||
void NP_LOADDS NPP_StreamAsFile(NPP instance, NPStream* stream,
|
||||
const char* fname);
|
||||
void NP_LOADDS NPP_Print(NPP instance, NPPrint* platformPrint);
|
||||
int16_t NP_LOADDS NPP_HandleEvent(NPP instance, void* event);
|
||||
void NP_LOADDS NPP_URLNotify(NPP instance, const char* url,
|
||||
NPReason reason, void* notifyData);
|
||||
NPError NP_LOADDS NPP_GetValue(NPP instance, NPPVariable variable, void *value);
|
||||
NPError NP_LOADDS NPP_SetValue(NPP instance, NPNVariable variable, void *value);
|
||||
NPBool NP_LOADDS NPP_GotFocus(NPP instance, NPFocusDirection direction);
|
||||
void NP_LOADDS NPP_LostFocus(NPP instance);
|
||||
void NP_LOADDS NPP_URLRedirectNotify(NPP instance, const char* url, int32_t status, void* notifyData);
|
||||
NPError NP_LOADDS NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge);
|
||||
char** NP_LOADDS NPP_GetSitesWithData(void);
|
||||
|
||||
/* NPN_* functions are provided by the navigator and called by the plugin. */
|
||||
void NP_LOADDS NPN_Version(int* plugin_major, int* plugin_minor,
|
||||
int* netscape_major, int* netscape_minor);
|
||||
NPError NP_LOADDS NPN_GetURLNotify(NPP instance, const char* url,
|
||||
const char* target, void* notifyData);
|
||||
NPError NP_LOADDS NPN_GetURL(NPP instance, const char* url,
|
||||
const char* target);
|
||||
NPError NP_LOADDS NPN_PostURLNotify(NPP instance, const char* url,
|
||||
const char* target, uint32_t len,
|
||||
const char* buf, NPBool file,
|
||||
void* notifyData);
|
||||
NPError NP_LOADDS NPN_PostURL(NPP instance, const char* url,
|
||||
const char* target, uint32_t len,
|
||||
const char* buf, NPBool file);
|
||||
NPError NP_LOADDS NPN_RequestRead(NPStream* stream, NPByteRange* rangeList);
|
||||
NPError NP_LOADDS NPN_NewStream(NPP instance, NPMIMEType type,
|
||||
const char* target, NPStream** stream);
|
||||
int32_t NP_LOADDS NPN_Write(NPP instance, NPStream* stream, int32_t len,
|
||||
void* buffer);
|
||||
NPError NP_LOADDS NPN_DestroyStream(NPP instance, NPStream* stream,
|
||||
NPReason reason);
|
||||
void NP_LOADDS NPN_Status(NPP instance, const char* message);
|
||||
const char* NP_LOADDS NPN_UserAgent(NPP instance);
|
||||
void* NP_LOADDS NPN_MemAlloc(uint32_t size);
|
||||
void NP_LOADDS NPN_MemFree(void* ptr);
|
||||
uint32_t NP_LOADDS NPN_MemFlush(uint32_t size);
|
||||
void NP_LOADDS NPN_ReloadPlugins(NPBool reloadPages);
|
||||
NPError NP_LOADDS NPN_GetValue(NPP instance, NPNVariable variable,
|
||||
void *value);
|
||||
NPError NP_LOADDS NPN_SetValue(NPP instance, NPPVariable variable,
|
||||
void *value);
|
||||
void NP_LOADDS NPN_InvalidateRect(NPP instance, NPRect *invalidRect);
|
||||
void NP_LOADDS NPN_InvalidateRegion(NPP instance,
|
||||
NPRegion invalidRegion);
|
||||
void NP_LOADDS NPN_ForceRedraw(NPP instance);
|
||||
void NP_LOADDS NPN_PushPopupsEnabledState(NPP instance, NPBool enabled);
|
||||
void NP_LOADDS NPN_PopPopupsEnabledState(NPP instance);
|
||||
void NP_LOADDS NPN_PluginThreadAsyncCall(NPP instance,
|
||||
void (*func) (void *),
|
||||
void *userData);
|
||||
NPError NP_LOADDS NPN_GetValueForURL(NPP instance, NPNURLVariable variable,
|
||||
const char *url, char **value,
|
||||
uint32_t *len);
|
||||
NPError NP_LOADDS NPN_SetValueForURL(NPP instance, NPNURLVariable variable,
|
||||
const char *url, const char *value,
|
||||
uint32_t len);
|
||||
NPError NP_LOADDS NPN_GetAuthenticationInfo(NPP instance,
|
||||
const char *protocol,
|
||||
const char *host, int32_t port,
|
||||
const char *scheme,
|
||||
const char *realm,
|
||||
char **username, uint32_t *ulen,
|
||||
char **password,
|
||||
uint32_t *plen);
|
||||
uint32_t NP_LOADDS NPN_ScheduleTimer(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID));
|
||||
void NP_LOADDS NPN_UnscheduleTimer(NPP instance, uint32_t timerID);
|
||||
NPError NP_LOADDS NPN_PopUpContextMenu(NPP instance, NPMenu* menu);
|
||||
NPBool NP_LOADDS NPN_ConvertPoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
|
||||
NPBool NP_LOADDS NPN_HandleEvent(NPP instance, void *event, NPBool handled);
|
||||
NPBool NP_LOADDS NPN_UnfocusInstance(NPP instance, NPFocusDirection direction);
|
||||
void NP_LOADDS NPN_URLRedirectResponse(NPP instance, void* notifyData, NPBool allow);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* RC_INVOKED */
|
||||
#if defined(__OS2__)
|
||||
#pragma pack()
|
||||
#endif
|
||||
|
||||
#endif /* npapi_h_ */
|
322
browser-plugin/npapi/npfunctions.h
Normal file
322
browser-plugin/npapi/npfunctions.h
Normal file
@ -0,0 +1,322 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef npfunctions_h_
|
||||
#define npfunctions_h_
|
||||
|
||||
#ifdef __OS2__
|
||||
#pragma pack(1)
|
||||
#define NP_LOADDS _System
|
||||
#else
|
||||
#define NP_LOADDS
|
||||
#endif
|
||||
|
||||
#include "npapi.h"
|
||||
#include "npruntime.h"
|
||||
|
||||
typedef NPError (* NP_LOADDS NPP_NewProcPtr)(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved);
|
||||
typedef NPError (* NP_LOADDS NPP_DestroyProcPtr)(NPP instance, NPSavedData** save);
|
||||
typedef NPError (* NP_LOADDS NPP_SetWindowProcPtr)(NPP instance, NPWindow* window);
|
||||
typedef NPError (* NP_LOADDS NPP_NewStreamProcPtr)(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype);
|
||||
typedef NPError (* NP_LOADDS NPP_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason);
|
||||
typedef int32_t (* NP_LOADDS NPP_WriteReadyProcPtr)(NPP instance, NPStream* stream);
|
||||
typedef int32_t (* NP_LOADDS NPP_WriteProcPtr)(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer);
|
||||
typedef void (* NP_LOADDS NPP_StreamAsFileProcPtr)(NPP instance, NPStream* stream, const char* fname);
|
||||
typedef void (* NP_LOADDS NPP_PrintProcPtr)(NPP instance, NPPrint* platformPrint);
|
||||
typedef int16_t (* NP_LOADDS NPP_HandleEventProcPtr)(NPP instance, void* event);
|
||||
typedef void (* NP_LOADDS NPP_URLNotifyProcPtr)(NPP instance, const char* url, NPReason reason, void* notifyData);
|
||||
/* Any NPObjects returned to the browser via NPP_GetValue should be retained
|
||||
by the plugin on the way out. The browser is responsible for releasing. */
|
||||
typedef NPError (* NP_LOADDS NPP_GetValueProcPtr)(NPP instance, NPPVariable variable, void *ret_value);
|
||||
typedef NPError (* NP_LOADDS NPP_SetValueProcPtr)(NPP instance, NPNVariable variable, void *value);
|
||||
typedef NPBool (* NP_LOADDS NPP_GotFocusPtr)(NPP instance, NPFocusDirection direction);
|
||||
typedef void (* NP_LOADDS NPP_LostFocusPtr)(NPP instance);
|
||||
typedef void (* NP_LOADDS NPP_URLRedirectNotifyPtr)(NPP instance, const char* url, int32_t status, void* notifyData);
|
||||
typedef NPError (* NP_LOADDS NPP_ClearSiteDataPtr)(const char* site, uint64_t flags, uint64_t maxAge);
|
||||
typedef char** (* NP_LOADDS NPP_GetSitesWithDataPtr)(void);
|
||||
|
||||
typedef NPError (*NPN_GetValueProcPtr)(NPP instance, NPNVariable variable, void *ret_value);
|
||||
typedef NPError (*NPN_SetValueProcPtr)(NPP instance, NPPVariable variable, void *value);
|
||||
typedef NPError (*NPN_GetURLNotifyProcPtr)(NPP instance, const char* url, const char* window, void* notifyData);
|
||||
typedef NPError (*NPN_PostURLNotifyProcPtr)(NPP instance, const char* url, const char* window, uint32_t len, const char* buf, NPBool file, void* notifyData);
|
||||
typedef NPError (*NPN_GetURLProcPtr)(NPP instance, const char* url, const char* window);
|
||||
typedef NPError (*NPN_PostURLProcPtr)(NPP instance, const char* url, const char* window, uint32_t len, const char* buf, NPBool file);
|
||||
typedef NPError (*NPN_RequestReadProcPtr)(NPStream* stream, NPByteRange* rangeList);
|
||||
typedef NPError (*NPN_NewStreamProcPtr)(NPP instance, NPMIMEType type, const char* window, NPStream** stream);
|
||||
typedef int32_t (*NPN_WriteProcPtr)(NPP instance, NPStream* stream, int32_t len, void* buffer);
|
||||
typedef NPError (*NPN_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason);
|
||||
typedef void (*NPN_StatusProcPtr)(NPP instance, const char* message);
|
||||
/* Browser manages the lifetime of the buffer returned by NPN_UserAgent, don't
|
||||
depend on it sticking around and don't free it. */
|
||||
typedef const char* (*NPN_UserAgentProcPtr)(NPP instance);
|
||||
typedef void* (*NPN_MemAllocProcPtr)(uint32_t size);
|
||||
typedef void (*NPN_MemFreeProcPtr)(void* ptr);
|
||||
typedef uint32_t (*NPN_MemFlushProcPtr)(uint32_t size);
|
||||
typedef void (*NPN_ReloadPluginsProcPtr)(NPBool reloadPages);
|
||||
typedef void* (*NPN_GetJavaEnvProcPtr)(void);
|
||||
typedef void* (*NPN_GetJavaPeerProcPtr)(NPP instance);
|
||||
typedef void (*NPN_InvalidateRectProcPtr)(NPP instance, NPRect *rect);
|
||||
typedef void (*NPN_InvalidateRegionProcPtr)(NPP instance, NPRegion region);
|
||||
typedef void (*NPN_ForceRedrawProcPtr)(NPP instance);
|
||||
typedef NPIdentifier (*NPN_GetStringIdentifierProcPtr)(const NPUTF8* name);
|
||||
typedef void (*NPN_GetStringIdentifiersProcPtr)(const NPUTF8** names, int32_t nameCount, NPIdentifier* identifiers);
|
||||
typedef NPIdentifier (*NPN_GetIntIdentifierProcPtr)(int32_t intid);
|
||||
typedef bool (*NPN_IdentifierIsStringProcPtr)(NPIdentifier identifier);
|
||||
typedef NPUTF8* (*NPN_UTF8FromIdentifierProcPtr)(NPIdentifier identifier);
|
||||
typedef int32_t (*NPN_IntFromIdentifierProcPtr)(NPIdentifier identifier);
|
||||
typedef NPObject* (*NPN_CreateObjectProcPtr)(NPP npp, NPClass *aClass);
|
||||
typedef NPObject* (*NPN_RetainObjectProcPtr)(NPObject *obj);
|
||||
typedef void (*NPN_ReleaseObjectProcPtr)(NPObject *obj);
|
||||
typedef bool (*NPN_InvokeProcPtr)(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result);
|
||||
typedef bool (*NPN_InvokeDefaultProcPtr)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result);
|
||||
typedef bool (*NPN_EvaluateProcPtr)(NPP npp, NPObject *obj, NPString *script, NPVariant *result);
|
||||
typedef bool (*NPN_GetPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result);
|
||||
typedef bool (*NPN_SetPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value);
|
||||
typedef bool (*NPN_RemovePropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName);
|
||||
typedef bool (*NPN_HasPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName);
|
||||
typedef bool (*NPN_HasMethodProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName);
|
||||
typedef void (*NPN_ReleaseVariantValueProcPtr)(NPVariant *variant);
|
||||
typedef void (*NPN_SetExceptionProcPtr)(NPObject *obj, const NPUTF8 *message);
|
||||
typedef void (*NPN_PushPopupsEnabledStateProcPtr)(NPP npp, NPBool enabled);
|
||||
typedef void (*NPN_PopPopupsEnabledStateProcPtr)(NPP npp);
|
||||
typedef bool (*NPN_EnumerateProcPtr)(NPP npp, NPObject *obj, NPIdentifier **identifier, uint32_t *count);
|
||||
typedef void (*NPN_PluginThreadAsyncCallProcPtr)(NPP instance, void (*func)(void *), void *userData);
|
||||
typedef bool (*NPN_ConstructProcPtr)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result);
|
||||
typedef NPError (*NPN_GetValueForURLPtr)(NPP npp, NPNURLVariable variable, const char *url, char **value, uint32_t *len);
|
||||
typedef NPError (*NPN_SetValueForURLPtr)(NPP npp, NPNURLVariable variable, const char *url, const char *value, uint32_t len);
|
||||
typedef NPError (*NPN_GetAuthenticationInfoPtr)(NPP npp, const char *protocol, const char *host, int32_t port, const char *scheme, const char *realm, char **username, uint32_t *ulen, char **password, uint32_t *plen);
|
||||
typedef uint32_t (*NPN_ScheduleTimerPtr)(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID));
|
||||
typedef void (*NPN_UnscheduleTimerPtr)(NPP instance, uint32_t timerID);
|
||||
typedef NPError (*NPN_PopUpContextMenuPtr)(NPP instance, NPMenu* menu);
|
||||
typedef NPBool (*NPN_ConvertPointPtr)(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
|
||||
typedef NPBool (*NPN_HandleEventPtr)(NPP instance, void *event, NPBool handled);
|
||||
typedef NPBool (*NPN_UnfocusInstancePtr)(NPP instance, NPFocusDirection direction);
|
||||
typedef void (*NPN_URLRedirectResponsePtr)(NPP instance, void* notifyData, NPBool allow);
|
||||
|
||||
typedef struct _NPPluginFuncs {
|
||||
uint16_t size;
|
||||
uint16_t version;
|
||||
NPP_NewProcPtr newp;
|
||||
NPP_DestroyProcPtr destroy;
|
||||
NPP_SetWindowProcPtr setwindow;
|
||||
NPP_NewStreamProcPtr newstream;
|
||||
NPP_DestroyStreamProcPtr destroystream;
|
||||
NPP_StreamAsFileProcPtr asfile;
|
||||
NPP_WriteReadyProcPtr writeready;
|
||||
NPP_WriteProcPtr write;
|
||||
NPP_PrintProcPtr print;
|
||||
NPP_HandleEventProcPtr event;
|
||||
NPP_URLNotifyProcPtr urlnotify;
|
||||
void* javaClass;
|
||||
NPP_GetValueProcPtr getvalue;
|
||||
NPP_SetValueProcPtr setvalue;
|
||||
NPP_GotFocusPtr gotfocus;
|
||||
NPP_LostFocusPtr lostfocus;
|
||||
NPP_URLRedirectNotifyPtr urlredirectnotify;
|
||||
NPP_ClearSiteDataPtr clearsitedata;
|
||||
NPP_GetSitesWithDataPtr getsiteswithdata;
|
||||
} NPPluginFuncs;
|
||||
|
||||
typedef struct _NPNetscapeFuncs {
|
||||
uint16_t size;
|
||||
uint16_t version;
|
||||
NPN_GetURLProcPtr geturl;
|
||||
NPN_PostURLProcPtr posturl;
|
||||
NPN_RequestReadProcPtr requestread;
|
||||
NPN_NewStreamProcPtr newstream;
|
||||
NPN_WriteProcPtr write;
|
||||
NPN_DestroyStreamProcPtr destroystream;
|
||||
NPN_StatusProcPtr status;
|
||||
NPN_UserAgentProcPtr uagent;
|
||||
NPN_MemAllocProcPtr memalloc;
|
||||
NPN_MemFreeProcPtr memfree;
|
||||
NPN_MemFlushProcPtr memflush;
|
||||
NPN_ReloadPluginsProcPtr reloadplugins;
|
||||
NPN_GetJavaEnvProcPtr getJavaEnv;
|
||||
NPN_GetJavaPeerProcPtr getJavaPeer;
|
||||
NPN_GetURLNotifyProcPtr geturlnotify;
|
||||
NPN_PostURLNotifyProcPtr posturlnotify;
|
||||
NPN_GetValueProcPtr getvalue;
|
||||
NPN_SetValueProcPtr setvalue;
|
||||
NPN_InvalidateRectProcPtr invalidaterect;
|
||||
NPN_InvalidateRegionProcPtr invalidateregion;
|
||||
NPN_ForceRedrawProcPtr forceredraw;
|
||||
NPN_GetStringIdentifierProcPtr getstringidentifier;
|
||||
NPN_GetStringIdentifiersProcPtr getstringidentifiers;
|
||||
NPN_GetIntIdentifierProcPtr getintidentifier;
|
||||
NPN_IdentifierIsStringProcPtr identifierisstring;
|
||||
NPN_UTF8FromIdentifierProcPtr utf8fromidentifier;
|
||||
NPN_IntFromIdentifierProcPtr intfromidentifier;
|
||||
NPN_CreateObjectProcPtr createobject;
|
||||
NPN_RetainObjectProcPtr retainobject;
|
||||
NPN_ReleaseObjectProcPtr releaseobject;
|
||||
NPN_InvokeProcPtr invoke;
|
||||
NPN_InvokeDefaultProcPtr invokeDefault;
|
||||
NPN_EvaluateProcPtr evaluate;
|
||||
NPN_GetPropertyProcPtr getproperty;
|
||||
NPN_SetPropertyProcPtr setproperty;
|
||||
NPN_RemovePropertyProcPtr removeproperty;
|
||||
NPN_HasPropertyProcPtr hasproperty;
|
||||
NPN_HasMethodProcPtr hasmethod;
|
||||
NPN_ReleaseVariantValueProcPtr releasevariantvalue;
|
||||
NPN_SetExceptionProcPtr setexception;
|
||||
NPN_PushPopupsEnabledStateProcPtr pushpopupsenabledstate;
|
||||
NPN_PopPopupsEnabledStateProcPtr poppopupsenabledstate;
|
||||
NPN_EnumerateProcPtr enumerate;
|
||||
NPN_PluginThreadAsyncCallProcPtr pluginthreadasynccall;
|
||||
NPN_ConstructProcPtr construct;
|
||||
NPN_GetValueForURLPtr getvalueforurl;
|
||||
NPN_SetValueForURLPtr setvalueforurl;
|
||||
NPN_GetAuthenticationInfoPtr getauthenticationinfo;
|
||||
NPN_ScheduleTimerPtr scheduletimer;
|
||||
NPN_UnscheduleTimerPtr unscheduletimer;
|
||||
NPN_PopUpContextMenuPtr popupcontextmenu;
|
||||
NPN_ConvertPointPtr convertpoint;
|
||||
NPN_HandleEventPtr handleevent;
|
||||
NPN_UnfocusInstancePtr unfocusinstance;
|
||||
NPN_URLRedirectResponsePtr urlredirectresponse;
|
||||
} NPNetscapeFuncs;
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
/*
|
||||
* Mac OS X version(s) of NP_GetMIMEDescription(const char *)
|
||||
* These can be called to retreive MIME information from the plugin dynamically
|
||||
*
|
||||
* Note: For compatibility with Quicktime, BPSupportedMIMEtypes is another way
|
||||
* to get mime info from the plugin only on OSX and may not be supported
|
||||
* in furture version -- use NP_GetMIMEDescription instead
|
||||
*/
|
||||
enum
|
||||
{
|
||||
kBPSupportedMIMETypesStructVers_1 = 1
|
||||
};
|
||||
typedef struct _BPSupportedMIMETypes
|
||||
{
|
||||
SInt32 structVersion; /* struct version */
|
||||
Handle typeStrings; /* STR# formated handle, allocated by plug-in */
|
||||
Handle infoStrings; /* STR# formated handle, allocated by plug-in */
|
||||
} BPSupportedMIMETypes;
|
||||
OSErr BP_GetSupportedMIMETypes(BPSupportedMIMETypes *mimeInfo, UInt32 flags);
|
||||
#define NP_GETMIMEDESCRIPTION_NAME "NP_GetMIMEDescription"
|
||||
typedef const char* (*NP_GetMIMEDescriptionProcPtr)(void);
|
||||
typedef OSErr (*BP_GetSupportedMIMETypesProcPtr)(BPSupportedMIMETypes*, UInt32);
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define OSCALL WINAPI
|
||||
#else
|
||||
#if defined(__OS2__)
|
||||
#define OSCALL _System
|
||||
#else
|
||||
#define OSCALL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(XP_UNIX)
|
||||
/* GCC 3.3 and later support the visibility attribute. */
|
||||
#if defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))
|
||||
#define NP_VISIBILITY_DEFAULT __attribute__((visibility("default")))
|
||||
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
||||
#define NP_VISIBILITY_DEFAULT __global
|
||||
#else
|
||||
#define NP_VISIBILITY_DEFAULT
|
||||
#endif
|
||||
#define NP_EXPORT(__type) NP_VISIBILITY_DEFAULT __type
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined (__OS2__)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* plugin meta member functions */
|
||||
#if defined(__OS2__)
|
||||
typedef struct _NPPluginData { /* Alternate OS2 Plugin interface */
|
||||
char *pMimeTypes;
|
||||
char *pFileExtents;
|
||||
char *pFileOpenTemplate;
|
||||
char *pProductName;
|
||||
char *pProductDescription;
|
||||
unsigned long dwProductVersionMS;
|
||||
unsigned long dwProductVersionLS;
|
||||
} NPPluginData;
|
||||
typedef NPError (*NP_GetPluginDataFunc)(NPPluginData*);
|
||||
NPError OSCALL NP_GetPluginData(NPPluginData * pPluginData);
|
||||
#endif
|
||||
typedef NPError (*NP_GetEntryPointsFunc)(NPPluginFuncs*);
|
||||
NPError OSCALL NP_GetEntryPoints(NPPluginFuncs* pFuncs);
|
||||
typedef NPError (*NP_InitializeFunc)(NPNetscapeFuncs*);
|
||||
NPError OSCALL NP_Initialize(NPNetscapeFuncs* bFuncs);
|
||||
typedef NPError (*NP_ShutdownFunc)(void);
|
||||
NPError OSCALL NP_Shutdown(void);
|
||||
typedef const char* (*NP_GetMIMEDescriptionFunc)(void);
|
||||
const char* NP_GetMIMEDescription(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__OS2__)
|
||||
#pragma pack()
|
||||
#endif
|
||||
|
||||
#ifdef XP_UNIX
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
typedef char* (*NP_GetPluginVersionFunc)(void);
|
||||
NP_EXPORT(char*) NP_GetPluginVersion(void);
|
||||
typedef const char* (*NP_GetMIMEDescriptionFunc)(void);
|
||||
NP_EXPORT(const char*) NP_GetMIMEDescription(void);
|
||||
#ifdef XP_MACOSX
|
||||
typedef NPError (*NP_InitializeFunc)(NPNetscapeFuncs*);
|
||||
NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs);
|
||||
typedef NPError (*NP_GetEntryPointsFunc)(NPPluginFuncs*);
|
||||
NP_EXPORT(NPError) NP_GetEntryPoints(NPPluginFuncs* pFuncs);
|
||||
#else
|
||||
typedef NPError (*NP_InitializeFunc)(NPNetscapeFuncs*, NPPluginFuncs*);
|
||||
NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs);
|
||||
#endif
|
||||
typedef NPError (*NP_ShutdownFunc)(void);
|
||||
NP_EXPORT(NPError) NP_Shutdown(void);
|
||||
typedef NPError (*NP_GetValueFunc)(void *, NPPVariable, void *);
|
||||
NP_EXPORT(NPError) NP_GetValue(void *future, NPPVariable aVariable, void *aValue);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* npfunctions_h_ */
|
393
browser-plugin/npapi/npruntime.h
Normal file
393
browser-plugin/npapi/npruntime.h
Normal file
@ -0,0 +1,393 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Copyright (c) 2004, Apple Computer, Inc. and The Mozilla Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of Apple Computer, Inc. ("Apple") or The Mozilla
|
||||
* Foundation ("Mozilla") nor the names of their contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE, MOZILLA AND THEIR CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE, MOZILLA OR
|
||||
* THEIR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
#ifndef _NP_RUNTIME_H_
|
||||
#define _NP_RUNTIME_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "nptypes.h"
|
||||
|
||||
/*
|
||||
This API is used to facilitate binding code written in C to script
|
||||
objects. The API in this header does not assume the presence of a
|
||||
user agent. That is, it can be used to bind C code to scripting
|
||||
environments outside of the context of a user agent.
|
||||
|
||||
However, the normal use of the this API is in the context of a
|
||||
scripting environment running in a browser or other user agent.
|
||||
In particular it is used to support the extended Netscape
|
||||
script-ability API for plugins (NP-SAP). NP-SAP is an extension
|
||||
of the Netscape plugin API. As such we have adopted the use of
|
||||
the "NP" prefix for this API.
|
||||
|
||||
The following NP{N|P}Variables were added to the Netscape plugin
|
||||
API (in npapi.h):
|
||||
|
||||
NPNVWindowNPObject
|
||||
NPNVPluginElementNPObject
|
||||
NPPVpluginScriptableNPObject
|
||||
|
||||
These variables are exposed through NPN_GetValue() and
|
||||
NPP_GetValue() (respectively) and are used to establish the
|
||||
initial binding between the user agent and native code. The DOM
|
||||
objects in the user agent can be examined and manipulated using
|
||||
the NPN_ functions that operate on NPObjects described in this
|
||||
header.
|
||||
|
||||
To the extent possible the assumptions about the scripting
|
||||
language used by the scripting environment have been minimized.
|
||||
*/
|
||||
|
||||
#define NP_BEGIN_MACRO do {
|
||||
#define NP_END_MACRO } while (0)
|
||||
|
||||
/*
|
||||
Objects (non-primitive data) passed between 'C' and script is
|
||||
always wrapped in an NPObject. The 'interface' of an NPObject is
|
||||
described by an NPClass.
|
||||
*/
|
||||
typedef struct NPObject NPObject;
|
||||
typedef struct NPClass NPClass;
|
||||
|
||||
typedef char NPUTF8;
|
||||
typedef struct _NPString {
|
||||
const NPUTF8 *UTF8Characters;
|
||||
uint32_t UTF8Length;
|
||||
} NPString;
|
||||
|
||||
typedef enum {
|
||||
NPVariantType_Void,
|
||||
NPVariantType_Null,
|
||||
NPVariantType_Bool,
|
||||
NPVariantType_Int32,
|
||||
NPVariantType_Double,
|
||||
NPVariantType_String,
|
||||
NPVariantType_Object
|
||||
} NPVariantType;
|
||||
|
||||
typedef struct _NPVariant {
|
||||
NPVariantType type;
|
||||
union {
|
||||
bool boolValue;
|
||||
int32_t intValue;
|
||||
double doubleValue;
|
||||
NPString stringValue;
|
||||
NPObject *objectValue;
|
||||
} value;
|
||||
} NPVariant;
|
||||
|
||||
/*
|
||||
NPN_ReleaseVariantValue is called on all 'out' parameters
|
||||
references. Specifically it is to be called on variants that own
|
||||
their value, as is the case with all non-const NPVariant*
|
||||
arguments after a successful call to any methods (except this one)
|
||||
in this API.
|
||||
|
||||
After calling NPN_ReleaseVariantValue, the type of the variant
|
||||
will be NPVariantType_Void.
|
||||
*/
|
||||
void NPN_ReleaseVariantValue(NPVariant *variant);
|
||||
|
||||
#define NPVARIANT_IS_VOID(_v) ((_v).type == NPVariantType_Void)
|
||||
#define NPVARIANT_IS_NULL(_v) ((_v).type == NPVariantType_Null)
|
||||
#define NPVARIANT_IS_BOOLEAN(_v) ((_v).type == NPVariantType_Bool)
|
||||
#define NPVARIANT_IS_INT32(_v) ((_v).type == NPVariantType_Int32)
|
||||
#define NPVARIANT_IS_DOUBLE(_v) ((_v).type == NPVariantType_Double)
|
||||
#define NPVARIANT_IS_STRING(_v) ((_v).type == NPVariantType_String)
|
||||
#define NPVARIANT_IS_OBJECT(_v) ((_v).type == NPVariantType_Object)
|
||||
|
||||
#define NPVARIANT_TO_BOOLEAN(_v) ((_v).value.boolValue)
|
||||
#define NPVARIANT_TO_INT32(_v) ((_v).value.intValue)
|
||||
#define NPVARIANT_TO_DOUBLE(_v) ((_v).value.doubleValue)
|
||||
#define NPVARIANT_TO_STRING(_v) ((_v).value.stringValue)
|
||||
#define NPVARIANT_TO_OBJECT(_v) ((_v).value.objectValue)
|
||||
|
||||
#define VOID_TO_NPVARIANT(_v) \
|
||||
NP_BEGIN_MACRO \
|
||||
(_v).type = NPVariantType_Void; \
|
||||
(_v).value.objectValue = NULL; \
|
||||
NP_END_MACRO
|
||||
|
||||
#define NULL_TO_NPVARIANT(_v) \
|
||||
NP_BEGIN_MACRO \
|
||||
(_v).type = NPVariantType_Null; \
|
||||
(_v).value.objectValue = NULL; \
|
||||
NP_END_MACRO
|
||||
|
||||
#define BOOLEAN_TO_NPVARIANT(_val, _v) \
|
||||
NP_BEGIN_MACRO \
|
||||
(_v).type = NPVariantType_Bool; \
|
||||
(_v).value.boolValue = !!(_val); \
|
||||
NP_END_MACRO
|
||||
|
||||
#define INT32_TO_NPVARIANT(_val, _v) \
|
||||
NP_BEGIN_MACRO \
|
||||
(_v).type = NPVariantType_Int32; \
|
||||
(_v).value.intValue = _val; \
|
||||
NP_END_MACRO
|
||||
|
||||
#define DOUBLE_TO_NPVARIANT(_val, _v) \
|
||||
NP_BEGIN_MACRO \
|
||||
(_v).type = NPVariantType_Double; \
|
||||
(_v).value.doubleValue = _val; \
|
||||
NP_END_MACRO
|
||||
|
||||
#define STRINGZ_TO_NPVARIANT(_val, _v) \
|
||||
NP_BEGIN_MACRO \
|
||||
(_v).type = NPVariantType_String; \
|
||||
NPString str = { _val, (uint32_t)(strlen(_val)) }; \
|
||||
(_v).value.stringValue = str; \
|
||||
NP_END_MACRO
|
||||
|
||||
#define STRINGN_TO_NPVARIANT(_val, _len, _v) \
|
||||
NP_BEGIN_MACRO \
|
||||
(_v).type = NPVariantType_String; \
|
||||
NPString str = { _val, (uint32_t)(_len) }; \
|
||||
(_v).value.stringValue = str; \
|
||||
NP_END_MACRO
|
||||
|
||||
#define OBJECT_TO_NPVARIANT(_val, _v) \
|
||||
NP_BEGIN_MACRO \
|
||||
(_v).type = NPVariantType_Object; \
|
||||
(_v).value.objectValue = _val; \
|
||||
NP_END_MACRO
|
||||
|
||||
|
||||
/*
|
||||
Type mappings (JavaScript types have been used for illustration
|
||||
purposes):
|
||||
|
||||
JavaScript to C (NPVariant with type:)
|
||||
undefined NPVariantType_Void
|
||||
null NPVariantType_Null
|
||||
Boolean NPVariantType_Bool
|
||||
Number NPVariantType_Double or NPVariantType_Int32
|
||||
String NPVariantType_String
|
||||
Object NPVariantType_Object
|
||||
|
||||
C (NPVariant with type:) to JavaScript
|
||||
NPVariantType_Void undefined
|
||||
NPVariantType_Null null
|
||||
NPVariantType_Bool Boolean
|
||||
NPVariantType_Int32 Number
|
||||
NPVariantType_Double Number
|
||||
NPVariantType_String String
|
||||
NPVariantType_Object Object
|
||||
*/
|
||||
|
||||
typedef void *NPIdentifier;
|
||||
|
||||
/*
|
||||
NPObjects have methods and properties. Methods and properties are
|
||||
identified with NPIdentifiers. These identifiers may be reflected
|
||||
in script. NPIdentifiers can be either strings or integers, IOW,
|
||||
methods and properties can be identified by either strings or
|
||||
integers (i.e. foo["bar"] vs foo[1]). NPIdentifiers can be
|
||||
compared using ==. In case of any errors, the requested
|
||||
NPIdentifier(s) will be NULL. NPIdentifier lifetime is controlled
|
||||
by the browser. Plugins do not need to worry about memory management
|
||||
with regards to NPIdentifiers.
|
||||
*/
|
||||
NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name);
|
||||
void NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount,
|
||||
NPIdentifier *identifiers);
|
||||
NPIdentifier NPN_GetIntIdentifier(int32_t intid);
|
||||
bool NPN_IdentifierIsString(NPIdentifier identifier);
|
||||
|
||||
/*
|
||||
The NPUTF8 returned from NPN_UTF8FromIdentifier SHOULD be freed.
|
||||
*/
|
||||
NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier);
|
||||
|
||||
/*
|
||||
Get the integer represented by identifier. If identifier is not an
|
||||
integer identifier, the behaviour is undefined.
|
||||
*/
|
||||
int32_t NPN_IntFromIdentifier(NPIdentifier identifier);
|
||||
|
||||
/*
|
||||
NPObject behavior is implemented using the following set of
|
||||
callback functions.
|
||||
|
||||
The NPVariant *result argument of these functions (where
|
||||
applicable) should be released using NPN_ReleaseVariantValue().
|
||||
*/
|
||||
typedef NPObject *(*NPAllocateFunctionPtr)(NPP npp, NPClass *aClass);
|
||||
typedef void (*NPDeallocateFunctionPtr)(NPObject *npobj);
|
||||
typedef void (*NPInvalidateFunctionPtr)(NPObject *npobj);
|
||||
typedef bool (*NPHasMethodFunctionPtr)(NPObject *npobj, NPIdentifier name);
|
||||
typedef bool (*NPInvokeFunctionPtr)(NPObject *npobj, NPIdentifier name,
|
||||
const NPVariant *args, uint32_t argCount,
|
||||
NPVariant *result);
|
||||
typedef bool (*NPInvokeDefaultFunctionPtr)(NPObject *npobj,
|
||||
const NPVariant *args,
|
||||
uint32_t argCount,
|
||||
NPVariant *result);
|
||||
typedef bool (*NPHasPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name);
|
||||
typedef bool (*NPGetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name,
|
||||
NPVariant *result);
|
||||
typedef bool (*NPSetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name,
|
||||
const NPVariant *value);
|
||||
typedef bool (*NPRemovePropertyFunctionPtr)(NPObject *npobj,
|
||||
NPIdentifier name);
|
||||
typedef bool (*NPEnumerationFunctionPtr)(NPObject *npobj, NPIdentifier **value,
|
||||
uint32_t *count);
|
||||
typedef bool (*NPConstructFunctionPtr)(NPObject *npobj,
|
||||
const NPVariant *args,
|
||||
uint32_t argCount,
|
||||
NPVariant *result);
|
||||
|
||||
/*
|
||||
NPObjects returned by create, retain, invoke, and getProperty pass
|
||||
a reference count to the caller. That is, the callee adds a
|
||||
reference count which passes to the caller. It is the caller's
|
||||
responsibility to release the returned object.
|
||||
|
||||
NPInvokeFunctionPtr function may return 0 to indicate a void
|
||||
result.
|
||||
|
||||
NPInvalidateFunctionPtr is called by the scripting environment
|
||||
when the native code is shutdown. Any attempt to message a
|
||||
NPObject instance after the invalidate callback has been
|
||||
called will result in undefined behavior, even if the native code
|
||||
is still retaining those NPObject instances. (The runtime
|
||||
will typically return immediately, with 0 or NULL, from an attempt
|
||||
to dispatch to a NPObject, but this behavior should not be
|
||||
depended upon.)
|
||||
|
||||
The NPEnumerationFunctionPtr function may pass an array of
|
||||
NPIdentifiers back to the caller. The callee allocs the memory of
|
||||
the array using NPN_MemAlloc(), and it's the caller's responsibility
|
||||
to release it using NPN_MemFree().
|
||||
*/
|
||||
struct NPClass
|
||||
{
|
||||
uint32_t structVersion;
|
||||
NPAllocateFunctionPtr allocate;
|
||||
NPDeallocateFunctionPtr deallocate;
|
||||
NPInvalidateFunctionPtr invalidate;
|
||||
NPHasMethodFunctionPtr hasMethod;
|
||||
NPInvokeFunctionPtr invoke;
|
||||
NPInvokeDefaultFunctionPtr invokeDefault;
|
||||
NPHasPropertyFunctionPtr hasProperty;
|
||||
NPGetPropertyFunctionPtr getProperty;
|
||||
NPSetPropertyFunctionPtr setProperty;
|
||||
NPRemovePropertyFunctionPtr removeProperty;
|
||||
NPEnumerationFunctionPtr enumerate;
|
||||
NPConstructFunctionPtr construct;
|
||||
};
|
||||
|
||||
#define NP_CLASS_STRUCT_VERSION 3
|
||||
|
||||
#define NP_CLASS_STRUCT_VERSION_ENUM 2
|
||||
#define NP_CLASS_STRUCT_VERSION_CTOR 3
|
||||
|
||||
#define NP_CLASS_STRUCT_VERSION_HAS_ENUM(npclass) \
|
||||
((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_ENUM)
|
||||
|
||||
#define NP_CLASS_STRUCT_VERSION_HAS_CTOR(npclass) \
|
||||
((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR)
|
||||
|
||||
struct NPObject {
|
||||
NPClass *_class;
|
||||
uint32_t referenceCount;
|
||||
/*
|
||||
* Additional space may be allocated here by types of NPObjects
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
If the class has an allocate function, NPN_CreateObject invokes
|
||||
that function, otherwise a NPObject is allocated and
|
||||
returned. This method will initialize the referenceCount member of
|
||||
the NPObject to 1.
|
||||
*/
|
||||
NPObject *NPN_CreateObject(NPP npp, NPClass *aClass);
|
||||
|
||||
/*
|
||||
Increment the NPObject's reference count.
|
||||
*/
|
||||
NPObject *NPN_RetainObject(NPObject *npobj);
|
||||
|
||||
/*
|
||||
Decremented the NPObject's reference count. If the reference
|
||||
count goes to zero, the class's destroy function is invoke if
|
||||
specified, otherwise the object is freed directly.
|
||||
*/
|
||||
void NPN_ReleaseObject(NPObject *npobj);
|
||||
|
||||
/*
|
||||
Functions to access script objects represented by NPObject.
|
||||
|
||||
Calls to script objects are synchronous. If a function returns a
|
||||
value, it will be supplied via the result NPVariant
|
||||
argument. Successful calls will return true, false will be
|
||||
returned in case of an error.
|
||||
|
||||
Calls made from plugin code to script must be made from the thread
|
||||
on which the plugin was initialized.
|
||||
*/
|
||||
|
||||
bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName,
|
||||
const NPVariant *args, uint32_t argCount, NPVariant *result);
|
||||
bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args,
|
||||
uint32_t argCount, NPVariant *result);
|
||||
bool NPN_Evaluate(NPP npp, NPObject *npobj, NPString *script,
|
||||
NPVariant *result);
|
||||
bool NPN_GetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName,
|
||||
NPVariant *result);
|
||||
bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName,
|
||||
const NPVariant *value);
|
||||
bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);
|
||||
bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);
|
||||
bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName);
|
||||
bool NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier,
|
||||
uint32_t *count);
|
||||
bool NPN_Construct(NPP npp, NPObject *npobj, const NPVariant *args,
|
||||
uint32_t argCount, NPVariant *result);
|
||||
|
||||
/*
|
||||
NPN_SetException may be called to trigger a script exception upon
|
||||
return from entry points into NPObjects. Typical usage:
|
||||
|
||||
NPN_SetException (npobj, message);
|
||||
*/
|
||||
void NPN_SetException(NPObject *npobj, const NPUTF8 *message);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
121
browser-plugin/npapi/nptypes.h
Normal file
121
browser-plugin/npapi/nptypes.h
Normal file
@ -0,0 +1,121 @@
|
||||
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* mozilla.org.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Johnny Stenback <jst@mozilla.org> (Original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nptypes_h_
|
||||
#define nptypes_h_
|
||||
|
||||
/*
|
||||
* Header file for ensuring that C99 types ([u]int32_t, [u]int64_t and bool) and
|
||||
* true/false macros are available.
|
||||
*/
|
||||
|
||||
#if defined(WIN32) || defined(OS2)
|
||||
/*
|
||||
* Win32 and OS/2 don't know C99, so define [u]int_16/32/64 here. The bool
|
||||
* is predefined tho, both in C and C++.
|
||||
*/
|
||||
typedef short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
#elif defined(_AIX) || defined(__sun) || defined(__osf__) || defined(IRIX) || defined(HPUX)
|
||||
/*
|
||||
* AIX and SunOS ship a inttypes.h header that defines [u]int32_t,
|
||||
* but not bool for C.
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifndef __cplusplus
|
||||
typedef int bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
#endif
|
||||
#elif defined(bsdi) || defined(FREEBSD) || defined(OPENBSD)
|
||||
/*
|
||||
* BSD/OS, FreeBSD, and OpenBSD ship sys/types.h that define int32_t and
|
||||
* u_int32_t.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
|
||||
/*
|
||||
* BSD/OS ships no header that defines uint32_t, nor bool (for C)
|
||||
*/
|
||||
#if defined(bsdi)
|
||||
typedef u_int32_t uint32_t;
|
||||
typedef u_int64_t uint64_t;
|
||||
|
||||
#if !defined(__cplusplus)
|
||||
typedef int bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
#endif
|
||||
#else
|
||||
/*
|
||||
* FreeBSD and OpenBSD define uint32_t and bool.
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
#elif defined(BEOS)
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
/*
|
||||
* For those that ship a standard C99 stdint.h header file, include
|
||||
* it. Can't do the same for stdbool.h tho, since some systems ship
|
||||
* with a stdbool.h file that doesn't compile!
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef __cplusplus
|
||||
#if !defined(__GNUC__) || (__GNUC__ > 2 || __GNUC_MINOR__ > 95)
|
||||
#include <stdbool.h>
|
||||
#else
|
||||
/*
|
||||
* GCC 2.91 can't deal with a typedef for bool, but a #define
|
||||
* works.
|
||||
*/
|
||||
#define bool int
|
||||
#define true 1
|
||||
#define false 0
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* nptypes_h_ */
|
65
configure.ac
65
configure.ac
@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.63)
|
||||
AC_INIT([gnome-shell],[3.1.91],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
AC_INIT([gnome-shell],[3.3.2],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_SRCDIR([src/shell-global.c])
|
||||
@ -9,8 +9,8 @@ AC_CONFIG_AUX_DIR([config])
|
||||
AC_SUBST([PACKAGE_NAME], ["$PACKAGE_NAME"])
|
||||
AC_SUBST([PACKAGE_VERSION], ["$PACKAGE_VERSION"])
|
||||
|
||||
AM_INIT_AUTOMAKE([1.10 dist-bzip2 no-dist-gzip foreign])
|
||||
AM_MAINTAINER_MODE
|
||||
AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar foreign])
|
||||
AM_MAINTAINER_MODE([enable])
|
||||
|
||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
||||
|
||||
@ -36,10 +36,6 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",
|
||||
|
||||
PKG_PROG_PKG_CONFIG([0.22])
|
||||
|
||||
# GConf stuff
|
||||
AC_PATH_PROG(GCONFTOOL, gconftool-2, no)
|
||||
AM_GCONF_SOURCE_2
|
||||
|
||||
GLIB_GSETTINGS
|
||||
|
||||
# Get a value to substitute into gnome-shell.in
|
||||
@ -66,11 +62,11 @@ AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
||||
|
||||
CLUTTER_MIN_VERSION=1.7.5
|
||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
||||
GJS_MIN_VERSION=1.29.15
|
||||
MUTTER_MIN_VERSION=3.0.0
|
||||
GJS_MIN_VERSION=1.29.18
|
||||
MUTTER_MIN_VERSION=3.3.2
|
||||
FOLKS_MIN_VERSION=0.5.2
|
||||
GTK_MIN_VERSION=3.0.0
|
||||
GIO_MIN_VERSION=2.29.10
|
||||
GIO_MIN_VERSION=2.31.0
|
||||
LIBECAL_MIN_VERSION=2.32.0
|
||||
LIBEDATASERVER_MIN_VERSION=1.2.0
|
||||
LIBEDATASERVERUI_MIN_VERSION=2.91.6
|
||||
@ -80,13 +76,13 @@ POLKIT_MIN_VERSION=0.100
|
||||
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
||||
|
||||
# Collect more than 20 libraries for a prize!
|
||||
PKG_CHECK_MODULES(GNOME_SHELL, gio-2.0 >= $GIO_MIN_VERSION
|
||||
gio-unix-2.0 dbus-glib-1 libxml-2.0
|
||||
PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
|
||||
libxml-2.0
|
||||
gtk+-3.0 >= $GTK_MIN_VERSION
|
||||
folks >= $FOLKS_MIN_VERSION
|
||||
libmutter >= $MUTTER_MIN_VERSION
|
||||
gjs-internals-1.0 >= $GJS_MIN_VERSION
|
||||
libgnome-menu-3.0 $recorder_modules gconf-2.0
|
||||
libgnome-menu-3.0 $recorder_modules
|
||||
gdk-x11-3.0 libsoup-2.4
|
||||
clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
|
||||
clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
|
||||
@ -102,6 +98,8 @@ PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
|
||||
|
||||
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)
|
||||
|
||||
GJS_VERSION=`$PKG_CONFIG --modversion gjs-internals-1.0`
|
||||
AC_DEFINE_UNQUOTED([GJS_VERSION], ["$GJS_VERSION"], [The version of GJS we're linking to])
|
||||
AC_SUBST([GJS_VERSION], ["$GJS_VERSION"])
|
||||
@ -119,7 +117,6 @@ CFLAGS=$saved_CFLAGS
|
||||
LIBS=$saved_LIBS
|
||||
|
||||
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.2 gnome-desktop-3.0 >= 2.90.0 x11)
|
||||
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-3.0)
|
||||
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
|
||||
PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
|
||||
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 0.1.7)
|
||||
@ -129,6 +126,7 @@ PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0],
|
||||
[BLUETOOTH_DIR=`$PKG_CONFIG --variable=applet_libdir gnome-bluetooth-1.0`
|
||||
BLUETOOTH_LIBS=`$PKG_CONFIG --variable=applet_libs gnome-bluetooth-1.0`
|
||||
AC_SUBST([BLUETOOTH_LIBS],["$BLUETOOTH_LIBS"])
|
||||
AC_SUBST([BLUETOOTH_DIR],["$BLUETOOTH_DIR"])
|
||||
AC_DEFINE_UNQUOTED([BLUETOOTH_DIR],["$BLUETOOTH_DIR"],[Path to installed GnomeBluetooth typelib and library])
|
||||
AC_DEFINE([HAVE_BLUETOOTH],[1],[Define if you have libgnome-bluetooth-applet])
|
||||
AC_SUBST([HAVE_BLUETOOTH],[1])
|
||||
@ -177,11 +175,13 @@ AC_SUBST(GIRDIR)
|
||||
TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)"
|
||||
AC_SUBST(TYPELIBDIR)
|
||||
|
||||
GTK_DOC_CHECK([1.15], [--flavour no-tmpl])
|
||||
|
||||
# Stay command-line compatible with the gnome-common configure option. Here
|
||||
# minimum/yes/maximum are the same, however.
|
||||
AC_ARG_ENABLE(compile_warnings,
|
||||
AS_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@],[Turn on compiler warnings]),,
|
||||
enable_compile_warnings=error)
|
||||
enable_compile_warnings=maximum)
|
||||
|
||||
changequote(,)dnl
|
||||
if test "$enable_compile_warnings" != no ; then
|
||||
@ -208,12 +208,47 @@ AC_ARG_ENABLE(jhbuild-wrapper-script,
|
||||
AS_HELP_STRING([--jhbuild-wrapper-script=yes],[Make "gnome-shell" script work for jhbuild]),,enable_jhbuild_wrapper_script=no)
|
||||
AM_CONDITIONAL(USE_JHBUILD_WRAPPER_SCRIPT, test "x$enable_jhbuild_wrapper_script" = xyes)
|
||||
|
||||
AC_MSG_CHECKING([location of system Certificate Authority list])
|
||||
AC_ARG_WITH(ca-certificates,
|
||||
[AC_HELP_STRING([--with-ca-certificates=@<:@path@:>@],
|
||||
[path to system Certificate Authority list])])
|
||||
|
||||
if test "$with_ca_certificates" = "no"; then
|
||||
AC_MSG_RESULT([disabled])
|
||||
else
|
||||
if test -z "$with_ca_certificates"; then
|
||||
for f in /etc/pki/tls/certs/ca-bundle.crt \
|
||||
/etc/ssl/certs/ca-certificates.crt; do
|
||||
if test -f "$f"; then
|
||||
with_ca_certificates="$f"
|
||||
fi
|
||||
done
|
||||
if test -z "$with_ca_certificates"; then
|
||||
AC_MSG_ERROR([could not find. Use --with-ca-certificates=path to set, or --without-ca-certificates to disable])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_MSG_RESULT($with_ca_certificates)
|
||||
AC_DEFINE_UNQUOTED(SHELL_SYSTEM_CA_FILE, ["$with_ca_certificates"], [The system TLS CA list])
|
||||
fi
|
||||
AC_SUBST(SHELL_SYSTEM_CA_FILE,["$with_ca_certificates"])
|
||||
|
||||
BROWSER_PLUGIN_DIR="${BROWSER_PLUGIN_DIR:-"\${libdir}/mozilla/plugins"}"
|
||||
AC_ARG_VAR([BROWSER_PLUGIN_DIR],[Where to install the plugin to])
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
data/Makefile
|
||||
docs/Makefile
|
||||
docs/reference/Makefile
|
||||
docs/reference/shell/Makefile
|
||||
docs/reference/shell/shell-docs.sgml
|
||||
docs/reference/st/Makefile
|
||||
docs/reference/st/st-docs.sgml
|
||||
js/Makefile
|
||||
js/misc/config.js
|
||||
src/Makefile
|
||||
browser-plugin/Makefile
|
||||
tests/Makefile
|
||||
po/Makefile.in
|
||||
man/Makefile
|
||||
|
@ -60,23 +60,14 @@ gschemas.compiled: $(gsettings_SCHEMAS:.xml=.valid)
|
||||
all-local: gschemas.compiled
|
||||
|
||||
|
||||
# GConf schemas: provide defaults for keys from Metacity we are overriding
|
||||
gconfschemadir = @GCONF_SCHEMA_FILE_DIR@
|
||||
gconfschema_DATA = gnome-shell.schemas
|
||||
|
||||
shadersdir = $(pkgdatadir)/shaders
|
||||
shaders_DATA = \
|
||||
shaders/dim-window.glsl
|
||||
|
||||
install-data-local:
|
||||
GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(srcdir)/$(gconfschema_DATA)
|
||||
|
||||
|
||||
|
||||
EXTRA_DIST = \
|
||||
gnome-shell.desktop.in.in \
|
||||
$(menu_DATA) \
|
||||
$(gconfschema_DATA) \
|
||||
$(shaders_DATA) \
|
||||
org.gnome.shell.gschema.xml.in
|
||||
|
||||
|
@ -1,100 +0,0 @@
|
||||
<gconfschemafile>
|
||||
<schemalist>
|
||||
|
||||
<!-- Metacity overrides -->
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/shell/windows/attach_modal_dialogs</key>
|
||||
<applyto>/desktop/gnome/shell/windows/attach_modal_dialogs</applyto>
|
||||
<owner>gnome-shell</owner>
|
||||
<type>bool</type>
|
||||
<default>true</default>
|
||||
<locale name="C">
|
||||
<short>Attach modal dialog to the parent window</short>
|
||||
<long>
|
||||
This key overrides /apps/mutter/general/attach_modal_dialogs when
|
||||
running GNOME Shell.
|
||||
</long>
|
||||
</locale>
|
||||
</schema>
|
||||
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/shell/windows/button_layout</key>
|
||||
<applyto>/desktop/gnome/shell/windows/button_layout</applyto>
|
||||
<owner>gnome-shell</owner>
|
||||
<type>string</type>
|
||||
<default>:close</default>
|
||||
<locale name="C">
|
||||
<short>Arrangement of buttons on the titlebar</short>
|
||||
<long>
|
||||
Arrangement of buttons on the titlebar. The
|
||||
value should be a string, such as
|
||||
"menu:minimize,maximize,spacer,close"; the colon separates the
|
||||
left corner of the window from the right corner, and
|
||||
the button names are comma-separated. Duplicate buttons
|
||||
are not allowed. Unknown button names are silently ignored
|
||||
so that buttons can be added in future gnome-shell versions
|
||||
without breaking older versions.
|
||||
A special spacer tag can be used to insert some space between
|
||||
two adjacent buttons.
|
||||
|
||||
This key overrides /apps/metacity/general/button_layout when
|
||||
running GNOME Shell.
|
||||
</long>
|
||||
</locale>
|
||||
</schema>
|
||||
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/shell/windows/edge_tiling</key>
|
||||
<applyto>/desktop/gnome/shell/windows/edge_tiling</applyto>
|
||||
<owner>gnome-shell</owner>
|
||||
<type>bool</type>
|
||||
<default>true</default>
|
||||
<locale name="C">
|
||||
<short>enable edge tiling when dropping windows on screen edges</short>
|
||||
<long>
|
||||
If enabled, dropping windows on vertical screen edges maximizes them
|
||||
vertically and resizes them horizontally to cover half of the
|
||||
available area. Dropping windows on the top screen edge maximizes them
|
||||
completely.
|
||||
|
||||
This key overrides /apps/metacity/general/edge_tiling when
|
||||
running GNOME Shell.
|
||||
</long>
|
||||
</locale>
|
||||
</schema>
|
||||
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/shell/windows/theme</key>
|
||||
<applyto>/desktop/gnome/shell/windows/theme</applyto>
|
||||
<owner>gnome-shell</owner>
|
||||
<type>string</type>
|
||||
<default>Adwaita</default>
|
||||
<locale name="C">
|
||||
<short>Current theme</short>
|
||||
<long>
|
||||
The theme determines the appearance of window borders,
|
||||
titlebar, and so forth.
|
||||
|
||||
This key overrides /apps/metacity/general/theme when
|
||||
running GNOME Shell.
|
||||
</long>
|
||||
</locale>
|
||||
</schema>
|
||||
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/shell/windows/workspaces_only_on_primary</key>
|
||||
<applyto>/desktop/gnome/shell/windows/workspaces_only_on_primary</applyto>
|
||||
<owner>gnome-shell</owner>
|
||||
<type>bool</type>
|
||||
<default>true</default>
|
||||
<locale name="C">
|
||||
<short>Workspaces only on primary monitor</short>
|
||||
<long>
|
||||
This key overrides /apps/mutter/general/workspaces_only_on_primary when
|
||||
running GNOME Shell.
|
||||
</long>
|
||||
</locale>
|
||||
</schema>
|
||||
|
||||
</schemalist>
|
||||
</gconfschemafile>
|
@ -16,8 +16,9 @@
|
||||
<_summary>Uuids of extensions to enable</_summary>
|
||||
<_description>
|
||||
GNOME Shell extensions have a uuid property; this key lists extensions
|
||||
which should be loaded. disabled-extensions overrides this setting for
|
||||
extensions that appear in both lists.
|
||||
which should be loaded. Any extension that wants to be loaded needs
|
||||
to be in this list. You can also manipulate this list with the
|
||||
EnableExtension and DisableExtension DBus methods on org.gnome.Shell.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="enable-app-monitoring" type="b">
|
||||
@ -50,6 +51,14 @@
|
||||
<default>[]</default>
|
||||
<_summary>History for the looking glass dialog</_summary>
|
||||
</key>
|
||||
<key name="saved-im-presence" type="i">
|
||||
<default>1</default>
|
||||
<_summary></_summary>
|
||||
</key>
|
||||
<key name="saved-session-presence" type="i">
|
||||
<default>0</default>
|
||||
<_summary></_summary>
|
||||
</key>
|
||||
<child name="clock" schema="org.gnome.shell.clock"/>
|
||||
<child name="calendar" schema="org.gnome.shell.calendar"/>
|
||||
<child name="recorder" schema="org.gnome.shell.recorder"/>
|
||||
@ -69,13 +78,6 @@
|
||||
|
||||
<schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
<key name="show-keyboard" type="b">
|
||||
<default>false</default>
|
||||
<_summary>Show the onscreen keyboard</_summary>
|
||||
<_description>
|
||||
If true, display onscreen keyboard.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="keyboard-type" type="s">
|
||||
<default>'touch'</default>
|
||||
<_summary>Which keyboard to use</_summary>
|
||||
@ -140,4 +142,40 @@
|
||||
</_description>
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.overrides" path="/org/gnome/shell/overrides/">
|
||||
<key name="attach-modal-dialogs" type="b">
|
||||
<default>true</default>
|
||||
<summary>Attach modal dialog to the parent window</summary>
|
||||
<description>
|
||||
This key overrides the key in org.gnome.mutter when running
|
||||
GNOME Shell.
|
||||
</description>
|
||||
</key>
|
||||
|
||||
<key name="button-layout" type="s">
|
||||
<default>":close"</default>
|
||||
<summary>Arrangement of buttons on the titlebar</summary>
|
||||
<description>
|
||||
This key overrides the key in org.gnome.desktop.wm.preferences when
|
||||
running GNOME Shell.
|
||||
</description>
|
||||
</key>
|
||||
|
||||
<key name="edge-tiling" type="b">
|
||||
<default>true</default>
|
||||
<summary>Enable edge tiling when dropping windows on screen edges</summary>
|
||||
<description>
|
||||
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
||||
</description>
|
||||
</key>
|
||||
|
||||
<key name="workspaces-only-on-primary" type="b">
|
||||
<default>true</default>
|
||||
<summary>Workspaces only on primary monitor</summary>
|
||||
<description>
|
||||
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
||||
</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
|
@ -1,5 +1,5 @@
|
||||
#version 110
|
||||
uniform sampler2D sampler0;
|
||||
uniform sampler2D tex;
|
||||
uniform float fraction;
|
||||
uniform float height;
|
||||
const float c = -0.2;
|
||||
@ -12,15 +12,16 @@ mat4 contrast = mat4 (1.0 + c, 0.0, 0.0, 0.0,
|
||||
vec4 off = vec4(0.633, 0.633, 0.633, 0);
|
||||
void main()
|
||||
{
|
||||
vec4 color = texture2D(sampler0, gl_TexCoord[0].st);
|
||||
float y = height * gl_TexCoord[0][1];
|
||||
vec4 color = texture2D(tex, cogl_tex_coord_in[0].xy);
|
||||
float y = height * cogl_tex_coord_in[0].y;
|
||||
|
||||
// To reduce contrast, blend with a mid gray
|
||||
gl_FragColor = color * contrast - off * c;
|
||||
cogl_color_out = color * contrast - off * c * color.a;
|
||||
|
||||
// We only fully dim at a distance of BORDER_MAX_HEIGHT from the edge and
|
||||
// We only fully dim at a distance of BORDER_MAX_HEIGHT from the top and
|
||||
// when the fraction is 1.0. For other locations and fractions we linearly
|
||||
// interpolate back to the original undimmed color.
|
||||
gl_FragColor = color + (gl_FragColor - color) * min(y / border_max_height, 1.0);
|
||||
gl_FragColor = color + (gl_FragColor - color) * fraction;
|
||||
// interpolate back to the original undimmed color, so the top of the window
|
||||
// is at full color.
|
||||
cogl_color_out = color + (cogl_color_out - color) * max(min(y / border_max_height, 1.0), 0.0);
|
||||
cogl_color_out = color + (cogl_color_out - color) * fraction;
|
||||
}
|
||||
|
@ -30,6 +30,10 @@
|
||||
min-width: 350px;
|
||||
}
|
||||
|
||||
.login-dialog-prompt-fingerprint-message {
|
||||
font-size: 10.5pt;
|
||||
}
|
||||
|
||||
.login-dialog-user-list-view {
|
||||
-st-vfade-offset: 1em;
|
||||
}
|
||||
@ -94,8 +98,12 @@
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.login-dialog-not-listed-button:hover .login-dialog-not-listed-label {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.login-dialog-prompt-layout {
|
||||
padding-bottom: 64px;
|
||||
padding-bottom: 32px;
|
||||
}
|
||||
.login-dialog-prompt-label {
|
||||
color: white;
|
||||
@ -110,6 +118,17 @@
|
||||
background-color: white;
|
||||
caret-color: black;
|
||||
caret-size: 1px;
|
||||
width: 15em;
|
||||
}
|
||||
|
||||
.login-dialog-prompt-entry .capslock-warning {
|
||||
icon-size: 16px;
|
||||
warning-color: #999;
|
||||
}
|
||||
|
||||
.login-dialog-prompt-entry:insensitive {
|
||||
color: rgba(0,0,0,0.7);
|
||||
border: 2px solid #565656;
|
||||
}
|
||||
|
||||
.login-dialog-session-list {
|
||||
|
@ -36,18 +36,18 @@ stage {
|
||||
|
||||
StScrollBar
|
||||
{
|
||||
padding: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
StScrollView.vfade
|
||||
{
|
||||
-st-vfade-offset: 68px;
|
||||
-st-vfade-offset: 68px;
|
||||
}
|
||||
|
||||
StScrollView StScrollBar
|
||||
{
|
||||
min-width: 16px;
|
||||
min-height: 16px;
|
||||
min-width: 16px;
|
||||
min-height: 16px;
|
||||
}
|
||||
|
||||
|
||||
@ -164,6 +164,10 @@ StTooltip StLabel {
|
||||
background-color: #4c4c4c;
|
||||
}
|
||||
|
||||
.popup-menu-item:insensitive {
|
||||
color: #9f9f9f;
|
||||
}
|
||||
|
||||
.popup-image-menu-item {
|
||||
}
|
||||
|
||||
@ -276,12 +280,12 @@ StTooltip StLabel {
|
||||
background-color: black;
|
||||
border-image: url("panel-border.svg") 1;
|
||||
font-size: 10.5pt;
|
||||
font-weight: bold;
|
||||
height: 1.86em;
|
||||
}
|
||||
|
||||
#panelLeft, #panelCenter, #panelRight {
|
||||
#panelLeft, #panelCenter {
|
||||
spacing: 4px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#panelLeft:ltr {
|
||||
@ -335,7 +339,8 @@ StTooltip StLabel {
|
||||
}
|
||||
|
||||
.panel-button {
|
||||
padding: 0px 12px;
|
||||
-natural-hpadding: 12px;
|
||||
-minimum-hpadding: 6px;
|
||||
font-weight: bold;
|
||||
color: #ccc;
|
||||
transition-duration: 100;
|
||||
@ -355,9 +360,9 @@ StTooltip StLabel {
|
||||
text-shadow: black 0px 2px 2px;
|
||||
}
|
||||
|
||||
#statusTray > .panel-button:active,
|
||||
#statusTray > .panel-button:checked,
|
||||
#statusTray > .panel-button:focus {
|
||||
.panel-status-button:active,
|
||||
.panel-status-button:checked,
|
||||
.panel-status-button:focus {
|
||||
background-image: url("panel-button-highlight-narrow.svg");
|
||||
}
|
||||
|
||||
@ -371,19 +376,7 @@ StTooltip StLabel {
|
||||
-boxpointer-gap: 4px
|
||||
}
|
||||
|
||||
/* The rounded panel corners we draw don't
|
||||
* support transitions, so disable transitions
|
||||
* for the buttons at the left/right edges
|
||||
*/
|
||||
#panelActivities {
|
||||
transition-duration: 0;
|
||||
}
|
||||
|
||||
#panelStatus {
|
||||
transition-duration: 0;
|
||||
}
|
||||
|
||||
#panelStatusMenu {
|
||||
#panelUserMenu {
|
||||
spacing: 4px;
|
||||
}
|
||||
|
||||
@ -410,6 +403,7 @@ StTooltip StLabel {
|
||||
.status-chooser-user-name {
|
||||
font-weight: bold;
|
||||
font-size: 1.3em;
|
||||
min-width: 120pt;
|
||||
}
|
||||
|
||||
.status-chooser-combo {
|
||||
@ -426,24 +420,10 @@ StTooltip StLabel {
|
||||
}
|
||||
|
||||
.status-chooser-status-item,
|
||||
.status-chooser-combo > .popup-combobox-item {
|
||||
.status-chooser-combo .popup-combobox-item {
|
||||
spacing: .4em;
|
||||
}
|
||||
|
||||
#legacyTray {
|
||||
spacing: 14px;
|
||||
padding-left: 14px;
|
||||
}
|
||||
|
||||
#legacyTray:rtl {
|
||||
padding-left: 0px;
|
||||
padding-right: 14px;
|
||||
}
|
||||
|
||||
#legacyTray:compact {
|
||||
spacing: 8px;
|
||||
}
|
||||
|
||||
.system-status-icon {
|
||||
icon-size: 1.14em;
|
||||
}
|
||||
@ -529,10 +509,9 @@ StTooltip StLabel {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.dash-placeholder {
|
||||
.placeholder {
|
||||
background-image: url("dash-placeholder.svg");
|
||||
height: 27px;
|
||||
width: 48px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
#viewSelector {
|
||||
@ -764,24 +743,24 @@ StTooltip StLabel {
|
||||
}
|
||||
|
||||
.contact-icon {
|
||||
border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.contact-details {
|
||||
padding: 6px 8px 11px 8px;
|
||||
padding: 6px 8px 11px 8px;
|
||||
}
|
||||
|
||||
.contact-details-alias {
|
||||
font-size: 16px;
|
||||
padding-bottom: 11px;
|
||||
font-size: 16px;
|
||||
padding-bottom: 11px;
|
||||
}
|
||||
|
||||
.contact-details-status {
|
||||
font-size: 11pt;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
.contact-details-status-icon {
|
||||
padding-right: 2px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.contact:hover {
|
||||
@ -822,37 +801,45 @@ StTooltip StLabel {
|
||||
|
||||
#LookingGlassDialog
|
||||
{
|
||||
background-color: rgba(0,0,0,0.85);
|
||||
spacing: 4px;
|
||||
padding: 4px;
|
||||
border: 2px solid grey;
|
||||
border-radius: 4px;
|
||||
background-color: rgba(0,0,0,0.80);
|
||||
spacing: 4px;
|
||||
padding: 4px;
|
||||
border: 2px solid grey;
|
||||
border-radius: 4px;
|
||||
|
||||
color: #88ff66;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
#LookingGlassDialog > #Toolbar
|
||||
{
|
||||
border: 1px solid grey;
|
||||
border-radius: 4px;
|
||||
border: 1px solid grey;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
#LookingGlassDialog .labels {
|
||||
spacing: 4px;
|
||||
spacing: 4px;
|
||||
}
|
||||
|
||||
#LookingGlassDialog .notebook-tab {
|
||||
padding: 2px;
|
||||
-natural-hpadding: 12px;
|
||||
-minimum-hpadding: 6px;
|
||||
font-weight: bold;
|
||||
color: #ccc;
|
||||
transition-duration: 100;
|
||||
padding-left: .3em;
|
||||
padding-right: .3em;
|
||||
}
|
||||
|
||||
#LookingGlassDialog .notebook-tab:hover {
|
||||
color: #00ff00;
|
||||
color: white;
|
||||
text-shadow: black 0px 2px 2px;
|
||||
}
|
||||
|
||||
#LookingGlassDialog .notebook-tab:selected {
|
||||
border: 1px solid #88ff66;
|
||||
border-radius: 4px;
|
||||
padding: 5px;
|
||||
border-image: url("panel-button-border.svg") 10 10 0 2;
|
||||
background-image: url("panel-button-highlight-wide.svg");
|
||||
color: white;
|
||||
text-shadow: black 0px 2px 2px;
|
||||
}
|
||||
|
||||
#LookingGlassDialog .lg-inspector-title {
|
||||
@ -862,52 +849,58 @@ StTooltip StLabel {
|
||||
|
||||
.lg-dialog StLabel
|
||||
{
|
||||
color: #88ff66;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.lg-dialog StEntry
|
||||
{
|
||||
color: #88ff66;
|
||||
selection-background-color: #88ff66;
|
||||
selected-color: black;
|
||||
color: #ffffff;
|
||||
selection-background-color: #bbbbbb;
|
||||
selected-color: #333333;
|
||||
}
|
||||
|
||||
.lg-completions-text
|
||||
{
|
||||
font-size: .9em;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.lg-obj-inspector-title
|
||||
{
|
||||
spacing: 4px;
|
||||
spacing: 4px;
|
||||
}
|
||||
|
||||
.lg-obj-inspector-button
|
||||
{
|
||||
border: 1px solid #88ff66;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid gray;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.lg-obj-inspector-button:hover
|
||||
{
|
||||
border: 1px solid #00ff00;
|
||||
border: 1px solid #ffffff;
|
||||
}
|
||||
|
||||
.lg-dialog .shell-link
|
||||
{
|
||||
color: #88ff66;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.lg-dialog .shell-link:hover
|
||||
{
|
||||
color: #00ff00;
|
||||
color: #dddddd;
|
||||
}
|
||||
|
||||
#LookingGlassDialog StBoxLayout#EvalBox
|
||||
{
|
||||
padding: 4px;
|
||||
spacing: 4px;
|
||||
padding: 4px;
|
||||
spacing: 4px;
|
||||
}
|
||||
|
||||
#LookingGlassDialog StBoxLayout#ResultsArea
|
||||
{
|
||||
spacing: 4px;
|
||||
spacing: 4px;
|
||||
}
|
||||
|
||||
#lookingGlassExtensions {
|
||||
@ -929,16 +922,16 @@ StTooltip StLabel {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.lg-extension-actions {
|
||||
.lg-extension-meta {
|
||||
spacing: 6px;
|
||||
}
|
||||
|
||||
#LookingGlassPropertyInspector {
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
border: 2px solid grey;
|
||||
border-radius: 4px;
|
||||
padding: 6px;
|
||||
color: #88ff66;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Calendar popup */
|
||||
@ -951,7 +944,7 @@ StTooltip StLabel {
|
||||
.calendar-vertical-separator {
|
||||
-stipple-width: 1px;
|
||||
-stipple-color: #505050;
|
||||
width: 1.5em;
|
||||
width: 0.3em;
|
||||
}
|
||||
|
||||
#calendarPopup {
|
||||
@ -974,13 +967,14 @@ StTooltip StLabel {
|
||||
.calendar-month-label {
|
||||
color: #666666;
|
||||
font-size: 7.5pt;
|
||||
padding: 2px;
|
||||
padding-bottom: 8px;
|
||||
padding-top: 8px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.calendar-change-month-back {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
width: 18px;
|
||||
height: 12px;
|
||||
background-image: url("calendar-arrow-left.svg");
|
||||
border-radius: 4px;
|
||||
}
|
||||
@ -997,8 +991,8 @@ StTooltip StLabel {
|
||||
}
|
||||
|
||||
.calendar-change-month-forward {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
width: 18px;
|
||||
height: 12px;
|
||||
background-image: url("calendar-arrow-right.svg");
|
||||
border-radius: 4px;
|
||||
}
|
||||
@ -1030,6 +1024,7 @@ StTooltip StLabel {
|
||||
|
||||
.calendar-day-base:hover {
|
||||
background-color: #777777;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.calendar-day-base:active {
|
||||
@ -1038,6 +1033,7 @@ StTooltip StLabel {
|
||||
|
||||
.calendar-day-heading {
|
||||
color: #666666;
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
.calendar-week-number {
|
||||
@ -1100,7 +1096,8 @@ StTooltip StLabel {
|
||||
font-size: 9pt;
|
||||
font-weight: bold;
|
||||
color: rgba(153, 153, 153, 1.0);
|
||||
padding-left: 0.3em;
|
||||
padding-left: 1.8em;
|
||||
padding-top: 0.8em;
|
||||
}
|
||||
|
||||
.events-day-header:rtl {
|
||||
@ -1227,6 +1224,7 @@ StTooltip StLabel {
|
||||
|
||||
#notification-scrollview {
|
||||
max-height: 10em;
|
||||
-st-vfade-offset: 24px;
|
||||
}
|
||||
|
||||
#notification-scrollview > .top-shadow, #notification-scrollview > .bottom-shadow {
|
||||
@ -1269,7 +1267,8 @@ StTooltip StLabel {
|
||||
}
|
||||
|
||||
.notification-icon-button > StIcon {
|
||||
icon-size: 36px;
|
||||
icon-size: 16px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.hotplug-transient-box {
|
||||
@ -1339,9 +1338,8 @@ StTooltip StLabel {
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.chat-sent {
|
||||
.chat-received {
|
||||
padding-left: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.chat-received:rtl {
|
||||
@ -1351,8 +1349,7 @@ StTooltip StLabel {
|
||||
|
||||
.chat-sent {
|
||||
padding-left: 18pt;
|
||||
border-radius: 4px;
|
||||
color: #7E7E7E;
|
||||
color: #959595;
|
||||
}
|
||||
|
||||
.chat-sent:rtl {
|
||||
@ -1362,7 +1359,6 @@ StTooltip StLabel {
|
||||
|
||||
.chat-meta-message {
|
||||
padding-left: 4px;
|
||||
border-radius: 4px;
|
||||
font-size: 9pt;
|
||||
color: #bbbbbb;
|
||||
}
|
||||
@ -1917,6 +1913,7 @@ StTooltip StLabel {
|
||||
background-gradient-end: white;
|
||||
background-gradient-direction: vertical;
|
||||
color: black;
|
||||
selected-color: white;
|
||||
border-radius: 5px;
|
||||
border: 2px solid #555753;
|
||||
}
|
||||
@ -1925,6 +1922,12 @@ StTooltip StLabel {
|
||||
border: 2px solid #3465a4;
|
||||
}
|
||||
|
||||
.polkit-dialog-password-entry .capslock-warning {
|
||||
icon-size: 16px;
|
||||
warning-color: #999;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.polkit-dialog-error-label {
|
||||
font-size: 10pt;
|
||||
color: #ffff00;
|
||||
@ -1943,14 +1946,6 @@ StTooltip StLabel {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.network-dialog-show-password-checkbox {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
font-size: 10pt;
|
||||
color: white;
|
||||
spacing: 10px;
|
||||
}
|
||||
|
||||
.network-dialog-secret-table {
|
||||
spacing-rows: 15px;
|
||||
}
|
||||
|
1
docs/Makefile.am
Normal file
1
docs/Makefile.am
Normal file
@ -0,0 +1 @@
|
||||
SUBDIRS = reference
|
1
docs/reference/Makefile.am
Normal file
1
docs/reference/Makefile.am
Normal file
@ -0,0 +1 @@
|
||||
SUBDIRS = shell st
|
105
docs/reference/shell/Makefile.am
Normal file
105
docs/reference/shell/Makefile.am
Normal file
@ -0,0 +1,105 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
# We require automake 1.6 at least.
|
||||
AUTOMAKE_OPTIONS = 1.6
|
||||
|
||||
# This is a blank Makefile.am for using gtk-doc.
|
||||
# Copy this to your project's API docs directory and modify the variables to
|
||||
# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
|
||||
# of using the various options.
|
||||
|
||||
# The name of the module, e.g. 'glib'.
|
||||
DOC_MODULE=shell
|
||||
|
||||
# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
|
||||
#DOC_MODULE_VERSION=2
|
||||
|
||||
|
||||
# The top-level SGML file. You can change this if you want to.
|
||||
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
|
||||
|
||||
# Directories containing the source code, relative to $(srcdir).
|
||||
# gtk-doc will search all .c and .h files beneath these paths
|
||||
# for inline comments documenting functions and macros.
|
||||
# e.g. DOC_SOURCE_DIR=../../../gtk ../../../gdk
|
||||
DOC_SOURCE_DIR=../../../src
|
||||
|
||||
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
|
||||
SCANGOBJ_OPTIONS=
|
||||
|
||||
# Extra options to supply to gtkdoc-scan.
|
||||
# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
|
||||
SCAN_OPTIONS=--rebuild-types
|
||||
|
||||
# Extra options to supply to gtkdoc-mkdb.
|
||||
# e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
|
||||
MKDB_OPTIONS=--xml-mode --output-format=xml
|
||||
|
||||
# Extra options to supply to gtkdoc-mktmpl
|
||||
# e.g. MKTMPL_OPTIONS=--only-section-tmpl
|
||||
MKTMPL_OPTIONS=
|
||||
|
||||
# Extra options to supply to gtkdoc-mkhtml
|
||||
MKHTML_OPTIONS=
|
||||
|
||||
# Extra options to supply to gtkdoc-fixref. Not normally needed.
|
||||
# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
|
||||
FIXXREF_OPTIONS=
|
||||
|
||||
# Used for dependencies. The docs will be rebuilt if any of these change.
|
||||
# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
|
||||
# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
|
||||
HFILE_GLOB=$(top_srcdir)/src/*.h
|
||||
CFILE_GLOB=$(top_srcdir)/src/*.c
|
||||
|
||||
# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
|
||||
# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
|
||||
EXTRA_HFILES=
|
||||
|
||||
# Header files or dirs to ignore when scanning. Use base file/dir names
|
||||
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
|
||||
IGNORE_HFILES=calendar-server gvc hotplug-sniffer st tray
|
||||
|
||||
# Images to copy into HTML directory.
|
||||
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
|
||||
HTML_IMAGES=
|
||||
|
||||
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
|
||||
# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
|
||||
content_files=
|
||||
|
||||
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
|
||||
# These files must be listed here *and* in content_files
|
||||
# e.g. expand_content_files=running.sgml
|
||||
expand_content_files=
|
||||
|
||||
# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
|
||||
# Only needed if you are using gtkdoc-scangobj to dynamically query widget
|
||||
# signals and properties.
|
||||
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
|
||||
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
|
||||
GTKDOC_CFLAGS=$(GNOME_SHELL_CFLAGS)
|
||||
GTKDOC_LIBS=$(GNOME_SHELL_LIBS) $(top_builddir)/src/libgnome-shell.la
|
||||
|
||||
# This includes the standard gtk-doc make rules, copied by gtkdocize.
|
||||
include $(top_srcdir)/gtk-doc.make
|
||||
|
||||
# Other files to distribute
|
||||
# e.g. EXTRA_DIST += version.xml.in
|
||||
EXTRA_DIST +=
|
||||
|
||||
# Files not to distribute
|
||||
# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
|
||||
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
|
||||
DISTCLEANFILES = $(DOC_MODULES).types
|
||||
|
||||
# Comment this out if you want 'make check' to test you doc status
|
||||
# and run some sanity checks
|
||||
if ENABLE_GTK_DOC
|
||||
TESTS_ENVIRONMENT = cd $(srcdir) && \
|
||||
DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \
|
||||
SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir)
|
||||
#TESTS = $(GTKDOC_CHECK)
|
||||
endif
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
73
docs/reference/shell/shell-docs.sgml.in
Normal file
73
docs/reference/shell/shell-docs.sgml.in
Normal file
@ -0,0 +1,73 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
|
||||
[
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
]>
|
||||
<book id="index">
|
||||
<bookinfo>
|
||||
<title>Shell Reference Manual</title>
|
||||
<releaseinfo>
|
||||
for Shell @VERSION@.
|
||||
<!--The latest version of this documentation can be found on-line at
|
||||
<ulink role="online-location" url="http://[SERVER]/shell/index.html">http://[SERVER]/shell/</ulink>.-->
|
||||
</releaseinfo>
|
||||
</bookinfo>
|
||||
|
||||
<chapter>
|
||||
<title>Actors</title>
|
||||
<xi:include href="xml/shell-generic-container.xml"/>
|
||||
<xi:include href="xml/shell-slicer.xml"/>
|
||||
<xi:include href="xml/shell-stack.xml"/>
|
||||
</chapter>
|
||||
<chapter>
|
||||
<title>Application tracking</title>
|
||||
<xi:include href="xml/shell-app.xml"/>
|
||||
<xi:include href="xml/shell-app-usage.xml"/>
|
||||
<xi:include href="xml/shell-window-tracker.xml"/>
|
||||
</chapter>
|
||||
<chapter>
|
||||
<title>Search</title>
|
||||
<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>
|
||||
<title>Tray Icons</title>
|
||||
<xi:include href="xml/shell-embedded-window.xml"/>
|
||||
<xi:include href="xml/shell-gtk-embed.xml"/>
|
||||
<xi:include href="xml/shell-tray-icon.xml"/>
|
||||
<xi:include href="xml/shell-tray-manager.xml"/>
|
||||
</chapter>
|
||||
<chapter>
|
||||
<title>Recorder</title>
|
||||
<xi:include href="xml/shell-recorder.xml"/>
|
||||
<xi:include href="xml/shell-recorder-src.xml"/>
|
||||
</chapter>
|
||||
<chapter>
|
||||
<title>Integration helpers and utilities</title>
|
||||
<xi:include href="xml/shell-global.xml"/>
|
||||
<xi:include href="xml/shell-wm.xml"/>
|
||||
<xi:include href="xml/shell-xfixes-cursor.xml"/>
|
||||
<xi:include href="xml/shell-util.xml"/>
|
||||
<xi:include href="xml/shell-mount-operation.xml"/>
|
||||
<xi:include href="xml/shell-mobile-providers.xml"/>
|
||||
<xi:include href="xml/shell-network-agent.xml"/>
|
||||
<xi:include href="xml/shell-polkit-authentication-agent.xml"/>
|
||||
<xi:include href="xml/shell-tp-client.xml"/>
|
||||
</chapter>
|
||||
<chapter id="object-tree">
|
||||
<title>Object Hierarchy</title>
|
||||
<xi:include href="xml/tree_index.sgml"/>
|
||||
</chapter>
|
||||
<index id="api-index-full">
|
||||
<title>API Index</title>
|
||||
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="deprecated-api-index" role="deprecated">
|
||||
<title>Index of deprecated API</title>
|
||||
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
|
||||
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
|
||||
</book>
|
105
docs/reference/st/Makefile.am
Normal file
105
docs/reference/st/Makefile.am
Normal file
@ -0,0 +1,105 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
# We require automake 1.6 at least.
|
||||
AUTOMAKE_OPTIONS = 1.6
|
||||
|
||||
# This is a blank Makefile.am for using gtk-doc.
|
||||
# Copy this to your project's API docs directory and modify the variables to
|
||||
# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
|
||||
# of using the various options.
|
||||
|
||||
# The name of the module, e.g. 'glib'.
|
||||
DOC_MODULE=st
|
||||
|
||||
# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
|
||||
#DOC_MODULE_VERSION=2
|
||||
|
||||
|
||||
# The top-level SGML file. You can change this if you want to.
|
||||
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
|
||||
|
||||
# Directories containing the source code, relative to $(srcdir).
|
||||
# gtk-doc will search all .c and .h files beneath these paths
|
||||
# for inline comments documenting functions and macros.
|
||||
# e.g. DOC_SOURCE_DIR=../../../gtk ../../../gdk
|
||||
DOC_SOURCE_DIR=../../../src/st
|
||||
|
||||
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
|
||||
SCANGOBJ_OPTIONS=
|
||||
|
||||
# Extra options to supply to gtkdoc-scan.
|
||||
# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
|
||||
SCAN_OPTIONS=--rebuild-types --rebuild-sections
|
||||
|
||||
# Extra options to supply to gtkdoc-mkdb.
|
||||
# e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
|
||||
MKDB_OPTIONS=--xml-mode --output-format=xml
|
||||
|
||||
# Extra options to supply to gtkdoc-mktmpl
|
||||
# e.g. MKTMPL_OPTIONS=--only-section-tmpl
|
||||
MKTMPL_OPTIONS=
|
||||
|
||||
# Extra options to supply to gtkdoc-mkhtml
|
||||
MKHTML_OPTIONS=
|
||||
|
||||
# Extra options to supply to gtkdoc-fixref. Not normally needed.
|
||||
# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
|
||||
FIXXREF_OPTIONS=
|
||||
|
||||
# Used for dependencies. The docs will be rebuilt if any of these change.
|
||||
# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
|
||||
# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
|
||||
HFILE_GLOB=$(top_srcdir)/src/st/*.h
|
||||
CFILE_GLOB=$(top_srcdir)/src/st/*.c
|
||||
|
||||
# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
|
||||
# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
|
||||
EXTRA_HFILES=
|
||||
|
||||
# Header files or dirs to ignore when scanning. Use base file/dir names
|
||||
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
|
||||
IGNORE_HFILES=st-private.h st-theme-node-private.h
|
||||
|
||||
# Images to copy into HTML directory.
|
||||
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
|
||||
HTML_IMAGES=
|
||||
|
||||
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
|
||||
# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
|
||||
content_files=
|
||||
|
||||
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
|
||||
# These files must be listed here *and* in content_files
|
||||
# e.g. expand_content_files=running.sgml
|
||||
expand_content_files=
|
||||
|
||||
# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
|
||||
# Only needed if you are using gtkdoc-scangobj to dynamically query widget
|
||||
# signals and properties.
|
||||
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
|
||||
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
|
||||
GTKDOC_CFLAGS=
|
||||
GTKDOC_LIBS=$(top_builddir)/src/libst-1.0.la
|
||||
|
||||
# This includes the standard gtk-doc make rules, copied by gtkdocize.
|
||||
include $(top_srcdir)/gtk-doc.make
|
||||
|
||||
# Other files to distribute
|
||||
# e.g. EXTRA_DIST += version.xml.in
|
||||
EXTRA_DIST +=
|
||||
|
||||
# Files not to distribute
|
||||
# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
|
||||
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
|
||||
DISTCLEANFILES = $(DOC_MODULE).types $(DOC_MODULE)-sections.txt
|
||||
|
||||
# Comment this out if you want 'make check' to test you doc status
|
||||
# and run some sanity checks
|
||||
if ENABLE_GTK_DOC
|
||||
TESTS_ENVIRONMENT = cd $(srcdir) && \
|
||||
DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \
|
||||
SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir)
|
||||
#TESTS = $(GTKDOC_CHECK)
|
||||
endif
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
68
docs/reference/st/st-docs.sgml.in
Normal file
68
docs/reference/st/st-docs.sgml.in
Normal file
@ -0,0 +1,68 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
|
||||
[
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
]>
|
||||
<book id="index">
|
||||
<bookinfo>
|
||||
<title>St Reference Manual</title>
|
||||
<releaseinfo>
|
||||
for St @VERSION@.
|
||||
<!--The latest version of this documentation can be found on-line at
|
||||
<ulink role="online-location" url="http://[SERVER]/st/index.html">http://[SERVER]/st/</ulink>.-->
|
||||
</releaseinfo>
|
||||
</bookinfo>
|
||||
|
||||
<part>
|
||||
<title>API reference</title>
|
||||
<chapter id="base">
|
||||
<title>Abstract classes and Interfaces</title>
|
||||
<xi:include href="xml/st-widget.xml"/>
|
||||
<xi:include href="xml/st-widget-accessible.xml"/>
|
||||
<xi:include href="xml/st-container.xml"/>
|
||||
<xi:include href="xml/st-scrollable.xml"/>
|
||||
</chapter>
|
||||
<chapter id="widgets">
|
||||
<title>Widgets</title>
|
||||
<xi:include href="xml/st-button.xml"/>
|
||||
<xi:include href="xml/st-drawing-area.xml"/>
|
||||
<xi:include href="xml/st-entry.xml"/>
|
||||
<xi:include href="xml/st-icon.xml"/>
|
||||
<xi:include href="xml/st-label.xml"/>
|
||||
<xi:include href="xml/st-tooltip.xml"/>
|
||||
</chapter>
|
||||
<chapter id="containers">
|
||||
<title>Containers</title>
|
||||
<xi:include href="xml/st-bin.xml"/>
|
||||
<xi:include href="xml/st-box-layout.xml"/>
|
||||
<xi:include href="xml/st-group.xml"/>
|
||||
<xi:include href="xml/st-overflow-box.xml"/>
|
||||
<xi:include href="xml/st-scroll-view.xml"/>
|
||||
<xi:include href="xml/st-table.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="styling">
|
||||
<title>Styling</title>
|
||||
<xi:include href="xml/st-theme.xml"/>
|
||||
<xi:include href="xml/st-theme-context.xml"/>
|
||||
<xi:include href="xml/st-theme-node.xml"/>
|
||||
<xi:include href="xml/st-theme-node-transition.xml"/>
|
||||
<xi:include href="xml/st-texture-cache.xml"/>
|
||||
</chapter>
|
||||
</part>
|
||||
<chapter id="object-tree">
|
||||
<title>Object Hierarchy</title>
|
||||
<xi:include href="xml/tree_index.sgml"/>
|
||||
</chapter>
|
||||
<index id="api-index-full">
|
||||
<title>API Index</title>
|
||||
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
<index id="deprecated-api-index" role="deprecated">
|
||||
<title>Index of deprecated API</title>
|
||||
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
|
||||
</index>
|
||||
|
||||
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
|
||||
</book>
|
@ -3,13 +3,17 @@ jsdir = $(pkgdatadir)/js
|
||||
|
||||
nobase_dist_js_DATA = \
|
||||
gdm/batch.js \
|
||||
gdm/consoleKit.js \
|
||||
gdm/fingerprint.js \
|
||||
gdm/loginDialog.js \
|
||||
gdm/powerMenu.js \
|
||||
misc/config.js \
|
||||
misc/docInfo.js \
|
||||
misc/fileUtils.js \
|
||||
misc/format.js \
|
||||
misc/gnomeSession.js \
|
||||
misc/history.js \
|
||||
misc/jsParse.js \
|
||||
misc/modemManager.js \
|
||||
misc/params.js \
|
||||
misc/screenSaver.js \
|
||||
@ -43,6 +47,7 @@ nobase_dist_js_DATA = \
|
||||
ui/messageTray.js \
|
||||
ui/modalDialog.js \
|
||||
ui/networkAgent.js \
|
||||
ui/shellEntry.js \
|
||||
ui/shellMountOperation.js \
|
||||
ui/notificationDaemon.js \
|
||||
ui/overview.js \
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
*
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/*
|
||||
* Copyright 2011 Red Hat, Inc
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -21,11 +21,9 @@
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
|
||||
function Task() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
const Task = new Lang.Class({
|
||||
Name: 'Task',
|
||||
|
||||
Task.prototype = {
|
||||
_init: function(scope, handler) {
|
||||
if (scope)
|
||||
this.scope = scope;
|
||||
@ -41,22 +39,17 @@ Task.prototype = {
|
||||
|
||||
return null;
|
||||
},
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(Task.prototype);
|
||||
|
||||
function Hold() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
Hold.prototype = {
|
||||
__proto__: Task.prototype,
|
||||
const Hold = new Lang.Class({
|
||||
Name: 'Hold',
|
||||
Extends: Task,
|
||||
|
||||
_init: function() {
|
||||
Task.prototype._init.call(this,
|
||||
this,
|
||||
function () {
|
||||
return this;
|
||||
});
|
||||
this.parent(this, function () {
|
||||
return this;
|
||||
});
|
||||
|
||||
this._acquisitions = 1;
|
||||
},
|
||||
@ -88,18 +81,15 @@ Hold.prototype = {
|
||||
isAcquired: function() {
|
||||
return this._acquisitions > 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(Hold.prototype);
|
||||
|
||||
function Batch() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
Batch.prototype = {
|
||||
__proto__: Task.prototype,
|
||||
const Batch = new Lang.Class({
|
||||
Name: 'Batch',
|
||||
Extends: Task,
|
||||
|
||||
_init: function(scope, tasks) {
|
||||
Task.prototype._init.call(this);
|
||||
this.parent();
|
||||
|
||||
this.tasks = [];
|
||||
|
||||
@ -166,20 +156,12 @@ Batch.prototype = {
|
||||
cancel: function() {
|
||||
this.tasks = this.tasks.splice(0, this._currentTaskIndex + 1);
|
||||
}
|
||||
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(Batch.prototype);
|
||||
|
||||
function ConcurrentBatch() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
ConcurrentBatch.prototype = {
|
||||
__proto__: Batch.prototype,
|
||||
|
||||
_init: function(scope, tasks) {
|
||||
Batch.prototype._init.call(this, scope, tasks);
|
||||
},
|
||||
const ConcurrentBatch = new Lang.Class({
|
||||
Name: 'ConcurrentBatch',
|
||||
Extends: Batch,
|
||||
|
||||
process: function() {
|
||||
let hold = this.runTask();
|
||||
@ -193,19 +175,12 @@ ConcurrentBatch.prototype = {
|
||||
// concurrently.
|
||||
this.nextTask();
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(ConcurrentBatch.prototype);
|
||||
|
||||
function ConsecutiveBatch() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
ConsecutiveBatch.prototype = {
|
||||
__proto__: Batch.prototype,
|
||||
|
||||
_init: function(scope, tasks) {
|
||||
Batch.prototype._init.call(this, scope, tasks);
|
||||
},
|
||||
const ConsecutiveBatch = new Lang.Class({
|
||||
Name: 'ConsecutiveBatch',
|
||||
Extends: Batch,
|
||||
|
||||
process: function() {
|
||||
let hold = this.runTask();
|
||||
@ -224,5 +199,5 @@ ConsecutiveBatch.prototype = {
|
||||
this.nextTask();
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(ConsecutiveBatch.prototype);
|
||||
|
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');
|
||||
};
|
20
js/gdm/fingerprint.js
Normal file
20
js/gdm/fingerprint.js
Normal file
@ -0,0 +1,20 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const FprintManagerIface = <interface name='net.reactivated.Fprint.Manager'>
|
||||
<method name='GetDefaultDevice'>
|
||||
<arg type='o' direction='out' />
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
const FprintManagerProxy = Gio.DBusProxy.makeProxyWrapper(FprintManagerIface);
|
||||
|
||||
function FprintManager() {
|
||||
return new FprintManagerProxy(Gio.DBus.system,
|
||||
'net.reactivated.Fprint',
|
||||
'/net/reactivated/Fprint/Manager');
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
*
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/*
|
||||
* Copyright 2011 Red Hat, Inc
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -33,15 +33,24 @@ const St = imports.gi.St;
|
||||
const GdmGreeter = imports.gi.GdmGreeter;
|
||||
|
||||
const Batch = imports.gdm.batch;
|
||||
const Fprint = imports.gdm.fingerprint;
|
||||
const Lightbox = imports.ui.lightbox;
|
||||
const Main = imports.ui.main;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const _PASSWORD_SERVICE_NAME = 'gdm-password';
|
||||
const _FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
||||
const _FADE_ANIMATION_TIME = 0.16;
|
||||
const _RESIZE_ANIMATION_TIME = 0.25;
|
||||
const _SCROLL_ANIMATION_TIME = 2.0;
|
||||
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
|
||||
const _LOGO_ICON_NAME_SIZE = 48;
|
||||
|
||||
const _LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
||||
const _FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
||||
|
||||
const _LOGO_KEY = 'logo';
|
||||
|
||||
let _loginDialog = null;
|
||||
|
||||
@ -131,11 +140,9 @@ function _smoothlyResizeActor(actor, width, height) {
|
||||
return hold;
|
||||
}
|
||||
|
||||
function UserListItem(user, reason) {
|
||||
this._init(user, reason);
|
||||
}
|
||||
const UserListItem = new Lang.Class({
|
||||
Name: 'UserListItem',
|
||||
|
||||
UserListItem.prototype = {
|
||||
_init: function(user) {
|
||||
this.user = user;
|
||||
this._userChangedId = this.user.connect('changed',
|
||||
@ -246,12 +253,15 @@ UserListItem.prototype = {
|
||||
showFocusAnimation: function(time) {
|
||||
let hold = new Batch.Hold();
|
||||
|
||||
let node = this.actor.get_theme_node();
|
||||
let padding = node.get_horizontal_padding();
|
||||
|
||||
let box = this._verticalBox.get_allocation_box();
|
||||
|
||||
Tweener.removeTweens(this._focusBin);
|
||||
this._focusBin.width = 0;
|
||||
Tweener.addTween(this._focusBin,
|
||||
{ width: box.x2 - box.x1,
|
||||
{ width: (box.x2 - box.x1 - padding),
|
||||
time: time,
|
||||
transition: 'linear',
|
||||
onComplete: function() {
|
||||
@ -261,15 +271,12 @@ UserListItem.prototype = {
|
||||
});
|
||||
return hold;
|
||||
}
|
||||
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(UserListItem.prototype);
|
||||
|
||||
function UserList() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
const UserList = new Lang.Class({
|
||||
Name: 'UserList',
|
||||
|
||||
UserList.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new St.ScrollView({ style_class: 'login-dialog-user-list-view'});
|
||||
this.actor.set_policy(Gtk.PolicyType.NEVER,
|
||||
@ -284,6 +291,20 @@ UserList.prototype = {
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.MIDDLE });
|
||||
this._items = {};
|
||||
|
||||
this.actor.connect('key-focus-in', Lang.bind(this, this._moveFocusToItems));
|
||||
},
|
||||
|
||||
_moveFocusToItems: function() {
|
||||
let hasItems = Object.keys(this._items).length > 0;
|
||||
|
||||
if (!hasItems)
|
||||
return;
|
||||
|
||||
if (global.stage.get_key_focus() != this.actor)
|
||||
return;
|
||||
|
||||
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
},
|
||||
|
||||
_showItem: function(item) {
|
||||
@ -489,6 +510,8 @@ UserList.prototype = {
|
||||
item.showFocusAnimation(0);
|
||||
}));
|
||||
|
||||
this._moveFocusToItems();
|
||||
|
||||
this.emit('item-added', item);
|
||||
},
|
||||
|
||||
@ -509,14 +532,12 @@ UserList.prototype = {
|
||||
item.actor.destroy();
|
||||
delete this._items[userName];
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(UserList.prototype);
|
||||
|
||||
function SessionListItem(id, name) {
|
||||
this._init(id, name);
|
||||
}
|
||||
const SessionListItem = new Lang.Class({
|
||||
Name: 'SessionListItem',
|
||||
|
||||
SessionListItem.prototype = {
|
||||
_init: function(id, name) {
|
||||
this.id = id;
|
||||
|
||||
@ -571,17 +592,18 @@ SessionListItem.prototype = {
|
||||
_onClicked: function() {
|
||||
this.emit('activate');
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(SessionListItem.prototype);
|
||||
|
||||
function SessionList() {
|
||||
this._init();
|
||||
}
|
||||
const SessionList = new Lang.Class({
|
||||
Name: 'SessionList',
|
||||
|
||||
SessionList.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new St.BoxLayout({ style_class: 'login-dialog-session-list',
|
||||
vertical: true});
|
||||
this.actor = new St.Bin();
|
||||
|
||||
this._box = new St.BoxLayout({ style_class: 'login-dialog-session-list',
|
||||
vertical: true});
|
||||
this.actor.child = this._box;
|
||||
|
||||
this._button = new St.Button({ style_class: 'login-dialog-session-list-button',
|
||||
can_focus: true,
|
||||
@ -606,17 +628,17 @@ SessionList.prototype = {
|
||||
|
||||
this._button.connect('clicked',
|
||||
Lang.bind(this, this._onClicked));
|
||||
this.actor.add_actor(this._button,
|
||||
{ x_fill: true,
|
||||
y_fill: true,
|
||||
expand: true });
|
||||
this._box.add_actor(this._button,
|
||||
{ x_fill: true,
|
||||
y_fill: true,
|
||||
expand: true });
|
||||
this._scrollView = new St.ScrollView({ style_class: 'login-dialog-session-list-scroll-view'});
|
||||
this._scrollView.set_policy(Gtk.PolicyType.NEVER,
|
||||
Gtk.PolicyType.AUTOMATIC);
|
||||
this.actor.add_actor(this._scrollView,
|
||||
{ x_fill: true,
|
||||
y_fill: true,
|
||||
expand: true });
|
||||
this._box.add_actor(this._scrollView,
|
||||
{ x_fill: true,
|
||||
y_fill: true,
|
||||
expand: true });
|
||||
this._itemList = new St.BoxLayout({ style_class: 'login-dialog-session-item-list',
|
||||
vertical: true });
|
||||
this._scrollView.add_actor(this._itemList,
|
||||
@ -678,10 +700,13 @@ SessionList.prototype = {
|
||||
let ids = GdmGreeter.get_session_ids();
|
||||
ids.sort();
|
||||
|
||||
if (ids.length <= 1)
|
||||
this.actor.hide();
|
||||
else
|
||||
this.actor.show();
|
||||
if (ids.length <= 1) {
|
||||
this._box.hide();
|
||||
this._button.hide();
|
||||
} else {
|
||||
this._button.show();
|
||||
this._box.show();
|
||||
}
|
||||
|
||||
for (let i = 0; i < ids.length; i++) {
|
||||
let [sessionName, sessionDescription] = GdmGreeter.get_session_name_and_description(ids[i]);
|
||||
@ -703,24 +728,15 @@ SessionList.prototype = {
|
||||
}));
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(SessionList.prototype);
|
||||
|
||||
function LoginDialog() {
|
||||
if (_loginDialog == null) {
|
||||
this._init();
|
||||
_loginDialog = this;
|
||||
}
|
||||
|
||||
return _loginDialog;
|
||||
}
|
||||
|
||||
LoginDialog.prototype = {
|
||||
__proto__: ModalDialog.ModalDialog.prototype,
|
||||
const LoginDialog = new Lang.Class({
|
||||
Name: 'LoginDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
|
||||
_init: function() {
|
||||
ModalDialog.ModalDialog.prototype._init.call(this, { shellReactive: true,
|
||||
styleClass: 'login-dialog' });
|
||||
this.parent({ shellReactive: true, styleClass: 'login-dialog' });
|
||||
this.connect('destroy',
|
||||
Lang.bind(this, this._onDestroy));
|
||||
this.connect('opened',
|
||||
@ -731,7 +747,7 @@ LoginDialog.prototype = {
|
||||
|
||||
this._greeterClient.open_connection();
|
||||
|
||||
this._greeterClient.call_start_conversation('gdm-password');
|
||||
this._greeterClient.call_start_conversation(_PASSWORD_SERVICE_NAME);
|
||||
|
||||
this._greeterClient.connect('reset',
|
||||
Lang.bind(this, this._onReset));
|
||||
@ -754,8 +770,19 @@ LoginDialog.prototype = {
|
||||
this._greeterClient.connect('conversation-stopped',
|
||||
Lang.bind(this, this._onConversationStopped));
|
||||
|
||||
this._settings = new Gio.Settings({ schema: _LOGIN_SCREEN_SCHEMA });
|
||||
|
||||
this._fprintManager = new Fprint.FprintManager();
|
||||
this._startFingerprintConversationIfNeeded();
|
||||
this._settings.connect('changed::' + _LOGO_KEY,
|
||||
Lang.bind(this, this._updateLogo));
|
||||
|
||||
this._logoBox = new St.Bin({ style_class: 'login-dialog-logo-box' });
|
||||
this.contentLayout.add(this._logoBox);
|
||||
this._updateLogo();
|
||||
|
||||
this._titleLabel = new St.Label({ style_class: 'login-dialog-title',
|
||||
text: _("Sign In") });
|
||||
text: C_("title", "Sign In") });
|
||||
|
||||
this.contentLayout.add(this._titleLabel,
|
||||
{ y_fill: false,
|
||||
@ -798,6 +825,12 @@ LoginDialog.prototype = {
|
||||
x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START });
|
||||
// Translators: this message is shown below the password entry field
|
||||
// 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._promptBox.add(this._promptFingerprintMessage);
|
||||
|
||||
this._sessionList = new SessionList();
|
||||
this._sessionList.connect('session-activated',
|
||||
@ -806,13 +839,15 @@ LoginDialog.prototype = {
|
||||
}));
|
||||
|
||||
this._promptBox.add(this._sessionList.actor,
|
||||
{ expand: true,
|
||||
x_fill: true,
|
||||
y_fill: true,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START});
|
||||
{ expand: true,
|
||||
x_fill: false,
|
||||
y_fill: true,
|
||||
x_align: St.Align.START });
|
||||
this._promptBox.hide();
|
||||
|
||||
// translators: this message is shown below the user list on the
|
||||
// login screen. It can be activated to reveal an entry for
|
||||
// manually entering the username.
|
||||
let notListedLabel = new St.Label({ text: _("Not listed?"),
|
||||
style_class: 'login-dialog-not-listed-label' });
|
||||
this._notListedButton = new St.Button({ style_class: 'login-dialog-not-listed-button',
|
||||
@ -846,18 +881,51 @@ LoginDialog.prototype = {
|
||||
this._onUserListActivated(item);
|
||||
}));
|
||||
|
||||
},
|
||||
|
||||
_startFingerprintConversationIfNeeded: function() {
|
||||
this._haveFingerprintReader = false;
|
||||
|
||||
if (!this._settings.get_boolean(_FINGERPRINT_AUTHENTICATION_KEY))
|
||||
return;
|
||||
|
||||
this._fprintManager.GetDefaultDeviceRemote(Gio.DBusCallFlags.NONE, Lang.bind(this,
|
||||
function(device, error) {
|
||||
if (!error && device)
|
||||
this._haveFingerprintReader = true;
|
||||
|
||||
if (this._haveFingerprintReader)
|
||||
this._greeterClient.call_start_conversation(_FINGERPRINT_SERVICE_NAME);
|
||||
}));
|
||||
},
|
||||
|
||||
_updateLogo: function() {
|
||||
this._logoBox.child = null;
|
||||
let path = this._settings.get_string(_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);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
_onReset: function(client, serviceName) {
|
||||
this._greeterClient.call_start_conversation('gdm-password');
|
||||
this._greeterClient.call_start_conversation(_PASSWORD_SERVICE_NAME);
|
||||
this._startFingerprintConversationIfNeeded();
|
||||
|
||||
let tasks = [this._hidePrompt,
|
||||
|
||||
new Batch.ConcurrentBatch(this, [this._fadeInTitleLabel,
|
||||
this._fadeInNotListedButton]),
|
||||
this._fadeInNotListedButton,
|
||||
this._fadeInLogo]),
|
||||
|
||||
function() {
|
||||
this._sessionList.close();
|
||||
this._promptFingerprintMessage.hide();
|
||||
this._userList.actor.show();
|
||||
this._userList.actor.opacity = 255;
|
||||
return this._userList.showItems();
|
||||
@ -879,10 +947,28 @@ LoginDialog.prototype = {
|
||||
},
|
||||
|
||||
_onInfo: function(client, serviceName, info) {
|
||||
// We don't display fingerprint messages, because they
|
||||
// have words like UPEK in them. Instead we use the messages
|
||||
// as a cue to display our own message.
|
||||
if (serviceName == _FINGERPRINT_SERVICE_NAME &&
|
||||
this._haveFingerprintReader &&
|
||||
(!this._promptFingerprintMessage.visible ||
|
||||
this._promptFingerprintMessage.opacity != 255)) {
|
||||
|
||||
_fadeInActor(this._promptFingerprintMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (serviceName != _PASSWORD_SERVICE_NAME)
|
||||
return;
|
||||
Main.notifyError(info);
|
||||
},
|
||||
|
||||
_onProblem: function(client, serviceName, problem) {
|
||||
// we don't want to show auth failed messages to
|
||||
// users who haven't enrolled their fingerprint.
|
||||
if (serviceName != _PASSWORD_SERVICE_NAME)
|
||||
return;
|
||||
Main.notifyError(problem);
|
||||
},
|
||||
|
||||
@ -899,6 +985,13 @@ LoginDialog.prototype = {
|
||||
return _fadeInActor(this._promptEntry);
|
||||
},
|
||||
|
||||
function() {
|
||||
// Show it with 0 opacity so we preallocate space for it
|
||||
// in the event we need to fade in the message
|
||||
this._promptFingerprintMessage.opacity = 0;
|
||||
this._promptFingerprintMessage.show();
|
||||
},
|
||||
|
||||
function() {
|
||||
return _fadeInActor(this._promptBox);
|
||||
},
|
||||
@ -928,7 +1021,7 @@ LoginDialog.prototype = {
|
||||
{ action: Lang.bind(this, function() {
|
||||
hold.release();
|
||||
}),
|
||||
label: _("Sign In") }];
|
||||
label: C_("button", "Sign In") }];
|
||||
|
||||
this._promptEntryActivateCallbackId = this._promptEntry.clutter_text.connect('activate',
|
||||
Lang.bind(this, function() {
|
||||
@ -967,6 +1060,9 @@ LoginDialog.prototype = {
|
||||
},
|
||||
|
||||
function() {
|
||||
this._promptFingerprintMessage.hide();
|
||||
this._promptEntry.reactive = true;
|
||||
this._promptEntry.remove_style_pseudo_class('insensitive');
|
||||
this._promptEntry.set_text('');
|
||||
}];
|
||||
|
||||
@ -982,7 +1078,8 @@ LoginDialog.prototype = {
|
||||
|
||||
function() {
|
||||
let _text = this._promptEntry.get_text();
|
||||
this._promptEntry.set_text('');
|
||||
this._promptEntry.reactive = false;
|
||||
this._promptEntry.add_style_pseudo_class('insensitive');
|
||||
this._greeterClient.call_answer_query(serviceName, _text);
|
||||
}];
|
||||
|
||||
@ -990,12 +1087,20 @@ LoginDialog.prototype = {
|
||||
return batch.run();
|
||||
},
|
||||
_onInfoQuery: function(client, serviceName, question) {
|
||||
// We only expect questions to come from the main auth service
|
||||
if (serviceName != _PASSWORD_SERVICE_NAME)
|
||||
return;
|
||||
|
||||
this._promptEntry.set_text('');
|
||||
this._promptEntry.clutter_text.set_password_char('');
|
||||
this._askQuestion(serviceName, question);
|
||||
},
|
||||
|
||||
_onSecretInfoQuery: function(client, serviceName, secretQuestion) {
|
||||
// We only expect secret requests to come from the main auth service
|
||||
if (serviceName != _PASSWORD_SERVICE_NAME)
|
||||
return;
|
||||
|
||||
this._promptEntry.set_text('');
|
||||
this._promptEntry.clutter_text.set_password_char('\u25cf');
|
||||
this._askQuestion(serviceName, secretQuestion);
|
||||
@ -1132,7 +1237,14 @@ LoginDialog.prototype = {
|
||||
},
|
||||
|
||||
_onConversationStopped: function(client, serviceName) {
|
||||
this._greeterClient.call_cancel();
|
||||
// if the password service fails, then cancel everything.
|
||||
// But if, e.g., fingerprint fails, still give
|
||||
// password authentication a chance to succeed
|
||||
if (serviceName == _PASSWORD_SERVICE_NAME) {
|
||||
this._greeterClient.call_cancel();
|
||||
} else if (serviceName == _FINGERPRINT_SERVICE_NAME) {
|
||||
_fadeOutActor(this._promptFingerprintMessage);
|
||||
}
|
||||
},
|
||||
|
||||
_onNotListedClicked: function(user) {
|
||||
@ -1149,16 +1261,25 @@ LoginDialog.prototype = {
|
||||
},
|
||||
|
||||
new Batch.ConcurrentBatch(this, [this._fadeOutTitleLabel,
|
||||
this._fadeOutNotListedButton]),
|
||||
this._fadeOutNotListedButton,
|
||||
this._fadeOutLogo]),
|
||||
|
||||
function() {
|
||||
this._greeterClient.call_begin_verification('gdm-password');
|
||||
this._greeterClient.call_begin_verification(_PASSWORD_SERVICE_NAME);
|
||||
}];
|
||||
|
||||
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||
batch.run();
|
||||
},
|
||||
|
||||
_fadeInLogo: function() {
|
||||
return _fadeInActor(this._logoBox);
|
||||
},
|
||||
|
||||
_fadeOutLogo: function() {
|
||||
return _fadeOutActor(this._logoBox);
|
||||
},
|
||||
|
||||
_fadeInTitleLabel: function() {
|
||||
return _fadeInActor(this._titleLabel);
|
||||
},
|
||||
@ -1194,7 +1315,8 @@ LoginDialog.prototype = {
|
||||
},
|
||||
|
||||
new Batch.ConcurrentBatch(this, [this._fadeOutTitleLabel,
|
||||
this._fadeOutNotListedButton]),
|
||||
this._fadeOutNotListedButton,
|
||||
this._fadeOutLogo]),
|
||||
|
||||
function() {
|
||||
return this._userList.shrinkToNaturalHeight();
|
||||
@ -1202,8 +1324,11 @@ LoginDialog.prototype = {
|
||||
|
||||
function() {
|
||||
let userName = activatedItem.user.get_user_name();
|
||||
this._greeterClient.call_begin_verification_for_user('gdm-password',
|
||||
this._greeterClient.call_begin_verification_for_user(_PASSWORD_SERVICE_NAME,
|
||||
userName);
|
||||
|
||||
if (this._haveFingerprintReader)
|
||||
this._greeterClient.call_begin_verification_for_user(_FINGERPRINT_SERVICE_NAME, userName);
|
||||
}];
|
||||
|
||||
this._user = activatedItem.user;
|
||||
@ -1255,8 +1380,8 @@ LoginDialog.prototype = {
|
||||
},
|
||||
|
||||
close: function() {
|
||||
ModalDialog.ModalDialog.prototype.close.call(this);
|
||||
this.parent();
|
||||
|
||||
Main.ctrlAltTabManager.removeGroup(this._group);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
143
js/gdm/powerMenu.js
Normal file
143
js/gdm/powerMenu.js
Normal file
@ -0,0 +1,143 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/*
|
||||
* Copyright 2011 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.
|
||||
*/
|
||||
|
||||
const Lang = imports.lang;
|
||||
const UPowerGlib = imports.gi.UPowerGlib;
|
||||
|
||||
const ConsoleKit = imports.gdm.consoleKit;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
|
||||
const PowerMenuButton = new Lang.Class({
|
||||
Name: 'PowerMenuButton',
|
||||
Extends: PanelMenu.SystemStatusButton,
|
||||
|
||||
_init: function() {
|
||||
this.parent('system-shutdown', null);
|
||||
this._consoleKitManager = new ConsoleKit.ConsoleKitManager();
|
||||
this._upClient = new UPowerGlib.Client();
|
||||
|
||||
this._createSubMenu();
|
||||
|
||||
this._upClient.connect('notify::can-suspend',
|
||||
Lang.bind(this, this._updateHaveSuspend));
|
||||
this._updateHaveSuspend();
|
||||
|
||||
// ConsoleKit doesn't send notifications when shutdown/reboot
|
||||
// are disabled, so we update the menu item each time the menu opens
|
||||
this.menu.connect('open-state-changed', Lang.bind(this,
|
||||
function(menu, open) {
|
||||
if (open) {
|
||||
this._updateHaveShutdown();
|
||||
this._updateHaveRestart();
|
||||
}
|
||||
}));
|
||||
this._updateHaveShutdown();
|
||||
this._updateHaveRestart();
|
||||
},
|
||||
|
||||
_updateVisibility: function() {
|
||||
if (!this._haveSuspend && !this._haveShutdown && !this._haveRestart)
|
||||
this.actor.hide();
|
||||
else
|
||||
this.actor.show();
|
||||
},
|
||||
|
||||
_updateHaveShutdown: function() {
|
||||
this._consoleKitManager.CanStopRemote(Lang.bind(this,
|
||||
function(result, error) {
|
||||
if (!error)
|
||||
this._haveShutdown = result;
|
||||
else
|
||||
this._haveShutdown = false;
|
||||
|
||||
if (this._haveShutdown) {
|
||||
this._powerOffItem.actor.show();
|
||||
} else {
|
||||
this._powerOffItem.actor.hide();
|
||||
}
|
||||
|
||||
this._updateVisibility();
|
||||
}));
|
||||
},
|
||||
|
||||
_updateHaveRestart: function() {
|
||||
this._consoleKitManager.CanRestartRemote(Lang.bind(this,
|
||||
function(result, error) {
|
||||
if (!error)
|
||||
this._haveRestart = result;
|
||||
else
|
||||
this._haveRestart = false;
|
||||
|
||||
if (this._haveRestart) {
|
||||
this._restartItem.actor.show();
|
||||
} else {
|
||||
this._restartItem.actor.hide();
|
||||
}
|
||||
|
||||
this._updateVisibility();
|
||||
}));
|
||||
},
|
||||
|
||||
_updateHaveSuspend: function() {
|
||||
this._haveSuspend = this._upClient.get_can_suspend();
|
||||
|
||||
if (this._haveSuspend)
|
||||
this._suspendItem.actor.show();
|
||||
else
|
||||
this._suspendItem.actor.hide();
|
||||
|
||||
this._updateVisibility();
|
||||
},
|
||||
|
||||
_createSubMenu: function() {
|
||||
let item;
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Suspend"));
|
||||
item.connect('activate', Lang.bind(this, this._onActivateSuspend));
|
||||
this.menu.addMenuItem(item);
|
||||
this._suspendItem = item;
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Restart"));
|
||||
item.connect('activate', Lang.bind(this, this._onActivateRestart));
|
||||
this.menu.addMenuItem(item);
|
||||
this._restartItem = item;
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Power Off"));
|
||||
item.connect('activate', Lang.bind(this, this._onActivatePowerOff));
|
||||
this.menu.addMenuItem(item);
|
||||
this._powerOffItem = item;
|
||||
},
|
||||
|
||||
_onActivateSuspend: function() {
|
||||
if (this._haveSuspend)
|
||||
this._upClient.suspend_sync(null);
|
||||
},
|
||||
|
||||
_onActivateRestart: function() {
|
||||
if (this._haveRestart)
|
||||
this._consoleKitManager.RestartRemote();
|
||||
},
|
||||
|
||||
_onActivatePowerOff: function() {
|
||||
if (this._haveShutdown)
|
||||
this._consoleKitManager.StopRemote();
|
||||
}
|
||||
});
|
@ -1,4 +1,5 @@
|
||||
/* mode: js2; indent-tabs-mode: nil; tab-size: 4 */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
/* The name of this package (not localized) */
|
||||
const PACKAGE_NAME = '@PACKAGE_NAME@';
|
||||
/* The version of this package */
|
||||
@ -7,4 +8,5 @@ const PACKAGE_VERSION = '@PACKAGE_VERSION@';
|
||||
const GJS_VERSION = '@GJS_VERSION@';
|
||||
/* 1 if gnome-bluetooth is available, 0 otherwise */
|
||||
const HAVE_BLUETOOTH = @HAVE_BLUETOOTH@;
|
||||
|
||||
/* The system TLS CA list */
|
||||
const SHELL_SYSTEM_CA_FILE = '@SHELL_SYSTEM_CA_FILE@';
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
@ -8,11 +8,9 @@ const Search = imports.ui.search;
|
||||
|
||||
const THUMBNAIL_ICON_MARGIN = 2;
|
||||
|
||||
function DocInfo(recentInfo) {
|
||||
this._init(recentInfo);
|
||||
}
|
||||
const DocInfo = new Lang.Class({
|
||||
Name: 'DocInfo',
|
||||
|
||||
DocInfo.prototype = {
|
||||
_init : function(recentInfo) {
|
||||
this.recentInfo = recentInfo;
|
||||
// We actually used get_modified() instead of get_visited()
|
||||
@ -49,7 +47,7 @@ DocInfo.prototype = {
|
||||
}
|
||||
return mtype;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var docManagerInstance = null;
|
||||
|
||||
@ -62,11 +60,9 @@ function getDocManager() {
|
||||
/**
|
||||
* DocManager wraps the DocSystem, primarily to expose DocInfo objects.
|
||||
*/
|
||||
function DocManager() {
|
||||
this._init();
|
||||
}
|
||||
const DocManager = new Lang.Class({
|
||||
Name: 'DocManager',
|
||||
|
||||
DocManager.prototype = {
|
||||
_init: function() {
|
||||
this._docSystem = Shell.DocSystem.get_default();
|
||||
this._infosByTimestamp = [];
|
||||
@ -135,6 +131,6 @@ DocManager.prototype = {
|
||||
return this._infosByUri[url];
|
||||
})), terms);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Signals.addSignalMethods(DocManager.prototype);
|
||||
|
@ -1,3 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
|
||||
@ -20,3 +22,25 @@ function listDirAsync(file, callback) {
|
||||
enumerator.next_files_async(100, GLib.PRIORITY_LOW, null, onNextFileComplete);
|
||||
});
|
||||
}
|
||||
|
||||
function deleteGFile(file) {
|
||||
// Work around 'delete' being a keyword in JS.
|
||||
return file['delete'](null);
|
||||
}
|
||||
|
||||
function recursivelyDeleteDir(dir) {
|
||||
let children = dir.enumerate_children('standard::name,standard::type',
|
||||
Gio.FileQueryInfoFlags.NONE, null);
|
||||
|
||||
let info, child;
|
||||
while ((info = children.next_file(null)) != null) {
|
||||
let type = info.get_file_type();
|
||||
let child = dir.get_child(info.get_name());
|
||||
if (type == Gio.FileType.REGULAR)
|
||||
deleteGFile(child);
|
||||
else if (type == Gio.TypeType.DIRECTORY)
|
||||
recursivelyDeleteDir(child);
|
||||
}
|
||||
|
||||
deleteGFile(dir);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
/*
|
||||
* This function is intended to extend the String object and provide
|
||||
|
@ -1,20 +1,18 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const DBus = imports.dbus;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const PresenceIface = {
|
||||
name: 'org.gnome.SessionManager.Presence',
|
||||
methods: [{ name: 'SetStatus',
|
||||
inSignature: 'u',
|
||||
outSignature: '' }],
|
||||
properties: [{ name: 'status',
|
||||
signature: 'u',
|
||||
access: 'readwrite' }],
|
||||
signals: [{ name: 'StatusChanged',
|
||||
inSignature: 'u' }]
|
||||
};
|
||||
const PresenceIface = <interface name="org.gnome.SessionManager.Presence">
|
||||
<method name="SetStatus">
|
||||
<arg type="u" direction="in"/>
|
||||
</method>
|
||||
<property name="status" type="u" access="readwrite"/>
|
||||
<signal name="StatusChanged">
|
||||
<arg type="u" direction="out"/>
|
||||
</signal>
|
||||
</interface>;
|
||||
|
||||
const PresenceStatus = {
|
||||
AVAILABLE: 0,
|
||||
@ -23,104 +21,41 @@ const PresenceStatus = {
|
||||
IDLE: 3
|
||||
};
|
||||
|
||||
function Presence() {
|
||||
this._init();
|
||||
var PresenceProxy = Gio.DBusProxy.makeProxyWrapper(PresenceIface);
|
||||
function Presence(initCallback, cancellable) {
|
||||
return new PresenceProxy(Gio.DBus.session, 'org.gnome.SessionManager',
|
||||
'/org/gnome/SessionManager/Presence', initCallback, cancellable);
|
||||
}
|
||||
|
||||
Presence.prototype = {
|
||||
_init: function() {
|
||||
DBus.session.proxifyObject(this, 'org.gnome.SessionManager', '/org/gnome/SessionManager/Presence', this);
|
||||
},
|
||||
|
||||
getStatus: function(callback) {
|
||||
this.GetRemote('status', Lang.bind(this,
|
||||
function(status, ex) {
|
||||
if (!ex)
|
||||
callback(this, status);
|
||||
}));
|
||||
},
|
||||
|
||||
setStatus: function(status) {
|
||||
this.SetStatusRemote(status);
|
||||
}
|
||||
};
|
||||
DBus.proxifyPrototype(Presence.prototype, PresenceIface);
|
||||
|
||||
// Note inhibitors are immutable objects, so they don't
|
||||
// change at runtime (changes always come in the form
|
||||
// of new inhibitors)
|
||||
const InhibitorIface = {
|
||||
name: 'org.gnome.SessionManager.Inhibitor',
|
||||
properties: [{ name: 'app_id',
|
||||
signature: 's',
|
||||
access: 'readonly' },
|
||||
{ name: 'client_id',
|
||||
signature: 's',
|
||||
access: 'readonly' },
|
||||
{ name: 'reason',
|
||||
signature: 's',
|
||||
access: 'readonly' },
|
||||
{ name: 'flags',
|
||||
signature: 'u',
|
||||
access: 'readonly' },
|
||||
{ name: 'toplevel_xid',
|
||||
signature: 'u',
|
||||
access: 'readonly' },
|
||||
{ name: 'cookie',
|
||||
signature: 'u',
|
||||
access: 'readonly' }],
|
||||
};
|
||||
const InhibitorIface = <interface name="org.gnome.SessionManager.Inhibitor">
|
||||
<property name="app_id" type="s" access="read" />
|
||||
<property name="client_id" type="s" access="read" />
|
||||
<property name="reason" type="s" access="read" />
|
||||
<property name="flags" type="u" access="read" />
|
||||
<property name="toplevel_xid" type="u" access="read" />
|
||||
<property name="cookie" type="u" access="read" />
|
||||
</interface>;
|
||||
|
||||
function Inhibitor(objectPath) {
|
||||
this._init(objectPath);
|
||||
var InhibitorProxy = Gio.DBusProxy.makeProxyWrapper(InhibitorIface);
|
||||
function Inhibitor(objectPath, initCallback, cancellable) {
|
||||
return new InhibitorProxy(Gio.DBus.session, 'org.gnome.SessionManager', objectPath, initCallback, cancellable);
|
||||
}
|
||||
|
||||
Inhibitor.prototype = {
|
||||
_init: function(objectPath) {
|
||||
DBus.session.proxifyObject(this,
|
||||
"org.gnome.SessionManager",
|
||||
objectPath);
|
||||
this.isLoaded = false;
|
||||
this._loadingPropertiesCount = InhibitorIface.properties.length;
|
||||
for (let i = 0; i < InhibitorIface.properties.length; i++) {
|
||||
let propertyName = InhibitorIface.properties[i].name;
|
||||
this.GetRemote(propertyName, Lang.bind(this,
|
||||
function(value, exception) {
|
||||
if (exception)
|
||||
return;
|
||||
|
||||
this[propertyName] = value;
|
||||
this._loadingPropertiesCount--;
|
||||
|
||||
if (this._loadingPropertiesCount == 0) {
|
||||
this.isLoaded = true;
|
||||
this.emit("is-loaded");
|
||||
}
|
||||
}));
|
||||
}
|
||||
},
|
||||
};
|
||||
DBus.proxifyPrototype(Inhibitor.prototype, InhibitorIface);
|
||||
Signals.addSignalMethods(Inhibitor.prototype);
|
||||
|
||||
|
||||
// Not the full interface, only the methods we use
|
||||
const SessionManagerIface = {
|
||||
name: 'org.gnome.SessionManager',
|
||||
methods: [
|
||||
{ name: 'Logout', inSignature: 'u', outSignature: '' },
|
||||
{ name: 'Shutdown', inSignature: '', outSignature: '' },
|
||||
{ name: 'CanShutdown', inSignature: '', outSignature: 'b' }
|
||||
]
|
||||
};
|
||||
const SessionManagerIface = <interface name="org.gnome.SessionManager">
|
||||
<method name="Logout">
|
||||
<arg type="u" direction="in" />
|
||||
</method>
|
||||
<method name="Shutdown" />
|
||||
<method name="CanShutdown">
|
||||
<arg type="b" direction="out" />
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
function SessionManager() {
|
||||
this._init();
|
||||
var SessionManagerProxy = Gio.DBusProxy.makeProxyWrapper(SessionManagerIface);
|
||||
function SessionManager(initCallback, cancellable) {
|
||||
return new SessionManagerProxy(Gio.DBus.session, 'org.gnome.SessionManager', '/org/gnome/SessionManager', initCallback, cancellable);
|
||||
}
|
||||
|
||||
SessionManager.prototype = {
|
||||
_init: function() {
|
||||
DBus.session.proxifyObject(this, 'org.gnome.SessionManager', '/org/gnome/SessionManager');
|
||||
}
|
||||
};
|
||||
DBus.proxifyPrototype(SessionManager.prototype, SessionManagerIface);
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
@ -7,11 +7,9 @@ const Params = imports.misc.params;
|
||||
|
||||
const DEFAULT_LIMIT = 512;
|
||||
|
||||
function HistoryManager(params) {
|
||||
this._init(params);
|
||||
}
|
||||
const HistoryManager = new Lang.Class({
|
||||
Name: 'HistoryManager',
|
||||
|
||||
HistoryManager.prototype = {
|
||||
_init: function(params) {
|
||||
params = Params.parse(params, { gsettingsKey: null,
|
||||
limit: DEFAULT_LIMIT,
|
||||
@ -111,5 +109,5 @@ HistoryManager.prototype = {
|
||||
if (this._key)
|
||||
global.settings.set_strv(this._key, this._history);
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(HistoryManager.prototype);
|
||||
|
246
js/misc/jsParse.js
Normal file
246
js/misc/jsParse.js
Normal file
@ -0,0 +1,246 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
// Returns a list of potential completions for text. Completions either
|
||||
// follow a dot (e.g. foo.ba -> bar) or they are picked from globalCompletionList (e.g. fo -> foo)
|
||||
// commandHeader is prefixed on any expression before it is eval'ed. It will most likely
|
||||
// consist of global constants that might not carry over from the calling environment.
|
||||
//
|
||||
// This function is likely the one you want to call from external modules
|
||||
function getCompletions(text, commandHeader, globalCompletionList) {
|
||||
let methods = [];
|
||||
let expr, base;
|
||||
let attrHead = '';
|
||||
if (globalCompletionList == null) {
|
||||
globalCompletionList = [];
|
||||
}
|
||||
|
||||
let offset = getExpressionOffset(text, text.length - 1);
|
||||
if (offset >= 0) {
|
||||
text = text.slice(offset);
|
||||
|
||||
// Look for expressions like "Main.panel.foo" and match Main.panel and foo
|
||||
let matches = text.match(/(.*)\.(.*)/);
|
||||
if (matches) {
|
||||
[expr, base, attrHead] = matches;
|
||||
|
||||
methods = getPropertyNamesFromExpression(base, commandHeader).filter(function(attr) {
|
||||
return attr.slice(0, attrHead.length) == attrHead;
|
||||
});
|
||||
}
|
||||
|
||||
// Look for the empty expression or partially entered words
|
||||
// not proceeded by a dot and match them against global constants
|
||||
matches = text.match(/^(\w*)$/);
|
||||
if (text == '' || matches) {
|
||||
[expr, attrHead] = matches;
|
||||
methods = globalCompletionList.filter(function(attr) {
|
||||
return attr.slice(0, attrHead.length) == attrHead;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return [methods, attrHead];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// A few functions for parsing strings of javascript code.
|
||||
//
|
||||
|
||||
// Identify characters that delimit an expression. That is,
|
||||
// if we encounter anything that isn't a letter, '.', ')', or ']',
|
||||
// we should stop parsing.
|
||||
function isStopChar(c) {
|
||||
return !c.match(/[\w\.\)\]]/);
|
||||
}
|
||||
|
||||
// Given the ending position of a quoted string, find where it starts
|
||||
function findMatchingQuote(expr, offset) {
|
||||
let quoteChar = expr.charAt(offset);
|
||||
for (let i = offset - 1; i >= 0; --i) {
|
||||
if (expr.charAt(i) == quoteChar && expr.charAt(i-1) != '\\'){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Given the ending position of a regex, find where it starts
|
||||
function findMatchingSlash(expr, offset) {
|
||||
for (let i = offset - 1; i >= 0; --i) {
|
||||
if (expr.charAt(i) == '/' && expr.charAt(i-1) != '\\'){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If expr.charAt(offset) is ')' or ']',
|
||||
// return the position of the corresponding '(' or '[' bracket.
|
||||
// This function does not check for syntactic correctness. e.g.,
|
||||
// findMatchingBrace("[(])", 3) returns 1.
|
||||
function findMatchingBrace(expr, offset) {
|
||||
let closeBrace = expr.charAt(offset);
|
||||
let openBrace = ({')': '(', ']': '['})[closeBrace];
|
||||
|
||||
function findTheBrace(expr, offset) {
|
||||
if (offset < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (expr.charAt(offset) == openBrace) {
|
||||
return offset;
|
||||
}
|
||||
if (expr.charAt(offset).match(/['"]/)) {
|
||||
return findTheBrace(expr, findMatchingQuote(expr, offset) - 1);
|
||||
}
|
||||
if (expr.charAt(offset) == '/') {
|
||||
return findTheBrace(expr, findMatchingSlash(expr, offset) - 1);
|
||||
}
|
||||
if (expr.charAt(offset) == closeBrace) {
|
||||
return findTheBrace(expr, findTheBrace(expr, offset - 1) - 1);
|
||||
}
|
||||
|
||||
return findTheBrace(expr, offset - 1);
|
||||
|
||||
}
|
||||
|
||||
return findTheBrace(expr, offset - 1);
|
||||
}
|
||||
|
||||
// Walk expr backwards from offset looking for the beginning of an
|
||||
// expression suitable for passing to eval.
|
||||
// There is no guarantee of correct javascript syntax between the return
|
||||
// value and offset. This function is meant to take a string like
|
||||
// "foo(Obj.We.Are.Completing" and allow you to extract "Obj.We.Are.Completing"
|
||||
function getExpressionOffset(expr, offset) {
|
||||
while (offset >= 0) {
|
||||
let currChar = expr.charAt(offset);
|
||||
|
||||
if (isStopChar(currChar)){
|
||||
return offset + 1;
|
||||
}
|
||||
|
||||
if (currChar.match(/[\)\]]/)) {
|
||||
offset = findMatchingBrace(expr, offset);
|
||||
}
|
||||
|
||||
--offset;
|
||||
}
|
||||
|
||||
return offset + 1;
|
||||
}
|
||||
|
||||
// Things with non-word characters or that start with a number
|
||||
// are not accessible via .foo notation and so aren't returned
|
||||
function isValidPropertyName(w) {
|
||||
return !(w.match(/\W/) || w.match(/^\d/));
|
||||
}
|
||||
|
||||
// To get all properties (enumerable and not), we need to walk
|
||||
// the prototype chain ourselves
|
||||
function getAllProps(obj) {
|
||||
if (obj === null || obj === undefined) {
|
||||
return [];
|
||||
}
|
||||
return Object.getOwnPropertyNames(obj).concat( getAllProps(Object.getPrototypeOf(obj)) );
|
||||
}
|
||||
|
||||
// Given a string _expr_, returns all methods
|
||||
// that can be accessed via '.' notation.
|
||||
// e.g., expr="({ foo: null, bar: null, 4: null })" will
|
||||
// return ["foo", "bar", ...] but the list will not include "4",
|
||||
// since methods accessed with '.' notation must star with a letter or _.
|
||||
function getPropertyNamesFromExpression(expr, commandHeader) {
|
||||
if (commandHeader == null) {
|
||||
commandHeader = '';
|
||||
}
|
||||
|
||||
let obj = {};
|
||||
if (!isUnsafeExpression(expr)) {
|
||||
try {
|
||||
obj = eval(commandHeader + expr);
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
||||
let propsUnique = {};
|
||||
if (typeof obj === 'object'){
|
||||
let allProps = getAllProps(obj);
|
||||
// Get only things we are allowed to complete following a '.'
|
||||
allProps = allProps.filter( isValidPropertyName );
|
||||
|
||||
// Make sure propsUnique contains one key for every
|
||||
// property so we end up with a unique list of properties
|
||||
allProps.map(function(p){ propsUnique[p] = null; });
|
||||
}
|
||||
return Object.keys(propsUnique).sort();
|
||||
}
|
||||
|
||||
// Given a list of words, returns the longest prefix they all have in common
|
||||
function getCommonPrefix(words) {
|
||||
let word = words[0];
|
||||
for (let i = 0; i < word.length; i++) {
|
||||
for (let w = 1; w < words.length; w++) {
|
||||
if (words[w].charAt(i) != word.charAt(i))
|
||||
return word.slice(0, i);
|
||||
}
|
||||
}
|
||||
return word;
|
||||
}
|
||||
|
||||
// Returns true if there is reason to think that eval(str)
|
||||
// will modify the global scope
|
||||
function isUnsafeExpression(str) {
|
||||
// Remove any blocks that are quoted or are in a regex
|
||||
function removeLiterals(str) {
|
||||
if (str.length == 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let currChar = str.charAt(str.length - 1);
|
||||
if (currChar == '"' || currChar == '\'') {
|
||||
return removeLiterals(str.slice(0, findMatchingQuote(str, str.length - 1)));
|
||||
} else if (currChar == '/') {
|
||||
return removeLiterals(str.slice(0, findMatchingSlash(str, str.length - 1)));
|
||||
}
|
||||
|
||||
return removeLiterals(str.slice(0, str.length - 1)) + currChar;
|
||||
}
|
||||
|
||||
// Check for any sort of assignment
|
||||
// The strategy used is dumb: remove any quotes
|
||||
// or regexs and comparison operators and see if there is an '=' character.
|
||||
// If there is, it might be an unsafe assignment.
|
||||
|
||||
let prunedStr = removeLiterals(str);
|
||||
prunedStr = prunedStr.replace(/[=!]==/g, ''); //replace === and !== with nothing
|
||||
prunedStr = prunedStr.replace(/[=<>!]=/g, ''); //replace ==, <=, >=, != with nothing
|
||||
|
||||
if (prunedStr.match(/=/)) {
|
||||
return true;
|
||||
} else if (prunedStr.match(/;/)) {
|
||||
// If we contain a semicolon not inside of a quote/regex, assume we're unsafe as well
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns a list of global keywords derived from str
|
||||
function getDeclaredConstants(str) {
|
||||
let ret = [];
|
||||
str.split(';').forEach(function(s) {
|
||||
let base, keyword;
|
||||
let match = s.match(/const\s+(\w+)\s*=/);
|
||||
if (match) {
|
||||
[base, keyword] = match;
|
||||
ret.push(keyword);
|
||||
}
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const DBus = imports.dbus;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
@ -8,33 +8,43 @@ const Signals = imports.signals;
|
||||
// The following are not the complete interfaces, just the methods we need
|
||||
// (or may need in the future)
|
||||
|
||||
const ModemGsmNetworkInterface = {
|
||||
name: 'org.freedesktop.ModemManager.Modem.Gsm.Network',
|
||||
methods: [
|
||||
{ name: 'GetRegistrationInfo', inSignature: '', outSignature: 'uss' },
|
||||
{ name: 'GetSignalQuality', inSignature: '', outSignature: 'u' }
|
||||
],
|
||||
properties: [
|
||||
{ name: 'AccessTechnology', signature: 'u', access: 'read' }
|
||||
],
|
||||
signals: [
|
||||
{ name: 'SignalQuality', inSignature: 'u' },
|
||||
{ name: 'RegistrationInfo', inSignature: 'uss' }
|
||||
]
|
||||
};
|
||||
const ModemGsmNetworkProxy = DBus.makeProxyClass(ModemGsmNetworkInterface);
|
||||
const ModemGsmNetworkInterface = <interface name="org.freedesktop.ModemManager.Modem.Gsm.Network">
|
||||
<method name="GetRegistrationInfo">
|
||||
<arg type="u" direction="out" />
|
||||
<arg type="s" direction="out" />
|
||||
<arg type="s" direction="out" />
|
||||
</method>
|
||||
<method name="GetSignalQuality">
|
||||
<arg type="u" direction="out" />
|
||||
</method>
|
||||
<property name="AccessTechnology" type="u" access="read" />
|
||||
<signal name="SignalQuality">
|
||||
<arg type="u" direction="out" />
|
||||
</signal>
|
||||
<signal name="RegistrationInfo">
|
||||
<arg type="u" direction="out" />
|
||||
<arg type="s" direction="out" />
|
||||
<arg type="s" direction="out" />
|
||||
</signal>
|
||||
</interface>;
|
||||
|
||||
const ModemCdmaInterface = {
|
||||
name: 'org.freedesktop.ModemManager.Modem.Cdma',
|
||||
methods: [
|
||||
{ name: 'GetSignalQuality', inSignature: '', outSignature: 'u' },
|
||||
{ name: 'GetServingSystem', inSignature: '', outSignature: 'usu' }
|
||||
],
|
||||
signals: [
|
||||
{ name: 'SignalQuality', inSignature: 'u' }
|
||||
]
|
||||
};
|
||||
const ModemCdmaProxy = DBus.makeProxyClass(ModemCdmaInterface);
|
||||
const ModemGsmNetworkProxy = Gio.DBusProxy.makeProxyWrapper(ModemGsmNetworkInterface);
|
||||
|
||||
const ModemCdmaInterface = <interface name="org.freedesktop.ModemManager.Modem.Cdma">
|
||||
<method name="GetSignalQuality">
|
||||
<arg type="u" direction="out" />
|
||||
</method>
|
||||
<method name="GetServingSystem">
|
||||
<arg type="u" direction="out" />
|
||||
<arg type="s" direction="out" />
|
||||
<arg type="u" direction="out" />
|
||||
</method>
|
||||
<signal name="SignalQuality">
|
||||
<arg type="u" direction="out" />
|
||||
</signal>
|
||||
</interface>;
|
||||
|
||||
const ModemCdmaProxy = Gio.DBusProxy.makeProxyWrapper(ModemCdmaInterface);
|
||||
|
||||
let _providersTable;
|
||||
function _getProvidersTable() {
|
||||
@ -44,23 +54,21 @@ function _getProvidersTable() {
|
||||
return _providersTable = providers;
|
||||
}
|
||||
|
||||
function ModemGsm() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
const ModemGsm = new Lang.Class({
|
||||
Name: 'ModemGsm',
|
||||
|
||||
ModemGsm.prototype = {
|
||||
_init: function(path) {
|
||||
this._proxy = new ModemGsmNetworkProxy(DBus.system, 'org.freedesktop.ModemManager', path);
|
||||
this._proxy = new ModemGsmNetworkProxy(Gio.DBus.system, 'org.freedesktop.ModemManager', path);
|
||||
|
||||
this.signal_quality = 0;
|
||||
this.operator_name = null;
|
||||
|
||||
// Code is duplicated because the function have different signatures
|
||||
this._proxy.connect('SignalQuality', Lang.bind(this, function(proxy, quality) {
|
||||
this._proxy.connectSignal('SignalQuality', Lang.bind(this, function(proxy, sender, [quality]) {
|
||||
this.signal_quality = quality;
|
||||
this.emit('notify::signal-quality');
|
||||
}));
|
||||
this._proxy.connect('RegistrationInfo', Lang.bind(this, function(proxy, status, code, name) {
|
||||
this._proxy.connectSignal('RegistrationInfo', Lang.bind(this, function(proxy, sender, [status, code, name]) {
|
||||
this.operator_name = this._findOperatorName(name, code);
|
||||
this.emit('notify::operator-name');
|
||||
}));
|
||||
@ -146,21 +154,19 @@ ModemGsm.prototype = {
|
||||
|
||||
return name3 || name2 || null;
|
||||
}
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(ModemGsm.prototype);
|
||||
|
||||
function ModemCdma() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
const ModemCdma = new Lang.Class({
|
||||
Name: 'ModemCdma',
|
||||
|
||||
ModemCdma.prototype = {
|
||||
_init: function(path) {
|
||||
this._proxy = new ModemCdmaProxy(DBus.system, 'org.freedesktop.ModemManager', path);
|
||||
this._proxy = new ModemCdmaProxy(Gio.DBus.system, 'org.freedesktop.ModemManager', path);
|
||||
|
||||
this.signal_quality = 0;
|
||||
this.operator_name = null;
|
||||
this._proxy.connect('SignalQuality', Lang.bind(this, function(proxy, quality) {
|
||||
this.signal_quality = quality;
|
||||
this._proxy.connect('SignalQuality', Lang.bind(this, function(proxy, sender, params) {
|
||||
this.signal_quality = params[0];
|
||||
this.emit('notify::signal-quality');
|
||||
|
||||
// receiving this signal means the device got activated
|
||||
@ -221,5 +227,5 @@ ModemCdma.prototype = {
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(ModemCdma.prototype);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
// parse:
|
||||
// @params: caller-provided parameter object, or %null
|
||||
|
@ -1,53 +1,48 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const DBus = imports.dbus;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
|
||||
const ScreenSaverIface = {
|
||||
name: 'org.gnome.ScreenSaver',
|
||||
methods: [{ name: 'GetActive',
|
||||
inSignature: '',
|
||||
outSignature: 'b' },
|
||||
{ name: 'Lock',
|
||||
inSignature: '' },
|
||||
{ name: 'SetActive',
|
||||
inSignature: 'b' }],
|
||||
signals: [{ name: 'ActiveChanged',
|
||||
inSignature: 'b' }]
|
||||
};
|
||||
const ScreenSaverIface = <interface name="org.gnome.ScreenSaver">
|
||||
<method name="GetActive">
|
||||
<arg type="b" direction="out" />
|
||||
</method>
|
||||
<method name="Lock" />
|
||||
<method name="SetActive">
|
||||
<arg type="b" direction="in" />
|
||||
</method>
|
||||
<signal name="ActiveChanged">
|
||||
<arg type="b" direction="out" />
|
||||
</signal>
|
||||
</interface>;
|
||||
|
||||
const ScreenSaverInfo = Gio.DBusInterfaceInfo.new_for_xml(ScreenSaverIface);
|
||||
|
||||
function ScreenSaverProxy() {
|
||||
this._init();
|
||||
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.session,
|
||||
g_interface_name: ScreenSaverInfo.name,
|
||||
g_interface_info: ScreenSaverInfo,
|
||||
g_name: 'org.gnome.ScreenSaver',
|
||||
g_object_path: '/org/gnome/ScreenSaver',
|
||||
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
|
||||
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
||||
self.init(null);
|
||||
self.screenSaverActive = false;
|
||||
|
||||
self.connectSignal('ActiveChanged', function(proxy, senderName, [isActive]) {
|
||||
self.screenSaverActive = isActive;
|
||||
});
|
||||
self.connect('notify::g-name-owner', function() {
|
||||
if (self.g_name_owner) {
|
||||
self.GetActiveRemote(function(result, excp) {
|
||||
if (result) {
|
||||
let [isActive] = result;
|
||||
self.screenSaverActive = isActive;
|
||||
}
|
||||
});
|
||||
} else
|
||||
self.screenSaverActive = false;
|
||||
});
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
ScreenSaverProxy.prototype = {
|
||||
_init: function() {
|
||||
DBus.session.proxifyObject(this,
|
||||
'org.gnome.ScreenSaver',
|
||||
'/org/gnome/ScreenSaver');
|
||||
|
||||
DBus.session.watch_name('org.gnome.ScreenSaver',
|
||||
false, // do not launch a name-owner if none exists
|
||||
Lang.bind(this, this._onSSAppeared),
|
||||
Lang.bind(this, this._onSSVanished));
|
||||
|
||||
this.screenSaverActive = false;
|
||||
this.connect('ActiveChanged',
|
||||
Lang.bind(this, this._onActiveChanged));
|
||||
},
|
||||
|
||||
_onSSAppeared: function(owner) {
|
||||
this.GetActiveRemote(Lang.bind(this, function(isActive) {
|
||||
this.screenSaverActive = isActive;
|
||||
}))
|
||||
},
|
||||
|
||||
_onSSVanished: function(oldOwner) {
|
||||
this.screenSaverActive = false;
|
||||
},
|
||||
|
||||
_onActiveChanged: function(object, isActive) {
|
||||
this.screenSaverActive = isActive;
|
||||
}
|
||||
};
|
||||
DBus.proxifyPrototype(ScreenSaverProxy.prototype, ScreenSaverIface);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Gdk = imports.gi.Gdk;
|
||||
const Gio = imports.gi.Gio;
|
||||
@ -7,8 +7,32 @@ const Shell = imports.gi.Shell;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
|
||||
/* http://daringfireball.net/2010/07/improved_regex_for_matching_urls */
|
||||
const _urlRegexp = new RegExp('\\b(([a-z][\\w-]+:(/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)([^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:\'\\".,<>?«»“”‘’]))', 'gi');
|
||||
// http://daringfireball.net/2010/07/improved_regex_for_matching_urls
|
||||
const _balancedParens = '\\((?:[^\\s()<>]+|(?:\\(?:[^\\s()<>]+\\)))*\\)';
|
||||
const _leadingJunk = '[\\s`(\\[{\'\\"<\u00AB\u201C\u2018]';
|
||||
const _notTrailingJunk = '[^\\s`!()\\[\\]{};:\'\\".,<>?\u00AB\u00BB\u201C\u201D\u2018\u2019]';
|
||||
|
||||
const _urlRegexp = new RegExp(
|
||||
'(^|' + _leadingJunk + ')' +
|
||||
'(' +
|
||||
'(?:' +
|
||||
'[a-z][\\w-]+://' + // scheme://
|
||||
'|' +
|
||||
'www\\d{0,3}[.]' + // www.
|
||||
'|' +
|
||||
'[a-z0-9.\\-]+[.][a-z]{2,4}/' + // foo.xx/
|
||||
')' +
|
||||
'(?:' + // one or more:
|
||||
'[^\\s()<>]+' + // run of non-space non-()
|
||||
'|' + // or
|
||||
_balancedParens + // balanced parens
|
||||
')+' +
|
||||
'(?:' + // end with:
|
||||
_balancedParens + // balanced parens
|
||||
'|' + // or
|
||||
_notTrailingJunk + // last non-junk char
|
||||
')' +
|
||||
')', 'gi');
|
||||
|
||||
// findUrls:
|
||||
// @str: string to find URLs in
|
||||
@ -21,7 +45,7 @@ const _urlRegexp = new RegExp('\\b(([a-z][\\w-]+:(/{1,3}|[a-z0-9%])|www\\d{0,3}[
|
||||
function findUrls(str) {
|
||||
let res = [], match;
|
||||
while ((match = _urlRegexp.exec(str)))
|
||||
res.push({ url: match[0], pos: match.index });
|
||||
res.push({ url: match[2], pos: match.index + match[1].length });
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Scripting = imports.ui.scripting;
|
||||
|
166
js/ui/altTab.js
166
js/ui/altTab.js
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
@ -31,11 +31,21 @@ function mod(a, b) {
|
||||
return (a + b) % b;
|
||||
}
|
||||
|
||||
function AltTabPopup() {
|
||||
this._init();
|
||||
function primaryModifier(mask) {
|
||||
if (mask == 0)
|
||||
return 0;
|
||||
|
||||
let primary = 1;
|
||||
while (mask > 1) {
|
||||
mask >>= 1;
|
||||
primary <<= 1;
|
||||
}
|
||||
return primary;
|
||||
}
|
||||
|
||||
AltTabPopup.prototype = {
|
||||
const AltTabPopup = new Lang.Class({
|
||||
Name: 'AltTabPopup',
|
||||
|
||||
_init : function() {
|
||||
this.actor = new Shell.GenericContainer({ name: 'altTabPopup',
|
||||
reactive: true,
|
||||
@ -48,6 +58,7 @@ AltTabPopup.prototype = {
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
this._haveModal = false;
|
||||
this._modifierMask = 0;
|
||||
|
||||
this._currentApp = 0;
|
||||
this._currentWindow = -1;
|
||||
@ -121,16 +132,50 @@ AltTabPopup.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
show : function(backward, binding) {
|
||||
_getAppLists: function() {
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
let appSys = Shell.AppSystem.get_default();
|
||||
let apps = appSys.get_running ();
|
||||
let allApps = appSys.get_running ();
|
||||
|
||||
if (!apps.length)
|
||||
let screen = global.screen;
|
||||
let display = screen.get_display();
|
||||
let windows = display.get_tab_list(Meta.TabList.NORMAL, screen,
|
||||
screen.get_active_workspace());
|
||||
|
||||
// windows is only the windows on the current workspace. For
|
||||
// each one, if it corresponds to an app we know, move that
|
||||
// app from allApps to apps.
|
||||
let apps = [];
|
||||
for (let i = 0; i < windows.length && allApps.length != 0; i++) {
|
||||
let app = tracker.get_window_app(windows[i]);
|
||||
let index = allApps.indexOf(app);
|
||||
if (index != -1) {
|
||||
apps.push(app);
|
||||
allApps.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Now @apps is a list of apps on the current workspace, in
|
||||
// standard Alt+Tab order (MRU except for minimized windows),
|
||||
// and allApps is a list of apps that only appear on other
|
||||
// workspaces, sorted by user_time, which is good enough.
|
||||
return [apps, allApps];
|
||||
},
|
||||
|
||||
show : function(backward, binding, mask) {
|
||||
let [localApps, otherApps] = this._getAppLists();
|
||||
|
||||
if (localApps.length == 0 && otherApps.length == 0)
|
||||
return false;
|
||||
|
||||
if (!Main.pushModal(this.actor))
|
||||
return false;
|
||||
if (!Main.pushModal(this.actor)) {
|
||||
// Probably someone else has a pointer grab, try again with keyboard only
|
||||
if (!Main.pushModal(this.actor, global.get_current_time(), Meta.ModalOptions.POINTER_ALREADY_GRABBED)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this._haveModal = true;
|
||||
this._modifierMask = primaryModifier(mask);
|
||||
|
||||
this.actor.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
|
||||
this.actor.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
|
||||
@ -138,7 +183,7 @@ AltTabPopup.prototype = {
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._clickedOutside));
|
||||
this.actor.connect('scroll-event', Lang.bind(this, this._onScroll));
|
||||
|
||||
this._appSwitcher = new AppSwitcher(apps, this);
|
||||
this._appSwitcher = new AppSwitcher(localApps, otherApps, this);
|
||||
this.actor.add_actor(this._appSwitcher.actor);
|
||||
this._appSwitcher.connect('item-activated', Lang.bind(this, this._appActivated));
|
||||
this._appSwitcher.connect('item-entered', Lang.bind(this, this._appEntered));
|
||||
@ -152,7 +197,7 @@ AltTabPopup.prototype = {
|
||||
this.actor.get_allocation_box();
|
||||
|
||||
// Make the initial selection
|
||||
if (binding == 'switch_group') {
|
||||
if (binding == 'switch-group') {
|
||||
if (backward) {
|
||||
this._select(0, this._appIcons[0].cachedWindows.length - 1);
|
||||
} else {
|
||||
@ -161,9 +206,9 @@ AltTabPopup.prototype = {
|
||||
else
|
||||
this._select(0, 0);
|
||||
}
|
||||
} else if (binding == 'switch_group_backward') {
|
||||
} else if (binding == 'switch-group-backward') {
|
||||
this._select(0, this._appIcons[0].cachedWindows.length - 1);
|
||||
} else if (binding == 'switch_windows_backward') {
|
||||
} else if (binding == 'switch-windows-backward') {
|
||||
this._select(this._appIcons.length - 1);
|
||||
} else if (this._appIcons.length == 1) {
|
||||
this._select(0);
|
||||
@ -179,7 +224,7 @@ AltTabPopup.prototype = {
|
||||
// details.) So we check now. (Have to do this after updating
|
||||
// selection.)
|
||||
let [x, y, mods] = global.get_pointer();
|
||||
if (!(mods & Gdk.ModifierType.MOD1_MASK)) {
|
||||
if (!(mods & this._modifierMask)) {
|
||||
this._finish();
|
||||
return false;
|
||||
}
|
||||
@ -256,7 +301,7 @@ AltTabPopup.prototype = {
|
||||
|
||||
_keyReleaseEvent : function(actor, event) {
|
||||
let [x, y, mods] = global.get_pointer();
|
||||
let state = mods & Clutter.ModifierType.MOD1_MASK;
|
||||
let state = mods & this._modifierMask;
|
||||
|
||||
if (state == 0)
|
||||
this._finish();
|
||||
@ -493,13 +538,11 @@ AltTabPopup.prototype = {
|
||||
onComplete: Lang.bind(this, function () { this.thumbnailsVisible = true; })
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function SwitcherList(squareItems) {
|
||||
this._init(squareItems);
|
||||
}
|
||||
const SwitcherList = new Lang.Class({
|
||||
Name: 'SwitcherList',
|
||||
|
||||
SwitcherList.prototype = {
|
||||
_init : function(squareItems) {
|
||||
this.actor = new Shell.GenericContainer({ style_class: 'switcher-list' });
|
||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
@ -636,11 +679,10 @@ SwitcherList.prototype = {
|
||||
this._items[this._highlighted].add_style_pseudo_class('selected');
|
||||
}
|
||||
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
let itemSize = this._items[index].allocation.x2 - this._items[index].allocation.x1;
|
||||
let [posX, posY] = this._items[index].get_transformed_position();
|
||||
posX += this.actor.x;
|
||||
if (posX + itemSize > monitor.width + monitor.x)
|
||||
let [absItemX, absItemY] = this._items[index].get_transformed_position();
|
||||
let [result, posX, posY] = this.actor.transform_stage_point(absItemX, 0);
|
||||
let [containerWidth, containerHeight] = this.actor.get_transformed_size();
|
||||
if (posX + this._items[index].get_width() > containerWidth)
|
||||
this._scrollToRight();
|
||||
else if (posX < 0)
|
||||
this._scrollToLeft();
|
||||
@ -805,15 +847,13 @@ SwitcherList.prototype = {
|
||||
// Clip the area for scrolling
|
||||
this._clipBin.set_clip(0, -topPadding, (this.actor.allocation.x2 - this.actor.allocation.x1) - leftPadding - rightPadding, this.actor.height + bottomPadding);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Signals.addSignalMethods(SwitcherList.prototype);
|
||||
|
||||
function AppIcon(app) {
|
||||
this._init(app);
|
||||
}
|
||||
const AppIcon = new Lang.Class({
|
||||
Name: 'AppIcon',
|
||||
|
||||
AppIcon.prototype = {
|
||||
_init: function(app) {
|
||||
this.app = app;
|
||||
this.actor = new St.BoxLayout({ style_class: 'alt-tab-app',
|
||||
@ -831,35 +871,31 @@ AppIcon.prototype = {
|
||||
this._iconBin.set_size(size, size);
|
||||
this._iconBin.child = this.icon;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function AppSwitcher(apps, altTabPopup) {
|
||||
this._init(apps, altTabPopup);
|
||||
}
|
||||
const AppSwitcher = new Lang.Class({
|
||||
Name: 'AppSwitcher',
|
||||
Extends: SwitcherList,
|
||||
|
||||
AppSwitcher.prototype = {
|
||||
__proto__ : SwitcherList.prototype,
|
||||
_init : function(localApps, otherApps, altTabPopup) {
|
||||
this.parent(true);
|
||||
|
||||
_init : function(apps, altTabPopup) {
|
||||
SwitcherList.prototype._init.call(this, true);
|
||||
|
||||
// Construct the AppIcons, sort by time, add to the popup
|
||||
// Construct the AppIcons, add to the popup
|
||||
let activeWorkspace = global.screen.get_active_workspace();
|
||||
let workspaceIcons = [];
|
||||
let otherIcons = [];
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
let appIcon = new AppIcon(apps[i]);
|
||||
for (let i = 0; i < localApps.length; i++) {
|
||||
let appIcon = new AppIcon(localApps[i]);
|
||||
// Cache the window list now; we don't handle dynamic changes here,
|
||||
// and we don't want to be continually retrieving it
|
||||
appIcon.cachedWindows = appIcon.app.get_windows();
|
||||
if (this._hasWindowsOnWorkspace(appIcon, activeWorkspace))
|
||||
workspaceIcons.push(appIcon);
|
||||
else
|
||||
otherIcons.push(appIcon);
|
||||
workspaceIcons.push(appIcon);
|
||||
}
|
||||
for (let i = 0; i < otherApps.length; i++) {
|
||||
let appIcon = new AppIcon(otherApps[i]);
|
||||
appIcon.cachedWindows = appIcon.app.get_windows();
|
||||
otherIcons.push(appIcon);
|
||||
}
|
||||
|
||||
workspaceIcons.sort(Lang.bind(this, this._sortAppIcon));
|
||||
otherIcons.sort(Lang.bind(this, this._sortAppIcon));
|
||||
|
||||
this.icons = [];
|
||||
this._arrows = [];
|
||||
@ -921,7 +957,7 @@ AppSwitcher.prototype = {
|
||||
|
||||
_allocate: function (actor, box, flags) {
|
||||
// Allocate the main list items
|
||||
SwitcherList.prototype._allocate.call(this, actor, box, flags);
|
||||
this.parent(actor, box, flags);
|
||||
|
||||
let arrowHeight = Math.floor(this.actor.get_theme_node().get_padding(St.Side.BOTTOM) / 3);
|
||||
let arrowWidth = arrowHeight * 2;
|
||||
@ -976,7 +1012,7 @@ AppSwitcher.prototype = {
|
||||
this._arrows[this._curApp].remove_style_pseudo_class('highlighted');
|
||||
}
|
||||
|
||||
SwitcherList.prototype.highlight.call(this, n, justOutline);
|
||||
this.parent(n, justOutline);
|
||||
this._curApp = n;
|
||||
|
||||
if (this._curApp != -1) {
|
||||
@ -999,31 +1035,15 @@ AppSwitcher.prototype = {
|
||||
|
||||
if (appIcon.cachedWindows.length == 1)
|
||||
arrow.hide();
|
||||
},
|
||||
|
||||
_hasWindowsOnWorkspace: function(appIcon, workspace) {
|
||||
let windows = appIcon.cachedWindows;
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
if (windows[i].get_workspace() == workspace)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_sortAppIcon : function(appIcon1, appIcon2) {
|
||||
return appIcon1.app.compare(appIcon2.app);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function ThumbnailList(windows) {
|
||||
this._init(windows);
|
||||
}
|
||||
|
||||
ThumbnailList.prototype = {
|
||||
__proto__ : SwitcherList.prototype,
|
||||
const ThumbnailList = new Lang.Class({
|
||||
Name: 'ThumbnailList',
|
||||
Extends: SwitcherList,
|
||||
|
||||
_init : function(windows) {
|
||||
SwitcherList.prototype._init.call(this);
|
||||
this.parent(false);
|
||||
|
||||
let activeWorkspace = global.screen.get_active_workspace();
|
||||
|
||||
@ -1101,7 +1121,7 @@ ThumbnailList.prototype = {
|
||||
// Make sure we only do this once
|
||||
this._thumbnailBins = new Array();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function _drawArrow(area, side) {
|
||||
let themeNode = area.get_theme_node();
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
@ -26,11 +26,9 @@ const MAX_APPLICATION_WORK_MILLIS = 75;
|
||||
const MENU_POPUP_TIMEOUT = 600;
|
||||
const SCROLL_TIME = 0.1;
|
||||
|
||||
function AlphabeticalView() {
|
||||
this._init();
|
||||
}
|
||||
const AlphabeticalView = new Lang.Class({
|
||||
Name: 'AlphabeticalView',
|
||||
|
||||
AlphabeticalView.prototype = {
|
||||
_init: function() {
|
||||
this._grid = new IconGrid.IconGrid({ xAlign: St.Align.START });
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
@ -130,13 +128,11 @@ AlphabeticalView.prototype = {
|
||||
this._addApp(app);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function ViewByCategories() {
|
||||
this._init();
|
||||
}
|
||||
const ViewByCategories = new Lang.Class({
|
||||
Name: 'ViewByCategories',
|
||||
|
||||
ViewByCategories.prototype = {
|
||||
_init: function() {
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this.actor = new St.BoxLayout({ style_class: 'all-app' });
|
||||
@ -281,16 +277,14 @@ ViewByCategories.prototype = {
|
||||
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/* This class represents a display containing a collection of application items.
|
||||
* The applications are sorted based on their name.
|
||||
*/
|
||||
function AllAppDisplay() {
|
||||
this._init();
|
||||
}
|
||||
const AllAppDisplay = new Lang.Class({
|
||||
Name: 'AllAppDisplay',
|
||||
|
||||
AllAppDisplay.prototype = {
|
||||
_init: function() {
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this._appSystem.connect('installed-changed', Lang.bind(this, function() {
|
||||
@ -306,17 +300,15 @@ AllAppDisplay.prototype = {
|
||||
_redisplay: function() {
|
||||
this._appView.refresh();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function AppSearchProvider() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
AppSearchProvider.prototype = {
|
||||
__proto__: Search.SearchProvider.prototype,
|
||||
const AppSearchProvider = new Lang.Class({
|
||||
Name: 'AppSearchProvider',
|
||||
Extends: Search.SearchProvider,
|
||||
|
||||
_init: function() {
|
||||
Search.SearchProvider.prototype._init.call(this, _("APPLICATIONS"));
|
||||
this.parent(_("APPLICATIONS"));
|
||||
|
||||
this._appSys = Shell.AppSystem.get_default();
|
||||
},
|
||||
|
||||
@ -364,17 +356,15 @@ AppSearchProvider.prototype = {
|
||||
let icon = new AppWellIcon(app);
|
||||
return icon.actor;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function SettingsSearchProvider() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
SettingsSearchProvider.prototype = {
|
||||
__proto__: Search.SearchProvider.prototype,
|
||||
const SettingsSearchProvider = new Lang.Class({
|
||||
Name: 'SettingsSearchProvider',
|
||||
Extends: Search.SearchProvider,
|
||||
|
||||
_init: function() {
|
||||
Search.SearchProvider.prototype._init.call(this, _("SETTINGS"));
|
||||
this.parent(_("SETTINGS"));
|
||||
|
||||
this._appSys = Shell.AppSystem.get_default();
|
||||
this._gnomecc = this._appSys.lookup_app('gnome-control-center.desktop');
|
||||
},
|
||||
@ -412,35 +402,28 @@ SettingsSearchProvider.prototype = {
|
||||
let icon = new AppWellIcon(app);
|
||||
return icon.actor;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function AppIcon(app, params) {
|
||||
this._init(app, params);
|
||||
}
|
||||
|
||||
AppIcon.prototype = {
|
||||
__proto__: IconGrid.BaseIcon.prototype,
|
||||
const AppIcon = new Lang.Class({
|
||||
Name: 'AppIcon',
|
||||
Extends: IconGrid.BaseIcon,
|
||||
|
||||
_init : function(app, params) {
|
||||
this.app = app;
|
||||
|
||||
let label = this.app.get_name();
|
||||
|
||||
IconGrid.BaseIcon.prototype._init.call(this,
|
||||
label,
|
||||
params);
|
||||
this.parent(label, params);
|
||||
},
|
||||
|
||||
createIcon: function(iconSize) {
|
||||
return this.app.create_icon_texture(iconSize);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function AppWellIcon(app, iconParams, onActivateOverride) {
|
||||
this._init(app, iconParams, onActivateOverride);
|
||||
}
|
||||
const AppWellIcon = new Lang.Class({
|
||||
Name: 'AppWellIcon',
|
||||
|
||||
AppWellIcon.prototype = {
|
||||
_init : function(app, iconParams, onActivateOverride) {
|
||||
this.app = app;
|
||||
this.actor = new St.Button({ style_class: 'app-well-app',
|
||||
@ -559,7 +542,7 @@ AppWellIcon.prototype = {
|
||||
this._menu.connect('activate-window', Lang.bind(this, function (menu, window) {
|
||||
this.activateWindow(window);
|
||||
}));
|
||||
this._menu.connect('popup', Lang.bind(this, function (menu, isPoppedUp) {
|
||||
this._menu.connect('open-state-changed', Lang.bind(this, function (menu, isPoppedUp) {
|
||||
if (!isPoppedUp)
|
||||
this._onMenuPoppedDown();
|
||||
}));
|
||||
@ -620,22 +603,19 @@ AppWellIcon.prototype = {
|
||||
getDragActorSource: function() {
|
||||
return this.icon.icon;
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(AppWellIcon.prototype);
|
||||
|
||||
function AppIconMenu(source) {
|
||||
this._init(source);
|
||||
}
|
||||
|
||||
AppIconMenu.prototype = {
|
||||
__proto__: PopupMenu.PopupMenu.prototype,
|
||||
const AppIconMenu = new Lang.Class({
|
||||
Name: 'AppIconMenu',
|
||||
Extends: PopupMenu.PopupMenu,
|
||||
|
||||
_init: function(source) {
|
||||
let side = St.Side.LEFT;
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||
side = St.Side.RIGHT;
|
||||
|
||||
PopupMenu.PopupMenu.prototype._init.call(this, source.actor, 0.5, side);
|
||||
this.parent(source.actor, 0.5, side);
|
||||
|
||||
// We want to keep the item hovered while the menu is up
|
||||
this.blockSourceEvents = true;
|
||||
@ -643,7 +623,6 @@ AppIconMenu.prototype = {
|
||||
this._source = source;
|
||||
|
||||
this.connect('activate', Lang.bind(this, this._onActivate));
|
||||
this.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
|
||||
|
||||
this.actor.add_style_class_name('app-well-menu');
|
||||
|
||||
@ -707,14 +686,6 @@ AppIconMenu.prototype = {
|
||||
this.open();
|
||||
},
|
||||
|
||||
_onOpenStateChanged: function (menu, open) {
|
||||
if (open) {
|
||||
this.emit('popup', true);
|
||||
} else {
|
||||
this.emit('popup', false);
|
||||
}
|
||||
},
|
||||
|
||||
_onActivate: function (actor, child) {
|
||||
if (child._window) {
|
||||
let metaWindow = child._window;
|
||||
@ -732,5 +703,5 @@ AppIconMenu.prototype = {
|
||||
}
|
||||
this.close();
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(AppIconMenu.prototype);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Shell = imports.gi.Shell;
|
||||
const Lang = imports.lang;
|
||||
@ -6,11 +6,9 @@ const Signals = imports.signals;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
|
||||
function AppFavorites() {
|
||||
this._init();
|
||||
}
|
||||
const AppFavorites = new Lang.Class({
|
||||
Name: 'AppFavorites',
|
||||
|
||||
AppFavorites.prototype = {
|
||||
FAVORITE_APPS_KEY: 'favorite-apps',
|
||||
|
||||
_init: function() {
|
||||
@ -122,7 +120,7 @@ AppFavorites.prototype = {
|
||||
this._addFavorite(appId, pos);
|
||||
}));
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(AppFavorites.prototype);
|
||||
|
||||
var appFavoritesInstance = null;
|
||||
|
@ -1,7 +1,6 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Lang = imports.lang;
|
||||
const DBus = imports.dbus;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Params = imports.misc.params;
|
||||
@ -16,69 +15,58 @@ const SETTING_ENABLE_AUTOMOUNT = 'automount';
|
||||
|
||||
const AUTORUN_EXPIRE_TIMEOUT_SECS = 10;
|
||||
|
||||
const ConsoleKitSessionIface = {
|
||||
name: 'org.freedesktop.ConsoleKit.Session',
|
||||
methods: [{ name: 'IsActive',
|
||||
inSignature: '',
|
||||
outSignature: 'b' }],
|
||||
signals: [{ name: 'ActiveChanged',
|
||||
inSignature: 'b' }]
|
||||
};
|
||||
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 = DBus.makeProxyClass(ConsoleKitSessionIface);
|
||||
const ConsoleKitSessionProxy = Gio.DBusProxy.makeProxyWrapper(ConsoleKitSessionIface);
|
||||
|
||||
const ConsoleKitManagerIface = {
|
||||
name: 'org.freedesktop.ConsoleKit.Manager',
|
||||
methods: [{ name: 'GetCurrentSession',
|
||||
inSignature: '',
|
||||
outSignature: 'o' }]
|
||||
};
|
||||
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() {
|
||||
this._init();
|
||||
};
|
||||
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) });
|
||||
|
||||
ConsoleKitManager.prototype = {
|
||||
_init: function() {
|
||||
this.sessionActive = true;
|
||||
self.connect('notify::g-name-owner', function() {
|
||||
if (self.g_name_owner) {
|
||||
self.GetCurrentSessionRemote(function([session]) {
|
||||
self._ckSession = new ConsoleKitSessionProxy(Gio.DBus.system, 'org.freedesktop.ConsoleKit', session);
|
||||
|
||||
DBus.system.proxifyObject(this,
|
||||
'org.freedesktop.ConsoleKit',
|
||||
'/org/freedesktop/ConsoleKit/Manager');
|
||||
self._ckSession.connectSignal('ActiveChanged', function(object, senderName, [isActive]) {
|
||||
self.sessionActive = isActive;
|
||||
});
|
||||
self._ckSession.IsActiveRemote(function([isActive]) {
|
||||
self.sessionActive = isActive;
|
||||
});
|
||||
});
|
||||
} else {
|
||||
self.sessionActive = true;
|
||||
}
|
||||
});
|
||||
|
||||
DBus.system.watch_name('org.freedesktop.ConsoleKit',
|
||||
false, // do not launch a name-owner if none exists
|
||||
Lang.bind(this, this._onManagerAppeared),
|
||||
Lang.bind(this, this._onManagerVanished));
|
||||
},
|
||||
|
||||
_onManagerAppeared: function(owner) {
|
||||
this.GetCurrentSessionRemote(Lang.bind(this, this._onCurrentSession));
|
||||
},
|
||||
|
||||
_onManagerVanished: function(oldOwner) {
|
||||
this.sessionActive = true;
|
||||
},
|
||||
|
||||
_onCurrentSession: function(session) {
|
||||
this._ckSession = new ConsoleKitSessionProxy(DBus.system, 'org.freedesktop.ConsoleKit', session);
|
||||
|
||||
this._ckSession.connect
|
||||
('ActiveChanged', Lang.bind(this, function(object, isActive) {
|
||||
this.sessionActive = isActive;
|
||||
}));
|
||||
this._ckSession.IsActiveRemote(Lang.bind(this, function(isActive) {
|
||||
this.sessionActive = isActive;
|
||||
}));
|
||||
}
|
||||
};
|
||||
DBus.proxifyPrototype(ConsoleKitManager.prototype, ConsoleKitManagerIface);
|
||||
|
||||
function AutomountManager() {
|
||||
this._init();
|
||||
self.init(null);
|
||||
return self;
|
||||
}
|
||||
|
||||
AutomountManager.prototype = {
|
||||
const AutomountManager = new Lang.Class({
|
||||
Name: 'AutomountManager',
|
||||
|
||||
_init: function() {
|
||||
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
||||
this._volumeQueue = [];
|
||||
@ -86,9 +74,8 @@ AutomountManager.prototype = {
|
||||
this.ckListener = new ConsoleKitManager();
|
||||
|
||||
this._ssProxy = new ScreenSaver.ScreenSaverProxy();
|
||||
this._ssProxy.connect('ActiveChanged',
|
||||
Lang.bind(this,
|
||||
this._screenSaverActiveChanged));
|
||||
this._ssProxy.connectSignal('ActiveChanged',
|
||||
Lang.bind(this, this._screenSaverActiveChanged));
|
||||
|
||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||
|
||||
@ -111,7 +98,7 @@ AutomountManager.prototype = {
|
||||
Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
|
||||
},
|
||||
|
||||
_screenSaverActiveChanged: function(object, isActive) {
|
||||
_screenSaverActiveChanged: function(object, senderName, [isActive]) {
|
||||
if (!isActive) {
|
||||
this._volumeQueue.forEach(Lang.bind(this, function(volume) {
|
||||
this._checkAndMountVolume(volume);
|
||||
@ -209,10 +196,14 @@ AutomountManager.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
// Volume is already mounted, don't bother.
|
||||
if (volume.get_mount())
|
||||
return;
|
||||
|
||||
if (!this._settings.get_boolean(SETTING_ENABLE_AUTOMOUNT) ||
|
||||
!volume.should_automount() ||
|
||||
!volume.can_mount()) {
|
||||
// allow the autorun to run anyway; this can happen if the
|
||||
// allow the autorun to run anyway; this can happen if the
|
||||
// mount gets added programmatically later, even if
|
||||
// should_automount() or can_mount() are false, like for
|
||||
// blank optical media.
|
||||
@ -275,4 +266,4 @@ AutomountManager.prototype = {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,7 +1,6 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Lang = imports.lang;
|
||||
const DBus = imports.dbus;
|
||||
const Gio = imports.gi.Gio;
|
||||
const St = imports.gi.St;
|
||||
|
||||
@ -23,8 +22,6 @@ const AutorunSetting = {
|
||||
ASK: 3
|
||||
};
|
||||
|
||||
const HOTPLUG_ICON_SIZE = 16;
|
||||
|
||||
// misc utils
|
||||
function ignoreAutorunForMount(mount) {
|
||||
let root = mount.get_root();
|
||||
@ -64,31 +61,23 @@ function startAppForMount(app, mount) {
|
||||
|
||||
/******************************************/
|
||||
|
||||
const HotplugSnifferIface = {
|
||||
name: 'org.gnome.Shell.HotplugSniffer',
|
||||
methods: [{ name: 'SniffURI',
|
||||
inSignature: 's',
|
||||
outSignature: 'as' }]
|
||||
};
|
||||
const HotplugSnifferIface = <interface name="org.gnome.Shell.HotplugSniffer">
|
||||
<method name="SniffURI">
|
||||
<arg type="s" direction="in" />
|
||||
<arg type="as" direction="out" />
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
const HotplugSniffer = function() {
|
||||
this._init();
|
||||
};
|
||||
|
||||
HotplugSniffer.prototype = {
|
||||
_init: function() {
|
||||
DBus.session.proxifyObject(this,
|
||||
const HotplugSnifferProxy = Gio.DBusProxy.makeProxyWrapper(HotplugSnifferIface);
|
||||
function HotplugSniffer() {
|
||||
return new HotplugSnifferProxy(Gio.DBus.session,
|
||||
'org.gnome.Shell.HotplugSniffer',
|
||||
'/org/gnome/Shell/HotplugSniffer');
|
||||
},
|
||||
};
|
||||
DBus.proxifyPrototype(HotplugSniffer.prototype, HotplugSnifferIface);
|
||||
|
||||
function ContentTypeDiscoverer(callback) {
|
||||
this._init(callback);
|
||||
}
|
||||
|
||||
ContentTypeDiscoverer.prototype = {
|
||||
const ContentTypeDiscoverer = new Lang.Class({
|
||||
Name: 'ContentTypeDiscoverer',
|
||||
|
||||
_init: function(callback) {
|
||||
this._callback = callback;
|
||||
},
|
||||
@ -116,9 +105,8 @@ ContentTypeDiscoverer.prototype = {
|
||||
let root = mount.get_root();
|
||||
|
||||
let hotplugSniffer = new HotplugSniffer();
|
||||
hotplugSniffer.SniffURIRemote
|
||||
(root.get_uri(), DBus.CALL_FLAG_START,
|
||||
Lang.bind(this, function(contentTypes) {
|
||||
hotplugSniffer.SniffURIRemote(root.get_uri(),
|
||||
Lang.bind(this, function([contentTypes]) {
|
||||
this._emitCallback(mount, contentTypes);
|
||||
}));
|
||||
}
|
||||
@ -146,13 +134,11 @@ ContentTypeDiscoverer.prototype = {
|
||||
|
||||
this._callback(mount, apps, contentTypes);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function AutorunManager() {
|
||||
this._init();
|
||||
}
|
||||
const AutorunManager = new Lang.Class({
|
||||
Name: 'AutorunManager',
|
||||
|
||||
AutorunManager.prototype = {
|
||||
_init: function() {
|
||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||
|
||||
@ -269,22 +255,19 @@ AutorunManager.prototype = {
|
||||
+ ': ' + e.toString());
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
function AutorunResidentSource() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
AutorunResidentSource.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
const AutorunResidentSource = new Lang.Class({
|
||||
Name: 'AutorunResidentSource',
|
||||
Extends: MessageTray.Source,
|
||||
|
||||
_init: function() {
|
||||
MessageTray.Source.prototype._init.call(this, _('Removable Devices'));
|
||||
this.parent(_("Removable Devices"));
|
||||
|
||||
this._mounts = [];
|
||||
|
||||
this._notification = new AutorunResidentNotification(this);
|
||||
this._setSummaryIcon(this.createNotificationIcon(HOTPLUG_ICON_SIZE));
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
},
|
||||
|
||||
addMount: function(mount, apps) {
|
||||
@ -329,24 +312,19 @@ AutorunResidentSource.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
createNotificationIcon: function(iconSize) {
|
||||
createNotificationIcon: function() {
|
||||
return new St.Icon ({ icon_name: 'media-removable',
|
||||
icon_type: St.IconType.FULLCOLOR,
|
||||
icon_size: iconSize ? iconSize : this.ICON_SIZE });
|
||||
icon_size: this.ICON_SIZE });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function AutorunResidentNotification(source) {
|
||||
this._init(source);
|
||||
}
|
||||
|
||||
AutorunResidentNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
const AutorunResidentNotification = new Lang.Class({
|
||||
Name: 'AutorunResidentNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source) {
|
||||
MessageTray.Notification.prototype._init.call(this, source,
|
||||
source.title, null,
|
||||
{ customContent: true });
|
||||
this.parent(source, source.title, null, { customContent: true });
|
||||
|
||||
// set the notification as resident
|
||||
this.setResident(true);
|
||||
@ -420,13 +398,11 @@ AutorunResidentNotification.prototype = {
|
||||
|
||||
return item;
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
function AutorunTransientDispatcher() {
|
||||
this._init();
|
||||
}
|
||||
const AutorunTransientDispatcher = new Lang.Class({
|
||||
Name: 'AutorunTransientDispatcher',
|
||||
|
||||
AutorunTransientDispatcher.prototype = {
|
||||
_init: function() {
|
||||
this._sources = [];
|
||||
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
||||
@ -493,7 +469,7 @@ AutorunTransientDispatcher.prototype = {
|
||||
let app = null;
|
||||
|
||||
if (setting == AutorunSetting.RUN) {
|
||||
app = Gio.app_info_get_default_for_type(type, false);
|
||||
app = Gio.app_info_get_default_for_type(contentTypes[0], false);
|
||||
} else if (setting == AutorunSetting.FILES) {
|
||||
app = Gio.app_info_get_default_for_type('inode/directory', false);
|
||||
}
|
||||
@ -517,46 +493,38 @@ AutorunTransientDispatcher.prototype = {
|
||||
// destroy the notification source
|
||||
source.destroy();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function AutorunTransientSource(mount, apps) {
|
||||
this._init(mount, apps);
|
||||
}
|
||||
|
||||
AutorunTransientSource.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
const AutorunTransientSource = new Lang.Class({
|
||||
Name: 'AutorunTransientSource',
|
||||
Extends: MessageTray.Source,
|
||||
|
||||
_init: function(mount, apps) {
|
||||
MessageTray.Source.prototype._init.call(this, mount.get_name());
|
||||
this.parent(mount.get_name());
|
||||
|
||||
this.mount = mount;
|
||||
this.apps = apps;
|
||||
|
||||
this._notification = new AutorunTransientNotification(this);
|
||||
this._setSummaryIcon(this.createNotificationIcon(this.ICON_SIZE));
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
|
||||
// add ourselves as a source, and popup the notification
|
||||
Main.messageTray.add(this);
|
||||
this.notify(this._notification);
|
||||
},
|
||||
|
||||
createNotificationIcon: function(iconSize) {
|
||||
createNotificationIcon: function() {
|
||||
return new St.Icon({ gicon: this.mount.get_icon(),
|
||||
icon_size: iconSize ? iconSize : this.ICON_SIZE });
|
||||
icon_size: this.ICON_SIZE });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function AutorunTransientNotification(source) {
|
||||
this._init(source);
|
||||
}
|
||||
|
||||
AutorunTransientNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
const AutorunTransientNotification = new Lang.Class({
|
||||
Name: 'AutorunTransientNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source) {
|
||||
MessageTray.Notification.prototype._init.call(this, source,
|
||||
source.title, null,
|
||||
{ customContent: true });
|
||||
this.parent(source, source.title, null, { customContent: true });
|
||||
|
||||
this._box = new St.BoxLayout({ style_class: 'hotplug-transient-box',
|
||||
vertical: true });
|
||||
@ -631,5 +599,5 @@ AutorunTransientNotification.prototype = {
|
||||
|
||||
return button;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
@ -21,11 +21,9 @@ const POPUP_ANIMATION_TIME = 0.15;
|
||||
* placed. The arrow position may be controlled via setArrowOrigin().
|
||||
*
|
||||
*/
|
||||
function BoxPointer(side, binProperties) {
|
||||
this._init(side, binProperties);
|
||||
}
|
||||
const BoxPointer = new Lang.Class({
|
||||
Name: 'BoxPointer',
|
||||
|
||||
BoxPointer.prototype = {
|
||||
_init: function(arrowSide, binProperties) {
|
||||
this._arrowSide = arrowSide;
|
||||
this._arrowOrigin = 0;
|
||||
@ -46,6 +44,7 @@ BoxPointer.prototype = {
|
||||
this._yOffset = 0;
|
||||
this._xPosition = 0;
|
||||
this._yPosition = 0;
|
||||
this._sourceAlignment = 0.5;
|
||||
},
|
||||
|
||||
show: function(animate, onComplete) {
|
||||
@ -75,7 +74,7 @@ BoxPointer.prototype = {
|
||||
Tweener.addTween(this, { opacity: 255,
|
||||
xOffset: 0,
|
||||
yOffset: 0,
|
||||
transition: "linear",
|
||||
transition: 'linear',
|
||||
onComplete: onComplete,
|
||||
time: POPUP_ANIMATION_TIME });
|
||||
},
|
||||
@ -106,7 +105,7 @@ BoxPointer.prototype = {
|
||||
Tweener.addTween(this, { opacity: 0,
|
||||
xOffset: xOffset,
|
||||
yOffset: yOffset,
|
||||
transition: "linear",
|
||||
transition: 'linear',
|
||||
time: POPUP_ANIMATION_TIME,
|
||||
onComplete: Lang.bind(this, function () {
|
||||
this.actor.hide();
|
||||
@ -180,7 +179,7 @@ BoxPointer.prototype = {
|
||||
this.bin.allocate(childBox, flags);
|
||||
|
||||
if (this._sourceActor && this._sourceActor.mapped)
|
||||
this._reposition(this._sourceActor, this._alignment);
|
||||
this._reposition(this._sourceActor, this._arrowAlignment);
|
||||
},
|
||||
|
||||
_drawBorder: function(area) {
|
||||
@ -312,24 +311,37 @@ BoxPointer.prototype = {
|
||||
this.actor.show();
|
||||
|
||||
this._sourceActor = sourceActor;
|
||||
this._alignment = alignment;
|
||||
this._arrowAlignment = alignment;
|
||||
|
||||
this._reposition(sourceActor, alignment);
|
||||
},
|
||||
|
||||
setSourceAlignment: function(alignment) {
|
||||
this._sourceAlignment = alignment;
|
||||
|
||||
if (!this._sourceActor)
|
||||
return;
|
||||
|
||||
// We need to show it now to force an allocation,
|
||||
// so that we can query the correct size.
|
||||
this.actor.show();
|
||||
|
||||
this._reposition(this._sourceActor, this._arrowAlignment);
|
||||
},
|
||||
|
||||
_reposition: function(sourceActor, alignment) {
|
||||
// Position correctly relative to the sourceActor
|
||||
let sourceNode = sourceActor.get_theme_node();
|
||||
let sourceContentBox = sourceNode.get_content_box(sourceActor.get_allocation_box());
|
||||
let sourceAllocation = Shell.util_get_transformed_allocation(sourceActor);
|
||||
let sourceCenterX = sourceAllocation.x1 + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) / 2;
|
||||
let sourceCenterY = sourceAllocation.y1 + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) / 2;
|
||||
let sourceCenterX = sourceAllocation.x1 + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * this._sourceAlignment;
|
||||
let sourceCenterY = sourceAllocation.y1 + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) * this._sourceAlignment;
|
||||
let [minWidth, minHeight, natWidth, natHeight] = this.actor.get_preferred_size();
|
||||
|
||||
// We also want to keep it onscreen, and separated from the
|
||||
// edge by the same distance as the main part of the box is
|
||||
// separated from its sourceActor
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
let monitor = Main.layoutManager.findMonitorForActor(sourceActor);
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
let borderWidth = themeNode.get_length('-arrow-border-width');
|
||||
let arrowBase = themeNode.get_length('-arrow-base');
|
||||
@ -364,8 +376,8 @@ BoxPointer.prototype = {
|
||||
case St.Side.BOTTOM:
|
||||
resX = sourceCenterX - (halfMargin + (natWidth - margin) * alignment);
|
||||
|
||||
resX = Math.max(resX, primary.x + 10);
|
||||
resX = Math.min(resX, primary.x + primary.width - (10 + natWidth));
|
||||
resX = Math.max(resX, monitor.x + 10);
|
||||
resX = Math.min(resX, monitor.x + monitor.width - (10 + natWidth));
|
||||
this.setArrowOrigin(sourceCenterX - resX);
|
||||
break;
|
||||
|
||||
@ -373,8 +385,8 @@ BoxPointer.prototype = {
|
||||
case St.Side.RIGHT:
|
||||
resY = sourceCenterY - (halfMargin + (natHeight - margin) * alignment);
|
||||
|
||||
resY = Math.max(resY, primary.y + 10);
|
||||
resY = Math.min(resY, primary.y + primary.height - (10 + natHeight));
|
||||
resY = Math.max(resY, monitor.y + 10);
|
||||
resY = Math.min(resY, monitor.y + monitor.height - (10 + natHeight));
|
||||
|
||||
this.setArrowOrigin(sourceCenterY - resY);
|
||||
break;
|
||||
@ -438,4 +450,4 @@ BoxPointer.prototype = {
|
||||
get opacity() {
|
||||
return this.actor.opacity;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const DBus = imports.dbus;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
@ -156,28 +155,24 @@ function _getEventDayAbbreviation(dayNumber) {
|
||||
|
||||
// Abstraction for an appointment/event in a calendar
|
||||
|
||||
function CalendarEvent(date, end, summary, allDay) {
|
||||
this._init(date, end, summary, allDay);
|
||||
}
|
||||
const CalendarEvent = new Lang.Class({
|
||||
Name: 'CalendarEvent',
|
||||
|
||||
CalendarEvent.prototype = {
|
||||
_init: function(date, end, summary, allDay) {
|
||||
this.date = date;
|
||||
this.end = end;
|
||||
this.summary = summary;
|
||||
this.allDay = allDay;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// Interface for appointments/events - e.g. the contents of a calendar
|
||||
//
|
||||
|
||||
// First, an implementation with no events
|
||||
function EmptyEventSource() {
|
||||
this._init();
|
||||
}
|
||||
const EmptyEventSource = new Lang.Class({
|
||||
Name: 'EmptyEventSource',
|
||||
|
||||
EmptyEventSource.prototype = {
|
||||
_init: function() {
|
||||
},
|
||||
|
||||
@ -192,33 +187,32 @@ EmptyEventSource.prototype = {
|
||||
hasEvents: function(day) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(EmptyEventSource.prototype);
|
||||
|
||||
const CalendarServerIface = {
|
||||
name: 'org.gnome.Shell.CalendarServer',
|
||||
methods: [{ name: 'GetEvents',
|
||||
inSignature: 'xxb',
|
||||
outSignature: 'a(sssbxxa{sv})' }],
|
||||
signals: [{ name: 'Changed',
|
||||
inSignature: '' }]
|
||||
};
|
||||
const CalendarServerIface = <interface name="org.gnome.Shell.CalendarServer">
|
||||
<method name="GetEvents">
|
||||
<arg type="x" direction="in" />
|
||||
<arg type="x" direction="in" />
|
||||
<arg type="b" direction="in" />
|
||||
<arg type="a(sssbxxa{sv})" direction="out" />
|
||||
</method>
|
||||
<signal name="Changed" />
|
||||
</interface>;
|
||||
|
||||
const CalendarServer = function () {
|
||||
this._init();
|
||||
};
|
||||
const CalendarServerInfo = Gio.DBusInterfaceInfo.new_for_xml(CalendarServerIface);
|
||||
|
||||
CalendarServer.prototype = {
|
||||
_init: function() {
|
||||
DBus.session.proxifyObject(this, 'org.gnome.Shell.CalendarServer', '/org/gnome/Shell/CalendarServer');
|
||||
}
|
||||
};
|
||||
function CalendarServer() {
|
||||
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.session,
|
||||
g_interface_name: CalendarServerInfo.name,
|
||||
g_interface_info: CalendarServerInfo,
|
||||
g_name: 'org.gnome.Shell.CalendarServer',
|
||||
g_object_path: '/org/gnome/Shell/CalendarServer',
|
||||
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
|
||||
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
||||
|
||||
DBus.proxifyPrototype(CalendarServer.prototype, CalendarServerIface);
|
||||
|
||||
// an implementation that reads data from a session bus service
|
||||
function DBusEventSource(owner) {
|
||||
this._init(owner);
|
||||
self.init(null);
|
||||
return self;
|
||||
}
|
||||
|
||||
function _datesEqual(a, b) {
|
||||
@ -239,18 +233,22 @@ function _dateIntervalsOverlap(a0, a1, b0, b1)
|
||||
return true;
|
||||
}
|
||||
|
||||
// an implementation that reads data from a session bus service
|
||||
const DBusEventSource = new Lang.Class({
|
||||
Name: 'DBusEventSource',
|
||||
|
||||
DBusEventSource.prototype = {
|
||||
_init: function(owner) {
|
||||
_init: function() {
|
||||
this._resetCache();
|
||||
|
||||
this._dbusProxy = new CalendarServer(owner);
|
||||
this._dbusProxy.connect('Changed', Lang.bind(this, this._onChanged));
|
||||
this._dbusProxy = new CalendarServer();
|
||||
this._dbusProxy.connectSignal('Changed', Lang.bind(this, this._onChanged));
|
||||
|
||||
DBus.session.watch_name('org.gnome.Shell.CalendarServer',
|
||||
false, // do not launch a name-owner if none exists
|
||||
Lang.bind(this, this._onNameAppeared),
|
||||
Lang.bind(this, this._onNameVanished));
|
||||
this._dbusProxy.connect('notify::g-name-owner', Lang.bind(this, function() {
|
||||
if (this._dbusProxy.g_name_owner)
|
||||
this._onNameAppeared();
|
||||
else
|
||||
this._onNameVanished();
|
||||
}));
|
||||
},
|
||||
|
||||
_resetCache: function() {
|
||||
@ -273,7 +271,7 @@ DBusEventSource.prototype = {
|
||||
this._loadEvents(false);
|
||||
},
|
||||
|
||||
_onEventsReceived: function(appointments) {
|
||||
_onEventsReceived: function([appointments]) {
|
||||
let newEvents = [];
|
||||
if (appointments != null) {
|
||||
for (let n = 0; n < appointments.length; n++) {
|
||||
@ -296,9 +294,9 @@ DBusEventSource.prototype = {
|
||||
|
||||
_loadEvents: function(forceReload) {
|
||||
if (this._curRequestBegin && this._curRequestEnd){
|
||||
let callFlags = 0;
|
||||
let callFlags = Gio.DBusCallFlags.NO_AUTO_START;
|
||||
if (forceReload)
|
||||
callFlags |= DBus.CALL_FLAG_START;
|
||||
callFlags = Gio.DBusCallFlags.NONE;
|
||||
this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
|
||||
this._curRequestEnd.getTime() / 1000,
|
||||
forceReload,
|
||||
@ -339,17 +337,15 @@ DBusEventSource.prototype = {
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(DBusEventSource.prototype);
|
||||
|
||||
// Calendar:
|
||||
// @eventSource: is an object implementing the EventSource API, e.g. the
|
||||
// requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
|
||||
function Calendar(eventSource) {
|
||||
this._init(eventSource);
|
||||
}
|
||||
const Calendar = new Lang.Class({
|
||||
Name: 'Calendar',
|
||||
|
||||
Calendar.prototype = {
|
||||
_init: function(eventSource) {
|
||||
if (eventSource) {
|
||||
this._eventSource = eventSource;
|
||||
@ -615,15 +611,13 @@ Calendar.prototype = {
|
||||
if (this._eventSource)
|
||||
this._eventSource.requestRange(beginDate, iter, forceReload);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Signals.addSignalMethods(Calendar.prototype);
|
||||
|
||||
function EventsList(eventSource) {
|
||||
this._init(eventSource);
|
||||
}
|
||||
const EventsList = new Lang.Class({
|
||||
Name: 'EventsList',
|
||||
|
||||
EventsList.prototype = {
|
||||
_init: function(eventSource) {
|
||||
this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'});
|
||||
this._date = new Date();
|
||||
@ -754,4 +748,4 @@ EventsList.prototype = {
|
||||
this._showOtherDay(this._date);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Folks = imports.gi.Folks
|
||||
const Lang = imports.lang;
|
||||
@ -20,13 +20,12 @@ function launchContact(id) {
|
||||
|
||||
|
||||
/* This class represents a shown contact search result in the overview */
|
||||
function Contact(id) {
|
||||
this._init(id);
|
||||
}
|
||||
const Contact = new Lang.Class({
|
||||
Name: 'Contact',
|
||||
|
||||
Contact.prototype = {
|
||||
_init: function(id) {
|
||||
this.individual = Shell.ContactSystem.get_default().get_individual(id);
|
||||
this._contactSys = Shell.ContactSystem.get_default();
|
||||
this.individual = this._contactSys.get_individual(id);
|
||||
|
||||
this.actor = new St.Bin({ style_class: 'contact',
|
||||
reactive: true,
|
||||
@ -56,7 +55,12 @@ Contact.prototype = {
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.MIDDLE });
|
||||
|
||||
let aliasText = this.individual.alias || _("Unknown");
|
||||
let email = this._contactSys.get_email_for_display(this.individual);
|
||||
let aliasText = this.individual.alias ||
|
||||
this.individual.full_name ||
|
||||
this.individual.nickname ||
|
||||
email ||
|
||||
_("Unknown");
|
||||
let aliasLabel = new St.Label({ text: aliasText,
|
||||
style_class: 'contact-details-alias' });
|
||||
details.add(aliasLabel, { x_fill: true,
|
||||
@ -125,19 +129,16 @@ Contact.prototype = {
|
||||
return tc.load_icon_name(null, 'avatar-default', St.IconType.FULLCOLOR, size);
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
/* Searches for and returns contacts */
|
||||
function ContactSearchProvider() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
ContactSearchProvider.prototype = {
|
||||
__proto__: Search.SearchProvider.prototype,
|
||||
const ContactSearchProvider = new Lang.Class({
|
||||
Name: 'ContactSearchProvider',
|
||||
Extends: Search.SearchProvider,
|
||||
|
||||
_init: function() {
|
||||
Search.SearchProvider.prototype._init.call(this, _("CONTACTS"));
|
||||
this.parent(_("CONTACTS"));
|
||||
this._contactSys = Shell.ContactSystem.get_default();
|
||||
},
|
||||
|
||||
@ -176,4 +177,4 @@ ContactSearchProvider.prototype = {
|
||||
activateResult: function(id, params) {
|
||||
launchContact(id);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
@ -22,11 +22,9 @@ const SortGroup = {
|
||||
BOTTOM: 2
|
||||
};
|
||||
|
||||
function CtrlAltTabManager() {
|
||||
this._init();
|
||||
}
|
||||
const CtrlAltTabManager = new Lang.Class({
|
||||
Name: 'CtrlAltTabManager',
|
||||
|
||||
CtrlAltTabManager.prototype = {
|
||||
_init: function() {
|
||||
this._items = [];
|
||||
this._focusManager = St.FocusManager.get_for_stage(global.stage);
|
||||
@ -94,7 +92,7 @@ CtrlAltTabManager.prototype = {
|
||||
return a.x - b.x;
|
||||
},
|
||||
|
||||
popup: function(backwards) {
|
||||
popup: function(backwards, mask) {
|
||||
// Start with the set of focus groups that are currently mapped
|
||||
let items = this._items.filter(function (item) { return item.proxy.mapped; });
|
||||
|
||||
@ -123,19 +121,26 @@ CtrlAltTabManager.prototype = {
|
||||
return;
|
||||
|
||||
items.sort(Lang.bind(this, this._sortItems));
|
||||
new CtrlAltTabPopup().show(items, backwards);
|
||||
|
||||
if (!this._popup) {
|
||||
this._popup = new CtrlAltTabPopup();
|
||||
this._popup.show(items, backwards, mask);
|
||||
|
||||
this._popup.actor.connect('destroy',
|
||||
Lang.bind(this, function() {
|
||||
this._popup = null;
|
||||
}));
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function mod(a, b) {
|
||||
return (a + b) % b;
|
||||
}
|
||||
|
||||
function CtrlAltTabPopup() {
|
||||
this._init();
|
||||
}
|
||||
const CtrlAltTabPopup = new Lang.Class({
|
||||
Name: 'CtrlAltTabPopup',
|
||||
|
||||
CtrlAltTabPopup.prototype = {
|
||||
_init : function() {
|
||||
this.actor = new Shell.GenericContainer({ name: 'ctrlAltTabPopup',
|
||||
reactive: true });
|
||||
@ -147,6 +152,7 @@ CtrlAltTabPopup.prototype = {
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
this._haveModal = false;
|
||||
this._modifierMask = 0;
|
||||
this._selection = 0;
|
||||
|
||||
Main.uiGroup.add_actor(this.actor);
|
||||
@ -177,16 +183,17 @@ CtrlAltTabPopup.prototype = {
|
||||
let [childMinHeight, childNaturalHeight] = this._switcher.actor.get_preferred_height(primary.width - hPadding);
|
||||
let [childMinWidth, childNaturalWidth] = this._switcher.actor.get_preferred_width(childNaturalHeight);
|
||||
childBox.x1 = Math.max(primary.x + leftPadding, primary.x + Math.floor((primary.width - childNaturalWidth) / 2));
|
||||
childBox.x2 = Math.min(primary.width - hPadding, childBox.x1 + childNaturalWidth);
|
||||
childBox.x2 = Math.min(primary.x + primary.width - hPadding, childBox.x1 + childNaturalWidth);
|
||||
childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
|
||||
childBox.y2 = childBox.y1 + childNaturalHeight;
|
||||
this._switcher.actor.allocate(childBox, flags);
|
||||
},
|
||||
|
||||
show : function(items, startBackwards) {
|
||||
show : function(items, startBackwards, mask) {
|
||||
if (!Main.pushModal(this.actor))
|
||||
return false;
|
||||
this._haveModal = true;
|
||||
this._modifierMask = AltTab.primaryModifier(mask);
|
||||
|
||||
this._keyPressEventId = this.actor.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
|
||||
this._keyReleaseEventId = this.actor.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
|
||||
@ -200,7 +207,7 @@ CtrlAltTabPopup.prototype = {
|
||||
this._select(this._selection);
|
||||
|
||||
let [x, y, mods] = global.get_pointer();
|
||||
if (!(mods & Gdk.ModifierType.MOD1_MASK)) {
|
||||
if (!(mods & this._modifierMask)) {
|
||||
this._finish();
|
||||
return false;
|
||||
}
|
||||
@ -246,7 +253,7 @@ CtrlAltTabPopup.prototype = {
|
||||
|
||||
_keyReleaseEvent : function(actor, event) {
|
||||
let [x, y, mods] = global.get_pointer();
|
||||
let state = mods & Clutter.ModifierType.MOD1_MASK;
|
||||
let state = mods & this._modifierMask;
|
||||
|
||||
if (state == 0)
|
||||
this._finish();
|
||||
@ -292,17 +299,14 @@ CtrlAltTabPopup.prototype = {
|
||||
this._selection = num;
|
||||
this._switcher.highlight(num);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function CtrlAltTabSwitcher(items) {
|
||||
this._init(items);
|
||||
}
|
||||
|
||||
CtrlAltTabSwitcher.prototype = {
|
||||
__proto__ : AltTab.SwitcherList.prototype,
|
||||
const CtrlAltTabSwitcher = new Lang.Class({
|
||||
Name: 'CtrlAltTabSwitcher',
|
||||
Extends: AltTab.SwitcherList,
|
||||
|
||||
_init : function(items) {
|
||||
AltTab.SwitcherList.prototype._init.call(this, true);
|
||||
this.parent(true);
|
||||
|
||||
for (let i = 0; i < items.length; i++)
|
||||
this._addIcon(items[i]);
|
||||
@ -325,4 +329,4 @@ CtrlAltTabSwitcher.prototype = {
|
||||
|
||||
this.addItem(box, text);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
158
js/ui/dash.js
158
js/ui/dash.js
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Signals = imports.signals;
|
||||
@ -19,11 +19,9 @@ const DASH_ANIMATION_TIME = 0.2;
|
||||
|
||||
// A container like StBin, but taking the child's scale into account
|
||||
// when requesting a size
|
||||
function DashItemContainer() {
|
||||
this._init();
|
||||
}
|
||||
const DashItemContainer = new Lang.Class({
|
||||
Name: 'DashItemContainer',
|
||||
|
||||
DashItemContainer.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new Shell.GenericContainer({ style_class: 'dash-item-container' });
|
||||
this.actor.connect('get-preferred-width',
|
||||
@ -37,6 +35,7 @@ DashItemContainer.prototype = {
|
||||
this.child = null;
|
||||
this._childScale = 1;
|
||||
this._childOpacity = 255;
|
||||
this.animatingOut = false;
|
||||
},
|
||||
|
||||
_allocate: function(actor, box, flags) {
|
||||
@ -115,6 +114,7 @@ DashItemContainer.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
this.animatingOut = true;
|
||||
this.childScale = 1.0;
|
||||
Tweener.addTween(this,
|
||||
{ childScale: 0.0,
|
||||
@ -155,17 +155,14 @@ DashItemContainer.prototype = {
|
||||
get childOpacity() {
|
||||
return this._childOpacity;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function RemoveFavoriteIcon() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
RemoveFavoriteIcon.prototype = {
|
||||
__proto__: DashItemContainer.prototype,
|
||||
const RemoveFavoriteIcon = new Lang.Class({
|
||||
Name: 'RemoveFavoriteIcon',
|
||||
Extends: DashItemContainer,
|
||||
|
||||
_init: function() {
|
||||
DashItemContainer.prototype._init.call(this);
|
||||
this.parent();
|
||||
|
||||
this._iconBin = new St.Bin({ style_class: 'remove-favorite' });
|
||||
this._iconActor = null;
|
||||
@ -177,12 +174,6 @@ RemoveFavoriteIcon.prototype = {
|
||||
this._iconBin._delegate = this;
|
||||
|
||||
this.setChild(this._iconBin);
|
||||
this.hiding = false;
|
||||
},
|
||||
|
||||
animateOutAndDestroy: function() {
|
||||
DashItemContainer.prototype.animateOutAndDestroy.call(this);
|
||||
this.hiding = true;
|
||||
},
|
||||
|
||||
_createIcon: function(size) {
|
||||
@ -223,28 +214,21 @@ RemoveFavoriteIcon.prototype = {
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
function DragPlaceholderItem() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
DragPlaceholderItem.prototype = {
|
||||
__proto__: DashItemContainer.prototype,
|
||||
const DragPlaceholderItem = new Lang.Class({
|
||||
Name: 'DragPlaceholderItem',
|
||||
Extends: DashItemContainer,
|
||||
|
||||
_init: function() {
|
||||
DashItemContainer.prototype._init.call(this);
|
||||
this.setChild(new St.Bin({ style_class: 'dash-placeholder' }));
|
||||
this.parent();
|
||||
this.setChild(new St.Bin({ style_class: 'placeholder' }));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const Dash = new Lang.Class({
|
||||
Name: 'Dash',
|
||||
|
||||
function Dash() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Dash.prototype = {
|
||||
_init : function() {
|
||||
this._maxHeight = -1;
|
||||
this.iconSize = 64;
|
||||
@ -314,15 +298,12 @@ Dash.prototype = {
|
||||
_endDrag: function() {
|
||||
this._clearDragPlaceholder();
|
||||
if (this._favRemoveTarget) {
|
||||
this._favRemoveTarget.actor.hide();
|
||||
this._adjustIconSize();
|
||||
this._favRemoveTarget.actor.show();
|
||||
|
||||
this._favRemoveTarget.animateOutAndDestroy();
|
||||
this._favRemoveTarget.actor.connect('destroy', Lang.bind(this,
|
||||
function() {
|
||||
this._favRemoveTarget = null;
|
||||
}));
|
||||
this._adjustIconSize();
|
||||
}
|
||||
DND.removeDragMonitor(this._dragMonitor);
|
||||
},
|
||||
@ -401,8 +382,18 @@ Dash.prototype = {
|
||||
},
|
||||
|
||||
_adjustIconSize: function() {
|
||||
let children = this._box.get_children();
|
||||
if (children.length == 0) {
|
||||
// For the icon size, we only consider children which are "proper"
|
||||
// icons (i.e. ignoring drag placeholders) and which are not
|
||||
// animating out (which means they will be destroyed at the end of
|
||||
// the animation)
|
||||
let iconChildren = this._box.get_children().filter(function(actor) {
|
||||
return actor._delegate.child &&
|
||||
actor._delegate.child._delegate &&
|
||||
actor._delegate.child._delegate.icon &&
|
||||
!actor._delegate.animatingOut;
|
||||
});
|
||||
|
||||
if (iconChildren.length == 0) {
|
||||
this._box.add_style_pseudo_class('empty');
|
||||
return;
|
||||
}
|
||||
@ -412,23 +403,45 @@ Dash.prototype = {
|
||||
if (this._maxHeight == -1)
|
||||
return;
|
||||
|
||||
let iconChildren = children.filter(function(actor) {
|
||||
return actor.visible &&
|
||||
actor._delegate.child &&
|
||||
actor._delegate.child._delegate &&
|
||||
actor._delegate.child._delegate.icon;
|
||||
});
|
||||
|
||||
// Compute the amount of extra space (or missing space) we have
|
||||
// per icon with the current icon size
|
||||
let [minHeight, natHeight] = this.actor.get_preferred_height(-1);
|
||||
let diff = (this._maxHeight - natHeight) / iconChildren.length;
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
let maxAllocation = new Clutter.ActorBox({ x1: 0, y1: 0,
|
||||
x2: 42 /* whatever */,
|
||||
y2: this._maxHeight });
|
||||
let maxContent = themeNode.get_content_box(maxAllocation);
|
||||
let availHeight = maxContent.y2 - maxContent.y1;
|
||||
let spacing = themeNode.get_length('spacing');
|
||||
|
||||
|
||||
let firstIcon = iconChildren[0]._delegate.child._delegate.icon;
|
||||
|
||||
let minHeight, natHeight;
|
||||
|
||||
// Enforce the current icon size during the size request if
|
||||
// the icon is animating
|
||||
if (firstIcon._animating) {
|
||||
let [currentWidth, currentHeight] = firstIcon.icon.get_size();
|
||||
|
||||
firstIcon.icon.set_size(this.iconSize, this.iconSize);
|
||||
[minHeight, natHeight] = iconChildren[0].get_preferred_height(-1);
|
||||
|
||||
firstIcon.icon.set_size(currentWidth, currentHeight);
|
||||
} else {
|
||||
[minHeight, natHeight] = iconChildren[0].get_preferred_height(-1);
|
||||
}
|
||||
|
||||
|
||||
// Subtract icon padding and box spacing from the available height
|
||||
availHeight -= iconChildren.length * (natHeight - this.iconSize) +
|
||||
(iconChildren.length - 1) * spacing;
|
||||
|
||||
let availSize = availHeight / iconChildren.length;
|
||||
|
||||
let iconSizes = [ 16, 22, 24, 32, 48, 64 ];
|
||||
|
||||
let newIconSize = 16;
|
||||
for (let i = 0; i < iconSizes.length; i++) {
|
||||
if (iconSizes[i] < this.iconSize + diff)
|
||||
if (iconSizes[i] < availSize)
|
||||
newIconSize = iconSizes[i];
|
||||
}
|
||||
|
||||
@ -459,11 +472,15 @@ Dash.prototype = {
|
||||
icon.icon.set_size(icon.icon.width * scale,
|
||||
icon.icon.height * scale);
|
||||
|
||||
icon._animating = true;
|
||||
Tweener.addTween(icon.icon,
|
||||
{ width: targetWidth,
|
||||
height: targetHeight,
|
||||
time: DASH_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: function() {
|
||||
icon._animating = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -566,29 +583,7 @@ Dash.prototype = {
|
||||
this._box.insert_actor(addedItems[i].item.actor,
|
||||
addedItems[i].pos);
|
||||
|
||||
// Hide removed actors to not take them into account
|
||||
// when adjusting the icon size ...
|
||||
for (let i = 0; i < removedActors.length; i++)
|
||||
removedActors[i].hide();
|
||||
|
||||
// ... and do the same for the remove target if necessary
|
||||
if (this._favRemoveTarget && this._favRemoveTarget.hiding)
|
||||
this._favRemoveTarget.actor.hide();
|
||||
|
||||
this._adjustIconSize();
|
||||
|
||||
if (this._favRemoveTarget && this._favRemoveTarget.hiding)
|
||||
this._favRemoveTarget.actor.show();
|
||||
|
||||
// Skip animations on first run when adding the initial set
|
||||
// of items, to avoid all items zooming in at once
|
||||
if (!this._shownInitially) {
|
||||
this._shownInitially = true;
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < removedActors.length; i++) {
|
||||
removedActors[i].show();
|
||||
let item = removedActors[i]._delegate;
|
||||
|
||||
// Don't animate item removal when the overview is hidden
|
||||
@ -598,6 +593,15 @@ Dash.prototype = {
|
||||
item.actor.destroy();
|
||||
}
|
||||
|
||||
this._adjustIconSize();
|
||||
|
||||
// Skip animations on first run when adding the initial set
|
||||
// of items, to avoid all items zooming in at once
|
||||
if (!this._shownInitially) {
|
||||
this._shownInitially = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't animate item addition when the overview is hidden
|
||||
if (!Main.overview.visible)
|
||||
return;
|
||||
@ -684,6 +688,8 @@ Dash.prototype = {
|
||||
}
|
||||
|
||||
this._dragPlaceholder = new DragPlaceholderItem();
|
||||
this._dragPlaceholder.child.set_width (this.iconSize);
|
||||
this._dragPlaceholder.child.set_height (this.iconSize / 2);
|
||||
this._box.insert_actor(this._dragPlaceholder.actor,
|
||||
this._dragPlaceholderPos);
|
||||
if (fadeIn)
|
||||
@ -744,6 +750,6 @@ Dash.prototype = {
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Signals.addSignalMethods(Dash.prototype);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
@ -40,12 +40,9 @@ function _onVertSepRepaint (area)
|
||||
cr.stroke();
|
||||
};
|
||||
|
||||
function DateMenuButton() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
DateMenuButton.prototype = {
|
||||
__proto__: PanelMenu.Button.prototype,
|
||||
const DateMenuButton = new Lang.Class({
|
||||
Name: 'DateMenuButton',
|
||||
Extends: PanelMenu.Button,
|
||||
|
||||
_init: function(params) {
|
||||
params = Params.parse(params, { showEvents: true });
|
||||
@ -57,10 +54,10 @@ DateMenuButton.prototype = {
|
||||
let menuAlignment = 0.25;
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||
menuAlignment = 1.0 - menuAlignment;
|
||||
PanelMenu.Button.prototype._init.call(this, menuAlignment);
|
||||
this.parent(menuAlignment);
|
||||
|
||||
this._clock = new St.Label();
|
||||
this.actor.set_child(this._clock);
|
||||
this.actor.add_actor(this._clock);
|
||||
|
||||
hbox = new St.BoxLayout({name: 'calendarArea' });
|
||||
this.menu.addActor(hbox);
|
||||
@ -239,4 +236,4 @@ DateMenuButton.prototype = {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
10
js/ui/dnd.js
10
js/ui/dnd.js
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
@ -69,11 +69,9 @@ function removeDragMonitor(monitor) {
|
||||
}
|
||||
}
|
||||
|
||||
function _Draggable(actor, params) {
|
||||
this._init(actor, params);
|
||||
}
|
||||
const _Draggable = new Lang.Class({
|
||||
Name: 'Draggable',
|
||||
|
||||
_Draggable.prototype = {
|
||||
_init : function(actor, params) {
|
||||
params = Params.parse(params, { manualMode: false,
|
||||
restoreOnSuccess: false,
|
||||
@ -596,7 +594,7 @@ _Draggable.prototype = {
|
||||
this._dragActor = undefined;
|
||||
currentDraggable = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Signals.addSignalMethods(_Draggable.prototype);
|
||||
|
||||
|
@ -1,19 +1,16 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const DocInfo = imports.misc.docInfo;
|
||||
const Lang = imports.lang;
|
||||
const Params = imports.misc.params;
|
||||
const Search = imports.ui.search;
|
||||
|
||||
|
||||
function DocSearchProvider() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
DocSearchProvider.prototype = {
|
||||
__proto__: Search.SearchProvider.prototype,
|
||||
const DocSearchProvider = new Lang.Class({
|
||||
Name: 'DocSearchProvider',
|
||||
Extends: Search.SearchProvider,
|
||||
|
||||
_init: function(name) {
|
||||
Search.SearchProvider.prototype._init.call(this, _("RECENT ITEMS"));
|
||||
this.parent(_("RECENT ITEMS"));
|
||||
this._docManager = DocInfo.getDocManager();
|
||||
},
|
||||
|
||||
@ -44,4 +41,4 @@ DocSearchProvider.prototype = {
|
||||
getSubsearchResultSet: function(previousResults, terms) {
|
||||
return this._docManager.subsearch(previousResults, terms);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 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
|
||||
@ -18,19 +18,19 @@
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
const DBus = imports.dbus;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const AccountsService = imports.gi.AccountsService;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Pango = imports.gi.Pango;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const GnomeSession = imports.misc.gnomeSession
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
const Lightbox = imports.ui.lightbox;
|
||||
const Main = imports.ui.main;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
@ -43,51 +43,68 @@ const _DIALOG_ICON_SIZE = 32;
|
||||
|
||||
const GSM_SESSION_MANAGER_LOGOUT_FORCE = 2;
|
||||
|
||||
const EndSessionDialogIface = {
|
||||
name: 'org.gnome.SessionManager.EndSessionDialog',
|
||||
methods: [{ name: 'Open',
|
||||
inSignature: 'uuuao',
|
||||
outSignature: ''
|
||||
}
|
||||
],
|
||||
signals: [{ name: 'Canceled',
|
||||
inSignature: '',
|
||||
}],
|
||||
properties: []
|
||||
};
|
||||
const EndSessionDialogIface = <interface name="org.gnome.SessionManager.EndSessionDialog">
|
||||
<method name="Open">
|
||||
<arg type="u" direction="in" />
|
||||
<arg type="u" direction="in" />
|
||||
<arg type="u" direction="in" />
|
||||
<arg type="ao" direction="in" />
|
||||
</method>
|
||||
<signal name="ConfirmedLogout" />
|
||||
<signal name="ConfirmedReboot" />
|
||||
<signal name="ConfirmedShutdown" />
|
||||
<signal name="Canceled" />
|
||||
<signal name="Closed" />
|
||||
</interface>;
|
||||
|
||||
const logoutDialogContent = {
|
||||
subjectWithUser: _("Log Out %s"),
|
||||
subject: _("Log Out"),
|
||||
subjectWithUser: C_("title", "Log Out %s"),
|
||||
subject: C_("title", "Log Out"),
|
||||
inhibitedDescription: _("Click Log Out to quit these applications and log out of the system."),
|
||||
uninhibitedDescriptionWithUser: _("%s will be logged out automatically in %d seconds."),
|
||||
uninhibitedDescription: _("You will be logged out automatically in %d seconds."),
|
||||
uninhibitedDescriptionWithUser: function(user, seconds) {
|
||||
return ngettext("%s will be logged out automatically in %d second.",
|
||||
"%s will be logged out automatically in %d seconds.",
|
||||
seconds).format(user, seconds);
|
||||
},
|
||||
uninhibitedDescription: function(seconds) {
|
||||
return ngettext("You will be logged out automatically in %d second.",
|
||||
"You will be logged out automatically in %d seconds.",
|
||||
seconds).format(seconds);
|
||||
},
|
||||
endDescription: _("Logging out of the system."),
|
||||
confirmButtons: [{ signal: 'ConfirmedLogout',
|
||||
label: _("Log Out") }],
|
||||
label: C_("button", "Log Out") }],
|
||||
iconStyleClass: 'end-session-dialog-logout-icon'
|
||||
};
|
||||
|
||||
const shutdownDialogContent = {
|
||||
subject: _("Power Off"),
|
||||
subject: C_("title", "Power Off"),
|
||||
inhibitedDescription: _("Click Power Off to quit these applications and power off the system."),
|
||||
uninhibitedDescription: _("The system will power off automatically in %d seconds."),
|
||||
uninhibitedDescription: function(seconds) {
|
||||
return ngettext("The system will power off automatically in %d second.",
|
||||
"The system will power off automatically in %d seconds.",
|
||||
seconds).format(seconds);
|
||||
},
|
||||
endDescription: _("Powering off the system."),
|
||||
confirmButtons: [{ signal: 'ConfirmedReboot',
|
||||
label: _("Restart") },
|
||||
label: C_("button", "Restart") },
|
||||
{ signal: 'ConfirmedShutdown',
|
||||
label: _("Power Off") }],
|
||||
label: C_("button", "Power Off") }],
|
||||
iconName: 'system-shutdown',
|
||||
iconStyleClass: 'end-session-dialog-shutdown-icon'
|
||||
};
|
||||
|
||||
const restartDialogContent = {
|
||||
subject: _("Restart"),
|
||||
subject: C_("title", "Restart"),
|
||||
inhibitedDescription: _("Click Restart to quit these applications and restart the system."),
|
||||
uninhibitedDescription: _("The system will restart automatically in %d seconds."),
|
||||
uninhibitedDescription: function(seconds) {
|
||||
return ngettext("The system will restart automatically in %d second.",
|
||||
"The system will restart automatically in %d seconds.",
|
||||
seconds).format(seconds);
|
||||
},
|
||||
endDescription: _("Restarting the system."),
|
||||
confirmButtons: [{ signal: 'ConfirmedReboot',
|
||||
label: _("Restart") }],
|
||||
label: C_("button", "Restart") }],
|
||||
iconName: 'system-shutdown',
|
||||
iconStyleClass: 'end-session-dialog-shutdown-icon'
|
||||
};
|
||||
@ -125,11 +142,9 @@ function findAppFromInhibitor(inhibitor) {
|
||||
return app;
|
||||
}
|
||||
|
||||
function ListItem(app, reason) {
|
||||
this._init(app, reason);
|
||||
}
|
||||
const ListItem = new Lang.Class({
|
||||
Name: 'ListItem',
|
||||
|
||||
ListItem.prototype = {
|
||||
_init: function(app, reason) {
|
||||
this._app = app;
|
||||
this._reason = reason;
|
||||
@ -175,7 +190,7 @@ ListItem.prototype = {
|
||||
this.emit('activate');
|
||||
this._app.activate();
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(ListItem.prototype);
|
||||
|
||||
// The logout timer only shows updates every 10 seconds
|
||||
@ -213,29 +228,19 @@ function _setLabelText(label, text) {
|
||||
}
|
||||
}
|
||||
|
||||
function EndSessionDialog() {
|
||||
if (_endSessionDialog == null) {
|
||||
this._init();
|
||||
DBus.session.exportObject('/org/gnome/SessionManager/EndSessionDialog',
|
||||
this);
|
||||
_endSessionDialog = this;
|
||||
}
|
||||
|
||||
return _endSessionDialog;
|
||||
}
|
||||
|
||||
function init() {
|
||||
// This always returns the same singleton object
|
||||
// By instantiating it initially, we register the
|
||||
// bus object, etc.
|
||||
let dialog = new EndSessionDialog();
|
||||
_endSessionDialog = new EndSessionDialog();
|
||||
}
|
||||
|
||||
EndSessionDialog.prototype = {
|
||||
__proto__: ModalDialog.ModalDialog.prototype,
|
||||
const EndSessionDialog = new Lang.Class({
|
||||
Name: 'EndSessionDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
|
||||
_init: function() {
|
||||
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'end-session-dialog' });
|
||||
this.parent({ styleClass: 'end-session-dialog' });
|
||||
|
||||
this._user = AccountsService.UserManager.get_default().get_user(GLib.get_user_name());
|
||||
|
||||
@ -310,6 +315,9 @@ EndSessionDialog.prototype = {
|
||||
if (this._applicationList.get_children().length == 0)
|
||||
scrollView.hide();
|
||||
}));
|
||||
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(EndSessionDialogIface, this);
|
||||
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog');
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
@ -388,14 +396,14 @@ EndSessionDialog.prototype = {
|
||||
subject = dialogContent.subjectWithUser.format(realName);
|
||||
|
||||
if (dialogContent.uninhibitedDescriptionWithUser)
|
||||
description = dialogContent.uninhibitedDescriptionWithUser.format(realName, displayTime);
|
||||
description = dialogContent.uninhibitedDescriptionWithUser(realName, displayTime);
|
||||
else
|
||||
description = dialogContent.uninhibitedDescription.format(displayTime);
|
||||
description = dialogContent.uninhibitedDescription(displayTime);
|
||||
}
|
||||
}
|
||||
|
||||
if (!description)
|
||||
description = dialogContent.uninhibitedDescription.format(displayTime);
|
||||
description = dialogContent.uninhibitedDescription(displayTime);
|
||||
} else {
|
||||
description = dialogContent.endDescription;
|
||||
}
|
||||
@ -423,26 +431,20 @@ EndSessionDialog.prototype = {
|
||||
},
|
||||
|
||||
close: function() {
|
||||
ModalDialog.ModalDialog.prototype.close.call(this);
|
||||
DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
|
||||
'org.gnome.SessionManager.EndSessionDialog',
|
||||
'Closed', '', []);
|
||||
this.parent();
|
||||
this._dbusImpl.emit_signal('Closed', null);
|
||||
},
|
||||
|
||||
cancel: function() {
|
||||
this._stopTimer();
|
||||
DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
|
||||
'org.gnome.SessionManager.EndSessionDialog',
|
||||
'Canceled', '', []);
|
||||
this._dbusImpl.emit_signal('Canceled', null);
|
||||
this.close(global.get_current_time());
|
||||
},
|
||||
|
||||
_confirm: function(signal) {
|
||||
this._fadeOutDialog();
|
||||
this._stopTimer();
|
||||
DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
|
||||
'org.gnome.SessionManager.EndSessionDialog',
|
||||
signal, '', []);
|
||||
this._dbusImpl.emit_signal(signal, null);
|
||||
},
|
||||
|
||||
_onOpened: function() {
|
||||
@ -494,39 +496,41 @@ EndSessionDialog.prototype = {
|
||||
this._updateContent();
|
||||
},
|
||||
|
||||
OpenAsync: function(type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths, callback) {
|
||||
OpenAsync: function(parameters, invocation) {
|
||||
let [type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths] = parameters;
|
||||
this._totalSecondsToStayOpen = totalSecondsToStayOpen;
|
||||
this._inhibitors = [];
|
||||
this._applicationList.destroy_children();
|
||||
this._type = type;
|
||||
|
||||
if (!(this._type in DialogContent))
|
||||
throw new DBus.DBusError('org.gnome.Shell.ModalDialog.TypeError',
|
||||
"Unknown dialog type requested");
|
||||
if (!(this._type in DialogContent)) {
|
||||
invocation.report_dbus_error('org.gnome.Shell.ModalDialog.TypeError',
|
||||
"Unknown dialog type requested");
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
this._onInhibitorLoaded(proxy);
|
||||
}));
|
||||
|
||||
inhibitor.connect('is-loaded',
|
||||
Lang.bind(this, function() {
|
||||
this._onInhibitorLoaded(inhibitor);
|
||||
}));
|
||||
this._inhibitors.push(inhibitor);
|
||||
}
|
||||
|
||||
this._updateButtons();
|
||||
|
||||
if (!this.open(timestamp))
|
||||
throw new DBus.DBusError('org.gnome.Shell.ModalDialog.GrabError',
|
||||
"Cannot grab pointer and keyboard");
|
||||
if (!this.open(timestamp)) {
|
||||
invocation.report_dbus_error('org.gnome.Shell.ModalDialog.GrabError',
|
||||
"Cannot grab pointer and keyboard");
|
||||
return;
|
||||
}
|
||||
|
||||
this._updateContent();
|
||||
|
||||
let signalId = this.connect('opened',
|
||||
Lang.bind(this, function() {
|
||||
callback();
|
||||
invocation.return_value(null);
|
||||
this.disconnect(signalId);
|
||||
}));
|
||||
}
|
||||
};
|
||||
DBus.conformExport(EndSessionDialog.prototype, EndSessionDialogIface);
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
imports.gi.versions.Clutter = '1.0';
|
||||
imports.gi.versions.Gio = '2.0';
|
||||
|
@ -1,8 +1,9 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const St = imports.gi.St;
|
||||
@ -10,6 +11,10 @@ const Shell = imports.gi.Shell;
|
||||
const Soup = imports.gi.Soup;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
const FileUtils = imports.misc.fileUtils;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
|
||||
const API_VERSION = 1;
|
||||
|
||||
const ExtensionState = {
|
||||
ENABLED: 1,
|
||||
@ -17,6 +22,7 @@ const ExtensionState = {
|
||||
ERROR: 3,
|
||||
OUT_OF_DATE: 4,
|
||||
DOWNLOADING: 5,
|
||||
INITIALIZED: 6,
|
||||
|
||||
// Used as an error state for operations on unknown extensions,
|
||||
// should never be in a real extensionMeta object.
|
||||
@ -28,6 +34,10 @@ const ExtensionType = {
|
||||
PER_USER: 2
|
||||
};
|
||||
|
||||
const REPOSITORY_URL_BASE = 'https://extensions.gnome.org';
|
||||
const REPOSITORY_URL_DOWNLOAD = REPOSITORY_URL_BASE + '/download-extension/%s.shell-extension.zip';
|
||||
const REPOSITORY_URL_INFO = REPOSITORY_URL_BASE + '/extension-info/';
|
||||
|
||||
const _httpSession = new Soup.SessionAsync();
|
||||
|
||||
// The unfortunate state of gjs, gobject-introspection and libsoup
|
||||
@ -37,12 +47,25 @@ const _httpSession = new Soup.SessionAsync();
|
||||
if (Soup.Session.prototype.add_feature != null)
|
||||
Soup.Session.prototype.add_feature.call(_httpSession, new Soup.ProxyResolverDefault());
|
||||
|
||||
function _getCertFile() {
|
||||
let localCert = GLib.build_filenamev([global.userdatadir, 'extensions.gnome.org.crt']);
|
||||
if (GLib.file_test(localCert, GLib.FileTest.EXISTS))
|
||||
return localCert;
|
||||
else
|
||||
return Config.SHELL_SYSTEM_CA_FILE;
|
||||
}
|
||||
|
||||
_httpSession.ssl_ca_file = _getCertFile();
|
||||
|
||||
// Maps uuid -> metadata object
|
||||
const extensionMeta = {};
|
||||
// Maps uuid -> importer object (extension directory tree)
|
||||
const extensions = {};
|
||||
// Maps uuid -> extension state object (returned from init())
|
||||
const extensionStateObjs = {};
|
||||
// Contains the order that extensions were enabled in.
|
||||
const extensionOrder = [];
|
||||
|
||||
// Arrays of uuids
|
||||
var enabledExtensions;
|
||||
// GFile for user extensions
|
||||
@ -92,53 +115,51 @@ function versionCheck(required, current) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function installExtensionFromManifestURL(uuid, url) {
|
||||
_httpSession.queue_message(
|
||||
Soup.Message.new('GET', url),
|
||||
function(session, message) {
|
||||
if (message.status_code != Soup.KnownStatusCode.OK) {
|
||||
logExtensionError(uuid, 'downloading manifest: ' + message.status_code.toString());
|
||||
return;
|
||||
}
|
||||
function installExtensionFromUUID(uuid, version_tag) {
|
||||
let params = { uuid: uuid,
|
||||
version_tag: version_tag,
|
||||
shell_version: Config.PACKAGE_VERSION,
|
||||
api_version: API_VERSION.toString() };
|
||||
|
||||
let manifest;
|
||||
try {
|
||||
manifest = JSON.parse(message.response_body.data);
|
||||
} catch (e) {
|
||||
logExtensionError(uuid, 'parsing: ' + e.toString());
|
||||
return;
|
||||
}
|
||||
let message = Soup.form_request_new_from_hash('GET', REPOSITORY_URL_INFO, params);
|
||||
|
||||
if (uuid != manifest['uuid']) {
|
||||
logExtensionError(uuid, 'manifest: manifest uuids do not match');
|
||||
return;
|
||||
}
|
||||
|
||||
let meta = extensionMeta[uuid] = { uuid: uuid,
|
||||
state: ExtensionState.DOWNLOADING,
|
||||
error: '' };
|
||||
|
||||
_signals.emit('extension-state-changed', meta);
|
||||
|
||||
installExtensionFromManifest(manifest, meta);
|
||||
});
|
||||
_httpSession.queue_message(message,
|
||||
function(session, message) {
|
||||
let info = JSON.parse(message.response_body.data);
|
||||
let dialog = new InstallExtensionDialog(uuid, version_tag, info.name);
|
||||
dialog.open(global.get_current_time());
|
||||
});
|
||||
}
|
||||
|
||||
function installExtensionFromManifest(manifest, meta) {
|
||||
let uuid = manifest['uuid'];
|
||||
let name = manifest['name'];
|
||||
function uninstallExtensionFromUUID(uuid) {
|
||||
let meta = extensionMeta[uuid];
|
||||
if (!meta)
|
||||
return false;
|
||||
|
||||
if (!versionCheck(manifest['shell-version'], Config.PACKAGE_VERSION)) {
|
||||
meta.state = ExtensionState.OUT_OF_DATE;
|
||||
logExtensionError(uuid, 'version: ' + name + ' is not compatible with current GNOME Shell version', meta.state);
|
||||
return;
|
||||
}
|
||||
// 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
|
||||
// broke too much.
|
||||
disableExtension(uuid);
|
||||
|
||||
let url = manifest['__installer'];
|
||||
_httpSession.queue_message(Soup.Message.new('GET', url),
|
||||
function(session, message) {
|
||||
gotExtensionZipFile(session, message, uuid);
|
||||
});
|
||||
// Don't try to uninstall system extensions
|
||||
if (meta.type != ExtensionType.PER_USER)
|
||||
return false;
|
||||
|
||||
meta.state = ExtensionState.UNINSTALLED;
|
||||
_signals.emit('extension-state-changed', meta);
|
||||
|
||||
delete extensionMeta[uuid];
|
||||
|
||||
// Importers are marked as PERMANENT, so we can't do this.
|
||||
// delete extensions[uuid];
|
||||
extensions[uuid] = undefined;
|
||||
|
||||
delete extensionStateObjs[uuid];
|
||||
delete errors[uuid];
|
||||
|
||||
FileUtils.recursivelyDeleteDir(Gio.file_new_for_path(meta.path));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function gotExtensionZipFile(session, message, uuid) {
|
||||
@ -173,6 +194,14 @@ function gotExtensionZipFile(session, message, uuid) {
|
||||
|
||||
GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function(pid, status) {
|
||||
GLib.spawn_close_pid(pid);
|
||||
|
||||
// Add extension to 'enabled-extensions' for the user, always...
|
||||
let enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
||||
if (enabledExtensions.indexOf(uuid) == -1) {
|
||||
enabledExtensions.push(uuid);
|
||||
global.settings.set_strv(ENABLED_EXTENSIONS_KEY, enabledExtensions);
|
||||
}
|
||||
|
||||
loadExtension(dir, true, ExtensionType.PER_USER);
|
||||
});
|
||||
}
|
||||
@ -187,6 +216,27 @@ function disableExtension(uuid) {
|
||||
|
||||
let extensionState = extensionStateObjs[uuid];
|
||||
|
||||
// "Rebase" the extension order by disabling and then enabling extensions
|
||||
// in order to help prevent conflicts.
|
||||
|
||||
// Example:
|
||||
// order = [A, B, C, D, E]
|
||||
// user disables C
|
||||
// this should: disable E, disable D, disable C, enable D, enable E
|
||||
|
||||
let orderIdx = extensionOrder.indexOf(uuid);
|
||||
let order = extensionOrder.slice(orderIdx + 1);
|
||||
let orderReversed = order.slice().reverse();
|
||||
|
||||
for (let i = 0; i < orderReversed.length; i++) {
|
||||
let uuid = orderReversed[i];
|
||||
try {
|
||||
extensionStateObjs[uuid].disable();
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
extensionState.disable();
|
||||
} catch(e) {
|
||||
@ -194,6 +244,17 @@ function disableExtension(uuid) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < order.length; i++) {
|
||||
let uuid = order[i];
|
||||
try {
|
||||
extensionStateObjs[uuid].enable();
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
extensionOrder.splice(orderIdx, 1);
|
||||
|
||||
meta.state = ExtensionState.DISABLED;
|
||||
_signals.emit('extension-state-changed', meta);
|
||||
}
|
||||
@ -203,11 +264,18 @@ function enableExtension(uuid) {
|
||||
if (!meta)
|
||||
return;
|
||||
|
||||
if (meta.state == ExtensionState.INITIALIZED) {
|
||||
loadExtension(meta.dir, meta.type, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (meta.state != ExtensionState.DISABLED)
|
||||
return;
|
||||
|
||||
let extensionState = extensionStateObjs[uuid];
|
||||
|
||||
extensionOrder.push(uuid);
|
||||
|
||||
try {
|
||||
extensionState.enable();
|
||||
} catch(e) {
|
||||
@ -229,7 +297,7 @@ function logExtensionError(uuid, message, state) {
|
||||
state: state });
|
||||
}
|
||||
|
||||
function loadExtension(dir, enabled, type) {
|
||||
function loadExtension(dir, type, enabled) {
|
||||
let info;
|
||||
let uuid = dir.get_basename();
|
||||
|
||||
@ -264,7 +332,7 @@ function loadExtension(dir, enabled, type) {
|
||||
}
|
||||
|
||||
if (extensions[uuid] != undefined) {
|
||||
logExtensionError(uuid, "extension already loaded");
|
||||
logExtensionError(uuid, 'extension already loaded');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -278,14 +346,9 @@ function loadExtension(dir, enabled, type) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!versionCheck(meta['shell-version'], Config.PACKAGE_VERSION) ||
|
||||
(meta['js-version'] && !versionCheck(meta['js-version'], Config.GJS_VERSION))) {
|
||||
logExtensionError(uuid, 'extension is not compatible with current GNOME Shell and/or GJS version');
|
||||
return;
|
||||
}
|
||||
|
||||
extensionMeta[uuid] = meta;
|
||||
meta.type = type;
|
||||
meta.dir = dir;
|
||||
meta.path = dir.get_path();
|
||||
meta.error = '';
|
||||
|
||||
@ -299,6 +362,11 @@ function loadExtension(dir, enabled, type) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
meta.state = ExtensionState.INITIALIZED;
|
||||
return;
|
||||
}
|
||||
|
||||
let extensionJs = dir.get_child('extension.js');
|
||||
if (!extensionJs.query_exists(null)) {
|
||||
logExtensionError(uuid, 'Missing extension.js');
|
||||
@ -358,8 +426,7 @@ function loadExtension(dir, enabled, type) {
|
||||
|
||||
meta.state = ExtensionState.DISABLED;
|
||||
|
||||
if (enabled)
|
||||
enableExtension(uuid);
|
||||
enableExtension(uuid);
|
||||
|
||||
_signals.emit('extension-loaded', meta.uuid);
|
||||
_signals.emit('extension-state-changed', meta);
|
||||
@ -419,13 +486,12 @@ function _loadExtensionsIn(dir, type) {
|
||||
let name = info.get_name();
|
||||
let child = dir.get_child(name);
|
||||
let enabled = enabledExtensions.indexOf(name) != -1;
|
||||
loadExtension(child, enabled, type);
|
||||
loadExtension(child, type, enabled);
|
||||
}
|
||||
fileEnum.close(null);
|
||||
}
|
||||
|
||||
function loadExtensions() {
|
||||
_loadExtensionsIn(userExtensionsDir, ExtensionType.PER_USER);
|
||||
let systemDataDirs = GLib.get_system_data_dirs();
|
||||
for (let i = 0; i < systemDataDirs.length; i++) {
|
||||
let dirPath = systemDataDirs[i] + '/gnome-shell/extensions';
|
||||
@ -433,4 +499,72 @@ function loadExtensions() {
|
||||
if (dir.query_exists(null))
|
||||
_loadExtensionsIn(dir, ExtensionType.SYSTEM);
|
||||
}
|
||||
_loadExtensionsIn(userExtensionsDir, ExtensionType.PER_USER);
|
||||
}
|
||||
|
||||
const InstallExtensionDialog = new Lang.Class({
|
||||
Name: 'InstallExtensionDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
|
||||
_init: function(uuid, version_tag, name) {
|
||||
this.parent({ styleClass: 'extension-dialog' });
|
||||
|
||||
this._uuid = uuid;
|
||||
this._version_tag = version_tag;
|
||||
this._name = name;
|
||||
|
||||
this.setButtons([{ label: _("Cancel"),
|
||||
action: Lang.bind(this, this._onCancelButtonPressed),
|
||||
key: Clutter.Escape
|
||||
},
|
||||
{ label: _("Install"),
|
||||
action: Lang.bind(this, this._onInstallButtonPressed)
|
||||
}]);
|
||||
|
||||
let message = _("Download and install '%s' from extensions.gnome.org?").format(name);
|
||||
|
||||
this._descriptionLabel = new St.Label({ text: message });
|
||||
|
||||
this.contentLayout.add(this._descriptionLabel,
|
||||
{ y_fill: true,
|
||||
y_align: St.Align.START });
|
||||
},
|
||||
|
||||
_onCancelButtonPressed: function(button, event) {
|
||||
this.close(global.get_current_time());
|
||||
|
||||
// Even though the extension is already "uninstalled", send through
|
||||
// a state-changed signal for any users who want to know if the install
|
||||
// went through correctly -- using proper async DBus would block more
|
||||
// traditional clients like the plugin
|
||||
let meta = { uuid: this._uuid,
|
||||
state: ExtensionState.UNINSTALLED,
|
||||
error: '' };
|
||||
|
||||
_signals.emit('extension-state-changed', meta);
|
||||
},
|
||||
|
||||
_onInstallButtonPressed: function(button, event) {
|
||||
let meta = { uuid: this._uuid,
|
||||
state: ExtensionState.DOWNLOADING,
|
||||
error: '' };
|
||||
|
||||
extensionMeta[this._uuid] = meta;
|
||||
|
||||
_signals.emit('extension-state-changed', meta);
|
||||
|
||||
let params = { version_tag: this._version_tag,
|
||||
shell_version: Config.PACKAGE_VERSION,
|
||||
api_version: API_VERSION.toString() };
|
||||
|
||||
let url = REPOSITORY_URL_DOWNLOAD.format(this._uuid);
|
||||
let message = Soup.form_request_new_from_hash('GET', url, params);
|
||||
|
||||
_httpSession.queue_message(message,
|
||||
Lang.bind(this, function(session, message) {
|
||||
gotExtensionZipFile(session, message, this._uuid);
|
||||
}));
|
||||
|
||||
this.close(global.get_current_time());
|
||||
}
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Shell = imports.gi.Shell;
|
||||
@ -10,11 +10,9 @@ const Params = imports.misc.params;
|
||||
const ICON_SIZE = 48;
|
||||
|
||||
|
||||
function BaseIcon(label, createIcon) {
|
||||
this._init(label, createIcon);
|
||||
}
|
||||
const BaseIcon = new Lang.Class({
|
||||
Name: 'BaseIcon',
|
||||
|
||||
BaseIcon.prototype = {
|
||||
_init : function(label, params) {
|
||||
params = Params.parse(params, { createIcon: null,
|
||||
setSizeManually: false,
|
||||
@ -149,13 +147,11 @@ BaseIcon.prototype = {
|
||||
|
||||
this._createIconTexture(size);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function IconGrid(params) {
|
||||
this._init(params);
|
||||
}
|
||||
const IconGrid = new Lang.Class({
|
||||
Name: 'IconGrid',
|
||||
|
||||
IconGrid.prototype = {
|
||||
_init: function(params) {
|
||||
params = Params.parse(params, { rowLimit: null,
|
||||
columnLimit: null,
|
||||
@ -324,4 +320,4 @@ IconGrid.prototype = {
|
||||
visibleItemsCount: function() {
|
||||
return this._grid.get_children().length - this._grid.get_n_skip_paint();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Caribou = imports.gi.Caribou;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
@ -15,9 +15,11 @@ const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
|
||||
const KEYBOARD_SCHEMA = 'org.gnome.shell.keyboard';
|
||||
const SHOW_KEYBOARD = 'show-keyboard';
|
||||
const KEYBOARD_TYPE = 'keyboard-type';
|
||||
|
||||
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
|
||||
const SHOW_KEYBOARD = 'screen-keyboard-enabled';
|
||||
|
||||
// Key constants taken from Antler
|
||||
// FIXME: ought to be moved into libcaribou
|
||||
const PRETTY_KEYS = {
|
||||
@ -37,34 +39,31 @@ const PRETTY_KEYS = {
|
||||
'Alt_L': 'Alt'
|
||||
};
|
||||
|
||||
const CaribouKeyboardIface = {
|
||||
name: 'org.gnome.Caribou.Keyboard',
|
||||
methods: [ { name: 'Show',
|
||||
inSignature: 'u',
|
||||
outSignature: ''
|
||||
},
|
||||
{ name: 'Hide',
|
||||
inSignature: 'u',
|
||||
outSignature: ''
|
||||
},
|
||||
{ name: 'SetCursorLocation',
|
||||
inSignature: 'iiii',
|
||||
outSignature: ''
|
||||
},
|
||||
{ name: 'SetEntryLocation',
|
||||
inSignature: 'iiii',
|
||||
outSignature: ''
|
||||
} ],
|
||||
properties: [ { name: 'Name',
|
||||
signature: 's',
|
||||
access: 'read' } ]
|
||||
};
|
||||
const CaribouKeyboardIface = <interface name='org.gnome.Caribou.Keyboard'>
|
||||
<method name='Show'>
|
||||
<arg type='u' direction='in' />
|
||||
</method>
|
||||
<method name='Hide'>
|
||||
<arg type='u' direction='in' />
|
||||
</method>
|
||||
<method name='SetCursorLocation'>
|
||||
<arg type='i' direction='in' />
|
||||
<arg type='i' direction='in' />
|
||||
<arg type='i' direction='in' />
|
||||
<arg type='i' direction='in' />
|
||||
</method>
|
||||
<method name='SetEntryLocation'>
|
||||
<arg type='i' direction='in' />
|
||||
<arg type='i' direction='in' />
|
||||
<arg type='i' direction='in' />
|
||||
<arg type='i' direction='in' />
|
||||
</method>
|
||||
<property name='Name' access='read' type='s' />
|
||||
</interface>;
|
||||
|
||||
function Key() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
const Key = new Lang.Class({
|
||||
Name: 'Key',
|
||||
|
||||
Key.prototype = {
|
||||
_init : function(key) {
|
||||
this._key = key;
|
||||
|
||||
@ -73,7 +72,7 @@ Key.prototype = {
|
||||
this._extended_keys = this._key.get_extended_keys();
|
||||
this._extended_keyboard = null;
|
||||
|
||||
if (this._key.name == "Control_L" || this._key.name == "Alt_L")
|
||||
if (this._key.name == 'Control_L' || this._key.name == 'Alt_L')
|
||||
this._key.latch = true;
|
||||
|
||||
this._key.connect('key-pressed', Lang.bind(this, function ()
|
||||
@ -190,15 +189,15 @@ Key.prototype = {
|
||||
this._boxPointer.hide(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function Keyboard() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
const Keyboard = new Lang.Class({
|
||||
// HACK: we can't set Name, because it collides with Name dbus property
|
||||
// Name: 'Keyboard',
|
||||
|
||||
Keyboard.prototype = {
|
||||
_init: function () {
|
||||
DBus.session.exportObject('/org/gnome/Caribou/Keyboard', this);
|
||||
this._impl = Gio.DBusExportedObject.wrapJSObject(CaribouKeyboardIface, this);
|
||||
this._impl.export(Gio.DBus.session, '/org/gnome/Caribou/Keyboard');
|
||||
|
||||
this.actor = null;
|
||||
|
||||
@ -207,6 +206,8 @@ Keyboard.prototype = {
|
||||
|
||||
this._keyboardSettings = new Gio.Settings({ schema: KEYBOARD_SCHEMA });
|
||||
this._keyboardSettings.connect('changed', Lang.bind(this, this._settingsChanged));
|
||||
this._a11yApplicationsSettings = new Gio.Settings({ schema: A11Y_APPLICATIONS_SCHEMA });
|
||||
this._a11yApplicationsSettings.connect('changed', Lang.bind(this, this._settingsChanged));
|
||||
this._settingsChanged();
|
||||
},
|
||||
|
||||
@ -214,8 +215,8 @@ Keyboard.prototype = {
|
||||
this._redraw();
|
||||
},
|
||||
|
||||
_settingsChanged: function () {
|
||||
this._enableKeyboard = this._keyboardSettings.get_boolean(SHOW_KEYBOARD);
|
||||
_settingsChanged: function (settings, key) {
|
||||
this._enableKeyboard = this._a11yApplicationsSettings.get_boolean(SHOW_KEYBOARD);
|
||||
if (!this._enableKeyboard && !this._keyboard)
|
||||
return;
|
||||
if (this._enableKeyboard && this._keyboard &&
|
||||
@ -224,9 +225,20 @@ Keyboard.prototype = {
|
||||
|
||||
if (this._keyboard)
|
||||
this._destroyKeyboard();
|
||||
if (this._enableKeyboard)
|
||||
this._setupKeyboard();
|
||||
else
|
||||
|
||||
if (this._enableKeyboard) {
|
||||
// If we've been called because the setting actually just
|
||||
// changed to true (as opposed to being called from
|
||||
// this._init()), then we want to pop up the keyboard.
|
||||
let showKeyboard = (settings != null);
|
||||
|
||||
// However, caribou-gtk-module or this._onKeyFocusChanged
|
||||
// will probably immediately tell us to hide it, so we
|
||||
// have to fake things out so we'll ignore that request.
|
||||
if (showKeyboard)
|
||||
this._timestamp = global.display.get_current_time_roundtrip() + 1;
|
||||
this._setupKeyboard(showKeyboard);
|
||||
} else
|
||||
Main.layoutManager.hideKeyboard(true);
|
||||
},
|
||||
|
||||
@ -242,7 +254,7 @@ Keyboard.prototype = {
|
||||
this._destroySource();
|
||||
},
|
||||
|
||||
_setupKeyboard: function() {
|
||||
_setupKeyboard: function(show) {
|
||||
this.actor = new St.BoxLayout({ name: 'keyboard', vertical: true, reactive: true });
|
||||
Main.layoutManager.keyboardBox.add_actor(this.actor);
|
||||
Main.layoutManager.trackChrome(this.actor);
|
||||
@ -259,21 +271,26 @@ Keyboard.prototype = {
|
||||
|
||||
this._keyboardNotifyId = this._keyboard.connect('notify::active-group', Lang.bind(this, this._onGroupChanged));
|
||||
this._focusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
|
||||
this._createSource();
|
||||
|
||||
if (show)
|
||||
this.show();
|
||||
else
|
||||
this._createSource();
|
||||
},
|
||||
|
||||
_onKeyFocusChanged: function () {
|
||||
let focus = global.stage.key_focus;
|
||||
|
||||
if (focus == global.stage || focus == null)
|
||||
// Showing an extended key popup and clicking a key from the extended keys
|
||||
// will grab focus, but ignore that
|
||||
if (focus && (focus._extended_keys || (focus._key && focus._key.extended_key)))
|
||||
return;
|
||||
|
||||
let time = global.get_current_time();
|
||||
if (focus instanceof Clutter.Text)
|
||||
this.show();
|
||||
else {
|
||||
if (focus._extended_keys == null)
|
||||
this.hide();
|
||||
}
|
||||
this.Show(time);
|
||||
else
|
||||
this.Hide(time);
|
||||
},
|
||||
|
||||
_addKeys: function () {
|
||||
@ -302,7 +319,8 @@ Keyboard.prototype = {
|
||||
},
|
||||
|
||||
_getTrayIcon: function () {
|
||||
let trayButton = new St.Button ({ label: "tray", style_class: 'keyboard-key' });
|
||||
let trayButton = new St.Button ({ label: _("tray"),
|
||||
style_class: 'keyboard-key' });
|
||||
trayButton.key_width = 1;
|
||||
trayButton.connect('button-press-event', Lang.bind(this, function () {
|
||||
Main.messageTray.toggle();
|
||||
@ -336,7 +354,7 @@ Keyboard.prototype = {
|
||||
right_box.add(button.actor);
|
||||
else
|
||||
left_box.add(button.actor);
|
||||
if (key.name == "Caribou_Prefs") {
|
||||
if (key.name == 'Caribou_Prefs') {
|
||||
key.connect('key-released', Lang.bind(this, this.hide));
|
||||
|
||||
// Add new key for hiding message tray
|
||||
@ -473,6 +491,9 @@ Keyboard.prototype = {
|
||||
|
||||
// D-Bus methods
|
||||
Show: function(timestamp) {
|
||||
if (!this._enableKeyboard)
|
||||
return;
|
||||
|
||||
if (timestamp - this._timestamp < 0)
|
||||
return;
|
||||
|
||||
@ -481,6 +502,9 @@ Keyboard.prototype = {
|
||||
},
|
||||
|
||||
Hide: function(timestamp) {
|
||||
if (!this._enableKeyboard)
|
||||
return;
|
||||
|
||||
if (timestamp - this._timestamp < 0)
|
||||
return;
|
||||
|
||||
@ -489,29 +513,31 @@ Keyboard.prototype = {
|
||||
},
|
||||
|
||||
SetCursorLocation: function(x, y, w, h) {
|
||||
this._setLocation(x, y);
|
||||
if (!this._enableKeyboard)
|
||||
return;
|
||||
|
||||
// this._setLocation(x, y);
|
||||
},
|
||||
|
||||
SetEntryLocation: function(x, y, w, h) {
|
||||
this._setLocation(x, y);
|
||||
if (!this._enableKeyboard)
|
||||
return;
|
||||
|
||||
// this._setLocation(x, y);
|
||||
},
|
||||
|
||||
get Name() {
|
||||
return 'gnome-shell';
|
||||
}
|
||||
};
|
||||
DBus.conformExport(Keyboard.prototype, CaribouKeyboardIface);
|
||||
});
|
||||
|
||||
function KeyboardSource() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
KeyboardSource.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
const KeyboardSource = new Lang.Class({
|
||||
Name: 'KeyboardSource',
|
||||
Extends: MessageTray.Source,
|
||||
|
||||
_init: function(keyboard) {
|
||||
this.parent(_("Keyboard"));
|
||||
this._keyboard = keyboard;
|
||||
MessageTray.Source.prototype._init.call(this, _("Keyboard"));
|
||||
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
},
|
||||
@ -522,7 +548,7 @@ KeyboardSource.prototype = {
|
||||
icon_size: this.ICON_SIZE });
|
||||
},
|
||||
|
||||
handleSummaryClick: function() {
|
||||
handleSummaryClick: function() {
|
||||
let event = Clutter.get_current_event();
|
||||
if (event.type() != Clutter.EventType.BUTTON_RELEASE)
|
||||
return false;
|
||||
@ -534,4 +560,4 @@ KeyboardSource.prototype = {
|
||||
open: function() {
|
||||
this._keyboard.show();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
@ -17,11 +17,9 @@ const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
|
||||
const STARTUP_ANIMATION_TIME = 0.2;
|
||||
const KEYBOARD_ANIMATION_TIME = 0.5;
|
||||
|
||||
function LayoutManager() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
const LayoutManager = new Lang.Class({
|
||||
Name: 'LayoutManager',
|
||||
|
||||
LayoutManager.prototype = {
|
||||
_init: function () {
|
||||
this._rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL);
|
||||
this.monitors = [];
|
||||
@ -45,7 +43,9 @@ LayoutManager.prototype = {
|
||||
this.trayBox.connect('allocation-changed',
|
||||
Lang.bind(this, this._updateTrayBarrier));
|
||||
|
||||
this.keyboardBox = new St.BoxLayout({ name: 'keyboardBox' });
|
||||
this.keyboardBox = new St.BoxLayout({ name: 'keyboardBox',
|
||||
reactive: true,
|
||||
track_hover: true });
|
||||
this.addChrome(this.keyboardBox, { visibleInFullscreen: true });
|
||||
this._keyboardHeightNotifyId = 0;
|
||||
|
||||
@ -214,10 +214,10 @@ LayoutManager.prototype = {
|
||||
let monitorLeft = monitor.x, monitorRight = monitor.x + monitor.width;
|
||||
let primaryLeft = primary.x, primaryRight = primary.x + primary.width;
|
||||
|
||||
if ((monitorLeft >= primaryLeft && monitorLeft <= primaryRight) ||
|
||||
(monitorRight >= primaryLeft && monitorRight <= primaryRight) ||
|
||||
(primaryLeft >= monitorLeft && primaryLeft <= monitorRight) ||
|
||||
(primaryRight >= monitorLeft && primaryRight <= monitorRight))
|
||||
if ((monitorLeft >= primaryLeft && monitorLeft < primaryRight) ||
|
||||
(monitorRight > primaryLeft && monitorRight <= primaryRight) ||
|
||||
(primaryLeft >= monitorLeft && primaryLeft < monitorRight) ||
|
||||
(primaryRight > monitorLeft && primaryRight <= monitorRight))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -367,8 +367,12 @@ LayoutManager.prototype = {
|
||||
// Removes @actor from the chrome
|
||||
removeChrome: function(actor) {
|
||||
this._chrome.removeActor(actor);
|
||||
},
|
||||
|
||||
findMonitorForActor: function(actor) {
|
||||
return this._chrome.findMonitorForActor(actor);
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(LayoutManager.prototype);
|
||||
|
||||
|
||||
@ -376,11 +380,9 @@ Signals.addSignalMethods(LayoutManager.prototype);
|
||||
//
|
||||
// This class manages a "hot corner" that can toggle switching to
|
||||
// overview.
|
||||
function HotCorner() {
|
||||
this._init();
|
||||
}
|
||||
const HotCorner = new Lang.Class({
|
||||
Name: 'HotCorner',
|
||||
|
||||
HotCorner.prototype = {
|
||||
_init : function() {
|
||||
// We use this flag to mark the case where the user has entered the
|
||||
// hot corner and has not left both the hot corner and a surrounding
|
||||
@ -542,7 +544,7 @@ HotCorner.prototype = {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
// This manages the shell "chrome"; the UI that's visible in the
|
||||
@ -555,11 +557,9 @@ const defaultParams = {
|
||||
affectsInputRegion: true
|
||||
};
|
||||
|
||||
function Chrome() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
const Chrome = new Lang.Class({
|
||||
Name: 'Chrome',
|
||||
|
||||
Chrome.prototype = {
|
||||
_init: function(layoutManager) {
|
||||
this._layoutManager = layoutManager;
|
||||
|
||||
@ -581,12 +581,13 @@ Chrome.prototype = {
|
||||
|
||||
this._screenSaverActive = false;
|
||||
this._screenSaverProxy = new ScreenSaver.ScreenSaverProxy();
|
||||
this._screenSaverProxy.connect('ActiveChanged', Lang.bind(this, this._onScreenSaverActiveChanged));
|
||||
this._screenSaverProxy.GetActiveRemote(Lang.bind(this,
|
||||
function(result, err) {
|
||||
if (!err)
|
||||
this._onScreenSaverActiveChanged(this._screenSaverProxy, result);
|
||||
}));
|
||||
this._screenSaverProxy.connectSignal('ActiveChanged', Lang.bind(this, function(proxy, senderName, [isActive]) {
|
||||
this._onScreenSaverActiveChanged(isActive);
|
||||
}));
|
||||
this._screenSaverProxy.GetActiveRemote(Lang.bind(this, function(result, err) {
|
||||
if (!err)
|
||||
this._onScreenSaverActiveChanged(result[0]);
|
||||
}));
|
||||
|
||||
this._relayout();
|
||||
},
|
||||
@ -619,7 +620,7 @@ Chrome.prototype = {
|
||||
// We can't use Params.parse here because we want to drop
|
||||
// the extra values like ancestorData.actor
|
||||
for (let prop in defaultParams) {
|
||||
if (!params[prop])
|
||||
if (!params.hasOwnProperty(prop))
|
||||
params[prop] = ancestorData[prop];
|
||||
}
|
||||
|
||||
@ -698,7 +699,7 @@ Chrome.prototype = {
|
||||
else if (this._inOverview)
|
||||
visible = true;
|
||||
else if (!actorData.visibleInFullscreen &&
|
||||
this._findMonitorForActor(actorData.actor).inFullscreen)
|
||||
this.findMonitorForActor(actorData.actor).inFullscreen)
|
||||
visible = false;
|
||||
else
|
||||
visible = true;
|
||||
@ -727,7 +728,7 @@ Chrome.prototype = {
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
_onScreenSaverActiveChanged: function(proxy, screenSaverActive) {
|
||||
_onScreenSaverActiveChanged: function(screenSaverActive) {
|
||||
this._screenSaverActive = screenSaverActive;
|
||||
this._updateVisibility();
|
||||
this._queueUpdateRegions();
|
||||
@ -760,7 +761,7 @@ Chrome.prototype = {
|
||||
|
||||
// This call guarantees that we return some monitor to simplify usage of it
|
||||
// In practice all tracked actors should be visible on some monitor anyway
|
||||
_findMonitorForActor: function(actor) {
|
||||
findMonitorForActor: function(actor) {
|
||||
let [x, y] = actor.get_transformed_position();
|
||||
let [w, h] = actor.get_transformed_size();
|
||||
let monitor = this._findMonitorForRect(x, y, w, h);
|
||||
@ -819,6 +820,18 @@ Chrome.prototype = {
|
||||
monitor.inFullscreen = true;
|
||||
}
|
||||
if (layer == Meta.StackLayer.OVERRIDE_REDIRECT) {
|
||||
// Check whether the window is screen sized
|
||||
let isScreenSized =
|
||||
(window.x == 0 && window.y == 0 &&
|
||||
window.width == global.screen_width &&
|
||||
window.height == global.screen_height);
|
||||
|
||||
if (isScreenSized) {
|
||||
for (let i = 0; i < this._monitors.length; i++)
|
||||
this._monitors[i].inFullscreen = true;
|
||||
}
|
||||
|
||||
// Or whether it is monitor sized
|
||||
let monitor = this._findMonitorForWindow(window);
|
||||
if (monitor &&
|
||||
window.x <= monitor.x &&
|
||||
@ -962,4 +975,4 @@ Chrome.prototype = {
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Meta = imports.gi.Meta;
|
||||
@ -30,11 +30,9 @@ const Tweener = imports.ui.tweener;
|
||||
* @container and will track any changes in its size. You can override
|
||||
* this by passing an explicit width and height in @params.
|
||||
*/
|
||||
function Lightbox(container, params) {
|
||||
this._init(container, params);
|
||||
}
|
||||
const Lightbox = new Lang.Class({
|
||||
Name: 'Lightbox',
|
||||
|
||||
Lightbox.prototype = {
|
||||
_init : function(container, params) {
|
||||
params = Params.parse(params, { inhibitEvents: false,
|
||||
width: null,
|
||||
@ -196,4 +194,4 @@ Lightbox.prototype = {
|
||||
|
||||
this.highlight(null);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,14 +1,12 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
|
||||
function Link(props) {
|
||||
this._init(props);
|
||||
}
|
||||
const Link = new Lang.Class({
|
||||
Name: 'Link',
|
||||
|
||||
Link.prototype = {
|
||||
_init : function(props) {
|
||||
let realProps = { reactive: true,
|
||||
track_hover: true,
|
||||
@ -19,6 +17,5 @@ Link.prototype = {
|
||||
|
||||
this.actor = new St.Button(realProps);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
Signals.addSignalMethods(Link.prototype);
|
||||
|
@ -1,8 +1,7 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Cogl = imports.gi.Cogl;
|
||||
const GConf = imports.gi.GConf;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
@ -17,8 +16,10 @@ const Mainloop = imports.mainloop;
|
||||
const History = imports.misc.history;
|
||||
const ExtensionSystem = imports.ui.extensionSystem;
|
||||
const Link = imports.ui.link;
|
||||
const ShellEntry = imports.ui.shellEntry;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Main = imports.ui.main;
|
||||
const JsParse = imports.misc.jsParse;
|
||||
|
||||
/* Imports...feel free to add here as needed */
|
||||
var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
|
||||
@ -40,12 +41,88 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
|
||||
'const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); ';
|
||||
|
||||
const HISTORY_KEY = 'looking-glass-history';
|
||||
// Time between tabs for them to count as a double-tab event
|
||||
const AUTO_COMPLETE_DOUBLE_TAB_DELAY = 500;
|
||||
const AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION = 0.2;
|
||||
const AUTO_COMPLETE_GLOBAL_KEYWORDS = _getAutoCompleteGlobalKeywords();
|
||||
|
||||
function Notebook() {
|
||||
this._init();
|
||||
function _getAutoCompleteGlobalKeywords() {
|
||||
const keywords = ['true', 'false', 'null', 'new'];
|
||||
// Don't add the private properties of window (i.e., ones starting with '_')
|
||||
const windowProperties = Object.getOwnPropertyNames(window).filter(function(a){ return a.charAt(0) != '_' });
|
||||
const headerProperties = JsParse.getDeclaredConstants(commandHeader);
|
||||
|
||||
return keywords.concat(windowProperties).concat(headerProperties);
|
||||
}
|
||||
|
||||
Notebook.prototype = {
|
||||
const AutoComplete = new Lang.Class({
|
||||
Name: 'AutoComplete',
|
||||
|
||||
_init: function(entry) {
|
||||
this._entry = entry;
|
||||
this._entry.connect('key-press-event', Lang.bind(this, this._entryKeyPressEvent));
|
||||
this._lastTabTime = global.get_current_time();
|
||||
},
|
||||
|
||||
_processCompletionRequest: function(event) {
|
||||
if (event.completions.length == 0) {
|
||||
return;
|
||||
}
|
||||
// Unique match = go ahead and complete; multiple matches + single tab = complete the common starting string;
|
||||
// multiple matches + double tab = emit a suggest event with all possible options
|
||||
if (event.completions.length == 1) {
|
||||
this.additionalCompletionText(event.completions[0], event.attrHead);
|
||||
this.emit('completion', { completion: event.completions[0], type: 'whole-word' });
|
||||
} else if (event.completions.length > 1 && event.tabType === 'single') {
|
||||
let commonPrefix = JsParse.getCommonPrefix(event.completions);
|
||||
|
||||
if (commonPrefix.length > 0) {
|
||||
this.additionalCompletionText(commonPrefix, event.attrHead);
|
||||
this.emit('completion', { completion: commonPrefix, type: 'prefix' });
|
||||
this.emit('suggest', { completions: event.completions});
|
||||
}
|
||||
} else if (event.completions.length > 1 && event.tabType === 'double') {
|
||||
this.emit('suggest', { completions: event.completions});
|
||||
}
|
||||
},
|
||||
|
||||
_entryKeyPressEvent: function(actor, event) {
|
||||
let cursorPos = this._entry.clutter_text.get_cursor_position();
|
||||
let text = this._entry.get_text();
|
||||
if (cursorPos != -1) {
|
||||
text = text.slice(0, cursorPos);
|
||||
}
|
||||
if (event.get_key_symbol() == Clutter.Tab) {
|
||||
let [completions, attrHead] = JsParse.getCompletions(text, commandHeader, AUTO_COMPLETE_GLOBAL_KEYWORDS);
|
||||
let currTime = global.get_current_time();
|
||||
if ((currTime - this._lastTabTime) < AUTO_COMPLETE_DOUBLE_TAB_DELAY) {
|
||||
this._processCompletionRequest({ tabType: 'double',
|
||||
completions: completions,
|
||||
attrHead: attrHead });
|
||||
} else {
|
||||
this._processCompletionRequest({ tabType: 'single',
|
||||
completions: completions,
|
||||
attrHead: attrHead });
|
||||
}
|
||||
this._lastTabTime = currTime;
|
||||
}
|
||||
},
|
||||
|
||||
// Insert characters of text not already included in head at cursor position. i.e., if text="abc" and head="a",
|
||||
// the string "bc" will be appended to this._entry
|
||||
additionalCompletionText: function(text, head) {
|
||||
let additionalCompletionText = text.slice(head.length);
|
||||
let cursorPos = this._entry.clutter_text.get_cursor_position();
|
||||
|
||||
this._entry.clutter_text.insert_text(additionalCompletionText, cursorPos);
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(AutoComplete.prototype);
|
||||
|
||||
|
||||
const Notebook = new Lang.Class({
|
||||
Name: 'Notebook',
|
||||
|
||||
_init: function() {
|
||||
this.actor = new St.BoxLayout({ vertical: true });
|
||||
|
||||
@ -150,25 +227,40 @@ Notebook.prototype = {
|
||||
return;
|
||||
let vAdjust = tabData.scrollView.vscroll.adjustment;
|
||||
vAdjust.value = vAdjust.upper - vAdjust.page_size;
|
||||
},
|
||||
|
||||
nextTab: function() {
|
||||
let nextIndex = this._selectedIndex;
|
||||
if (nextIndex < this._tabs.length - 1) {
|
||||
++nextIndex;
|
||||
}
|
||||
|
||||
this.selectIndex(nextIndex);
|
||||
},
|
||||
|
||||
prevTab: function() {
|
||||
let prevIndex = this._selectedIndex;
|
||||
if (prevIndex > 0) {
|
||||
--prevIndex;
|
||||
}
|
||||
|
||||
this.selectIndex(prevIndex);
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(Notebook.prototype);
|
||||
|
||||
function objectToString(o) {
|
||||
if (typeof(o) == typeof(objectToString)) {
|
||||
// special case this since the default is way, way too verbose
|
||||
return "<js function>";
|
||||
return '<js function>';
|
||||
} else {
|
||||
return "" + o;
|
||||
return '' + o;
|
||||
}
|
||||
}
|
||||
|
||||
function ObjLink(o, title) {
|
||||
this._init(o, title);
|
||||
}
|
||||
|
||||
ObjLink.prototype = {
|
||||
__proto__: Link.Link,
|
||||
const ObjLink = new Lang.Class({
|
||||
Name: 'ObjLink',
|
||||
Extends: Link.Link,
|
||||
|
||||
_init: function(o, title) {
|
||||
let text;
|
||||
@ -178,7 +270,8 @@ ObjLink.prototype = {
|
||||
text = objectToString(o);
|
||||
text = GLib.markup_escape_text(text, -1);
|
||||
this._obj = o;
|
||||
Link.Link.prototype._init.call(this, { label: text });
|
||||
|
||||
this.parent({ label: text });
|
||||
this.actor.get_child().single_line_mode = true;
|
||||
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||
},
|
||||
@ -186,13 +279,11 @@ ObjLink.prototype = {
|
||||
_onClicked: function (link) {
|
||||
Main.lookingGlass.inspectObject(this._obj, this.actor);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function Result(command, o, index) {
|
||||
this._init(command, o, index);
|
||||
}
|
||||
const Result = new Lang.Class({
|
||||
Name: 'Result',
|
||||
|
||||
Result.prototype = {
|
||||
_init : function(command, o, index) {
|
||||
this.index = index;
|
||||
this.o = o;
|
||||
@ -214,13 +305,11 @@ Result.prototype = {
|
||||
padBin.add_actor(line);
|
||||
this.actor.add(padBin);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function WindowList() {
|
||||
this._init();
|
||||
}
|
||||
const WindowList = new Lang.Class({
|
||||
Name: 'WindowList',
|
||||
|
||||
WindowList.prototype = {
|
||||
_init : function () {
|
||||
this.actor = new St.BoxLayout({ name: 'Windows', vertical: true, style: 'spacing: 8px' });
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
@ -261,14 +350,12 @@ WindowList.prototype = {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(WindowList.prototype);
|
||||
|
||||
function ObjInspector() {
|
||||
this._init();
|
||||
}
|
||||
const ObjInspector = new Lang.Class({
|
||||
Name: 'ObjInspector',
|
||||
|
||||
ObjInspector.prototype = {
|
||||
_init : function () {
|
||||
this._obj = null;
|
||||
this._previousObj = null;
|
||||
@ -322,7 +409,7 @@ ObjInspector.prototype = {
|
||||
link = new St.Label({ text: '<error>' });
|
||||
}
|
||||
let hbox = new St.BoxLayout();
|
||||
let propText = propName + ": " + valueStr;
|
||||
let propText = propName + ': ' + valueStr;
|
||||
hbox.add(new St.Label({ text: propName + ': ' }));
|
||||
hbox.add(link);
|
||||
this._container.add_actor(hbox);
|
||||
@ -343,7 +430,7 @@ ObjInspector.prototype = {
|
||||
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,
|
||||
transition: "easeOutQuad",
|
||||
transition: 'easeOutQuad',
|
||||
time: 0.2 });
|
||||
} else {
|
||||
this.actor.set_scale(1, 1);
|
||||
@ -368,7 +455,7 @@ ObjInspector.prototype = {
|
||||
_onBack: function() {
|
||||
this.selectObject(this._previousObj, true);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function addBorderPaintHook(actor) {
|
||||
let signalId = actor.connect_after('paint',
|
||||
@ -394,11 +481,9 @@ function addBorderPaintHook(actor) {
|
||||
return signalId;
|
||||
}
|
||||
|
||||
function Inspector() {
|
||||
this._init();
|
||||
}
|
||||
const Inspector = new Lang.Class({
|
||||
Name: 'Inspector',
|
||||
|
||||
Inspector.prototype = {
|
||||
_init: function() {
|
||||
let container = new Shell.GenericContainer({ width: 0,
|
||||
height: 0 });
|
||||
@ -537,15 +622,13 @@ Inspector.prototype = {
|
||||
this._borderPaintId = addBorderPaintHook(this._target);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Signals.addSignalMethods(Inspector.prototype);
|
||||
|
||||
function ErrorLog() {
|
||||
this._init();
|
||||
}
|
||||
const ErrorLog = new Lang.Class({
|
||||
Name: 'ErrorLog',
|
||||
|
||||
ErrorLog.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new St.BoxLayout();
|
||||
this.text = new St.Label();
|
||||
@ -580,13 +663,11 @@ ErrorLog.prototype = {
|
||||
}
|
||||
this.text.text = text;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function Memory() {
|
||||
this._init();
|
||||
}
|
||||
const Memory = new Lang.Class({
|
||||
Name: 'Memory',
|
||||
|
||||
Memory.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new St.BoxLayout({ vertical: true });
|
||||
this._glibc_uordblks = new St.Label();
|
||||
@ -607,6 +688,9 @@ Memory.prototype = {
|
||||
this._gjs_closure = new St.Label();
|
||||
this.actor.add(this._gjs_closure);
|
||||
|
||||
this._last_gc_seconds_ago = new St.Label();
|
||||
this.actor.add(this._last_gc_seconds_ago);
|
||||
|
||||
this._gcbutton = new St.Button({ label: 'Full GC',
|
||||
style_class: 'lg-obj-inspector-button' });
|
||||
this._gcbutton.connect('clicked', Lang.bind(this, function () { global.gc(); this._renderText(); }));
|
||||
@ -626,14 +710,13 @@ Memory.prototype = {
|
||||
this._gjs_gobject.text = 'gjs_gobject: ' + memInfo.gjs_gobject;
|
||||
this._gjs_function.text = 'gjs_function: ' + memInfo.gjs_function;
|
||||
this._gjs_closure.text = 'gjs_closure: ' + memInfo.gjs_closure;
|
||||
this._last_gc_seconds_ago.text = 'last_gc_seconds_ago: ' + memInfo.last_gc_seconds_ago;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function Extensions() {
|
||||
this._init();
|
||||
}
|
||||
const Extensions = new Lang.Class({
|
||||
Name: 'Extensions',
|
||||
|
||||
Extensions.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new St.BoxLayout({ vertical: true,
|
||||
name: 'lookingGlassExtensions' });
|
||||
@ -681,11 +764,40 @@ Extensions.prototype = {
|
||||
Main.lookingGlass.close();
|
||||
},
|
||||
|
||||
_onViewErrors: function (actor) {
|
||||
let meta = actor._extensionMeta;
|
||||
let shouldShow = !actor._isShowing;
|
||||
|
||||
if (shouldShow) {
|
||||
let errors = ExtensionSystem.errors[meta.uuid];
|
||||
let errorDisplay = new St.BoxLayout({ vertical: true });
|
||||
if (errors && errors.length) {
|
||||
for (let i = 0; i < errors.length; i ++)
|
||||
errorDisplay.add(new St.Label({ text: errors[i] }));
|
||||
} else {
|
||||
/* Translators: argument is an extension UUID. */
|
||||
let message = _("%s has not emitted any errors.").format(meta.uuid);
|
||||
errorDisplay.add(new St.Label({ text: message }));
|
||||
}
|
||||
|
||||
actor._errorDisplay = errorDisplay;
|
||||
actor._parentBox.add(errorDisplay);
|
||||
actor.label = _("Hide Errors");
|
||||
} else {
|
||||
actor._errorDisplay.destroy();
|
||||
actor._errorDisplay = null;
|
||||
actor.label = _("Show Errors");
|
||||
}
|
||||
|
||||
actor._isShowing = shouldShow;
|
||||
},
|
||||
|
||||
_stateToString: function(extensionState) {
|
||||
switch (extensionState) {
|
||||
case ExtensionSystem.ExtensionState.ENABLED:
|
||||
return _("Enabled");
|
||||
case ExtensionSystem.ExtensionState.DISABLED:
|
||||
case ExtensionSystem.ExtensionState.INITIALIZED:
|
||||
return _("Disabled");
|
||||
case ExtensionSystem.ExtensionState.ERROR:
|
||||
return _("Error");
|
||||
@ -706,38 +818,39 @@ Extensions.prototype = {
|
||||
text: meta.description || 'No description' });
|
||||
box.add(description, { expand: true });
|
||||
|
||||
let metaBox = new St.BoxLayout();
|
||||
let metaBox = new St.BoxLayout({ style_class: 'lg-extension-meta' });
|
||||
box.add(metaBox);
|
||||
let stateString = this._stateToString(meta.state);
|
||||
let state = new St.Label({ style_class: 'lg-extension-state',
|
||||
text: this._stateToString(meta.state) });
|
||||
|
||||
let actionsContainer = new St.Bin({ x_align: St.Align.END });
|
||||
metaBox.add(actionsContainer);
|
||||
let actionsBox = new St.BoxLayout({ style_class: 'lg-extension-actions' });
|
||||
actionsContainer.set_child(actionsBox);
|
||||
metaBox.add(state);
|
||||
|
||||
let viewsource = new Link.Link({ label: _("View Source") });
|
||||
viewsource.actor._extensionMeta = meta;
|
||||
viewsource.actor.connect('clicked', Lang.bind(this, this._onViewSource));
|
||||
actionsBox.add(viewsource.actor);
|
||||
metaBox.add(viewsource.actor);
|
||||
|
||||
if (meta.url) {
|
||||
let webpage = new Link.Link({ label: _("Web Page") });
|
||||
webpage.actor._extensionMeta = meta;
|
||||
webpage.actor.connect('clicked', Lang.bind(this, this._onWebPage));
|
||||
actionsBox.add(webpage.actor);
|
||||
metaBox.add(webpage.actor);
|
||||
}
|
||||
|
||||
let viewerrors = new Link.Link({ label: _("Show Errors") });
|
||||
viewerrors.actor._extensionMeta = meta;
|
||||
viewerrors.actor._parentBox = box;
|
||||
viewerrors.actor._isShowing = false;
|
||||
viewerrors.actor.connect('clicked', Lang.bind(this, this._onViewErrors));
|
||||
metaBox.add(viewerrors.actor);
|
||||
|
||||
return box;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function LookingGlass() {
|
||||
this._init();
|
||||
}
|
||||
const LookingGlass = new Lang.Class({
|
||||
Name: 'LookingGlass',
|
||||
|
||||
LookingGlass.prototype = {
|
||||
_init : function() {
|
||||
this._borderPaintTarget = null;
|
||||
this._borderPaintId = 0;
|
||||
@ -754,7 +867,8 @@ LookingGlass.prototype = {
|
||||
this.actor = new St.BoxLayout({ name: 'LookingGlassDialog',
|
||||
style_class: 'lg-dialog',
|
||||
vertical: true,
|
||||
visible: false });
|
||||
visible: false,
|
||||
reactive: true });
|
||||
this.actor.connect('key-press-event', Lang.bind(this, this._globalKeyPressEvent));
|
||||
|
||||
this._interfaceSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
|
||||
@ -809,14 +923,15 @@ LookingGlass.prototype = {
|
||||
this._resultsArea = new St.BoxLayout({ name: 'ResultsArea', vertical: true });
|
||||
this._evalBox.add(this._resultsArea, { expand: true });
|
||||
|
||||
let entryArea = new St.BoxLayout({ name: 'EntryArea' });
|
||||
this._evalBox.add_actor(entryArea);
|
||||
this._entryArea = new St.BoxLayout({ name: 'EntryArea' });
|
||||
this._evalBox.add_actor(this._entryArea);
|
||||
|
||||
let label = new St.Label({ text: 'js>>> ' });
|
||||
entryArea.add(label);
|
||||
this._entryArea.add(label);
|
||||
|
||||
this._entry = new St.Entry({ can_focus: true });
|
||||
entryArea.add(this._entry, { expand: true });
|
||||
ShellEntry.addContextMenu(this._entry);
|
||||
this._entryArea.add(this._entry, { expand: true });
|
||||
|
||||
this._windowList = new WindowList();
|
||||
this._windowList.connect('selected', Lang.bind(this, function(list, window) {
|
||||
@ -835,6 +950,9 @@ LookingGlass.prototype = {
|
||||
notebook.appendPage('Extensions', this._extensions.actor);
|
||||
|
||||
this._entry.clutter_text.connect('activate', Lang.bind(this, function (o, e) {
|
||||
// Hide any completions we are currently showing
|
||||
this._hideCompletions();
|
||||
|
||||
let text = o.get_text();
|
||||
// Ensure we don't get newlines in the command; the history file is
|
||||
// newline-separated.
|
||||
@ -850,6 +968,17 @@ LookingGlass.prototype = {
|
||||
this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY,
|
||||
entry: this._entry.clutter_text });
|
||||
|
||||
this._autoComplete = new AutoComplete(this._entry);
|
||||
this._autoComplete.connect('suggest', Lang.bind(this, function(a,e) {
|
||||
this._showCompletions(e.completions);
|
||||
}));
|
||||
// If a completion is completed unambiguously, the currently-displayed completion
|
||||
// suggestions become irrelevant.
|
||||
this._autoComplete.connect('completion', Lang.bind(this, function(a,e) {
|
||||
if (e.type == 'whole-word')
|
||||
this._hideCompletions();
|
||||
}));
|
||||
|
||||
this._resize();
|
||||
},
|
||||
|
||||
@ -894,6 +1023,59 @@ LookingGlass.prototype = {
|
||||
this._notebook.scrollToBottom(0);
|
||||
},
|
||||
|
||||
_showCompletions: function(completions) {
|
||||
if (!this._completionActor) {
|
||||
let actor = new St.BoxLayout({ vertical: true });
|
||||
|
||||
this._completionText = new St.Label({ name: 'LookingGlassAutoCompletionText', style_class: 'lg-completions-text' });
|
||||
this._completionText.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
this._completionText.clutter_text.line_wrap = true;
|
||||
actor.add(this._completionText);
|
||||
|
||||
let line = new Clutter.Rectangle();
|
||||
let padBin = new St.Bin({ x_fill: true, y_fill: true });
|
||||
padBin.add_actor(line);
|
||||
actor.add(padBin);
|
||||
|
||||
this._completionActor = actor;
|
||||
this._evalBox.insert_before(this._completionActor, this._entryArea);
|
||||
}
|
||||
|
||||
this._completionText.set_text(completions.join(', '));
|
||||
|
||||
// Setting the height to -1 allows us to get its actual preferred height rather than
|
||||
// whatever was last given in set_height by Tweener.
|
||||
this._completionActor.set_height(-1);
|
||||
let [minHeight, naturalHeight] = this._completionText.get_preferred_height(this._resultsArea.get_width());
|
||||
|
||||
// Don't reanimate if we are already visible
|
||||
if (this._completionActor.visible) {
|
||||
this._completionActor.height = naturalHeight;
|
||||
} else {
|
||||
this._completionActor.show();
|
||||
Tweener.removeTweens(this._completionActor);
|
||||
Tweener.addTween(this._completionActor, { time: AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION / St.get_slow_down_factor(),
|
||||
transition: 'easeOutQuad',
|
||||
height: naturalHeight,
|
||||
opacity: 255
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_hideCompletions: function() {
|
||||
if (this._completionActor) {
|
||||
Tweener.removeTweens(this._completionActor);
|
||||
Tweener.addTween(this._completionActor, { time: AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION / St.get_slow_down_factor(),
|
||||
transition: 'easeOutQuad',
|
||||
height: 0,
|
||||
opacity: 0,
|
||||
onComplete: Lang.bind(this, function () {
|
||||
this._completionActor.hide();
|
||||
})
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_evaluate : function(command) {
|
||||
this._history.addItem(command);
|
||||
|
||||
@ -958,6 +1140,7 @@ LookingGlass.prototype = {
|
||||
// Handle key events which are relevant for all tabs of the LookingGlass
|
||||
_globalKeyPressEvent : function(actor, event) {
|
||||
let symbol = event.get_key_symbol();
|
||||
let modifierState = Shell.get_event_state(event);
|
||||
if (symbol == Clutter.Escape) {
|
||||
if (this._objInspector.actor.visible) {
|
||||
this._objInspector.close();
|
||||
@ -966,6 +1149,14 @@ LookingGlass.prototype = {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Ctrl+PgUp and Ctrl+PgDown switches tabs in the notebook view
|
||||
if (modifierState & Clutter.ModifierType.CONTROL_MASK) {
|
||||
if (symbol == Clutter.KEY_Page_Up) {
|
||||
this._notebook.prevTab();
|
||||
} else if (symbol == Clutter.KEY_Page_Down) {
|
||||
this._notebook.nextTab();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
@ -1016,5 +1207,5 @@ LookingGlass.prototype = {
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(LookingGlass.prototype);
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GDesktopEnums = imports.gi.GDesktopEnums;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
@ -12,22 +13,6 @@ const Main = imports.ui.main;
|
||||
const MagnifierDBus = imports.ui.magnifierDBus;
|
||||
const Params = imports.misc.params;
|
||||
|
||||
// Keep enums in sync with GSettings schemas
|
||||
const MouseTrackingMode = {
|
||||
NONE: 0,
|
||||
CENTERED: 1,
|
||||
PROPORTIONAL: 2,
|
||||
PUSH: 3
|
||||
};
|
||||
|
||||
const ScreenPosition = {
|
||||
NONE: 0,
|
||||
FULL_SCREEN: 1,
|
||||
TOP_HALF: 2,
|
||||
BOTTOM_HALF: 3,
|
||||
LEFT_HALF: 4,
|
||||
RIGHT_HALF: 5
|
||||
};
|
||||
|
||||
const MOUSE_POLL_FREQUENCY = 50;
|
||||
const CROSSHAIRS_CLIP_SIZE = [100, 100];
|
||||
@ -51,11 +36,9 @@ const CROSS_HAIRS_CLIP_KEY = 'cross-hairs-clip';
|
||||
|
||||
let magDBusService = null;
|
||||
|
||||
function Magnifier() {
|
||||
this._init();
|
||||
}
|
||||
const Magnifier = new Lang.Class({
|
||||
Name: 'Magnifier',
|
||||
|
||||
Magnifier.prototype = {
|
||||
_init: function() {
|
||||
// Magnifier is a manager of ZoomRegions.
|
||||
this._zoomRegions = [];
|
||||
@ -520,7 +503,7 @@ Magnifier.prototype = {
|
||||
if (this._zoomRegions.length) {
|
||||
let position = this._settings.get_enum(SCREEN_POSITION_KEY);
|
||||
this._zoomRegions[0].setScreenPosition(position);
|
||||
if (position != ScreenPosition.FULL_SCREEN)
|
||||
if (position != GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN)
|
||||
this._updateLensMode();
|
||||
}
|
||||
},
|
||||
@ -558,21 +541,19 @@ Magnifier.prototype = {
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(Magnifier.prototype);
|
||||
|
||||
function ZoomRegion(magnifier, mouseSourceActor) {
|
||||
this._init(magnifier, mouseSourceActor);
|
||||
}
|
||||
const ZoomRegion = new Lang.Class({
|
||||
Name: 'ZoomRegion',
|
||||
|
||||
ZoomRegion.prototype = {
|
||||
_init: function(magnifier, mouseSourceActor) {
|
||||
this._magnifier = magnifier;
|
||||
|
||||
this._mouseTrackingMode = MouseTrackingMode.NONE;
|
||||
this._mouseTrackingMode = GDesktopEnums.MagnifierMouseTrackingMode.NONE;
|
||||
this._clampScrollingAtEdges = false;
|
||||
this._lensMode = false;
|
||||
this._screenPosition = ScreenPosition.FULL_SCREEN;
|
||||
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN;
|
||||
|
||||
this._magView = null;
|
||||
this._uiGroupClone = null;
|
||||
@ -647,7 +628,8 @@ ZoomRegion.prototype = {
|
||||
* @mode: One of the enum MouseTrackingMode values.
|
||||
*/
|
||||
setMouseTrackingMode: function(mode) {
|
||||
if (mode >= MouseTrackingMode.NONE && mode <= MouseTrackingMode.PUSH)
|
||||
if (mode >= GDesktopEnums.MagnifierMouseTrackingMode.NONE &&
|
||||
mode <= GDesktopEnums.MagnifierMouseTrackingMode.PUSH)
|
||||
this._mouseTrackingMode = mode;
|
||||
},
|
||||
|
||||
@ -668,7 +650,7 @@ ZoomRegion.prototype = {
|
||||
*/
|
||||
setViewPort: function(viewPort) {
|
||||
this._setViewPort(viewPort);
|
||||
this._screenPosition = ScreenPosition.NONE;
|
||||
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.NONE;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -750,7 +732,7 @@ ZoomRegion.prototype = {
|
||||
viewPort.width = global.screen_width;
|
||||
viewPort.height = global.screen_height/2;
|
||||
this._setViewPort(viewPort);
|
||||
this._screenPosition = ScreenPosition.TOP_HALF;
|
||||
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.TOP_HALF;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -764,7 +746,7 @@ ZoomRegion.prototype = {
|
||||
viewPort.width = global.screen_width;
|
||||
viewPort.height = global.screen_height/2;
|
||||
this._setViewPort(viewPort);
|
||||
this._screenPosition = ScreenPosition.BOTTOM_HALF;
|
||||
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.BOTTOM_HALF;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -778,7 +760,7 @@ ZoomRegion.prototype = {
|
||||
viewPort.width = global.screen_width/2;
|
||||
viewPort.height = global.screen_height;
|
||||
this._setViewPort(viewPort);
|
||||
this._screenPosition = ScreenPosition.LEFT_HALF;
|
||||
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.LEFT_HALF;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -792,7 +774,7 @@ ZoomRegion.prototype = {
|
||||
viewPort.width = global.screen_width/2;
|
||||
viewPort.height = global.screen_height;
|
||||
this._setViewPort(viewPort);
|
||||
this._screenPosition = ScreenPosition.RIGHT_HALF;
|
||||
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.RIGHT_HALF;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -808,7 +790,7 @@ ZoomRegion.prototype = {
|
||||
viewPort.height = global.screen_height;
|
||||
this.setViewPort(viewPort);
|
||||
|
||||
this._screenPosition = ScreenPosition.FULL_SCREEN;
|
||||
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -821,19 +803,19 @@ ZoomRegion.prototype = {
|
||||
*/
|
||||
setScreenPosition: function(inPosition) {
|
||||
switch (inPosition) {
|
||||
case ScreenPosition.FULL_SCREEN:
|
||||
case GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN:
|
||||
this.setFullScreenMode();
|
||||
break;
|
||||
case ScreenPosition.TOP_HALF:
|
||||
case GDesktopEnums.MagnifierScreenPosition.TOP_HALF:
|
||||
this.setTopHalf();
|
||||
break;
|
||||
case ScreenPosition.BOTTOM_HALF:
|
||||
case GDesktopEnums.MagnifierScreenPosition.BOTTOM_HALF:
|
||||
this.setBottomHalf();
|
||||
break;
|
||||
case ScreenPosition.LEFT_HALF:
|
||||
case GDesktopEnums.MagnifierScreenPosition.LEFT_HALF:
|
||||
this.setLeftHalf();
|
||||
break;
|
||||
case ScreenPosition.RIGHT_HALF:
|
||||
case GDesktopEnums.MagnifierScreenPosition.RIGHT_HALF:
|
||||
this.setRightHalf();
|
||||
break;
|
||||
}
|
||||
@ -856,7 +838,7 @@ ZoomRegion.prototype = {
|
||||
*/
|
||||
scrollToMousePos: function() {
|
||||
this._followingCursor = true;
|
||||
if (this._mouseTrackingMode != MouseTrackingMode.NONE)
|
||||
if (this._mouseTrackingMode != GDesktopEnums.MagnifierMouseTrackingMode.NONE)
|
||||
this._changeROI({ redoCursorTracking: true });
|
||||
else
|
||||
this._updateMousePosition();
|
||||
@ -991,7 +973,7 @@ ZoomRegion.prototype = {
|
||||
this._yMagFactor = params.yMagFactor;
|
||||
|
||||
if (params.redoCursorTracking &&
|
||||
this._mouseTrackingMode != MouseTrackingMode.NONE) {
|
||||
this._mouseTrackingMode != GDesktopEnums.MagnifierMouseTrackingMode.NONE) {
|
||||
// This depends on this.xMagFactor/yMagFactor already being updated
|
||||
[params.xCenter, params.yCenter] = this._centerFromMousePosition();
|
||||
}
|
||||
@ -1041,7 +1023,7 @@ ZoomRegion.prototype = {
|
||||
_isFullScreen: function() {
|
||||
// Does the magnified view occupy the whole screen? Note that this
|
||||
// doesn't necessarily imply
|
||||
// this._screenPosition = ScreenPosition.FULL_SCREEN;
|
||||
// this._screenPosition = GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN;
|
||||
|
||||
if (this._viewPortX != 0 || this._viewPortY != 0)
|
||||
return false;
|
||||
@ -1058,13 +1040,13 @@ ZoomRegion.prototype = {
|
||||
let xMouse = this._magnifier.xMouse;
|
||||
let yMouse = this._magnifier.yMouse;
|
||||
|
||||
if (this._mouseTrackingMode == MouseTrackingMode.PROPORTIONAL) {
|
||||
if (this._mouseTrackingMode == GDesktopEnums.MagnifierMouseTrackingMode.PROPORTIONAL) {
|
||||
return this._centerFromMouseProportional(xMouse, yMouse);
|
||||
}
|
||||
else if (this._mouseTrackingMode == MouseTrackingMode.PUSH) {
|
||||
else if (this._mouseTrackingMode == GDesktopEnums.MagnifierMouseTrackingMode.PUSH) {
|
||||
return this._centerFromMousePush(xMouse, yMouse);
|
||||
}
|
||||
else if (this._mouseTrackingMode == MouseTrackingMode.CENTERED) {
|
||||
else if (this._mouseTrackingMode == GDesktopEnums.MagnifierMouseTrackingMode.CENTERED) {
|
||||
return this._centerFromMouseCentered(xMouse, yMouse);
|
||||
}
|
||||
|
||||
@ -1164,13 +1146,11 @@ ZoomRegion.prototype = {
|
||||
yMagMouse - groupHeight / 2);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function Crosshairs() {
|
||||
this._init();
|
||||
}
|
||||
const Crosshairs = new Lang.Class({
|
||||
Name: 'Crosshairs',
|
||||
|
||||
Crosshairs.prototype = {
|
||||
_init: function() {
|
||||
|
||||
// Set the group containing the crosshairs to three times the desktop
|
||||
@ -1426,4 +1406,4 @@ Crosshairs.prototype = {
|
||||
this._vertTopHair.set_position((groupWidth - thickness) / 2, top);
|
||||
this._vertBottomHair.set_position((groupWidth - thickness) / 2, bottom);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const DBus = imports.dbus;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const MAG_SERVICE_NAME = 'org.gnome.Magnifier';
|
||||
@ -10,61 +11,99 @@ const ZOOM_SERVICE_PATH = '/org/gnome/Magnifier/ZoomRegion';
|
||||
|
||||
// Subset of gnome-mag's Magnifier dbus interface -- to be expanded. See:
|
||||
// http://git.gnome.org/browse/gnome-mag/tree/xml/...Magnifier.xml
|
||||
const MagnifierIface = {
|
||||
name: MAG_SERVICE_NAME,
|
||||
methods: [
|
||||
{ name: 'setActive', inSignature: 'b', outSignature: '' },
|
||||
{ name: 'isActive', inSignature: '', outSignature: 'b' },
|
||||
{ name: 'showCursor', inSignature: '', outSignature: '' },
|
||||
{ name: 'hideCursor', inSignature: '', outSignature: '' },
|
||||
{ name: 'createZoomRegion', inSignature: 'ddaiai', outSignature: 'o' },
|
||||
{ name: 'addZoomRegion', inSignature: 'o', outSignature: 'b' },
|
||||
{ name: 'getZoomRegions', inSignature: '', outSignature: 'ao' },
|
||||
{ name: 'clearAllZoomRegions', inSignature: '', outSignature: '' },
|
||||
{ name: 'fullScreenCapable', inSignature: '', outSignature: 'b' },
|
||||
|
||||
{ name: 'setCrosswireSize', inSignature: 'i', outSignature: '' },
|
||||
{ name: 'getCrosswireSize', inSignature: '', outSignature: 'i' },
|
||||
{ name: 'setCrosswireLength', inSignature: 'i', outSignature: '' },
|
||||
{ name: 'getCrosswireLength', inSignature: '', outSignature: 'i' },
|
||||
{ name: 'setCrosswireClip', inSignature: 'b', outSignature: '' },
|
||||
{ name: 'getCrosswireClip', inSignature: '', outSignature: 'b' },
|
||||
{ name: 'setCrosswireColor', inSignature: 'u', outSignature: '' },
|
||||
{ name: 'getCrosswireColor', inSignature: '', outSignature: 'u' }
|
||||
],
|
||||
signals: [],
|
||||
properties: []
|
||||
};
|
||||
const MagnifierIface = <interface name={MAG_SERVICE_NAME}>
|
||||
<method name="setActive">
|
||||
<arg type="b" direction="in" />
|
||||
</method>
|
||||
<method name="isActive">
|
||||
<arg type="b" direction="out" />
|
||||
</method>
|
||||
<method name="showCursor" />
|
||||
<method name="hideCursor" />
|
||||
<method name="createZoomRegion">
|
||||
<arg type="d" direction="in" />
|
||||
<arg type="d" direction="in" />
|
||||
<arg type="ai" direction="in" />
|
||||
<arg type="ai" direction="in" />
|
||||
<arg type="o" direction="out" />
|
||||
</method>
|
||||
<method name="addZoomRegion">
|
||||
<arg type="o" direction="in" />
|
||||
<arg type="b" direction="out" />
|
||||
</method>
|
||||
<method name="getZoomRegions">
|
||||
<arg type="ao" direction="out" />
|
||||
</method>
|
||||
<method name="clearAllZoomRegions" />
|
||||
<method name="fullScreenCapable">
|
||||
<arg type="b" direction="out" />
|
||||
</method>
|
||||
<method name="setCrosswireSize">
|
||||
<arg type="i" direction="in" />
|
||||
</method>
|
||||
<method name="getCrosswireSize">
|
||||
<arg type="i" direction="out" />
|
||||
</method>
|
||||
<method name="setCrosswireLength">
|
||||
<arg type="i" direction="in" />
|
||||
</method>
|
||||
<method name="getCrosswireLength">
|
||||
<arg type="i" direction="out" />
|
||||
</method>
|
||||
<method name="setCrosswireClip">
|
||||
<arg type="b" direction="in" />
|
||||
</method>
|
||||
<method name="getCrosswireClip">
|
||||
<arg type="b" direction="out" />
|
||||
</method>
|
||||
<method name="setCrosswireColor">
|
||||
<arg type="u" direction="in" />
|
||||
</method>
|
||||
<method name="getCrosswireColor">
|
||||
<arg type="u" direction="out" />
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
// Subset of gnome-mag's ZoomRegion dbus interface -- to be expanded. See:
|
||||
// http://git.gnome.org/browse/gnome-mag/tree/xml/...ZoomRegion.xml
|
||||
const ZoomRegionIface = {
|
||||
name: ZOOM_SERVICE_NAME,
|
||||
methods: [
|
||||
{ name: 'setMagFactor', inSignature: 'dd', outSignature: ''},
|
||||
{ name: 'getMagFactor', inSignature: '', outSignature: 'dd' },
|
||||
{ name: 'setRoi', inSignature: 'ai', outSignature: '' },
|
||||
{ name: 'getRoi', inSignature: '', outSignature: 'ai' },
|
||||
{ name: 'shiftContentsTo', inSignature: 'ii', outSignature: 'b' },
|
||||
{ name: 'moveResize', inSignature: 'ai', outSignature: '' }
|
||||
],
|
||||
signals: [],
|
||||
properties: []
|
||||
};
|
||||
const ZoomRegionIface = <interface name={ZOOM_SERVICE_NAME}>
|
||||
<method name="setMagFactor">
|
||||
<arg type="d" direction="in" />
|
||||
<arg type="d" direction="in" />
|
||||
</method>
|
||||
<method name="getMagFactor">
|
||||
<arg type="d" direction="out" />
|
||||
<arg type="d" direction="out" />
|
||||
</method>
|
||||
<method name="setRoi">
|
||||
<arg type="ai" direction="in" />
|
||||
</method>
|
||||
<method name="getRoi">
|
||||
<arg type="ai" direction="out" />
|
||||
</method>
|
||||
<method name="shiftContentsTo">
|
||||
<arg type="i" direction="in" />
|
||||
<arg type="i" direction="in" />
|
||||
<arg type="b" direction="out" />
|
||||
</method>
|
||||
<method name="moveResize">
|
||||
<arg type="ai" direction="in" />
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
// For making unique ZoomRegion DBus proxy object paths of the form:
|
||||
// '/org/gnome/Magnifier/ZoomRegion/zoomer0',
|
||||
// '/org/gnome/Magnifier/ZoomRegion/zoomer1', etc.
|
||||
let _zoomRegionInstanceCount = 0;
|
||||
|
||||
function ShellMagnifier() {
|
||||
this._init();
|
||||
}
|
||||
const ShellMagnifier = new Lang.Class({
|
||||
Name: 'ShellMagnifier',
|
||||
|
||||
ShellMagnifier.prototype = {
|
||||
_init: function() {
|
||||
this._zoomers = {};
|
||||
DBus.session.exportObject(MAG_SERVICE_PATH, this);
|
||||
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(MagnifierIface, this);
|
||||
this._dbusImpl.export(Gio.DBus.session, MAG_SERVICE_PATH);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -195,10 +234,10 @@ ShellMagnifier.prototype = {
|
||||
Main.magnifier.clearAllZoomRegions();
|
||||
for (let objectPath in this._zoomers) {
|
||||
let proxyAndZoomer = this._zoomers[objectPath];
|
||||
proxyAndZoomer.proxy.destroy();
|
||||
proxyAndZoomer.proxy = null;
|
||||
proxyAndZoomer.zoomRegion = null;
|
||||
delete this._zoomers[objectPath];
|
||||
DBus.session.unexportObject(proxyAndZoomer);
|
||||
}
|
||||
this._zoomers = {};
|
||||
},
|
||||
@ -285,7 +324,7 @@ ShellMagnifier.prototype = {
|
||||
// Drop the leading '#'.
|
||||
return parseInt(colorString.slice(1), 16);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* ShellMagnifierZoomRegion:
|
||||
@ -293,15 +332,14 @@ ShellMagnifier.prototype = {
|
||||
* @zoomerObjectPath: String that is the path to a DBus ZoomRegion.
|
||||
* @zoomRegion: The actual zoom region associated with the object path.
|
||||
*/
|
||||
function ShellMagnifierZoomRegion(zoomerObjectPath, zoomRegion) {
|
||||
this._init(zoomerObjectPath, zoomRegion);
|
||||
}
|
||||
const ShellMagnifierZoomRegion = new Lang.Class({
|
||||
Name: 'ShellMagnifierZoomRegion',
|
||||
|
||||
ShellMagnifierZoomRegion.prototype = {
|
||||
_init: function(zoomerObjectPath, zoomRegion) {
|
||||
this._zoomRegion = zoomRegion;
|
||||
DBus.session.proxifyObject(this, ZOOM_SERVICE_NAME, zoomerObjectPath);
|
||||
DBus.session.exportObject(zoomerObjectPath, this);
|
||||
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ZoomRegionIface, this);
|
||||
this._dbusImpl.export(Gio.DBus.session, zoomerObjectPath);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -376,8 +414,9 @@ ShellMagnifierZoomRegion.prototype = {
|
||||
moveResize: function(viewPort) {
|
||||
let viewRect = { x: viewPort[0], y: viewPort[1], width: viewPort[2] - viewPort[0], height: viewPort[3] - viewPort[1] };
|
||||
this._zoomRegion.setViewPort(viewRect);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
DBus.conformExport(ShellMagnifier.prototype, MagnifierIface);
|
||||
DBus.conformExport(ShellMagnifierZoomRegion.prototype, ZoomRegionIface);
|
||||
destroy: function() {
|
||||
this._dbusImpl.unexport();
|
||||
}
|
||||
});
|
||||
|
@ -1,11 +1,9 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const DBus = imports.dbus;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const GConf = imports.gi.GConf;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
@ -129,22 +127,16 @@ function _initRecorder() {
|
||||
function _initUserSession() {
|
||||
_initRecorder();
|
||||
|
||||
keyboard.init();
|
||||
|
||||
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT, false, -1, 1);
|
||||
|
||||
ExtensionSystem.init();
|
||||
ExtensionSystem.loadExtensions();
|
||||
|
||||
let shellwm = global.window_manager;
|
||||
|
||||
shellwm.takeover_keybinding('panel_run_dialog');
|
||||
shellwm.connect('keybinding::panel_run_dialog', function () {
|
||||
Meta.keybindings_set_custom_handler('panel-run-dialog', function() {
|
||||
getRunDialog().open();
|
||||
});
|
||||
|
||||
shellwm.takeover_keybinding('panel_main_menu');
|
||||
shellwm.connect('keybinding::panel_main_menu', function () {
|
||||
Meta.keybindings_set_custom_handler('panel-main-menu', function () {
|
||||
overview.toggle();
|
||||
});
|
||||
|
||||
@ -165,11 +157,6 @@ function start() {
|
||||
Gio.DesktopAppInfo.set_desktop_env('GNOME');
|
||||
|
||||
shellDBusService = new ShellDBus.GnomeShell();
|
||||
// Force a connection now; dbus.js will do this internally
|
||||
// if we use its name acquisition stuff but we aren't right
|
||||
// now; to do so we'd need to convert from its async calls
|
||||
// back into sync ones.
|
||||
DBus.session.flush();
|
||||
|
||||
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
|
||||
// also initialize ShellAppSystem first. ShellAppSystem
|
||||
@ -496,9 +483,9 @@ function notify(msg, details) {
|
||||
function notifyError(msg, details) {
|
||||
// Also print to stderr so it's logged somewhere
|
||||
if (details)
|
||||
log("error: " + msg + ": " + details);
|
||||
log('error: ' + msg + ': ' + details);
|
||||
else
|
||||
log("error: " + msg)
|
||||
log('error: ' + msg);
|
||||
|
||||
notify(msg, details);
|
||||
}
|
||||
@ -585,19 +572,9 @@ function _globalKeyPressHandler(actor, event) {
|
||||
// This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType
|
||||
let action = global.display.get_keybinding_action(keyCode, modifierState);
|
||||
|
||||
// The screenshot action should always be available (even if a
|
||||
// modal dialog is present)
|
||||
if (action == Meta.KeyBindingAction.COMMAND_SCREENSHOT) {
|
||||
let gconf = GConf.Client.get_default();
|
||||
let command = gconf.get_string('/apps/metacity/keybinding_commands/command_screenshot');
|
||||
if (command != null && command != '')
|
||||
Util.spawnCommandLine(command);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Other bindings are only available when the overview is up and
|
||||
// Other bindings are only available to the user session when the overview is up and
|
||||
// no modal dialog is present.
|
||||
if (!overview.visible || modalCount > 1)
|
||||
if (global.session_type == Shell.SessionType.USER && (!overview.visible || modalCount > 1))
|
||||
return false;
|
||||
|
||||
// This isn't a Meta.KeyBindingAction yet
|
||||
@ -607,7 +584,8 @@ function _globalKeyPressHandler(actor, event) {
|
||||
}
|
||||
|
||||
if (action == Meta.KeyBindingAction.SWITCH_PANELS) {
|
||||
ctrlAltTabManager.popup(modifierState & Clutter.ModifierType.SHIFT_MASK);
|
||||
ctrlAltTabManager.popup(modifierState & Clutter.ModifierType.SHIFT_MASK,
|
||||
modifierState);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -669,14 +647,17 @@ function _findModal(actor) {
|
||||
* initiated event. If not provided then the value of
|
||||
* global.get_current_time() is assumed.
|
||||
*
|
||||
* @options: optional Meta.ModalOptions flags to indicate that the
|
||||
* pointer is alrady grabbed
|
||||
*
|
||||
* Returns: true iff we successfully acquired a grab or already had one
|
||||
*/
|
||||
function pushModal(actor, timestamp) {
|
||||
function pushModal(actor, timestamp, options) {
|
||||
if (timestamp == undefined)
|
||||
timestamp = global.get_current_time();
|
||||
|
||||
if (modalCount == 0) {
|
||||
if (!global.begin_modal(timestamp)) {
|
||||
if (!global.begin_modal(timestamp, options ? options : 0)) {
|
||||
log('pushModal: invocation of begin_modal failed');
|
||||
return false;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
@ -83,11 +83,9 @@ function _fixMarkup(text, allowMarkup) {
|
||||
return GLib.markup_escape_text(text, -1);
|
||||
}
|
||||
|
||||
function URLHighlighter(text, lineWrap, allowMarkup) {
|
||||
this._init(text, lineWrap, allowMarkup);
|
||||
}
|
||||
const URLHighlighter = new Lang.Class({
|
||||
Name: 'URLHighlighter',
|
||||
|
||||
URLHighlighter.prototype = {
|
||||
_init: function(text, lineWrap, allowMarkup) {
|
||||
if (!text)
|
||||
text = '';
|
||||
@ -211,13 +209,11 @@ URLHighlighter.prototype = {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function FocusGrabber() {
|
||||
this._init();
|
||||
}
|
||||
const FocusGrabber = new Lang.Class({
|
||||
Name: 'FocusGrabber',
|
||||
|
||||
FocusGrabber.prototype = {
|
||||
_init: function() {
|
||||
this.actor = null;
|
||||
|
||||
@ -252,7 +248,8 @@ FocusGrabber.prototype = {
|
||||
this._prevFocusedWindow = global.display.focus_window;
|
||||
this._prevKeyFocusActor = global.stage.get_key_focus();
|
||||
|
||||
if (!Main.overview.visible)
|
||||
if (global.stage_input_mode == Shell.StageInputMode.NONREACTIVE ||
|
||||
global.stage_input_mode == Shell.StageInputMode.NORMAL)
|
||||
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
|
||||
|
||||
// Use captured-event to notice clicks outside the focused actor
|
||||
@ -284,7 +281,8 @@ FocusGrabber.prototype = {
|
||||
let source = event.get_source();
|
||||
switch (event.type()) {
|
||||
case Clutter.EventType.BUTTON_PRESS:
|
||||
if (!this.actor.contains(source) && !Main.keyboard.actor.contains(source))
|
||||
if (!this.actor.contains(source) &&
|
||||
!Main.layoutManager.keyboardBox.contains(source))
|
||||
this.emit('button-pressed', source);
|
||||
break;
|
||||
case Clutter.EventType.KEY_PRESS:
|
||||
@ -349,7 +347,7 @@ FocusGrabber.prototype = {
|
||||
this._togglingFocusGrabMode = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(FocusGrabber.prototype);
|
||||
|
||||
// Notification:
|
||||
@ -406,15 +404,14 @@ Signals.addSignalMethods(FocusGrabber.prototype);
|
||||
// the content and the action area of the notification will be cleared.
|
||||
// The content area is also always cleared if 'customContent' is false
|
||||
// because it might contain the @banner that didn't fit in the banner mode.
|
||||
function Notification(source, title, banner, params) {
|
||||
this._init(source, title, banner, params);
|
||||
}
|
||||
const Notification = new Lang.Class({
|
||||
Name: 'Notification',
|
||||
|
||||
Notification.prototype = {
|
||||
IMAGE_SIZE: 125,
|
||||
|
||||
_init: function(source, title, banner, params) {
|
||||
this.source = source;
|
||||
this.title = title;
|
||||
this.urgency = Urgency.NORMAL;
|
||||
this.resident = false;
|
||||
// 'transient' is a reserved keyword in JS, so we have to use an alternate variable name
|
||||
@ -502,8 +499,11 @@ Notification.prototype = {
|
||||
|
||||
let oldFocus = global.stage.key_focus;
|
||||
|
||||
if (this._icon)
|
||||
if (this._icon && (params.icon || params.clear)) {
|
||||
this._icon.destroy();
|
||||
this._icon = null;
|
||||
}
|
||||
|
||||
// We always clear the content area if we don't have custom
|
||||
// content because it might contain the @banner that didn't
|
||||
// fit in the banner mode.
|
||||
@ -529,14 +529,17 @@ Notification.prototype = {
|
||||
if (!this._scrollArea && !this._actionArea && !this._imageBin)
|
||||
this._table.remove_style_class_name('multi-line-notification');
|
||||
|
||||
this._icon = params.icon || this.source.createNotificationIcon();
|
||||
this._table.add(this._icon, { row: 0,
|
||||
col: 0,
|
||||
x_expand: false,
|
||||
y_expand: false,
|
||||
y_fill: false,
|
||||
y_align: St.Align.START });
|
||||
if (!this._icon) {
|
||||
this._icon = params.icon || this.source.createNotificationIcon();
|
||||
this._table.add(this._icon, { row: 0,
|
||||
col: 0,
|
||||
x_expand: false,
|
||||
y_expand: false,
|
||||
y_fill: false,
|
||||
y_align: St.Align.START });
|
||||
}
|
||||
|
||||
this.title = title;
|
||||
title = title ? _fixMarkup(title.replace(/\n/g, ' '), params.titleMarkup) : '';
|
||||
this._titleLabel.clutter_text.set_markup('<b>' + title + '</b>');
|
||||
|
||||
@ -588,8 +591,7 @@ Notification.prototype = {
|
||||
this._table.add_style_class_name('multi-line-notification');
|
||||
this._scrollArea = new St.ScrollView({ name: 'notification-scrollview',
|
||||
vscrollbar_policy: this._scrollPolicy,
|
||||
hscrollbar_policy: Gtk.PolicyType.NEVER,
|
||||
style_class: 'vfade' });
|
||||
hscrollbar_policy: Gtk.PolicyType.NEVER });
|
||||
this._table.add(this._scrollArea, { row: 1,
|
||||
col: 2 });
|
||||
this._updateLastColumnSettings();
|
||||
@ -694,6 +696,7 @@ Notification.prototype = {
|
||||
this._imageBin.opacity = 230;
|
||||
this._table.add_style_class_name('multi-line-notification');
|
||||
this._table.add_style_class_name('notification-with-image');
|
||||
this._addBannerBody();
|
||||
this._updateLastColumnSettings();
|
||||
this._table.add(this._imageBin, { row: 1,
|
||||
col: 1,
|
||||
@ -791,11 +794,12 @@ Notification.prototype = {
|
||||
},
|
||||
|
||||
_bannerBoxAllocate: function(actor, box, flags) {
|
||||
let [titleMinW, titleNatW] = this._titleLabel.get_preferred_width(-1);
|
||||
let [titleMinH, titleNatH] = this._titleLabel.get_preferred_height(-1);
|
||||
let [bannerMinW, bannerNatW] = this._bannerLabel.get_preferred_width(-1);
|
||||
let availWidth = box.x2 - box.x1;
|
||||
|
||||
let [titleMinW, titleNatW] = this._titleLabel.get_preferred_width(-1);
|
||||
let [titleMinH, titleNatH] = this._titleLabel.get_preferred_height(availWidth);
|
||||
let [bannerMinW, bannerNatW] = this._bannerLabel.get_preferred_width(availWidth);
|
||||
|
||||
let titleBox = new Clutter.ActorBox();
|
||||
let titleBoxW = Math.min(titleNatW, availWidth);
|
||||
if (this._titleDirection == St.TextDirection.RTL) {
|
||||
@ -943,14 +947,12 @@ Notification.prototype = {
|
||||
this.actor.destroy();
|
||||
this.actor._delegate = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(Notification.prototype);
|
||||
|
||||
function Source(title) {
|
||||
this._init(title);
|
||||
}
|
||||
const Source = new Lang.Class({
|
||||
Name: 'MessageTraySource',
|
||||
|
||||
Source.prototype = {
|
||||
ICON_SIZE: 24,
|
||||
|
||||
_init: function(title) {
|
||||
@ -981,6 +983,7 @@ Source.prototype = {
|
||||
|
||||
this.isTransient = false;
|
||||
this.isChat = false;
|
||||
this.isMuted = false;
|
||||
|
||||
this.notifications = [];
|
||||
},
|
||||
@ -1045,6 +1048,13 @@ Source.prototype = {
|
||||
this.emit('title-changed');
|
||||
},
|
||||
|
||||
setMuted: function(muted) {
|
||||
if (!this.isChat || this.isMuted == muted)
|
||||
return;
|
||||
this.isMuted = muted;
|
||||
this.emit('muted-changed');
|
||||
},
|
||||
|
||||
// Called to create a new icon actor (of size this.ICON_SIZE).
|
||||
// Must be overridden by the subclass if you do not pass icons
|
||||
// explicitly to the Notification() constructor.
|
||||
@ -1083,7 +1093,8 @@ Source.prototype = {
|
||||
|
||||
notify: function(notification) {
|
||||
this.pushNotification(notification);
|
||||
this.emit('notify', notification);
|
||||
if (!this.isMuted)
|
||||
this.emit('notify', notification);
|
||||
},
|
||||
|
||||
destroy: function(reason) {
|
||||
@ -1123,14 +1134,12 @@ Source.prototype = {
|
||||
_lastNotificationRemoved: function() {
|
||||
this.destroy();
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(Source.prototype);
|
||||
|
||||
function SummaryItem(source) {
|
||||
this._init(source);
|
||||
}
|
||||
const SummaryItem = new Lang.Class({
|
||||
Name: 'SummaryItem',
|
||||
|
||||
SummaryItem.prototype = {
|
||||
_init: function(source) {
|
||||
this.source = source;
|
||||
this.source.connect('notification-added', Lang.bind(this, this._notificationAddedToSource));
|
||||
@ -1169,9 +1178,7 @@ SummaryItem.prototype = {
|
||||
this.notificationStack = new St.BoxLayout({ name: 'summary-notification-stack',
|
||||
vertical: true });
|
||||
this.notificationStackView.add_actor(this.notificationStack);
|
||||
this._notificationExpandedIds = [];
|
||||
this._notificationDoneDisplayingIds = [];
|
||||
this._notificationDestroyedIds = [];
|
||||
this._stackedNotifications = [];
|
||||
|
||||
this._oldMaxScrollAdjustment = 0;
|
||||
|
||||
@ -1201,6 +1208,18 @@ SummaryItem.prototype = {
|
||||
}));
|
||||
this.rightClickMenu.add(item.actor);
|
||||
|
||||
if (source.isChat) {
|
||||
item = new PopupMenu.PopupMenuItem('');
|
||||
item.actor.connect('notify::mapped', Lang.bind(this, function() {
|
||||
item.label.set_text(source.isMuted ? _("Unmute") : _("Mute"));
|
||||
}));
|
||||
item.connect('activate', Lang.bind(this, function() {
|
||||
source.setMuted(!source.isMuted);
|
||||
this.emit('done-displaying-content');
|
||||
}));
|
||||
this.rightClickMenu.add(item.actor);
|
||||
}
|
||||
|
||||
let focusManager = St.FocusManager.get_for_stage(global.stage);
|
||||
focusManager.add_group(this.rightClickMenu);
|
||||
},
|
||||
@ -1240,18 +1259,19 @@ SummaryItem.prototype = {
|
||||
|
||||
doneShowingNotificationStack: function() {
|
||||
let notificationActors = this.notificationStack.get_children();
|
||||
for (let i = 0; i < notificationActors.length; i++) {
|
||||
notificationActors[i]._delegate.collapseCompleted();
|
||||
notificationActors[i]._delegate.disconnect(this._notificationExpandedIds[i]);
|
||||
notificationActors[i]._delegate.disconnect(this._notificationDoneDisplayingIds[i]);
|
||||
notificationActors[i]._delegate.disconnect(this._notificationDestroyedIds[i]);
|
||||
this.notificationStack.remove_actor(notificationActors[i]);
|
||||
notificationActors[i]._delegate.setIconVisible(true);
|
||||
notificationActors[i]._delegate.enableScrolling(true);
|
||||
for (let i = 0; i < this._stackedNotifications.length; i++) {
|
||||
let stackedNotification = this._stackedNotifications[i];
|
||||
let notification = stackedNotification.notification;
|
||||
notification.collapseCompleted();
|
||||
notification.disconnect(stackedNotification.notificationExpandedId);
|
||||
notification.disconnect(stackedNotification.notificationDoneDisplayingId);
|
||||
notification.disconnect(stackedNotification.notificationDestroyedId);
|
||||
if (notification.actor.get_parent() == this.notificationStack)
|
||||
this.notificationStack.remove_actor(notification.actor);
|
||||
notification.setIconVisible(true);
|
||||
notification.enableScrolling(true);
|
||||
}
|
||||
this._notificationExpandedIds = [];
|
||||
this._notificationDoneDisplayingIds = [];
|
||||
this._notificationDestroyedIds = [];
|
||||
this._stackedNotifications = [];
|
||||
},
|
||||
|
||||
_notificationAddedToSource: function(source, notification) {
|
||||
@ -1260,12 +1280,12 @@ SummaryItem.prototype = {
|
||||
},
|
||||
|
||||
_appendNotificationToStack: function(notification) {
|
||||
let notificationExpandedId = notification.connect('expanded', Lang.bind(this, this._contentUpdated));
|
||||
this._notificationExpandedIds.push(notificationExpandedId);
|
||||
let notificationDoneDisplayingId = notification.connect('done-displaying', Lang.bind(this, this._notificationDoneDisplaying));
|
||||
this._notificationDoneDisplayingIds.push(notificationDoneDisplayingId);
|
||||
let notificationDestroyedId = notification.connect('destroy', Lang.bind(this, this._notificationDestroyed));
|
||||
this._notificationDestroyedIds.push(notificationDestroyedId);
|
||||
let stackedNotification = {};
|
||||
stackedNotification.notification = notification;
|
||||
stackedNotification.notificationExpandedId = notification.connect('expanded', Lang.bind(this, this._contentUpdated));
|
||||
stackedNotification.notificationDoneDisplayingId = notification.connect('done-displaying', Lang.bind(this, this._notificationDoneDisplaying));
|
||||
stackedNotification.notificationDestroyedId = notification.connect('destroy', Lang.bind(this, this._notificationDestroyed));
|
||||
this._stackedNotifications.push(stackedNotification);
|
||||
if (!this.source.isChat)
|
||||
notification.enableScrolling(false);
|
||||
if (this.notificationStack.get_children().length > 0)
|
||||
@ -1295,35 +1315,37 @@ SummaryItem.prototype = {
|
||||
},
|
||||
|
||||
_notificationDestroyed: function(notification) {
|
||||
let index = this.notificationStack.get_children().indexOf(notification.actor);
|
||||
if (index >= 0) {
|
||||
notification.disconnect(this._notificationExpandedIds[index]);
|
||||
this._notificationExpandedIds.splice(index, 1);
|
||||
notification.disconnect(this._notificationDoneDisplayingIds[index]);
|
||||
this._notificationDoneDisplayingIds.splice(index, 1);
|
||||
notification.disconnect(this._notificationDestroyedIds[index]);
|
||||
this._notificationDestroyedIds.splice(index, 1);
|
||||
this.notificationStack.remove_actor(notification.actor);
|
||||
this._contentUpdated();
|
||||
for (let i = 0; i < this._stackedNotifications.length; i++) {
|
||||
if (this._stackedNotifications[i].notification == notification) {
|
||||
let stackedNotification = this._stackedNotifications[i];
|
||||
notification.disconnect(stackedNotification.notificationExpandedId);
|
||||
notification.disconnect(stackedNotification.notificationDoneDisplayingId);
|
||||
notification.disconnect(stackedNotification.notificationDestroyedId);
|
||||
this._stackedNotifications.splice(i, 1);
|
||||
this._contentUpdated();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.notificationStack.get_children().length > 0)
|
||||
this.notificationStack.get_children()[0]._delegate.setIconVisible(true);
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(SummaryItem.prototype);
|
||||
|
||||
function MessageTray() {
|
||||
this._init();
|
||||
}
|
||||
const MessageTray = new Lang.Class({
|
||||
Name: 'MessageTray',
|
||||
|
||||
MessageTray.prototype = {
|
||||
_init: function() {
|
||||
this._presence = new GnomeSession.Presence();
|
||||
this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) {
|
||||
this._onStatusChanged(proxy.status);
|
||||
}));
|
||||
this._userStatus = GnomeSession.PresenceStatus.AVAILABLE;
|
||||
this._busy = false;
|
||||
this._backFromAway = false;
|
||||
this._presence.connect('StatusChanged', Lang.bind(this, this._onStatusChanged));
|
||||
this._presence.getStatus(Lang.bind(this, this._onStatusChanged));
|
||||
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
|
||||
this._onStatusChanged(status);
|
||||
}));
|
||||
|
||||
this.actor = new St.Group({ name: 'message-tray',
|
||||
reactive: true,
|
||||
@ -1347,6 +1369,7 @@ MessageTray.prototype = {
|
||||
this._summaryBin.opacity = 0;
|
||||
|
||||
this._summaryMotionId = 0;
|
||||
this._trayMotionId = 0;
|
||||
|
||||
this._summaryBoxPointer = new BoxPointer.BoxPointer(St.Side.BOTTOM,
|
||||
{ reactive: true,
|
||||
@ -1386,12 +1409,15 @@ MessageTray.prototype = {
|
||||
}));
|
||||
this._focusGrabber.connect('escape-pressed', Lang.bind(this, this._escapeTray));
|
||||
|
||||
Main.layoutManager.keyboardBox.connect('notify::hover', Lang.bind(this, this._onKeyboardHoverChanged));
|
||||
|
||||
this._trayState = State.HIDDEN;
|
||||
this._locked = false;
|
||||
this._traySummoned = false;
|
||||
this._useLongerTrayLeftTimeout = false;
|
||||
this._trayLeftTimeoutId = 0;
|
||||
this._pointerInTray = false;
|
||||
this._pointerInKeyboard = false;
|
||||
this._summaryState = State.HIDDEN;
|
||||
this._summaryTimeoutId = 0;
|
||||
this._pointerInSummary = false;
|
||||
@ -1494,12 +1520,23 @@ MessageTray.prototype = {
|
||||
// after notifications are done showing. However, we don't want that to happen for
|
||||
// transient sources, which are removed after the notification is shown, but are
|
||||
// not removed fast enough because of the callbacks to avoid the summary popping up.
|
||||
// So we just don't add transient sources to this._newSummaryItems .
|
||||
if (!source.isTransient)
|
||||
// So we just don't add transient sources to this._newSummaryItems.
|
||||
// We don't want that to happen for chat sources neither, because they
|
||||
// can be added when the user starts a chat from Empathy and they are not transient.
|
||||
// The notification will popup on incoming message anyway. See bug #657249.
|
||||
if (!source.isTransient && !source.isChat)
|
||||
this._newSummaryItems.push(summaryItem);
|
||||
|
||||
source.connect('notify', Lang.bind(this, this._onNotify));
|
||||
|
||||
source.connect('muted-changed', Lang.bind(this,
|
||||
function () {
|
||||
if (source.isMuted)
|
||||
this._notificationQueue = this._notificationQueue.filter(function(notification) {
|
||||
return source != notification.source;
|
||||
});
|
||||
}));
|
||||
|
||||
summaryItem.actor.connect('notify::hover', Lang.bind(this,
|
||||
function () {
|
||||
this._onSummaryItemHoverChanged(summaryItem);
|
||||
@ -1569,7 +1606,7 @@ MessageTray.prototype = {
|
||||
|
||||
summaryItemToRemove.actor.destroy();
|
||||
|
||||
if (needUpdate);
|
||||
if (needUpdate)
|
||||
this._updateState();
|
||||
},
|
||||
|
||||
@ -1814,7 +1851,7 @@ MessageTray.prototype = {
|
||||
// automatically. Instead, the user is able to expand the notification by mousing away from it and then
|
||||
// mousing back in. Because this is an expected action, we set the boolean flag that indicates that a longer
|
||||
// timeout should be used before popping down the notification.
|
||||
if (this._notificationBin.contains(actorAtShowNotificationPosition)) {
|
||||
if (this.actor.contains(actorAtShowNotificationPosition)) {
|
||||
this._useLongerTrayLeftTimeout = true;
|
||||
return;
|
||||
}
|
||||
@ -1838,7 +1875,25 @@ MessageTray.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_onStatusChanged: function(presence, status) {
|
||||
_onKeyboardHoverChanged: function(keyboard) {
|
||||
this._pointerInKeyboard = keyboard.hover;
|
||||
|
||||
if (!keyboard.hover) {
|
||||
let event = Clutter.get_current_event();
|
||||
if (event && event.type() == Clutter.EventType.LEAVE) {
|
||||
let into = event.get_related();
|
||||
if (into && this.actor.contains(into)) {
|
||||
// Don't call _updateState, because pointerInTray is
|
||||
// still false
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._updateState();
|
||||
},
|
||||
|
||||
_onStatusChanged: function(status) {
|
||||
this._backFromAway = (this._userStatus == GnomeSession.PresenceStatus.IDLE && this._userStatus != status);
|
||||
this._userStatus = status;
|
||||
|
||||
@ -1902,7 +1957,7 @@ MessageTray.prototype = {
|
||||
let notificationsPending = this._notificationQueue.length > 0 && (!this._busy || notificationUrgent);
|
||||
let notificationPinned = this._pointerInTray && !this._pointerInSummary && !this._notificationRemoved;
|
||||
let notificationExpanded = this._notificationBin.y < 0;
|
||||
let notificationExpired = (this._notificationTimeoutId == 0 && !(this._notification && this._notification.urgency == Urgency.CRITICAL) && !this._pointerInTray && !this._locked) || this._notificationRemoved;
|
||||
let notificationExpired = (this._notificationTimeoutId == 0 && !(this._notification && this._notification.urgency == Urgency.CRITICAL) && !this._pointerInTray && !this._locked && !(this._pointerInKeyboard && notificationExpanded)) || this._notificationRemoved;
|
||||
let canShowNotification = notificationsPending && this._summaryState == State.HIDDEN;
|
||||
|
||||
if (this._notificationState == State.HIDDEN) {
|
||||
@ -2237,7 +2292,7 @@ MessageTray.prototype = {
|
||||
_showSummaryBoxPointer: function() {
|
||||
this._summaryBoxPointerItem = this._clickedSummaryItem;
|
||||
this._summaryBoxPointerContentUpdatedId = this._summaryBoxPointerItem.connect('content-updated',
|
||||
Lang.bind(this, this._adjustSummaryBoxPointerPosition));
|
||||
Lang.bind(this, this._onSummaryBoxPointerContentUpdated));
|
||||
this._summaryBoxPointerDoneDisplayingId = this._summaryBoxPointerItem.connect('done-displaying-content',
|
||||
Lang.bind(this, this._escapeTray));
|
||||
if (this._clickedSummaryItemMouseButton == 1) {
|
||||
@ -2260,6 +2315,8 @@ MessageTray.prototype = {
|
||||
// _clickedSummaryItem.actor can change absolute position without changing allocation
|
||||
this._summaryMotionId = this._summary.connect('allocation-changed',
|
||||
Lang.bind(this, this._adjustSummaryBoxPointerPosition));
|
||||
this._trayMotionId = Main.layoutManager.trayBox.connect('notify::anchor-y',
|
||||
Lang.bind(this, this._adjustSummaryBoxPointerPosition));
|
||||
|
||||
this._summaryBoxPointer.actor.opacity = 0;
|
||||
this._summaryBoxPointer.actor.show();
|
||||
@ -2272,6 +2329,13 @@ MessageTray.prototype = {
|
||||
}));
|
||||
},
|
||||
|
||||
_onSummaryBoxPointerContentUpdated: function() {
|
||||
if (this._summaryBoxPointerItem.notificationStack.get_children().length == 0)
|
||||
this._hideSummaryBoxPointer();
|
||||
this._adjustSummaryBoxPointerPosition();
|
||||
|
||||
},
|
||||
|
||||
_adjustSummaryBoxPointerPosition: function() {
|
||||
// The position of the arrow origin should be the same as center of this._clickedSummaryItem.actor
|
||||
if (!this._clickedSummaryItem)
|
||||
@ -2284,8 +2348,10 @@ MessageTray.prototype = {
|
||||
if (this._clickedSummaryItemAllocationChangedId) {
|
||||
this._clickedSummaryItem.actor.disconnect(this._clickedSummaryItemAllocationChangedId);
|
||||
this._summary.disconnect(this._summaryMotionId);
|
||||
Main.layoutManager.trayBox.disconnect(this._trayMotionId);
|
||||
this._clickedSummaryItemAllocationChangedId = 0;
|
||||
this._summaryMotionId = 0;
|
||||
this._trayMotionId = 0;
|
||||
}
|
||||
|
||||
if (this._clickedSummaryItem)
|
||||
@ -2295,9 +2361,18 @@ MessageTray.prototype = {
|
||||
},
|
||||
|
||||
_hideSummaryBoxPointer: function() {
|
||||
// We should be sure to hide the box pointer if all notifications in it are destroyed while
|
||||
// it is hiding, so that we don't show an an animation of an empty blob being hidden.
|
||||
if (this._summaryBoxPointerState == State.HIDING &&
|
||||
this._summaryBoxPointerItem.notificationStack.get_children().length == 0) {
|
||||
this._summaryBoxPointer.actor.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
this._summaryBoxPointerState = State.HIDING;
|
||||
// Unset this._clickedSummaryItem if we are no longer showing the summary
|
||||
if (this._summaryState != State.SHOWN)
|
||||
// Unset this._clickedSummaryItem if we are no longer showing the summary or if
|
||||
// this._clickedSummaryItem is still the item associated with the currently showing box pointer
|
||||
if (this._summaryState != State.SHOWN || this._summaryBoxPointerItem == this._clickedSummaryItem)
|
||||
this._unsetClickedSummaryItem();
|
||||
|
||||
this._focusGrabber.ungrabFocus();
|
||||
@ -2339,17 +2414,14 @@ MessageTray.prototype = {
|
||||
if (this._clickedSummaryItem)
|
||||
this._updateState();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function SystemNotificationSource() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
SystemNotificationSource.prototype = {
|
||||
__proto__: Source.prototype,
|
||||
const SystemNotificationSource = new Lang.Class({
|
||||
Name: 'SystemNotificationSource',
|
||||
Extends: Source,
|
||||
|
||||
_init: function() {
|
||||
Source.prototype._init.call(this, _("System Information"));
|
||||
this.parent(_("System Information"));
|
||||
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
},
|
||||
@ -2363,4 +2435,4 @@ SystemNotificationSource.prototype = {
|
||||
open: function() {
|
||||
this.destroy();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
@ -29,11 +29,9 @@ const State = {
|
||||
FADED_OUT: 4
|
||||
};
|
||||
|
||||
function ModalDialog() {
|
||||
this._init();
|
||||
}
|
||||
const ModalDialog = new Lang.Class({
|
||||
Name: 'ModalDialog',
|
||||
|
||||
ModalDialog.prototype = {
|
||||
_init: function(params) {
|
||||
params = Params.parse(params, { shellReactive: false,
|
||||
styleClass: null });
|
||||
@ -110,9 +108,8 @@ ModalDialog.prototype = {
|
||||
this._buttonLayout.destroy_children();
|
||||
this._actionKeys = {};
|
||||
|
||||
let i = 0;
|
||||
for (let index in buttons) {
|
||||
let buttonInfo = buttons[index];
|
||||
for (let i = 0; i < buttons.length; i++) {
|
||||
let buttonInfo = buttons[i];
|
||||
let label = buttonInfo['label'];
|
||||
let action = buttonInfo['action'];
|
||||
let key = buttonInfo['key'];
|
||||
@ -132,7 +129,9 @@ ModalDialog.prototype = {
|
||||
else
|
||||
x_alignment = St.Align.MIDDLE;
|
||||
|
||||
this._initialKeyFocus = buttonInfo.button;
|
||||
if (this._initialKeyFocus == this._dialogLayout ||
|
||||
this._buttonLayout.contains(this._initialKeyFocus))
|
||||
this._initialKeyFocus = buttonInfo.button;
|
||||
this._buttonLayout.add(buttonInfo.button,
|
||||
{ expand: true,
|
||||
x_fill: false,
|
||||
@ -144,11 +143,10 @@ ModalDialog.prototype = {
|
||||
|
||||
if (key)
|
||||
this._actionKeys[key] = action;
|
||||
i++;
|
||||
}
|
||||
|
||||
// Fade in buttons if there weren't any before
|
||||
if (!hadChildren && i > 0) {
|
||||
if (!hadChildren && buttons.length > 0) {
|
||||
this._buttonLayout.opacity = 0;
|
||||
Tweener.addTween(this._buttonLayout,
|
||||
{ opacity: 255,
|
||||
@ -303,5 +301,5 @@ ModalDialog.prototype = {
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(ModalDialog.prototype);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 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
|
||||
@ -30,16 +30,14 @@ const St = imports.gi.St;
|
||||
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const ShellEntry = imports.ui.shellEntry;
|
||||
|
||||
function NetworkSecretDialog() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
NetworkSecretDialog.prototype = {
|
||||
__proto__: ModalDialog.ModalDialog.prototype,
|
||||
const NetworkSecretDialog = new Lang.Class({
|
||||
Name: 'NetworkSecretDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
|
||||
_init: function(agent, requestId, connection, settingName, hints) {
|
||||
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'polkit-dialog' });
|
||||
this.parent({ styleClass: 'polkit-dialog' });
|
||||
|
||||
this._agent = agent;
|
||||
this._requestId = requestId;
|
||||
@ -91,6 +89,7 @@ NetworkSecretDialog.prototype = {
|
||||
}
|
||||
|
||||
let secretTable = new St.Table({ style_class: 'network-dialog-secret-table' });
|
||||
let initialFocusSet = false;
|
||||
let pos = 0;
|
||||
for (let i = 0; i < this._content.secrets.length; i++) {
|
||||
let secret = this._content.secrets[i];
|
||||
@ -102,6 +101,8 @@ NetworkSecretDialog.prototype = {
|
||||
secret.entry = new St.Entry({ style_class: 'polkit-dialog-password-entry',
|
||||
text: secret.value, can_focus: reactive,
|
||||
reactive: reactive });
|
||||
ShellEntry.addContextMenu(secret.entry,
|
||||
{ isPassword: secret.password });
|
||||
|
||||
if (secret.validate)
|
||||
secret.valid = secret.validate(secret);
|
||||
@ -109,6 +110,12 @@ NetworkSecretDialog.prototype = {
|
||||
secret.valid = secret.value.length > 0;
|
||||
|
||||
if (reactive) {
|
||||
if (!initialFocusSet) {
|
||||
this.setInitialKeyFocus(secret.entry);
|
||||
initialFocusSet = true;
|
||||
}
|
||||
|
||||
secret.entry.clutter_text.connect('activate', Lang.bind(this, this._onOk));
|
||||
secret.entry.clutter_text.connect('text-changed', Lang.bind(this, function() {
|
||||
secret.value = secret.entry.get_text();
|
||||
if (secret.validate)
|
||||
@ -120,34 +127,14 @@ NetworkSecretDialog.prototype = {
|
||||
} else
|
||||
secret.valid = true;
|
||||
|
||||
secretTable.add(label, { row: pos, col: 0, x_align: St.Align.START, y_align: St.Align.START });
|
||||
secretTable.add(label, { row: pos, col: 0, x_expand: false, x_fill: true, x_align: St.Align.START, y_align: St.Align.START });
|
||||
secretTable.add(secret.entry, { row: pos, col: 1, x_expand: true, x_fill: true, y_align: St.Align.END });
|
||||
pos++;
|
||||
|
||||
if (secret.password) {
|
||||
if (secret.password)
|
||||
secret.entry.clutter_text.set_password_char('\u25cf');
|
||||
|
||||
// FIXME: need a real checkbox here
|
||||
let button = new St.Button({ button_mask: St.ButtonMask.ONE,
|
||||
can_focus: true });
|
||||
let checkbox = new St.BoxLayout({ vertical: false,
|
||||
style_class: 'network-dialog-show-password-checkbox'
|
||||
});
|
||||
let _switch = new PopupMenu.Switch(false);
|
||||
checkbox.add(_switch.actor);
|
||||
checkbox.add(new St.Label({ text: _("Show password") }), { expand: true });
|
||||
button.connect('clicked', function() {
|
||||
_switch.toggle();
|
||||
if (_switch.state)
|
||||
secret.entry.clutter_text.set_password_char('');
|
||||
else
|
||||
secret.entry.clutter_text.set_password_char('\u25cf');
|
||||
});
|
||||
button.child = checkbox;
|
||||
secretTable.add(button, { row: pos, col: 1, x_expand: true, x_fill: true, y_fill: true })
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
messageBox.add(secretTable);
|
||||
|
||||
this._okButton = { label: _("Connect"),
|
||||
@ -360,7 +347,7 @@ NetworkSecretDialog.prototype = {
|
||||
case 'bluetooth':
|
||||
content.title = _("Mobile broadband network password");
|
||||
content.message = _("A password is required to connect to '%s'.").format(connectionSetting.get_id());
|
||||
this._getMobileSecrets(content.secrets);
|
||||
this._getMobileSecrets(content.secrets, connectionType);
|
||||
break;
|
||||
default:
|
||||
log('Invalid connection type: ' + connectionType);
|
||||
@ -368,13 +355,11 @@ NetworkSecretDialog.prototype = {
|
||||
|
||||
return content;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function NetworkAgent() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
const NetworkAgent = new Lang.Class({
|
||||
Name: 'NetworkAgent',
|
||||
|
||||
NetworkAgent.prototype = {
|
||||
_init: function() {
|
||||
this._native = new Shell.NetworkAgent({ auto_register: true,
|
||||
identifier: 'org.gnome.Shell.NetworkAgent' });
|
||||
@ -397,4 +382,4 @@ NetworkAgent.prototype = {
|
||||
this._dialogs[requestId].close(global.get_current_time());
|
||||
this._dialogs[requestId].destroy();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const DBus = imports.dbus;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
@ -16,49 +16,52 @@ const Util = imports.misc.util;
|
||||
|
||||
let nextNotificationId = 1;
|
||||
|
||||
// Should really be defined in dbus.js
|
||||
const BusIface = {
|
||||
name: 'org.freedesktop.DBus',
|
||||
methods: [{ name: 'GetConnectionUnixProcessID',
|
||||
inSignature: 's',
|
||||
outSignature: 'i' }]
|
||||
};
|
||||
// Should really be defined in Gio.js
|
||||
const BusIface = <interface name="org.freedesktop.DBus">
|
||||
<method name="GetConnectionUnixProcessID">
|
||||
<arg type="s" direction="in" />
|
||||
<arg type="u" direction="out" />
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
const Bus = function () {
|
||||
this._init();
|
||||
};
|
||||
var BusProxy = Gio.DBusProxy.makeProxyWrapper(BusIface);
|
||||
function Bus() {
|
||||
return new BusProxy(Gio.DBus.session, 'org.freedesktop.DBus', '/org/freedesktop/DBus');
|
||||
}
|
||||
|
||||
Bus.prototype = {
|
||||
_init: function() {
|
||||
DBus.session.proxifyObject(this, 'org.freedesktop.DBus', '/org/freedesktop/DBus');
|
||||
}
|
||||
};
|
||||
|
||||
DBus.proxifyPrototype(Bus.prototype, BusIface);
|
||||
|
||||
const NotificationDaemonIface = {
|
||||
name: 'org.freedesktop.Notifications',
|
||||
methods: [{ name: 'Notify',
|
||||
inSignature: 'susssasa{sv}i',
|
||||
outSignature: 'u'
|
||||
},
|
||||
{ name: 'CloseNotification',
|
||||
inSignature: 'u',
|
||||
outSignature: ''
|
||||
},
|
||||
{ name: 'GetCapabilities',
|
||||
inSignature: '',
|
||||
outSignature: 'as'
|
||||
},
|
||||
{ name: 'GetServerInformation',
|
||||
inSignature: '',
|
||||
outSignature: 'ssss'
|
||||
}],
|
||||
signals: [{ name: 'NotificationClosed',
|
||||
inSignature: 'uu' },
|
||||
{ name: 'ActionInvoked',
|
||||
inSignature: 'us' }]
|
||||
};
|
||||
const NotificationDaemonIface = <interface name="org.freedesktop.Notifications">
|
||||
<method name="Notify">
|
||||
<arg type="s" direction="in"/>
|
||||
<arg type="u" direction="in"/>
|
||||
<arg type="s" direction="in"/>
|
||||
<arg type="s" direction="in"/>
|
||||
<arg type="s" direction="in"/>
|
||||
<arg type="as" direction="in"/>
|
||||
<arg type="a{sv}" direction="in"/>
|
||||
<arg type="i" direction="in"/>
|
||||
<arg type="u" direction="out"/>
|
||||
</method>
|
||||
<method name="CloseNotification">
|
||||
<arg type="u" direction="in"/>
|
||||
</method>
|
||||
<method name="GetCapabilities">
|
||||
<arg type="as" direction="out"/>
|
||||
</method>
|
||||
<method name="GetServerInformation">
|
||||
<arg type="s" direction="out"/>
|
||||
<arg type="s" direction="out"/>
|
||||
<arg type="s" direction="out"/>
|
||||
<arg type="s" direction="out"/>
|
||||
</method>
|
||||
<signal name="NotificationClosed">
|
||||
<arg type="u"/>
|
||||
<arg type="u"/>
|
||||
</signal>
|
||||
<signal name="ActionInvoked">
|
||||
<arg type="u"/>
|
||||
<arg type="s"/>
|
||||
</signal>
|
||||
</interface>;
|
||||
|
||||
const NotificationClosedReason = {
|
||||
EXPIRED: 1,
|
||||
@ -84,13 +87,12 @@ const rewriteRules = {
|
||||
]
|
||||
};
|
||||
|
||||
function NotificationDaemon() {
|
||||
this._init();
|
||||
}
|
||||
const NotificationDaemon = new Lang.Class({
|
||||
Name: 'NotificationDaemon',
|
||||
|
||||
NotificationDaemon.prototype = {
|
||||
_init: function() {
|
||||
DBus.session.exportObject('/org/freedesktop/Notifications', this);
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(NotificationDaemonIface, this);
|
||||
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
|
||||
|
||||
this._sources = {};
|
||||
this._senderToPid = {};
|
||||
@ -109,6 +111,14 @@ NotificationDaemon.prototype = {
|
||||
_iconForNotificationData: function(icon, hints, size) {
|
||||
let textureCache = St.TextureCache.get_default();
|
||||
|
||||
// If an icon is not specified, we use 'image-data' or 'image-path' hint for an icon
|
||||
// and don't show a large image. There are currently many applications that use
|
||||
// notify_notification_set_icon_from_pixbuf() from libnotify, which in turn sets
|
||||
// the 'image-data' hint. These applications don't typically pass in 'app_icon'
|
||||
// argument to Notify() and actually expect the pixbuf to be shown as an icon.
|
||||
// So the logic here does the right thing for this case. If both an icon and either
|
||||
// one of 'image-data' or 'image-path' are specified, we show both an icon and
|
||||
// a large image.
|
||||
if (icon) {
|
||||
if (icon.substr(0, 7) == 'file://')
|
||||
return textureCache.load_uri_async(icon, size, size);
|
||||
@ -119,6 +129,12 @@ NotificationDaemon.prototype = {
|
||||
return new St.Icon({ icon_name: icon,
|
||||
icon_type: St.IconType.FULLCOLOR,
|
||||
icon_size: size });
|
||||
} else if (hints['image-data']) {
|
||||
let [width, height, rowStride, hasAlpha,
|
||||
bitsPerSample, nChannels, data] = hints['image-data'];
|
||||
return textureCache.load_from_raw(data, hasAlpha, width, height, rowStride, size);
|
||||
} else if (hints['image-path']) {
|
||||
return textureCache.load_uri_async(GLib.filename_to_uri(hints['image-path'], null), size, size);
|
||||
} else {
|
||||
let stockIcon;
|
||||
switch (hints.urgency) {
|
||||
@ -181,8 +197,8 @@ NotificationDaemon.prototype = {
|
||||
return source;
|
||||
},
|
||||
|
||||
Notify: function(appName, replacesId, icon, summary, body,
|
||||
actions, hints, timeout) {
|
||||
NotifyAsync: function(params, invocation) {
|
||||
let [appName, replacesId, icon, summary, body, actions, hints, timeout] = params;
|
||||
let id;
|
||||
|
||||
// Filter out chat, presence, calls and invitation notifications from
|
||||
@ -201,7 +217,7 @@ NotificationDaemon.prototype = {
|
||||
function () {
|
||||
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
|
||||
}));
|
||||
return id;
|
||||
return invocation.return_value(GLib.Variant.new('(u)', [id]));
|
||||
}
|
||||
|
||||
let rewrites = rewriteRules[appName];
|
||||
@ -213,6 +229,11 @@ NotificationDaemon.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
for (let hint in hints) {
|
||||
// unpack the variants
|
||||
hints[hint] = hints[hint].deep_unpack();
|
||||
}
|
||||
|
||||
hints = Params.parse(hints, { urgency: Urgency.NORMAL }, true);
|
||||
|
||||
// Be compatible with the various hints for image data and image path
|
||||
@ -244,51 +265,55 @@ NotificationDaemon.prototype = {
|
||||
}
|
||||
this._notifications[id] = ndata;
|
||||
|
||||
let sender = DBus.getCurrentMessageContext().sender;
|
||||
let sender = invocation.get_sender();
|
||||
let pid = this._senderToPid[sender];
|
||||
|
||||
let source = this._getSource(appName, pid, ndata, sender);
|
||||
|
||||
if (source) {
|
||||
this._notifyForSource(source, ndata);
|
||||
return id;
|
||||
return invocation.return_value(GLib.Variant.new('(u)', [id]));
|
||||
}
|
||||
|
||||
if (replacesId) {
|
||||
// There's already a pending call to GetConnectionUnixProcessID,
|
||||
// which will see the new notification data when it finishes,
|
||||
// so we don't have to do anything.
|
||||
return id;
|
||||
return invocation.return_value(GLib.Variant.new('(u)', [id]));;
|
||||
}
|
||||
|
||||
this._busProxy.GetConnectionUnixProcessIDRemote(sender, Lang.bind(this,
|
||||
function (pid, ex) {
|
||||
// The app may have updated or removed the notification
|
||||
ndata = this._notifications[id];
|
||||
if (!ndata)
|
||||
return;
|
||||
this._busProxy.GetConnectionUnixProcessIDRemote(sender, Lang.bind(this, function (result, excp) {
|
||||
// The app may have updated or removed the notification
|
||||
ndata = this._notifications[id];
|
||||
if (!ndata)
|
||||
return;
|
||||
|
||||
source = this._getSource(appName, pid, ndata, sender);
|
||||
if (excp) {
|
||||
logError(excp, 'Call to GetConnectionUnixProcessID failed');
|
||||
return;
|
||||
}
|
||||
|
||||
// We only store sender-pid entries for persistent sources.
|
||||
// Removing the entries once the source is destroyed
|
||||
// would result in the entries associated with transient
|
||||
// sources removed once the notification is shown anyway.
|
||||
// However, keeping these pairs would mean that we would
|
||||
// possibly remove an entry associated with a persistent
|
||||
// source when a transient source for the same sender is
|
||||
// distroyed.
|
||||
if (!source.isTransient) {
|
||||
this._senderToPid[sender] = pid;
|
||||
source.connect('destroy', Lang.bind(this,
|
||||
function() {
|
||||
delete this._senderToPid[sender];
|
||||
}));
|
||||
}
|
||||
this._notifyForSource(source, ndata);
|
||||
}));
|
||||
let [pid] = result;
|
||||
source = this._getSource(appName, pid, ndata, sender);
|
||||
|
||||
return id;
|
||||
// We only store sender-pid entries for persistent sources.
|
||||
// Removing the entries once the source is destroyed
|
||||
// would result in the entries associated with transient
|
||||
// sources removed once the notification is shown anyway.
|
||||
// However, keeping these pairs would mean that we would
|
||||
// possibly remove an entry associated with a persistent
|
||||
// source when a transient source for the same sender is
|
||||
// distroyed.
|
||||
if (!source.isTransient) {
|
||||
this._senderToPid[sender] = pid;
|
||||
source.connect('destroy', Lang.bind(this, function() {
|
||||
delete this._senderToPid[sender];
|
||||
}));
|
||||
}
|
||||
this._notifyForSource(source, ndata);
|
||||
}));
|
||||
|
||||
return invocation.return_value(GLib.Variant.new('(u)', [id]));
|
||||
},
|
||||
|
||||
_notifyForSource: function(source, ndata) {
|
||||
@ -330,7 +355,8 @@ NotificationDaemon.prototype = {
|
||||
clear: true });
|
||||
}
|
||||
|
||||
if (hints['image-data'] || hints['image-path']) {
|
||||
// We only display a large image if an icon is also specified.
|
||||
if (icon && (hints['image-data'] || hints['image-path'])) {
|
||||
let image = null;
|
||||
if (hints['image-data']) {
|
||||
let [width, height, rowStride, hasAlpha,
|
||||
@ -427,17 +453,13 @@ NotificationDaemon.prototype = {
|
||||
},
|
||||
|
||||
_emitNotificationClosed: function(id, reason) {
|
||||
DBus.session.emit_signal('/org/freedesktop/Notifications',
|
||||
'org.freedesktop.Notifications',
|
||||
'NotificationClosed', 'uu',
|
||||
[id, reason]);
|
||||
this._dbusImpl.emit_signal('NotificationClosed',
|
||||
GLib.Variant.new('(uu)', [id, reason]));
|
||||
},
|
||||
|
||||
_emitActionInvoked: function(id, action) {
|
||||
DBus.session.emit_signal('/org/freedesktop/Notifications',
|
||||
'org.freedesktop.Notifications',
|
||||
'ActionInvoked', 'us',
|
||||
[id, action]);
|
||||
this._dbusImpl.emit_signal('ActionInvoked',
|
||||
GLib.Variant.new('(us)', [id, action]));
|
||||
},
|
||||
|
||||
_onTrayIconAdded: function(o, icon) {
|
||||
@ -450,31 +472,23 @@ NotificationDaemon.prototype = {
|
||||
if (source)
|
||||
source.destroy();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
DBus.conformExport(NotificationDaemon.prototype, NotificationDaemonIface);
|
||||
|
||||
function Source(title, pid, sender) {
|
||||
this._init(title, pid, sender);
|
||||
}
|
||||
|
||||
Source.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
const Source = new Lang.Class({
|
||||
Name: 'NotificationDaemonSource',
|
||||
Extends: MessageTray.Source,
|
||||
|
||||
_init: function(title, pid, sender) {
|
||||
MessageTray.Source.prototype._init.call(this, title);
|
||||
this.parent(title);
|
||||
|
||||
this._pid = pid;
|
||||
if (sender)
|
||||
// TODO: dbus-glib implementation of watch_name() doesn’t return an id to be used for
|
||||
// unwatch_name() or implement unwatch_name(), however when we move to using GDBus implementation,
|
||||
// we should save the id here and call unwatch_name() with it in destroy().
|
||||
// Moving to GDBus is the work in progress: https://bugzilla.gnome.org/show_bug.cgi?id=648651
|
||||
// and https://bugzilla.gnome.org/show_bug.cgi?id=622921 .
|
||||
DBus.session.watch_name(sender,
|
||||
false,
|
||||
null,
|
||||
Lang.bind(this, this._onNameVanished));
|
||||
this._nameWatcherId = Gio.DBus.session.watch_name(sender,
|
||||
Gio.BusNameWatcherFlags.NONE,
|
||||
null,
|
||||
Lang.bind(this, this._onNameVanished));
|
||||
else
|
||||
this._nameWatcherId = 0;
|
||||
|
||||
this._setApp();
|
||||
if (this.app)
|
||||
@ -582,6 +596,11 @@ Source.prototype = {
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
MessageTray.Source.prototype.destroy.call(this);
|
||||
if (this._nameWatcherId) {
|
||||
Gio.DBus.session.unwatch_name(this._nameWatcherId);
|
||||
this._nameWatcherId = 0;
|
||||
}
|
||||
|
||||
this.parent();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
@ -46,11 +46,9 @@ const SwipeScrollResult = {
|
||||
CLICK: 2
|
||||
};
|
||||
|
||||
function ShellInfo() {
|
||||
this._init();
|
||||
}
|
||||
const ShellInfo = new Lang.Class({
|
||||
Name: 'ShellInfo',
|
||||
|
||||
ShellInfo.prototype = {
|
||||
_init: function() {
|
||||
this._source = null;
|
||||
this._undoCallback = null;
|
||||
@ -95,13 +93,11 @@ ShellInfo.prototype = {
|
||||
|
||||
this._source.notify(notification);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function Overview() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
const Overview = new Lang.Class({
|
||||
Name: 'Overview',
|
||||
|
||||
Overview.prototype = {
|
||||
_init : function(params) {
|
||||
params = Params.parse(params, { isDummy: false });
|
||||
|
||||
@ -811,5 +807,5 @@ Overview.prototype = {
|
||||
this._needsFakePointerEvent = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(Overview.prototype);
|
||||
|
261
js/ui/panel.js
261
js/ui/panel.js
@ -1,8 +1,9 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 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 Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Pango = imports.gi.Pango;
|
||||
@ -16,7 +17,6 @@ const Layout = imports.ui.layout;
|
||||
const Overview = imports.ui.overview;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const UserMenu = imports.ui.userMenu;
|
||||
const DateMenu = imports.ui.dateMenu;
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
@ -28,29 +28,31 @@ const BUTTON_DND_ACTIVATION_TIMEOUT = 250;
|
||||
const ANIMATED_ICON_UPDATE_TIMEOUT = 100;
|
||||
const SPINNER_ANIMATION_TIME = 0.2;
|
||||
|
||||
const STANDARD_TRAY_ICON_ORDER = ['a11y', 'keyboard', 'volume', 'bluetooth', 'network', 'battery'];
|
||||
const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
|
||||
const STANDARD_STATUS_AREA_ORDER = ['a11y', 'keyboard', 'volume', 'bluetooth', 'network', 'battery', 'userMenu'];
|
||||
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.XKBIndicator
|
||||
'keyboard': imports.ui.status.keyboard.XKBIndicator,
|
||||
'userMenu': imports.ui.userMenu.UserMenuButton
|
||||
};
|
||||
|
||||
if (Config.HAVE_BLUETOOTH)
|
||||
STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION['bluetooth'] = imports.ui.status.bluetooth.Indicator;
|
||||
STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION['bluetooth'] = imports.ui.status.bluetooth.Indicator;
|
||||
|
||||
try {
|
||||
STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION['network'] = imports.ui.status.network.NMApplet;
|
||||
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 GDM_TRAY_ICON_ORDER = ['a11y', 'display', 'keyboard', 'volume', 'battery'];
|
||||
const GDM_TRAY_ICON_SHELL_IMPLEMENTATION = {
|
||||
const GDM_STATUS_AREA_ORDER = ['a11y', 'display', 'keyboard', 'volume', 'battery', 'powerMenu'];
|
||||
const GDM_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.XKBIndicator
|
||||
'keyboard': imports.ui.status.keyboard.XKBIndicator,
|
||||
'powerMenu': imports.gdm.powerMenu.PowerMenuButton
|
||||
};
|
||||
|
||||
// To make sure the panel corners blend nicely with the panel,
|
||||
@ -97,11 +99,9 @@ function _unpremultiply(color) {
|
||||
};
|
||||
|
||||
|
||||
function AnimatedIcon(name, size) {
|
||||
this._init(name, size);
|
||||
}
|
||||
const AnimatedIcon = new Lang.Class({
|
||||
Name: 'AnimatedIcon',
|
||||
|
||||
AnimatedIcon.prototype = {
|
||||
_init: function(name, size) {
|
||||
this.actor = new St.Bin({ visible: false });
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
@ -138,13 +138,11 @@ AnimatedIcon.prototype = {
|
||||
if (this._timeoutId)
|
||||
Mainloop.source_remove(this._timeoutId);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function TextShadower() {
|
||||
this._init();
|
||||
}
|
||||
const TextShadower = new Lang.Class({
|
||||
Name: 'TextShadower',
|
||||
|
||||
TextShadower.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new Shell.GenericContainer();
|
||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
@ -224,7 +222,7 @@ TextShadower.prototype = {
|
||||
child.allocate(childBox, flags);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* AppMenuButton:
|
||||
@ -234,21 +232,20 @@ TextShadower.prototype = {
|
||||
* this menu also handles startup notification for it. So when we
|
||||
* have an active startup notification, we switch modes to display that.
|
||||
*/
|
||||
function AppMenuButton() {
|
||||
this._init();
|
||||
}
|
||||
const AppMenuButton = new Lang.Class({
|
||||
Name: 'AppMenuButton',
|
||||
Extends: PanelMenu.Button,
|
||||
|
||||
AppMenuButton.prototype = {
|
||||
__proto__: PanelMenu.Button.prototype,
|
||||
_init: function(menuManager) {
|
||||
this.parent(0.0, true);
|
||||
|
||||
_init: function() {
|
||||
PanelMenu.Button.prototype._init.call(this, 0.0);
|
||||
this._startingApps = [];
|
||||
|
||||
this._menuManager = menuManager;
|
||||
this._targetApp = null;
|
||||
|
||||
let bin = new St.Bin({ name: 'appMenu' });
|
||||
this.actor.set_child(bin);
|
||||
this.actor.add_actor(bin);
|
||||
|
||||
this.actor.reactive = false;
|
||||
this._targetIsCurrent = false;
|
||||
@ -270,10 +267,6 @@ AppMenuButton.prototype = {
|
||||
|
||||
this._iconBottomClip = 0;
|
||||
|
||||
this._quitMenu = new PopupMenu.PopupMenuItem('');
|
||||
this.menu.addMenuItem(this._quitMenu);
|
||||
this._quitMenu.connect('activate', Lang.bind(this, this._onQuit));
|
||||
|
||||
this._visible = !Main.overview.visible;
|
||||
if (!this._visible)
|
||||
this.actor.hide();
|
||||
@ -452,12 +445,6 @@ AppMenuButton.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_onQuit: function() {
|
||||
if (this._targetApp == null)
|
||||
return;
|
||||
this._targetApp.request_quit();
|
||||
},
|
||||
|
||||
_onAppStateChanged: function(appSys, app) {
|
||||
let state = app.state;
|
||||
if (state != Shell.AppState.STARTING) {
|
||||
@ -519,8 +506,10 @@ AppMenuButton.prototype = {
|
||||
}
|
||||
|
||||
if (targetApp == this._targetApp) {
|
||||
if (targetApp && targetApp.get_state() != Shell.AppState.STARTING)
|
||||
if (targetApp && targetApp.get_state() != Shell.AppState.STARTING) {
|
||||
this.stopAnimation();
|
||||
this._maybeSetMenu();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -534,39 +523,60 @@ AppMenuButton.prototype = {
|
||||
let icon = targetApp.get_faded_icon(2 * PANEL_ICON_SIZE);
|
||||
|
||||
this._label.setText(targetApp.get_name());
|
||||
// TODO - _quit() doesn't really work on apps in state STARTING yet
|
||||
this._quitMenu.label.set_text(_("Quit %s").format(targetApp.get_name()));
|
||||
|
||||
this._iconBox.set_child(icon);
|
||||
this._iconBox.show();
|
||||
|
||||
if (targetApp.get_state() == Shell.AppState.STARTING)
|
||||
this.startAnimation();
|
||||
else
|
||||
this._maybeSetMenu();
|
||||
|
||||
this.emit('changed');
|
||||
},
|
||||
|
||||
_maybeSetMenu: function() {
|
||||
let menu;
|
||||
|
||||
if (this._targetApp.action_group) {
|
||||
if (this.menu instanceof PopupMenu.RemoteMenu &&
|
||||
this.menu.actionGroup == this._targetApp.action_group)
|
||||
return;
|
||||
|
||||
menu = new PopupMenu.RemoteMenu(this.actor, this._targetApp.menu, this._targetApp.action_group);
|
||||
} else {
|
||||
if (this.menu && !(this.menu instanceof PopupMenu.RemoteMenu))
|
||||
return;
|
||||
|
||||
// fallback to older menu
|
||||
menu = new PopupMenu.PopupMenu(this.actor, 0.0, St.Side.TOP, 0);
|
||||
menu.addAction(_("Quit"), Lang.bind(this, function() {
|
||||
this._targetApp.request_quit();
|
||||
}));
|
||||
}
|
||||
|
||||
this.setMenu(menu);
|
||||
this._menuManager.addMenu(menu);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Signals.addSignalMethods(AppMenuButton.prototype);
|
||||
|
||||
// Activities button. Because everything else in the top bar is a
|
||||
// PanelMenu.Button, it simplifies some things to make this be one too.
|
||||
// We just hack it up to not actually have a menu attached to it.
|
||||
function ActivitiesButton() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
ActivitiesButton.prototype = {
|
||||
__proto__: PanelMenu.Button.prototype,
|
||||
const ActivitiesButton = new Lang.Class({
|
||||
Name: 'ActivitiesButton',
|
||||
Extends: PanelMenu.Button,
|
||||
|
||||
_init: function() {
|
||||
PanelMenu.Button.prototype._init.call(this, 0.0);
|
||||
this.parent(0.0);
|
||||
|
||||
let container = new Shell.GenericContainer();
|
||||
container.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
container.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||
container.connect('allocate', Lang.bind(this, this._allocate));
|
||||
this.actor.child = container;
|
||||
container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth));
|
||||
container.connect('get-preferred-height', Lang.bind(this, this._containerGetPreferredHeight));
|
||||
container.connect('allocate', Lang.bind(this, this._containerAllocate));
|
||||
this.actor.add_actor(container);
|
||||
this.actor.name = 'panelActivities';
|
||||
|
||||
/* Translators: If there is no suitable word for "Activities"
|
||||
@ -598,15 +608,15 @@ ActivitiesButton.prototype = {
|
||||
this._xdndTimeOut = 0;
|
||||
},
|
||||
|
||||
_getPreferredWidth: function(actor, forHeight, alloc) {
|
||||
_containerGetPreferredWidth: function(actor, forHeight, alloc) {
|
||||
[alloc.min_size, alloc.natural_size] = this._label.get_preferred_width(forHeight);
|
||||
},
|
||||
|
||||
_getPreferredHeight: function(actor, forWidth, alloc) {
|
||||
_containerGetPreferredHeight: function(actor, forWidth, alloc) {
|
||||
[alloc.min_size, alloc.natural_size] = this._label.get_preferred_height(forWidth);
|
||||
},
|
||||
|
||||
_allocate: function(actor, box, flags) {
|
||||
_containerAllocate: function(actor, box, flags) {
|
||||
this._label.allocate(box, flags);
|
||||
|
||||
// The hot corner needs to be outside any padding/alignment
|
||||
@ -697,13 +707,11 @@ ActivitiesButton.prototype = {
|
||||
Mainloop.source_remove(this._xdndTimeOut);
|
||||
this._xdndTimeOut = 0;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function PanelCorner(panel, side) {
|
||||
this._init(panel, side);
|
||||
}
|
||||
const PanelCorner = new Lang.Class({
|
||||
Name: 'PanelCorner',
|
||||
|
||||
PanelCorner.prototype = {
|
||||
_init: function(box, side) {
|
||||
this._side = side;
|
||||
|
||||
@ -764,16 +772,28 @@ PanelCorner.prototype = {
|
||||
},
|
||||
|
||||
_boxStyleChanged: function() {
|
||||
let button;
|
||||
let side = this._side;
|
||||
|
||||
if (this._side == St.Side.LEFT)
|
||||
let rtlAwareContainer = this._box instanceof St.BoxLayout;
|
||||
if (rtlAwareContainer &&
|
||||
this._box.get_direction() == St.TextDirection.RTL) {
|
||||
if (this._side == St.Side.LEFT)
|
||||
side = St.Side.RIGHT;
|
||||
else if (this._side == St.Side.RIGHT)
|
||||
side = St.Side.LEFT;
|
||||
}
|
||||
|
||||
let button;
|
||||
if (side == St.Side.LEFT)
|
||||
button = this._findLeftmostButton(this._box);
|
||||
else if (this._side == St.Side.RIGHT)
|
||||
else if (side == St.Side.RIGHT)
|
||||
button = this._findRightmostButton(this._box);
|
||||
|
||||
if (button) {
|
||||
if (this._button && this._buttonStyleChangedSignalId)
|
||||
if (this._button && this._buttonStyleChangedSignalId) {
|
||||
this._button.disconnect(this._buttonStyleChangedSignalId);
|
||||
this._button.style = null;
|
||||
}
|
||||
|
||||
this._button = button;
|
||||
|
||||
@ -791,6 +811,10 @@ PanelCorner.prototype = {
|
||||
let pseudoClass = button.get_style_pseudo_class();
|
||||
this.actor.set_style_pseudo_class(pseudoClass);
|
||||
}));
|
||||
|
||||
// The corner doesn't support theme transitions, so override
|
||||
// the .panel-button default
|
||||
button.style = 'transition-duration: 0';
|
||||
}
|
||||
},
|
||||
|
||||
@ -863,14 +887,12 @@ PanelCorner.prototype = {
|
||||
this.actor.set_size(cornerRadius, innerBorderWidth + cornerRadius);
|
||||
this.actor.set_anchor_point(0, innerBorderWidth);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
function Panel() {
|
||||
this._init();
|
||||
}
|
||||
const Panel = new Lang.Class({
|
||||
Name: 'Panel',
|
||||
|
||||
Panel.prototype = {
|
||||
_init : function() {
|
||||
this.actor = new Shell.GenericContainer({ name: 'panel',
|
||||
reactive: true });
|
||||
@ -885,14 +907,6 @@ Panel.prototype = {
|
||||
this.actor.remove_style_class_name('in-overview');
|
||||
}));
|
||||
|
||||
if (global.session_type == Shell.SessionType.GDM) {
|
||||
this._tray_icon_order = GDM_TRAY_ICON_ORDER;
|
||||
this._tray_icon_shell_implementation = GDM_TRAY_ICON_SHELL_IMPLEMENTATION;
|
||||
} else {
|
||||
this._tray_icon_order = STANDARD_TRAY_ICON_ORDER;
|
||||
this._tray_icon_shell_implementation = STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION;
|
||||
}
|
||||
|
||||
this._menus = new PopupMenu.PopupMenuManager(this);
|
||||
|
||||
this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
|
||||
@ -929,9 +943,8 @@ Panel.prototype = {
|
||||
// more cleanly with the rest of the panel
|
||||
this._menus.addMenu(this._activitiesButton.menu);
|
||||
|
||||
this._appMenu = new AppMenuButton();
|
||||
this._appMenu = new AppMenuButton(this._menus);
|
||||
this._leftBox.add(this._appMenu.actor);
|
||||
this._menus.addMenu(this._appMenu.menu);
|
||||
}
|
||||
|
||||
/* center */
|
||||
@ -943,21 +956,12 @@ Panel.prototype = {
|
||||
this._menus.addMenu(this._dateMenu.menu);
|
||||
|
||||
/* right */
|
||||
|
||||
// System status applets live in statusBox, while legacy tray icons
|
||||
// live in trayBox
|
||||
// The trayBox is hidden when there are no tray icons.
|
||||
this._trayBox = new St.BoxLayout({ name: 'legacyTray' });
|
||||
this._statusBox = new St.BoxLayout({ name: 'statusTray' });
|
||||
|
||||
this._trayBox.hide();
|
||||
this._rightBox.add(this._trayBox);
|
||||
this._rightBox.add(this._statusBox);
|
||||
|
||||
if (global.session_type == Shell.SessionType.USER) {
|
||||
this._userMenu = new UserMenu.UserMenuButton();
|
||||
this._userMenu.actor.name = 'panelStatus';
|
||||
this._rightBox.add(this._userMenu.actor);
|
||||
if (global.session_type == Shell.SessionType.GDM) {
|
||||
this._status_area_order = GDM_STATUS_AREA_ORDER;
|
||||
this._status_area_shell_implementation = GDM_STATUS_AREA_SHELL_IMPLEMENTATION;
|
||||
} else {
|
||||
this._status_area_order = STANDARD_STATUS_AREA_ORDER;
|
||||
this._status_area_shell_implementation = STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION;
|
||||
}
|
||||
|
||||
Main.statusIconDispatcher.connect('status-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
||||
@ -1043,9 +1047,9 @@ Panel.prototype = {
|
||||
},
|
||||
|
||||
startStatusArea: function() {
|
||||
for (let i = 0; i < this._tray_icon_order.length; i++) {
|
||||
let role = this._tray_icon_order[i];
|
||||
let constructor = this._tray_icon_shell_implementation[role];
|
||||
for (let i = 0; i < this._status_area_order.length; i++) {
|
||||
let role = this._status_area_order[i];
|
||||
let constructor = this._status_area_shell_implementation[role];
|
||||
if (!constructor) {
|
||||
// This icon is not implemented (this is a bug)
|
||||
continue;
|
||||
@ -1054,11 +1058,23 @@ Panel.prototype = {
|
||||
let indicator = new constructor();
|
||||
this.addToStatusArea(role, indicator, i);
|
||||
}
|
||||
},
|
||||
|
||||
// PopupMenuManager depends on menus being added in order for
|
||||
// keyboard navigation
|
||||
if (this._userMenu)
|
||||
this._menus.addMenu(this._userMenu.menu);
|
||||
_insertStatusItem: function(actor, position) {
|
||||
let children = this._rightBox.get_children();
|
||||
let i;
|
||||
for (i = children.length - 1; i >= 0; i--) {
|
||||
let rolePosition = children[i]._rolePosition;
|
||||
if (position > rolePosition) {
|
||||
this._rightBox.insert_actor(actor, i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == -1) {
|
||||
// If we didn't find a position, we must be first
|
||||
this._rightBox.insert_actor(actor, 0);
|
||||
}
|
||||
actor._rolePosition = position;
|
||||
},
|
||||
|
||||
addToStatusArea: function(role, indicator, position) {
|
||||
@ -1070,8 +1086,7 @@ Panel.prototype = {
|
||||
|
||||
if (!position)
|
||||
position = 0;
|
||||
|
||||
this._statusBox.insert_actor(indicator.actor, position);
|
||||
this._insertStatusItem(indicator.actor, position);
|
||||
this._menus.addMenu(indicator.menu);
|
||||
|
||||
this._statusArea[role] = indicator;
|
||||
@ -1084,39 +1099,23 @@ Panel.prototype = {
|
||||
},
|
||||
|
||||
_onTrayIconAdded: function(o, icon, role) {
|
||||
icon.height = PANEL_ICON_SIZE;
|
||||
|
||||
if (this._tray_icon_shell_implementation[role]) {
|
||||
if (this._status_area_shell_implementation[role]) {
|
||||
// This icon is legacy, and replaced by a Shell version
|
||||
// Hide it
|
||||
return;
|
||||
}
|
||||
// Figure out the index in our well-known order for this icon
|
||||
let position = this._tray_icon_order.indexOf(role);
|
||||
icon._rolePosition = position;
|
||||
let children = this._trayBox.get_children();
|
||||
let i;
|
||||
// Walk children backwards, until we find one that isn't
|
||||
// well-known, or one where we should follow
|
||||
for (i = children.length - 1; i >= 0; i--) {
|
||||
let rolePosition = children[i]._rolePosition;
|
||||
if (!rolePosition || position > rolePosition) {
|
||||
this._trayBox.insert_actor(icon, i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == -1) {
|
||||
// If we didn't find a position, we must be first
|
||||
this._trayBox.insert_actor(icon, 0);
|
||||
}
|
||||
|
||||
// Make sure the trayBox is shown.
|
||||
this._trayBox.show();
|
||||
icon.height = PANEL_ICON_SIZE;
|
||||
let buttonBox = new PanelMenu.ButtonBox();
|
||||
let box = buttonBox.actor;
|
||||
box.add_actor(icon);
|
||||
|
||||
this._insertStatusItem(box, this._status_area_order.indexOf(role));
|
||||
},
|
||||
|
||||
_onTrayIconRemoved: function(o, icon) {
|
||||
if (icon.get_parent() != null)
|
||||
this._trayBox.remove_actor(icon);
|
||||
let box = icon.get_parent();
|
||||
if (box && box._delegate instanceof PanelMenu.ButtonBox)
|
||||
box.destroy();
|
||||
},
|
||||
|
||||
};
|
||||
});
|
||||
|
@ -1,38 +1,134 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Lang = imports.lang;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
|
||||
function Button(menuAlignment) {
|
||||
this._init(menuAlignment);
|
||||
}
|
||||
const ButtonBox = new Lang.Class({
|
||||
Name: 'ButtonBox',
|
||||
|
||||
Button.prototype = {
|
||||
_init: function(menuAlignment) {
|
||||
this.actor = new St.Bin({ style_class: 'panel-button',
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
x_fill: true,
|
||||
y_fill: false,
|
||||
track_hover: true });
|
||||
_init: function(params) {
|
||||
params = Params.parse(params, { style_class: 'panel-button' }, true);
|
||||
this.actor = new Shell.GenericContainer(params);
|
||||
this.actor._delegate = this;
|
||||
|
||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||
|
||||
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
|
||||
this._minHPadding = this._natHPadding = 0.0;
|
||||
},
|
||||
|
||||
_onStyleChanged: function(actor) {
|
||||
let themeNode = actor.get_theme_node();
|
||||
|
||||
this._minHPadding = themeNode.get_length('-minimum-hpadding');
|
||||
this._natHPadding = themeNode.get_length('-natural-hpadding');
|
||||
},
|
||||
|
||||
_getPreferredWidth: function(actor, forHeight, alloc) {
|
||||
let children = actor.get_children();
|
||||
let child = children.length > 0 ? children[0] : null;
|
||||
|
||||
if (child) {
|
||||
[alloc.min_size, alloc.natural_size] = child.get_preferred_width(-1);
|
||||
} else {
|
||||
alloc.min_size = alloc.natural_size = 0;
|
||||
}
|
||||
|
||||
alloc.min_size += 2 * this._minHPadding;
|
||||
alloc.natural_size += 2 * this._natHPadding;
|
||||
},
|
||||
|
||||
_getPreferredHeight: function(actor, forWidth, alloc) {
|
||||
let children = actor.get_children();
|
||||
let child = children.length > 0 ? children[0] : null;
|
||||
|
||||
if (child) {
|
||||
[alloc.min_size, alloc.natural_size] = child.get_preferred_height(-1);
|
||||
} else {
|
||||
alloc.min_size = alloc.natural_size = 0;
|
||||
}
|
||||
},
|
||||
|
||||
_allocate: function(actor, box, flags) {
|
||||
let children = actor.get_children();
|
||||
if (children.length == 0)
|
||||
return;
|
||||
|
||||
let child = children[0];
|
||||
let [minWidth, natWidth] = child.get_preferred_width(-1);
|
||||
let [minHeight, natHeight] = child.get_preferred_height(-1);
|
||||
|
||||
let availWidth = box.x2 - box.x1;
|
||||
let availHeight = box.y2 - box.y1;
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
if (natWidth + 2 * this._natHPadding <= availWidth) {
|
||||
childBox.x1 = this._natHPadding;
|
||||
childBox.x2 = availWidth - this._natHPadding;
|
||||
} else {
|
||||
childBox.x1 = this._minHPadding;
|
||||
childBox.x2 = availWidth - this._minHPadding;
|
||||
}
|
||||
|
||||
if (natHeight <= availHeight) {
|
||||
childBox.y1 = Math.floor((availHeight - natHeight) / 2);
|
||||
childBox.y2 = childBox.y1 + natHeight;
|
||||
} else {
|
||||
childBox.y1 = 0;
|
||||
childBox.y2 = availHeight;
|
||||
}
|
||||
|
||||
child.allocate(childBox, flags);
|
||||
},
|
||||
});
|
||||
|
||||
const Button = new Lang.Class({
|
||||
Name: 'PanelMenuButton',
|
||||
Extends: ButtonBox,
|
||||
|
||||
_init: function(menuAlignment, dontCreateMenu) {
|
||||
this.parent({ reactive: true,
|
||||
can_focus: true,
|
||||
track_hover: true });
|
||||
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
||||
this.actor.connect('key-press-event', Lang.bind(this, this._onSourceKeyPress));
|
||||
this.menu = new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP);
|
||||
this.menu.actor.add_style_class_name('panel-menu');
|
||||
this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
|
||||
this.menu.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress));
|
||||
Main.uiGroup.add_actor(this.menu.actor);
|
||||
this.menu.actor.hide();
|
||||
|
||||
if (dontCreateMenu)
|
||||
this.menu = null;
|
||||
else
|
||||
this.setMenu(new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP, 0));
|
||||
},
|
||||
|
||||
setMenu: function(menu) {
|
||||
if (this.menu)
|
||||
this.menu.destroy();
|
||||
|
||||
this.menu = menu;
|
||||
if (this.menu) {
|
||||
this.menu.actor.add_style_class_name('panel-menu');
|
||||
this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
|
||||
this.menu.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress));
|
||||
|
||||
Main.uiGroup.add_actor(this.menu.actor);
|
||||
this.menu.actor.hide();
|
||||
}
|
||||
},
|
||||
|
||||
_onButtonPress: function(actor, event) {
|
||||
if (!this.menu)
|
||||
return;
|
||||
|
||||
if (!this.menu.isOpen) {
|
||||
// Setting the max-height won't do any good if the minimum height of the
|
||||
// menu is higher then the screen; it's useful if part of the menu is
|
||||
@ -46,6 +142,9 @@ Button.prototype = {
|
||||
},
|
||||
|
||||
_onSourceKeyPress: function(actor, event) {
|
||||
if (!this.menu)
|
||||
return false;
|
||||
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
|
||||
this.menu.toggle();
|
||||
@ -91,7 +190,7 @@ Button.prototype = {
|
||||
|
||||
this.emit('destroy');
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(Button.prototype);
|
||||
|
||||
/* SystemStatusButton:
|
||||
@ -100,19 +199,18 @@ Signals.addSignalMethods(Button.prototype);
|
||||
* volume, bluetooth...), which is just a PanelMenuButton with an
|
||||
* icon and a tooltip
|
||||
*/
|
||||
function SystemStatusButton() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
SystemStatusButton.prototype = {
|
||||
__proto__: Button.prototype,
|
||||
const SystemStatusButton = new Lang.Class({
|
||||
Name: 'SystemStatusButton',
|
||||
Extends: Button,
|
||||
|
||||
_init: function(iconName,tooltipText) {
|
||||
Button.prototype._init.call(this, 0.0);
|
||||
this.parent(0.0);
|
||||
|
||||
this._iconActor = new St.Icon({ icon_name: iconName,
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
style_class: 'system-status-icon' });
|
||||
this.actor.set_child(this._iconActor);
|
||||
this.actor.add_actor(this._iconActor);
|
||||
this.actor.add_style_class_name('panel-status-button');
|
||||
this.setTooltip(tooltipText);
|
||||
},
|
||||
|
||||
@ -134,4 +232,4 @@ SystemStatusButton.prototype = {
|
||||
this.tooltip = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
@ -22,11 +22,9 @@ const Util = imports.misc.util;
|
||||
* @iconFactory: A JavaScript callback which will create an icon texture given a size parameter
|
||||
* @launch: A JavaScript callback to launch the entry
|
||||
*/
|
||||
function PlaceInfo(id, name, iconFactory, launch) {
|
||||
this._init(id, name, iconFactory, launch);
|
||||
}
|
||||
const PlaceInfo = new Lang.Class({
|
||||
Name: 'PlaceInfo',
|
||||
|
||||
PlaceInfo.prototype = {
|
||||
_init: function(id, name, iconFactory, launch) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
@ -55,7 +53,7 @@ PlaceInfo.prototype = {
|
||||
isRemovable: function() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// Helper function to translate launch parameters into a GAppLaunchContext
|
||||
function _makeLaunchContext(params)
|
||||
@ -72,12 +70,9 @@ function _makeLaunchContext(params)
|
||||
return launchContext;
|
||||
}
|
||||
|
||||
function PlaceDeviceInfo(mount) {
|
||||
this._init(mount);
|
||||
}
|
||||
|
||||
PlaceDeviceInfo.prototype = {
|
||||
__proto__: PlaceInfo.prototype,
|
||||
const PlaceDeviceInfo = new Lang.Class({
|
||||
Name: 'PlaceDeviceInfo',
|
||||
Extends: PlaceInfo,
|
||||
|
||||
_init: function(mount) {
|
||||
this._mount = mount;
|
||||
@ -123,13 +118,11 @@ PlaceDeviceInfo.prototype = {
|
||||
_("Retry"));
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function PlacesManager() {
|
||||
this._init();
|
||||
}
|
||||
const PlacesManager = new Lang.Class({
|
||||
Name: 'PlacesManager',
|
||||
|
||||
PlacesManager.prototype = {
|
||||
_init: function() {
|
||||
this._defaultPlaces = [];
|
||||
this._mounts = [];
|
||||
@ -195,9 +188,9 @@ PlacesManager.prototype = {
|
||||
|
||||
this._bookmarksPath = GLib.build_filenamev([GLib.get_home_dir(), '.gtk-bookmarks']);
|
||||
this._bookmarksFile = Gio.file_new_for_path(this._bookmarksPath);
|
||||
let monitor = this._bookmarksFile.monitor_file(Gio.FileMonitorFlags.NONE, null);
|
||||
this._monitor = this._bookmarksFile.monitor_file(Gio.FileMonitorFlags.NONE, null);
|
||||
this._bookmarkTimeoutId = 0;
|
||||
monitor.connect('changed', Lang.bind(this, function () {
|
||||
this._monitor.connect('changed', Lang.bind(this, function () {
|
||||
if (this._bookmarkTimeoutId > 0)
|
||||
return;
|
||||
/* Defensive event compression */
|
||||
@ -360,19 +353,15 @@ PlacesManager.prototype = {
|
||||
_removeById: function(sourceArray, id) {
|
||||
sourceArray.splice(this._lookupIndexById(sourceArray, id), 1);
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(PlacesManager.prototype);
|
||||
|
||||
|
||||
function PlaceSearchProvider() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
PlaceSearchProvider.prototype = {
|
||||
__proto__: Search.SearchProvider.prototype,
|
||||
const PlaceSearchProvider = new Lang.Class({
|
||||
Name: 'PlaceSearchProvider',
|
||||
Extends: Search.SearchProvider,
|
||||
|
||||
_init: function() {
|
||||
Search.SearchProvider.prototype._init.call(this, _("PLACES & DEVICES"));
|
||||
this.parent(_("PLACES & DEVICES"));
|
||||
},
|
||||
|
||||
getResultMeta: function(resultId) {
|
||||
@ -434,4 +423,4 @@ PlaceSearchProvider.prototype = {
|
||||
let places = previousResults.map(function (id) { return Main.placesManager.lookupPlaceById(id); });
|
||||
return this._searchPlaces(places, terms);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 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
|
||||
@ -27,22 +27,21 @@ const AccountsService = imports.gi.AccountsService;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const St = imports.gi.St;
|
||||
const Pango = imports.gi.Pango;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Polkit = imports.gi.Polkit;
|
||||
const PolkitAgent = imports.gi.PolkitAgent;
|
||||
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
const ShellEntry = imports.ui.shellEntry;
|
||||
|
||||
function AuthenticationDialog(actionId, message, cookie, userNames) {
|
||||
this._init(actionId, message, cookie, userNames);
|
||||
}
|
||||
|
||||
AuthenticationDialog.prototype = {
|
||||
__proto__: ModalDialog.ModalDialog.prototype,
|
||||
const AuthenticationDialog = new Lang.Class({
|
||||
Name: 'AuthenticationDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
|
||||
_init: function(actionId, message, cookie, userNames) {
|
||||
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'polkit-dialog' });
|
||||
this.parent({ styleClass: 'polkit-dialog' });
|
||||
|
||||
this.actionId = actionId;
|
||||
this.message = message;
|
||||
@ -87,10 +86,14 @@ AuthenticationDialog.prototype = {
|
||||
if (userNames.length > 1) {
|
||||
log('polkitAuthenticationAgent: Received ' + userNames.length +
|
||||
' identities that can be used for authentication. Only ' +
|
||||
'considering the first one.');
|
||||
'considering one.');
|
||||
}
|
||||
|
||||
let userName = userNames[0];
|
||||
let userName = GLib.get_user_name();
|
||||
if (userNames.indexOf(userName) < 0)
|
||||
userName = 'root';
|
||||
if (userNames.indexOf(userName) < 0)
|
||||
userName = userNames[0];
|
||||
|
||||
this._user = AccountsService.UserManager.get_default().get_user(userName);
|
||||
let userRealName = this._user.get_real_name()
|
||||
@ -139,9 +142,11 @@ AuthenticationDialog.prototype = {
|
||||
this._passwordEntry = new St.Entry({ style_class: 'polkit-dialog-password-entry',
|
||||
text: "",
|
||||
can_focus: true});
|
||||
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
|
||||
this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivate));
|
||||
this._passwordBox.add(this._passwordEntry,
|
||||
{expand: true });
|
||||
this.setInitialKeyFocus(this._passwordEntry);
|
||||
this._passwordBox.hide();
|
||||
|
||||
this._errorMessageLabel = new St.Label({ style_class: 'polkit-dialog-error-label' });
|
||||
@ -186,13 +191,6 @@ AuthenticationDialog.prototype = {
|
||||
this._session.connect('request', Lang.bind(this, this._onSessionRequest));
|
||||
this._session.connect('show-error', Lang.bind(this, this._onSessionShowError));
|
||||
this._session.connect('show-info', Lang.bind(this, this._onSessionShowInfo));
|
||||
|
||||
// Delay focus grab to avoid ModalDialog stealing focus with
|
||||
// its buttons
|
||||
this.connect('opened',
|
||||
Lang.bind(this, function() {
|
||||
this._passwordEntry.grab_key_focus();
|
||||
}));
|
||||
},
|
||||
|
||||
startAuthentication: function() {
|
||||
@ -334,15 +332,12 @@ AuthenticationDialog.prototype = {
|
||||
this.close(global.get_current_time());
|
||||
this._emitDone(false, true);
|
||||
},
|
||||
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(AuthenticationDialog.prototype);
|
||||
|
||||
function AuthenticationAgent() {
|
||||
this._init();
|
||||
}
|
||||
const AuthenticationAgent = new Lang.Class({
|
||||
Name: 'AuthenticationAgent',
|
||||
|
||||
AuthenticationAgent.prototype = {
|
||||
_init: function() {
|
||||
this._native = new Shell.PolkitAuthenticationAgent();
|
||||
this._native.connect('initiate', Lang.bind(this, this._onInitiate));
|
||||
@ -403,7 +398,7 @@ AuthenticationAgent.prototype = {
|
||||
this._reallyCompleteRequest(wasDismissed);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function init() {
|
||||
let agent = new AuthenticationAgent();
|
||||
|
@ -1,8 +1,10 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 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 GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
@ -26,15 +28,14 @@ function _ensureStyle(actor) {
|
||||
actor.ensure_style();
|
||||
}
|
||||
|
||||
function PopupBaseMenuItem(params) {
|
||||
this._init(params);
|
||||
}
|
||||
const PopupBaseMenuItem = new Lang.Class({
|
||||
Name: 'PopupBaseMenuItem',
|
||||
|
||||
PopupBaseMenuItem.prototype = {
|
||||
_init: function (params) {
|
||||
params = Params.parse (params, { reactive: true,
|
||||
activate: true,
|
||||
hover: true,
|
||||
sensitive: true,
|
||||
style_class: null
|
||||
});
|
||||
this.actor = new Shell.GenericContainer({ style_class: 'popup-menu-item',
|
||||
@ -52,11 +53,15 @@ PopupBaseMenuItem.prototype = {
|
||||
this._columnWidths = null;
|
||||
this._spacing = 0;
|
||||
this.active = false;
|
||||
this._activatable = params.reactive && params.activate;
|
||||
this.sensitive = this._activatable && params.sensitive;
|
||||
|
||||
this.setSensitive(this.sensitive);
|
||||
|
||||
if (params.style_class)
|
||||
this.actor.add_style_class_name(params.style_class);
|
||||
|
||||
if (params.reactive && params.activate) {
|
||||
if (this._activatable) {
|
||||
this.actor.connect('button-release-event', Lang.bind(this, this._onButtonReleaseEvent));
|
||||
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
|
||||
}
|
||||
@ -103,20 +108,39 @@ PopupBaseMenuItem.prototype = {
|
||||
this.emit('activate', event);
|
||||
},
|
||||
|
||||
setActive: function (active) {
|
||||
setActive: function (active, params) {
|
||||
let activeChanged = active != this.active;
|
||||
params = Params.parse (params, { grabKeyboard: true });
|
||||
|
||||
if (activeChanged) {
|
||||
this.active = active;
|
||||
if (active) {
|
||||
this.actor.add_style_pseudo_class('active');
|
||||
this.actor.grab_key_focus();
|
||||
if (params.grabKeyboard)
|
||||
this.actor.grab_key_focus();
|
||||
} else
|
||||
this.actor.remove_style_pseudo_class('active');
|
||||
this.emit('active-changed', active);
|
||||
}
|
||||
},
|
||||
|
||||
setSensitive: function(sensitive) {
|
||||
if (!this._activatable)
|
||||
return;
|
||||
if (this.sensitive == sensitive)
|
||||
return;
|
||||
|
||||
this.sensitive = sensitive;
|
||||
this.actor.reactive = sensitive;
|
||||
this.actor.can_focus = sensitive;
|
||||
|
||||
if (sensitive)
|
||||
this.actor.remove_style_pseudo_class('insensitive');
|
||||
else
|
||||
this.actor.add_style_pseudo_class('insensitive');
|
||||
this.emit('sensitive-changed', sensitive);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.actor.destroy();
|
||||
this.emit('destroy');
|
||||
@ -214,7 +238,7 @@ PopupBaseMenuItem.prototype = {
|
||||
let child = this._children[i];
|
||||
if (i > 0)
|
||||
width += this._spacing;
|
||||
let [min, natural] = child.actor.get_preferred_width(forHeight);
|
||||
let [min, natural] = child.actor.get_preferred_width(-1);
|
||||
width += natural;
|
||||
}
|
||||
}
|
||||
@ -222,10 +246,25 @@ PopupBaseMenuItem.prototype = {
|
||||
},
|
||||
|
||||
_getPreferredHeight: function(actor, forWidth, alloc) {
|
||||
let height = 0;
|
||||
let height = 0, x = 0, minWidth, childWidth;
|
||||
for (let i = 0; i < this._children.length; i++) {
|
||||
let child = this._children[i];
|
||||
let [min, natural] = child.actor.get_preferred_height(-1);
|
||||
if (this._columnWidths) {
|
||||
if (child.span == -1) {
|
||||
childWidth = 0;
|
||||
for (let j = i; j < this._columnWidths.length; j++)
|
||||
childWidth += this._columnWidths[j]
|
||||
} else
|
||||
childWidth = this._columnWidths[i];
|
||||
} else {
|
||||
if (child.span == -1)
|
||||
childWidth = forWidth - x;
|
||||
else
|
||||
[minWidth, childWidth] = child.actor.get_preferred_width(-1);
|
||||
}
|
||||
x += childWidth;
|
||||
|
||||
let [min, natural] = child.actor.get_preferred_height(childWidth);
|
||||
if (natural > height)
|
||||
height = natural;
|
||||
}
|
||||
@ -283,7 +322,14 @@ PopupBaseMenuItem.prototype = {
|
||||
}
|
||||
extraWidth = availWidth - naturalWidth;
|
||||
} else {
|
||||
availWidth = naturalWidth;
|
||||
if (child.span == -1) {
|
||||
if (direction == St.TextDirection.LTR)
|
||||
availWidth = box.x2 - x;
|
||||
else
|
||||
availWidth = x - box.x1;
|
||||
} else {
|
||||
availWidth = naturalWidth;
|
||||
}
|
||||
extraWidth = 0;
|
||||
}
|
||||
|
||||
@ -291,7 +337,7 @@ PopupBaseMenuItem.prototype = {
|
||||
if (child.expand) {
|
||||
childBox.x1 = x;
|
||||
childBox.x2 = x + availWidth;
|
||||
} else if (child.align === St.Align.CENTER) {
|
||||
} else if (child.align === St.Align.MIDDLE) {
|
||||
childBox.x1 = x + Math.round(extraWidth / 2);
|
||||
childBox.x2 = childBox.x1 + naturalWidth;
|
||||
} else if (child.align === St.Align.END) {
|
||||
@ -305,7 +351,7 @@ PopupBaseMenuItem.prototype = {
|
||||
if (child.expand) {
|
||||
childBox.x1 = x - availWidth;
|
||||
childBox.x2 = x;
|
||||
} else if (child.align === St.Align.CENTER) {
|
||||
} else if (child.align === St.Align.MIDDLE) {
|
||||
childBox.x1 = x - Math.round(extraWidth / 2);
|
||||
childBox.x2 = childBox.x1 + naturalWidth;
|
||||
} else if (child.align === St.Align.END) {
|
||||
@ -319,7 +365,7 @@ PopupBaseMenuItem.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
let [minHeight, naturalHeight] = child.actor.get_preferred_height(-1);
|
||||
let [minHeight, naturalHeight] = child.actor.get_preferred_height(childBox.x2 - childBox.x1);
|
||||
childBox.y1 = Math.round(box.y1 + (height - naturalHeight) / 2);
|
||||
childBox.y2 = childBox.y1 + naturalHeight;
|
||||
|
||||
@ -331,33 +377,27 @@ PopupBaseMenuItem.prototype = {
|
||||
x -= availWidth + this._spacing;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(PopupBaseMenuItem.prototype);
|
||||
|
||||
function PopupMenuItem() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
PopupMenuItem.prototype = {
|
||||
__proto__: PopupBaseMenuItem.prototype,
|
||||
const PopupMenuItem = new Lang.Class({
|
||||
Name: 'PopupMenuItem',
|
||||
Extends: PopupBaseMenuItem,
|
||||
|
||||
_init: function (text, params) {
|
||||
PopupBaseMenuItem.prototype._init.call(this, params);
|
||||
this.parent(params);
|
||||
|
||||
this.label = new St.Label({ text: text });
|
||||
this.addActor(this.label);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function PopupSeparatorMenuItem() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
PopupSeparatorMenuItem.prototype = {
|
||||
__proto__: PopupBaseMenuItem.prototype,
|
||||
const PopupSeparatorMenuItem = new Lang.Class({
|
||||
Name: 'PopupSeparatorMenuItem',
|
||||
Extends: PopupBaseMenuItem,
|
||||
|
||||
_init: function () {
|
||||
PopupBaseMenuItem.prototype._init.call(this, { reactive: false });
|
||||
this.parent({ reactive: false });
|
||||
|
||||
this._drawingArea = new St.DrawingArea({ style_class: 'popup-separator-menu-item' });
|
||||
this.addActor(this._drawingArea, { span: -1, expand: true });
|
||||
@ -383,22 +423,19 @@ PopupSeparatorMenuItem.prototype = {
|
||||
cr.rectangle(margin, gradientOffset, gradientWidth, gradientHeight);
|
||||
cr.fill();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const PopupAlternatingMenuItemState = {
|
||||
DEFAULT: 0,
|
||||
ALTERNATIVE: 1
|
||||
}
|
||||
|
||||
function PopupAlternatingMenuItem() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
PopupAlternatingMenuItem.prototype = {
|
||||
__proto__: PopupBaseMenuItem.prototype,
|
||||
const PopupAlternatingMenuItem = new Lang.Class({
|
||||
Name: 'PopupAlternatingMenuItem',
|
||||
Extends: PopupBaseMenuItem,
|
||||
|
||||
_init: function(text, alternateText, params) {
|
||||
PopupBaseMenuItem.prototype._init.call(this, params);
|
||||
this.parent(params);
|
||||
this.actor.add_style_class_name('popup-alternating-menu-item');
|
||||
|
||||
this._text = text;
|
||||
@ -484,17 +521,14 @@ PopupAlternatingMenuItem.prototype = {
|
||||
|
||||
this._updateLabel();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function PopupSliderMenuItem() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
PopupSliderMenuItem.prototype = {
|
||||
__proto__: PopupBaseMenuItem.prototype,
|
||||
const PopupSliderMenuItem = new Lang.Class({
|
||||
Name: 'PopupSliderMenuItem',
|
||||
Extends: PopupBaseMenuItem,
|
||||
|
||||
_init: function(value) {
|
||||
PopupBaseMenuItem.prototype._init.call(this, { activate: false });
|
||||
this.parent({ activate: false });
|
||||
|
||||
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
|
||||
|
||||
@ -670,13 +704,11 @@ PopupSliderMenuItem.prototype = {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function Switch() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
const Switch = new Lang.Class({
|
||||
Name: 'Switch',
|
||||
|
||||
Switch.prototype = {
|
||||
_init: function(state) {
|
||||
this.actor = new St.Bin({ style_class: 'toggle-switch' });
|
||||
// Translators: this MUST be either "toggle-switch-us"
|
||||
@ -699,17 +731,14 @@ Switch.prototype = {
|
||||
toggle: function() {
|
||||
this.setToggleState(!this.state);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function PopupSwitchMenuItem() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
PopupSwitchMenuItem.prototype = {
|
||||
__proto__: PopupBaseMenuItem.prototype,
|
||||
const PopupSwitchMenuItem = new Lang.Class({
|
||||
Name: 'PopupSwitchMenuItem',
|
||||
Extends: PopupBaseMenuItem,
|
||||
|
||||
_init: function(text, active, params) {
|
||||
PopupBaseMenuItem.prototype._init.call(this, params);
|
||||
this.parent(params);
|
||||
|
||||
this.label = new St.Label({ text: text });
|
||||
this._switch = new Switch(active);
|
||||
@ -744,7 +773,7 @@ PopupSwitchMenuItem.prototype = {
|
||||
this.toggle();
|
||||
}
|
||||
|
||||
PopupBaseMenuItem.prototype.activate.call(this, event);
|
||||
this.parent(event);
|
||||
},
|
||||
|
||||
toggle: function() {
|
||||
@ -759,17 +788,14 @@ PopupSwitchMenuItem.prototype = {
|
||||
setToggleState: function(state) {
|
||||
this._switch.setToggleState(state);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function PopupImageMenuItem() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
PopupImageMenuItem.prototype = {
|
||||
__proto__: PopupBaseMenuItem.prototype,
|
||||
const PopupImageMenuItem = new Lang.Class({
|
||||
Name: 'PopupImageMenuItem',
|
||||
Extends: PopupBaseMenuItem,
|
||||
|
||||
_init: function (text, iconName, params) {
|
||||
PopupBaseMenuItem.prototype._init.call(this, params);
|
||||
this.parent(params);
|
||||
|
||||
this.label = new St.Label({ text: text });
|
||||
this.addActor(this.label);
|
||||
@ -782,13 +808,12 @@ PopupImageMenuItem.prototype = {
|
||||
setIcon: function(name) {
|
||||
this._icon.icon_name = name;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function PopupMenuBase() {
|
||||
throw new TypeError('Trying to instantiate abstract class PopupMenuBase');
|
||||
}
|
||||
const PopupMenuBase = new Lang.Class({
|
||||
Name: 'PopupMenuBase',
|
||||
Abstract: true,
|
||||
|
||||
PopupMenuBase.prototype = {
|
||||
_init: function(sourceActor, styleClass) {
|
||||
this.sourceActor = sourceActor;
|
||||
|
||||
@ -899,6 +924,17 @@ PopupMenuBase.prototype = {
|
||||
this.emit('active-changed', null);
|
||||
}
|
||||
}));
|
||||
menuItem._sensitiveChangeId = menuItem.connect('sensitive-changed', Lang.bind(this, function(menuItem, sensitive) {
|
||||
if (!sensitive && this._activeMenuItem == menuItem) {
|
||||
if (!this.actor.navigate_focus(menuItem.actor,
|
||||
Gtk.DirectionType.TAB_FORWARD,
|
||||
true))
|
||||
this.actor.grab_key_focus();
|
||||
} else if (sensitive && this._activeMenuItem == null) {
|
||||
if (global.stage.get_key_focus() == this.actor)
|
||||
menuItem.actor.grab_key_focus();
|
||||
}
|
||||
}));
|
||||
menuItem._activateId = menuItem.connect('activate', Lang.bind(this, function (menuItem, event) {
|
||||
this.emit('activate', menuItem);
|
||||
this.close(true);
|
||||
@ -906,6 +942,7 @@ PopupMenuBase.prototype = {
|
||||
menuItem.connect('destroy', Lang.bind(this, function(emitter) {
|
||||
menuItem.disconnect(menuItem._activateId);
|
||||
menuItem.disconnect(menuItem._activeChangeId);
|
||||
menuItem.disconnect(menuItem._sensitiveChangeId);
|
||||
if (menuItem.menu) {
|
||||
menuItem.menu.disconnect(menuItem._subMenuActivateId);
|
||||
menuItem.menu.disconnect(menuItem._subMenuActiveChangeId);
|
||||
@ -963,6 +1000,11 @@ PopupMenuBase.prototype = {
|
||||
}
|
||||
if (menuItem instanceof PopupMenuSection) {
|
||||
this._connectSubMenuSignals(menuItem, menuItem);
|
||||
menuItem._closingId = this.connect('open-state-changed',
|
||||
function(self, open) {
|
||||
if (!open)
|
||||
menuItem.close(false);
|
||||
});
|
||||
menuItem.connect('destroy', Lang.bind(this, function() {
|
||||
menuItem.disconnect(menuItem._subMenuActivateId);
|
||||
menuItem.disconnect(menuItem._subMenuActiveChangeId);
|
||||
@ -1076,20 +1118,17 @@ PopupMenuBase.prototype = {
|
||||
|
||||
this.emit('destroy');
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(PopupMenuBase.prototype);
|
||||
|
||||
function PopupMenu() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
const PopupMenu = new Lang.Class({
|
||||
Name: 'PopupMenu',
|
||||
Extends: PopupMenuBase,
|
||||
|
||||
PopupMenu.prototype = {
|
||||
__proto__: PopupMenuBase.prototype,
|
||||
_init: function(sourceActor, arrowAlignment, arrowSide) {
|
||||
this.parent(sourceActor, 'popup-menu-content');
|
||||
|
||||
_init: function(sourceActor, alignment, arrowSide) {
|
||||
PopupMenuBase.prototype._init.call (this, sourceActor, 'popup-menu-content');
|
||||
|
||||
this._alignment = alignment;
|
||||
this._arrowAlignment = arrowAlignment;
|
||||
this._arrowSide = arrowSide;
|
||||
|
||||
this._boxPointer = new BoxPointer.BoxPointer(arrowSide,
|
||||
@ -1142,13 +1181,17 @@ PopupMenu.prototype = {
|
||||
this._boxPointer.setArrowOrigin(origin);
|
||||
},
|
||||
|
||||
setSourceAlignment: function(alignment) {
|
||||
this._boxPointer.setSourceAlignment(alignment);
|
||||
},
|
||||
|
||||
open: function(animate) {
|
||||
if (this.isOpen)
|
||||
return;
|
||||
|
||||
this.isOpen = true;
|
||||
|
||||
this._boxPointer.setPosition(this.sourceActor, this._alignment);
|
||||
this._boxPointer.setPosition(this.sourceActor, this._arrowAlignment);
|
||||
this._boxPointer.show(animate);
|
||||
|
||||
this.actor.raise_top();
|
||||
@ -1168,17 +1211,14 @@ PopupMenu.prototype = {
|
||||
this.isOpen = false;
|
||||
this.emit('open-state-changed', false);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function PopupSubMenu() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
PopupSubMenu.prototype = {
|
||||
__proto__: PopupMenuBase.prototype,
|
||||
const PopupSubMenu = new Lang.Class({
|
||||
Name: 'PopupSubMenu',
|
||||
Extends: PopupMenuBase,
|
||||
|
||||
_init: function(sourceActor, sourceArrow) {
|
||||
PopupMenuBase.prototype._init.call(this, sourceActor);
|
||||
this.parent(sourceActor);
|
||||
|
||||
this._arrow = sourceArrow;
|
||||
this._arrow.rotation_center_z_gravity = Clutter.Gravity.CENTER;
|
||||
@ -1333,7 +1373,7 @@ PopupSubMenu.prototype = {
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* PopupMenuSection:
|
||||
@ -1343,35 +1383,30 @@ PopupSubMenu.prototype = {
|
||||
* can add it to another menu), but is completely transparent
|
||||
* to the user
|
||||
*/
|
||||
function PopupMenuSection() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
PopupMenuSection.prototype = {
|
||||
__proto__: PopupMenuBase.prototype,
|
||||
const PopupMenuSection = new Lang.Class({
|
||||
Name: 'PopupMenuSection',
|
||||
Extends: PopupMenuBase,
|
||||
|
||||
_init: function() {
|
||||
PopupMenuBase.prototype._init.call(this);
|
||||
this.parent();
|
||||
|
||||
this.actor = this.box;
|
||||
this.actor._delegate = this;
|
||||
this.isOpen = true;
|
||||
},
|
||||
|
||||
// deliberately ignore any attempt to open() or close()
|
||||
open: function(animate) { },
|
||||
close: function() { },
|
||||
}
|
||||
// deliberately ignore any attempt to open() or close(), but emit the
|
||||
// corresponding signal so children can still pick it up
|
||||
open: function(animate) { this.emit('open-state-changed', true); },
|
||||
close: function() { this.emit('open-state-changed', false); },
|
||||
});
|
||||
|
||||
function PopupSubMenuMenuItem() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
PopupSubMenuMenuItem.prototype = {
|
||||
__proto__: PopupBaseMenuItem.prototype,
|
||||
const PopupSubMenuMenuItem = new Lang.Class({
|
||||
Name: 'PopupSubMenuMenuItem',
|
||||
Extends: PopupBaseMenuItem,
|
||||
|
||||
_init: function(text) {
|
||||
PopupBaseMenuItem.prototype._init.call(this);
|
||||
this.parent();
|
||||
|
||||
this.actor.add_style_class_name('popup-submenu-menu-item');
|
||||
|
||||
@ -1393,7 +1428,8 @@ PopupSubMenuMenuItem.prototype = {
|
||||
|
||||
destroy: function() {
|
||||
this.menu.destroy();
|
||||
PopupBaseMenuItem.prototype.destroy.call(this);
|
||||
|
||||
this.parent();
|
||||
},
|
||||
|
||||
_onKeyPressEvent: function(actor, event) {
|
||||
@ -1408,7 +1444,7 @@ PopupSubMenuMenuItem.prototype = {
|
||||
return true;
|
||||
}
|
||||
|
||||
return PopupBaseMenuItem.prototype._onKeyPressEvent.call(this, actor, event);
|
||||
return this.parent(actor, event);
|
||||
},
|
||||
|
||||
activate: function(event) {
|
||||
@ -1418,22 +1454,21 @@ PopupSubMenuMenuItem.prototype = {
|
||||
_onButtonReleaseEvent: function(actor) {
|
||||
this.menu.toggle();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function PopupComboMenu() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
PopupComboMenu.prototype = {
|
||||
__proto__: PopupMenuBase.prototype,
|
||||
const PopupComboMenu = new Lang.Class({
|
||||
Name: 'PopupComboMenu',
|
||||
Extends: PopupMenuBase,
|
||||
|
||||
_init: function(sourceActor) {
|
||||
PopupMenuBase.prototype._init.call(this,
|
||||
sourceActor, 'popup-combo-menu');
|
||||
this.parent(sourceActor, 'popup-combo-menu');
|
||||
|
||||
this.actor = this.box;
|
||||
this.actor._delegate = this;
|
||||
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
|
||||
this.actor.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
|
||||
sourceActor.connect('style-changed',
|
||||
Lang.bind(this, this._onSourceActorStyleChanged));
|
||||
this._activeItemPos = -1;
|
||||
global.focus_manager.add_group(this.actor);
|
||||
},
|
||||
@ -1453,6 +1488,26 @@ PopupComboMenu.prototype = {
|
||||
activeItem.actor.grab_key_focus();
|
||||
},
|
||||
|
||||
_onSourceActorStyleChanged: function() {
|
||||
// PopupComboBoxMenuItem clones the active item's actors
|
||||
// to work with arbitrary items in the menu; this means
|
||||
// that we need to propagate some style information and
|
||||
// enforce style updates even when the menu is closed
|
||||
let activeItem = this._getMenuItems()[this._activeItemPos];
|
||||
if (this.sourceActor.has_style_pseudo_class('insensitive'))
|
||||
activeItem.actor.add_style_pseudo_class('insensitive');
|
||||
else
|
||||
activeItem.actor.remove_style_pseudo_class('insensitive');
|
||||
|
||||
// To propagate the :active style, we need to make sure that the
|
||||
// internal state of the PopupComboMenu is updated as well, but
|
||||
// we must not move the keyboard grab
|
||||
activeItem.setActive(this.sourceActor.has_style_pseudo_class('active'),
|
||||
{ grabKeyboard: false });
|
||||
|
||||
_ensureStyle(this.actor);
|
||||
},
|
||||
|
||||
open: function() {
|
||||
if (this.isOpen)
|
||||
return;
|
||||
@ -1512,23 +1567,21 @@ PopupComboMenu.prototype = {
|
||||
getItemVisible: function(position) {
|
||||
return this._getMenuItems()[position].actor.visible;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function PopupComboBoxMenuItem() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
PopupComboBoxMenuItem.prototype = {
|
||||
__proto__: PopupBaseMenuItem.prototype,
|
||||
const PopupComboBoxMenuItem = new Lang.Class({
|
||||
Name: 'PopupComboBoxMenuItem',
|
||||
Extends: PopupBaseMenuItem,
|
||||
|
||||
_init: function (params) {
|
||||
PopupBaseMenuItem.prototype._init.call(this, params);
|
||||
this.parent(params);
|
||||
|
||||
this._itemBox = new Shell.Stack();
|
||||
this.addActor(this._itemBox);
|
||||
|
||||
let expander = new St.Label({ text: '\u2304' });
|
||||
this.addActor(expander, { align: St.Align.END });
|
||||
this.addActor(expander, { align: St.Align.END,
|
||||
span: -1 });
|
||||
|
||||
this._menu = new PopupComboMenu(this.actor);
|
||||
Main.uiGroup.add_actor(this._menu.actor);
|
||||
@ -1639,16 +1692,262 @@ PopupComboBoxMenuItem.prototype = {
|
||||
this.setActiveItem(position);
|
||||
this.emit('active-item-changed', position);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* RemoteMenu:
|
||||
*
|
||||
* A PopupMenu that tracks a GMenuModel and shows its actions
|
||||
* (exposed by GApplication/GActionGroup)
|
||||
*/
|
||||
const RemoteMenu = new Lang.Class({
|
||||
Name: 'RemoteMenu',
|
||||
Extends: PopupMenu,
|
||||
|
||||
_init: function(sourceActor, model, actionGroup) {
|
||||
this.parent(sourceActor, 0.0, St.Side.TOP);
|
||||
|
||||
this.model = model;
|
||||
this.actionGroup = actionGroup;
|
||||
|
||||
this._actions = { };
|
||||
this._modelChanged(this.model, 0, 0, this.model.get_n_items(), this);
|
||||
|
||||
this._actionStateChangeId = this.actionGroup.connect('action-state-changed', Lang.bind(this, this._actionStateChanged));
|
||||
this._actionEnableChangeId = this.actionGroup.connect('action-enabled-changed', Lang.bind(this, this._actionEnabledChanged));
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
if (this._actionStateChangeId) {
|
||||
this.actionGroup.disconnect(this._actionStateChangeId);
|
||||
this._actionStateChangeId = 0;
|
||||
}
|
||||
|
||||
if (this._actionEnableChangeId) {
|
||||
this.actionGroup.disconnect(this._actionEnableChangeId);
|
||||
this._actionEnableChangeId = 0;
|
||||
}
|
||||
|
||||
this.parent();
|
||||
},
|
||||
|
||||
_createMenuItem: function(model, index) {
|
||||
let section_link = model.get_item_link(index, Gio.MENU_LINK_SECTION);
|
||||
if (section_link) {
|
||||
let item = new PopupMenuSection();
|
||||
this._modelChanged(section_link, 0, 0, section_link.get_n_items(), item);
|
||||
return [item, true, ''];
|
||||
}
|
||||
|
||||
// labels are not checked for existance, as they're required for all items
|
||||
let label = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_LABEL, null).deep_unpack();
|
||||
// remove all underscores that are not followed by another underscore
|
||||
label = label.replace(/_([^_])/, '$1');
|
||||
let submenu_link = model.get_item_link(index, Gio.MENU_LINK_SUBMENU);
|
||||
|
||||
if (submenu_link) {
|
||||
let item = new PopupSubMenuMenuItem(label);
|
||||
this._modelChanged(submenu_link, 0, 0, submenu_link.get_n_items(), item.menu);
|
||||
return [item, false, ''];
|
||||
}
|
||||
|
||||
let action_id = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_ACTION, null).deep_unpack();
|
||||
if (!this.actionGroup.has_action(action_id)) {
|
||||
// the action may not be there yet, wait for action-added
|
||||
return [null, false, 'action-added'];
|
||||
}
|
||||
|
||||
if (!this._actions[action_id])
|
||||
this._actions[action_id] = { enabled: this.actionGroup.get_action_enabled(action_id),
|
||||
state: this.actionGroup.get_action_state(action_id),
|
||||
items: [ ],
|
||||
};
|
||||
let action = this._actions[action_id];
|
||||
let item, target, destroyId, specificSignalId;
|
||||
|
||||
if (action.state) {
|
||||
// Docs have get_state_hint(), except that the DBus protocol
|
||||
// has no provision for it (so ShellApp does not implement it,
|
||||
// and neither GApplication), and g_action_get_state_hint()
|
||||
// always returns null
|
||||
// Funny :)
|
||||
|
||||
switch (String.fromCharCode(action.state.classify())) {
|
||||
case 'b':
|
||||
item = new PopupSwitchMenuItem(label, action.state.get_boolean());
|
||||
action.items.push(item);
|
||||
specificSignalId = item.connect('toggled', Lang.bind(this, function(item) {
|
||||
this.actionGroup.change_action_state(action_id, GLib.Variant.new_boolean(item.state));
|
||||
}));
|
||||
break;
|
||||
case 'd':
|
||||
item = new PopupSliderMenuItem(label, action.state.get_double());
|
||||
action.items.push(item);
|
||||
// value-changed is emitted for each motion-event, maybe an idle is more appropriate here?
|
||||
specificSignalId = item.connect('value-changed', Lang.bind(this, function(item) {
|
||||
this.actionGroup.change_action_state(action_id, GLib.Variant.new_double(item.value));
|
||||
}));
|
||||
break;
|
||||
case 's':
|
||||
item = new PopupMenuItem(label);
|
||||
item._remoteTarget = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_TARGET, null).deep_unpack();
|
||||
action.items.push(item);
|
||||
item.setShowDot(action.state.deep_unpack() == item._remoteTarget);
|
||||
specificSignalId = item.connect('activate', Lang.bind(this, function(item) {
|
||||
this.actionGroup.change_action_state(action_id, GLib.Variant.new_string(item._remoteTarget));
|
||||
}));
|
||||
break;
|
||||
default:
|
||||
log('Action "%s" has state of type %s, which is not supported'.format(action_id, action.state.get_type_string()));
|
||||
return [null, false, 'action-state-changed'];
|
||||
}
|
||||
} else {
|
||||
target = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_TARGET, null);
|
||||
item = new PopupMenuItem(label);
|
||||
action.items.push(item);
|
||||
specificSignalId = item.connect('activate', Lang.bind(this, function() {
|
||||
this.actionGroup.activate_action(action_id, target);
|
||||
}));
|
||||
}
|
||||
|
||||
item.actor.reactive = item.actor.can_focus = action.enabled;
|
||||
if (action.enabled)
|
||||
item.actor.remove_style_pseudo_class('insensitive');
|
||||
else
|
||||
item.actor.add_style_pseudo_class('insensitive');
|
||||
|
||||
destroyId = item.connect('destroy', Lang.bind(this, function() {
|
||||
item.disconnect(destroyId);
|
||||
item.disconnect(specificSignalId);
|
||||
|
||||
let pos = action.items.indexOf(item);
|
||||
if (pos != -1)
|
||||
action.items.splice(pos, 1);
|
||||
}));
|
||||
|
||||
return [item, false, ''];
|
||||
},
|
||||
|
||||
_modelChanged: function(model, position, removed, added, target) {
|
||||
let j, k;
|
||||
let j0, k0;
|
||||
|
||||
let currentItems = target._getMenuItems();
|
||||
|
||||
for (j0 = 0, k0 = 0; j0 < position; j0++, k0++) {
|
||||
if (currentItems[k0] instanceof PopupSeparatorMenuItem)
|
||||
k0++;
|
||||
}
|
||||
|
||||
if (removed == -1) {
|
||||
// special flag to indicate we should destroy everything
|
||||
for (k = k0; k < currentItems.length; k++)
|
||||
currentItems[k].destroy();
|
||||
} else {
|
||||
for (j = j0, k = k0; j < j0 + removed; j++, k++) {
|
||||
currentItems[k].destroy();
|
||||
|
||||
if (currentItems[k] instanceof PopupSeparatorMenuItem)
|
||||
j--;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = j0, k = k0; j < j0 + added; j++, k++) {
|
||||
let [item, addSeparator, changeSignal] = this._createMenuItem(model, j);
|
||||
|
||||
if (item) {
|
||||
// separators must be added in the parent to make autohiding work
|
||||
if (addSeparator) {
|
||||
target.addMenuItem(new PopupSeparatorMenuItem(), k+1);
|
||||
k++;
|
||||
}
|
||||
|
||||
target.addMenuItem(item, k);
|
||||
|
||||
if (addSeparator) {
|
||||
target.addMenuItem(new PopupSeparatorMenuItem(), k+1);
|
||||
k++;
|
||||
}
|
||||
} else if (changeSignal) {
|
||||
let signalId = this.actionGroup.connect(changeSignal, Lang.bind(this, function() {
|
||||
this.actionGroup.disconnect(signalId);
|
||||
|
||||
// force a full update
|
||||
this._modelChanged(model, 0, -1, model.get_n_items(), target);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if (!model._changedId) {
|
||||
model._changedId = model.connect('items-changed', Lang.bind(this, this._modelChanged, target));
|
||||
model._destroyId = target.connect('destroy', function() {
|
||||
if (model._changedId)
|
||||
model.disconnect(model._changedId);
|
||||
if (model._destroyId)
|
||||
target.disconnect(model._destroyId);
|
||||
model._changedId = 0;
|
||||
model._destroyId = 0;
|
||||
});
|
||||
}
|
||||
|
||||
if (target instanceof PopupMenuSection) {
|
||||
target.actor.visible = target.numMenuItems != 0;
|
||||
} else {
|
||||
let sourceItem = target.sourceActor._delegate;
|
||||
if (sourceItem instanceof PopupSubMenuMenuItem)
|
||||
sourceItem.actor.visible = target.numMenuItems != 0;
|
||||
}
|
||||
},
|
||||
|
||||
_actionStateChanged: function(actionGroup, action_id) {
|
||||
let action = this._actions[action_id];
|
||||
if (!action)
|
||||
return;
|
||||
|
||||
action.state = actionGroup.get_action_state(action_id);
|
||||
if (action.items.length) {
|
||||
switch (String.fromCharCode(action.state.classify())) {
|
||||
case 'b':
|
||||
for (let i = 0; i < action.items.length; i++)
|
||||
action.items[i].setToggleState(action.state.get_boolean());
|
||||
break;
|
||||
case 'd':
|
||||
for (let i = 0; i < action.items.length; i++)
|
||||
action.items[i].setValue(action.state.get_double());
|
||||
break;
|
||||
case 's':
|
||||
for (let i = 0; i < action.items.length; i++)
|
||||
action.items[i].setShowDot(action.items[i]._remoteTarget == action.state.deep_unpack());
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_actionEnabledChanged: function(actionGroup, action_id) {
|
||||
let action = this._actions[action_id];
|
||||
if (!action)
|
||||
return;
|
||||
|
||||
action.enabled = actionGroup.get_action_enabled(action_id);
|
||||
if (action.items.length) {
|
||||
for (let i = 0; i < action.items.length; i++) {
|
||||
let item = action.items[i];
|
||||
item.actor.reactive = item.actor.can_focus = action.enabled;
|
||||
|
||||
if (action.enabled)
|
||||
item.actor.remove_style_pseudo_class('insensitive');
|
||||
else
|
||||
item.actor.add_style_pseudo_class('insensitive');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/* Basic implementation of a menu manager.
|
||||
* Call addMenu to add menus
|
||||
*/
|
||||
function PopupMenuManager(owner) {
|
||||
this._init(owner);
|
||||
}
|
||||
const PopupMenuManager = new Lang.Class({
|
||||
Name: 'PopupMenuManager',
|
||||
|
||||
PopupMenuManager.prototype = {
|
||||
_init: function(owner) {
|
||||
this._owner = owner;
|
||||
this.grabbed = false;
|
||||
@ -1920,4 +2219,4 @@ PopupMenuManager.prototype = {
|
||||
if (this._activeMenu != null)
|
||||
this._activeMenu.close(true);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
@ -12,6 +12,7 @@ const Signals = imports.signals;
|
||||
const FileUtils = imports.misc.fileUtils;
|
||||
const Main = imports.ui.main;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
const ShellEntry = imports.ui.shellEntry;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Util = imports.misc.util;
|
||||
const History = imports.misc.history;
|
||||
@ -29,11 +30,9 @@ const EXEC_ARG_KEY = 'exec-arg';
|
||||
|
||||
const DIALOG_GROW_TIME = 0.1;
|
||||
|
||||
function CommandCompleter() {
|
||||
this._init();
|
||||
}
|
||||
const CommandCompleter = new Lang.Class({
|
||||
Name: 'CommandCompleter',
|
||||
|
||||
CommandCompleter.prototype = {
|
||||
_init : function() {
|
||||
this._changedCount = 0;
|
||||
this._paths = GLib.getenv('PATH').split(':');
|
||||
@ -161,16 +160,14 @@ CommandCompleter.prototype = {
|
||||
return common.substr(text.length);
|
||||
return common;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function RunDialog() {
|
||||
this._init();
|
||||
}
|
||||
const RunDialog = new Lang.Class({
|
||||
Name: 'RunDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
|
||||
RunDialog.prototype = {
|
||||
__proto__: ModalDialog.ModalDialog.prototype,
|
||||
_init : function() {
|
||||
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'run-dialog' });
|
||||
this.parent({ styleClass: 'run-dialog' });
|
||||
|
||||
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
|
||||
this._terminalSettings = new Gio.Settings({ schema: TERMINAL_SCHEMA });
|
||||
@ -210,6 +207,7 @@ __proto__: ModalDialog.ModalDialog.prototype,
|
||||
this.contentLayout.add(label, { y_align: St.Align.START });
|
||||
|
||||
let entry = new St.Entry({ style_class: 'run-dialog-entry' });
|
||||
ShellEntry.addContextMenu(entry);
|
||||
|
||||
this._entryText = entry.clutter_text;
|
||||
this.contentLayout.add(entry, { y_align: St.Align.START });
|
||||
@ -382,8 +380,7 @@ __proto__: ModalDialog.ModalDialog.prototype,
|
||||
if (this._lockdownSettings.get_boolean(DISABLE_COMMAND_LINE_KEY))
|
||||
return;
|
||||
|
||||
ModalDialog.ModalDialog.prototype.open.call(this);
|
||||
this.parent();
|
||||
},
|
||||
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(RunDialog.prototype);
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const DBus = imports.dbus;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
@ -70,24 +69,21 @@ function waitLeisure() {
|
||||
};
|
||||
}
|
||||
|
||||
const PerfHelperIface = {
|
||||
name: 'org.gnome.Shell.PerfHelper',
|
||||
methods: [{ name: 'CreateWindow', inSignature: 'iibb', outSignature: '' },
|
||||
{ name: 'WaitWindows', inSignature: '', outSignature: '' },
|
||||
{ name: 'DestroyWindows', inSignature: '', outSignature: ''}]
|
||||
};
|
||||
const PerfHelperIface = <interface name="org.gnome.Shell.PerfHelper">
|
||||
<method name="CreateWindow">
|
||||
<arg type="i" direction="in" />
|
||||
<arg type="i" direction="in" />
|
||||
<arg type="b" direction="in" />
|
||||
<arg type="b" direction="in" />
|
||||
</method>
|
||||
<method name="WaitWindows" />
|
||||
<method name="DestroyWindows" />
|
||||
</interface>;
|
||||
|
||||
const PerfHelper = function () {
|
||||
this._init();
|
||||
};
|
||||
|
||||
PerfHelper.prototype = {
|
||||
_init: function() {
|
||||
DBus.session.proxifyObject(this, 'org.gnome.Shell.PerfHelper', '/org/gnome/Shell/PerfHelper');
|
||||
}
|
||||
};
|
||||
|
||||
DBus.proxifyPrototype(PerfHelper.prototype, PerfHelperIface);
|
||||
var PerfHelperProxy = Gio.DBusProxy.makeProxyWrapper(PerfHelperIface);
|
||||
function PerfHelper() {
|
||||
return new PerfHelperProxy(Gio.DBus.session, 'org.gnome.Shell.PerfHelper', '/org/gnome/Shell/PerfHelper');
|
||||
}
|
||||
|
||||
let _perfHelper = null;
|
||||
function _getPerfHelper() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
@ -23,11 +23,9 @@ const MatchType = {
|
||||
MULTIPLE_PREFIX: 4
|
||||
};
|
||||
|
||||
function SearchResultDisplay(provider) {
|
||||
this._init(provider);
|
||||
}
|
||||
const SearchResultDisplay = new Lang.Class({
|
||||
Name: 'SearchResultDisplay',
|
||||
|
||||
SearchResultDisplay.prototype = {
|
||||
_init: function(provider) {
|
||||
this.provider = provider;
|
||||
this.actor = null;
|
||||
@ -96,7 +94,7 @@ SearchResultDisplay.prototype = {
|
||||
activateSelected: function() {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* SearchProvider:
|
||||
@ -105,11 +103,9 @@ SearchResultDisplay.prototype = {
|
||||
* to the search system, then call registerProvider()
|
||||
* in SearchSystem with an instance.
|
||||
*/
|
||||
function SearchProvider(title) {
|
||||
this._init(title);
|
||||
}
|
||||
const SearchProvider = new Lang.Class({
|
||||
Name: 'SearchProvider',
|
||||
|
||||
SearchProvider.prototype = {
|
||||
_init: function(title) {
|
||||
this.title = title;
|
||||
this.searchSystem = null;
|
||||
@ -243,14 +239,12 @@ SearchProvider.prototype = {
|
||||
activateResult: function(id) {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(SearchProvider.prototype);
|
||||
|
||||
function OpenSearchSystem() {
|
||||
this._init();
|
||||
}
|
||||
const OpenSearchSystem = new Lang.Class({
|
||||
Name: 'OpenSearchSystem',
|
||||
|
||||
OpenSearchSystem.prototype = {
|
||||
_init: function() {
|
||||
this._providers = [];
|
||||
global.settings.connect('changed::' + DISABLED_OPEN_SEARCH_PROVIDERS_KEY, Lang.bind(this, this._refresh));
|
||||
@ -338,14 +332,12 @@ OpenSearchSystem.prototype = {
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(OpenSearchSystem.prototype);
|
||||
|
||||
function SearchSystem() {
|
||||
this._init();
|
||||
}
|
||||
const SearchSystem = new Lang.Class({
|
||||
Name: 'SearchSystem',
|
||||
|
||||
SearchSystem.prototype = {
|
||||
_init: function() {
|
||||
this._providers = [];
|
||||
this.reset();
|
||||
@ -433,5 +425,5 @@ SearchSystem.prototype = {
|
||||
this._previousResults = results;
|
||||
this.emit('search-completed', results);
|
||||
},
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(SearchSystem.prototype);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
@ -15,11 +15,9 @@ const Search = imports.ui.search;
|
||||
const MAX_SEARCH_RESULTS_ROWS = 1;
|
||||
|
||||
|
||||
function SearchResult(provider, metaInfo, terms) {
|
||||
this._init(provider, metaInfo, terms);
|
||||
}
|
||||
const SearchResult = new Lang.Class({
|
||||
Name: 'SearchResult',
|
||||
|
||||
SearchResult.prototype = {
|
||||
_init: function(provider, metaInfo, terms) {
|
||||
this.provider = provider;
|
||||
this.metaInfo = metaInfo;
|
||||
@ -97,18 +95,16 @@ SearchResult.prototype = {
|
||||
else
|
||||
this.provider.activateResult(this.metaInfo.id, params);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
function GridSearchResults(provider, grid) {
|
||||
this._init(provider, grid);
|
||||
}
|
||||
|
||||
GridSearchResults.prototype = {
|
||||
__proto__: Search.SearchResultDisplay.prototype,
|
||||
const GridSearchResults = new Lang.Class({
|
||||
Name: 'GridSearchResults',
|
||||
Extends: Search.SearchResultDisplay,
|
||||
|
||||
_init: function(provider, grid) {
|
||||
Search.SearchResultDisplay.prototype._init.call(this, provider);
|
||||
this.parent(provider);
|
||||
|
||||
this._grid = grid || new IconGrid.IconGrid({ rowLimit: MAX_SEARCH_RESULTS_ROWS,
|
||||
xAlign: St.Align.START });
|
||||
this.actor = new St.Bin({ x_align: St.Align.START });
|
||||
@ -179,14 +175,11 @@ GridSearchResults.prototype = {
|
||||
let targetActor = this._grid.getItemAtIndex(this.selectionIndex);
|
||||
targetActor._delegate.activate();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const SearchResults = new Lang.Class({
|
||||
Name: 'SearchResults',
|
||||
|
||||
function SearchResults(searchSystem, openSearchSystem) {
|
||||
this._init(searchSystem, openSearchSystem);
|
||||
}
|
||||
|
||||
SearchResults.prototype = {
|
||||
_init: function(searchSystem, openSearchSystem) {
|
||||
this._searchSystem = searchSystem;
|
||||
this._searchSystem.connect('search-updated', Lang.bind(this, this._updateCurrentResults));
|
||||
@ -486,4 +479,4 @@ SearchResults.prototype = {
|
||||
resultDisplay.activateSelected();
|
||||
Main.overview.hide();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,75 +1,77 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const DBus = imports.dbus;
|
||||
const Lang = imports.lang;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
const ExtensionSystem = imports.ui.extensionSystem;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const GnomeShellIface = {
|
||||
name: 'org.gnome.Shell',
|
||||
methods: [{ name: 'Eval',
|
||||
inSignature: 's',
|
||||
outSignature: 'bs'
|
||||
},
|
||||
{ name: 'ListExtensions',
|
||||
inSignature: '',
|
||||
outSignature: 'a{sa{sv}}'
|
||||
},
|
||||
{ name: 'GetExtensionInfo',
|
||||
inSignature: 's',
|
||||
outSignature: 'a{sv}'
|
||||
},
|
||||
{ name: 'GetExtensionErrors',
|
||||
inSignature: 's',
|
||||
outSignature: 'as'
|
||||
},
|
||||
{ name: 'ScreenshotArea',
|
||||
inSignature: 'iiiis',
|
||||
outSignature: 'b'
|
||||
},
|
||||
{ name: 'ScreenshotWindow',
|
||||
inSignature: 'bs',
|
||||
outSignature: 'b'
|
||||
},
|
||||
{ name: 'Screenshot',
|
||||
inSignature: 's',
|
||||
outSignature: 'b'
|
||||
},
|
||||
{ name: 'EnableExtension',
|
||||
inSignature: 's',
|
||||
outSignature: ''
|
||||
},
|
||||
{ name: 'DisableExtension',
|
||||
inSignature: 's',
|
||||
outSignature: ''
|
||||
},
|
||||
{ name: 'InstallRemoteExtension',
|
||||
inSignature: 's',
|
||||
outSignature: ''
|
||||
}
|
||||
],
|
||||
signals: [{ name: 'ExtensionStatusChanged',
|
||||
inSignature: 'sis' }],
|
||||
properties: [{ name: 'OverviewActive',
|
||||
signature: 'b',
|
||||
access: 'readwrite' },
|
||||
{ name: 'ApiVersion',
|
||||
signature: 'i',
|
||||
access: 'read' },
|
||||
{ name: 'ShellVersion',
|
||||
signature: 's',
|
||||
access: 'read' }]
|
||||
};
|
||||
const GnomeShellIface = <interface name="org.gnome.Shell">
|
||||
<method name="Eval">
|
||||
<arg type="s" direction="in" name="script" />
|
||||
<arg type="b" direction="out" name="success" />
|
||||
<arg type="s" direction="out" name="result" />
|
||||
</method>
|
||||
<method name="ListExtensions">
|
||||
<arg type="a{sa{sv}}" direction="out" name="extensions" />
|
||||
</method>
|
||||
<method name="GetExtensionInfo">
|
||||
<arg type="s" direction="in" name="extension" />
|
||||
<arg type="a{sv}" direction="out" name="info" />
|
||||
</method>
|
||||
<method name="GetExtensionErrors">
|
||||
<arg type="s" direction="in" name="extension" />
|
||||
<arg type="as" direction="out" name="errors" />
|
||||
</method>
|
||||
<method name="ScreenshotArea">
|
||||
<arg type="i" direction="in" name="x"/>
|
||||
<arg type="i" direction="in" name="y"/>
|
||||
<arg type="i" direction="in" name="width"/>
|
||||
<arg type="i" direction="in" name="height"/>
|
||||
<arg type="s" direction="in" name="filename"/>
|
||||
<arg type="b" direction="out" name="success"/>
|
||||
</method>
|
||||
<method name="ScreenshotWindow">
|
||||
<arg type="b" direction="in" name="include_frame"/>
|
||||
<arg type="s" direction="in" name="filename"/>
|
||||
<arg type="b" direction="out" name="success"/>
|
||||
</method>
|
||||
<method name="Screenshot">
|
||||
<arg type="s" direction="in" name="filename"/>
|
||||
<arg type="b" direction="out" name="success"/>
|
||||
</method>
|
||||
<method name="EnableExtension">
|
||||
<arg type="s" direction="in" name="uuid"/>
|
||||
</method>
|
||||
<method name="DisableExtension">
|
||||
<arg type="s" direction="in" name="uuid"/>
|
||||
</method>
|
||||
<method name="InstallRemoteExtension">
|
||||
<arg type="s" direction="in" name="uuid"/>
|
||||
<arg type="s" direction="in" name="version"/>
|
||||
</method>
|
||||
<method name="UninstallExtension">
|
||||
<arg type="s" direction="in" name="uuid"/>
|
||||
<arg type="b" direction="out" name="success"/>
|
||||
</method>
|
||||
<property name="OverviewActive" type="b" access="readwrite" />
|
||||
<property name="ApiVersion" type="i" access="read" />
|
||||
<property name="ShellVersion" type="s" access="read" />
|
||||
<signal name="ExtensionStatusChanged">
|
||||
<arg type="s" name="uuid"/>
|
||||
<arg type="i" name="state"/>
|
||||
<arg type="s" name="error"/>
|
||||
</signal>
|
||||
</interface>;
|
||||
|
||||
function GnomeShell() {
|
||||
this._init();
|
||||
}
|
||||
const GnomeShell = new Lang.Class({
|
||||
Name: 'GnomeShellDBus',
|
||||
|
||||
GnomeShell.prototype = {
|
||||
_init: function() {
|
||||
DBus.session.exportObject('/org/gnome/Shell', this);
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellIface, this);
|
||||
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
|
||||
ExtensionSystem.connect('extension-state-changed',
|
||||
Lang.bind(this, this._extensionStateChanged));
|
||||
},
|
||||
@ -89,6 +91,9 @@ GnomeShell.prototype = {
|
||||
*
|
||||
*/
|
||||
Eval: function(code) {
|
||||
if (!global.settings.get_boolean('development-tools'))
|
||||
return [false, null];
|
||||
|
||||
let returnValue;
|
||||
let success;
|
||||
try {
|
||||
@ -149,11 +154,33 @@ GnomeShell.prototype = {
|
||||
},
|
||||
|
||||
ListExtensions: function() {
|
||||
return ExtensionSystem.extensionMeta;
|
||||
let out = {};
|
||||
for (let uuid in ExtensionSystem.extensionMeta) {
|
||||
let dbusObj = this.GetExtensionInfo(uuid);
|
||||
out[uuid] = dbusObj;
|
||||
}
|
||||
return out;
|
||||
},
|
||||
|
||||
GetExtensionInfo: function(uuid) {
|
||||
return ExtensionSystem.extensionMeta[uuid] || {};
|
||||
let meta = ExtensionSystem.extensionMeta[uuid] || {};
|
||||
let out = {};
|
||||
for (let key in meta) {
|
||||
let val = meta[key];
|
||||
let type;
|
||||
switch (typeof val) {
|
||||
case 'string':
|
||||
type = 's';
|
||||
break;
|
||||
case 'number':
|
||||
type = 'd';
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
out[key] = GLib.Variant.new(type, val);
|
||||
}
|
||||
return out;
|
||||
},
|
||||
|
||||
GetExtensionErrors: function(uuid) {
|
||||
@ -174,8 +201,12 @@ GnomeShell.prototype = {
|
||||
global.settings.set_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY, enabledExtensions);
|
||||
},
|
||||
|
||||
InstallRemoteExtension: function(uuid, url) {
|
||||
ExtensionSystem.installExtensionFromManifestURL(uuid, url);
|
||||
InstallRemoteExtension: function(uuid, version_tag) {
|
||||
ExtensionSystem.installExtensionFromUUID(uuid, version_tag);
|
||||
},
|
||||
|
||||
UninstallExtension: function(uuid) {
|
||||
return ExtensionSystem.uninstallExtensionFromUUID(uuid);
|
||||
},
|
||||
|
||||
get OverviewActive() {
|
||||
@ -189,17 +220,12 @@ GnomeShell.prototype = {
|
||||
Main.overview.hide();
|
||||
},
|
||||
|
||||
ApiVersion: 1,
|
||||
ApiVersion: ExtensionSystem.API_VERSION,
|
||||
|
||||
ShellVersion: Config.PACKAGE_VERSION,
|
||||
|
||||
_extensionStateChanged: function(_, newState) {
|
||||
DBus.session.emit_signal('/org/gnome/Shell',
|
||||
'org.gnome.Shell',
|
||||
'ExtensionStatusChanged', 'sis',
|
||||
[newState.uuid, newState.state, newState.error]);
|
||||
this._dbusImpl.emit_signal('ExtensionStatusChanged',
|
||||
GLib.Variant.new('(sis)', [newState.uuid, newState.state, newState.error]));
|
||||
}
|
||||
};
|
||||
|
||||
DBus.conformExport(GnomeShell.prototype, GnomeShellIface);
|
||||
|
||||
});
|
||||
|
168
js/ui/shellEntry.js
Normal file
168
js/ui/shellEntry.js
Normal file
@ -0,0 +1,168 @@
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
|
||||
const _EntryMenu = new Lang.Class({
|
||||
Name: 'ShellEntryMenu',
|
||||
Extends: PopupMenu.PopupMenu,
|
||||
|
||||
_init: function(entry, params) {
|
||||
params = Params.parse (params, { isPassword: false });
|
||||
|
||||
this.parent(entry, 0, St.Side.TOP);
|
||||
|
||||
this.actor.add_style_class_name('entry-context-menu');
|
||||
|
||||
this._entry = entry;
|
||||
this._clipboard = St.Clipboard.get_default();
|
||||
|
||||
// Populate menu
|
||||
let item;
|
||||
item = new PopupMenu.PopupMenuItem(_("Copy"));
|
||||
item.connect('activate', Lang.bind(this, this._onCopyActivated));
|
||||
this.addMenuItem(item);
|
||||
this._copyItem = item;
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Paste"));
|
||||
item.connect('activate', Lang.bind(this, this._onPasteActivated));
|
||||
this.addMenuItem(item);
|
||||
this._pasteItem = item;
|
||||
|
||||
this._passwordItem = null;
|
||||
if (params.isPassword) {
|
||||
item = new PopupMenu.PopupMenuItem('');
|
||||
item.connect('activate', Lang.bind(this,
|
||||
this._onPasswordActivated));
|
||||
this.addMenuItem(item);
|
||||
this._passwordItem = item;
|
||||
}
|
||||
|
||||
Main.uiGroup.add_actor(this.actor);
|
||||
this.actor.hide();
|
||||
},
|
||||
|
||||
open: function() {
|
||||
this._updatePasteItem();
|
||||
this._updateCopyItem();
|
||||
if (this._passwordItem)
|
||||
this._updatePasswordItem();
|
||||
|
||||
let direction = Gtk.DirectionType.TAB_FORWARD;
|
||||
if (!this.actor.navigate_focus(null, direction, false))
|
||||
this.actor.grab_key_focus();
|
||||
|
||||
this.parent();
|
||||
},
|
||||
|
||||
_updateCopyItem: function() {
|
||||
let selection = this._entry.clutter_text.get_selection();
|
||||
this._copyItem.setSensitive(selection && selection != '');
|
||||
},
|
||||
|
||||
_updatePasteItem: function() {
|
||||
this._clipboard.get_text(Lang.bind(this,
|
||||
function(clipboard, text) {
|
||||
this._pasteItem.setSensitive(text && text != '');
|
||||
}));
|
||||
},
|
||||
|
||||
_updatePasswordItem: function() {
|
||||
let textHidden = (this._entry.clutter_text.password_char);
|
||||
if (textHidden)
|
||||
this._passwordItem.label.set_text(_("Show Text"));
|
||||
else
|
||||
this._passwordItem.label.set_text(_("Hide Text"));
|
||||
},
|
||||
|
||||
_onCopyActivated: function() {
|
||||
let selection = this._entry.clutter_text.get_selection();
|
||||
this._clipboard.set_text(selection);
|
||||
},
|
||||
|
||||
_onPasteActivated: function() {
|
||||
this._clipboard.get_text(Lang.bind(this,
|
||||
function(clipboard, text) {
|
||||
if (!text)
|
||||
return;
|
||||
this._entry.clutter_text.delete_selection();
|
||||
let pos = this._entry.clutter_text.get_cursor_position();
|
||||
this._entry.clutter_text.insert_text(text, pos);
|
||||
}));
|
||||
},
|
||||
|
||||
_onPasswordActivated: function() {
|
||||
let visible = !!(this._entry.clutter_text.password_char);
|
||||
this._entry.clutter_text.set_password_char(visible ? '' : '\u25cf');
|
||||
}
|
||||
});
|
||||
|
||||
function _setMenuAlignment(entry, stageX) {
|
||||
let [success, entryX, entryY] = entry.transform_stage_point(stageX, 0);
|
||||
if (success)
|
||||
entry._menu.setSourceAlignment(entryX / entry.width);
|
||||
};
|
||||
|
||||
function _onClicked(action, actor) {
|
||||
let entry = actor._menu ? actor : actor.get_parent();
|
||||
|
||||
if (entry._menu.isOpen) {
|
||||
entry._menu.close();
|
||||
} else if (action.get_button() == 3) {
|
||||
let [stageX, stageY] = action.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);
|
||||
entry._menu.open();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
function _onPopup(actor) {
|
||||
let entry = actor._menu ? actor : actor.get_parent();
|
||||
let [success, textX, textY, lineHeight] = entry.clutter_text.position_to_coords(-1);
|
||||
if (success)
|
||||
entry._menu.setSourceAlignment(textX / entry.width);
|
||||
entry._menu.open();
|
||||
};
|
||||
|
||||
function addContextMenu(entry, params) {
|
||||
if (entry._menu)
|
||||
return;
|
||||
|
||||
entry._menu = new _EntryMenu(entry, params);
|
||||
entry._menuManager = new PopupMenu.PopupMenuManager({ actor: entry });
|
||||
entry._menuManager.addMenu(entry._menu);
|
||||
|
||||
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
|
||||
// event processing of ClutterText prevents event-bubbling.
|
||||
clickAction = new Clutter.ClickAction();
|
||||
clickAction.connect('clicked', _onClicked);
|
||||
clickAction.connect('long-press', _onLongPress);
|
||||
entry.clutter_text.add_action(clickAction);
|
||||
|
||||
clickAction = new Clutter.ClickAction();
|
||||
clickAction.connect('clicked', _onClicked);
|
||||
clickAction.connect('long-press', _onLongPress);
|
||||
entry.add_action(clickAction);
|
||||
|
||||
entry.connect('popup-menu', _onPopup);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
@ -50,11 +50,9 @@ function _setLabelsForMessage(dialog, message) {
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
|
||||
function ListItem(app) {
|
||||
this._init(app);
|
||||
}
|
||||
const ListItem = new Lang.Class({
|
||||
Name: 'ListItem',
|
||||
|
||||
ListItem.prototype = {
|
||||
_init: function(app) {
|
||||
this._app = app;
|
||||
|
||||
@ -86,14 +84,12 @@ ListItem.prototype = {
|
||||
this.emit('activate');
|
||||
this._app.activate();
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(ListItem.prototype);
|
||||
|
||||
function ShellMountOperation(source, params) {
|
||||
this._init(source, params);
|
||||
}
|
||||
const ShellMountOperation = new Lang.Class({
|
||||
Name: 'ShellMountOperation',
|
||||
|
||||
ShellMountOperation.prototype = {
|
||||
_init: function(source, params) {
|
||||
params = Params.parse(params, { reaskPassword: false });
|
||||
|
||||
@ -190,17 +186,14 @@ ShellMountOperation.prototype = {
|
||||
|
||||
this._processesDialog.update(message, processes, choices);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
function ShellMountQuestionDialog(icon) {
|
||||
this._init(icon);
|
||||
}
|
||||
|
||||
ShellMountQuestionDialog.prototype = {
|
||||
__proto__: ModalDialog.ModalDialog.prototype,
|
||||
const ShellMountQuestionDialog = new Lang.Class({
|
||||
Name: 'ShellMountQuestionDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
|
||||
_init: function(icon) {
|
||||
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'mount-question-dialog' });
|
||||
this.parent({ styleClass: 'mount-question-dialog' });
|
||||
|
||||
let mainContentLayout = new St.BoxLayout();
|
||||
this.contentLayout.add(mainContentLayout, { x_fill: true,
|
||||
@ -236,19 +229,16 @@ ShellMountQuestionDialog.prototype = {
|
||||
_setLabelsForMessage(this, message);
|
||||
_setButtonsForChoices(this, choices);
|
||||
}
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(ShellMountQuestionDialog.prototype);
|
||||
|
||||
function ShellMountPasswordSource(message, icon, reaskPassword) {
|
||||
this._init(message, icon, reaskPassword);
|
||||
}
|
||||
|
||||
ShellMountPasswordSource.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
const ShellMountPasswordSource = new Lang.Class({
|
||||
Name: 'ShellMountPasswordSource',
|
||||
Extends: MessageTray.Source,
|
||||
|
||||
_init: function(message, icon, reaskPassword) {
|
||||
let strings = message.split('\n');
|
||||
MessageTray.Source.prototype._init.call(this, strings[0]);
|
||||
this.parent(strings[0]);
|
||||
|
||||
this._notification = new ShellMountPasswordNotification(this, strings, icon, reaskPassword);
|
||||
|
||||
@ -256,21 +246,15 @@ ShellMountPasswordSource.prototype = {
|
||||
Main.messageTray.add(this);
|
||||
this.notify(this._notification);
|
||||
},
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(ShellMountPasswordSource.prototype);
|
||||
|
||||
function ShellMountPasswordNotification(source, strings, icon, reaskPassword) {
|
||||
this._init(source, strings, icon, reaskPassword);
|
||||
}
|
||||
|
||||
ShellMountPasswordNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
const ShellMountPasswordNotification = new Lang.Class({
|
||||
Name: 'ShellMountPasswordNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source, strings, icon, reaskPassword) {
|
||||
MessageTray.Notification.prototype._init.call(this, source,
|
||||
strings[0], null,
|
||||
{ customContent: true,
|
||||
icon: icon });
|
||||
this.parent(source, strings[0], null, { customContent: true, icon: icon });
|
||||
|
||||
// set the notification to transient and urgent, so that it
|
||||
// expands out
|
||||
@ -305,17 +289,14 @@ ShellMountPasswordNotification.prototype = {
|
||||
|
||||
this.source.emit('password-ready', text);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function ShellProcessesDialog(icon) {
|
||||
this._init(icon);
|
||||
}
|
||||
|
||||
ShellProcessesDialog.prototype = {
|
||||
__proto__: ModalDialog.ModalDialog.prototype,
|
||||
const ShellProcessesDialog = new Lang.Class({
|
||||
Name: 'ShellProcessesDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
|
||||
_init: function(icon) {
|
||||
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'show-processes-dialog' });
|
||||
this.parent({ styleClass: 'show-processes-dialog' });
|
||||
|
||||
let mainContentLayout = new St.BoxLayout();
|
||||
this.contentLayout.add(mainContentLayout, { x_fill: true,
|
||||
@ -401,5 +382,5 @@ ShellProcessesDialog.prototype = {
|
||||
_setLabelsForMessage(this, message);
|
||||
_setButtonsForChoices(this, choices);
|
||||
}
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(ShellProcessesDialog.prototype);
|
||||
|
@ -1,7 +1,6 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const DBus = imports.dbus;
|
||||
const GConf = imports.gi.GConf;
|
||||
const GDesktopEnums = imports.gi.GDesktopEnums;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
@ -30,8 +29,8 @@ const DPI_FACTOR_LARGE = 1.25;
|
||||
const DPI_FACTOR_LARGER = 1.5;
|
||||
const DPI_FACTOR_LARGEST = 2.0;
|
||||
|
||||
const KEY_META_DIR = '/apps/metacity/general';
|
||||
const KEY_VISUAL_BELL = KEY_META_DIR + '/visual_bell';
|
||||
const WM_SCHEMA = 'org.gnome.desktop.wm.preferences';
|
||||
const KEY_VISUAL_BELL = 'visual-bell';
|
||||
|
||||
const DESKTOP_INTERFACE_SCHEMA = 'org.gnome.desktop.interface';
|
||||
const KEY_GTK_THEME = 'gtk-theme';
|
||||
@ -40,19 +39,12 @@ const KEY_TEXT_SCALING_FACTOR = 'text-scaling-factor';
|
||||
|
||||
const HIGH_CONTRAST_THEME = 'HighContrast';
|
||||
|
||||
function ATIndicator() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
ATIndicator.prototype = {
|
||||
__proto__: PanelMenu.SystemStatusButton.prototype,
|
||||
const ATIndicator = new Lang.Class({
|
||||
Name: 'ATIndicator',
|
||||
Extends: PanelMenu.SystemStatusButton,
|
||||
|
||||
_init: function() {
|
||||
PanelMenu.SystemStatusButton.prototype._init.call(this, 'preferences-desktop-accessibility', null);
|
||||
|
||||
let client = GConf.Client.get_default();
|
||||
client.add_dir(KEY_META_DIR, GConf.ClientPreloadType.PRELOAD_ONELEVEL, null);
|
||||
client.notify_add(KEY_META_DIR, Lang.bind(this, this._keyChanged), null, null);
|
||||
this.parent('preferences-desktop-accessibility', null);
|
||||
|
||||
let highContrast = this._buildHCItem();
|
||||
this.menu.addMenuItem(highContrast);
|
||||
@ -68,11 +60,11 @@ ATIndicator.prototype = {
|
||||
// 'screen-reader-enabled');
|
||||
// this.menu.addMenuItem(screenReader);
|
||||
|
||||
// let screenKeyboard = this._buildItem(_("Screen Keyboard"), APPLICATIONS_SCHEMA,
|
||||
// 'screen-keyboard-enabled');
|
||||
// this.menu.addMenuItem(screenKeyboard);
|
||||
let screenKeyboard = this._buildItem(_("Screen Keyboard"), APPLICATIONS_SCHEMA,
|
||||
'screen-keyboard-enabled');
|
||||
this.menu.addMenuItem(screenKeyboard);
|
||||
|
||||
let visualBell = this._buildItemGConf(_("Visual Alerts"), client, KEY_VISUAL_BELL);
|
||||
let visualBell = this._buildItem(_("Visual Alerts"), WM_SCHEMA, KEY_VISUAL_BELL);
|
||||
this.menu.addMenuItem(visualBell);
|
||||
|
||||
let stickyKeys = this._buildItem(_("Sticky Keys"), A11Y_SCHEMA, KEY_STICKY_KEYS_ENABLED);
|
||||
@ -102,22 +94,6 @@ ATIndicator.prototype = {
|
||||
return widget;
|
||||
},
|
||||
|
||||
_buildItemGConf: function(string, client, key) {
|
||||
function on_get() {
|
||||
return client.get_bool(key);
|
||||
}
|
||||
let widget = this._buildItemExtended(string,
|
||||
client.get_bool(key),
|
||||
client.key_is_writable(key),
|
||||
function(enabled) {
|
||||
client.set_bool(key, enabled);
|
||||
});
|
||||
this.connect('gconf-changed', function() {
|
||||
widget.setToggleState(client.get_bool(key));
|
||||
});
|
||||
return widget;
|
||||
},
|
||||
|
||||
_buildItem: function(string, schema, key) {
|
||||
let settings = new Gio.Settings({ schema: schema });
|
||||
let widget = this._buildItemExtended(string,
|
||||
@ -191,10 +167,5 @@ ATIndicator.prototype = {
|
||||
widget.setToggleState(active);
|
||||
});
|
||||
return widget;
|
||||
},
|
||||
|
||||
_keyChanged: function() {
|
||||
this.emit('gconf-changed');
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(ATIndicator.prototype);
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
@ -23,15 +23,12 @@ const ConnectionState = {
|
||||
CONNECTING: 3
|
||||
}
|
||||
|
||||
function Indicator() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
Indicator.prototype = {
|
||||
__proto__: PanelMenu.SystemStatusButton.prototype,
|
||||
const Indicator = new Lang.Class({
|
||||
Name: 'BTIndicator',
|
||||
Extends: PanelMenu.SystemStatusButton,
|
||||
|
||||
_init: function() {
|
||||
PanelMenu.SystemStatusButton.prototype._init.call(this, 'bluetooth-disabled', null);
|
||||
this.parent('bluetooth-disabled', null);
|
||||
|
||||
GLib.spawn_command_line_sync ('pkill -f "^bluetooth-applet$"');
|
||||
this._applet = new GnomeBluetoothApplet.Applet();
|
||||
@ -204,9 +201,10 @@ Indicator.prototype = {
|
||||
|
||||
_buildDeviceSubMenu: function(item, device) {
|
||||
if (device.can_connect) {
|
||||
let menuitem = new PopupMenu.PopupSwitchMenuItem(_("Connection"), device.connected);
|
||||
item._connected = device.connected;
|
||||
item._connectedMenuitem = new PopupMenu.PopupSwitchMenuItem(_("Connection"), device.connected);
|
||||
item._connectedMenuitem.connect('toggled', Lang.bind(this, function() {
|
||||
item._connectedMenuItem = menuitem;
|
||||
menuitem.connect('toggled', Lang.bind(this, function() {
|
||||
if (item._connected > ConnectionState.CONNECTED) {
|
||||
// operation already in progress, revert
|
||||
// (should not happen anyway)
|
||||
@ -241,7 +239,7 @@ Indicator.prototype = {
|
||||
}
|
||||
}));
|
||||
|
||||
item.menu.addMenuItem(item._connectedMenuitem);
|
||||
item.menu.addMenuItem(menuitem);
|
||||
}
|
||||
|
||||
if (device.capabilities & GnomeBluetoothApplet.Capabilities.OBEX_PUSH) {
|
||||
@ -334,17 +332,14 @@ Indicator.prototype = {
|
||||
_cancelRequest: function() {
|
||||
this._source.destroy();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function Source() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
Source.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
const Source = new Lang.Class({
|
||||
Name: 'BluetoothSource',
|
||||
Extends: MessageTray.Source,
|
||||
|
||||
_init: function() {
|
||||
MessageTray.Source.prototype._init.call(this, _("Bluetooth"));
|
||||
this.parent(_("Bluetooth"));
|
||||
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
},
|
||||
@ -358,7 +353,7 @@ Source.prototype = {
|
||||
}
|
||||
}));
|
||||
|
||||
MessageTray.Source.prototype.notify.call(this, notification);
|
||||
this.parent(notification);
|
||||
},
|
||||
|
||||
createNotificationIcon: function() {
|
||||
@ -366,21 +361,17 @@ Source.prototype = {
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
icon_size: this.ICON_SIZE });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function AuthNotification() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
AuthNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
const AuthNotification = new Lang.Class({
|
||||
Name: 'AuthNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source, applet, device_path, name, long_name, uuid) {
|
||||
MessageTray.Notification.prototype._init.call(this,
|
||||
source,
|
||||
_("Bluetooth"),
|
||||
_("Authorization request from %s").format(name),
|
||||
{ customContent: true });
|
||||
this.parent(source,
|
||||
_("Bluetooth"),
|
||||
_("Authorization request from %s").format(name),
|
||||
{ customContent: true });
|
||||
this.setResident(true);
|
||||
|
||||
this._applet = applet;
|
||||
@ -406,21 +397,17 @@ AuthNotification.prototype = {
|
||||
this.destroy();
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function ConfirmNotification() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
ConfirmNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
const ConfirmNotification = new Lang.Class({
|
||||
Name: 'ConfirmNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source, applet, device_path, name, long_name, pin) {
|
||||
MessageTray.Notification.prototype._init.call(this,
|
||||
source,
|
||||
_("Bluetooth"),
|
||||
_("Pairing confirmation for %s").format(name),
|
||||
{ customContent: true });
|
||||
this.parent(source,
|
||||
_("Bluetooth"),
|
||||
_("Pairing confirmation for %s").format(name),
|
||||
{ customContent: true });
|
||||
this.setResident(true);
|
||||
|
||||
this._applet = applet;
|
||||
@ -439,21 +426,17 @@ ConfirmNotification.prototype = {
|
||||
this.destroy();
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function PinNotification() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
PinNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
const PinNotification = new Lang.Class({
|
||||
Name: 'PinNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source, applet, device_path, name, long_name, numeric) {
|
||||
MessageTray.Notification.prototype._init.call(this,
|
||||
source,
|
||||
_("Bluetooth"),
|
||||
_("Pairing request for %s").format(name),
|
||||
{ customContent: true });
|
||||
this.parent(source,
|
||||
_("Bluetooth"),
|
||||
_("Pairing request for %s").format(name),
|
||||
{ customContent: true });
|
||||
this.setResident(true);
|
||||
|
||||
this._applet = applet;
|
||||
@ -502,7 +485,7 @@ PinNotification.prototype = {
|
||||
},
|
||||
|
||||
grabFocus: function(lockTray) {
|
||||
MessageTray.Notification.prototype.grabFocus.call(this, lockTray);
|
||||
this.parent(lockTray);
|
||||
global.stage.set_key_focus(this._entry);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 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;
|
||||
@ -14,15 +14,12 @@ const PopupMenu = imports.ui.popupMenu;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
function LayoutMenuItem() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
LayoutMenuItem.prototype = {
|
||||
__proto__: PopupMenu.PopupBaseMenuItem.prototype,
|
||||
const LayoutMenuItem = new Lang.Class({
|
||||
Name: 'LayoutMenuItem',
|
||||
Extends: PopupMenu.PopupBaseMenuItem,
|
||||
|
||||
_init: function(config, id, indicator, long_name) {
|
||||
PopupMenu.PopupBaseMenuItem.prototype._init.call(this);
|
||||
this.parent();
|
||||
|
||||
this._config = config;
|
||||
this._id = id;
|
||||
@ -33,26 +30,25 @@ LayoutMenuItem.prototype = {
|
||||
},
|
||||
|
||||
activate: function(event) {
|
||||
PopupMenu.PopupBaseMenuItem.prototype.activate.call(this);
|
||||
this.parent(event);
|
||||
|
||||
this._config.lock_group(this._id);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function XKBIndicator() {
|
||||
this._init.call(this);
|
||||
}
|
||||
|
||||
XKBIndicator.prototype = {
|
||||
__proto__: PanelMenu.Button.prototype,
|
||||
const XKBIndicator = new Lang.Class({
|
||||
Name: 'XKBIndicator',
|
||||
Extends: PanelMenu.Button,
|
||||
|
||||
_init: function() {
|
||||
PanelMenu.Button.prototype._init.call(this, St.Align.START);
|
||||
this.parent(0.0);
|
||||
|
||||
this._container = new Shell.GenericContainer();
|
||||
this._container.connect('get-preferred-width', Lang.bind(this, this._get_preferred_width));
|
||||
this._container.connect('get-preferred-height', Lang.bind(this, this._get_preferred_height));
|
||||
this._container.connect('allocate', Lang.bind(this, this._allocate));
|
||||
this.actor.set_child(this._container);
|
||||
this._container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth));
|
||||
this._container.connect('get-preferred-height', Lang.bind(this, this._containerGetPreferredHeight));
|
||||
this._container.connect('allocate', Lang.bind(this, this._containerAllocate));
|
||||
this.actor.add_actor(this._container);
|
||||
this.actor.add_style_class_name('panel-status-button');
|
||||
|
||||
this._iconActor = new St.Icon({ icon_name: 'keyboard', icon_type: St.IconType.SYMBOLIC, style_class: 'system-status-icon' });
|
||||
this._container.add_actor(this._iconActor);
|
||||
@ -61,21 +57,23 @@ XKBIndicator.prototype = {
|
||||
|
||||
this._showFlags = false;
|
||||
this._config = Gkbd.Configuration.get();
|
||||
this._config.connect('changed', Lang.bind(this, this._sync_config));
|
||||
this._config.connect('group-changed', Lang.bind(this, this._sync_group));
|
||||
this._config.connect('changed', Lang.bind(this, this._syncConfig));
|
||||
this._config.connect('group-changed', Lang.bind(this, this._syncGroup));
|
||||
this._config.start_listen();
|
||||
|
||||
this._sync_config();
|
||||
this._syncConfig();
|
||||
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, function() {
|
||||
Main.overview.hide();
|
||||
Util.spawn(['gkbd-keyboard-display', '-g', String(this._config.get_current_group() + 1)]);
|
||||
}));
|
||||
if (global.session_type == Shell.SessionType.USER) {
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, function() {
|
||||
Main.overview.hide();
|
||||
Util.spawn(['gkbd-keyboard-display', '-g', String(this._config.get_current_group() + 1)]);
|
||||
}));
|
||||
}
|
||||
this.menu.addSettingsAction(_("Region and Language Settings"), 'gnome-region-panel.desktop');
|
||||
},
|
||||
|
||||
_adjust_group_names: function(names) {
|
||||
_adjustGroupNames: function(names) {
|
||||
// Disambiguate duplicate names with a subscript
|
||||
// This is O(N^2) to avoid sorting names
|
||||
// but N <= 4 so who cares?
|
||||
@ -97,7 +95,7 @@ XKBIndicator.prototype = {
|
||||
return names;
|
||||
},
|
||||
|
||||
_sync_config: function() {
|
||||
_syncConfig: function() {
|
||||
this._showFlags = this._config.if_flags_shown();
|
||||
if (this._showFlags) {
|
||||
this._container.set_skip_paint(this._iconActor, false);
|
||||
@ -119,7 +117,7 @@ XKBIndicator.prototype = {
|
||||
for (let i = 0; i < this._labelActors.length; i++)
|
||||
this._labelActors[i].destroy();
|
||||
|
||||
let short_names = this._adjust_group_names(this._config.get_short_group_names());
|
||||
let short_names = this._adjustGroupNames(this._config.get_short_group_names());
|
||||
|
||||
this._selectedLayout = null;
|
||||
this._layoutItems = [ ];
|
||||
@ -144,10 +142,10 @@ XKBIndicator.prototype = {
|
||||
this._container.set_skip_paint(shortLabel, true);
|
||||
}
|
||||
|
||||
this._sync_group();
|
||||
this._syncGroup();
|
||||
},
|
||||
|
||||
_sync_group: function() {
|
||||
_syncGroup: function() {
|
||||
let selected = this._config.get_current_group();
|
||||
|
||||
if (this._selectedLayout) {
|
||||
@ -170,10 +168,10 @@ XKBIndicator.prototype = {
|
||||
this._selectedLayout = item;
|
||||
},
|
||||
|
||||
_get_preferred_width: function(container, for_height, alloc) {
|
||||
/* Here, and in _get_preferred_height, we need to query for the
|
||||
height of all children, but we ignore the results for those
|
||||
we don't actually display. */
|
||||
_containerGetPreferredWidth: function(container, for_height, alloc) {
|
||||
// Here, and in _containerGetPreferredHeight, we need to query
|
||||
// for the height of all children, but we ignore the results
|
||||
// for those we don't actually display.
|
||||
let max_min_width = 0, max_natural_width = 0;
|
||||
if (this._showFlags)
|
||||
[max_min_width, max_natural_width] = this._iconActor.get_preferred_width(for_height);
|
||||
@ -190,7 +188,7 @@ XKBIndicator.prototype = {
|
||||
alloc.natural_size = max_natural_width;
|
||||
},
|
||||
|
||||
_get_preferred_height: function(container, for_width, alloc) {
|
||||
_containerGetPreferredHeight: function(container, for_width, alloc) {
|
||||
let max_min_height = 0, max_natural_height = 0;
|
||||
if (this._showFlags)
|
||||
[max_min_height, max_natural_height] = this._iconActor.get_preferred_height(for_width);
|
||||
@ -207,7 +205,7 @@ XKBIndicator.prototype = {
|
||||
alloc.natural_size = max_natural_height;
|
||||
},
|
||||
|
||||
_allocate: function(container, box, flags) {
|
||||
_containerAllocate: function(container, box, flags) {
|
||||
// translate box to (0, 0)
|
||||
box.x2 -= box.x1;
|
||||
box.x1 = 0;
|
||||
@ -218,4 +216,4 @@ XKBIndicator.prototype = {
|
||||
for (let i = 0; i < this._labelActors.length; i++)
|
||||
this._labelActors[i].allocate_align_fill(box, 0.5, 0, false, false, flags);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,6 +1,5 @@
|
||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
const ByteArray = imports.byteArray;
|
||||
const DBus = imports.dbus;
|
||||
const GLib = imports.gi.GLib;
|
||||
const GObject = imports.gi.GObject;
|
||||
const Lang = imports.lang;
|
||||
@ -98,15 +97,12 @@ function ssidToLabel(ssid) {
|
||||
return label;
|
||||
}
|
||||
|
||||
function NMNetworkMenuItem() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
NMNetworkMenuItem.prototype = {
|
||||
__proto__: PopupMenu.PopupBaseMenuItem.prototype,
|
||||
const NMNetworkMenuItem = new Lang.Class({
|
||||
Name: 'NMNetworkMenuItem',
|
||||
Extends: PopupMenu.PopupBaseMenuItem,
|
||||
|
||||
_init: function(accessPoints, title, params) {
|
||||
PopupMenu.PopupBaseMenuItem.prototype._init.call(this, params);
|
||||
this.parent(params);
|
||||
|
||||
accessPoints = sortAccessPoints(accessPoints);
|
||||
this.bestAP = accessPoints[0];
|
||||
@ -185,21 +181,18 @@ NMNetworkMenuItem.prototype = {
|
||||
apObj.updateId = 0;
|
||||
}
|
||||
|
||||
PopupMenu.PopupBaseMenuItem.prototype.destroy.call(this);
|
||||
this.parent();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function NMWiredSectionTitleMenuItem() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
NMWiredSectionTitleMenuItem.prototype = {
|
||||
__proto__: PopupMenu.PopupSwitchMenuItem.prototype,
|
||||
const NMWiredSectionTitleMenuItem = new Lang.Class({
|
||||
Name: 'NMWiredSectionTitleMenuItem',
|
||||
Extends: PopupMenu.PopupSwitchMenuItem,
|
||||
|
||||
_init: function(label, params) {
|
||||
params = params || { };
|
||||
params.style_class = 'popup-subtitle-menu-item';
|
||||
PopupMenu.PopupSwitchMenuItem.prototype._init.call(this, label, false, params);
|
||||
this.parent(label, false, params);
|
||||
},
|
||||
|
||||
updateForDevice: function(device) {
|
||||
@ -212,7 +205,7 @@ NMWiredSectionTitleMenuItem.prototype = {
|
||||
},
|
||||
|
||||
activate: function(event) {
|
||||
PopupMenu.PopupSwitchMenuItem.prototype.activate.call(this, event);
|
||||
this.parent(event);
|
||||
|
||||
if (!this._device) {
|
||||
log('Section title activated when there is more than one device, should be non reactive');
|
||||
@ -231,19 +224,16 @@ NMWiredSectionTitleMenuItem.prototype = {
|
||||
else
|
||||
this._device.deactivate();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function NMWirelessSectionTitleMenuItem() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
NMWirelessSectionTitleMenuItem.prototype = {
|
||||
__proto__: PopupMenu.PopupSwitchMenuItem.prototype,
|
||||
const NMWirelessSectionTitleMenuItem = new Lang.Class({
|
||||
Name: 'NMWirelessSectionTitleMenuItem',
|
||||
Extends: PopupMenu.PopupSwitchMenuItem,
|
||||
|
||||
_init: function(client, property, title, params) {
|
||||
params = params || { };
|
||||
params.style_class = 'popup-subtitle-menu-item';
|
||||
PopupMenu.PopupSwitchMenuItem.prototype._init.call(this, title, false, params);
|
||||
this.parent(title, false, params);
|
||||
|
||||
this._client = client;
|
||||
this._property = property + '_enabled';
|
||||
@ -269,7 +259,7 @@ NMWirelessSectionTitleMenuItem.prototype = {
|
||||
},
|
||||
|
||||
activate: function(event) {
|
||||
PopupMenu.PopupSwitchMenuItem.prototype.activate.call(this, event);
|
||||
this.parent(event);
|
||||
|
||||
this._client[this._setEnabledFunc](this._switch.state);
|
||||
},
|
||||
@ -286,13 +276,12 @@ NMWirelessSectionTitleMenuItem.prototype = {
|
||||
|
||||
this.emit('enabled-changed', enabled);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function NMDevice() {
|
||||
throw new TypeError('Instantanting abstract class NMDevice');
|
||||
}
|
||||
const NMDevice = new Lang.Class({
|
||||
Name: 'NMDevice',
|
||||
Abstract: true,
|
||||
|
||||
NMDevice.prototype = {
|
||||
_init: function(client, device, connections) {
|
||||
this.device = device;
|
||||
if (device) {
|
||||
@ -674,26 +663,23 @@ NMDevice.prototype = {
|
||||
|
||||
return out;
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(NMDevice.prototype);
|
||||
|
||||
|
||||
function NMDeviceWired() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
NMDeviceWired.prototype = {
|
||||
__proto__: NMDevice.prototype,
|
||||
const NMDeviceWired = new Lang.Class({
|
||||
Name: 'NMDeviceWired',
|
||||
Extends: NMDevice,
|
||||
|
||||
_init: function(client, device, connections) {
|
||||
this._autoConnectionName = _("Auto Ethernet");
|
||||
this.category = NMConnectionCategory.WIRED;
|
||||
|
||||
NMDevice.prototype._init.call(this, client, device, connections);
|
||||
this.parent(client, device, connections);
|
||||
},
|
||||
|
||||
_createSection: function() {
|
||||
NMDevice.prototype._createSection.call(this);
|
||||
this.parent();
|
||||
|
||||
// if we have only one connection (normal or automatic)
|
||||
// we hide the connection list, and use the switch to control
|
||||
@ -718,14 +704,11 @@ NMDeviceWired.prototype = {
|
||||
}));
|
||||
return connection;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function NMDeviceModem() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
NMDeviceModem.prototype = {
|
||||
__proto__: NMDevice.prototype,
|
||||
const NMDeviceModem = new Lang.Class({
|
||||
Name: 'NMDeviceModem',
|
||||
Extends: NMDevice,
|
||||
|
||||
_init: function(client, device, connections) {
|
||||
let is_wwan = false;
|
||||
@ -774,7 +757,7 @@ NMDeviceModem.prototype = {
|
||||
}));
|
||||
}
|
||||
|
||||
NMDevice.prototype._init.call(this, client, device, connections);
|
||||
this.parent(client, device, connections);
|
||||
},
|
||||
|
||||
setEnabled: function(enabled) {
|
||||
@ -787,7 +770,7 @@ NMDeviceModem.prototype = {
|
||||
this.statusItem.setStatus(this.getStatusLabel());
|
||||
}
|
||||
|
||||
NMDevice.prototype.setEnabled.call(this, enabled);
|
||||
this.parent(enabled);
|
||||
},
|
||||
|
||||
get connected() {
|
||||
@ -804,7 +787,7 @@ NMDeviceModem.prototype = {
|
||||
this._signalQualityId = 0;
|
||||
}
|
||||
|
||||
NMDevice.prototype.destroy.call(this);
|
||||
this.parent();
|
||||
},
|
||||
|
||||
_getSignalIcon: function() {
|
||||
@ -825,13 +808,13 @@ NMDeviceModem.prototype = {
|
||||
this.section.addMenuItem(this._operatorItem);
|
||||
}
|
||||
|
||||
NMDevice.prototype._createSection.call(this);
|
||||
this.parent();
|
||||
},
|
||||
|
||||
_clearSection: function() {
|
||||
this._operatorItem = null;
|
||||
|
||||
NMDevice.prototype._clearSection.call(this);
|
||||
this.parent();
|
||||
},
|
||||
|
||||
_createAutomaticConnection: function() {
|
||||
@ -841,14 +824,11 @@ NMDeviceModem.prototype = {
|
||||
'connect-3g', this.device.get_path()]);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function NMDeviceBluetooth() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
NMDeviceBluetooth.prototype = {
|
||||
__proto__: NMDevice.prototype,
|
||||
const NMDeviceBluetooth = new Lang.Class({
|
||||
Name: 'NMDeviceBluetooth',
|
||||
Extends: NMDevice,
|
||||
|
||||
_init: function(client, device, connections) {
|
||||
this._autoConnectionName = this._makeConnectionName(device);
|
||||
@ -856,7 +836,7 @@ NMDeviceBluetooth.prototype = {
|
||||
|
||||
this.category = NMConnectionCategory.WWAN;
|
||||
|
||||
NMDevice.prototype._init.call(this, client, device, connections);
|
||||
this.parent(client, device, connections);
|
||||
},
|
||||
|
||||
_createAutomaticConnection: function() {
|
||||
@ -886,23 +866,20 @@ NMDeviceBluetooth.prototype = {
|
||||
this._clearSection();
|
||||
this._createSection();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
// Not a real device, but I save a lot code this way
|
||||
function NMDeviceVPN() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
NMDeviceVPN.prototype = {
|
||||
__proto__: NMDevice.prototype,
|
||||
const NMDeviceVPN = new Lang.Class({
|
||||
Name: 'NMDeviceVPN',
|
||||
Extends: NMDevice,
|
||||
|
||||
_init: function(client) {
|
||||
// Disable autoconnections
|
||||
this._autoConnectionName = null;
|
||||
this.category = NMConnectionCategory.VPN;
|
||||
|
||||
NMDevice.prototype._init.call(this, client, null, [ ]);
|
||||
this.parent(client, null, [ ]);
|
||||
},
|
||||
|
||||
connectionValid: function(connection) {
|
||||
@ -918,7 +895,7 @@ NMDeviceVPN.prototype = {
|
||||
},
|
||||
|
||||
setActiveConnection: function(activeConnection) {
|
||||
NMDevice.prototype.setActiveConnection.call(this, activeConnection);
|
||||
this.parent(activeConnection);
|
||||
|
||||
this.emit('active-connection-changed');
|
||||
},
|
||||
@ -935,14 +912,11 @@ NMDeviceVPN.prototype = {
|
||||
getStatusLabel: function() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function NMDeviceWireless() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
NMDeviceWireless.prototype = {
|
||||
__proto__: NMDevice.prototype,
|
||||
const NMDeviceWireless = new Lang.Class({
|
||||
Name: 'NMDeviceWireless',
|
||||
Extends: NMDevice,
|
||||
|
||||
_init: function(client, device, connections) {
|
||||
this.category = NMConnectionCategory.WIRELESS;
|
||||
@ -1014,7 +988,7 @@ NMDeviceWireless.prototype = {
|
||||
this._apAddedId = device.connect('access-point-added', Lang.bind(this, this._accessPointAdded));
|
||||
this._apRemovedId = device.connect('access-point-removed', Lang.bind(this, this._accessPointRemoved));
|
||||
|
||||
NMDevice.prototype._init.call(this, client, device, validConnections);
|
||||
this.parent(client, device, validConnections);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
@ -1034,7 +1008,7 @@ NMDeviceWireless.prototype = {
|
||||
this._apRemovedId = 0;
|
||||
}
|
||||
|
||||
NMDevice.prototype.destroy.call(this);
|
||||
this.parent();
|
||||
},
|
||||
|
||||
setEnabled: function(enabled) {
|
||||
@ -1104,10 +1078,10 @@ NMDeviceWireless.prototype = {
|
||||
let activeAp = this.device.active_access_point;
|
||||
|
||||
if (activeAp) {
|
||||
let pos = this._findNetwork(activeAp);
|
||||
let res = this._findExistingNetwork(activeAp);
|
||||
|
||||
if (pos != -1)
|
||||
this._activeNetwork = this._networks[pos];
|
||||
if (res != null)
|
||||
this._activeNetwork = this._networks[res.network];
|
||||
}
|
||||
|
||||
// we don't refresh the view here, setActiveConnection will
|
||||
@ -1181,6 +1155,18 @@ NMDeviceWireless.prototype = {
|
||||
return true;
|
||||
},
|
||||
|
||||
_findExistingNetwork: function(accessPoint) {
|
||||
for (let i = 0; i < this._networks.length; i++) {
|
||||
let apObj = this._networks[i];
|
||||
for (let j = 0; j < apObj.accessPoints.length; j++) {
|
||||
if (apObj.accessPoints[j] == accessPoint)
|
||||
return { network: i, ap: j };
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
_findNetwork: function(accessPoint) {
|
||||
if (accessPoint.get_ssid() == null)
|
||||
return -1;
|
||||
@ -1273,24 +1259,20 @@ NMDeviceWireless.prototype = {
|
||||
},
|
||||
|
||||
_accessPointRemoved: function(device, accessPoint) {
|
||||
let pos = this._findNetwork(accessPoint);
|
||||
let res = this._findExistingNetwork(accessPoint);
|
||||
|
||||
if (pos == -1) {
|
||||
if (res == null) {
|
||||
log('Removing an access point that was never added');
|
||||
return;
|
||||
}
|
||||
|
||||
let apObj = this._networks[pos];
|
||||
let i = apObj.accessPoints.indexOf(accessPoint);
|
||||
|
||||
if (i == -1) {
|
||||
log('Removing an access point that was never added');
|
||||
return;
|
||||
}
|
||||
|
||||
apObj.accessPoints.splice(i, 1);
|
||||
let apObj = this._networks[res.network];
|
||||
apObj.accessPoints.splice(res.ap, 1);
|
||||
|
||||
if (apObj.accessPoints.length == 0) {
|
||||
if (this._activeNetwork == apObj)
|
||||
this._activeNetwork = null;
|
||||
|
||||
if (apObj.item)
|
||||
apObj.item.destroy();
|
||||
|
||||
@ -1299,22 +1281,26 @@ NMDeviceWireless.prototype = {
|
||||
// we removed an item in the main menu, and we have a more submenu
|
||||
// we need to extract the first item in more and move it to the submenu
|
||||
|
||||
let apObj = this._overflowItem.menu.firstMenuItem;
|
||||
if (apObj.item) {
|
||||
apObj.item.destroy();
|
||||
let item = this._overflowItem.menu.firstMenuItem;
|
||||
if (item && item._apObj) {
|
||||
item.destroy();
|
||||
// clear the cycle, and allow the construction of the new item
|
||||
item._apObj.item = null;
|
||||
|
||||
this._createNetworkItem(apObj, NUM_VISIBLE_NETWORKS-1);
|
||||
this._createNetworkItem(item._apObj, NUM_VISIBLE_NETWORKS-1);
|
||||
} else {
|
||||
log('The more... menu was existing and empty! This should not happen');
|
||||
}
|
||||
}
|
||||
|
||||
// This can happen if the removed connection is from the overflow
|
||||
// menu, or if we just moved the last connection out from the menu
|
||||
if (this._overflowItem.menu.length == 0) {
|
||||
if (this._overflowItem.menu.numMenuItems == 0) {
|
||||
this._overflowItem.destroy();
|
||||
this._overflowItem = null;
|
||||
}
|
||||
}
|
||||
this._networks.splice(pos, 1);
|
||||
this._networks.splice(res.network, 1);
|
||||
|
||||
} else if (apObj.item)
|
||||
apObj.item.updateAccessPoints(apObj.accessPoints);
|
||||
@ -1336,7 +1322,7 @@ NMDeviceWireless.prototype = {
|
||||
},
|
||||
|
||||
_clearSection: function() {
|
||||
NMDevice.prototype._clearSection.call(this);
|
||||
this.parent();
|
||||
|
||||
for (let i = 0; i < this._networks.length; i++)
|
||||
this._networks[i].item = null;
|
||||
@ -1480,19 +1466,22 @@ NMDeviceWireless.prototype = {
|
||||
},
|
||||
|
||||
_createNetworkItem: function(apObj, position) {
|
||||
if(!apObj.accessPoints || apObj.accessPoints.length == 0) {
|
||||
// this should not happen, but I have no idea why it happens
|
||||
return;
|
||||
}
|
||||
|
||||
if(apObj.connections.length > 0) {
|
||||
if (apObj.connections.length == 1)
|
||||
if (apObj.connections.length == 1) {
|
||||
apObj.item = this._createAPItem(apObj.connections[0], apObj, false);
|
||||
else {
|
||||
} else {
|
||||
let title = apObj.ssidText;
|
||||
apObj.item = new PopupMenu.PopupSubMenuMenuItem(title);
|
||||
apObj.item._apObj = apObj;
|
||||
for (let i = 0; i < apObj.connections.length; i++)
|
||||
apObj.item.menu.addMenuItem(this._createAPItem(apObj.connections[i], apObj, true));
|
||||
}
|
||||
} else {
|
||||
apObj.item = new NMNetworkMenuItem(apObj.accessPoints);
|
||||
apObj.item._apObj = apObj;
|
||||
apObj.item.connect('activate', Lang.bind(this, function() {
|
||||
let accessPoints = sortAccessPoints(apObj.accessPoints);
|
||||
if ( (accessPoints[0]._secType == NMAccessPointSecurity.WPA2_ENT)
|
||||
@ -1507,6 +1496,8 @@ NMDeviceWireless.prototype = {
|
||||
}
|
||||
}));
|
||||
}
|
||||
apObj.item._apObj = apObj;
|
||||
|
||||
if (position < NUM_VISIBLE_NETWORKS) {
|
||||
apObj.isMore = false;
|
||||
this.section.addMenuItem(apObj.item, position);
|
||||
@ -1539,16 +1530,14 @@ NMDeviceWireless.prototype = {
|
||||
this._createNetworkItem(apObj, j + activeOffset);
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
function NMApplet() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
NMApplet.prototype = {
|
||||
__proto__: PanelMenu.SystemStatusButton.prototype,
|
||||
const NMApplet = new Lang.Class({
|
||||
Name: 'NMApplet',
|
||||
Extends: PanelMenu.SystemStatusButton,
|
||||
|
||||
_init: function() {
|
||||
PanelMenu.SystemStatusButton.prototype._init.call(this, 'network-error');
|
||||
this.parent('network-error', null);
|
||||
|
||||
this._client = NMClient.Client.new();
|
||||
|
||||
@ -1742,13 +1731,6 @@ NMApplet.prototype = {
|
||||
if (wrapperClass) {
|
||||
let wrapper = new wrapperClass(this._client, device, this._connections);
|
||||
|
||||
wrapper._networkLostId = wrapper.connect('network-lost', Lang.bind(this, function(device) {
|
||||
this._notifyForDevice(device, 'network-offline',
|
||||
_("Connectivity lost"),
|
||||
_("You're no longer connected to the network"),
|
||||
// set critical urgency to popup the notification automatically
|
||||
MessageTray.Urgency.CRITICAL);
|
||||
}));
|
||||
wrapper._activationFailedId = wrapper.connect('activation-failed', Lang.bind(this, function(device, reason) {
|
||||
// XXX: nm-applet has no special text depending on reason
|
||||
// but I'm not sure of this generic message
|
||||
@ -1761,7 +1743,6 @@ NMApplet.prototype = {
|
||||
this._syncSectionTitle(dev.category);
|
||||
}));
|
||||
wrapper._destroyId = wrapper.connect('destroy', function(wrapper) {
|
||||
wrapper.disconnect(wrapper._networkLostId);
|
||||
wrapper.disconnect(wrapper._activationFailedId);
|
||||
wrapper.disconnect(wrapper._deviceStateChangedId);
|
||||
wrapper.disconnect(wrapper._destroyId);
|
||||
@ -1828,7 +1809,7 @@ NMApplet.prototype = {
|
||||
if (!a._inited) {
|
||||
a._notifyDefaultId = a.connect('notify::default', Lang.bind(this, this._updateIcon));
|
||||
a._notifyDefault6Id = a.connect('notify::default6', Lang.bind(this, this._updateIcon));
|
||||
a._notifyStateId = a.connect('notify::state', Lang.bind(this, this._updateIcon));
|
||||
a._notifyStateId = a.connect('notify::state', Lang.bind(this, this._notifyActivated));
|
||||
|
||||
a._inited = true;
|
||||
}
|
||||
@ -1872,12 +1853,28 @@ NMApplet.prototype = {
|
||||
|
||||
if (a._primaryDevice)
|
||||
a._primaryDevice.setActiveConnection(a);
|
||||
|
||||
if (a.state == NetworkManager.ActiveConnectionState.ACTIVATED
|
||||
&& a._primaryDevice && a._primaryDevice._notification) {
|
||||
a._primaryDevice._notification.destroy();
|
||||
a._primaryDevice._notification = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._mainConnection = activating || default_ip4 || default_ip6 || this._activeConnections[0] || null;
|
||||
},
|
||||
|
||||
_notifyActivated: function(activeConnection) {
|
||||
if (activeConnection.state == NetworkManager.ActiveConnectionState.ACTIVATED
|
||||
&& activeConnection._primaryDevice && activeConnection._primaryDevice._notification) {
|
||||
activeConnection._primaryDevice._notification.destroy();
|
||||
activeConnection._primaryDevice._notification = null;
|
||||
}
|
||||
|
||||
this._updateIcon();
|
||||
},
|
||||
|
||||
_readConnections: function() {
|
||||
let connections = this._settings.list_connections();
|
||||
for (let i = 0; i < connections.length; i++) {
|
||||
@ -2040,10 +2037,11 @@ NMApplet.prototype = {
|
||||
}
|
||||
this.setIcon('network-wireless-connected');
|
||||
} else {
|
||||
if (this._accessPointUpdateId && this._activeAccessPoint != ap) {
|
||||
this._activeAccessPoint.disconnect(this._accessPointUpdateId);
|
||||
if (this._activeAccessPoint != ap) {
|
||||
if (this._accessPointUpdateId)
|
||||
this._activeAccessPoint.disconnect(this._accessPointUpdateId);
|
||||
this._activeAccessPoint = ap;
|
||||
this._activeAccessPointUpdateId = ap.connect('notify::strength', Lang.bind(function() {
|
||||
this._activeAccessPointUpdateId = ap.connect('notify::strength', Lang.bind(this, function() {
|
||||
this.setIcon('network-wireless-signal-' + signalToIcon(ap.strength));
|
||||
}));
|
||||
}
|
||||
@ -2070,8 +2068,9 @@ NMApplet.prototype = {
|
||||
break;
|
||||
}
|
||||
|
||||
if (this._mobileUpdateId && this._mobileUpdateDevice != dev) {
|
||||
this._mobileUpdateDevice.disconnect(this._mobileUpdateId);
|
||||
if (dev.mobileDevice != this._mobileUpdateDevice) {
|
||||
if (this._mobileUpdateId)
|
||||
this._mobileUpdateDevice.disconnect(this._mobileUpdateId);
|
||||
this._mobileUpdateDevice = dev.mobileDevice;
|
||||
this._mobileUpdateId = dev.mobileDevice.connect('notify::signal-quality', Lang.bind(this, function() {
|
||||
this.setIcon('network-cellular-signal-' + signalToIcon(dev.mobileDevice.signal_quality));
|
||||
@ -2104,17 +2103,14 @@ NMApplet.prototype = {
|
||||
this._mobileUpdateId = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function NMMessageTraySource() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
NMMessageTraySource.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
const NMMessageTraySource = new Lang.Class({
|
||||
Name: 'NMMessageTraySource',
|
||||
Extends: MessageTray.Source,
|
||||
|
||||
_init: function() {
|
||||
MessageTray.Source.prototype._init.call(this, _("Network Manager"));
|
||||
this.parent(_("Network Manager"));
|
||||
|
||||
let icon = new St.Icon({ icon_name: 'network-transmit-receive',
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
@ -2122,4 +2118,4 @@ NMMessageTraySource.prototype = {
|
||||
});
|
||||
this._setSummaryIcon(icon);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,7 +1,6 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const DBus = imports.dbus;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Shell = imports.gi.Shell;
|
||||
@ -40,31 +39,27 @@ const UPDeviceState = {
|
||||
PENDING_DISCHARGE: 6
|
||||
};
|
||||
|
||||
const PowerManagerInterface = {
|
||||
name: 'org.gnome.SettingsDaemon.Power',
|
||||
methods: [
|
||||
{ name: 'GetDevices', inSignature: '', outSignature: 'a(susbut)' },
|
||||
{ name: 'GetPrimaryDevice', inSignature: '', outSignature: '(susbut)' },
|
||||
],
|
||||
signals: [
|
||||
{ name: 'Changed', inSignature: '' },
|
||||
],
|
||||
properties: [
|
||||
{ name: 'Icon', signature: 's', access: 'read' },
|
||||
]
|
||||
};
|
||||
let PowerManagerProxy = DBus.makeProxyClass(PowerManagerInterface);
|
||||
const PowerManagerInterface = <interface name="org.gnome.SettingsDaemon.Power">
|
||||
<method name="GetDevices">
|
||||
<arg type="a(susdut)" direction="out" />
|
||||
</method>
|
||||
<method name="GetPrimaryDevice">
|
||||
<arg type="(susdut)" direction="out" />
|
||||
</method>
|
||||
<signal name="Changed" />
|
||||
<property name="Icon" type="s" access="read" />
|
||||
</interface>;
|
||||
|
||||
function Indicator() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(PowerManagerInterface);
|
||||
|
||||
Indicator.prototype = {
|
||||
__proto__: PanelMenu.SystemStatusButton.prototype,
|
||||
const Indicator = new Lang.Class({
|
||||
Name: 'PowerIndicator',
|
||||
Extends: PanelMenu.SystemStatusButton,
|
||||
|
||||
_init: function() {
|
||||
PanelMenu.SystemStatusButton.prototype._init.call(this, 'battery-missing');
|
||||
this._proxy = new PowerManagerProxy(DBus.session, BUS_NAME, OBJECT_PATH);
|
||||
this.parent('battery-missing', null);
|
||||
|
||||
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
|
||||
|
||||
this._deviceItems = [ ];
|
||||
this._hasPrimary = false;
|
||||
@ -81,19 +76,19 @@ Indicator.prototype = {
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addSettingsAction(_("Power Settings"), 'gnome-power-panel.desktop');
|
||||
|
||||
this._proxy.connect('Changed', Lang.bind(this, this._devicesChanged));
|
||||
this._proxy.connectSignal('Changed', Lang.bind(this, this._devicesChanged));
|
||||
this._devicesChanged();
|
||||
},
|
||||
|
||||
_readPrimaryDevice: function() {
|
||||
this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(device, error) {
|
||||
this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(result, error) {
|
||||
if (error) {
|
||||
this._hasPrimary = false;
|
||||
this._primaryDeviceId = null;
|
||||
this._batteryItem.actor.hide();
|
||||
return;
|
||||
}
|
||||
let [device_id, device_type, icon, percentage, state, seconds] = device;
|
||||
let [[device_id, device_type, icon, percentage, state, seconds]] = result;
|
||||
if (device_type == UPDeviceType.BATTERY) {
|
||||
this._hasPrimary = true;
|
||||
let time = Math.round(seconds / 60);
|
||||
@ -118,7 +113,7 @@ Indicator.prototype = {
|
||||
timestring = ngettext("%d minute remaining", "%d minutes remaining", minutes).format(minutes);
|
||||
this._batteryItem.label.text = timestring;
|
||||
}
|
||||
this._primaryPercentage.text = Math.round(percentage) + '%';
|
||||
this._primaryPercentage.text = C_("percent of battery remaining", "%d%%").format(Math.round(percentage));
|
||||
this._batteryItem.actor.show();
|
||||
} else {
|
||||
this._hasPrimary = false;
|
||||
@ -130,7 +125,7 @@ Indicator.prototype = {
|
||||
},
|
||||
|
||||
_readOtherDevices: function() {
|
||||
this._proxy.GetDevicesRemote(Lang.bind(this, function(devices, error) {
|
||||
this._proxy.GetDevicesRemote(Lang.bind(this, function(result, error) {
|
||||
this._deviceItems.forEach(function(i) { i.destroy(); });
|
||||
this._deviceItems = [];
|
||||
|
||||
@ -139,6 +134,7 @@ Indicator.prototype = {
|
||||
}
|
||||
|
||||
let position = 0;
|
||||
let [devices] = result;
|
||||
for (let i = 0; i < devices.length; i++) {
|
||||
let [device_id, device_type] = devices[i];
|
||||
if (device_type == UPDeviceType.AC_POWER || device_id == this._primaryDeviceId)
|
||||
@ -153,37 +149,33 @@ Indicator.prototype = {
|
||||
},
|
||||
|
||||
_devicesChanged: function() {
|
||||
this._proxy.GetRemote('Icon', Lang.bind(this, function(icon, error) {
|
||||
if (icon) {
|
||||
let gicon = Shell.util_icon_from_string (icon);
|
||||
this.setGIcon(gicon);
|
||||
this.actor.show();
|
||||
} else {
|
||||
this.menu.close();
|
||||
this.actor.hide();
|
||||
}
|
||||
}));
|
||||
let icon = this._proxy.Icon;
|
||||
if (icon) {
|
||||
let gicon = Gio.icon_new_for_string(icon);
|
||||
this.setGIcon(gicon);
|
||||
this.actor.show();
|
||||
} else {
|
||||
this.menu.close();
|
||||
this.actor.hide();
|
||||
}
|
||||
this._readPrimaryDevice();
|
||||
this._readOtherDevices();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function DeviceItem() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
DeviceItem.prototype = {
|
||||
__proto__: PopupMenu.PopupBaseMenuItem.prototype,
|
||||
const DeviceItem = new Lang.Class({
|
||||
Name: 'DeviceItem',
|
||||
Extends: PopupMenu.PopupBaseMenuItem,
|
||||
|
||||
_init: function(device) {
|
||||
PopupMenu.PopupBaseMenuItem.prototype._init.call(this, { reactive: false });
|
||||
this.parent({ reactive: false });
|
||||
|
||||
let [device_id, device_type, icon, percentage, state, time] = device;
|
||||
|
||||
this._box = new St.BoxLayout({ style_class: 'popup-device-menu-item' });
|
||||
this._label = new St.Label({ text: this._deviceTypeToString(device_type) });
|
||||
|
||||
this._icon = new St.Icon({ gicon: Shell.util_icon_from_string(icon),
|
||||
this._icon = new St.Icon({ gicon: Gio.icon_new_for_string(icon),
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
style_class: 'popup-menu-icon' });
|
||||
|
||||
@ -191,7 +183,7 @@ DeviceItem.prototype = {
|
||||
this._box.add_actor(this._label);
|
||||
this.addActor(this._box);
|
||||
|
||||
let percentLabel = new St.Label({ text: '%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 });
|
||||
},
|
||||
|
||||
@ -223,4 +215,4 @@ DeviceItem.prototype = {
|
||||
return _("Unknown");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,7 +1,6 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const DBus = imports.dbus;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Shell = imports.gi.Shell;
|
||||
@ -18,15 +17,12 @@ const VOLUME_ADJUSTMENT_STEP = 0.05; /* Volume adjustment step in % */
|
||||
|
||||
const VOLUME_NOTIFY_ID = 1;
|
||||
|
||||
function Indicator() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
Indicator.prototype = {
|
||||
__proto__: PanelMenu.SystemStatusButton.prototype,
|
||||
const Indicator = new Lang.Class({
|
||||
Name: 'VolumeIndicator',
|
||||
Extends: PanelMenu.SystemStatusButton,
|
||||
|
||||
_init: function() {
|
||||
PanelMenu.SystemStatusButton.prototype._init.call(this, 'audio-volume-muted', null);
|
||||
this.parent('audio-volume-muted', null);
|
||||
|
||||
this._control = new Gvc.MixerControl({ name: 'GNOME Shell Volume Control' });
|
||||
this._control.connect('state-changed', Lang.bind(this, this._onControlStateChanged));
|
||||
@ -215,4 +211,4 @@ Indicator.prototype = {
|
||||
if (property == '_output' && !this._output.is_muted)
|
||||
this.setIcon(this._volumeToIcon(this._output.volume));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
@ -23,11 +23,9 @@ const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
|
||||
'ibus-ui-gtk': 'input-method'
|
||||
};
|
||||
|
||||
function StatusIconDispatcher() {
|
||||
this._init();
|
||||
}
|
||||
const StatusIconDispatcher = new Lang.Class({
|
||||
Name: 'StatusIconDispatcher',
|
||||
|
||||
StatusIconDispatcher.prototype = {
|
||||
_init: function() {
|
||||
this._traymanager = new Shell.TrayManager();
|
||||
this._traymanager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
||||
@ -61,5 +59,5 @@ StatusIconDispatcher.prototype = {
|
||||
else
|
||||
this.emit('message-icon-removed', icon);
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(StatusIconDispatcher.prototype);
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const DBus = imports.dbus;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
@ -73,16 +72,17 @@ function makeMessageFromTplEvent(event) {
|
||||
};
|
||||
}
|
||||
|
||||
function Client() {
|
||||
this._init();
|
||||
};
|
||||
const Client = new Lang.Class({
|
||||
Name: 'Client',
|
||||
|
||||
Client.prototype = {
|
||||
_init : function() {
|
||||
// channel path -> ChatSource
|
||||
this._chatSources = {};
|
||||
this._chatState = Tp.ChannelChatState.ACTIVE;
|
||||
|
||||
// account path -> AccountNotification
|
||||
this._accountNotifications = {};
|
||||
|
||||
// Set up a SimpleObserver, which will call _observeChannels whenever a
|
||||
// channel matching its filters is detected.
|
||||
// The second argument, recover, means _observeChannels will be run
|
||||
@ -254,7 +254,7 @@ Client.prototype = {
|
||||
// FIXME: We don't have a 'chat room' icon (bgo #653737) use
|
||||
// system-users for now as Empathy does.
|
||||
let source = new ApproverSource(dispatchOp, _("Invitation"),
|
||||
Shell.util_icon_from_string('system-users'));
|
||||
Gio.icon_new_for_string('system-users'));
|
||||
Main.messageTray.add(source);
|
||||
|
||||
let notif = new RoomInviteNotification(source, dispatchOp, channel, contacts[0]);
|
||||
@ -302,6 +302,8 @@ Client.prototype = {
|
||||
Shell.get_tp_contacts(conn, [targetHandle],
|
||||
contactFeatures,
|
||||
Lang.bind(this, this._createAudioVideoSource, channel, context, dispatchOp));
|
||||
|
||||
context.delay();
|
||||
},
|
||||
|
||||
_createAudioVideoSource: function(connection, contacts, failed, channel, context, dispatchOp) {
|
||||
@ -320,8 +322,8 @@ Client.prototype = {
|
||||
|
||||
// We got the TpContact
|
||||
let source = new ApproverSource(dispatchOp, _("Call"), isVideo ?
|
||||
Shell.util_icon_from_string('camera-web') :
|
||||
Shell.util_icon_from_string('audio-input-microphone'));
|
||||
Gio.icon_new_for_string('camera-web') :
|
||||
Gio.icon_new_for_string('audio-input-microphone'));
|
||||
Main.messageTray.add(source);
|
||||
|
||||
let notif = new AudioVideoNotification(source, dispatchOp, channel, contacts[0], isVideo);
|
||||
@ -335,6 +337,8 @@ Client.prototype = {
|
||||
Shell.get_tp_contacts(conn, [targetHandle],
|
||||
contactFeatures,
|
||||
Lang.bind(this, this._createFileTransferSource, channel, context, dispatchOp));
|
||||
|
||||
context.delay();
|
||||
},
|
||||
|
||||
_createFileTransferSource: function(connection, contacts, failed, channel, context, dispatchOp) {
|
||||
@ -420,7 +424,6 @@ Client.prototype = {
|
||||
|
||||
/* Display notification to ask user to accept/reject request */
|
||||
let source = this._ensureSubscriptionSource();
|
||||
Main.messageTray.add(source);
|
||||
|
||||
let notif = new SubscriptionRequestNotification(source, contact);
|
||||
source.notify(notif);
|
||||
@ -430,6 +433,7 @@ Client.prototype = {
|
||||
if (this._subscriptionSource == null) {
|
||||
this._subscriptionSource = new MultiNotificationSource(
|
||||
_("Subscription request"), 'gtk-dialog-question');
|
||||
Main.messageTray.add(this._subscriptionSource);
|
||||
this._subscriptionSource.connect('destroy', Lang.bind(this, function () {
|
||||
this._subscriptionSource = null;
|
||||
}));
|
||||
@ -446,11 +450,18 @@ Client.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
let notif = this._accountNotifications[account.get_object_path()];
|
||||
if (notif)
|
||||
return;
|
||||
|
||||
/* Display notification that account failed to connect */
|
||||
let source = this._ensureAccountSource();
|
||||
Main.messageTray.add(source);
|
||||
|
||||
let notif = new AccountNotification(source, account, connectionError);
|
||||
notif = new AccountNotification(source, account, connectionError);
|
||||
this._accountNotifications[account.get_object_path()] = notif;
|
||||
notif.connect('destroy', Lang.bind(this, function() {
|
||||
delete this._accountNotifications[account.get_object_path()];
|
||||
}));
|
||||
source.notify(notif);
|
||||
},
|
||||
|
||||
@ -458,6 +469,7 @@ Client.prototype = {
|
||||
if (this._accountSource == null) {
|
||||
this._accountSource = new MultiNotificationSource(
|
||||
_("Connection error"), 'gtk-dialog-error');
|
||||
Main.messageTray.add(this._accountSource);
|
||||
this._accountSource.connect('destroy', Lang.bind(this, function () {
|
||||
this._accountSource = null;
|
||||
}));
|
||||
@ -465,17 +477,14 @@ Client.prototype = {
|
||||
|
||||
return this._accountSource;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function ChatSource(account, conn, channel, contact, client) {
|
||||
this._init(account, conn, channel, contact, client);
|
||||
}
|
||||
|
||||
ChatSource.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
const ChatSource = new Lang.Class({
|
||||
Name: 'ChatSource',
|
||||
Extends: MessageTray.Source,
|
||||
|
||||
_init: function(account, conn, channel, contact, client) {
|
||||
MessageTray.Source.prototype._init.call(this, contact.get_alias());
|
||||
this.parent(contact.get_alias());
|
||||
|
||||
this.isChat = true;
|
||||
|
||||
@ -524,21 +533,18 @@ ChatSource.prototype = {
|
||||
|
||||
_updateAlias: function() {
|
||||
let oldAlias = this.title;
|
||||
this.setTitle(this._contact.get_alias());
|
||||
this._notification.appendAliasChange(oldAlias, this.title);
|
||||
this.pushNotification(this._notification);
|
||||
let newAlias = this._contact.get_alias();
|
||||
|
||||
if (oldAlias == newAlias)
|
||||
return;
|
||||
|
||||
this.setTitle(newAlias);
|
||||
this._notification.appendAliasChange(oldAlias, newAlias);
|
||||
},
|
||||
|
||||
createNotificationIcon: function() {
|
||||
this._iconBox = new St.Bin({ style_class: 'avatar-box' });
|
||||
this._iconBox._size = this.ICON_SIZE;
|
||||
|
||||
this._updateAvatarIcon();
|
||||
|
||||
return this._iconBox;
|
||||
},
|
||||
|
||||
_updateAvatarIcon: function() {
|
||||
let textureCache = St.TextureCache.get_default();
|
||||
let file = this._contact.get_avatar_file();
|
||||
|
||||
@ -550,12 +556,19 @@ ChatSource.prototype = {
|
||||
icon_type: St.IconType.FULLCOLOR,
|
||||
icon_size: this._iconBox._size });
|
||||
}
|
||||
|
||||
return this._iconBox;
|
||||
},
|
||||
|
||||
_updateAvatarIcon: function() {
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
this._notification.update(this._notification.title, null, { customContent: true, icon: this.createNotificationIcon() });
|
||||
},
|
||||
|
||||
open: function(notification) {
|
||||
if (this._client.is_handling_channel(this._channel)) {
|
||||
// We are handling the channel, try to pass it to Empathy
|
||||
this._client.delegate_channels_async([this._channel], global.get_current_time(), "", null);
|
||||
this._client.delegate_channels_async([this._channel], global.get_current_time(), '', null);
|
||||
}
|
||||
else {
|
||||
// We are not the handler, just ask to present the channel
|
||||
@ -679,7 +692,7 @@ ChatSource.prototype = {
|
||||
},
|
||||
|
||||
notify: function() {
|
||||
MessageTray.Source.prototype.notify.call(this, this._notification);
|
||||
this.parent(this._notification);
|
||||
},
|
||||
|
||||
respond: function(text) {
|
||||
@ -780,17 +793,14 @@ ChatSource.prototype = {
|
||||
|
||||
this._shouldAck = false;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function ChatNotification(source) {
|
||||
this._init(source);
|
||||
}
|
||||
|
||||
ChatNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
const ChatNotification = new Lang.Class({
|
||||
Name: 'ChatNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source) {
|
||||
MessageTray.Notification.prototype._init.call(this, source, source.title, null, { customContent: true });
|
||||
this.parent(source, source.title, null, { customContent: true });
|
||||
this.setResident(true);
|
||||
|
||||
this._responseEntry = new St.Entry({ style_class: 'chat-response',
|
||||
@ -881,7 +891,7 @@ ChatNotification.prototype = {
|
||||
}
|
||||
|
||||
let groups = this._contentArea.get_children();
|
||||
for (let i = 0; i < groups.length; i ++) {
|
||||
for (let i = 0; i < groups.length; i++) {
|
||||
let group = groups[i];
|
||||
if (group.get_children().length == 0)
|
||||
group.destroy();
|
||||
@ -919,7 +929,7 @@ ChatNotification.prototype = {
|
||||
let body = highlighter.actor;
|
||||
|
||||
let styles = props.styles;
|
||||
for (let i = 0; i < styles.length; i ++)
|
||||
for (let i = 0; i < styles.length; i++)
|
||||
body.add_style_class_name(styles[i]);
|
||||
|
||||
let group = props.group;
|
||||
@ -1019,7 +1029,7 @@ ChatNotification.prototype = {
|
||||
IM name. */
|
||||
let message = '<i>' + _("%s is now known as %s").format(oldAlias, newAlias) + '</i>';
|
||||
|
||||
let label = this._append({ body: text,
|
||||
let label = this._append({ body: message,
|
||||
group: 'meta',
|
||||
styles: ['chat-meta-message'] });
|
||||
|
||||
@ -1073,17 +1083,14 @@ ChatNotification.prototype = {
|
||||
this.source.setChatState(Tp.ChannelChatState.ACTIVE);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function ApproverSource(dispatchOp, text, gicon) {
|
||||
this._init(dispatchOp, text, gicon);
|
||||
}
|
||||
|
||||
ApproverSource.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
const ApproverSource = new Lang.Class({
|
||||
Name: 'ApproverSource',
|
||||
Extends: MessageTray.Source,
|
||||
|
||||
_init: function(dispatchOp, text, gicon) {
|
||||
MessageTray.Source.prototype._init.call(this, text);
|
||||
this.parent(text);
|
||||
|
||||
this._gicon = gicon;
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
@ -1104,7 +1111,7 @@ ApproverSource.prototype = {
|
||||
this._invalidId = 0;
|
||||
}
|
||||
|
||||
MessageTray.Source.prototype.destroy.call(this);
|
||||
this.parent();
|
||||
},
|
||||
|
||||
createNotificationIcon: function() {
|
||||
@ -1112,23 +1119,19 @@ ApproverSource.prototype = {
|
||||
icon_type: St.IconType.FULLCOLOR,
|
||||
icon_size: this.ICON_SIZE });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function RoomInviteNotification(source, dispatchOp, channel, inviter) {
|
||||
this._init(source, dispatchOp, channel, inviter);
|
||||
}
|
||||
|
||||
RoomInviteNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
const RoomInviteNotification = new Lang.Class({
|
||||
Name: 'RoomInviteNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source, dispatchOp, channel, inviter) {
|
||||
MessageTray.Notification.prototype._init.call(this,
|
||||
source,
|
||||
/* translators: argument is a room name like
|
||||
* room@jabber.org for example. */
|
||||
_("Invitation to %s").format(channel.get_identifier()),
|
||||
null,
|
||||
{ customContent: true });
|
||||
this.parent(source,
|
||||
/* translators: argument is a room name like
|
||||
* room@jabber.org for example. */
|
||||
_("Invitation to %s").format(channel.get_identifier()),
|
||||
null,
|
||||
{ customContent: true });
|
||||
this.setResident(true);
|
||||
|
||||
/* translators: first argument is the name of a contact and the second
|
||||
@ -1155,15 +1158,12 @@ RoomInviteNotification.prototype = {
|
||||
this.destroy();
|
||||
}));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// Audio Video
|
||||
function AudioVideoNotification(source, dispatchOp, channel, contact, isVideo) {
|
||||
this._init(source, dispatchOp, channel, contact, isVideo);
|
||||
}
|
||||
|
||||
AudioVideoNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
const AudioVideoNotification = new Lang.Class({
|
||||
Name: 'AudioVideoNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source, dispatchOp, channel, contact, isVideo) {
|
||||
let title = '';
|
||||
@ -1175,14 +1175,11 @@ AudioVideoNotification.prototype = {
|
||||
/* translators: argument is a contact name like Alice for example. */
|
||||
title = _("Call from %s").format(contact.get_alias());
|
||||
|
||||
MessageTray.Notification.prototype._init.call(this,
|
||||
source,
|
||||
title,
|
||||
null,
|
||||
{ customContent: true });
|
||||
this.parent(this, source, title, null, { customContent: true });
|
||||
this.setResident(true);
|
||||
|
||||
this.addButton('reject', _("Reject"));
|
||||
/* translators: this is a button label (verb), not a noun */
|
||||
this.addButton('answer', _("Answer"));
|
||||
|
||||
this.connect('action-invoked', Lang.bind(this, function(self, action) {
|
||||
@ -1201,28 +1198,25 @@ AudioVideoNotification.prototype = {
|
||||
this.destroy();
|
||||
}));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// File Transfer
|
||||
function FileTransferNotification(source, dispatchOp, channel, contact) {
|
||||
this._init(source, dispatchOp, channel, contact);
|
||||
}
|
||||
|
||||
FileTransferNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
const FileTransferNotification = new Lang.Class({
|
||||
Name: 'FileTransferNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source, dispatchOp, channel, contact) {
|
||||
MessageTray.Notification.prototype._init.call(this,
|
||||
source,
|
||||
/* To translators: The first parameter is
|
||||
* the contact's alias and the second one is the
|
||||
* file name. The string will be something
|
||||
* like: "Alice is sending you test.ogg"
|
||||
*/
|
||||
_("%s is sending you %s").format(contact.get_alias(),
|
||||
channel.get_filename()),
|
||||
null,
|
||||
{ customContent: true });
|
||||
this.parent(this,
|
||||
source,
|
||||
/* To translators: The first parameter is
|
||||
* the contact's alias and the second one is the
|
||||
* file name. The string will be something
|
||||
* like: "Alice is sending you test.ogg"
|
||||
*/
|
||||
_("%s is sending you %s").format(contact.get_alias(),
|
||||
channel.get_filename()),
|
||||
null,
|
||||
{ customContent: true });
|
||||
this.setResident(true);
|
||||
|
||||
this.addButton('decline', _("Decline"));
|
||||
@ -1244,18 +1238,15 @@ FileTransferNotification.prototype = {
|
||||
this.destroy();
|
||||
}));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// A notification source that can embed multiple notifications
|
||||
function MultiNotificationSource(title, icon) {
|
||||
this._init(title, icon);
|
||||
}
|
||||
|
||||
MultiNotificationSource.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
const MultiNotificationSource = new Lang.Class({
|
||||
Name: 'MultiNotificationSource',
|
||||
Extends: MessageTray.Source,
|
||||
|
||||
_init: function(title, icon) {
|
||||
MessageTray.Source.prototype._init.call(this, title);
|
||||
this.parent(title);
|
||||
|
||||
this._icon = icon;
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
@ -1263,7 +1254,7 @@ MultiNotificationSource.prototype = {
|
||||
},
|
||||
|
||||
notify: function(notification) {
|
||||
MessageTray.Source.prototype.notify.call(this, notification);
|
||||
this.parent(notification);
|
||||
|
||||
this._nbNotifications += 1;
|
||||
|
||||
@ -1277,25 +1268,22 @@ MultiNotificationSource.prototype = {
|
||||
},
|
||||
|
||||
createNotificationIcon: function() {
|
||||
return new St.Icon({ gicon: Shell.util_icon_from_string(this._icon),
|
||||
return new St.Icon({ gicon: Gio.icon_new_for_string(this._icon),
|
||||
icon_type: St.IconType.FULLCOLOR,
|
||||
icon_size: this.ICON_SIZE });
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// Subscription request
|
||||
function SubscriptionRequestNotification(source, contact) {
|
||||
this._init(source, contact);
|
||||
}
|
||||
|
||||
SubscriptionRequestNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
const SubscriptionRequestNotification = new Lang.Class({
|
||||
Name: 'SubscriptionRequestNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source, contact) {
|
||||
MessageTray.Notification.prototype._init.call(this, source,
|
||||
/* To translators: The parameter is the contact's alias */
|
||||
_("%s would like permission to see when you are online").format(contact.get_alias()),
|
||||
null, { customContent: true });
|
||||
this.parent(this, source,
|
||||
/* To translators: The parameter is the contact's alias */
|
||||
_("%s would like permission to see when you are online").format(contact.get_alias()),
|
||||
null, { customContent: true });
|
||||
|
||||
this._contact = contact;
|
||||
this._connection = contact.get_connection();
|
||||
@ -1369,7 +1357,7 @@ SubscriptionRequestNotification.prototype = {
|
||||
this._invalidatedId = 0;
|
||||
}
|
||||
|
||||
MessageTray.Notification.prototype.destroy.call(this);
|
||||
this.parent();
|
||||
},
|
||||
|
||||
_subscriptionStatesChangedCb: function(contact, subscribe, publish, msg) {
|
||||
@ -1378,12 +1366,7 @@ SubscriptionRequestNotification.prototype = {
|
||||
if (publish != Tp.SubscriptionState.ASK)
|
||||
this.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function AccountNotification(source, account, connectionError) {
|
||||
this._init(source, account, connectionError);
|
||||
}
|
||||
});
|
||||
|
||||
// Messages from empathy/libempathy/empathy-utils.c
|
||||
// create_errors_to_message_hash()
|
||||
@ -1438,27 +1421,23 @@ _connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_INSECURE)]
|
||||
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_LIMIT_EXCEEDED)]
|
||||
= _("The length of the server certificate, or the depth of the server certificate chain, exceed the limits imposed by the cryptography library");
|
||||
|
||||
AccountNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
const AccountNotification = new Lang.Class({
|
||||
Name: 'AccountNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source, account, connectionError) {
|
||||
MessageTray.Notification.prototype._init.call(this, source,
|
||||
/* translators: argument is the account name, like
|
||||
* name@jabber.org for example. */
|
||||
_("Connection to %s failed").format(account.get_display_name()),
|
||||
null, { customContent: true });
|
||||
this.parent(source,
|
||||
/* translators: argument is the account name, like
|
||||
* name@jabber.org for example. */
|
||||
_("Connection to %s failed").format(account.get_display_name()),
|
||||
null, { customContent: true });
|
||||
|
||||
let message;
|
||||
if (connectionError in _connectionErrorMessages) {
|
||||
message = _connectionErrorMessages[connectionError];
|
||||
} else {
|
||||
message = _("Unknown reason");
|
||||
}
|
||||
this._label = new St.Label();
|
||||
this.addActor(this._label);
|
||||
this._updateMessage(connectionError);
|
||||
|
||||
this._account = account;
|
||||
|
||||
this.addBody(message);
|
||||
|
||||
this.addButton('reconnect', _("Reconnect"));
|
||||
this.addButton('edit', _("Edit account"));
|
||||
|
||||
@ -1492,11 +1471,25 @@ AccountNotification.prototype = {
|
||||
|
||||
this._connectionStatusId = account.connect('notify::connection-status',
|
||||
Lang.bind(this, function() {
|
||||
if (account.connection_status != Tp.ConnectionStatus.DISCONNECTED)
|
||||
let status = account.connection_status;
|
||||
if (status == Tp.ConnectionStatus.CONNECTED) {
|
||||
this.destroy();
|
||||
} else if (status == Tp.ConnectionStatus.DISCONNECTED) {
|
||||
this._updateMessage(account.connection_error);
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
_updateMessage: function(connectionError) {
|
||||
let message;
|
||||
if (connectionError in _connectionErrorMessages) {
|
||||
message = _connectionErrorMessages[connectionError];
|
||||
} else {
|
||||
message = _("Unknown reason");
|
||||
}
|
||||
this._label.set_text(message);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
if (this._enabledId != 0) {
|
||||
this._account.disconnect(this._enabledId);
|
||||
@ -1513,6 +1506,6 @@ AccountNotification.prototype = {
|
||||
this._connectionStatusId = 0;
|
||||
}
|
||||
|
||||
MessageTray.Notification.prototype.destroy.call(this);
|
||||
this.parent();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
@ -202,11 +202,9 @@ function registerSpecialPropertySplitter(name, splitFunction, parameters) {
|
||||
// time updates; even better is to pay attention to the vertical
|
||||
// vblank and sync to that when possible.)
|
||||
//
|
||||
function ClutterFrameTicker() {
|
||||
this._init();
|
||||
}
|
||||
const ClutterFrameTicker = new Lang.Class({
|
||||
Name: 'ClutterFrameTicker',
|
||||
|
||||
ClutterFrameTicker.prototype = {
|
||||
FRAME_RATE : 60,
|
||||
|
||||
_init : function() {
|
||||
@ -261,6 +259,6 @@ ClutterFrameTicker.prototype = {
|
||||
this._startTime = -1;
|
||||
global.end_work();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Signals.addSignalMethods(ClutterFrameTicker.prototype);
|
||||
|
@ -1,10 +1,10 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const AccountsService = imports.gi.AccountsService;
|
||||
const DBus = imports.dbus;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Tp = imports.gi.TelepathyGLib;
|
||||
@ -22,7 +22,6 @@ const DISABLE_USER_SWITCH_KEY = 'disable-user-switching';
|
||||
const DISABLE_LOCK_SCREEN_KEY = 'disable-lock-screen';
|
||||
const DISABLE_LOG_OUT_KEY = 'disable-log-out';
|
||||
|
||||
const WRAP_WIDTH = 150;
|
||||
const DIALOG_ICON_SIZE = 64;
|
||||
|
||||
const IMStatus = {
|
||||
@ -41,15 +40,12 @@ const IMStatus = {
|
||||
// Copyright (C) 2008,2009 Red Hat, Inc.
|
||||
|
||||
|
||||
function IMStatusItem(label, iconName) {
|
||||
this._init(label, iconName);
|
||||
}
|
||||
|
||||
IMStatusItem.prototype = {
|
||||
__proto__: PopupMenu.PopupBaseMenuItem.prototype,
|
||||
const IMStatusItem = new Lang.Class({
|
||||
Name: 'IMStatusItem',
|
||||
Extends: PopupMenu.PopupBaseMenuItem,
|
||||
|
||||
_init: function(label, iconName) {
|
||||
PopupMenu.PopupBaseMenuItem.prototype._init.call(this);
|
||||
this.parent();
|
||||
|
||||
this.actor.add_style_class_name('status-chooser-status-item');
|
||||
|
||||
@ -62,19 +58,15 @@ IMStatusItem.prototype = {
|
||||
this.label = new St.Label({ text: label });
|
||||
this.addActor(this.label);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function IMUserNameItem() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
IMUserNameItem.prototype = {
|
||||
__proto__: PopupMenu.PopupBaseMenuItem.prototype,
|
||||
const IMUserNameItem = new Lang.Class({
|
||||
Name: 'IMUserNameItem',
|
||||
Extends: PopupMenu.PopupBaseMenuItem,
|
||||
|
||||
_init: function() {
|
||||
PopupMenu.PopupBaseMenuItem.prototype._init.call(this,
|
||||
{ reactive: false,
|
||||
style_class: 'status-chooser-user-name' });
|
||||
this.parent({ reactive: false,
|
||||
style_class: 'status-chooser-user-name' });
|
||||
|
||||
this._wrapper = new Shell.GenericContainer();
|
||||
this._wrapper.connect('get-preferred-width',
|
||||
@ -87,43 +79,31 @@ IMUserNameItem.prototype = {
|
||||
|
||||
this.label = new St.Label();
|
||||
this.label.clutter_text.set_line_wrap(true);
|
||||
this.label.clutter_text.set_ellipsize(Pango.EllipsizeMode.NONE);
|
||||
this._wrapper.add_actor(this.label);
|
||||
},
|
||||
|
||||
_wrapperGetPreferredWidth: function(actor, forHeight, alloc) {
|
||||
[alloc.min_size, alloc.natural_size] = this.label.get_preferred_width(-1);
|
||||
if (alloc.natural_size > WRAP_WIDTH)
|
||||
alloc.natural_size = WRAP_WIDTH;
|
||||
alloc.min_size = 1;
|
||||
alloc.natural_size = 1;
|
||||
},
|
||||
|
||||
_wrapperGetPreferredHeight: function(actor, forWidth, alloc) {
|
||||
let minWidth, natWidth;
|
||||
[alloc.min_size, alloc.natural_size] = this.label.get_preferred_height(forWidth);
|
||||
[minWidth, natWidth] = this.label.get_preferred_width(-1);
|
||||
if (natWidth > WRAP_WIDTH) {
|
||||
alloc.min_size *= 2;
|
||||
alloc.natural_size *= 2;
|
||||
}
|
||||
},
|
||||
|
||||
_wrapperAllocate: function(actor, box, flags) {
|
||||
let availWidth = box.x2 - box.x1;
|
||||
let availHeight = box.y2 - box.y1;
|
||||
this.label.allocate(box, flags);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function IMStatusChooserItem() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
IMStatusChooserItem.prototype = {
|
||||
__proto__: PopupMenu.PopupBaseMenuItem.prototype,
|
||||
const IMStatusChooserItem = new Lang.Class({
|
||||
Name: 'IMStatusChooserItem',
|
||||
Extends: PopupMenu.PopupBaseMenuItem,
|
||||
|
||||
_init: function() {
|
||||
PopupMenu.PopupBaseMenuItem.prototype._init.call (this,
|
||||
{ reactive: false,
|
||||
style_class: 'status-chooser' });
|
||||
this.parent({ reactive: false,
|
||||
style_class: 'status-chooser' });
|
||||
|
||||
this._iconBin = new St.Button({ style_class: 'status-chooser-user-icon' });
|
||||
this.addActor(this._iconBin);
|
||||
@ -166,22 +146,39 @@ IMStatusChooserItem.prototype = {
|
||||
Lang.bind(this, this._changeIMStatus));
|
||||
|
||||
this._presence = new GnomeSession.Presence();
|
||||
this._presence.getStatus(Lang.bind(this, this._sessionStatusChanged));
|
||||
this._presence.connect('StatusChanged',
|
||||
Lang.bind(this, this._sessionStatusChanged));
|
||||
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
|
||||
this._sessionStatusChanged(status);
|
||||
}));
|
||||
|
||||
this._sessionPresenceRestored = false;
|
||||
this._imPresenceRestored = false;
|
||||
this._currentPresence = undefined;
|
||||
this._previousPresence = undefined;
|
||||
|
||||
this._accountMgr = Tp.AccountManager.dup()
|
||||
this._accountMgr = Tp.AccountManager.dup();
|
||||
this._accountMgr.connect('most-available-presence-changed',
|
||||
Lang.bind(this, this._IMStatusChanged));
|
||||
this._accountMgr.connect('account-enabled',
|
||||
Lang.bind(this, this._IMAccountsChanged));
|
||||
this._accountMgr.connect('account-disabled',
|
||||
Lang.bind(this, this._IMAccountsChanged));
|
||||
this._accountMgr.connect('account-removed',
|
||||
Lang.bind(this, this._IMAccountsChanged));
|
||||
this._accountMgr.prepare_async(null, Lang.bind(this,
|
||||
function(mgr) {
|
||||
let [presence, s, msg] = mgr.get_most_available_presence();
|
||||
let [presence, status, msg] = mgr.get_most_available_presence();
|
||||
|
||||
this._previousPresence = presence;
|
||||
this._IMStatusChanged(mgr, presence, s, msg);
|
||||
let savedPresence = global.settings.get_int('saved-im-presence');
|
||||
|
||||
this._IMAccountsChanged(mgr);
|
||||
|
||||
if (savedPresence == presence) {
|
||||
this._IMStatusChanged(mgr, presence, status, msg);
|
||||
} else {
|
||||
this._setComboboxPresence(savedPresence);
|
||||
status = this._statusForPresence(savedPresence);
|
||||
msg = msg ? msg : '';
|
||||
mgr.set_all_requested_presences(savedPresence, status, msg);
|
||||
}
|
||||
}));
|
||||
|
||||
this._userManager = AccountsService.UserManager.get_default();
|
||||
@ -194,6 +191,25 @@ IMStatusChooserItem.prototype = {
|
||||
this._userChangedId = this._user.connect('changed',
|
||||
Lang.bind(this,
|
||||
this._updateUser));
|
||||
this.actor.connect('notify::mapped', Lang.bind(this, function() {
|
||||
if (this.actor.mapped)
|
||||
this._updateUser();
|
||||
}));
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
// clean up signal handlers
|
||||
if (this._userLoadedId != 0) {
|
||||
this._user.disconnect(this._userLoadedId);
|
||||
this._userLoadedId = 0;
|
||||
}
|
||||
|
||||
if (this._userChangedId != 0) {
|
||||
this._user.disconnect(this._userChangedId);
|
||||
this._userChangedId = 0;
|
||||
}
|
||||
|
||||
this.parent();
|
||||
},
|
||||
|
||||
// Override getColumnWidths()/setColumnWidths() to make the item
|
||||
@ -203,9 +219,6 @@ IMStatusChooserItem.prototype = {
|
||||
},
|
||||
|
||||
setColumnWidths: function(widths) {
|
||||
this._columnWidths = PopupMenu.PopupBaseMenuItem.prototype.getColumnWidths.call(this);
|
||||
let sectionWidths = this._section.getColumnWidths();
|
||||
this._section.setColumnWidths(sectionWidths);
|
||||
},
|
||||
|
||||
_updateUser: function() {
|
||||
@ -267,20 +280,43 @@ IMStatusChooserItem.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_IMAccountsChanged: function(mgr) {
|
||||
let accounts = mgr.get_valid_accounts().filter(function(account) {
|
||||
return account.enabled;
|
||||
});
|
||||
this._combo.setSensitive(accounts.length > 0);
|
||||
},
|
||||
|
||||
_IMStatusChanged: function(accountMgr, presence, status, message) {
|
||||
if (!this._imPresenceRestored)
|
||||
this._imPresenceRestored = true;
|
||||
|
||||
if (presence == this._currentPresence)
|
||||
return;
|
||||
|
||||
this._currentPresence = presence;
|
||||
this._setComboboxPresence(presence);
|
||||
|
||||
if (!this._sessionPresenceRestored) {
|
||||
this._sessionStatusChanged(this._presence.status);
|
||||
return;
|
||||
}
|
||||
|
||||
if (presence == Tp.ConnectionPresenceType.AVAILABLE)
|
||||
this._presence.setStatus(GnomeSession.PresenceStatus.AVAILABLE);
|
||||
this._presence.status = GnomeSession.PresenceStatus.AVAILABLE;
|
||||
|
||||
if (!this._expectedPresence || presence != this._expectedPresence)
|
||||
this._previousPresence = presence;
|
||||
// We ignore the actual value of _expectedPresence and never safe
|
||||
// the first presence change after an "automatic" change, assuming
|
||||
// that it is the response to our request; this is to account for
|
||||
// mission control falling back to "similar" presences if an account
|
||||
// type does not implement the requested presence.
|
||||
if (!this._expectedPresence)
|
||||
global.settings.set_int('saved-im-presence', presence);
|
||||
else
|
||||
this._expectedPresence = undefined;
|
||||
},
|
||||
|
||||
_setComboboxPresence: function(presence) {
|
||||
let activatedItem;
|
||||
|
||||
if (presence == Tp.ConnectionPresenceType.AVAILABLE)
|
||||
@ -317,59 +353,76 @@ IMStatusChooserItem.prototype = {
|
||||
return;
|
||||
|
||||
status = this._statusForPresence(newPresence);
|
||||
msg = msg ? msg : "";
|
||||
msg = msg ? msg : '';
|
||||
this._accountMgr.set_all_requested_presences(newPresence, status, msg);
|
||||
},
|
||||
|
||||
_sessionStatusChanged: function(sessionPresence, sessionStatus) {
|
||||
getIMPresenceForSessionStatus: function(sessionStatus) {
|
||||
// Restore the last user-set presence when coming back from
|
||||
// BUSY/IDLE (otherwise the last user-set presence matches
|
||||
// the current one)
|
||||
if (sessionStatus == GnomeSession.PresenceStatus.AVAILABLE)
|
||||
return global.settings.get_int('saved-im-presence');
|
||||
|
||||
if (sessionStatus == GnomeSession.PresenceStatus.BUSY) {
|
||||
// Only change presence if the current one is "more present" than
|
||||
// busy, or if coming back from idle
|
||||
if (this._currentPresence == Tp.ConnectionPresenceType.AVAILABLE ||
|
||||
this._currentPresence == Tp.ConnectionPresenceType.EXTENDED_AWAY)
|
||||
return Tp.ConnectionPresenceType.BUSY;
|
||||
}
|
||||
|
||||
if (sessionStatus == GnomeSession.PresenceStatus.IDLE) {
|
||||
// Only change presence if the current one is "more present" than
|
||||
// idle
|
||||
if (this._currentPresence != Tp.ConnectionPresenceType.OFFLINE)
|
||||
return Tp.ConnectionPresenceType.EXTENDED_AWAY;
|
||||
}
|
||||
|
||||
return this._currentPresence;
|
||||
},
|
||||
|
||||
_sessionStatusChanged: function(sessionStatus) {
|
||||
if (!this._imPresenceRestored)
|
||||
return;
|
||||
|
||||
if (!this._sessionPresenceRestored) {
|
||||
let savedStatus = global.settings.get_int('saved-session-presence');
|
||||
if (sessionStatus != savedStatus) {
|
||||
this._presence.status = savedStatus;
|
||||
return;
|
||||
}
|
||||
this._sessionPresenceRestored = true;
|
||||
}
|
||||
|
||||
global.settings.set_int('saved-session-presence', sessionStatus);
|
||||
|
||||
let [presence, s, msg] = this._accountMgr.get_most_available_presence();
|
||||
let newPresence, status;
|
||||
|
||||
if (sessionStatus == GnomeSession.PresenceStatus.AVAILABLE) {
|
||||
newPresence = this._previousPresence;
|
||||
} else if (sessionStatus == GnomeSession.PresenceStatus.BUSY) {
|
||||
// Only change presence if the current one is "more present" than
|
||||
// busy, or if coming back from idle
|
||||
if (presence == Tp.ConnectionPresenceType.AVAILABLE ||
|
||||
presence == Tp.ConnectionPresenceType.EXTENDED_AWAY) {
|
||||
newPresence = Tp.ConnectionPresenceType.BUSY;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (sessionStatus == GnomeSession.PresenceStatus.IDLE) {
|
||||
// Only change presence if the current one is "more present" than
|
||||
// idle
|
||||
if (presence != Tp.ConnectionPresenceType.OFFLINE)
|
||||
newPresence = Tp.ConnectionPresenceType.EXTENDED_AWAY;
|
||||
else
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
let newPresence = this.getIMPresenceForSessionStatus(sessionStatus);
|
||||
|
||||
if (newPresence == undefined)
|
||||
if (!newPresence || newPresence == presence)
|
||||
return;
|
||||
|
||||
status = this._statusForPresence(newPresence);
|
||||
msg = msg ? msg : "";
|
||||
msg = msg ? msg : '';
|
||||
|
||||
this._expectedPresence = newPresence;
|
||||
this._accountMgr.set_all_requested_presences(newPresence, status, msg);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
function UserMenuButton() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
UserMenuButton.prototype = {
|
||||
__proto__: PanelMenu.Button.prototype,
|
||||
const UserMenuButton = new Lang.Class({
|
||||
Name: 'UserMenuButton',
|
||||
Extends: PanelMenu.Button,
|
||||
|
||||
_init: function() {
|
||||
PanelMenu.Button.prototype._init.call(this, 0.0);
|
||||
let box = new St.BoxLayout({ name: 'panelStatusMenu' });
|
||||
this.actor.set_child(box);
|
||||
this.parent(0.0);
|
||||
|
||||
let box = new St.BoxLayout({ name: 'panelUserMenu' });
|
||||
this.actor.add_actor(box);
|
||||
|
||||
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
|
||||
|
||||
@ -380,7 +433,7 @@ UserMenuButton.prototype = {
|
||||
this._session = new GnomeSession.SessionManager();
|
||||
this._haveShutdown = true;
|
||||
|
||||
this._account_mgr = Tp.AccountManager.dup()
|
||||
this._accountMgr = Tp.AccountManager.dup();
|
||||
|
||||
this._upClient = new UPowerGlib.Client();
|
||||
this._screenSaverProxy = new ScreenSaver.ScreenSaverProxy();
|
||||
@ -403,13 +456,9 @@ UserMenuButton.prototype = {
|
||||
this._idleIcon = new St.Icon({ icon_name: 'user-idle',
|
||||
style_class: 'popup-menu-icon' });
|
||||
|
||||
this._presence.connect('StatusChanged',
|
||||
Lang.bind(this, this._updateSwitch));
|
||||
this._presence.getStatus(Lang.bind(this, this._updateSwitch));
|
||||
|
||||
this._account_mgr.connect('most-available-presence-changed',
|
||||
this._accountMgr.connect('most-available-presence-changed',
|
||||
Lang.bind(this, this._updatePresenceIcon));
|
||||
this._account_mgr.prepare_async(null, Lang.bind(this,
|
||||
this._accountMgr.prepare_async(null, Lang.bind(this,
|
||||
function(mgr) {
|
||||
let [presence, s, msg] = mgr.get_most_available_presence();
|
||||
this._updatePresenceIcon(mgr, presence, s, msg);
|
||||
@ -419,10 +468,19 @@ UserMenuButton.prototype = {
|
||||
box.add(this._name, { y_align: St.Align.MIDDLE, y_fill: false });
|
||||
this._userLoadedId = this._user.connect('notify::is-loaded', Lang.bind(this, this._updateUserName));
|
||||
this._userChangedId = this._user.connect('changed', Lang.bind(this, this._updateUserName));
|
||||
this._updateUserName();
|
||||
|
||||
this._createSubMenu();
|
||||
|
||||
this._updateSwitch(this._presence.status);
|
||||
this._presence.connectSignal('StatusChanged', Lang.bind(this, function (proxy, senderName, [status]) {
|
||||
this._updateSwitch(status);
|
||||
}));
|
||||
|
||||
this._userManager.connect('notify::is-loaded',
|
||||
Lang.bind(this, this._updateSwitchUser));
|
||||
this._userManager.connect('notify::has-multiple-users',
|
||||
Lang.bind(this, this._updateSwitchUser));
|
||||
this._userManager.connect('user-added',
|
||||
Lang.bind(this, this._updateSwitchUser));
|
||||
this._userManager.connect('user-removed',
|
||||
@ -467,7 +525,9 @@ UserMenuButton.prototype = {
|
||||
|
||||
_updateSwitchUser: function() {
|
||||
let allowSwitch = !this._lockdownSettings.get_boolean(DISABLE_USER_SWITCH_KEY);
|
||||
if (allowSwitch && this._userManager.can_switch ())
|
||||
if (allowSwitch &&
|
||||
this._userManager.can_switch() &&
|
||||
this._userManager.has_multiple_users)
|
||||
this._loginScreenItem.actor.show();
|
||||
else
|
||||
this._loginScreenItem.actor.hide();
|
||||
@ -521,7 +581,7 @@ UserMenuButton.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_updateSwitch: function(presence, status) {
|
||||
_updateSwitch: function(status) {
|
||||
let active = status == GnomeSession.PresenceStatus.AVAILABLE;
|
||||
this._notificationsSwitch.setToggleState(active);
|
||||
},
|
||||
@ -547,6 +607,7 @@ UserMenuButton.prototype = {
|
||||
item = new IMStatusChooserItem();
|
||||
item.connect('activate', Lang.bind(this, this._onMyAccountActivate));
|
||||
this.menu.addMenuItem(item);
|
||||
this._statusChooser = item;
|
||||
|
||||
item = new PopupMenu.PopupSwitchMenuItem(_("Notifications"));
|
||||
item.connect('activate', Lang.bind(this, this._updatePresenceStatus));
|
||||
@ -594,9 +655,22 @@ UserMenuButton.prototype = {
|
||||
},
|
||||
|
||||
_updatePresenceStatus: function(item, event) {
|
||||
let status = item.state ? GnomeSession.PresenceStatus.AVAILABLE
|
||||
: GnomeSession.PresenceStatus.BUSY;
|
||||
this._presence.setStatus(status);
|
||||
let status;
|
||||
|
||||
if (item.state) {
|
||||
status = GnomeSession.PresenceStatus.AVAILABLE;
|
||||
} else {
|
||||
status = GnomeSession.PresenceStatus.BUSY;
|
||||
|
||||
let [presence, s, msg] = this._accountMgr.get_most_available_presence();
|
||||
let newPresence = this._statusChooser.getIMPresenceForSessionStatus(status);
|
||||
if (newPresence != presence &&
|
||||
newPresence == Tp.ConnectionPresenceType.BUSY)
|
||||
Main.notify(_("Your chat status will be set to busy"),
|
||||
_("Notifications are now disabled, including chat messages. Your online status has been adjusted to let others know that you might not see their messages."));
|
||||
}
|
||||
|
||||
this._presence.status = status;
|
||||
},
|
||||
|
||||
_onMyAccountActivate: function() {
|
||||
@ -649,4 +723,4 @@ UserMenuButton.prototype = {
|
||||
this._session.ShutdownRemote();
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
@ -12,13 +12,12 @@ const St = imports.gi.St;
|
||||
const Main = imports.ui.main;
|
||||
const Search = imports.ui.search;
|
||||
const SearchDisplay = imports.ui.searchDisplay;
|
||||
const ShellEntry = imports.ui.shellEntry;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
function BaseTab(titleActor, pageActor, name, a11yIcon) {
|
||||
this._init(titleActor, pageActor, name, a11yIcon);
|
||||
}
|
||||
const BaseTab = new Lang.Class({
|
||||
Name: 'BaseTab',
|
||||
|
||||
BaseTab.prototype = {
|
||||
_init: function(titleActor, pageActor, name, a11yIcon) {
|
||||
this.title = titleActor;
|
||||
this.page = new St.Bin({ child: pageActor,
|
||||
@ -74,16 +73,13 @@ BaseTab.prototype = {
|
||||
_activate: function() {
|
||||
this.emit('activated');
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(BaseTab.prototype);
|
||||
|
||||
|
||||
function ViewTab(id, label, pageActor, a11yIcon) {
|
||||
this._init(id, label, pageActor, a11yIcon);
|
||||
}
|
||||
|
||||
ViewTab.prototype = {
|
||||
__proto__: BaseTab.prototype,
|
||||
const ViewTab = new Lang.Class({
|
||||
Name: 'ViewTab',
|
||||
Extends: BaseTab,
|
||||
|
||||
_init: function(id, label, pageActor, a11yIcon) {
|
||||
this.id = id;
|
||||
@ -92,17 +88,14 @@ ViewTab.prototype = {
|
||||
style_class: 'view-tab-title' });
|
||||
titleActor.connect('clicked', Lang.bind(this, this._activate));
|
||||
|
||||
BaseTab.prototype._init.call(this, titleActor, pageActor, label, a11yIcon);
|
||||
this.parent(titleActor, pageActor, label, a11yIcon);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
function SearchTab() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
SearchTab.prototype = {
|
||||
__proto__: BaseTab.prototype,
|
||||
const SearchTab = new Lang.Class({
|
||||
Name: 'SearchTab',
|
||||
Extends: BaseTab,
|
||||
|
||||
_init: function() {
|
||||
this.active = false;
|
||||
@ -120,6 +113,7 @@ SearchTab.prototype = {
|
||||
hint_text: _("Type to search..."),
|
||||
track_hover: true,
|
||||
can_focus: true });
|
||||
ShellEntry.addContextMenu(this._entry);
|
||||
this._text = this._entry.clutter_text;
|
||||
this._text.connect('key-press-event', Lang.bind(this, this._onKeyPress));
|
||||
|
||||
@ -134,11 +128,7 @@ SearchTab.prototype = {
|
||||
this._iconClickedId = 0;
|
||||
|
||||
this._searchResults = new SearchDisplay.SearchResults(this._searchSystem, this._openSearchSystem);
|
||||
BaseTab.prototype._init.call(this,
|
||||
this._entry,
|
||||
this._searchResults.actor,
|
||||
_("Search"),
|
||||
'edit-find');
|
||||
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) {
|
||||
@ -164,7 +154,7 @@ SearchTab.prototype = {
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
BaseTab.prototype.hide.call(this);
|
||||
this.parent();
|
||||
|
||||
// Leave the entry focused when it doesn't have any text;
|
||||
// when replacing a selected search term, Clutter emits
|
||||
@ -289,9 +279,11 @@ SearchTab.prototype = {
|
||||
_onCapturedEvent: function(actor, event) {
|
||||
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
|
||||
let source = event.get_source();
|
||||
if (source != this._text && this._text.text == '') {
|
||||
if (source != this._text && this._text.text == '' &&
|
||||
!Main.layoutManager.keyboardBox.contains(source)) {
|
||||
// the user clicked outside after activating the entry, but
|
||||
// with no search term entered - cancel the search
|
||||
// with no search term entered and no keyboard button pressed
|
||||
// - cancel the search
|
||||
this._reset();
|
||||
}
|
||||
}
|
||||
@ -306,14 +298,12 @@ SearchTab.prototype = {
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
function ViewSelector() {
|
||||
this._init();
|
||||
}
|
||||
const ViewSelector = new Lang.Class({
|
||||
Name: 'ViewSelector',
|
||||
|
||||
ViewSelector.prototype = {
|
||||
_init : function() {
|
||||
this.actor = new St.BoxLayout({ name: 'viewSelector',
|
||||
vertical: true });
|
||||
@ -573,5 +563,5 @@ ViewSelector.prototype = {
|
||||
removeSearchProvider: function(provider) {
|
||||
this._searchTab.removeSearchProvider(provider);
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(ViewSelector.prototype);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
@ -6,41 +6,14 @@ const Shell = imports.gi.Shell;
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
|
||||
function WindowAttentionHandler() {
|
||||
this._init();
|
||||
}
|
||||
const WindowAttentionHandler = new Lang.Class({
|
||||
Name: 'WindowAttentionHandler',
|
||||
|
||||
WindowAttentionHandler.prototype = {
|
||||
_init : function() {
|
||||
this._startupIds = {};
|
||||
this._tracker = Shell.WindowTracker.get_default();
|
||||
this._tracker.connect('startup-sequence-changed', Lang.bind(this, this._onStartupSequenceChanged));
|
||||
|
||||
global.display.connect('window-demands-attention', Lang.bind(this, this._onWindowDemandsAttention));
|
||||
},
|
||||
|
||||
_onStartupSequenceChanged : function(tracker) {
|
||||
let sequences = tracker.get_startup_sequences();
|
||||
this._startupIds = {};
|
||||
for(let i = 0; i < sequences.length; i++) {
|
||||
this._startupIds[sequences[i].get_id()] = true;
|
||||
}
|
||||
},
|
||||
|
||||
_getTitle : function(app, window) {
|
||||
if (this._startupIds[window.get_startup_id()])
|
||||
return app.get_name();
|
||||
else
|
||||
return window.title;
|
||||
},
|
||||
|
||||
_getBanner : function(app, window) {
|
||||
if (this._startupIds[window.get_startup_id()])
|
||||
return _("%s has finished starting").format(app.get_name());
|
||||
else
|
||||
return _("'%s' is ready").format(window.title);
|
||||
},
|
||||
|
||||
_onWindowDemandsAttention : function(display, window) {
|
||||
// We don't want to show the notification when the window is already focused,
|
||||
// because this is rather pointless.
|
||||
@ -57,24 +30,25 @@ WindowAttentionHandler.prototype = {
|
||||
let source = new Source(app, window);
|
||||
Main.messageTray.add(source);
|
||||
|
||||
let notification = new MessageTray.Notification(source, this._getTitle(app, window), this._getBanner(app, window));
|
||||
let banner = _("'%s' is ready").format(window.title);
|
||||
let title = app.get_name();
|
||||
|
||||
let notification = new MessageTray.Notification(source, title, banner);
|
||||
source.notify(notification);
|
||||
|
||||
source.signalIDs.push(window.connect('notify::title', Lang.bind(this, function(win) {
|
||||
notification.update(this._getTitle(app, win), this._getBanner(app, win));
|
||||
})));
|
||||
source.signalIDs.push(window.connect('notify::title',
|
||||
Lang.bind(this, function() {
|
||||
notification.update(title, banner);
|
||||
})));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function Source(app, window) {
|
||||
this._init(app, window);
|
||||
}
|
||||
|
||||
Source.prototype = {
|
||||
__proto__ : MessageTray.Source.prototype,
|
||||
const Source = new Lang.Class({
|
||||
Name: 'WindowAttentionSource',
|
||||
Extends: MessageTray.Source,
|
||||
|
||||
_init: function(app, window) {
|
||||
MessageTray.Source.prototype._init.call(this, app.get_name());
|
||||
this.parent(app.get_name());
|
||||
this._window = window;
|
||||
this._app = app;
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
@ -102,4 +76,4 @@ Source.prototype = {
|
||||
Main.activateWindow(this._window);
|
||||
this.destroy();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
@ -19,47 +19,53 @@ const UNDIM_TIME = 0.250;
|
||||
|
||||
var dimShader = undefined;
|
||||
|
||||
function getDimShader() {
|
||||
if (dimShader === null)
|
||||
return null;
|
||||
if (!dimShader) {
|
||||
let source = Shell.get_file_contents_utf8_sync(global.datadir + '/shaders/dim-window.glsl');
|
||||
try {
|
||||
let shader = new Clutter.Shader();
|
||||
shader.set_fragment_source(source, -1);
|
||||
shader.compile();
|
||||
|
||||
dimShader = shader;
|
||||
} catch (e) {
|
||||
log(e.message);
|
||||
dimShader = null;
|
||||
}
|
||||
}
|
||||
function getDimShaderSource() {
|
||||
if (!dimShader)
|
||||
dimShader = Shell.get_file_contents_utf8_sync(global.datadir + '/shaders/dim-window.glsl');
|
||||
return dimShader;
|
||||
}
|
||||
|
||||
function WindowDimmer(actor) {
|
||||
this._init(actor);
|
||||
function getTopInvisibleBorder(metaWindow) {
|
||||
let outerRect = metaWindow.get_outer_rect();
|
||||
let inputRect = metaWindow.get_input_rect();
|
||||
return outerRect.y - inputRect.y;
|
||||
}
|
||||
|
||||
WindowDimmer.prototype = {
|
||||
const WindowDimmer = new Lang.Class({
|
||||
Name: 'WindowDimmer',
|
||||
|
||||
_init: function(actor) {
|
||||
if (Clutter.feature_available(Clutter.FeatureFlags.SHADERS_GLSL)) {
|
||||
this._effect = new Clutter.ShaderEffect({ shader_type: Clutter.ShaderType.FRAGMENT_SHADER });
|
||||
this._effect.set_shader_source(getDimShaderSource());
|
||||
} else {
|
||||
this._effect = null;
|
||||
}
|
||||
|
||||
this.actor = actor;
|
||||
},
|
||||
|
||||
set dimFraction(fraction) {
|
||||
this._dimFraction = fraction;
|
||||
let shader = getDimShader();
|
||||
if (!Meta.prefs_get_attach_modal_dialogs() || !shader) {
|
||||
this.actor.set_shader(null);
|
||||
|
||||
if (this._effect == null)
|
||||
return;
|
||||
|
||||
if (!Meta.prefs_get_attach_modal_dialogs()) {
|
||||
this._effect.enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fraction > 0.01) {
|
||||
this.actor.set_shader(shader);
|
||||
this.actor.set_shader_param_float('height', this.actor.get_height());
|
||||
this.actor.set_shader_param_float('fraction', fraction);
|
||||
} else
|
||||
this.actor.set_shader(null);
|
||||
Shell.shader_effect_set_double_uniform(this._effect, 'height', this.actor.get_height());
|
||||
Shell.shader_effect_set_double_uniform(this._effect, 'fraction', fraction);
|
||||
|
||||
if (!this._effect.actor)
|
||||
this.actor.add_effect(this._effect);
|
||||
} else {
|
||||
if (this._effect.actor)
|
||||
this.actor.remove_effect(this._effect);
|
||||
}
|
||||
},
|
||||
|
||||
get dimFraction() {
|
||||
@ -67,24 +73,21 @@ WindowDimmer.prototype = {
|
||||
},
|
||||
|
||||
_dimFraction: 0.0
|
||||
};
|
||||
});
|
||||
|
||||
function getWindowDimmer(texture) {
|
||||
if (!texture._windowDimmer)
|
||||
texture._windowDimmer = new WindowDimmer(texture);
|
||||
function getWindowDimmer(actor) {
|
||||
if (!actor._windowDimmer)
|
||||
actor._windowDimmer = new WindowDimmer(actor);
|
||||
|
||||
return texture._windowDimmer;
|
||||
return actor._windowDimmer;
|
||||
}
|
||||
|
||||
function WindowManager() {
|
||||
this._init();
|
||||
}
|
||||
const WindowManager = new Lang.Class({
|
||||
Name: 'WindowManager',
|
||||
|
||||
WindowManager.prototype = {
|
||||
_init : function() {
|
||||
this._shellwm = global.window_manager;
|
||||
|
||||
this._keyBindingHandlers = [];
|
||||
this._minimizing = [];
|
||||
this._maximizing = [];
|
||||
this._unmaximizing = [];
|
||||
@ -113,15 +116,24 @@ WindowManager.prototype = {
|
||||
this._shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
|
||||
|
||||
this._workspaceSwitcherPopup = null;
|
||||
this.setKeybindingHandler('switch_to_workspace_left', Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
this.setKeybindingHandler('switch_to_workspace_right', Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
this.setKeybindingHandler('switch_to_workspace_up', Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
this.setKeybindingHandler('switch_to_workspace_down', Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
this.setKeybindingHandler('switch_windows', Lang.bind(this, this._startAppSwitcher));
|
||||
this.setKeybindingHandler('switch_group', Lang.bind(this, this._startAppSwitcher));
|
||||
this.setKeybindingHandler('switch_windows_backward', Lang.bind(this, this._startAppSwitcher));
|
||||
this.setKeybindingHandler('switch_group_backward', Lang.bind(this, this._startAppSwitcher));
|
||||
this.setKeybindingHandler('switch_panels', Lang.bind(this, this._startA11ySwitcher));
|
||||
Meta.keybindings_set_custom_handler('switch-to-workspace-left',
|
||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
Meta.keybindings_set_custom_handler('switch-to-workspace-right',
|
||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
Meta.keybindings_set_custom_handler('switch-to-workspace-up',
|
||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
Meta.keybindings_set_custom_handler('switch-to-workspace-down',
|
||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
Meta.keybindings_set_custom_handler('switch-windows',
|
||||
Lang.bind(this, this._startAppSwitcher));
|
||||
Meta.keybindings_set_custom_handler('switch-group',
|
||||
Lang.bind(this, this._startAppSwitcher));
|
||||
Meta.keybindings_set_custom_handler('switch-windows-backward',
|
||||
Lang.bind(this, this._startAppSwitcher));
|
||||
Meta.keybindings_set_custom_handler('switch-group-backward',
|
||||
Lang.bind(this, this._startAppSwitcher));
|
||||
Meta.keybindings_set_custom_handler('switch-panels',
|
||||
Lang.bind(this, this._startA11ySwitcher));
|
||||
|
||||
Main.overview.connect('showing', Lang.bind(this, function() {
|
||||
for (let i = 0; i < this._dimmedWindows.length; i++)
|
||||
@ -133,16 +145,6 @@ WindowManager.prototype = {
|
||||
}));
|
||||
},
|
||||
|
||||
setKeybindingHandler: function(keybinding, handler){
|
||||
if (this._keyBindingHandlers[keybinding])
|
||||
this._shellwm.disconnect(this._keyBindingHandlers[keybinding]);
|
||||
else
|
||||
this._shellwm.takeover_keybinding(keybinding);
|
||||
|
||||
this._keyBindingHandlers[keybinding] =
|
||||
this._shellwm.connect('keybinding::' + keybinding, handler);
|
||||
},
|
||||
|
||||
blockAnimations: function() {
|
||||
this._animationBlockCount++;
|
||||
},
|
||||
@ -152,7 +154,7 @@ WindowManager.prototype = {
|
||||
},
|
||||
|
||||
_shouldAnimate : function(actor) {
|
||||
if (Main.overview.visible || this._animationsBlocked > 0)
|
||||
if (Main.overview.visible || this._animationBlockCount > 0)
|
||||
return false;
|
||||
if (actor && (actor.meta_window.get_window_type() != Meta.WindowType.NORMAL))
|
||||
return false;
|
||||
@ -268,30 +270,28 @@ WindowManager.prototype = {
|
||||
let actor = window.get_compositor_private();
|
||||
if (!actor)
|
||||
return;
|
||||
let texture = actor.get_texture();
|
||||
if (animate)
|
||||
Tweener.addTween(getWindowDimmer(texture),
|
||||
Tweener.addTween(getWindowDimmer(actor),
|
||||
{ dimFraction: 1.0,
|
||||
time: DIM_TIME,
|
||||
transition: 'linear'
|
||||
});
|
||||
else
|
||||
getWindowDimmer(texture).dimFraction = 1.0;
|
||||
getWindowDimmer(actor).dimFraction = 1.0;
|
||||
},
|
||||
|
||||
_undimWindow: function(window, animate) {
|
||||
let actor = window.get_compositor_private();
|
||||
if (!actor)
|
||||
return;
|
||||
let texture = actor.get_texture();
|
||||
if (animate)
|
||||
Tweener.addTween(getWindowDimmer(texture),
|
||||
Tweener.addTween(getWindowDimmer(actor),
|
||||
{ dimFraction: 0.0,
|
||||
time: UNDIM_TIME,
|
||||
transition: 'linear'
|
||||
});
|
||||
else
|
||||
getWindowDimmer(texture).dimFraction = 0.0;
|
||||
getWindowDimmer(actor).dimFraction = 0.0;
|
||||
},
|
||||
|
||||
_mapWindow : function(shellwm, actor) {
|
||||
@ -528,37 +528,41 @@ WindowManager.prototype = {
|
||||
shellwm.completed_switch_workspace();
|
||||
},
|
||||
|
||||
_startAppSwitcher : function(shellwm, binding, window, backwards) {
|
||||
_startAppSwitcher : function(display, screen, window, binding) {
|
||||
/* prevent a corner case where both popups show up at once */
|
||||
if (this._workspaceSwitcherPopup != null)
|
||||
this._workspaceSwitcherPopup.actor.hide();
|
||||
|
||||
let tabPopup = new AltTab.AltTabPopup();
|
||||
|
||||
if (!tabPopup.show(backwards, binding))
|
||||
let modifiers = binding.get_modifiers();
|
||||
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
|
||||
if (!tabPopup.show(backwards, binding.get_name(), binding.get_mask()))
|
||||
tabPopup.destroy();
|
||||
},
|
||||
|
||||
_startA11ySwitcher : function(shellwm, binding, window, backwards) {
|
||||
Main.ctrlAltTabManager.popup(backwards);
|
||||
_startA11ySwitcher : function(display, screen, window, binding) {
|
||||
let modifiers = binding.get_modifiers();
|
||||
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
|
||||
Main.ctrlAltTabManager.popup(backwards, binding.get_mask());
|
||||
},
|
||||
|
||||
_showWorkspaceSwitcher : function(shellwm, binding, window, backwards) {
|
||||
if (global.screen.n_workspaces == 1)
|
||||
_showWorkspaceSwitcher : function(display, screen, window, binding) {
|
||||
if (screen.n_workspaces == 1)
|
||||
return;
|
||||
|
||||
if (this._workspaceSwitcherPopup == null)
|
||||
this._workspaceSwitcherPopup = new WorkspaceSwitcherPopup.WorkspaceSwitcherPopup();
|
||||
|
||||
if (binding == 'switch_to_workspace_up')
|
||||
if (binding.get_name() == 'switch-to-workspace-up')
|
||||
this.actionMoveWorkspaceUp();
|
||||
else if (binding == 'switch_to_workspace_down')
|
||||
else if (binding.get_name() == 'switch-to-workspace-down')
|
||||
this.actionMoveWorkspaceDown();
|
||||
// left/right would effectively act as synonyms for up/down if we enabled them;
|
||||
// but that could be considered confusing.
|
||||
// else if (binding == 'switch_to_workspace_left')
|
||||
// else if (binding.get_name() == 'switch-to-workspace-left')
|
||||
// this.actionMoveWorkspaceLeft();
|
||||
// else if (binding == 'switch_to_workspace_right')
|
||||
// else if (binding.get_name() == 'switch-to-workspace-right')
|
||||
// this.actionMoveWorkspaceRight();
|
||||
},
|
||||
|
||||
@ -619,4 +623,4 @@ WindowManager.prototype = {
|
||||
if (!Main.overview.visible)
|
||||
this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.DOWN, indexToActivate);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GConf = imports.gi.GConf;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
@ -28,7 +28,8 @@ const CLOSE_BUTTON_FADE_TIME = 0.1;
|
||||
|
||||
const DRAGGING_WINDOW_OPACITY = 100;
|
||||
|
||||
const BUTTON_LAYOUT_KEY = '/desktop/gnome/shell/windows/button_layout';
|
||||
const BUTTON_LAYOUT_SCHEMA = 'org.gnome.shell.overrides';
|
||||
const BUTTON_LAYOUT_KEY = 'button-layout';
|
||||
|
||||
// Define a layout scheme for small window counts. For larger
|
||||
// counts we fall back to an algorithm. We need more schemes here
|
||||
@ -55,11 +56,13 @@ function _clamp(value, min, max) {
|
||||
}
|
||||
|
||||
|
||||
function ScaledPoint(x, y, scaleX, scaleY) {
|
||||
[this.x, this.y, this.scaleX, this.scaleY] = arguments;
|
||||
}
|
||||
const ScaledPoint = new Lang.Class({
|
||||
Name: 'ScaledPoint',
|
||||
|
||||
_init: function(x, y, scaleX, scaleY) {
|
||||
[this.x, this.y, this.scaleX, this.scaleY] = arguments;
|
||||
},
|
||||
|
||||
ScaledPoint.prototype = {
|
||||
getPosition : function() {
|
||||
return [this.x, this.y];
|
||||
},
|
||||
@ -85,14 +88,12 @@ ScaledPoint.prototype = {
|
||||
return [_interpolate(this.scaleX, other.scaleX, step),
|
||||
_interpolate(this.scaleY, other.scaleY, step)];
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
function WindowClone(realWindow) {
|
||||
this._init(realWindow);
|
||||
}
|
||||
const WindowClone = new Lang.Class({
|
||||
Name: 'WindowClone',
|
||||
|
||||
WindowClone.prototype = {
|
||||
_init : function(realWindow) {
|
||||
this.realWindow = realWindow;
|
||||
this.metaWindow = realWindow.meta_window;
|
||||
@ -102,6 +103,12 @@ WindowClone.prototype = {
|
||||
this._windowClone = new Clutter.Clone({ source: realWindow.get_texture(),
|
||||
x: -borderX,
|
||||
y: -borderY });
|
||||
// We expect this.actor to be used for all interaction rather than
|
||||
// this._windowClone; as the former is reactive and the latter
|
||||
// is not, this just works for most cases. However, for DND all
|
||||
// actors are picked, so DND operations would operate on the clone.
|
||||
// To avoid this, we hide it from pick.
|
||||
Shell.util_set_hidden_from_pick(this._windowClone, true);
|
||||
|
||||
this.origX = realWindow.x + borderX;
|
||||
this.origY = realWindow.y + borderY;
|
||||
@ -129,8 +136,11 @@ WindowClone.prototype = {
|
||||
this._realWindowDestroyId = this.realWindow.connect('destroy',
|
||||
Lang.bind(this, this._disconnectRealWindowSignals));
|
||||
|
||||
this.actor.connect('button-release-event',
|
||||
Lang.bind(this, this._onButtonRelease));
|
||||
let clickAction = new Clutter.ClickAction();
|
||||
clickAction.connect('clicked', Lang.bind(this, this._onClicked));
|
||||
clickAction.connect('long-press', Lang.bind(this, this._onLongPress));
|
||||
|
||||
this.actor.add_action(clickAction);
|
||||
|
||||
this.actor.connect('scroll-event',
|
||||
Lang.bind(this, this._onScroll));
|
||||
@ -141,6 +151,7 @@ WindowClone.prototype = {
|
||||
|
||||
this._draggable = DND.makeDraggable(this.actor,
|
||||
{ restoreOnSuccess: true,
|
||||
manualMode: true,
|
||||
dragActorMaxSize: WINDOW_DND_SIZE,
|
||||
dragActorOpacity: DRAGGING_WINDOW_OPACITY });
|
||||
this._draggable.connect('drag-begin', Lang.bind(this, this._onDragBegin));
|
||||
@ -339,9 +350,27 @@ WindowClone.prototype = {
|
||||
this._zoomStep = undefined;
|
||||
},
|
||||
|
||||
_onButtonRelease : function (actor, event) {
|
||||
_onClicked: function(action, actor) {
|
||||
this._selected = true;
|
||||
this.emit('selected', event.get_time());
|
||||
this.emit('selected', global.get_current_time());
|
||||
},
|
||||
|
||||
_onLongPress: function(action, actor, state) {
|
||||
// Take advantage of the Clutter policy to consider
|
||||
// a long-press canceled when the pointer movement
|
||||
// exceeds dnd-drag-threshold to manually start the drag
|
||||
if (state == Clutter.LongPressState.CANCEL) {
|
||||
// A click cancels a long-press before any click handler is
|
||||
// run - make sure to not start a drag in that case
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
|
||||
function() {
|
||||
if (this._selected)
|
||||
return;
|
||||
let [x, y] = action.get_coords();
|
||||
this._draggable.startDrag(x, y, global.get_current_time());
|
||||
}));
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
_onDragBegin : function (draggable, time) {
|
||||
@ -389,7 +418,7 @@ WindowClone.prototype = {
|
||||
|
||||
this.emit('drag-end');
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(WindowClone.prototype);
|
||||
|
||||
|
||||
@ -398,11 +427,9 @@ Signals.addSignalMethods(WindowClone.prototype);
|
||||
* @parentActor: The actor which will be the parent of all overlay items
|
||||
* such as app icon and window caption
|
||||
*/
|
||||
function WindowOverlay(windowClone, parentActor) {
|
||||
this._init(windowClone, parentActor);
|
||||
}
|
||||
const WindowOverlay = new Lang.Class({
|
||||
Name: 'WindowOverlay',
|
||||
|
||||
WindowOverlay.prototype = {
|
||||
_init : function(windowClone, parentActor) {
|
||||
let metaWindow = windowClone.metaWindow;
|
||||
|
||||
@ -499,8 +526,8 @@ WindowOverlay.prototype = {
|
||||
let button = this.closeButton;
|
||||
let title = this.title;
|
||||
|
||||
let gconf = GConf.Client.get_default();
|
||||
let layout = gconf.get_string(BUTTON_LAYOUT_KEY);
|
||||
let settings = new Gio.Settings({ schema: BUTTON_LAYOUT_SCHEMA });
|
||||
let layout = settings.get_string(BUTTON_LAYOUT_KEY);
|
||||
let rtl = St.Widget.get_default_direction() == St.TextDirection.RTL;
|
||||
|
||||
let split = layout.split(":");
|
||||
@ -613,7 +640,7 @@ WindowOverlay.prototype = {
|
||||
|
||||
this._parentActor.queue_relayout();
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(WindowOverlay.prototype);
|
||||
|
||||
const WindowPositionFlags = {
|
||||
@ -624,11 +651,9 @@ const WindowPositionFlags = {
|
||||
/**
|
||||
* @metaWorkspace: a #Meta.Workspace, or null
|
||||
*/
|
||||
function Workspace(metaWorkspace, monitorIndex) {
|
||||
this._init(metaWorkspace, monitorIndex);
|
||||
}
|
||||
const Workspace = new Lang.Class({
|
||||
Name: 'Workspace',
|
||||
|
||||
Workspace.prototype = {
|
||||
_init : function(metaWorkspace, monitorIndex) {
|
||||
// When dragging a window, we use this slot for reserve space.
|
||||
this._reservedSlot = null;
|
||||
@ -1489,6 +1514,6 @@ Workspace.prototype = {
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Signals.addSignalMethods(Workspace.prototype);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
@ -15,11 +15,9 @@ const DISPLAY_TIMEOUT = 600;
|
||||
const UP = -1;
|
||||
const DOWN = 1;
|
||||
|
||||
function WorkspaceSwitcherPopup() {
|
||||
this._init();
|
||||
}
|
||||
const WorkspaceSwitcherPopup = new Lang.Class({
|
||||
Name: 'WorkspaceSwitcherPopup',
|
||||
|
||||
WorkspaceSwitcherPopup.prototype = {
|
||||
_init : function() {
|
||||
this.actor = new St.Group({ reactive: true,
|
||||
x: 0,
|
||||
@ -158,4 +156,4 @@ WorkspaceSwitcherPopup.prototype = {
|
||||
onCompleteScope: this
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
@ -20,11 +20,14 @@ let MAX_THUMBNAIL_SCALE = 1/8.;
|
||||
const RESCALE_ANIMATION_TIME = 0.2;
|
||||
const SLIDE_ANIMATION_TIME = 0.2;
|
||||
|
||||
function WindowClone(realWindow) {
|
||||
this._init(realWindow);
|
||||
}
|
||||
// When we create workspaces by dragging, we add a "cut" into the top and
|
||||
// bottom of each workspace so that the user doesn't have to hit the
|
||||
// placeholder exactly.
|
||||
const WORKSPACE_CUT_SIZE = 10;
|
||||
|
||||
const WindowClone = new Lang.Class({
|
||||
Name: 'WindowClone',
|
||||
|
||||
WindowClone.prototype = {
|
||||
_init : function(realWindow) {
|
||||
this.actor = new Clutter.Clone({ source: realWindow.get_texture(),
|
||||
reactive: true });
|
||||
@ -121,7 +124,7 @@ WindowClone.prototype = {
|
||||
|
||||
this.emit('drag-end');
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(WindowClone.prototype);
|
||||
|
||||
|
||||
@ -139,11 +142,9 @@ const ThumbnailState = {
|
||||
/**
|
||||
* @metaWorkspace: a #Meta.Workspace
|
||||
*/
|
||||
function WorkspaceThumbnail(metaWorkspace) {
|
||||
this._init(metaWorkspace);
|
||||
}
|
||||
const WorkspaceThumbnail = new Lang.Class({
|
||||
Name: 'WorkspaceThumbnail',
|
||||
|
||||
WorkspaceThumbnail.prototype = {
|
||||
_init : function(metaWorkspace) {
|
||||
this.metaWorkspace = metaWorkspace;
|
||||
this.monitorIndex = Main.layoutManager.primaryIndex;
|
||||
@ -422,6 +423,11 @@ WorkspaceThumbnail.prototype = {
|
||||
if (this.state > ThumbnailState.NORMAL)
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
|
||||
let [w, h] = this.actor.get_transformed_size();
|
||||
// Bubble up if we're in the "workspace cut".
|
||||
if (y < WORKSPACE_CUT_SIZE || y > h - WORKSPACE_CUT_SIZE)
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
|
||||
if (source.realWindow && !this._isMyWindow(source.realWindow))
|
||||
return DND.DragMotionResult.MOVE_DROP;
|
||||
if (source.shellWorkspaceLaunch)
|
||||
@ -459,22 +465,21 @@ WorkspaceThumbnail.prototype = {
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Signals.addSignalMethods(WorkspaceThumbnail.prototype);
|
||||
|
||||
|
||||
function ThumbnailsBox() {
|
||||
this._init();
|
||||
}
|
||||
const ThumbnailsBox = new Lang.Class({
|
||||
Name: 'ThumbnailsBox',
|
||||
|
||||
ThumbnailsBox.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new Shell.GenericContainer({ style_class: 'workspace-thumbnails',
|
||||
request_mode: Clutter.RequestMode.WIDTH_FOR_HEIGHT });
|
||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||
this.actor._delegate = this;
|
||||
|
||||
// When we animate the scale, we don't animate the requested size of the thumbnails, rather
|
||||
// we ask for our final size and then animate within that size. This slightly simplifies the
|
||||
@ -498,6 +503,10 @@ ThumbnailsBox.prototype = {
|
||||
this._indicator = indicator;
|
||||
this.actor.add_actor(indicator);
|
||||
|
||||
this._dropPlaceholderPos = -1;
|
||||
this._dropPlaceholder = new St.Bin({ style_class: 'placeholder' });
|
||||
this.actor.add_actor(this._dropPlaceholder);
|
||||
|
||||
this._targetScale = 0;
|
||||
this._scale = 0;
|
||||
this._pendingScaleUpdate = false;
|
||||
@ -512,6 +521,83 @@ ThumbnailsBox.prototype = {
|
||||
this._thumbnails = [];
|
||||
},
|
||||
|
||||
// Draggable target interface
|
||||
handleDragOver : function(source, actor, x, y, time) {
|
||||
if (!source.realWindow && !source.shellWorkspaceLaunch)
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
|
||||
let spacing = this.actor.get_theme_node().get_length('spacing');
|
||||
let thumbHeight = this._porthole.height * this._scale;
|
||||
|
||||
let workspace = -1;
|
||||
let firstThumbY = this._thumbnails[0].actor.y;
|
||||
for (let i = 0; i < this._thumbnails.length; i ++) {
|
||||
let targetBase = firstThumbY + (thumbHeight + spacing) * i;
|
||||
|
||||
// Allow the reorder target to have a 10px "cut" into
|
||||
// each side of the thumbnail, to make dragging onto the
|
||||
// placeholder easier
|
||||
let targetTop = targetBase - spacing - WORKSPACE_CUT_SIZE;
|
||||
let targetBottom = targetBase + WORKSPACE_CUT_SIZE;
|
||||
|
||||
// Expand the target to include the placeholder, if it exists.
|
||||
if (i == this._dropPlaceholderPos)
|
||||
targetBottom += this._dropPlaceholder.get_height();
|
||||
|
||||
if (y > targetTop && y <= targetBottom) {
|
||||
workspace = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this._dropPlaceholderPos = workspace;
|
||||
this.actor.queue_relayout();
|
||||
|
||||
if (workspace == -1)
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
|
||||
return DND.DragMotionResult.MOVE_DROP;
|
||||
},
|
||||
|
||||
acceptDrop: function(source, actor, x, y, time) {
|
||||
if (this._dropPlaceholderPos == -1)
|
||||
return false;
|
||||
|
||||
if (!source.realWindow && !source.shellWorkspaceLaunch)
|
||||
return false;
|
||||
|
||||
let isWindow = !!source.realWindow;
|
||||
|
||||
// To create a new workspace, we first slide all the windows on workspaces
|
||||
// below us to the next workspace, leaving a blank workspace for us to recycle.
|
||||
let newWorkspaceIndex;
|
||||
[newWorkspaceIndex, this._dropPlaceholderPos] = [this._dropPlaceholderPos, -1];
|
||||
|
||||
// Nab all the windows below us.
|
||||
let windows = global.get_window_actors().filter(function(win) {
|
||||
if (isWindow)
|
||||
return win.get_workspace() >= newWorkspaceIndex && win != source;
|
||||
else
|
||||
return win.get_workspace() >= newWorkspaceIndex;
|
||||
});
|
||||
|
||||
// ... move them down one.
|
||||
windows.forEach(function(win) {
|
||||
win.meta_window.change_workspace_by_index(win.get_workspace() + 1,
|
||||
true, time);
|
||||
});
|
||||
|
||||
if (isWindow)
|
||||
// ... and bam, a workspace, good as new.
|
||||
source.metaWindow.change_workspace_by_index(newWorkspaceIndex,
|
||||
true, time);
|
||||
else if (source.shellWorkspaceLaunch)
|
||||
source.shellWorkspaceLaunch({ workspace: newWorkspaceIndex,
|
||||
timestamp: time });
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
show: function() {
|
||||
this._switchWorkspaceNotifyId =
|
||||
global.window_manager.connect('switch-workspace',
|
||||
@ -840,20 +926,18 @@ ThumbnailsBox.prototype = {
|
||||
|
||||
let y = contentBox.y1;
|
||||
|
||||
if (this._dropPlaceholderPos == -1) {
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
||||
this._dropPlaceholder.hide();
|
||||
}));
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._thumbnails.length; i++) {
|
||||
let thumbnail = this._thumbnails[i];
|
||||
|
||||
if (i > 0)
|
||||
y += spacing - Math.round(thumbnail.collapseFraction * spacing);
|
||||
|
||||
// We might end up with thumbnailHeight being something like 99.33
|
||||
// pixels. To make this work and not end up with a gap at the bottom,
|
||||
// we need some thumbnails to be 99 pixels and some 100 pixels height;
|
||||
// we compute an actual scale separately for each thumbnail.
|
||||
let y1 = Math.round(y);
|
||||
let y2 = Math.round(y + thumbnailHeight);
|
||||
let roundedVScale = (y2 - y1) / portholeHeight;
|
||||
|
||||
let x1, x2;
|
||||
if (rtl) {
|
||||
x1 = contentBox.x1 + slideOffset * thumbnail.slidePosition;
|
||||
@ -863,6 +947,27 @@ ThumbnailsBox.prototype = {
|
||||
x2 = x1 + thumbnailWidth;
|
||||
}
|
||||
|
||||
if (i == this._dropPlaceholderPos) {
|
||||
let [minHeight, placeholderHeight] = this._dropPlaceholder.get_preferred_height(-1);
|
||||
childBox.x1 = x1;
|
||||
childBox.x2 = x1 + thumbnailWidth;
|
||||
childBox.y1 = Math.round(y);
|
||||
childBox.y2 = Math.round(y + placeholderHeight);
|
||||
this._dropPlaceholder.allocate(childBox, flags);
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
||||
this._dropPlaceholder.show();
|
||||
}));
|
||||
y += placeholderHeight + spacing;
|
||||
}
|
||||
|
||||
// We might end up with thumbnailHeight being something like 99.33
|
||||
// pixels. To make this work and not end up with a gap at the bottom,
|
||||
// we need some thumbnails to be 99 pixels and some 100 pixels height;
|
||||
// we compute an actual scale separately for each thumbnail.
|
||||
let y1 = Math.round(y);
|
||||
let y2 = Math.round(y + thumbnailHeight);
|
||||
let roundedVScale = (y2 - y1) / portholeHeight;
|
||||
|
||||
if (thumbnail.metaWorkspace == indicatorWorkspace)
|
||||
indicatorY = y1;
|
||||
|
||||
@ -917,4 +1022,4 @@ ThumbnailsBox.prototype = {
|
||||
onCompleteScope: this
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
@ -23,11 +23,9 @@ const MAX_WORKSPACES = 16;
|
||||
const CONTROLS_POP_IN_TIME = 0.1;
|
||||
|
||||
|
||||
function WorkspacesView(workspaces) {
|
||||
this._init(workspaces);
|
||||
}
|
||||
const WorkspacesView = new Lang.Class({
|
||||
Name: 'WorkspacesView',
|
||||
|
||||
WorkspacesView.prototype = {
|
||||
_init: function(workspaces) {
|
||||
this.actor = new St.Group({ style_class: 'workspaces-view' });
|
||||
|
||||
@ -109,8 +107,6 @@ WorkspacesView.prototype = {
|
||||
this._scrollAdjustment.connect('notify::value',
|
||||
Lang.bind(this, this._onScroll));
|
||||
|
||||
this._timeoutId = 0;
|
||||
|
||||
this._switchWorkspaceNotifyId =
|
||||
global.window_manager.connect('switch-workspace',
|
||||
Lang.bind(this, this._activeWorkspaceChanged));
|
||||
@ -321,10 +317,6 @@ WorkspacesView.prototype = {
|
||||
if (this._inDrag)
|
||||
this._dragEnd();
|
||||
|
||||
if (this._timeoutId) {
|
||||
Mainloop.source_remove(this._timeoutId);
|
||||
this._timeoutId = 0;
|
||||
}
|
||||
if (this._itemDragBeginId > 0) {
|
||||
Main.overview.disconnect(this._itemDragBeginId);
|
||||
this._itemDragBeginId = 0;
|
||||
@ -383,72 +375,10 @@ WorkspacesView.prototype = {
|
||||
this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
||||
}
|
||||
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||
let topWorkspace, bottomWorkspace;
|
||||
topWorkspace = this._workspaces[activeWorkspaceIndex - 1];
|
||||
bottomWorkspace = this._workspaces[activeWorkspaceIndex + 1];
|
||||
let hoverWorkspace = null;
|
||||
|
||||
// reactive monitor edges
|
||||
let topEdge = primary.y;
|
||||
let switchTop = (dragEvent.y <= topEdge && topWorkspace);
|
||||
if (switchTop && this._dragOverLastY != topEdge) {
|
||||
topWorkspace.metaWorkspace.activate(global.get_current_time());
|
||||
this._dragOverLastY = topEdge;
|
||||
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
}
|
||||
let bottomEdge = primary.y + primary.height - 1;
|
||||
let switchBottom = (dragEvent.y >= bottomEdge && bottomWorkspace);
|
||||
if (switchBottom && this._dragOverLastY != bottomEdge) {
|
||||
bottomWorkspace.metaWorkspace.activate(global.get_current_time());
|
||||
this._dragOverLastY = bottomEdge;
|
||||
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
}
|
||||
this._dragOverLastY = dragEvent.y;
|
||||
let result = DND.DragMotionResult.CONTINUE;
|
||||
|
||||
// check hover state of new workspace area / inactive workspaces
|
||||
if (topWorkspace) {
|
||||
if (topWorkspace.actor.contains(dragEvent.targetActor)) {
|
||||
hoverWorkspace = topWorkspace;
|
||||
result = topWorkspace.handleDragOver(dragEvent.source, dragEvent.dragActor);
|
||||
}
|
||||
}
|
||||
|
||||
if (bottomWorkspace) {
|
||||
if (bottomWorkspace.actor.contains(dragEvent.targetActor)) {
|
||||
hoverWorkspace = bottomWorkspace;
|
||||
result = bottomWorkspace.handleDragOver(dragEvent.source, dragEvent.dragActor);
|
||||
}
|
||||
}
|
||||
|
||||
// handle delayed workspace switches
|
||||
if (hoverWorkspace) {
|
||||
if (!this._timeoutId)
|
||||
this._timeoutId = Mainloop.timeout_add_seconds(1,
|
||||
Lang.bind(this, function() {
|
||||
hoverWorkspace.metaWorkspace.activate(global.get_current_time());
|
||||
return false;
|
||||
}));
|
||||
} else {
|
||||
if (this._timeoutId) {
|
||||
Mainloop.source_remove(this._timeoutId);
|
||||
this._timeoutId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
},
|
||||
|
||||
_dragEnd: function() {
|
||||
if (this._timeoutId) {
|
||||
Mainloop.source_remove(this._timeoutId);
|
||||
this._timeoutId = 0;
|
||||
}
|
||||
DND.removeDragMonitor(this._dragMonitor);
|
||||
this._inDrag = false;
|
||||
|
||||
@ -520,15 +450,13 @@ WorkspacesView.prototype = {
|
||||
_getWorkspaceIndexToRemove: function() {
|
||||
return global.screen.get_active_workspace_index();
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(WorkspacesView.prototype);
|
||||
|
||||
|
||||
function WorkspacesDisplay() {
|
||||
this._init();
|
||||
}
|
||||
const WorkspacesDisplay = new Lang.Class({
|
||||
Name: 'WorkspacesDisplay',
|
||||
|
||||
WorkspacesDisplay.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new Shell.GenericContainer();
|
||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
@ -920,5 +848,5 @@ WorkspacesDisplay.prototype = {
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
Signals.addSignalMethods(WorkspacesDisplay.prototype);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user