Compare commits
	
		
			542 Commits
		
	
	
		
			3.16.1
			...
			gnome-3-20
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					5e290d06dd | ||
| 
						 | 
					b08270a750 | ||
| 
						 | 
					783f9b1739 | ||
| 
						 | 
					7db0729ea1 | ||
| 
						 | 
					adcf275b86 | ||
| 
						 | 
					f49e28aedc | ||
| 
						 | 
					80b2e810ed | ||
| 
						 | 
					d5dc463a87 | ||
| 
						 | 
					15e727e174 | ||
| 
						 | 
					890a1f112b | ||
| 
						 | 
					a7ab0892e6 | ||
| 
						 | 
					1d9f48993e | ||
| 
						 | 
					b21e4d1dee | ||
| 
						 | 
					bea8def074 | ||
| 
						 | 
					0d862181f2 | ||
| 
						 | 
					8994d53355 | ||
| 
						 | 
					7327448f45 | ||
| 
						 | 
					8587fc7461 | ||
| 
						 | 
					7c44909da6 | ||
| 
						 | 
					6a93afa333 | ||
| 
						 | 
					71c26cc7ce | ||
| 
						 | 
					e0307bb7e0 | ||
| 
						 | 
					550715a071 | ||
| 
						 | 
					faa5c179e8 | ||
| 
						 | 
					90596b0964 | ||
| 
						 | 
					8954d99659 | ||
| 
						 | 
					a300a3d6aa | ||
| 
						 | 
					23788b9e7d | ||
| 
						 | 
					5d307c9ad5 | ||
| 
						 | 
					74553fa95e | ||
| 
						 | 
					bc4891c3a3 | ||
| 
						 | 
					35cc224240 | ||
| 
						 | 
					3bbf681385 | ||
| 
						 | 
					ae6256ba16 | ||
| 
						 | 
					3cf2e1ad8b | ||
| 
						 | 
					d756e2eefb | ||
| 
						 | 
					ea27ed8c55 | ||
| 
						 | 
					1883df2927 | ||
| 
						 | 
					3274f270e3 | ||
| 
						 | 
					c97626e516 | ||
| 
						 | 
					9c483dd9a6 | ||
| 
						 | 
					8fd6e93fbe | ||
| 
						 | 
					8416ba25de | ||
| 
						 | 
					63f6ff9151 | ||
| 
						 | 
					59c2ace98c | ||
| 
						 | 
					cf4465027a | ||
| 
						 | 
					a23b293fe2 | ||
| 
						 | 
					c039a3ddda | ||
| 
						 | 
					ebe071bd50 | ||
| 
						 | 
					2edfd458b7 | ||
| 
						 | 
					3b750aa815 | ||
| 
						 | 
					d96f97e55a | ||
| 
						 | 
					55ac2f46ba | ||
| 
						 | 
					262c04ab91 | ||
| 
						 | 
					c80e7784fb | ||
| 
						 | 
					763567377f | ||
| 
						 | 
					ea9dcbf8b7 | ||
| 
						 | 
					2b383bf73e | ||
| 
						 | 
					b8dcbfebb2 | ||
| 
						 | 
					a257aa35d5 | ||
| 
						 | 
					941513b280 | ||
| 
						 | 
					a9bb0558bc | ||
| 
						 | 
					58834b80d7 | ||
| 
						 | 
					b125a0e371 | ||
| 
						 | 
					980ac0da8a | ||
| 
						 | 
					f15fb0bd73 | ||
| 
						 | 
					7d25592165 | ||
| 
						 | 
					9ee36f2b71 | ||
| 
						 | 
					f3e226103f | ||
| 
						 | 
					a03e5662e2 | ||
| 
						 | 
					16bb3efeb9 | ||
| 
						 | 
					e01d867e69 | ||
| 
						 | 
					1d4dfd7d5f | ||
| 
						 | 
					da05d1d864 | ||
| 
						 | 
					6499424eba | ||
| 
						 | 
					824a602963 | ||
| 
						 | 
					0092d8fff3 | ||
| 
						 | 
					5fbe454836 | ||
| 
						 | 
					23a59d387b | ||
| 
						 | 
					6b2a68e553 | ||
| 
						 | 
					82950ecea0 | ||
| 
						 | 
					2da4df219c | ||
| 
						 | 
					8b5597fd8d | ||
| 
						 | 
					82ae06ad55 | ||
| 
						 | 
					c594b66a2a | ||
| 
						 | 
					13e3318e4d | ||
| 
						 | 
					4aa4bb4a6a | ||
| 
						 | 
					4a74df86e2 | ||
| 
						 | 
					30ebc9c241 | ||
| 
						 | 
					e0f6cf538d | ||
| 
						 | 
					ba71382c72 | ||
| 
						 | 
					87eb0d7e2f | ||
| 
						 | 
					da199242b2 | ||
| 
						 | 
					5e3d378667 | ||
| 
						 | 
					a6d2735373 | ||
| 
						 | 
					2ea435a928 | ||
| 
						 | 
					75ba75900c | ||
| 
						 | 
					7bacf4e344 | ||
| 
						 | 
					258993d8ad | ||
| 
						 | 
					ff19e411a2 | ||
| 
						 | 
					e86c2826ef | ||
| 
						 | 
					64741e41df | ||
| 
						 | 
					fceac27412 | ||
| 
						 | 
					0a394799da | ||
| 
						 | 
					b83f2c0e33 | ||
| 
						 | 
					225f825faf | ||
| 
						 | 
					ed054f4f40 | ||
| 
						 | 
					a1244a9b26 | ||
| 
						 | 
					3a3714f4ff | ||
| 
						 | 
					be483c4137 | ||
| 
						 | 
					3492121c3f | ||
| 
						 | 
					364f1453c1 | ||
| 
						 | 
					9392e50cf1 | ||
| 
						 | 
					f60a6ab465 | ||
| 
						 | 
					f3a92d558d | ||
| 
						 | 
					d387d4a60d | ||
| 
						 | 
					4503ca4ca0 | ||
| 
						 | 
					eeb10c0ce3 | ||
| 
						 | 
					c69fcc2ef8 | ||
| 
						 | 
					7d67d88ae8 | ||
| 
						 | 
					310622b14e | ||
| 
						 | 
					00065b84e1 | ||
| 
						 | 
					4f7a8902f8 | ||
| 
						 | 
					d20a6e0988 | ||
| 
						 | 
					96fa7b7e77 | ||
| 
						 | 
					61e4d40852 | ||
| 
						 | 
					cc826f77fb | ||
| 
						 | 
					1de288c5bb | ||
| 
						 | 
					fe986faa2d | ||
| 
						 | 
					f11b404622 | ||
| 
						 | 
					508668107b | ||
| 
						 | 
					674454621f | ||
| 
						 | 
					2c907bd422 | ||
| 
						 | 
					4eb6c0c4ee | ||
| 
						 | 
					dd2eff2b6f | ||
| 
						 | 
					d8960b396b | ||
| 
						 | 
					4c29604e1e | ||
| 
						 | 
					ede0bf2d88 | ||
| 
						 | 
					893bfdf85f | ||
| 
						 | 
					ac7a4c27fd | ||
| 
						 | 
					4fe0233139 | ||
| 
						 | 
					f9f9c7fe5b | ||
| 
						 | 
					f1b90f174a | ||
| 
						 | 
					3dd74c86c1 | ||
| 
						 | 
					0edbdc529e | ||
| 
						 | 
					b08523b170 | ||
| 
						 | 
					cd2f8d8177 | ||
| 
						 | 
					a1e8c79d38 | ||
| 
						 | 
					34fc454764 | ||
| 
						 | 
					e98a434ede | ||
| 
						 | 
					02cdc065e7 | ||
| 
						 | 
					77eb8f98c0 | ||
| 
						 | 
					68679e1e7e | ||
| 
						 | 
					05f2dbf205 | ||
| 
						 | 
					45779bc7be | ||
| 
						 | 
					1bf27b1f18 | ||
| 
						 | 
					3ecdfaffd2 | ||
| 
						 | 
					ee8fd1e613 | ||
| 
						 | 
					ccfd5e35d6 | ||
| 
						 | 
					b2eab65a81 | ||
| 
						 | 
					00814dd159 | ||
| 
						 | 
					57f9ffcaa7 | ||
| 
						 | 
					ce83f378a5 | ||
| 
						 | 
					30c7545ff3 | ||
| 
						 | 
					a13357c2a8 | ||
| 
						 | 
					75dc5c16c8 | ||
| 
						 | 
					acd5d70209 | ||
| 
						 | 
					669d20bcf0 | ||
| 
						 | 
					793a8005a5 | ||
| 
						 | 
					23b81fb241 | ||
| 
						 | 
					73ba9d33eb | ||
| 
						 | 
					75e2a7228c | ||
| 
						 | 
					91d70f2487 | ||
| 
						 | 
					779b1ae8e5 | ||
| 
						 | 
					346ffd14d7 | ||
| 
						 | 
					558b51f555 | ||
| 
						 | 
					ef18b7ea25 | ||
| 
						 | 
					0044e225aa | ||
| 
						 | 
					c25c143b24 | ||
| 
						 | 
					b87da87252 | ||
| 
						 | 
					f9258bb5e3 | ||
| 
						 | 
					3d747b00e6 | ||
| 
						 | 
					450345b4d0 | ||
| 
						 | 
					7563e1ebcd | ||
| 
						 | 
					f96cc4dd69 | ||
| 
						 | 
					c65a9c4d2e | ||
| 
						 | 
					c01bd37edc | ||
| 
						 | 
					021cecbce2 | ||
| 
						 | 
					2a0cb7ff05 | ||
| 
						 | 
					0085a94706 | ||
| 
						 | 
					5db38194dc | ||
| 
						 | 
					2a26143149 | ||
| 
						 | 
					62f22557aa | ||
| 
						 | 
					516ea5a02e | ||
| 
						 | 
					9154471aba | ||
| 
						 | 
					fbf6746acf | ||
| 
						 | 
					a36686a6aa | ||
| 
						 | 
					fd837d74d1 | ||
| 
						 | 
					fd57334395 | ||
| 
						 | 
					85100cb65f | ||
| 
						 | 
					c70f6278d6 | ||
| 
						 | 
					e573441bac | ||
| 
						 | 
					5ed9571b37 | ||
| 
						 | 
					9d203ddc0f | ||
| 
						 | 
					508a13ae72 | ||
| 
						 | 
					c0b50cbdf2 | ||
| 
						 | 
					06f78549bd | ||
| 
						 | 
					67afd7a6d8 | ||
| 
						 | 
					ffa8c2f2b1 | ||
| 
						 | 
					3803a880e8 | ||
| 
						 | 
					965aedb0bb | ||
| 
						 | 
					80911535a7 | ||
| 
						 | 
					ca401d5036 | ||
| 
						 | 
					a1c091d98d | ||
| 
						 | 
					e1e08f0a68 | ||
| 
						 | 
					1a4f629554 | ||
| 
						 | 
					4113be770b | ||
| 
						 | 
					cf3f4850b8 | ||
| 
						 | 
					14f374096a | ||
| 
						 | 
					6fef5c37f7 | ||
| 
						 | 
					6e7455aa1e | ||
| 
						 | 
					03bf6fa399 | ||
| 
						 | 
					f777e761c0 | ||
| 
						 | 
					31201d9618 | ||
| 
						 | 
					d95d78ac15 | ||
| 
						 | 
					bef4f17c49 | ||
| 
						 | 
					f4b7ab0cb6 | ||
| 
						 | 
					a180dde01c | ||
| 
						 | 
					385c918e2e | ||
| 
						 | 
					d7401c8646 | ||
| 
						 | 
					a456d5eb19 | ||
| 
						 | 
					6c08799c7b | ||
| 
						 | 
					8d7bb6496c | ||
| 
						 | 
					f0496a2d3c | ||
| 
						 | 
					6664553b7e | ||
| 
						 | 
					2a950ca3b3 | ||
| 
						 | 
					463cd6382c | ||
| 
						 | 
					78db025b10 | ||
| 
						 | 
					f3265c28a9 | ||
| 
						 | 
					a6e5e459d3 | ||
| 
						 | 
					9ba399bf18 | ||
| 
						 | 
					a52c91e9e5 | ||
| 
						 | 
					9a7b47c23f | ||
| 
						 | 
					18f7d20006 | ||
| 
						 | 
					3f0ee88657 | ||
| 
						 | 
					c634718dfa | ||
| 
						 | 
					df6b31de05 | ||
| 
						 | 
					b8e29ae8c7 | ||
| 
						 | 
					cdba8e5cea | ||
| 
						 | 
					4fccdaafb7 | ||
| 
						 | 
					df0b465e76 | ||
| 
						 | 
					aacdd4fd5e | ||
| 
						 | 
					5f68c3a324 | ||
| 
						 | 
					8ceae3b054 | ||
| 
						 | 
					3fc5afaff1 | ||
| 
						 | 
					8b7464c648 | ||
| 
						 | 
					3e602b1765 | ||
| 
						 | 
					5858028411 | ||
| 
						 | 
					2c682ace81 | ||
| 
						 | 
					45f3106814 | ||
| 
						 | 
					aa947f9948 | ||
| 
						 | 
					0c72d1fcbd | ||
| 
						 | 
					6d22670307 | ||
| 
						 | 
					0b9e68e305 | ||
| 
						 | 
					da8155cbe5 | ||
| 
						 | 
					5b7a052e18 | ||
| 
						 | 
					6f26e39082 | ||
| 
						 | 
					489b96a310 | ||
| 
						 | 
					e65d90d624 | ||
| 
						 | 
					9c74e22313 | ||
| 
						 | 
					48a1fce151 | ||
| 
						 | 
					83e7f6f496 | ||
| 
						 | 
					3c5c3a6597 | ||
| 
						 | 
					1c3ea1649f | ||
| 
						 | 
					48a54e8ac4 | ||
| 
						 | 
					113a854048 | ||
| 
						 | 
					882f5fa79e | ||
| 
						 | 
					9acdb8012c | ||
| 
						 | 
					731d64e0e4 | ||
| 
						 | 
					ccf1bd9f27 | ||
| 
						 | 
					c164a8fe03 | ||
| 
						 | 
					1a39666f7c | ||
| 
						 | 
					f2731d4d6a | ||
| 
						 | 
					3e63fb7abe | ||
| 
						 | 
					8b4249ef26 | ||
| 
						 | 
					bf0be6ef12 | ||
| 
						 | 
					294702d3f1 | ||
| 
						 | 
					58f3b7c748 | ||
| 
						 | 
					e25502aeb2 | ||
| 
						 | 
					ffe4eaf00d | ||
| 
						 | 
					2f88a7a1e1 | ||
| 
						 | 
					cd7d564125 | ||
| 
						 | 
					ede81017ec | ||
| 
						 | 
					a539e6236a | ||
| 
						 | 
					90b7710834 | ||
| 
						 | 
					f8cc8f1dc1 | ||
| 
						 | 
					f8e5e3e435 | ||
| 
						 | 
					508e751ffd | ||
| 
						 | 
					207c847762 | ||
| 
						 | 
					3c980566d3 | ||
| 
						 | 
					50b59e0ca6 | ||
| 
						 | 
					14c52bb00a | ||
| 
						 | 
					9720b32987 | ||
| 
						 | 
					674ae262c8 | ||
| 
						 | 
					db297e7fdb | ||
| 
						 | 
					d57c146514 | ||
| 
						 | 
					ec5a4328e3 | ||
| 
						 | 
					e4ee72c481 | ||
| 
						 | 
					31f1e9ff0a | ||
| 
						 | 
					d6c049a8c9 | ||
| 
						 | 
					44047ac881 | ||
| 
						 | 
					464d5d8a13 | ||
| 
						 | 
					29811a85dc | ||
| 
						 | 
					36ee4e6c3b | ||
| 
						 | 
					2036e4c85c | ||
| 
						 | 
					f24034de84 | ||
| 
						 | 
					522ff86081 | ||
| 
						 | 
					669e3c8ed9 | ||
| 
						 | 
					ce850f464c | ||
| 
						 | 
					03eaa61cef | ||
| 
						 | 
					e10e953d24 | ||
| 
						 | 
					2b47bb3d82 | ||
| 
						 | 
					73d819116c | ||
| 
						 | 
					c8dd984663 | ||
| 
						 | 
					6087eb6d0e | ||
| 
						 | 
					97b43d1d36 | ||
| 
						 | 
					57ebadbaf8 | ||
| 
						 | 
					cad7bb1151 | ||
| 
						 | 
					9a376d47c5 | ||
| 
						 | 
					b79adc05f4 | ||
| 
						 | 
					f765c5e319 | ||
| 
						 | 
					edc445c0c9 | ||
| 
						 | 
					ab6b0f3f7f | ||
| 
						 | 
					5e7902e733 | ||
| 
						 | 
					f9f821aa55 | ||
| 
						 | 
					9ed4b2a5ae | ||
| 
						 | 
					0130ced790 | ||
| 
						 | 
					8dab07af82 | ||
| 
						 | 
					f6cd3fa5ed | ||
| 
						 | 
					faae1a028e | ||
| 
						 | 
					f5e32184fe | ||
| 
						 | 
					18c7138237 | ||
| 
						 | 
					3f0fbae7e2 | ||
| 
						 | 
					7f1a258ff9 | ||
| 
						 | 
					35b38d5cb2 | ||
| 
						 | 
					09e8a437d4 | ||
| 
						 | 
					d2bedcc182 | ||
| 
						 | 
					84eda6e459 | ||
| 
						 | 
					f5e7530fc7 | ||
| 
						 | 
					f983b34784 | ||
| 
						 | 
					36bbe64898 | ||
| 
						 | 
					627a393ed6 | ||
| 
						 | 
					a025b151ef | ||
| 
						 | 
					18b6f13395 | ||
| 
						 | 
					051413550f | ||
| 
						 | 
					3e10574736 | ||
| 
						 | 
					9a3041004b | ||
| 
						 | 
					87f71b8ce1 | ||
| 
						 | 
					825146f1e3 | ||
| 
						 | 
					52995416fd | ||
| 
						 | 
					6c43d0247a | ||
| 
						 | 
					9aa98d9f0c | ||
| 
						 | 
					c3a29d6df1 | ||
| 
						 | 
					82f84416a9 | ||
| 
						 | 
					9dd3162dbe | ||
| 
						 | 
					7ef519756a | ||
| 
						 | 
					3bbe74d1c1 | ||
| 
						 | 
					409f6718b8 | ||
| 
						 | 
					9c0e179080 | ||
| 
						 | 
					b3b278d41f | ||
| 
						 | 
					0f466dbafb | ||
| 
						 | 
					fbb4a9a3a6 | ||
| 
						 | 
					8ddae5cd71 | ||
| 
						 | 
					b0915c7b60 | ||
| 
						 | 
					831bb4e334 | ||
| 
						 | 
					4e025506fa | ||
| 
						 | 
					abccf451bf | ||
| 
						 | 
					14954117c0 | ||
| 
						 | 
					629f408fe5 | ||
| 
						 | 
					86c6ab3c01 | ||
| 
						 | 
					4a6ff94701 | ||
| 
						 | 
					e480b08d58 | ||
| 
						 | 
					caf53861d1 | ||
| 
						 | 
					d0480648ba | ||
| 
						 | 
					eb8cfe799f | ||
| 
						 | 
					b9f2541880 | ||
| 
						 | 
					bde9b08bfe | ||
| 
						 | 
					8a4c862633 | ||
| 
						 | 
					785c90f4b8 | ||
| 
						 | 
					dd6a11e4c7 | ||
| 
						 | 
					64e9503adb | ||
| 
						 | 
					36c885bf34 | ||
| 
						 | 
					ad7cde805d | ||
| 
						 | 
					2c2c67f4dc | ||
| 
						 | 
					cc4f8dfab0 | ||
| 
						 | 
					0fb13608c5 | ||
| 
						 | 
					09dbe17da0 | ||
| 
						 | 
					fdd347c9aa | ||
| 
						 | 
					572095515b | ||
| 
						 | 
					f2d4aa0822 | ||
| 
						 | 
					030a22d795 | ||
| 
						 | 
					c70afcdb44 | ||
| 
						 | 
					526d6c03b8 | ||
| 
						 | 
					261b55300d | ||
| 
						 | 
					e13bfd9a17 | ||
| 
						 | 
					e096d18bac | ||
| 
						 | 
					9460f0e4f3 | ||
| 
						 | 
					e6591f52ac | ||
| 
						 | 
					07e3d1fd5c | ||
| 
						 | 
					1fbc6b24c8 | ||
| 
						 | 
					982777be94 | ||
| 
						 | 
					6610a34ad0 | ||
| 
						 | 
					bfa8a0441a | ||
| 
						 | 
					7723622ec7 | ||
| 
						 | 
					6bcc8c70ef | ||
| 
						 | 
					d114d5f95a | ||
| 
						 | 
					b5c734da42 | ||
| 
						 | 
					2077bb94c1 | ||
| 
						 | 
					65a4ee7fb4 | ||
| 
						 | 
					debf293298 | ||
| 
						 | 
					a0df3e7d1e | ||
| 
						 | 
					0d67c2d164 | ||
| 
						 | 
					682bd7b622 | ||
| 
						 | 
					fa0e54edbb | ||
| 
						 | 
					5a0b209663 | ||
| 
						 | 
					7e8859fd0e | ||
| 
						 | 
					444fa2e0ab | ||
| 
						 | 
					a31455b921 | ||
| 
						 | 
					ac0213a516 | ||
| 
						 | 
					45a6e2c305 | ||
| 
						 | 
					11cbd396c0 | ||
| 
						 | 
					a343445cd2 | ||
| 
						 | 
					be3d62487c | ||
| 
						 | 
					58905bd01a | ||
| 
						 | 
					08506eac2d | ||
| 
						 | 
					02c6b0374d | ||
| 
						 | 
					0722c06275 | ||
| 
						 | 
					17a4044d97 | ||
| 
						 | 
					27a7194634 | ||
| 
						 | 
					d73f560bcc | ||
| 
						 | 
					e92f43b83e | ||
| 
						 | 
					fed79ce4e6 | ||
| 
						 | 
					fc45cf03bf | ||
| 
						 | 
					efde11a0f3 | ||
| 
						 | 
					fb951ff9b5 | ||
| 
						 | 
					f5865e895e | ||
| 
						 | 
					b8c2d4c6c7 | ||
| 
						 | 
					778ad49ab4 | ||
| 
						 | 
					fe7dd1305f | ||
| 
						 | 
					378a3df5ea | ||
| 
						 | 
					e63b81d69c | ||
| 
						 | 
					c2fa2cdd8a | ||
| 
						 | 
					6f215427f8 | ||
| 
						 | 
					67ed4e0570 | ||
| 
						 | 
					8a15178557 | ||
| 
						 | 
					f3ecfab378 | ||
| 
						 | 
					804563d5b2 | ||
| 
						 | 
					c3e5d983b9 | ||
| 
						 | 
					d21edcfed5 | ||
| 
						 | 
					9b69a45eee | ||
| 
						 | 
					7424ee755a | ||
| 
						 | 
					ff664fd1d8 | ||
| 
						 | 
					fd3f03580d | ||
| 
						 | 
					a09150846a | ||
| 
						 | 
					f2a9c55637 | ||
| 
						 | 
					eaa3f83e46 | ||
| 
						 | 
					e786cc1454 | ||
| 
						 | 
					cd0c632fcb | ||
| 
						 | 
					d5f248cb82 | ||
| 
						 | 
					6a800abe06 | ||
| 
						 | 
					fe265554a7 | ||
| 
						 | 
					7305466765 | ||
| 
						 | 
					9ac55a98f1 | ||
| 
						 | 
					a1149fb6ad | ||
| 
						 | 
					dfc4cc4aaf | ||
| 
						 | 
					ef7541291b | ||
| 
						 | 
					248a3e6b7e | ||
| 
						 | 
					6b1e381750 | ||
| 
						 | 
					feaf6108f9 | ||
| 
						 | 
					9ad104585d | ||
| 
						 | 
					7c44af3616 | ||
| 
						 | 
					0599bf41b0 | ||
| 
						 | 
					eac303f84c | ||
| 
						 | 
					7bdd1c625c | ||
| 
						 | 
					0003760fd9 | ||
| 
						 | 
					eafb8c8e38 | ||
| 
						 | 
					60c8105559 | ||
| 
						 | 
					54626c6f7e | ||
| 
						 | 
					cca528a630 | ||
| 
						 | 
					530193a3a2 | ||
| 
						 | 
					52e3149040 | ||
| 
						 | 
					ad297ea9dc | ||
| 
						 | 
					2015fc97dc | ||
| 
						 | 
					35889a0f7d | ||
| 
						 | 
					dcd84a4b53 | ||
| 
						 | 
					01374989b1 | ||
| 
						 | 
					f300462003 | ||
| 
						 | 
					1e4da1b99c | ||
| 
						 | 
					e1de6cb98d | ||
| 
						 | 
					59a18c4ead | ||
| 
						 | 
					b881e4b62a | ||
| 
						 | 
					7060ae077b | ||
| 
						 | 
					a7b0910566 | ||
| 
						 | 
					60706f72d4 | ||
| 
						 | 
					2e77f6b34b | ||
| 
						 | 
					50d5030949 | ||
| 
						 | 
					03dbb0f931 | ||
| 
						 | 
					249619fabd | ||
| 
						 | 
					60d1f7797c | ||
| 
						 | 
					dc4b8c876e | ||
| 
						 | 
					1724723e63 | ||
| 
						 | 
					02455b1e28 | ||
| 
						 | 
					47a9b97f8b | ||
| 
						 | 
					0aa29daa72 | ||
| 
						 | 
					182b1c1941 | ||
| 
						 | 
					bbc8010de3 | ||
| 
						 | 
					15baa56584 | ||
| 
						 | 
					a72683707f | ||
| 
						 | 
					f4baa4ddf8 | ||
| 
						 | 
					f9eb36434f | ||
| 
						 | 
					bc5e16bcea | ||
| 
						 | 
					86e04048ff | ||
| 
						 | 
					d7c0ff5e89 | ||
| 
						 | 
					51e1efa277 | ||
| 
						 | 
					67f636cc68 | ||
| 
						 | 
					fcdfebd0e7 | ||
| 
						 | 
					069ec3b910 | ||
| 
						 | 
					1092f55b54 | ||
| 
						 | 
					8a8abf12f9 | ||
| 
						 | 
					f044e29526 | ||
| 
						 | 
					4f703019ca | ||
| 
						 | 
					0e6baec350 | ||
| 
						 | 
					08690d658f | ||
| 
						 | 
					674325e96c | ||
| 
						 | 
					f8aa486ad1 | ||
| 
						 | 
					be78f0f36a | ||
| 
						 | 
					9917f05be8 | ||
| 
						 | 
					d23228522c | ||
| 
						 | 
					8c9896561e | ||
| 
						 | 
					23cdb2125e | ||
| 
						 | 
					43fc598bd5 | ||
| 
						 | 
					2105d2f952 | 
							
								
								
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -17,10 +17,8 @@ config.status
 | 
			
		||||
config
 | 
			
		||||
configure
 | 
			
		||||
data/50-gnome-shell-*.xml
 | 
			
		||||
data/gnome-shell.desktop
 | 
			
		||||
data/gnome-shell.desktop.in
 | 
			
		||||
data/gnome-shell-wayland.desktop
 | 
			
		||||
data/gnome-shell-wayland.desktop.in
 | 
			
		||||
data/org.gnome.Shell.desktop
 | 
			
		||||
data/org.gnome.Shell.desktop.in
 | 
			
		||||
data/gnome-shell-extension-prefs.desktop
 | 
			
		||||
data/gnome-shell-extension-prefs.desktop.in
 | 
			
		||||
data/gnome-shell-theme.gresource
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										330
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						@@ -1,3 +1,333 @@
 | 
			
		||||
3.20.4
 | 
			
		||||
======
 | 
			
		||||
* Free old backgrounds immediately [Hyungwon; #766353]
 | 
			
		||||
* Adjust to flatpak PermissionStore API changes [Florian; #766598]
 | 
			
		||||
* calendar: Only hide dismissed occurrence of recurring event [Florian; #748226]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Hyungwon Hwang, Florian Müllner
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Bruce Cowan [en_GB], Piotr Drąg [pl]
 | 
			
		||||
 | 
			
		||||
3.20.3
 | 
			
		||||
======
 | 
			
		||||
* Fix sorting of hidden apps in app switcher [Florian; #766238]
 | 
			
		||||
* Allocate framebuffers early to fix a crash on NVIDIA [Martin; #764898]
 | 
			
		||||
* Fix cycle-windows/cycle-group keybindings [Florian; #730739]
 | 
			
		||||
* networkAgent: Handle VPN service aliases [David; #658484]
 | 
			
		||||
* Fix crash when using screen recorder under wayland [Rui; #767001]
 | 
			
		||||
* Plug a memory leak [Hans; #710230]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Rui Matos, Florian Müllner, Hans Petter Jansson, Martin Szulecki,
 | 
			
		||||
  David Woodhouse
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Sveinn í Felli [is], Andika Triwidada [id]
 | 
			
		||||
 | 
			
		||||
3.20.2
 | 
			
		||||
======
 | 
			
		||||
* Save screencasts in HOME if XDG_VIDEO_DIR doesn't exist [Florian; #765015]
 | 
			
		||||
* Don't show orientation lock when g-s-d won't rotate [Florian; #765267]
 | 
			
		||||
* Misc. bug fixes [Heiher, Florian, Marek; #722752, #765061, #763068, #765607,
 | 
			
		||||
  #757676]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Heiher, Marek Chalupa, Florian Müllner
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Arash Mousavi [fa], Kristjan SCHMIDT [eo], Tiago Santos [pt],
 | 
			
		||||
  Kjartan Maraas [nb]
 | 
			
		||||
 | 
			
		||||
3.20.1
 | 
			
		||||
======
 | 
			
		||||
* Plug a memory leak [Aaron; #735705]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Aaron Plattner
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Daniel Korostil [uk], Matej Urbančič [sl], Inaki Larranaga Murgoitio [eu],
 | 
			
		||||
  Cheng-Chia Tseng [zh_TW], Fabio Tomat [fur], Trần Ngọc Quân [vi],
 | 
			
		||||
  YunQiang Su [zh_CN], Marek Černocký [cs], Arash Mousavi [fa],
 | 
			
		||||
  Alexander Shopov [bg], Khaled Hosny [ar]
 | 
			
		||||
 | 
			
		||||
3.20.0
 | 
			
		||||
======
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Changwoo Ryu [ko], Baurzhan Muftakhidinov [kk], Milo Casagrande [it],
 | 
			
		||||
  Anders Jonsson [sv], Muhammet Kara [tr], Alexandre Franke [fr],
 | 
			
		||||
  Rūdolfs Mazurs [lv], Ask Hjorth Larsen [da], Jiro Matsuzawa [ja]
 | 
			
		||||
 | 
			
		||||
3.19.92
 | 
			
		||||
=======
 | 
			
		||||
* Update location dialog according to latest mockups [Zeeshan; #762480]
 | 
			
		||||
* Fix deleting chat notifications in calendar [Florian; #747991]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Zeeshan Ali (Khattak), Florian Müllner
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Rūdolfs Mazurs [lv], Changwoo Ryu [ko], Matej Urbančič [sl],
 | 
			
		||||
  Justin van Steijn [nl], Fabio Tomat [fur], Kris Thomsen [da],
 | 
			
		||||
  Marek Černocký [cs], Piotr Drąg [pl], Dušan Kazik [sk],
 | 
			
		||||
  Мирослав Николић [sr, sr@latin], Balázs Úr [hu], Yosef Or Boczko [he],
 | 
			
		||||
  Daniel Mustieles [es], Fran Dieguez [gl], Bernd Homuth [de],
 | 
			
		||||
  Tom Tryfonidis [el], Jiri Grönroos [fi], Gil Forcada [ca],
 | 
			
		||||
  Artur Morais [pt_BR], Aurimas Černius [lt], Stas Solovey [ru]
 | 
			
		||||
 | 
			
		||||
3.19.91
 | 
			
		||||
=======
 | 
			
		||||
* location: Ask user only once [Zeeshan; #762559]
 | 
			
		||||
* Fix jiggling when auto-hiding legacy tray [Florian; #747957]
 | 
			
		||||
* Misc. bug fixes [Florian, Michael, Ting-Wei; #762475, #762507, #755659]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Zeeshan Ali (Khattak), Michael Catanzaro, Ting-Wei Lan, Florian Müllner
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Мирослав Николић [sr, sr@latin], Piotr Drąg [pl], A S Alam [pa],
 | 
			
		||||
  Artur de Aquino Morais [pt_BR], Daniel Mustieles [es],
 | 
			
		||||
  Chao-Hsiung Liao [zh_TW], Daniel Korostil [uk], Fran Dieguez [gl],
 | 
			
		||||
  Tom Tryfonidis [el], Bernd Homuth [de], Sebastian Rasmussen [sv],
 | 
			
		||||
  Jordi Mas [ca], Piotr Drąg [ga], Cédric Valmary [oc], Gábor Kelemen [hu],
 | 
			
		||||
  Baurzhan Muftakhidinov [kk], Friedel Wolff [af], Marek Černocký [cs],
 | 
			
		||||
  Mingye Wang (Arthur2e5) [zh_CN], Aron Xu [zh_CN], Khaled Hosny [ar],
 | 
			
		||||
  Aurimas Černius [lt], Stas Solovey [ru], Yosef Or Boczko [he]
 | 
			
		||||
 | 
			
		||||
3.19.90
 | 
			
		||||
=======
 | 
			
		||||
* Correctly identify VPN secret requests [Lubomir; #760999]
 | 
			
		||||
* Improve week number presentation [Jakub; #683245]
 | 
			
		||||
* Add audio device selection dialog [Florian; #760284]
 | 
			
		||||
* Add media controls to the time and date drop down [Florian; #756491]
 | 
			
		||||
* Fix IBus candidate popup position under wayland [Rui; #753476]
 | 
			
		||||
* Ask user to grant applications access to location [Zeeshan; #762119]
 | 
			
		||||
* Misc. bug fixes [Mario, Jakub, Florian; #761208, #761772, #762270]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Zeeshan Ali (Khattak), Michael Catanzaro, Rui Matos, Florian Müllner,
 | 
			
		||||
  Lubomir Rintel, Mario Sanchez Prada, Jakub Steiner
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Alexander Shopov [bg], Balázs Meskó [hu], Fabio Tomat [fur],
 | 
			
		||||
  Dušan Kazik [sk], Piotr Drąg [pl], Alexandre Franke [fr],
 | 
			
		||||
  Mario Blättermann [de], Milo Casagrande [it], Jordi Mas [ca]
 | 
			
		||||
 | 
			
		||||
3.19.4
 | 
			
		||||
======
 | 
			
		||||
* gdm: Do not allow bypassing disabled Sign In button [Michael; #746180]
 | 
			
		||||
* Style week numbers in calendar [Jakub; #683245]
 | 
			
		||||
* Misc. bug fixes [Christophe, Jakub, Rui; #759708, #760577, #760945]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Michael Catanzaro, Marek Černocký, Christophe Fergeau, Rui Matos,
 | 
			
		||||
  Jakub Steiner
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Aurimas Černius [lt], Enrico Nicoletto [pt_BR], Andika Triwidada [id],
 | 
			
		||||
  Mario Blättermann [de], Marek Černocký [cs], Kjartan Maraas [nb],
 | 
			
		||||
  Muhammet Kara [tr], Stas Solovey [ru]
 | 
			
		||||
 | 
			
		||||
3.19.3
 | 
			
		||||
======
 | 
			
		||||
* Fix thumbnail scaling in window switcher on HiDPI [Florian; #758676]
 | 
			
		||||
* Update animated backgrounds on timezone changes [Florian; #758939]
 | 
			
		||||
* loginDialog: Update user list on user changes [Michael; #758568]
 | 
			
		||||
* Fix touch interaction on wayland [Carlos; #756748]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Michael Catanzaro, Carlos Garnacho, Kalev Lember, Florian Müllner
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Daniel Korostil [uk], Muhammet Kara [tr], Dušan Kazik [sk],
 | 
			
		||||
  Baurzhan Muftakhidinov [kk], Marek Černocký [cs]
 | 
			
		||||
 | 
			
		||||
3.19.2
 | 
			
		||||
======
 | 
			
		||||
* Make gnome-shell DBus activatable [Ray; #741666]
 | 
			
		||||
* Fix browser plugin crash in Firefox [Carlos; #737932, #757940]
 | 
			
		||||
* Optionally show battery percentage in system status area [Bastien; #735771]
 | 
			
		||||
* Misc. bug fixes [Kalev, Florian, Bastien; #757418, #757668, #757779, #757816,
 | 
			
		||||
  #745626, #758220]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Michael Biebl, Michael Catanzaro, Piotr Drąg, Carlos Garcia Campos,
 | 
			
		||||
  Kalev Lember, Florian Müllner, Bastien Nocera, Ray Strode
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Pedro Albuquerque [pt], liushuyu [zh_CN], Yosef Or Boczko [he],
 | 
			
		||||
  Jiri Grönroos [fi], Kjartan Maraas [nb], GNOME Translation Robot [gd],
 | 
			
		||||
  Daniel Mustieles [es], Marek Černocký [cs], Kristjan SCHMIDT [eo],
 | 
			
		||||
  Stas Solovey [ru]
 | 
			
		||||
 | 
			
		||||
3.19.1
 | 
			
		||||
======
 | 
			
		||||
* Respect text-scaling factor under wayland [Owen; #756447]
 | 
			
		||||
* Show the Bluetooth submenu when there were setup devices [Bastien; #723848]
 | 
			
		||||
* Misc. bug fixes [Florian, Cosimo, Rui, Ray, Owen, Jakub, Bastien;
 | 
			
		||||
  #756697, #756714, #756605, #754814, #738942, #756983, #756925,
 | 
			
		||||
  #757011, #673235, #757150]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Cosimo Cecchi, Rui Matos, Florian Müllner, Bastien Nocera, Jakub Steiner,
 | 
			
		||||
  Ray Strode, Owen W. Taylor
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Kjartan Maraas [nb], Khaled Hosny [ar], Balázs Meskó [hu],
 | 
			
		||||
  Daniel Șerbănescu [ro], Marek Černocký [cs]
 | 
			
		||||
 | 
			
		||||
3.18.1
 | 
			
		||||
======
 | 
			
		||||
* Fix screen freezes when a notification is pushed [Carlos; #755425]
 | 
			
		||||
* Fix overzealous ellipsization in system status menu [Adel, Florian; #708472]
 | 
			
		||||
* Hide app menu when disabled by setting [Florian; #745919]
 | 
			
		||||
* Fix lightbox effect when animations are disabled [Rui; #755827]
 | 
			
		||||
* Do not mark hotplug notifications as critical [Florian; #657923]
 | 
			
		||||
* Fix icons getting cut off in dash [Florian; #745649]
 | 
			
		||||
* Animate fullscreen/unfullscreen operations [Cosimo; #707248]
 | 
			
		||||
* Misc. bug fixes [Florian, Owen; #748919, #674799, #754581]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Emmanuele Bassi, Michael Catanzaro, Cosimo Cecchi, Matthias Clasen,
 | 
			
		||||
  Adel Gadllah, Carlos Garnacho, Ekaterina Gerasimova, Rui Matos,
 | 
			
		||||
  Florian Müllner, Owen W. Taylor
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Марко Костић [sr], Милош Поповић [sr@latin], Khaled Hosny [ar],
 | 
			
		||||
  Trần Ngọc Quân [vi], Petr Kovar [cs], Alexandre Franke [fr],
 | 
			
		||||
  Fran Dieguez [gl], Anders Jonsson [sv], Piotr Drąg [pl], Dušan Kazik [sk],
 | 
			
		||||
  Milo Casagrande [it], Changwoo Ryu [ko], Stas Solovey [ru],
 | 
			
		||||
  Rafael Fontenelle [pt_BR], Tom Tryfonidis [el], Aurimas Černius [lt],
 | 
			
		||||
  Seán de Búrca [ga], Christian Kirbach [de], Jiri Grönroos [fi],
 | 
			
		||||
  Pedro Albuquerque [pt], Baurzhan Muftakhidinov [kk], Daniel Mustieles [es],
 | 
			
		||||
  Marek Černocký [cs], Ask Hjorth Larsen [da], Inaki Larranaga Murgoitio [eu]
 | 
			
		||||
 | 
			
		||||
3.18.0
 | 
			
		||||
======
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Sendy Aditya Suryana [id], Kris Thomsen [da], Seán de Búrca [ga],
 | 
			
		||||
  Andika Triwidada [id], Enrico Nicoletto [pt_BR], Anders Jonsson [sv],
 | 
			
		||||
  Rūdolfs Mazurs [lv]
 | 
			
		||||
 | 
			
		||||
3.17.92
 | 
			
		||||
=======
 | 
			
		||||
* Fix race when loading multiple background animations [Josselin; #741453]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Michael Biebl, Josselin Mouette, Florian Müllner
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Baurzhan Muftakhidinov [kk], Changwoo Ryu [ko], Christian Kirbach [de],
 | 
			
		||||
  Kjartan Maraas [nb], Jiri Grönroos [fi], Arash Mousavi [fa],
 | 
			
		||||
  Jiro Matsuzawa [ja], Marek Černocký [cs], Milo Casagrande [it]
 | 
			
		||||
 | 
			
		||||
3.17.91
 | 
			
		||||
=======
 | 
			
		||||
* Fix login screen spinner causing wakeups while VT-switched away
 | 
			
		||||
  [Ray, Rui; #753891]
 | 
			
		||||
* Fix scrolling of user list on login screen [Florian; #754525]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Piotr Drąg, Rui Matos, Florian Müllner, Ray Strode
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Dušan Kazik [sk], Jordi Mas [ca], Aurimas Černius [lt], Stas Solovey [ru],
 | 
			
		||||
  Piotr Drąg [pl], Pedro Albuquerque [pt], Daniel Mustieles [es],
 | 
			
		||||
  Chao-Hsiung Liao [zh_TW], Muhammet Kara [tr], Fran Dieguez [gl],
 | 
			
		||||
  Hannie Dumoleyn [nl], Yosef Or Boczko [he], Tom Tryfonidis [el],
 | 
			
		||||
  A S Alam [pa], Balázs Úr [hu], Alexandre Franke [fr], Frédéric Péters [fr]
 | 
			
		||||
 | 
			
		||||
3.17.90
 | 
			
		||||
=======
 | 
			
		||||
* Avoid caret/focus viewport changes during pointer movement [Rui; #752138]
 | 
			
		||||
* Match GTK+'s modal dialogs for system modal dialogs [Carlos; #746108]
 | 
			
		||||
* Refine message list style [Florian; #749958]
 | 
			
		||||
* Fix type-ahead behavior for backspace and compose key [Rui; #753319, #753320]
 | 
			
		||||
* Refine the system status menu [Florian; #751377]
 | 
			
		||||
* Misc. bug fixes and cleanups [Bastien, Ray, Florian, Jakub; #752779, #752739,
 | 
			
		||||
  #741366, #651503, #753064, #753181, #752881]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Rui Matos, Florian Müllner, Bastien Nocera, Carlos Soriano, Jakub Steiner,
 | 
			
		||||
  Ray Strode, Rico Tzschichholz
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Marek Černocký [cs], Kjartan Maraas [nb], Jordi Mas [ca], Muhammet Kara [tr],
 | 
			
		||||
  Enrico Nicoletto [pt_BR]
 | 
			
		||||
 | 
			
		||||
3.17.4
 | 
			
		||||
======
 | 
			
		||||
* Fix fuzziness of app menu icon [Jakub; #747932]
 | 
			
		||||
* Implement 4 finger swipe gesture for touchpads [Carlos; #752250]
 | 
			
		||||
* Misc. bug fixes [Florian, Alexandre, Piotr, Ray, Mario; #751921, #659969,
 | 
			
		||||
  #752438, #752675]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Piotr Drąg, Alexandre Franke, Carlos Garnacho, Florian Müllner,
 | 
			
		||||
  Mario Sanchez Prada, Jakub Steiner, Jasper St. Pierre, Ray Strode
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Benjamin Steinwender [de], Pedro Albuquerque [pt], Fabio Tomat [fur],
 | 
			
		||||
  Matej Urbančič [sl], Daniel Mustieles [es], Yosef Or Boczko [he],
 | 
			
		||||
  Daniel Martinez [an]
 | 
			
		||||
 | 
			
		||||
3.17.3
 | 
			
		||||
======
 | 
			
		||||
* Handle touch events in OSK on wayland [Rui; #750287]
 | 
			
		||||
* Reinstate left/right movement to window menu [Ron; #751344]
 | 
			
		||||
* Allow extensions to disable "Window is ready" notification [Adel; #748846]
 | 
			
		||||
* Misc. bug fixes [Watson, Michael, Ray, Rui, Florian, Cosimo; #750465,
 | 
			
		||||
  #751016, #751517, #750714, #751541, #751599]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Michael Biebl, Cosimo Cecchi, Adel Gadllah, Rui Matos, Florian Müllner,
 | 
			
		||||
  Ray Strode, Wim Taymans, Ron Yorston, Watson Yuuma Sato
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Sebastian Rasmussen [sv], Dimitris Spingos [el], Muhammet Kara [tr],
 | 
			
		||||
  Stas Solovey [ru], Benjamin Steinwender [de], Balázs Úr [hu],
 | 
			
		||||
  Victor Ibragimov [tg], Dušan Kazik [sk], Pedro Albuquerque [pt]
 | 
			
		||||
 | 
			
		||||
3.17.2
 | 
			
		||||
======
 | 
			
		||||
* Remove StTable widget [Florian; #703833]
 | 
			
		||||
* Increase visibility of expanders in alt-tab popup [Jakub; #745058]
 | 
			
		||||
* Ensure suspend inhibitors are released when VT switched away [Rui; #749228]
 | 
			
		||||
* Use iio-sensor-proxy directly for orientation lock [Bastien; #749671]
 | 
			
		||||
* Misc. bug fixes [Florian, Lan, Carlos; #749279, #749383, #749529, #749490,
 | 
			
		||||
  #749742]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Carlos Garnacho, Ting-Wei Lan, Rui Matos, Florian Müllner, Bastien Nocera,
 | 
			
		||||
  Jakub Steiner
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Yosef Or Boczko [he], sun [zh_CN], Felipe Braga [pt_BR],
 | 
			
		||||
  Victor Ibragimov [tg], Gábor Kelemen [hu], Cédric Valmary [oc],
 | 
			
		||||
  Dušan Kazik [sk], Kjartan Maraas [nb], Bruno Ramalhete [pt],
 | 
			
		||||
  Matej Urbančič [sl], Daniel Mustieles [es]
 | 
			
		||||
 | 
			
		||||
3.17.1
 | 
			
		||||
======
 | 
			
		||||
* Add Display Settings entry to background menu [Meet; #697346]
 | 
			
		||||
* Add window menu option to move to different monitor [Isaac; #633994]
 | 
			
		||||
* Improve switch style in default/highContrast themes [Jakub; #746294, #747912]
 | 
			
		||||
* Make event highlight in calendar more prominent [Jakub; #747715]
 | 
			
		||||
* Fix keyboard focus when focusing a notification banner [Florian; #747205]
 | 
			
		||||
* Move notification banners below the dateMenu [Meet, Florian; #745910]
 | 
			
		||||
* Misc. bug fixes [Mario, Rui; #748338, #748541]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Isaac Ge, Rui Matos, Florian Müllner, Meet Parikh, Mario Sanchez Prada,
 | 
			
		||||
  Jakub Steiner, Jasper St. Pierre
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Sveinn í Felli [is], Marek Černocký [cs], laurent Soleil [oc]
 | 
			
		||||
 | 
			
		||||
3.16.1
 | 
			
		||||
======
 | 
			
		||||
* gdm: Move long session chooser menus to the side [Florian; #734352]
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,10 @@ mozillalibdir = $(BROWSER_PLUGIN_DIR)
 | 
			
		||||
 | 
			
		||||
mozillalib_LTLIBRARIES = libgnome-shell-browser-plugin.la
 | 
			
		||||
 | 
			
		||||
libgnome_shell_browser_plugin_la_LDFLAGS = -module -avoid-version -no-undefined
 | 
			
		||||
# Browsers can unload and reload the module while browsing, which is not supported by GObject.
 | 
			
		||||
# We pass -Wl,-z,nodelete to the linker to ensure the module is never unloaded.
 | 
			
		||||
# https://bugzilla.gnome.org/show_bug.cgi?id=737932
 | 
			
		||||
libgnome_shell_browser_plugin_la_LDFLAGS = -module -avoid-version -no-undefined -Wl,-z,nodelete
 | 
			
		||||
 | 
			
		||||
libgnome_shell_browser_plugin_la_LIBADD = 	\
 | 
			
		||||
	$(BROWSER_PLUGIN_LIBS)
 | 
			
		||||
 
 | 
			
		||||
@@ -33,20 +33,16 @@
 | 
			
		||||
#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 " \
 | 
			
		||||
#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_MIME_STRING "application/x-gnome-shell-integration::GNOME Shell Integration Dummy Content-Type";
 | 
			
		||||
 | 
			
		||||
#define PLUGIN_API_VERSION 5
 | 
			
		||||
 | 
			
		||||
#define EXTENSION_DISABLE_VERSION_CHECK_KEY "disable-extension-version-validation"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  GDBusProxy *proxy;
 | 
			
		||||
} PluginData;
 | 
			
		||||
 | 
			
		||||
static NPNetscapeFuncs funcs;
 | 
			
		||||
 | 
			
		||||
static inline gchar *
 | 
			
		||||
@@ -145,121 +141,6 @@ check_origin_and_protocol (NPP instance)
 | 
			
		||||
  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;
 | 
			
		||||
  plugin->setwindow = NPP_SetWindow;
 | 
			
		||||
 | 
			
		||||
  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.Extensions",
 | 
			
		||||
                                               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 {
 | 
			
		||||
@@ -330,45 +211,18 @@ static NPObject *
 | 
			
		||||
plugin_object_allocate (NPP      instance,
 | 
			
		||||
                        NPClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  PluginData *data = instance->pdata;
 | 
			
		||||
  PluginObject *obj = g_slice_new0 (PluginObject);
 | 
			
		||||
  PluginObject *obj = (PluginObject *) funcs.memalloc (sizeof (PluginObject));
 | 
			
		||||
 | 
			
		||||
  memset (obj, 0, sizeof (PluginObject));
 | 
			
		||||
  obj->instance = instance;
 | 
			
		||||
  obj->proxy = g_object_ref (data->proxy);
 | 
			
		||||
  obj->settings = g_settings_new (SHELL_SCHEMA);
 | 
			
		||||
  obj->signal_id = g_signal_connect (obj->proxy, "g-signal",
 | 
			
		||||
                                     G_CALLBACK (on_shell_signal), obj);
 | 
			
		||||
 | 
			
		||||
  obj->watch_name_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
 | 
			
		||||
                                         "org.gnome.Shell",
 | 
			
		||||
                                         G_BUS_NAME_WATCHER_FLAGS_NONE,
 | 
			
		||||
                                         on_shell_appeared,
 | 
			
		||||
                                         NULL,
 | 
			
		||||
                                         obj,
 | 
			
		||||
                                         NULL);
 | 
			
		||||
 | 
			
		||||
  g_debug ("plugin object created");
 | 
			
		||||
 | 
			
		||||
  return (NPObject*)obj;
 | 
			
		||||
  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);
 | 
			
		||||
 | 
			
		||||
  if (obj->watch_name_id)
 | 
			
		||||
    g_bus_unwatch_name (obj->watch_name_id);
 | 
			
		||||
 | 
			
		||||
  g_debug ("plugin object destroyed");
 | 
			
		||||
 | 
			
		||||
  g_slice_free (PluginObject, obj);
 | 
			
		||||
  funcs.memfree (npobj);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline gboolean
 | 
			
		||||
@@ -1019,6 +873,149 @@ init_methods_and_properties (void)
 | 
			
		||||
  onextension_changed_id = funcs.getstringidentifier ("onchange");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* =============== 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;
 | 
			
		||||
  plugin->setwindow = NPP_SetWindow;
 | 
			
		||||
  plugin->event = NPP_HandleEvent;
 | 
			
		||||
 | 
			
		||||
  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 */
 | 
			
		||||
  PluginObject *obj;
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
 | 
			
		||||
  g_debug ("plugin created");
 | 
			
		||||
 | 
			
		||||
  if (!check_origin_and_protocol (instance))
 | 
			
		||||
    return NPERR_GENERIC_ERROR;
 | 
			
		||||
 | 
			
		||||
  /* set windowless mode */
 | 
			
		||||
  funcs.setvalue(instance, NPPVpluginWindowBool, NULL);
 | 
			
		||||
 | 
			
		||||
  g_debug ("creating scriptable object");
 | 
			
		||||
  init_methods_and_properties ();
 | 
			
		||||
  obj = (PluginObject *) funcs.createobject (instance, &plugin_class);
 | 
			
		||||
  instance->pdata = obj;
 | 
			
		||||
 | 
			
		||||
  obj->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.Extensions",
 | 
			
		||||
                                              NULL, /* GCancellable */
 | 
			
		||||
                                              &error);
 | 
			
		||||
  if (!obj->proxy)
 | 
			
		||||
    {
 | 
			
		||||
      /* ignore error if the shell is not running, otherwise warn */
 | 
			
		||||
      if (!g_error_matches (error, G_DBUS_ERROR, 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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  obj->settings = g_settings_new (SHELL_SCHEMA);
 | 
			
		||||
  obj->signal_id = g_signal_connect (obj->proxy, "g-signal",
 | 
			
		||||
                                     G_CALLBACK (on_shell_signal), obj);
 | 
			
		||||
  obj->watch_name_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
 | 
			
		||||
                                         "org.gnome.Shell",
 | 
			
		||||
                                         G_BUS_NAME_WATCHER_FLAGS_NONE,
 | 
			
		||||
                                         on_shell_appeared,
 | 
			
		||||
                                         NULL,
 | 
			
		||||
                                         obj,
 | 
			
		||||
                                         NULL);
 | 
			
		||||
 | 
			
		||||
  g_debug ("plugin created successfully");
 | 
			
		||||
 | 
			
		||||
  return NPERR_NO_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NPError
 | 
			
		||||
NPP_Destroy(NPP           instance,
 | 
			
		||||
	    NPSavedData **saved)
 | 
			
		||||
{
 | 
			
		||||
  /* instance finalization function */
 | 
			
		||||
  PluginObject *obj = (PluginObject *) instance->pdata;
 | 
			
		||||
 | 
			
		||||
  if (!obj)
 | 
			
		||||
    return NPERR_INVALID_INSTANCE_ERROR;
 | 
			
		||||
 | 
			
		||||
  g_debug ("plugin destroyed");
 | 
			
		||||
 | 
			
		||||
  g_signal_handler_disconnect (obj->proxy, obj->signal_id);
 | 
			
		||||
  g_object_unref (obj->proxy);
 | 
			
		||||
 | 
			
		||||
  if (obj->listener)
 | 
			
		||||
    funcs.releaseobject (obj->listener);
 | 
			
		||||
 | 
			
		||||
  if (obj->restart_listener)
 | 
			
		||||
    funcs.releaseobject (obj->restart_listener);
 | 
			
		||||
 | 
			
		||||
  if (obj->watch_name_id)
 | 
			
		||||
    g_bus_unwatch_name (obj->watch_name_id);
 | 
			
		||||
 | 
			
		||||
  funcs.releaseobject((NPObject *)obj);
 | 
			
		||||
 | 
			
		||||
  return NPERR_NO_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NPError
 | 
			
		||||
NPP_GetValue(NPP          instance,
 | 
			
		||||
	     NPPVariable  variable,
 | 
			
		||||
@@ -1029,13 +1026,11 @@ NPP_GetValue(NPP          instance,
 | 
			
		||||
  switch (variable) {
 | 
			
		||||
  case NPPVpluginScriptableNPObject:
 | 
			
		||||
    g_debug ("creating scriptable object");
 | 
			
		||||
    init_methods_and_properties ();
 | 
			
		||||
    if (!instance->pdata)
 | 
			
		||||
      return NPERR_INVALID_INSTANCE_ERROR;
 | 
			
		||||
 | 
			
		||||
    *(NPObject**)value = funcs.createobject (instance, &plugin_class);
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
  case NPPVpluginNeedsXEmbed:
 | 
			
		||||
    *(bool *)value = TRUE;
 | 
			
		||||
    funcs.retainobject (instance->pdata);
 | 
			
		||||
    *(NPObject**)value = instance->pdata;
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
  default:
 | 
			
		||||
@@ -1053,3 +1048,11 @@ NPP_SetWindow(NPP          instance,
 | 
			
		||||
{
 | 
			
		||||
  return NPERR_NO_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int16_t
 | 
			
		||||
NPP_HandleEvent(NPP   instance,
 | 
			
		||||
                void *event)
 | 
			
		||||
{
 | 
			
		||||
  /* Ignore the event */
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						@@ -1,5 +1,6 @@
 | 
			
		||||
AC_PREREQ(2.63)
 | 
			
		||||
AC_INIT([gnome-shell],[3.16.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
 | 
			
		||||
AC_INIT([gnome-shell],[3.20.4],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
 | 
			
		||||
AX_IS_RELEASE([git-directory])
 | 
			
		||||
 | 
			
		||||
AC_CONFIG_HEADERS([config.h])
 | 
			
		||||
AC_CONFIG_SRCDIR([src/shell-global.c])
 | 
			
		||||
@@ -63,8 +64,8 @@ AC_ARG_ENABLE([systemd],
 | 
			
		||||
              [enable_systemd=$enableval],
 | 
			
		||||
              [enable_systemd=auto])
 | 
			
		||||
AS_IF([test x$enable_systemd != xno], [
 | 
			
		||||
  AC_MSG_CHECKING([for libsystemd-journal])
 | 
			
		||||
  PKG_CHECK_EXISTS([libsystemd-journal],
 | 
			
		||||
  AC_MSG_CHECKING([for libsystemd])
 | 
			
		||||
  PKG_CHECK_EXISTS([libsystemd],
 | 
			
		||||
                   [have_systemd=yes
 | 
			
		||||
                    AC_DEFINE([HAVE_SYSTEMD], [1], [Define if we have systemd])],
 | 
			
		||||
                   [have_systemd=no])
 | 
			
		||||
@@ -74,13 +75,13 @@ AS_IF([test x$enable_systemd != xno], [
 | 
			
		||||
AC_MSG_RESULT($enable_systemd)
 | 
			
		||||
 | 
			
		||||
CLUTTER_MIN_VERSION=1.21.5
 | 
			
		||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
 | 
			
		||||
GOBJECT_INTROSPECTION_MIN_VERSION=1.45.4
 | 
			
		||||
GJS_MIN_VERSION=1.39.0
 | 
			
		||||
MUTTER_MIN_VERSION=3.16.1
 | 
			
		||||
MUTTER_MIN_VERSION=3.20.2
 | 
			
		||||
GTK_MIN_VERSION=3.15.0
 | 
			
		||||
GIO_MIN_VERSION=2.37.0
 | 
			
		||||
GIO_MIN_VERSION=2.45.3
 | 
			
		||||
LIBECAL_MIN_VERSION=3.5.3
 | 
			
		||||
LIBEDATASERVER_MIN_VERSION=3.13.90
 | 
			
		||||
LIBEDATASERVER_MIN_VERSION=3.17.2
 | 
			
		||||
TELEPATHY_GLIB_MIN_VERSION=0.17.5
 | 
			
		||||
POLKIT_MIN_VERSION=0.100
 | 
			
		||||
STARTUP_NOTIFICATION_MIN_VERSION=0.11
 | 
			
		||||
@@ -106,7 +107,7 @@ SHARED_PCS="gio-unix-2.0 >= $GIO_MIN_VERSION
 | 
			
		||||
            polkit-agent-1 >= $POLKIT_MIN_VERSION
 | 
			
		||||
            gcr-base-3 >= $GCR_MIN_VERSION"
 | 
			
		||||
if test x$have_systemd = xyes; then
 | 
			
		||||
  SHARED_PCS="${SHARED_PCS} libsystemd-journal"
 | 
			
		||||
  SHARED_PCS="${SHARED_PCS} libsystemd"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(GNOME_SHELL, $SHARED_PCS)
 | 
			
		||||
@@ -116,9 +117,9 @@ PKG_CHECK_MODULES(GNOME_SHELL_JS, gio-2.0 gjs-internals-1.0 >= $GJS_MIN_VERSION)
 | 
			
		||||
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.8 x11)
 | 
			
		||||
PKG_CHECK_MODULES(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(TRAY, gtk+-3.0)
 | 
			
		||||
PKG_CHECK_MODULES(TRAY, clutter-1.0 gtk+-3.0)
 | 
			
		||||
PKG_CHECK_MODULES(GVC, libpulse >= $PULSE_MIN_VERS libpulse-mainloop-glib gobject-2.0)
 | 
			
		||||
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.13.1)
 | 
			
		||||
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.19.2)
 | 
			
		||||
 | 
			
		||||
AC_ARG_ENABLE(browser-plugin,
 | 
			
		||||
              [AS_HELP_STRING([--enable-browser-plugin],
 | 
			
		||||
@@ -220,7 +221,7 @@ if test "$enable_man" != no; then
 | 
			
		||||
fi
 | 
			
		||||
AM_CONDITIONAL(ENABLE_MAN, test "$enable_man" != no)
 | 
			
		||||
 | 
			
		||||
GNOME_COMPILE_WARNINGS([error])
 | 
			
		||||
AX_COMPILER_FLAGS()
 | 
			
		||||
case "$WARN_CFLAGS" in
 | 
			
		||||
    *-Werror*)
 | 
			
		||||
        WARN_CFLAGS="$WARN_CFLAGS -Wno-error=deprecated-declarations"
 | 
			
		||||
@@ -269,7 +270,7 @@ Build configuration:
 | 
			
		||||
       Prefix:                                 ${prefix}
 | 
			
		||||
       Source code location:                   ${srcdir}
 | 
			
		||||
       Compiler:                               ${CC}
 | 
			
		||||
       Compiler Warnings:                      $enable_compile_warnings
 | 
			
		||||
       Compiler Warnings:                      $ax_enable_compile_warnings
 | 
			
		||||
 | 
			
		||||
       Support for NetworkManager:             $have_networkmanager
 | 
			
		||||
       Support for GStreamer recording:        $build_recorder
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ CLEANFILES =
 | 
			
		||||
NULL =
 | 
			
		||||
 | 
			
		||||
desktopdir=$(datadir)/applications
 | 
			
		||||
desktop_DATA = gnome-shell.desktop gnome-shell-wayland.desktop  gnome-shell-extension-prefs.desktop
 | 
			
		||||
desktop_DATA = org.gnome.Shell.desktop gnome-shell-extension-prefs.desktop
 | 
			
		||||
 | 
			
		||||
if HAVE_NETWORKMANAGER
 | 
			
		||||
desktop_DATA += org.gnome.Shell.PortalHelper.desktop
 | 
			
		||||
@@ -104,8 +104,7 @@ convertdir = $(datadir)/GConf/gsettings
 | 
			
		||||
convert_DATA = gnome-shell-overrides.convert
 | 
			
		||||
 | 
			
		||||
EXTRA_DIST =						\
 | 
			
		||||
	gnome-shell.desktop.in.in			\
 | 
			
		||||
	gnome-shell-wayland.desktop.in.in		\
 | 
			
		||||
	org.gnome.Shell.desktop.in.in			\
 | 
			
		||||
	gnome-shell-extension-prefs.desktop.in.in	\
 | 
			
		||||
	$(introspection_DATA)				\
 | 
			
		||||
	$(menu_DATA)					\
 | 
			
		||||
@@ -121,8 +120,7 @@ EXTRA_DIST =						\
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
CLEANFILES +=						\
 | 
			
		||||
	gnome-shell.desktop.in				\
 | 
			
		||||
	gnome-shell-wayland.desktop.in			\
 | 
			
		||||
	org.gnome.Shell.desktop.in			\
 | 
			
		||||
	gnome-shell-extension-prefs.in			\
 | 
			
		||||
	$(desktop_DATA)					\
 | 
			
		||||
	$(keys_DATA)					\
 | 
			
		||||
 
 | 
			
		||||
@@ -32,8 +32,10 @@
 | 
			
		||||
    <file>summary-counter.svg</file>
 | 
			
		||||
    <file>toggle-off-us.svg</file>
 | 
			
		||||
    <file>toggle-off-intl.svg</file>
 | 
			
		||||
    <file>toggle-off-hc.svg</file>
 | 
			
		||||
    <file>toggle-on-us.svg</file>
 | 
			
		||||
    <file>toggle-on-intl.svg</file>
 | 
			
		||||
    <file>toggle-on-hc.svg</file>
 | 
			
		||||
    <file>ws-switch-arrow-up.png</file>
 | 
			
		||||
    <file>ws-switch-arrow-down.png</file>
 | 
			
		||||
  </gresource>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +0,0 @@
 | 
			
		||||
[Desktop Entry]
 | 
			
		||||
Type=Application
 | 
			
		||||
_Name=GNOME Shell (wayland compositor)
 | 
			
		||||
_Comment=Window management and application launching
 | 
			
		||||
Exec=@bindir@/gnome-shell --wayland --display-server
 | 
			
		||||
X-GNOME-Bugzilla-Bugzilla=GNOME
 | 
			
		||||
X-GNOME-Bugzilla-Product=gnome-shell
 | 
			
		||||
X-GNOME-Bugzilla-Component=general
 | 
			
		||||
X-GNOME-Bugzilla-Version=@VERSION@
 | 
			
		||||
Categories=GNOME;GTK;Core;
 | 
			
		||||
OnlyShowIn=GNOME;
 | 
			
		||||
NoDisplay=true
 | 
			
		||||
X-GNOME-Autostart-Phase=DisplayServer
 | 
			
		||||
X-GNOME-Autostart-Notify=true
 | 
			
		||||
X-GNOME-AutoRestart=false
 | 
			
		||||
@@ -10,7 +10,7 @@ X-GNOME-Bugzilla-Version=@VERSION@
 | 
			
		||||
Categories=GNOME;GTK;Core;
 | 
			
		||||
OnlyShowIn=GNOME;
 | 
			
		||||
NoDisplay=true
 | 
			
		||||
X-GNOME-Autostart-Phase=WindowManager
 | 
			
		||||
X-GNOME-Autostart-Phase=DisplayServer
 | 
			
		||||
X-GNOME-Provides=panel;windowmanager;
 | 
			
		||||
X-GNOME-Autostart-Notify=true
 | 
			
		||||
X-GNOME-AutoRestart=false
 | 
			
		||||
@@ -51,6 +51,7 @@
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="looking-glass-history" type="as">
 | 
			
		||||
      <default>[]</default>
 | 
			
		||||
      <!-- Translators: looking glass is a debugger and inspector tool, see https://live.gnome.org/GnomeShell/LookingGlass -->
 | 
			
		||||
      <_summary>History for the looking glass dialog</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="always-show-log-out" type="b">
 | 
			
		||||
@@ -71,6 +72,16 @@
 | 
			
		||||
        This key sets the default state of the checkbox.
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="had-bluetooth-devices-setup" type="b">
 | 
			
		||||
      <default>false</default>
 | 
			
		||||
      <_summary>Whether the default Bluetooth adapter had set up devices associated to it</_summary>
 | 
			
		||||
      <_description>
 | 
			
		||||
        The shell will only show a Bluetooth menu item if a Bluetooth
 | 
			
		||||
        adapter is powered, or if there were devices set up associated
 | 
			
		||||
        with the default adapter. This will be reset if the default
 | 
			
		||||
        adapter is ever seen not to have devices associated to it.
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
    <child name="calendar" schema="org.gnome.shell.calendar"/>
 | 
			
		||||
    <child name="keybindings" schema="org.gnome.shell.keybindings"/>
 | 
			
		||||
    <child name="keyboard" schema="org.gnome.shell.keyboard"/>
 | 
			
		||||
 
 | 
			
		||||
@@ -10,11 +10,11 @@
 | 
			
		||||
   xmlns:xlink="http://www.w3.org/1999/xlink"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   width="29"
 | 
			
		||||
   height="29"
 | 
			
		||||
   width="24"
 | 
			
		||||
   height="24"
 | 
			
		||||
   id="svg10621"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.48.2 r9819"
 | 
			
		||||
   inkscape:version="0.91 r13725"
 | 
			
		||||
   sodipodi:docname="calendar-today.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs10623">
 | 
			
		||||
@@ -118,17 +118,6 @@
 | 
			
		||||
       fx="51"
 | 
			
		||||
       fy="30"
 | 
			
		||||
       r="42" />
 | 
			
		||||
    <radialGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       xlink:href="#linearGradient34508-1-3"
 | 
			
		||||
       id="radialGradient3113"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
 | 
			
		||||
       cx="51"
 | 
			
		||||
       cy="30"
 | 
			
		||||
       fx="51"
 | 
			
		||||
       fy="30"
 | 
			
		||||
       r="42" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
@@ -137,22 +126,23 @@
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="15.839192"
 | 
			
		||||
     inkscape:cx="20.652108"
 | 
			
		||||
     inkscape:cy="11.839084"
 | 
			
		||||
     inkscape:zoom="8"
 | 
			
		||||
     inkscape:cx="-23.537329"
 | 
			
		||||
     inkscape:cy="-31.442864"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="true"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     fit-margin-top="0"
 | 
			
		||||
     fit-margin-left="0"
 | 
			
		||||
     fit-margin-right="0"
 | 
			
		||||
     fit-margin-bottom="0"
 | 
			
		||||
     inkscape:window-width="1280"
 | 
			
		||||
     inkscape:window-height="741"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="27"
 | 
			
		||||
     inkscape:window-maximized="1"
 | 
			
		||||
     borderlayer="true">
 | 
			
		||||
     inkscape:window-width="2133"
 | 
			
		||||
     inkscape:window-height="1241"
 | 
			
		||||
     inkscape:window-x="238"
 | 
			
		||||
     inkscape:window-y="88"
 | 
			
		||||
     inkscape:window-maximized="0"
 | 
			
		||||
     borderlayer="true"
 | 
			
		||||
     inkscape:showpageshadow="false">
 | 
			
		||||
    <inkscape:grid
 | 
			
		||||
       type="xygrid"
 | 
			
		||||
       id="grid3109"
 | 
			
		||||
@@ -169,7 +159,7 @@
 | 
			
		||||
        <dc:format>image/svg+xml</dc:format>
 | 
			
		||||
        <dc:type
 | 
			
		||||
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
 | 
			
		||||
        <dc:title />
 | 
			
		||||
        <dc:title></dc:title>
 | 
			
		||||
      </cc:Work>
 | 
			
		||||
    </rdf:RDF>
 | 
			
		||||
  </metadata>
 | 
			
		||||
@@ -177,28 +167,12 @@
 | 
			
		||||
     inkscape:label="Layer 1"
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     transform="translate(-469.08263,-532.99307)">
 | 
			
		||||
    <path
 | 
			
		||||
       sodipodi:type="arc"
 | 
			
		||||
       style="opacity:0.4625;color:#000000;fill:url(#radialGradient3113);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
       id="path34506-3"
 | 
			
		||||
       sodipodi:cx="51"
 | 
			
		||||
       sodipodi:cy="30"
 | 
			
		||||
       sodipodi:rx="42"
 | 
			
		||||
       sodipodi:ry="16"
 | 
			
		||||
       d="M 9,29.999999 A 42,16 0 0 1 93,30 l -42,0 z"
 | 
			
		||||
       sodipodi:start="3.1415927"
 | 
			
		||||
       sodipodi:end="6.2831853"
 | 
			
		||||
       transform="matrix(0.43692393,0,0,1.3783114,461.29951,517.6437)"
 | 
			
		||||
       inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/motion/textures/panel.png"
 | 
			
		||||
       inkscape:export-xdpi="90"
 | 
			
		||||
       inkscape:export-ydpi="90" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:0.50196078;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
       id="rect2996"
 | 
			
		||||
       width="31"
 | 
			
		||||
       height="3"
 | 
			
		||||
       x="468.08264"
 | 
			
		||||
       y="558.99304" />
 | 
			
		||||
     transform="translate(-469.08263,-537.99307)">
 | 
			
		||||
    <circle
 | 
			
		||||
       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:0.23756906;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
 | 
			
		||||
       id="path7305"
 | 
			
		||||
       cx="481.57138"
 | 
			
		||||
       cy="559.4649"
 | 
			
		||||
       r="1.5" />
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
 
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 5.6 KiB  | 
@@ -37,14 +37,13 @@ stage {
 | 
			
		||||
  icon-shadow: 0 1px black; }
 | 
			
		||||
  .button:focus {
 | 
			
		||||
    color: #eeeeec;
 | 
			
		||||
    border-color: #215d9c;
 | 
			
		||||
    box-shadow: inset 0 1px #454f52;
 | 
			
		||||
    text-shadow: 0 1px black;
 | 
			
		||||
    icon-shadow: 0 1px black; }
 | 
			
		||||
    icon-shadow: 0 1px black;
 | 
			
		||||
    box-shadow: inset 0px 0px 0px 1px #215d9c; }
 | 
			
		||||
  .button:insensitive {
 | 
			
		||||
    color: #7f7f7f;
 | 
			
		||||
    color: gray;
 | 
			
		||||
    border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
    background-color: rgba(62, 67, 68, 0.7);
 | 
			
		||||
    background-color: rgba(62, 67, 69, 0.7);
 | 
			
		||||
    box-shadow: none;
 | 
			
		||||
    text-shadow: none;
 | 
			
		||||
    icon-shadow: none; }
 | 
			
		||||
@@ -52,9 +51,46 @@ stage {
 | 
			
		||||
    color: white;
 | 
			
		||||
    border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
    background-color: #222728;
 | 
			
		||||
    box-shadow: inset 0 0 black;
 | 
			
		||||
    text-shadow: none;
 | 
			
		||||
    icon-shadow: none; }
 | 
			
		||||
 | 
			
		||||
.modal-dialog-linked-button {
 | 
			
		||||
  border-right-width: 1px;
 | 
			
		||||
  color: #eeeeec;
 | 
			
		||||
  background-color: #2e3436;
 | 
			
		||||
  border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
  box-shadow: inset 0 1px #454f52;
 | 
			
		||||
  text-shadow: 0 1px black;
 | 
			
		||||
  icon-shadow: 0 1px black;
 | 
			
		||||
  padding: 12px; }
 | 
			
		||||
  .modal-dialog-linked-button:insensitive {
 | 
			
		||||
    color: gray;
 | 
			
		||||
    border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
    background-color: rgba(62, 67, 69, 0.7);
 | 
			
		||||
    box-shadow: none;
 | 
			
		||||
    text-shadow: none;
 | 
			
		||||
    icon-shadow: none; }
 | 
			
		||||
  .modal-dialog-linked-button:active {
 | 
			
		||||
    color: white;
 | 
			
		||||
    border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
    background-color: #222728;
 | 
			
		||||
    box-shadow: inset 0 0 black;
 | 
			
		||||
    text-shadow: none;
 | 
			
		||||
    icon-shadow: none; }
 | 
			
		||||
  .modal-dialog-linked-button:focus {
 | 
			
		||||
    color: #eeeeec;
 | 
			
		||||
    text-shadow: 0 1px black;
 | 
			
		||||
    icon-shadow: 0 1px black;
 | 
			
		||||
    box-shadow: inset 0px 0px 0px 1px #215d9c; }
 | 
			
		||||
  .modal-dialog-linked-button:first-child {
 | 
			
		||||
    border-radius: 0px 0px 0px 6px; }
 | 
			
		||||
  .modal-dialog-linked-button:last-child {
 | 
			
		||||
    border-right-width: 0px;
 | 
			
		||||
    border-radius: 0px 0px 6px 0px; }
 | 
			
		||||
  .modal-dialog-linked-button:first-child:last-child {
 | 
			
		||||
    border-right-width: 0px;
 | 
			
		||||
    border-radius: 0px 0px 6px 6px; }
 | 
			
		||||
 | 
			
		||||
/* Entries */
 | 
			
		||||
StEntry {
 | 
			
		||||
@@ -71,8 +107,8 @@ StEntry {
 | 
			
		||||
    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4);
 | 
			
		||||
    border-color: rgba(166, 166, 166, 0.5); }
 | 
			
		||||
  StEntry:insensitive {
 | 
			
		||||
    color: #7f7f7f;
 | 
			
		||||
    border-color: #0d0d0d;
 | 
			
		||||
    color: gray;
 | 
			
		||||
    border-color: #0e0e0e;
 | 
			
		||||
    box-shadow: none; }
 | 
			
		||||
  StEntry StIcon.capslock-warning {
 | 
			
		||||
    icon-size: 16px;
 | 
			
		||||
@@ -95,10 +131,10 @@ StScrollBar {
 | 
			
		||||
    background-color: transparent; }
 | 
			
		||||
  StScrollBar StButton#vhandle, StScrollBar StButton#hhandle {
 | 
			
		||||
    border-radius: 8px;
 | 
			
		||||
    background-color: #000;
 | 
			
		||||
    background-color: #999999;
 | 
			
		||||
    margin: 3px; }
 | 
			
		||||
    StScrollBar StButton#vhandle:hover, StScrollBar StButton#hhandle:hover {
 | 
			
		||||
      background-color: #1a1a1a; }
 | 
			
		||||
      background-color: #cccccc; }
 | 
			
		||||
    StScrollBar StButton#vhandle:active, StScrollBar StButton#hhandle:active {
 | 
			
		||||
      background-color: #215d9c; }
 | 
			
		||||
 | 
			
		||||
@@ -106,7 +142,7 @@ StScrollBar {
 | 
			
		||||
.slider {
 | 
			
		||||
  height: 1em;
 | 
			
		||||
  -slider-height: 0.3em;
 | 
			
		||||
  -slider-background-color: #0d0d0d;
 | 
			
		||||
  -slider-background-color: #0e0e0e;
 | 
			
		||||
  -slider-border-color: black;
 | 
			
		||||
  -slider-active-background-color: #215d9c;
 | 
			
		||||
  -slider-active-border-color: #184472;
 | 
			
		||||
@@ -160,11 +196,12 @@ StScrollBar {
 | 
			
		||||
  background-color: white; }
 | 
			
		||||
 | 
			
		||||
.modal-dialog {
 | 
			
		||||
  border-radius: 5px;
 | 
			
		||||
  border-radius: 9px;
 | 
			
		||||
  color: #eeeeec;
 | 
			
		||||
  background-color: rgba(23, 25, 26, 0.95);
 | 
			
		||||
  border: 3px solid rgba(238, 238, 236, 0.5);
 | 
			
		||||
  padding: 24px; }
 | 
			
		||||
  border: 1px solid rgba(238, 238, 236, 0.2); }
 | 
			
		||||
  .modal-dialog .modal-dialog-content-box {
 | 
			
		||||
    padding: 24px; }
 | 
			
		||||
  .modal-dialog .run-dialog-entry {
 | 
			
		||||
    width: 20em;
 | 
			
		||||
    margin-bottom: 6px; }
 | 
			
		||||
@@ -179,10 +216,6 @@ StScrollBar {
 | 
			
		||||
    color: #d6d6d1;
 | 
			
		||||
    padding-bottom: .4em; }
 | 
			
		||||
 | 
			
		||||
.button-dialog-button-box {
 | 
			
		||||
  spacing: 18px;
 | 
			
		||||
  padding-top: 48px; }
 | 
			
		||||
 | 
			
		||||
.show-processes-dialog-subject,
 | 
			
		||||
.mount-question-dialog-subject,
 | 
			
		||||
.end-session-dialog-subject {
 | 
			
		||||
@@ -191,7 +224,7 @@ StScrollBar {
 | 
			
		||||
/* End Session Dialog */
 | 
			
		||||
.end-session-dialog {
 | 
			
		||||
  spacing: 42px;
 | 
			
		||||
  border: 3px solid rgba(238, 238, 236, 0.2); }
 | 
			
		||||
  border: 1px solid rgba(238, 238, 236, 0.2); }
 | 
			
		||||
 | 
			
		||||
.end-session-dialog-list {
 | 
			
		||||
  padding-top: 20px; }
 | 
			
		||||
@@ -366,6 +399,54 @@ StScrollBar {
 | 
			
		||||
  width: 48px;
 | 
			
		||||
  height: 48px; }
 | 
			
		||||
 | 
			
		||||
/* Audio selection dialog */
 | 
			
		||||
.audio-device-selection-dialog {
 | 
			
		||||
  spacing: 30px; }
 | 
			
		||||
 | 
			
		||||
.audio-selection-content {
 | 
			
		||||
  spacing: 20px;
 | 
			
		||||
  padding: 24px; }
 | 
			
		||||
 | 
			
		||||
.audio-selection-title {
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  text-align: center; }
 | 
			
		||||
 | 
			
		||||
.audio-selection-box {
 | 
			
		||||
  spacing: 20px; }
 | 
			
		||||
 | 
			
		||||
.audio-selection-device {
 | 
			
		||||
  border: 1px solid rgba(238, 238, 236, 0.2);
 | 
			
		||||
  border-radius: 12px; }
 | 
			
		||||
  .audio-selection-device:active, .audio-selection-device:hover, .audio-selection-device:focus {
 | 
			
		||||
    background-color: #215d9c; }
 | 
			
		||||
 | 
			
		||||
.audio-selection-device-box {
 | 
			
		||||
  padding: 20px;
 | 
			
		||||
  spacing: 20px; }
 | 
			
		||||
 | 
			
		||||
.audio-selection-device-icon {
 | 
			
		||||
  icon-size: 64px; }
 | 
			
		||||
 | 
			
		||||
/* Geolocation Dialog */
 | 
			
		||||
.geolocation-dialog {
 | 
			
		||||
  spacing: 30px; }
 | 
			
		||||
 | 
			
		||||
.geolocation-dialog-main-layout {
 | 
			
		||||
  spacing: 12px; }
 | 
			
		||||
 | 
			
		||||
.geolocation-dialog-content {
 | 
			
		||||
  spacing: 20px; }
 | 
			
		||||
 | 
			
		||||
.geolocation-dialog-icon {
 | 
			
		||||
  icon-size: 48px; }
 | 
			
		||||
 | 
			
		||||
.geolocation-dialog-title {
 | 
			
		||||
  font-weight: bold; }
 | 
			
		||||
 | 
			
		||||
.geolocation-dialog-reason {
 | 
			
		||||
  color: #999999;
 | 
			
		||||
  font-weight: bold; }
 | 
			
		||||
 | 
			
		||||
/* Network Agent Dialog */
 | 
			
		||||
.network-dialog-secret-table {
 | 
			
		||||
  spacing-rows: 15px;
 | 
			
		||||
@@ -375,9 +456,9 @@ StScrollBar {
 | 
			
		||||
  spacing-rows: 15px;
 | 
			
		||||
  spacing-columns: 1em; }
 | 
			
		||||
 | 
			
		||||
/* Popvers/Menus */
 | 
			
		||||
/* Popovers/Menus */
 | 
			
		||||
.popup-menu {
 | 
			
		||||
  min-width: 200px; }
 | 
			
		||||
  min-width: 15em; }
 | 
			
		||||
  .popup-menu .popup-sub-menu {
 | 
			
		||||
    background-color: black;
 | 
			
		||||
    box-shadow: inset 0 -1px 0px #0d0d0d; }
 | 
			
		||||
@@ -411,7 +492,7 @@ StScrollBar {
 | 
			
		||||
 | 
			
		||||
.popup-menu-ornament {
 | 
			
		||||
  text-align: right;
 | 
			
		||||
  width: 1em; }
 | 
			
		||||
  width: 1.2em; }
 | 
			
		||||
 | 
			
		||||
.popup-menu-boxpointer,
 | 
			
		||||
.candidate-popup-boxpointer {
 | 
			
		||||
@@ -488,10 +569,9 @@ StScrollBar {
 | 
			
		||||
 | 
			
		||||
.switcher-arrow {
 | 
			
		||||
  border-color: transparent;
 | 
			
		||||
  color: black; }
 | 
			
		||||
 | 
			
		||||
.switcher-arrow:highlighted {
 | 
			
		||||
  color: #fff; }
 | 
			
		||||
  color: rgba(255, 255, 255, 0.8); }
 | 
			
		||||
  .switcher-arrow:highlighted {
 | 
			
		||||
    color: #fff; }
 | 
			
		||||
 | 
			
		||||
.input-source-switcher-symbol {
 | 
			
		||||
  font-size: 34pt;
 | 
			
		||||
@@ -593,6 +673,8 @@ StScrollBar {
 | 
			
		||||
  #panel .panel-status-indicators-box,
 | 
			
		||||
  #panel .panel-status-menu-box {
 | 
			
		||||
    spacing: 2px; }
 | 
			
		||||
  #panel .power-status.panel-status-indicators-box {
 | 
			
		||||
    spacing: 0; }
 | 
			
		||||
  #panel .screencast-indicator {
 | 
			
		||||
    color: #f57900; }
 | 
			
		||||
 | 
			
		||||
@@ -703,23 +785,35 @@ StScrollBar {
 | 
			
		||||
  border-left-width: 1px; }
 | 
			
		||||
 | 
			
		||||
.calendar-nonwork-day {
 | 
			
		||||
  color: #7f7f7f; }
 | 
			
		||||
  color: gray; }
 | 
			
		||||
 | 
			
		||||
.calendar-today {
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  border: 1px solid rgba(0, 0, 0, 0.5); }
 | 
			
		||||
 | 
			
		||||
.calendar-day-with-events {
 | 
			
		||||
  color: #f2f2f2;
 | 
			
		||||
  font-weight: bold; }
 | 
			
		||||
  color: white;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  background-image: url("resource:///org/gnome/shell/theme/calendar-today.svg"); }
 | 
			
		||||
 | 
			
		||||
.calendar-other-month-day {
 | 
			
		||||
  color: rgba(255, 255, 255, 0.15);
 | 
			
		||||
  opacity: 0.5; }
 | 
			
		||||
 | 
			
		||||
.calendar-week-number {
 | 
			
		||||
  font-size: 70%;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  width: 2.3em;
 | 
			
		||||
  height: 1.8em;
 | 
			
		||||
  border-radius: 2px;
 | 
			
		||||
  padding: 0.5em 0 0;
 | 
			
		||||
  margin: 6px;
 | 
			
		||||
  background-color: rgba(255, 255, 255, 0.3);
 | 
			
		||||
  color: #000; }
 | 
			
		||||
 | 
			
		||||
/* Message list */
 | 
			
		||||
.message-list {
 | 
			
		||||
  width: 420px; }
 | 
			
		||||
  width: 31.5em; }
 | 
			
		||||
 | 
			
		||||
.message-list-sections {
 | 
			
		||||
  spacing: 1.5em; }
 | 
			
		||||
@@ -754,7 +848,12 @@ StScrollBar {
 | 
			
		||||
    padding: 8px 8px 8px 0px; }
 | 
			
		||||
 | 
			
		||||
.message-icon-bin > StIcon {
 | 
			
		||||
  icon-size: 48px; }
 | 
			
		||||
  icon-size: 32px; }
 | 
			
		||||
 | 
			
		||||
.message-secondary-bin:ltr {
 | 
			
		||||
  padding-left: 8px; }
 | 
			
		||||
.message-secondary-bin:rtl {
 | 
			
		||||
  padding-right: 8px; }
 | 
			
		||||
 | 
			
		||||
.message-secondary-bin {
 | 
			
		||||
  color: #999999; }
 | 
			
		||||
@@ -763,14 +862,37 @@ StScrollBar {
 | 
			
		||||
  icon-size: 16px; }
 | 
			
		||||
 | 
			
		||||
.message-title {
 | 
			
		||||
  font-weight: bold; }
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  font-size: 1.1em; }
 | 
			
		||||
 | 
			
		||||
.message-content {
 | 
			
		||||
  padding: 8px; }
 | 
			
		||||
  padding: 8px;
 | 
			
		||||
  font-size: .9em; }
 | 
			
		||||
 | 
			
		||||
.system-switch-user-submenu-icon {
 | 
			
		||||
  icon-size: 24px;
 | 
			
		||||
  border: 1px solid rgba(255, 255, 255, 0.4); }
 | 
			
		||||
.message-media-control {
 | 
			
		||||
  padding: 6px; }
 | 
			
		||||
  .message-media-control:last-child:ltr {
 | 
			
		||||
    padding-right: 18px; }
 | 
			
		||||
  .message-media-control:last-child:rtl {
 | 
			
		||||
    padding-left: 18px; }
 | 
			
		||||
 | 
			
		||||
.media-message-cover-icon {
 | 
			
		||||
  icon-size: 32px; }
 | 
			
		||||
  .media-message-cover-icon.fallback {
 | 
			
		||||
    color: #1a1a1a;
 | 
			
		||||
    background-color: #000;
 | 
			
		||||
    border: 2px solid #000;
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
    icon-size: 16px;
 | 
			
		||||
    padding: 8px; }
 | 
			
		||||
 | 
			
		||||
.system-switch-user-submenu-icon.user-icon {
 | 
			
		||||
  icon-size: 20px;
 | 
			
		||||
  padding: 0 2px; }
 | 
			
		||||
 | 
			
		||||
.system-switch-user-submenu-icon.default-icon {
 | 
			
		||||
  icon-size: 16px;
 | 
			
		||||
  padding: 0 4px; }
 | 
			
		||||
 | 
			
		||||
#appMenu {
 | 
			
		||||
  spinner-image: url("resource:///org/gnome/shell/theme/process-working.svg");
 | 
			
		||||
@@ -779,7 +901,7 @@ StScrollBar {
 | 
			
		||||
    color: transparent; }
 | 
			
		||||
 | 
			
		||||
.aggregate-menu {
 | 
			
		||||
  width: 360px; }
 | 
			
		||||
  min-width: 21em; }
 | 
			
		||||
  .aggregate-menu .popup-menu-icon {
 | 
			
		||||
    padding: 0 4px; }
 | 
			
		||||
 | 
			
		||||
@@ -834,7 +956,8 @@ StScrollBar {
 | 
			
		||||
  min-width: 470px; }
 | 
			
		||||
 | 
			
		||||
.nm-dialog-content {
 | 
			
		||||
  spacing: 20px; }
 | 
			
		||||
  spacing: 20px;
 | 
			
		||||
  padding: 24px; }
 | 
			
		||||
 | 
			
		||||
.nm-dialog-header-hbox {
 | 
			
		||||
  spacing: 10px; }
 | 
			
		||||
@@ -915,10 +1038,14 @@ StScrollBar {
 | 
			
		||||
.search-entry {
 | 
			
		||||
  width: 320px;
 | 
			
		||||
  padding: 7px 9px;
 | 
			
		||||
  border-radius: 6px; }
 | 
			
		||||
  border-radius: 6px;
 | 
			
		||||
  border-color: #747467;
 | 
			
		||||
  color: #eeeeec;
 | 
			
		||||
  background-color: #2e3436; }
 | 
			
		||||
  .search-entry:focus {
 | 
			
		||||
    padding: 6px 8px;
 | 
			
		||||
    border-width: 2px; }
 | 
			
		||||
    border-width: 2px;
 | 
			
		||||
    border-color: #215d9c; }
 | 
			
		||||
  .search-entry .search-entry-icon {
 | 
			
		||||
    icon-size: 1em;
 | 
			
		||||
    padding: 0 4px;
 | 
			
		||||
@@ -1016,7 +1143,7 @@ StScrollBar {
 | 
			
		||||
    color: white;
 | 
			
		||||
    border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
    background-color: #222728;
 | 
			
		||||
    box-shadow: none;
 | 
			
		||||
    box-shadow: inset 0 0 black;
 | 
			
		||||
    text-shadow: none;
 | 
			
		||||
    icon-shadow: none; }
 | 
			
		||||
  .app-view-control:first-child {
 | 
			
		||||
@@ -1335,10 +1462,9 @@ StScrollBar {
 | 
			
		||||
  color: white; }
 | 
			
		||||
  .keyboard-key:focus {
 | 
			
		||||
    color: #eeeeec;
 | 
			
		||||
    border-color: #215d9c;
 | 
			
		||||
    box-shadow: inset 0 1px #454f52;
 | 
			
		||||
    text-shadow: 0 1px black;
 | 
			
		||||
    icon-shadow: 0 1px black; }
 | 
			
		||||
    icon-shadow: 0 1px black;
 | 
			
		||||
    box-shadow: inset 0px 0px 0px 1px #215d9c; }
 | 
			
		||||
  .keyboard-key:hover, .keyboard-key:checked {
 | 
			
		||||
    color: white;
 | 
			
		||||
    border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
@@ -1350,7 +1476,7 @@ StScrollBar {
 | 
			
		||||
    color: white;
 | 
			
		||||
    border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
    background-color: #222728;
 | 
			
		||||
    box-shadow: none;
 | 
			
		||||
    box-shadow: inset 0 0 black;
 | 
			
		||||
    text-shadow: none;
 | 
			
		||||
    icon-shadow: none; }
 | 
			
		||||
  .keyboard-key:grayed {
 | 
			
		||||
@@ -1443,13 +1569,13 @@ StScrollBar {
 | 
			
		||||
        color: white;
 | 
			
		||||
        border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
        background-color: #1c5187;
 | 
			
		||||
        box-shadow: none;
 | 
			
		||||
        box-shadow: inset 0 0 black;
 | 
			
		||||
        text-shadow: none;
 | 
			
		||||
        icon-shadow: none; }
 | 
			
		||||
      .login-dialog .modal-dialog-button:default:insensitive {
 | 
			
		||||
        color: #7f7f7f;
 | 
			
		||||
        color: gray;
 | 
			
		||||
        border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
        background-color: rgba(62, 67, 68, 0.7);
 | 
			
		||||
        background-color: rgba(62, 67, 69, 0.7);
 | 
			
		||||
        box-shadow: none;
 | 
			
		||||
        text-shadow: none;
 | 
			
		||||
        icon-shadow: none; }
 | 
			
		||||
@@ -1696,3 +1822,11 @@ StScrollBar {
 | 
			
		||||
 | 
			
		||||
stage {
 | 
			
		||||
  -st-icon-style: symbolic; }
 | 
			
		||||
 | 
			
		||||
.toggle-switch {
 | 
			
		||||
  width: 48px; }
 | 
			
		||||
 | 
			
		||||
.toggle-switch-us, .toggle-switch-intl {
 | 
			
		||||
  background-image: url("resource:///org/gnome/shell/theme/toggle-off-hc.svg"); }
 | 
			
		||||
  .toggle-switch-us:checked, .toggle-switch-intl:checked {
 | 
			
		||||
    background-image: url("resource:///org/gnome/shell/theme/toggle-on-hc.svg"); }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,3 +6,9 @@
 | 
			
		||||
stage {
 | 
			
		||||
  -st-icon-style: symbolic;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.toggle-switch { width: 48px; }
 | 
			
		||||
.toggle-switch-us, .toggle-switch-intl {
 | 
			
		||||
  background-image: url("resource:///org/gnome/shell/theme/toggle-off-hc.svg");
 | 
			
		||||
  &:checked { background-image: url("resource:///org/gnome/shell/theme/toggle-on-hc.svg"); }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -37,14 +37,13 @@ stage {
 | 
			
		||||
  icon-shadow: 0 1px black; }
 | 
			
		||||
  .button:focus {
 | 
			
		||||
    color: #eeeeec;
 | 
			
		||||
    border-color: #215d9c;
 | 
			
		||||
    box-shadow: inset 0 1px #454f52;
 | 
			
		||||
    text-shadow: 0 1px black;
 | 
			
		||||
    icon-shadow: 0 1px black; }
 | 
			
		||||
    icon-shadow: 0 1px black;
 | 
			
		||||
    box-shadow: inset 0px 0px 0px 1px #215d9c; }
 | 
			
		||||
  .button:insensitive {
 | 
			
		||||
    color: #939695;
 | 
			
		||||
    color: #949796;
 | 
			
		||||
    border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
    background-color: rgba(66, 71, 73, 0.7);
 | 
			
		||||
    background-color: rgba(66, 72, 73, 0.7);
 | 
			
		||||
    box-shadow: none;
 | 
			
		||||
    text-shadow: none;
 | 
			
		||||
    icon-shadow: none; }
 | 
			
		||||
@@ -52,9 +51,46 @@ stage {
 | 
			
		||||
    color: white;
 | 
			
		||||
    border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
    background-color: #222728;
 | 
			
		||||
    box-shadow: inset 0 0 black;
 | 
			
		||||
    text-shadow: none;
 | 
			
		||||
    icon-shadow: none; }
 | 
			
		||||
 | 
			
		||||
.modal-dialog-linked-button {
 | 
			
		||||
  border-right-width: 1px;
 | 
			
		||||
  color: #eeeeec;
 | 
			
		||||
  background-color: #2e3436;
 | 
			
		||||
  border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
  box-shadow: inset 0 1px #454f52;
 | 
			
		||||
  text-shadow: 0 1px black;
 | 
			
		||||
  icon-shadow: 0 1px black;
 | 
			
		||||
  padding: 12px; }
 | 
			
		||||
  .modal-dialog-linked-button:insensitive {
 | 
			
		||||
    color: #949796;
 | 
			
		||||
    border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
    background-color: rgba(66, 72, 73, 0.7);
 | 
			
		||||
    box-shadow: none;
 | 
			
		||||
    text-shadow: none;
 | 
			
		||||
    icon-shadow: none; }
 | 
			
		||||
  .modal-dialog-linked-button:active {
 | 
			
		||||
    color: white;
 | 
			
		||||
    border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
    background-color: #222728;
 | 
			
		||||
    box-shadow: inset 0 0 black;
 | 
			
		||||
    text-shadow: none;
 | 
			
		||||
    icon-shadow: none; }
 | 
			
		||||
  .modal-dialog-linked-button:focus {
 | 
			
		||||
    color: #eeeeec;
 | 
			
		||||
    text-shadow: 0 1px black;
 | 
			
		||||
    icon-shadow: 0 1px black;
 | 
			
		||||
    box-shadow: inset 0px 0px 0px 1px #215d9c; }
 | 
			
		||||
  .modal-dialog-linked-button:first-child {
 | 
			
		||||
    border-radius: 0px 0px 0px 6px; }
 | 
			
		||||
  .modal-dialog-linked-button:last-child {
 | 
			
		||||
    border-right-width: 0px;
 | 
			
		||||
    border-radius: 0px 0px 6px 0px; }
 | 
			
		||||
  .modal-dialog-linked-button:first-child:last-child {
 | 
			
		||||
    border-right-width: 0px;
 | 
			
		||||
    border-radius: 0px 0px 6px 6px; }
 | 
			
		||||
 | 
			
		||||
/* Entries */
 | 
			
		||||
StEntry {
 | 
			
		||||
@@ -71,8 +107,8 @@ StEntry {
 | 
			
		||||
    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4);
 | 
			
		||||
    border-color: rgba(154, 154, 142, 0.5); }
 | 
			
		||||
  StEntry:insensitive {
 | 
			
		||||
    color: #939695;
 | 
			
		||||
    border-color: #323636;
 | 
			
		||||
    color: #949796;
 | 
			
		||||
    border-color: #333636;
 | 
			
		||||
    box-shadow: none; }
 | 
			
		||||
  StEntry StIcon.capslock-warning {
 | 
			
		||||
    icon-size: 16px;
 | 
			
		||||
@@ -95,10 +131,10 @@ StScrollBar {
 | 
			
		||||
    background-color: transparent; }
 | 
			
		||||
  StScrollBar StButton#vhandle, StScrollBar StButton#hhandle {
 | 
			
		||||
    border-radius: 8px;
 | 
			
		||||
    background-color: #393f3f;
 | 
			
		||||
    background-color: #a6a8a7;
 | 
			
		||||
    margin: 3px; }
 | 
			
		||||
    StScrollBar StButton#vhandle:hover, StScrollBar StButton#hhandle:hover {
 | 
			
		||||
      background-color: #515a5a; }
 | 
			
		||||
      background-color: #cacbc9; }
 | 
			
		||||
    StScrollBar StButton#vhandle:active, StScrollBar StButton#hhandle:active {
 | 
			
		||||
      background-color: #215d9c; }
 | 
			
		||||
 | 
			
		||||
@@ -106,7 +142,7 @@ StScrollBar {
 | 
			
		||||
.slider {
 | 
			
		||||
  height: 1em;
 | 
			
		||||
  -slider-height: 0.3em;
 | 
			
		||||
  -slider-background-color: #323636;
 | 
			
		||||
  -slider-background-color: #333636;
 | 
			
		||||
  -slider-border-color: #1c1f1f;
 | 
			
		||||
  -slider-active-background-color: #215d9c;
 | 
			
		||||
  -slider-active-border-color: #184472;
 | 
			
		||||
@@ -160,11 +196,12 @@ StScrollBar {
 | 
			
		||||
  background-color: white; }
 | 
			
		||||
 | 
			
		||||
.modal-dialog {
 | 
			
		||||
  border-radius: 5px;
 | 
			
		||||
  border-radius: 9px;
 | 
			
		||||
  color: #eeeeec;
 | 
			
		||||
  background-color: rgba(23, 25, 26, 0.95);
 | 
			
		||||
  border: 3px solid rgba(238, 238, 236, 0.5);
 | 
			
		||||
  padding: 24px; }
 | 
			
		||||
  border: 1px solid rgba(238, 238, 236, 0.2); }
 | 
			
		||||
  .modal-dialog .modal-dialog-content-box {
 | 
			
		||||
    padding: 24px; }
 | 
			
		||||
  .modal-dialog .run-dialog-entry {
 | 
			
		||||
    width: 20em;
 | 
			
		||||
    margin-bottom: 6px; }
 | 
			
		||||
@@ -179,10 +216,6 @@ StScrollBar {
 | 
			
		||||
    color: #d6d6d1;
 | 
			
		||||
    padding-bottom: .4em; }
 | 
			
		||||
 | 
			
		||||
.button-dialog-button-box {
 | 
			
		||||
  spacing: 18px;
 | 
			
		||||
  padding-top: 48px; }
 | 
			
		||||
 | 
			
		||||
.show-processes-dialog-subject,
 | 
			
		||||
.mount-question-dialog-subject,
 | 
			
		||||
.end-session-dialog-subject {
 | 
			
		||||
@@ -191,7 +224,7 @@ StScrollBar {
 | 
			
		||||
/* End Session Dialog */
 | 
			
		||||
.end-session-dialog {
 | 
			
		||||
  spacing: 42px;
 | 
			
		||||
  border: 3px solid rgba(238, 238, 236, 0.2); }
 | 
			
		||||
  border: 1px solid rgba(238, 238, 236, 0.2); }
 | 
			
		||||
 | 
			
		||||
.end-session-dialog-list {
 | 
			
		||||
  padding-top: 20px; }
 | 
			
		||||
@@ -366,6 +399,54 @@ StScrollBar {
 | 
			
		||||
  width: 48px;
 | 
			
		||||
  height: 48px; }
 | 
			
		||||
 | 
			
		||||
/* Audio selection dialog */
 | 
			
		||||
.audio-device-selection-dialog {
 | 
			
		||||
  spacing: 30px; }
 | 
			
		||||
 | 
			
		||||
.audio-selection-content {
 | 
			
		||||
  spacing: 20px;
 | 
			
		||||
  padding: 24px; }
 | 
			
		||||
 | 
			
		||||
.audio-selection-title {
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  text-align: center; }
 | 
			
		||||
 | 
			
		||||
.audio-selection-box {
 | 
			
		||||
  spacing: 20px; }
 | 
			
		||||
 | 
			
		||||
.audio-selection-device {
 | 
			
		||||
  border: 1px solid rgba(238, 238, 236, 0.2);
 | 
			
		||||
  border-radius: 12px; }
 | 
			
		||||
  .audio-selection-device:active, .audio-selection-device:hover, .audio-selection-device:focus {
 | 
			
		||||
    background-color: #215d9c; }
 | 
			
		||||
 | 
			
		||||
.audio-selection-device-box {
 | 
			
		||||
  padding: 20px;
 | 
			
		||||
  spacing: 20px; }
 | 
			
		||||
 | 
			
		||||
.audio-selection-device-icon {
 | 
			
		||||
  icon-size: 64px; }
 | 
			
		||||
 | 
			
		||||
/* Geolocation Dialog */
 | 
			
		||||
.geolocation-dialog {
 | 
			
		||||
  spacing: 30px; }
 | 
			
		||||
 | 
			
		||||
.geolocation-dialog-main-layout {
 | 
			
		||||
  spacing: 12px; }
 | 
			
		||||
 | 
			
		||||
.geolocation-dialog-content {
 | 
			
		||||
  spacing: 20px; }
 | 
			
		||||
 | 
			
		||||
.geolocation-dialog-icon {
 | 
			
		||||
  icon-size: 48px; }
 | 
			
		||||
 | 
			
		||||
.geolocation-dialog-title {
 | 
			
		||||
  font-weight: bold; }
 | 
			
		||||
 | 
			
		||||
.geolocation-dialog-reason {
 | 
			
		||||
  color: #8e8e80;
 | 
			
		||||
  font-weight: bold; }
 | 
			
		||||
 | 
			
		||||
/* Network Agent Dialog */
 | 
			
		||||
.network-dialog-secret-table {
 | 
			
		||||
  spacing-rows: 15px;
 | 
			
		||||
@@ -375,9 +456,9 @@ StScrollBar {
 | 
			
		||||
  spacing-rows: 15px;
 | 
			
		||||
  spacing-columns: 1em; }
 | 
			
		||||
 | 
			
		||||
/* Popvers/Menus */
 | 
			
		||||
/* Popovers/Menus */
 | 
			
		||||
.popup-menu {
 | 
			
		||||
  min-width: 200px; }
 | 
			
		||||
  min-width: 15em; }
 | 
			
		||||
  .popup-menu .popup-sub-menu {
 | 
			
		||||
    background-color: #343a3a;
 | 
			
		||||
    box-shadow: inset 0 -1px 0px #282c2c; }
 | 
			
		||||
@@ -411,7 +492,7 @@ StScrollBar {
 | 
			
		||||
 | 
			
		||||
.popup-menu-ornament {
 | 
			
		||||
  text-align: right;
 | 
			
		||||
  width: 1em; }
 | 
			
		||||
  width: 1.2em; }
 | 
			
		||||
 | 
			
		||||
.popup-menu-boxpointer,
 | 
			
		||||
.candidate-popup-boxpointer {
 | 
			
		||||
@@ -488,10 +569,9 @@ StScrollBar {
 | 
			
		||||
 | 
			
		||||
.switcher-arrow {
 | 
			
		||||
  border-color: transparent;
 | 
			
		||||
  color: #1c1f1f; }
 | 
			
		||||
 | 
			
		||||
.switcher-arrow:highlighted {
 | 
			
		||||
  color: #eeeeec; }
 | 
			
		||||
  color: rgba(238, 238, 236, 0.8); }
 | 
			
		||||
  .switcher-arrow:highlighted {
 | 
			
		||||
    color: #eeeeec; }
 | 
			
		||||
 | 
			
		||||
.input-source-switcher-symbol {
 | 
			
		||||
  font-size: 34pt;
 | 
			
		||||
@@ -593,6 +673,8 @@ StScrollBar {
 | 
			
		||||
  #panel .panel-status-indicators-box,
 | 
			
		||||
  #panel .panel-status-menu-box {
 | 
			
		||||
    spacing: 2px; }
 | 
			
		||||
  #panel .power-status.panel-status-indicators-box {
 | 
			
		||||
    spacing: 0; }
 | 
			
		||||
  #panel .screencast-indicator {
 | 
			
		||||
    color: #f57900; }
 | 
			
		||||
 | 
			
		||||
@@ -703,23 +785,35 @@ StScrollBar {
 | 
			
		||||
  border-left-width: 1px; }
 | 
			
		||||
 | 
			
		||||
.calendar-nonwork-day {
 | 
			
		||||
  color: #939695; }
 | 
			
		||||
  color: #949796; }
 | 
			
		||||
 | 
			
		||||
.calendar-today {
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  border: 1px solid rgba(28, 31, 31, 0.5); }
 | 
			
		||||
 | 
			
		||||
.calendar-day-with-events {
 | 
			
		||||
  color: #e2e2df;
 | 
			
		||||
  font-weight: bold; }
 | 
			
		||||
  color: white;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  background-image: url("resource:///org/gnome/shell/theme/calendar-today.svg"); }
 | 
			
		||||
 | 
			
		||||
.calendar-other-month-day {
 | 
			
		||||
  color: rgba(238, 238, 236, 0.15);
 | 
			
		||||
  opacity: 0.5; }
 | 
			
		||||
 | 
			
		||||
.calendar-week-number {
 | 
			
		||||
  font-size: 70%;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  width: 2.3em;
 | 
			
		||||
  height: 1.8em;
 | 
			
		||||
  border-radius: 2px;
 | 
			
		||||
  padding: 0.5em 0 0;
 | 
			
		||||
  margin: 6px;
 | 
			
		||||
  background-color: rgba(238, 238, 236, 0.3);
 | 
			
		||||
  color: #393f3f; }
 | 
			
		||||
 | 
			
		||||
/* Message list */
 | 
			
		||||
.message-list {
 | 
			
		||||
  width: 420px; }
 | 
			
		||||
  width: 31.5em; }
 | 
			
		||||
 | 
			
		||||
.message-list-sections {
 | 
			
		||||
  spacing: 1.5em; }
 | 
			
		||||
@@ -754,7 +848,12 @@ StScrollBar {
 | 
			
		||||
    padding: 8px 8px 8px 0px; }
 | 
			
		||||
 | 
			
		||||
.message-icon-bin > StIcon {
 | 
			
		||||
  icon-size: 48px; }
 | 
			
		||||
  icon-size: 32px; }
 | 
			
		||||
 | 
			
		||||
.message-secondary-bin:ltr {
 | 
			
		||||
  padding-left: 8px; }
 | 
			
		||||
.message-secondary-bin:rtl {
 | 
			
		||||
  padding-right: 8px; }
 | 
			
		||||
 | 
			
		||||
.message-secondary-bin {
 | 
			
		||||
  color: #8e8e80; }
 | 
			
		||||
@@ -763,14 +862,37 @@ StScrollBar {
 | 
			
		||||
  icon-size: 16px; }
 | 
			
		||||
 | 
			
		||||
.message-title {
 | 
			
		||||
  font-weight: bold; }
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  font-size: 1.1em; }
 | 
			
		||||
 | 
			
		||||
.message-content {
 | 
			
		||||
  padding: 8px; }
 | 
			
		||||
  padding: 8px;
 | 
			
		||||
  font-size: .9em; }
 | 
			
		||||
 | 
			
		||||
.system-switch-user-submenu-icon {
 | 
			
		||||
  icon-size: 24px;
 | 
			
		||||
  border: 1px solid rgba(238, 238, 236, 0.4); }
 | 
			
		||||
.message-media-control {
 | 
			
		||||
  padding: 6px; }
 | 
			
		||||
  .message-media-control:last-child:ltr {
 | 
			
		||||
    padding-right: 18px; }
 | 
			
		||||
  .message-media-control:last-child:rtl {
 | 
			
		||||
    padding-left: 18px; }
 | 
			
		||||
 | 
			
		||||
.media-message-cover-icon {
 | 
			
		||||
  icon-size: 32px; }
 | 
			
		||||
  .media-message-cover-icon.fallback {
 | 
			
		||||
    color: #515a5a;
 | 
			
		||||
    background-color: #393f3f;
 | 
			
		||||
    border: 2px solid #393f3f;
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
    icon-size: 16px;
 | 
			
		||||
    padding: 8px; }
 | 
			
		||||
 | 
			
		||||
.system-switch-user-submenu-icon.user-icon {
 | 
			
		||||
  icon-size: 20px;
 | 
			
		||||
  padding: 0 2px; }
 | 
			
		||||
 | 
			
		||||
.system-switch-user-submenu-icon.default-icon {
 | 
			
		||||
  icon-size: 16px;
 | 
			
		||||
  padding: 0 4px; }
 | 
			
		||||
 | 
			
		||||
#appMenu {
 | 
			
		||||
  spinner-image: url("resource:///org/gnome/shell/theme/process-working.svg");
 | 
			
		||||
@@ -779,7 +901,7 @@ StScrollBar {
 | 
			
		||||
    color: transparent; }
 | 
			
		||||
 | 
			
		||||
.aggregate-menu {
 | 
			
		||||
  width: 360px; }
 | 
			
		||||
  min-width: 21em; }
 | 
			
		||||
  .aggregate-menu .popup-menu-icon {
 | 
			
		||||
    padding: 0 4px; }
 | 
			
		||||
 | 
			
		||||
@@ -834,7 +956,8 @@ StScrollBar {
 | 
			
		||||
  min-width: 470px; }
 | 
			
		||||
 | 
			
		||||
.nm-dialog-content {
 | 
			
		||||
  spacing: 20px; }
 | 
			
		||||
  spacing: 20px;
 | 
			
		||||
  padding: 24px; }
 | 
			
		||||
 | 
			
		||||
.nm-dialog-header-hbox {
 | 
			
		||||
  spacing: 10px; }
 | 
			
		||||
@@ -915,10 +1038,14 @@ StScrollBar {
 | 
			
		||||
.search-entry {
 | 
			
		||||
  width: 320px;
 | 
			
		||||
  padding: 7px 9px;
 | 
			
		||||
  border-radius: 6px; }
 | 
			
		||||
  border-radius: 6px;
 | 
			
		||||
  border-color: #747467;
 | 
			
		||||
  color: #eeeeec;
 | 
			
		||||
  background-color: #2e3436; }
 | 
			
		||||
  .search-entry:focus {
 | 
			
		||||
    padding: 6px 8px;
 | 
			
		||||
    border-width: 2px; }
 | 
			
		||||
    border-width: 2px;
 | 
			
		||||
    border-color: #215d9c; }
 | 
			
		||||
  .search-entry .search-entry-icon {
 | 
			
		||||
    icon-size: 1em;
 | 
			
		||||
    padding: 0 4px;
 | 
			
		||||
@@ -1016,7 +1143,7 @@ StScrollBar {
 | 
			
		||||
    color: white;
 | 
			
		||||
    border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
    background-color: #222728;
 | 
			
		||||
    box-shadow: none;
 | 
			
		||||
    box-shadow: inset 0 0 black;
 | 
			
		||||
    text-shadow: none;
 | 
			
		||||
    icon-shadow: none; }
 | 
			
		||||
  .app-view-control:first-child {
 | 
			
		||||
@@ -1335,10 +1462,9 @@ StScrollBar {
 | 
			
		||||
  color: white; }
 | 
			
		||||
  .keyboard-key:focus {
 | 
			
		||||
    color: #eeeeec;
 | 
			
		||||
    border-color: #215d9c;
 | 
			
		||||
    box-shadow: inset 0 1px #454f52;
 | 
			
		||||
    text-shadow: 0 1px black;
 | 
			
		||||
    icon-shadow: 0 1px black; }
 | 
			
		||||
    icon-shadow: 0 1px black;
 | 
			
		||||
    box-shadow: inset 0px 0px 0px 1px #215d9c; }
 | 
			
		||||
  .keyboard-key:hover, .keyboard-key:checked {
 | 
			
		||||
    color: white;
 | 
			
		||||
    border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
@@ -1350,7 +1476,7 @@ StScrollBar {
 | 
			
		||||
    color: white;
 | 
			
		||||
    border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
    background-color: #222728;
 | 
			
		||||
    box-shadow: none;
 | 
			
		||||
    box-shadow: inset 0 0 black;
 | 
			
		||||
    text-shadow: none;
 | 
			
		||||
    icon-shadow: none; }
 | 
			
		||||
  .keyboard-key:grayed {
 | 
			
		||||
@@ -1443,13 +1569,13 @@ StScrollBar {
 | 
			
		||||
        color: white;
 | 
			
		||||
        border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
        background-color: #1c5187;
 | 
			
		||||
        box-shadow: none;
 | 
			
		||||
        box-shadow: inset 0 0 black;
 | 
			
		||||
        text-shadow: none;
 | 
			
		||||
        icon-shadow: none; }
 | 
			
		||||
      .login-dialog .modal-dialog-button:default:insensitive {
 | 
			
		||||
        color: #939695;
 | 
			
		||||
        color: #949796;
 | 
			
		||||
        border-color: rgba(0, 0, 0, 0.7);
 | 
			
		||||
        background-color: rgba(66, 71, 73, 0.7);
 | 
			
		||||
        background-color: rgba(66, 72, 73, 0.7);
 | 
			
		||||
        box-shadow: none;
 | 
			
		||||
        text-shadow: none;
 | 
			
		||||
        icon-shadow: none; }
 | 
			
		||||
 
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 98 KiB  | 
							
								
								
									
										133
									
								
								data/theme/toggle-off-hc.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,133 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
 | 
			
		||||
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   width="48"
 | 
			
		||||
   height="22"
 | 
			
		||||
   id="svg2857"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.91 r13725"
 | 
			
		||||
   sodipodi:docname="toggle-off-hc.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs2859">
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       sodipodi:type="inkscape:persp3d"
 | 
			
		||||
       inkscape:vp_x="0 : 526.18109 : 1"
 | 
			
		||||
       inkscape:vp_y="0 : 1000 : 0"
 | 
			
		||||
       inkscape:vp_z="744.09448 : 526.18109 : 1"
 | 
			
		||||
       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
 | 
			
		||||
       id="perspective2865" />
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       id="perspective2843"
 | 
			
		||||
       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
 | 
			
		||||
       inkscape:vp_z="1 : 0.5 : 1"
 | 
			
		||||
       inkscape:vp_y="0 : 1000 : 0"
 | 
			
		||||
       inkscape:vp_x="0 : 0.5 : 1"
 | 
			
		||||
       sodipodi:type="inkscape:persp3d" />
 | 
			
		||||
    <inkscape:path-effect
 | 
			
		||||
       effect="spiro"
 | 
			
		||||
       id="path-effect77541-4"
 | 
			
		||||
       is_visible="true" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#000000"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="1"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="1"
 | 
			
		||||
     inkscape:cx="-6.1820581"
 | 
			
		||||
     inkscape:cy="-16.463788"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:current-layer="g37994"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:window-width="2560"
 | 
			
		||||
     inkscape:window-height="1364"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="27"
 | 
			
		||||
     inkscape:window-maximized="1"
 | 
			
		||||
     borderlayer="true"
 | 
			
		||||
     inkscape:showpageshadow="false"
 | 
			
		||||
     inkscape:snap-nodes="false"
 | 
			
		||||
     inkscape:snap-bbox="true"
 | 
			
		||||
     showborder="true">
 | 
			
		||||
    <inkscape:grid
 | 
			
		||||
       type="xygrid"
 | 
			
		||||
       id="grid12954"
 | 
			
		||||
       empspacing="5"
 | 
			
		||||
       visible="true"
 | 
			
		||||
       enabled="true"
 | 
			
		||||
       snapvisiblegridlinesonly="true" />
 | 
			
		||||
  </sodipodi:namedview>
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata2862">
 | 
			
		||||
    <rdf:RDF>
 | 
			
		||||
      <cc:Work
 | 
			
		||||
         rdf:about="">
 | 
			
		||||
        <dc:format>image/svg+xml</dc:format>
 | 
			
		||||
        <dc:type
 | 
			
		||||
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
 | 
			
		||||
        <dc:title></dc:title>
 | 
			
		||||
      </cc:Work>
 | 
			
		||||
    </rdf:RDF>
 | 
			
		||||
  </metadata>
 | 
			
		||||
  <g
 | 
			
		||||
     inkscape:label="Layer 1"
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     transform="translate(-444.64286,-781.36218)">
 | 
			
		||||
    <g
 | 
			
		||||
       transform="matrix(0.6526046,0,0,0.80554422,99.592644,-636.32172)"
 | 
			
		||||
       id="g37994">
 | 
			
		||||
      <g
 | 
			
		||||
         transform="matrix(1.5323214,0,0,1.2413968,-324.76058,489.69039)"
 | 
			
		||||
         id="toggle-off"
 | 
			
		||||
         inkscape:label="#g8477">
 | 
			
		||||
        <circle
 | 
			
		||||
           cy="1033.993"
 | 
			
		||||
           cx="571.95966"
 | 
			
		||||
           id="path8444"
 | 
			
		||||
           style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#555753;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
 | 
			
		||||
           r="7" />
 | 
			
		||||
        <rect
 | 
			
		||||
           ry="2.0108337"
 | 
			
		||||
           rx="1.9562569"
 | 
			
		||||
           y="1031.9885"
 | 
			
		||||
           x="565.0083"
 | 
			
		||||
           height="4.0216675"
 | 
			
		||||
           width="34.850178"
 | 
			
		||||
           id="rect8461"
 | 
			
		||||
           style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#555753;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
 | 
			
		||||
      </g>
 | 
			
		||||
      <g
 | 
			
		||||
         transform="matrix(1.5323214,0,0,1.2413968,-324.85635,491.16456)"
 | 
			
		||||
         id="toggle-on"
 | 
			
		||||
         inkscape:label="#g8481">
 | 
			
		||||
        <rect
 | 
			
		||||
           style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#3465a4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
 | 
			
		||||
           id="rect8475"
 | 
			
		||||
           width="34.850178"
 | 
			
		||||
           height="4.0216675"
 | 
			
		||||
           x="565.0083"
 | 
			
		||||
           y="1070.9279"
 | 
			
		||||
           rx="1.9562569"
 | 
			
		||||
           ry="2.0108337" />
 | 
			
		||||
        <circle
 | 
			
		||||
           transform="scale(-1,1)"
 | 
			
		||||
           style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#3465a4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
 | 
			
		||||
           id="circle8463"
 | 
			
		||||
           cx="-591.0213"
 | 
			
		||||
           cy="1072.9402"
 | 
			
		||||
           r="9" />
 | 
			
		||||
      </g>
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 6.1 KiB  | 
							
								
								
									
										113
									
								
								data/theme/toggle-on-hc.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,113 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
 | 
			
		||||
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   width="48"
 | 
			
		||||
   height="22"
 | 
			
		||||
   id="svg2857"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.91 r13725"
 | 
			
		||||
   sodipodi:docname="toggle-on-hc.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs2859">
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       sodipodi:type="inkscape:persp3d"
 | 
			
		||||
       inkscape:vp_x="0 : 526.18109 : 1"
 | 
			
		||||
       inkscape:vp_y="0 : 1000 : 0"
 | 
			
		||||
       inkscape:vp_z="744.09448 : 526.18109 : 1"
 | 
			
		||||
       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
 | 
			
		||||
       id="perspective2865" />
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       id="perspective2843"
 | 
			
		||||
       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
 | 
			
		||||
       inkscape:vp_z="1 : 0.5 : 1"
 | 
			
		||||
       inkscape:vp_y="0 : 1000 : 0"
 | 
			
		||||
       inkscape:vp_x="0 : 0.5 : 1"
 | 
			
		||||
       sodipodi:type="inkscape:persp3d" />
 | 
			
		||||
    <inkscape:path-effect
 | 
			
		||||
       effect="spiro"
 | 
			
		||||
       id="path-effect77541-4"
 | 
			
		||||
       is_visible="true" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#000000"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="1"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="1"
 | 
			
		||||
     inkscape:cx="-222.95215"
 | 
			
		||||
     inkscape:cy="3.9378433"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:current-layer="g37994"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:window-width="2560"
 | 
			
		||||
     inkscape:window-height="1364"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="27"
 | 
			
		||||
     inkscape:window-maximized="1"
 | 
			
		||||
     borderlayer="true"
 | 
			
		||||
     inkscape:showpageshadow="false"
 | 
			
		||||
     inkscape:snap-nodes="false"
 | 
			
		||||
     inkscape:snap-bbox="true"
 | 
			
		||||
     showborder="true">
 | 
			
		||||
    <inkscape:grid
 | 
			
		||||
       type="xygrid"
 | 
			
		||||
       id="grid12954"
 | 
			
		||||
       empspacing="5"
 | 
			
		||||
       visible="true"
 | 
			
		||||
       enabled="true"
 | 
			
		||||
       snapvisiblegridlinesonly="true" />
 | 
			
		||||
  </sodipodi:namedview>
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata2862">
 | 
			
		||||
    <rdf:RDF>
 | 
			
		||||
      <cc:Work
 | 
			
		||||
         rdf:about="">
 | 
			
		||||
        <dc:format>image/svg+xml</dc:format>
 | 
			
		||||
        <dc:type
 | 
			
		||||
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
 | 
			
		||||
        <dc:title></dc:title>
 | 
			
		||||
      </cc:Work>
 | 
			
		||||
    </rdf:RDF>
 | 
			
		||||
  </metadata>
 | 
			
		||||
  <g
 | 
			
		||||
     inkscape:label="Layer 1"
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     transform="translate(-444.64286,-781.36218)">
 | 
			
		||||
    <g
 | 
			
		||||
       transform="matrix(0.6526046,0,0,0.80554422,99.592644,-636.32172)"
 | 
			
		||||
       id="g37994">
 | 
			
		||||
      <g
 | 
			
		||||
         transform="matrix(1.5323214,0,0,1.2413968,-324.85635,441.50868)"
 | 
			
		||||
         id="toggle-on"
 | 
			
		||||
         inkscape:label="#g8481">
 | 
			
		||||
        <rect
 | 
			
		||||
           style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#3465a4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
 | 
			
		||||
           id="rect8475"
 | 
			
		||||
           width="34.850178"
 | 
			
		||||
           height="4.0216675"
 | 
			
		||||
           x="565.0083"
 | 
			
		||||
           y="1070.9279"
 | 
			
		||||
           rx="1.9562569"
 | 
			
		||||
           ry="2.0108337" />
 | 
			
		||||
        <circle
 | 
			
		||||
           transform="scale(-1,1)"
 | 
			
		||||
           style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#3465a4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
 | 
			
		||||
           id="circle8463"
 | 
			
		||||
           cx="-591.0213"
 | 
			
		||||
           cy="1072.9402"
 | 
			
		||||
           r="9" />
 | 
			
		||||
      </g>
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 4.4 KiB  | 
@@ -14,7 +14,7 @@
 | 
			
		||||
   height="22"
 | 
			
		||||
   id="svg2857"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.48.5 r10040"
 | 
			
		||||
   inkscape:version="0.91 r13725"
 | 
			
		||||
   sodipodi:docname="toggle-on-intl.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs2859">
 | 
			
		||||
@@ -52,7 +52,7 @@
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop77465"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         style="stop-color:#204a87;stop-opacity:1" />
 | 
			
		||||
         style="stop-color:#205b9a;stop-opacity:1" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
@@ -88,14 +88,14 @@
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="1"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="32"
 | 
			
		||||
     inkscape:cx="17.255148"
 | 
			
		||||
     inkscape:cy="8.9252639"
 | 
			
		||||
     inkscape:zoom="1"
 | 
			
		||||
     inkscape:cx="37.410841"
 | 
			
		||||
     inkscape:cy="16.009314"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:current-layer="g37994"
 | 
			
		||||
     showgrid="true"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:window-width="2560"
 | 
			
		||||
     inkscape:window-height="1375"
 | 
			
		||||
     inkscape:window-height="1376"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="27"
 | 
			
		||||
     inkscape:window-maximized="1"
 | 
			
		||||
 
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB  | 
@@ -14,7 +14,7 @@
 | 
			
		||||
   height="22"
 | 
			
		||||
   id="svg2857"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.48.5 r10040"
 | 
			
		||||
   inkscape:version="0.91 r13725"
 | 
			
		||||
   sodipodi:docname="toggle-on-us.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs2859">
 | 
			
		||||
@@ -32,28 +32,6 @@
 | 
			
		||||
       inkscape:vp_y="0 : 1000 : 0"
 | 
			
		||||
       inkscape:vp_x="0 : 0.5 : 1"
 | 
			
		||||
       sodipodi:type="inkscape:persp3d" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       xlink:href="#linearGradient77461"
 | 
			
		||||
       id="linearGradient77551"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       gradientTransform="matrix(1.3066667,0,0,1,-841.64667,-483)"
 | 
			
		||||
       x1="1164.7644"
 | 
			
		||||
       y1="962.93695"
 | 
			
		||||
       x2="1164.7644"
 | 
			
		||||
       y2="970.51404" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       id="linearGradient77461"
 | 
			
		||||
       inkscape:collect="always">
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop77463"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         style="stop-color:#182f4c;stop-opacity:1" />
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop77465"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         style="stop-color:#204a87;stop-opacity:1" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       xlink:href="#linearGradient76469-7-7-4"
 | 
			
		||||
@@ -80,6 +58,38 @@
 | 
			
		||||
       effect="spiro"
 | 
			
		||||
       id="path-effect77541-4"
 | 
			
		||||
       is_visible="true" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       id="linearGradient77461-1"
 | 
			
		||||
       inkscape:collect="always">
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop77463-1"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         style="stop-color:#182f4c;stop-opacity:1" />
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop77465-4"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         style="stop-color:#205b9a;stop-opacity:1" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       xlink:href="#linearGradient77461-1"
 | 
			
		||||
       id="linearGradient77551-6-5"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       gradientTransform="matrix(0.8527367,0,0,0.80554422,-969.41608,-778.00299)"
 | 
			
		||||
       x1="1164.7644"
 | 
			
		||||
       y1="962.93695"
 | 
			
		||||
       x2="1164.7644"
 | 
			
		||||
       y2="970.51404" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       xlink:href="#linearGradient77461-1"
 | 
			
		||||
       id="linearGradient11198"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       gradientTransform="matrix(1.3066667,0,0,1,-1066.3709,794.25325)"
 | 
			
		||||
       x1="1322.5831"
 | 
			
		||||
       y1="-312.51855"
 | 
			
		||||
       x2="1322.5831"
 | 
			
		||||
       y2="-306.53461" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
@@ -89,13 +99,13 @@
 | 
			
		||||
     inkscape:pageopacity="1"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="1"
 | 
			
		||||
     inkscape:cx="33.380898"
 | 
			
		||||
     inkscape:cy="6.9658271"
 | 
			
		||||
     inkscape:cx="-26.798898"
 | 
			
		||||
     inkscape:cy="5.3753009"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:current-layer="g37994"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:window-width="2560"
 | 
			
		||||
     inkscape:window-height="1375"
 | 
			
		||||
     inkscape:window-height="1376"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="27"
 | 
			
		||||
     inkscape:window-maximized="1"
 | 
			
		||||
@@ -152,7 +162,7 @@
 | 
			
		||||
           height="25"
 | 
			
		||||
           width="98"
 | 
			
		||||
           id="rect38000"
 | 
			
		||||
           style="color:#000000;fill:url(#linearGradient77551);fill-opacity:1;fill-rule:nonzero;stroke:#182f4c;stroke-width:1.37920964;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
 | 
			
		||||
           style="color:#000000;fill:url(#linearGradient11198);fill-opacity:1;fill-rule:nonzero;stroke:#182f4c;stroke-width:1.37920964;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;filter-blend-mode:normal;filter-gaussianBlur-deviation:0;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto" />
 | 
			
		||||
      </g>
 | 
			
		||||
      <g
 | 
			
		||||
         transform="translate(2.0625,-2)"
 | 
			
		||||
 
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.7 KiB  | 
@@ -35,7 +35,6 @@
 | 
			
		||||
      <xi:include href="xml/st-bin.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-box-layout.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-scroll-view.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-table.xml"/>
 | 
			
		||||
    </chapter>
 | 
			
		||||
 | 
			
		||||
    <chapter id="styling">
 | 
			
		||||
 
 | 
			
		||||
@@ -23,11 +23,6 @@ const GnomeShellIface = '<node> \
 | 
			
		||||
</interface> \
 | 
			
		||||
</node>';
 | 
			
		||||
 | 
			
		||||
const customCss = '.prefs-button { \
 | 
			
		||||
                       padding: 8px; \
 | 
			
		||||
                       border-radius: 20px; \
 | 
			
		||||
                   }';
 | 
			
		||||
 | 
			
		||||
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
 | 
			
		||||
 | 
			
		||||
function stripPrefix(string, prefix) {
 | 
			
		||||
@@ -176,21 +171,6 @@ const Application = new Lang.Class({
 | 
			
		||||
        this._window.show_all();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _addCustomStyle: function() {
 | 
			
		||||
        let provider = new Gtk.CssProvider();
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            provider.load_from_data(customCss, -1);
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            log('Failed to add application style');
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let screen = this._window.window.get_screen();
 | 
			
		||||
        let priority = Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION;
 | 
			
		||||
        Gtk.StyleContext.add_provider_for_screen(screen, provider, priority);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _sortList: function(row1, row2) {
 | 
			
		||||
        let name1 = ExtensionUtils.extensions[row1.uuid].metadata.name;
 | 
			
		||||
        let name2 = ExtensionUtils.extensions[row2.uuid].metadata.name;
 | 
			
		||||
@@ -239,7 +219,6 @@ const Application = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _onStartup: function(app) {
 | 
			
		||||
        this._buildUI(app);
 | 
			
		||||
        this._addCustomStyle();
 | 
			
		||||
        this._scanExtensions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -316,7 +295,7 @@ const ExtensionRow = new Lang.Class({
 | 
			
		||||
        button.add(new Gtk.Image({ icon_name: 'emblem-system-symbolic',
 | 
			
		||||
                                   icon_size: Gtk.IconSize.BUTTON,
 | 
			
		||||
                                   visible: true }));
 | 
			
		||||
        button.get_style_context().add_class('prefs-button');
 | 
			
		||||
        button.get_style_context().add_class('circular');
 | 
			
		||||
        hbox.add(button);
 | 
			
		||||
 | 
			
		||||
        this.prefsButton = button;
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ const ShellEntry = imports.ui.shellEntry;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const UserWidget = imports.ui.userWidget;
 | 
			
		||||
 | 
			
		||||
const DEFAULT_BUTTON_WELL_ICON_SIZE = 24;
 | 
			
		||||
const DEFAULT_BUTTON_WELL_ICON_SIZE = 16;
 | 
			
		||||
const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0;
 | 
			
		||||
const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3;
 | 
			
		||||
 | 
			
		||||
@@ -189,7 +189,8 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
                                             this._updateNextButtonSensitivity(this._entry.text.length > 0);
 | 
			
		||||
                                         }));
 | 
			
		||||
        this._entry.clutter_text.connect('activate', Lang.bind(this, function() {
 | 
			
		||||
            this.emit('next');
 | 
			
		||||
            if (this.nextButton.reactive)
 | 
			
		||||
                this.emit('next');
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -258,6 +259,7 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onVerificationComplete: function() {
 | 
			
		||||
        this.setActorInDefaultButtonWell(null);
 | 
			
		||||
        this.verificationStatus = AuthPromptStatus.VERIFICATION_SUCCEEDED;
 | 
			
		||||
	this.cancelButton.reactive = false;
 | 
			
		||||
    },
 | 
			
		||||
@@ -281,6 +283,12 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
        if (oldActor)
 | 
			
		||||
            Tweener.removeTweens(oldActor);
 | 
			
		||||
 | 
			
		||||
        let wasSpinner;
 | 
			
		||||
        if (oldActor == this._spinner.actor)
 | 
			
		||||
            wasSpinner = true;
 | 
			
		||||
        else
 | 
			
		||||
            wasSpinner = false;
 | 
			
		||||
 | 
			
		||||
        let isSpinner;
 | 
			
		||||
        if (actor == this._spinner.actor)
 | 
			
		||||
            isSpinner = true;
 | 
			
		||||
@@ -290,6 +298,11 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
        if (this._defaultButtonWellActor != actor && oldActor) {
 | 
			
		||||
            if (!animate) {
 | 
			
		||||
                oldActor.opacity = 0;
 | 
			
		||||
 | 
			
		||||
                if (wasSpinner) {
 | 
			
		||||
                    if (this._spinner)
 | 
			
		||||
                        this._spinner.stop();
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                Tweener.addTween(oldActor,
 | 
			
		||||
                                 { opacity: 0,
 | 
			
		||||
@@ -298,7 +311,7 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
                                   transition: 'linear',
 | 
			
		||||
                                   onCompleteScope: this,
 | 
			
		||||
                                   onComplete: function() {
 | 
			
		||||
                                      if (isSpinner) {
 | 
			
		||||
                                      if (wasSpinner) {
 | 
			
		||||
                                          if (this._spinner)
 | 
			
		||||
                                              this._spinner.stop();
 | 
			
		||||
                                      }
 | 
			
		||||
@@ -401,7 +414,7 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    updateSensitivity: function(sensitive) {
 | 
			
		||||
        this._updateNextButtonSensitivity(sensitive);
 | 
			
		||||
        this._updateNextButtonSensitivity(sensitive && this._entry.text.length > 0);
 | 
			
		||||
        this._entry.reactive = sensitive;
 | 
			
		||||
        this._entry.clutter_text.editable = sensitive;
 | 
			
		||||
    },
 | 
			
		||||
@@ -432,8 +445,9 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
        let oldStatus = this.verificationStatus;
 | 
			
		||||
        this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
 | 
			
		||||
        this.cancelButton.reactive = true;
 | 
			
		||||
        this.nextButton.label = _("Next");
 | 
			
		||||
 | 
			
		||||
        if (oldStatus == AuthPromptStatus.VERIFYING)
 | 
			
		||||
        if (this._userVerifier)
 | 
			
		||||
            this._userVerifier.cancel();
 | 
			
		||||
 | 
			
		||||
        this._queryingService = null;
 | 
			
		||||
@@ -488,6 +502,7 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    finish: function(onComplete) {
 | 
			
		||||
        if (!this._userVerifier.hasPendingMessages) {
 | 
			
		||||
            this._userVerifier.clear();
 | 
			
		||||
            onComplete();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -495,12 +510,13 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
        let signalId = this._userVerifier.connect('no-more-messages',
 | 
			
		||||
                                                  Lang.bind(this, function() {
 | 
			
		||||
                                                      this._userVerifier.disconnect(signalId);
 | 
			
		||||
                                                      this._userVerifier.clear();
 | 
			
		||||
                                                      onComplete();
 | 
			
		||||
                                                  }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    cancel: function() {
 | 
			
		||||
        if (this.verificationStatus == AuthPromptStatus.NOT_VERIFYING || this.verificationStatus == AuthPromptStatus.VERIFICATION_SUCCEEDED) {
 | 
			
		||||
        if (this.verificationStatus == AuthPromptStatus.VERIFICATION_SUCCEEDED) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        this.reset();
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,34 @@
 | 
			
		||||
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * In order for transformation animations to look good, they need to be
 | 
			
		||||
 * incremental and have some order to them (e.g., fade out hidden items,
 | 
			
		||||
 * then shrink to close the void left over). Chaining animations in this way can
 | 
			
		||||
 * be error-prone and wordy using just Tweener callbacks.
 | 
			
		||||
 *
 | 
			
		||||
 * The classes in this file help with this:
 | 
			
		||||
 *
 | 
			
		||||
 * - Task.  encapsulates schedulable work to be run in a specific scope.
 | 
			
		||||
 *
 | 
			
		||||
 * - ConsecutiveBatch.  runs a series of tasks in order and completes
 | 
			
		||||
 *                      when the last in the series finishes.
 | 
			
		||||
 *
 | 
			
		||||
 * - ConcurrentBatch.  runs a set of tasks at the same time and completes
 | 
			
		||||
 *                     when the last to finish completes.
 | 
			
		||||
 *
 | 
			
		||||
 * - Hold.  prevents a batch from completing the pending task until
 | 
			
		||||
 *          the hold is released.
 | 
			
		||||
 *
 | 
			
		||||
 * The tasks associated with a batch are specified in a list at batch
 | 
			
		||||
 * construction time as either task objects or plain functions.
 | 
			
		||||
 * Batches are task objects, themselves, so they can be nested.
 | 
			
		||||
 *
 | 
			
		||||
 * These classes aren't specific to GDM, but were found to be unintuitive and so
 | 
			
		||||
 * are not used elsewhere. These APIs may ultimately get dropped entirely and
 | 
			
		||||
 * replaced by something else.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -96,7 +96,7 @@ const UserListItem = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDestroy: function() {
 | 
			
		||||
        this._user.disconnect(this._userChangedId);
 | 
			
		||||
        this.user.disconnect(this._userChangedId);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onClicked: function() {
 | 
			
		||||
@@ -212,6 +212,10 @@ const UserList = new Lang.Class({
 | 
			
		||||
        return item;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    containsUser: function(user) {
 | 
			
		||||
        return this._items[user.get_user_name()] != null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addUser: function(user) {
 | 
			
		||||
        if (!user.is_loaded)
 | 
			
		||||
            return;
 | 
			
		||||
@@ -535,6 +539,9 @@ const LoginDialog = new Lang.Class({
 | 
			
		||||
        let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2;
 | 
			
		||||
        let centerY = dialogBox.y1 + (dialogBox.y2 - dialogBox.y1) / 2;
 | 
			
		||||
 | 
			
		||||
        natWidth = Math.min(natWidth, dialogBox.x2 - dialogBox.x1);
 | 
			
		||||
        natHeight = Math.min(natHeight, dialogBox.y2 - dialogBox.y1);
 | 
			
		||||
 | 
			
		||||
        actorBox.x1 = Math.floor(centerX - natWidth / 2);
 | 
			
		||||
        actorBox.y1 = Math.floor(centerY - natHeight / 2);
 | 
			
		||||
        actorBox.x2 = actorBox.x1 + natWidth;
 | 
			
		||||
@@ -584,7 +591,14 @@ const LoginDialog = new Lang.Class({
 | 
			
		||||
        // try a different layout, or if we have what extra space we
 | 
			
		||||
        // can hand out
 | 
			
		||||
        if (bannerAllocation) {
 | 
			
		||||
            let leftOverYSpace = dialogHeight - bannerHeight - authPromptHeight - logoHeight;
 | 
			
		||||
            let bannerSpace;
 | 
			
		||||
 | 
			
		||||
            if (authPromptAllocation)
 | 
			
		||||
                bannerSpace = authPromptAllocation.y1 - bannerAllocation.y1;
 | 
			
		||||
            else
 | 
			
		||||
                bannerSpace = 0;
 | 
			
		||||
 | 
			
		||||
            let leftOverYSpace = bannerSpace - bannerHeight;
 | 
			
		||||
 | 
			
		||||
            if (leftOverYSpace > 0) {
 | 
			
		||||
                 // First figure out how much left over space is up top
 | 
			
		||||
@@ -790,6 +804,11 @@ const LoginDialog = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._user = null;
 | 
			
		||||
 | 
			
		||||
        if (this._nextSignalId) {
 | 
			
		||||
            this._authPrompt.disconnect(this._nextSignalId);
 | 
			
		||||
            this._nextSignalId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (beginRequest == AuthPrompt.BeginRequestType.PROVIDE_USERNAME) {
 | 
			
		||||
            if (!this._disableUserList)
 | 
			
		||||
                this._showUserList();
 | 
			
		||||
@@ -867,7 +886,7 @@ const LoginDialog = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _loginScreenSessionActivated: function() {
 | 
			
		||||
        if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFICATION_SUCCEEDED)
 | 
			
		||||
        if (this.actor.opacity == 255 && this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Tweener.addTween(this.actor,
 | 
			
		||||
@@ -884,7 +903,8 @@ const LoginDialog = new Lang.Class({
 | 
			
		||||
                           },
 | 
			
		||||
                           onUpdateScope: this,
 | 
			
		||||
                           onComplete: function() {
 | 
			
		||||
                               this._authPrompt.reset();
 | 
			
		||||
                               if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
 | 
			
		||||
                                   this._authPrompt.reset();
 | 
			
		||||
                           },
 | 
			
		||||
                           onCompleteScope: this });
 | 
			
		||||
    },
 | 
			
		||||
@@ -913,11 +933,7 @@ const LoginDialog = new Lang.Class({
 | 
			
		||||
                           },
 | 
			
		||||
                           onUpdateScope: this,
 | 
			
		||||
                           onComplete: function() {
 | 
			
		||||
                               let id = Mainloop.idle_add(Lang.bind(this, function() {
 | 
			
		||||
                                   this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
 | 
			
		||||
                                   return GLib.SOURCE_REMOVE;
 | 
			
		||||
                               }));
 | 
			
		||||
                               GLib.Source.set_name_by_id(id, '[gnome-shell] this._greeter.call_start_session_when_ready_sync');
 | 
			
		||||
                               this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
 | 
			
		||||
                           },
 | 
			
		||||
                           onCompleteScope: this });
 | 
			
		||||
    },
 | 
			
		||||
@@ -1119,6 +1135,10 @@ const LoginDialog = new Lang.Class({
 | 
			
		||||
            this._userManager.disconnect(this._userRemovedId);
 | 
			
		||||
            this._userRemovedId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (this._userChangedId) {
 | 
			
		||||
            this._userManager.disconnect(this._userChangedId);
 | 
			
		||||
            this._userChangedId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        this._textureCache.disconnect(this._updateLogoTextureId);
 | 
			
		||||
        Main.layoutManager.disconnect(this._startupCompleteId);
 | 
			
		||||
        if (this._settings) {
 | 
			
		||||
@@ -1165,6 +1185,14 @@ const LoginDialog = new Lang.Class({
 | 
			
		||||
                                                            this._userList.removeUser(user);
 | 
			
		||||
                                                        }));
 | 
			
		||||
 | 
			
		||||
        this._userChangedId = this._userManager.connect('user-changed',
 | 
			
		||||
                                                        Lang.bind(this, function(userManager, user) {
 | 
			
		||||
                                                            if (this._userList.containsUser(user) && user.locked)
 | 
			
		||||
                                                                this._userList.removeUser(user);
 | 
			
		||||
                                                            else if (!this._userList.containsUser(user) && !user.locked)
 | 
			
		||||
                                                                this._userList.addUser(user);
 | 
			
		||||
                                                        }));
 | 
			
		||||
 | 
			
		||||
        return GLib.SOURCE_REMOVE;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -1197,7 +1225,7 @@ const LoginDialog = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addCharacter: function(unichar) {
 | 
			
		||||
        this._authPrompt.addCharacter(unichar);
 | 
			
		||||
        // Don't allow type ahead at the login screen
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    finish: function(onComplete) {
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,7 @@
 | 
			
		||||
    <file>ui/animation.js</file>
 | 
			
		||||
    <file>ui/appDisplay.js</file>
 | 
			
		||||
    <file>ui/appFavorites.js</file>
 | 
			
		||||
    <file>ui/audioDeviceSelection.js</file>
 | 
			
		||||
    <file>ui/backgroundMenu.js</file>
 | 
			
		||||
    <file>ui/background.js</file>
 | 
			
		||||
    <file>ui/boxpointer.js</file>
 | 
			
		||||
@@ -62,7 +63,9 @@
 | 
			
		||||
    <file>ui/magnifierDBus.js</file>
 | 
			
		||||
    <file>ui/main.js</file>
 | 
			
		||||
    <file>ui/messageTray.js</file>
 | 
			
		||||
    <file>ui/messageList.js</file>
 | 
			
		||||
    <file>ui/modalDialog.js</file>
 | 
			
		||||
    <file>ui/mpris.js</file>
 | 
			
		||||
    <file>ui/notificationDaemon.js</file>
 | 
			
		||||
    <file>ui/osdWindow.js</file>
 | 
			
		||||
    <file>ui/osdMonitorLabeler.js</file>
 | 
			
		||||
 
 | 
			
		||||
@@ -134,7 +134,7 @@ const LoginManagerSystemd = new Lang.Class({
 | 
			
		||||
            if (error)
 | 
			
		||||
                asyncCallback(false);
 | 
			
		||||
            else
 | 
			
		||||
                asyncCallback(result[0] != 'no');
 | 
			
		||||
                asyncCallback(result[0] != 'no' && result[0] != 'na');
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@ const PortalWindow = new Lang.Class({
 | 
			
		||||
        this.parent({ application: application });
 | 
			
		||||
 | 
			
		||||
        if (!url) {
 | 
			
		||||
            url = 'http://www.gnome.org';
 | 
			
		||||
            url = 'http://nmcheck.gnome.org';
 | 
			
		||||
            this._originalUrlWasGnome = true;
 | 
			
		||||
        } else {
 | 
			
		||||
            this._originalUrlWasGnome = false;
 | 
			
		||||
@@ -112,12 +112,12 @@ const PortalWindow = new Lang.Class({
 | 
			
		||||
        let uri = new Soup.URI(request.get_uri());
 | 
			
		||||
 | 
			
		||||
        if (!uri.host_equal(this._uri) && this._originalUrlWasGnome) {
 | 
			
		||||
            if (uri.get_host() == 'www.gnome.org' && this._everSeenRedirect) {
 | 
			
		||||
            if (uri.get_host() == 'nmcheck.gnome.org' && this._everSeenRedirect) {
 | 
			
		||||
                // Yay, we got to gnome!
 | 
			
		||||
                decision.ignore();
 | 
			
		||||
                this._doneCallback(PortalHelperResult.COMPLETED);
 | 
			
		||||
                return true;
 | 
			
		||||
            } else if (uri.get_host() != 'www.gnome.org') {
 | 
			
		||||
            } else if (uri.get_host() != 'nmcheck.gnome.org') {
 | 
			
		||||
                this._everSeenRedirect = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -354,6 +354,59 @@ const AppSwitcherPopup = new Lang.Class({
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const CyclerPopup = new Lang.Class({
 | 
			
		||||
    Name: 'CyclerPopup',
 | 
			
		||||
    Extends: SwitcherPopup.SwitcherPopup,
 | 
			
		||||
    Abstract: true,
 | 
			
		||||
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        this.parent();
 | 
			
		||||
 | 
			
		||||
        this._items = this._getWindows();
 | 
			
		||||
 | 
			
		||||
        if (this._items.length == 0)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // We don't show an actual popup, so just provide what SwitcherPopup
 | 
			
		||||
        // expects instead of inheriting from SwitcherList
 | 
			
		||||
        this._switcherList = { actor: new St.Widget(),
 | 
			
		||||
                               highlight: Lang.bind(this, this._highlightItem),
 | 
			
		||||
                               connect: function() {} };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _highlightItem: function(index, justOutline) {
 | 
			
		||||
        Main.activateWindow(this._items[index]);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _finish: function() {
 | 
			
		||||
        this._highlightItem(this._selectedIndex);
 | 
			
		||||
 | 
			
		||||
        this.parent();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const GroupCyclerPopup = new Lang.Class({
 | 
			
		||||
    Name: 'GroupCyclerPopup',
 | 
			
		||||
    Extends: CyclerPopup,
 | 
			
		||||
 | 
			
		||||
    _getWindows: function() {
 | 
			
		||||
        let app = Shell.WindowTracker.get_default().focus_app;
 | 
			
		||||
        return app ? app.get_windows() : [];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _keyPressHandler: function(keysym, action) {
 | 
			
		||||
        if (action == Meta.KeyBindingAction.CYCLE_GROUP)
 | 
			
		||||
            this._select(this._next());
 | 
			
		||||
        else if (action == Meta.KeyBindingAction.CYCLE_GROUP_BACKWARD)
 | 
			
		||||
            this._select(this._previous());
 | 
			
		||||
        else
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
        return Clutter.EVENT_STOP;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const WindowSwitcherPopup = new Lang.Class({
 | 
			
		||||
    Name: 'WindowSwitcherPopup',
 | 
			
		||||
    Extends: SwitcherPopup.SwitcherPopup,
 | 
			
		||||
@@ -401,6 +454,32 @@ const WindowSwitcherPopup = new Lang.Class({
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const WindowCyclerPopup = new Lang.Class({
 | 
			
		||||
    Name: 'WindowCyclerPopup',
 | 
			
		||||
    Extends: CyclerPopup,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell.window-switcher' });
 | 
			
		||||
        this.parent();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getWindows: function() {
 | 
			
		||||
        let workspace = this._settings.get_boolean('current-workspace-only') ? global.screen.get_active_workspace() : null;
 | 
			
		||||
        return global.display.get_tab_list(Meta.TabList.NORMAL, workspace);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _keyPressHandler: function(keysym, action) {
 | 
			
		||||
        if (action == Meta.KeyBindingAction.CYCLE_WINDOWS)
 | 
			
		||||
            this._select(this._next());
 | 
			
		||||
        else if (action == Meta.KeyBindingAction.CYCLE_WINDOWS_BACKWARD)
 | 
			
		||||
            this._select(this._previous());
 | 
			
		||||
        else
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
        return Clutter.EVENT_STOP;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AppIcon = new Lang.Class({
 | 
			
		||||
    Name: 'AppIcon',
 | 
			
		||||
 | 
			
		||||
@@ -448,8 +527,6 @@ const AppSwitcher = new Lang.Class({
 | 
			
		||||
            });
 | 
			
		||||
            if (appIcon.cachedWindows.length > 0)
 | 
			
		||||
                this._addIcon(appIcon);
 | 
			
		||||
            else if (workspace == null)
 | 
			
		||||
                throw new Error('%s appears to be running, but doesn\'t have any windows'.format(appIcon.app.get_name()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._curApp = -1;
 | 
			
		||||
@@ -687,15 +764,17 @@ const WindowIcon = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._icon.destroy_all_children();
 | 
			
		||||
 | 
			
		||||
        let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
 | 
			
		||||
 | 
			
		||||
        switch (mode) {
 | 
			
		||||
            case AppIconMode.THUMBNAIL_ONLY:
 | 
			
		||||
                size = WINDOW_PREVIEW_SIZE;
 | 
			
		||||
                this._icon.add_actor(_createWindowClone(mutterWindow, WINDOW_PREVIEW_SIZE));
 | 
			
		||||
                this._icon.add_actor(_createWindowClone(mutterWindow, size * scaleFactor));
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case AppIconMode.BOTH:
 | 
			
		||||
                size = WINDOW_PREVIEW_SIZE;
 | 
			
		||||
                this._icon.add_actor(_createWindowClone(mutterWindow, WINDOW_PREVIEW_SIZE));
 | 
			
		||||
                this._icon.add_actor(_createWindowClone(mutterWindow, size * scaleFactor));
 | 
			
		||||
 | 
			
		||||
                if (this.app)
 | 
			
		||||
                    this._icon.add_actor(this._createAppIcon(this.app,
 | 
			
		||||
@@ -707,7 +786,7 @@ const WindowIcon = new Lang.Class({
 | 
			
		||||
                this._icon.add_actor(this._createAppIcon(this.app, size));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._icon.set_size(size, size);
 | 
			
		||||
        this._icon.set_size(size * scaleFactor, size * scaleFactor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createAppIcon: function(app, size) {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ const St = imports.gi.St;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Atk = imports.gi.Atk;
 | 
			
		||||
 | 
			
		||||
const ANIMATED_ICON_UPDATE_TIMEOUT = 100;
 | 
			
		||||
const ANIMATED_ICON_UPDATE_TIMEOUT = 16;
 | 
			
		||||
 | 
			
		||||
const Animation = new Lang.Class({
 | 
			
		||||
    Name: 'Animation',
 | 
			
		||||
@@ -33,7 +33,7 @@ const Animation = new Lang.Class({
 | 
			
		||||
            if (this._frame == 0)
 | 
			
		||||
                this._showFrame(0);
 | 
			
		||||
 | 
			
		||||
            this._timeoutId = Mainloop.timeout_add(this._speed, Lang.bind(this, this._update));
 | 
			
		||||
            this._timeoutId = GLib.timeout_add(GLib.PRIORITY_LOW, this._speed, Lang.bind(this, this._update));
 | 
			
		||||
            GLib.Source.set_name_by_id(this._timeoutId, '[gnome-shell] this._update');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -500,6 +500,11 @@ const AllView = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _loadApps: function() {
 | 
			
		||||
        let apps = Gio.AppInfo.get_all().filter(function(appInfo) {
 | 
			
		||||
            try {
 | 
			
		||||
                let id = appInfo.get_id(); // catch invalid file encodings
 | 
			
		||||
            } catch(e) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            return appInfo.should_show();
 | 
			
		||||
        }).map(function(app) {
 | 
			
		||||
            return app.get_id();
 | 
			
		||||
@@ -753,7 +758,8 @@ const AllView = new Lang.Class({
 | 
			
		||||
        let fadeOffset = Math.min(this._grid.topPadding,
 | 
			
		||||
                                  this._grid.bottomPadding);
 | 
			
		||||
        this._scrollView.update_fade_effect(fadeOffset, 0);
 | 
			
		||||
        this._scrollView.get_effect('fade').fade_edges = true;
 | 
			
		||||
        if (fadeOffset > 0)
 | 
			
		||||
            this._scrollView.get_effect('fade').fade_edges = true;
 | 
			
		||||
 | 
			
		||||
        if (this._availWidth != availWidth || this._availHeight != availHeight || oldNPages != this._grid.nPages()) {
 | 
			
		||||
            this._adjustment.value = 0;
 | 
			
		||||
@@ -1060,7 +1066,7 @@ const AppSearchProvider = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    getInitialResultSet: function(terms, callback, cancellable) {
 | 
			
		||||
        let query = terms.join(' ');
 | 
			
		||||
        let groups = Gio.DesktopAppInfo.search(query);
 | 
			
		||||
        let groups = Shell.AppSystem.search(query);
 | 
			
		||||
        let usage = Shell.AppUsage.get_default();
 | 
			
		||||
        let results = [];
 | 
			
		||||
        groups.forEach(function(group) {
 | 
			
		||||
@@ -1289,7 +1295,10 @@ const FolderIcon = new Lang.Class({
 | 
			
		||||
            if (!_listsIntersect(folderCategories, appCategories))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            addAppId(appInfo.get_id());
 | 
			
		||||
            try {
 | 
			
		||||
                addAppId(appInfo.get_id()); // catch invalid file encodings
 | 
			
		||||
            } catch(e) {
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.actor.visible = this.view.getAllItems().length > 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -16,16 +16,18 @@ const RENAMED_DESKTOP_IDS = {
 | 
			
		||||
    'glchess.desktop': 'gnome-chess.desktop',
 | 
			
		||||
    'glines.desktop': 'five-or-more.desktop',
 | 
			
		||||
    'gnect.desktop': 'four-in-a-row.desktop',
 | 
			
		||||
    'gnibbles.desktop': 'gnome-nibbles.desktop',
 | 
			
		||||
    'gnibbles.desktop': 'org.gnome.Nibbles.desktop',
 | 
			
		||||
    'gnobots2.desktop': 'gnome-robots.desktop',
 | 
			
		||||
    'gnome-boxes.desktop': 'org.gnome.Boxes.desktop',
 | 
			
		||||
    'gnome-clocks.desktop': 'org.gnome.clocks.desktop',
 | 
			
		||||
    'gnome-contacts.desktop': 'org.gnome.Contacts.desktop',
 | 
			
		||||
    'gnome-documents.desktop': 'org.gnome.Documents.desktop',
 | 
			
		||||
    'gnome-font-viewer.desktop': 'org.gnome.font-viewer.desktop',
 | 
			
		||||
    'gnome-nibbles.desktop': 'org.gnome.Nibbles.desktop',
 | 
			
		||||
    'gnome-photos.desktop': 'org.gnome.Photos.desktop',
 | 
			
		||||
    'gnome-screenshot.desktop': 'org.gnome.Screenshot.desktop',
 | 
			
		||||
    'gnome-software.desktop': 'org.gnome.Software.desktop',
 | 
			
		||||
    'gnome-terminal.desktop': 'org.gnome.Terminal.desktop',
 | 
			
		||||
    'gnome-weather.desktop': 'org.gnome.Weather.Application.desktop',
 | 
			
		||||
    'gnomine.desktop': 'gnome-mines.desktop',
 | 
			
		||||
    'gnotravex.desktop': 'gnome-tetravex.desktop',
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										216
									
								
								js/ui/audioDeviceSelection.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,216 @@
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
 | 
			
		||||
const AudioDevice = {
 | 
			
		||||
    HEADPHONES: 1 << 0,
 | 
			
		||||
    HEADSET:    1 << 1,
 | 
			
		||||
    MICROPHONE: 1 << 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const AudioDeviceSelectionIface = '<node> \
 | 
			
		||||
<interface name="org.gnome.Shell.AudioDeviceSelection"> \
 | 
			
		||||
<method name="Open"> \
 | 
			
		||||
    <arg name="devices" direction="in" type="as" /> \
 | 
			
		||||
</method> \
 | 
			
		||||
<method name="Close"> \
 | 
			
		||||
</method> \
 | 
			
		||||
<signal name="DeviceSelected"> \
 | 
			
		||||
    <arg name="device" type="s" /> \
 | 
			
		||||
</signal> \
 | 
			
		||||
</interface> \
 | 
			
		||||
</node>';
 | 
			
		||||
 | 
			
		||||
const AudioDeviceSelectionDialog = new Lang.Class({
 | 
			
		||||
    Name: 'AudioDeviceSelectionDialog',
 | 
			
		||||
    Extends: ModalDialog.ModalDialog,
 | 
			
		||||
 | 
			
		||||
    _init: function(devices) {
 | 
			
		||||
        this.parent({ styleClass: 'audio-device-selection-dialog' });
 | 
			
		||||
 | 
			
		||||
        this._deviceItems = {};
 | 
			
		||||
 | 
			
		||||
        this._buildLayout();
 | 
			
		||||
 | 
			
		||||
        if (devices & AudioDevice.HEADPHONES)
 | 
			
		||||
            this._addDevice(AudioDevice.HEADPHONES);
 | 
			
		||||
        if (devices & AudioDevice.HEADSET)
 | 
			
		||||
            this._addDevice(AudioDevice.HEADSET);
 | 
			
		||||
        if (devices & AudioDevice.MICROPHONE)
 | 
			
		||||
            this._addDevice(AudioDevice.MICROPHONE);
 | 
			
		||||
 | 
			
		||||
        if (this._selectionBox.get_n_children() < 2)
 | 
			
		||||
            throw new Error('Too few devices for a selection');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
        this.parent();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _buildLayout: function(devices) {
 | 
			
		||||
        let title = new St.Label({ style_class: 'audio-selection-title',
 | 
			
		||||
                                   text: _("Select Audio Device"),
 | 
			
		||||
                                   x_align: Clutter.ActorAlign.CENTER });
 | 
			
		||||
 | 
			
		||||
        this.contentLayout.style_class = 'audio-selection-content';
 | 
			
		||||
        this.contentLayout.add(title);
 | 
			
		||||
 | 
			
		||||
        this._selectionBox = new St.BoxLayout({ style_class: 'audio-selection-box' });
 | 
			
		||||
        this.contentLayout.add(this._selectionBox, { expand: true });
 | 
			
		||||
 | 
			
		||||
        this.addButton({ action: Lang.bind(this, this._openSettings),
 | 
			
		||||
                         label: _("Sound Settings") });
 | 
			
		||||
        this.addButton({ action: Lang.bind(this, this.close),
 | 
			
		||||
                         label: _("Cancel"),
 | 
			
		||||
                         key: Clutter.Escape });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getDeviceLabel: function(device) {
 | 
			
		||||
        switch(device) {
 | 
			
		||||
            case AudioDevice.HEADPHONES:
 | 
			
		||||
                return _("Headphones");
 | 
			
		||||
            case AudioDevice.HEADSET:
 | 
			
		||||
                return _("Headset");
 | 
			
		||||
            case AudioDevice.MICROPHONE:
 | 
			
		||||
                return _("Microphone");
 | 
			
		||||
            default:
 | 
			
		||||
                return null;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getDeviceIcon: function(device) {
 | 
			
		||||
        switch(device) {
 | 
			
		||||
            case AudioDevice.HEADPHONES:
 | 
			
		||||
                return 'audio-headphones-symbolic';
 | 
			
		||||
            case AudioDevice.HEADSET:
 | 
			
		||||
                return 'audio-headset-symbolic';
 | 
			
		||||
            case AudioDevice.MICROPHONE:
 | 
			
		||||
                return 'audio-input-microphone-symbolic';
 | 
			
		||||
            default:
 | 
			
		||||
                return null;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _addDevice: function(device) {
 | 
			
		||||
        let box = new St.BoxLayout({ style_class: 'audio-selection-device-box',
 | 
			
		||||
                                     vertical: true });
 | 
			
		||||
        box.connect('notify::height',
 | 
			
		||||
            function() {
 | 
			
		||||
                Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
 | 
			
		||||
                    function() {
 | 
			
		||||
                        box.width = box.height;
 | 
			
		||||
                    });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        let icon = new St.Icon({ style_class: 'audio-selection-device-icon',
 | 
			
		||||
                                 icon_name: this._getDeviceIcon(device) });
 | 
			
		||||
        box.add(icon);
 | 
			
		||||
 | 
			
		||||
        let label = new St.Label({ style_class: 'audio-selection-device-label',
 | 
			
		||||
                                   text: this._getDeviceLabel(device),
 | 
			
		||||
                                   x_align: Clutter.ActorAlign.CENTER });
 | 
			
		||||
        box.add(label);
 | 
			
		||||
 | 
			
		||||
        let button = new St.Button({ style_class: 'audio-selection-device',
 | 
			
		||||
                                     can_focus: true,
 | 
			
		||||
                                     child: box });
 | 
			
		||||
        this._selectionBox.add(button);
 | 
			
		||||
 | 
			
		||||
        button.connect('clicked', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
                this.emit('device-selected', device);
 | 
			
		||||
                this.close();
 | 
			
		||||
                Main.overview.hide();
 | 
			
		||||
            }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _openSettings: function() {
 | 
			
		||||
        let desktopFile = 'gnome-sound-panel.desktop'
 | 
			
		||||
        let app = Shell.AppSystem.get_default().lookup_app(desktopFile);
 | 
			
		||||
 | 
			
		||||
        if (!app) {
 | 
			
		||||
            log('Settings panel for desktop file ' + desktopFile + ' could not be loaded!');
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.close();
 | 
			
		||||
        Main.overview.hide();
 | 
			
		||||
        app.activate();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AudioDeviceSelectionDBus = new Lang.Class({
 | 
			
		||||
    Name: 'AudioDeviceSelectionDBus',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._audioSelectionDialog = null;
 | 
			
		||||
 | 
			
		||||
        this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(AudioDeviceSelectionIface, this);
 | 
			
		||||
        this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/AudioDeviceSelection');
 | 
			
		||||
 | 
			
		||||
        Gio.DBus.session.own_name('org.gnome.Shell.AudioDeviceSelection', Gio.BusNameOwnerFlags.REPLACE, null, null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDialogClosed: function() {
 | 
			
		||||
        this._audioSelectionDialog = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDeviceSelected: function(dialog, device) {
 | 
			
		||||
        let connection = this._dbusImpl.get_connection();
 | 
			
		||||
        let info = this._dbusImpl.get_info();
 | 
			
		||||
        let deviceName = Object.keys(AudioDevice).filter(
 | 
			
		||||
            function(dev) {
 | 
			
		||||
                return AudioDevice[dev] == device;
 | 
			
		||||
            })[0].toLowerCase();
 | 
			
		||||
        connection.emit_signal(this._audioSelectionDialog._sender,
 | 
			
		||||
                               this._dbusImpl.get_object_path(),
 | 
			
		||||
                               info ? info.name : null,
 | 
			
		||||
                               'DeviceSelected',
 | 
			
		||||
                               GLib.Variant.new('(s)', [deviceName]));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    OpenAsync: function(params, invocation) {
 | 
			
		||||
        if (this._audioSelectionDialog) {
 | 
			
		||||
            invocation.return_value(null);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let [deviceNames] = params;
 | 
			
		||||
        let devices = 0;
 | 
			
		||||
        deviceNames.forEach(function(n) {
 | 
			
		||||
            devices |= AudioDevice[n.toUpperCase()];
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let dialog;
 | 
			
		||||
        try {
 | 
			
		||||
            dialog = new AudioDeviceSelectionDialog(devices);
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            invocation.return_value(null);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        dialog._sender = invocation.get_sender();
 | 
			
		||||
 | 
			
		||||
        dialog.connect('closed', Lang.bind(this, this._onDialogClosed));
 | 
			
		||||
        dialog.connect('device-selected',
 | 
			
		||||
                       Lang.bind(this, this._onDeviceSelected));
 | 
			
		||||
        dialog.open();
 | 
			
		||||
 | 
			
		||||
        this._audioSelectionDialog = dialog;
 | 
			
		||||
        invocation.return_value(null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    CloseAsync: function(params, invocation) {
 | 
			
		||||
        if (this._audioSelectionDialog &&
 | 
			
		||||
            this._audioSelectionDialog._sender == invocation.get_sender())
 | 
			
		||||
            this._audioSelectionDialog.close();
 | 
			
		||||
 | 
			
		||||
        invocation.return_value(null);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
@@ -144,6 +144,7 @@ const BackgroundCache = new Lang.Class({
 | 
			
		||||
        this._pendingFileLoads = [];
 | 
			
		||||
        this._fileMonitors = {};
 | 
			
		||||
        this._backgroundSources = {};
 | 
			
		||||
        this._animations = {};
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    monitorFile: function(file) {
 | 
			
		||||
@@ -162,12 +163,13 @@ const BackgroundCache = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    getAnimation: function(params) {
 | 
			
		||||
        params = Params.parse(params, { file: null,
 | 
			
		||||
                                        settingsSchema: null,
 | 
			
		||||
                                        onLoaded: null });
 | 
			
		||||
 | 
			
		||||
        if (_fileEqual0(this._animationFile, params.file)) {
 | 
			
		||||
        if (this._animations[params.settingsSchema] && _fileEqual0(this._animationFile, params.file)) {
 | 
			
		||||
            if (params.onLoaded) {
 | 
			
		||||
                let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
 | 
			
		||||
                    params.onLoaded(this._animation);
 | 
			
		||||
                    params.onLoaded(this._animations[params.settingsSchema]);
 | 
			
		||||
                    return GLib.SOURCE_REMOVE;
 | 
			
		||||
                }));
 | 
			
		||||
                GLib.Source.set_name_by_id(id, '[gnome-shell] params.onLoaded');
 | 
			
		||||
@@ -178,12 +180,11 @@ const BackgroundCache = new Lang.Class({
 | 
			
		||||
        let animation = new Animation({ file: params.file });
 | 
			
		||||
 | 
			
		||||
        animation.load(Lang.bind(this, function() {
 | 
			
		||||
                           this._animationFile = params.file;
 | 
			
		||||
                           this._animation = animation;
 | 
			
		||||
                           this._animations[params.settingsSchema] = animation;
 | 
			
		||||
 | 
			
		||||
                           if (params.onLoaded) {
 | 
			
		||||
                               let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
 | 
			
		||||
                                   params.onLoaded(this._animation);
 | 
			
		||||
                                   params.onLoaded(this._animations[params.settingsSchema]);
 | 
			
		||||
                                   return GLib.SOURCE_REMOVE;
 | 
			
		||||
                               }));
 | 
			
		||||
                               GLib.Source.set_name_by_id(id, '[gnome-shell] params.onLoaded');
 | 
			
		||||
@@ -246,6 +247,13 @@ const Background = new Lang.Class({
 | 
			
		||||
        this._cancellable = new Gio.Cancellable();
 | 
			
		||||
        this.isLoaded = false;
 | 
			
		||||
 | 
			
		||||
        this._clock = new GnomeDesktop.WallClock();
 | 
			
		||||
        this._timezoneChangedId = this._clock.connect('notify::timezone',
 | 
			
		||||
            Lang.bind(this, function() {
 | 
			
		||||
                if (this._animation)
 | 
			
		||||
                    this._loadAnimation(this._animation.file);
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        this._settingsChangedSignalId = this._settings.connect('changed', Lang.bind(this, function() {
 | 
			
		||||
                                            this.emit('changed');
 | 
			
		||||
                                        }));
 | 
			
		||||
@@ -264,6 +272,10 @@ const Background = new Lang.Class({
 | 
			
		||||
        }
 | 
			
		||||
        this._fileWatches = null;
 | 
			
		||||
 | 
			
		||||
        if (this._timezoneChangedId != 0)
 | 
			
		||||
            this._clock.disconnect(this._timezoneChangedId);
 | 
			
		||||
        this._timezoneChangedId = 0;
 | 
			
		||||
 | 
			
		||||
        if (this._settingsChangedSignalId != 0)
 | 
			
		||||
            this._settings.disconnect(this._settingsChangedSignalId);
 | 
			
		||||
        this._settingsChangedSignalId = 0;
 | 
			
		||||
@@ -403,17 +415,18 @@ const Background = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _loadAnimation: function(file) {
 | 
			
		||||
        this._cache.getAnimation({ file: file,
 | 
			
		||||
                                         onLoaded: Lang.bind(this, function(animation) {
 | 
			
		||||
                                             this._animation = animation;
 | 
			
		||||
                                   settingsSchema: this._settings.schema_id,
 | 
			
		||||
                                   onLoaded: Lang.bind(this, function(animation) {
 | 
			
		||||
                                       this._animation = animation;
 | 
			
		||||
 | 
			
		||||
                                             if (!this._animation || this._cancellable.is_cancelled()) {
 | 
			
		||||
                                                 this._setLoaded();
 | 
			
		||||
                                                 return;
 | 
			
		||||
                                             }
 | 
			
		||||
                                       if (!this._animation || this._cancellable.is_cancelled()) {
 | 
			
		||||
                                           this._setLoaded();
 | 
			
		||||
                                           return;
 | 
			
		||||
                                       }
 | 
			
		||||
 | 
			
		||||
                                             this._updateAnimation();
 | 
			
		||||
                                             this._watchFile(file);
 | 
			
		||||
                                         })
 | 
			
		||||
                                       this._updateAnimation();
 | 
			
		||||
                                       this._watchFile(file);
 | 
			
		||||
                                   })
 | 
			
		||||
                                 });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -683,6 +696,7 @@ const BackgroundManager = new Lang.Class({
 | 
			
		||||
                           time: FADE_ANIMATION_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: function() {
 | 
			
		||||
                               oldBackgroundActor.background.run_dispose();
 | 
			
		||||
                               oldBackgroundActor.destroy();
 | 
			
		||||
                           }
 | 
			
		||||
                         });
 | 
			
		||||
 
 | 
			
		||||
@@ -16,9 +16,10 @@ const BackgroundMenu = new Lang.Class({
 | 
			
		||||
    _init: function(layoutManager) {
 | 
			
		||||
        this.parent(layoutManager.dummyCursor, 0, St.Side.TOP);
 | 
			
		||||
 | 
			
		||||
        this.addSettingsAction(_("Settings"), 'gnome-control-center.desktop');
 | 
			
		||||
        this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
 | 
			
		||||
        this.addSettingsAction(_("Change Background…"), 'gnome-background-panel.desktop');
 | 
			
		||||
        this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
 | 
			
		||||
        this.addSettingsAction(_("Display Settings"), 'gnome-display-panel.desktop');
 | 
			
		||||
        this.addSettingsAction(_("Settings"), 'gnome-control-center.desktop');
 | 
			
		||||
 | 
			
		||||
        this.actor.add_style_class_name('background-menu');
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,51 +1,45 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Atk = imports.gi.Atk;
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const GObject = imports.gi.GObject;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Pango = imports.gi.Pango;
 | 
			
		||||
const Gettext_gtk30 = imports.gettext.domain('gtk30');
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageList = imports.ui.messageList;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const Mpris = imports.ui.mpris;
 | 
			
		||||
const Util = imports.misc.util;
 | 
			
		||||
 | 
			
		||||
const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
 | 
			
		||||
const SHOW_WEEKDATE_KEY = 'show-weekdate';
 | 
			
		||||
const ELLIPSIS_CHAR = '\u2026';
 | 
			
		||||
 | 
			
		||||
const MESSAGE_ANIMATION_TIME = 0.1;
 | 
			
		||||
 | 
			
		||||
const DEFAULT_EXPAND_LINES = 6;
 | 
			
		||||
const MESSAGE_ICON_SIZE = 32;
 | 
			
		||||
 | 
			
		||||
// alias to prevent xgettext from picking up strings translated in GTK+
 | 
			
		||||
const gtk30_ = Gettext_gtk30.gettext;
 | 
			
		||||
const NC_ = function(context, str) { return context + '\u0004' + str; };
 | 
			
		||||
 | 
			
		||||
function _sameYear(dateA, dateB) {
 | 
			
		||||
function sameYear(dateA, dateB) {
 | 
			
		||||
    return (dateA.getYear() == dateB.getYear());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _sameMonth(dateA, dateB) {
 | 
			
		||||
    return _sameYear(dateA, dateB) && (dateA.getMonth() == dateB.getMonth());
 | 
			
		||||
function sameMonth(dateA, dateB) {
 | 
			
		||||
    return sameYear(dateA, dateB) && (dateA.getMonth() == dateB.getMonth());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _sameDay(dateA, dateB) {
 | 
			
		||||
    return _sameMonth(dateA, dateB) && (dateA.getDate() == dateB.getDate());
 | 
			
		||||
function sameDay(dateA, dateB) {
 | 
			
		||||
    return sameMonth(dateA, dateB) && (dateA.getDate() == dateB.getDate());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _isToday(date) {
 | 
			
		||||
    return _sameDay(new Date(), date);
 | 
			
		||||
function isToday(date) {
 | 
			
		||||
    return sameDay(new Date(), date);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _isWorkDay(date) {
 | 
			
		||||
@@ -96,148 +90,6 @@ function _getCalendarDayAbbreviation(dayNumber) {
 | 
			
		||||
    return Shell.util_translate_time_string(abbreviations[dayNumber]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _fixMarkup(text, allowMarkup) {
 | 
			
		||||
    if (allowMarkup) {
 | 
			
		||||
        // Support &, ", ', < and >, escape all other
 | 
			
		||||
        // occurrences of '&'.
 | 
			
		||||
        let _text = text.replace(/&(?!amp;|quot;|apos;|lt;|gt;)/g, '&');
 | 
			
		||||
 | 
			
		||||
        // Support <b>, <i>, and <u>, escape anything else
 | 
			
		||||
        // so it displays as raw markup.
 | 
			
		||||
        _text = _text.replace(/<(?!\/?[biu]>)/g, '<');
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            Pango.parse_markup(_text, -1, '');
 | 
			
		||||
            return _text;
 | 
			
		||||
        } catch (e) {}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // !allowMarkup, or invalid markup
 | 
			
		||||
    return GLib.markup_escape_text(text, -1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const URLHighlighter = new Lang.Class({
 | 
			
		||||
    Name: 'URLHighlighter',
 | 
			
		||||
 | 
			
		||||
    _init: function(text, lineWrap, allowMarkup) {
 | 
			
		||||
        if (!text)
 | 
			
		||||
            text = '';
 | 
			
		||||
        this.actor = new St.Label({ reactive: true, style_class: 'url-highlighter',
 | 
			
		||||
                                    x_expand: true, x_align: Clutter.ActorAlign.START });
 | 
			
		||||
        this._linkColor = '#ccccff';
 | 
			
		||||
        this.actor.connect('style-changed', Lang.bind(this, function() {
 | 
			
		||||
            let [hasColor, color] = this.actor.get_theme_node().lookup_color('link-color', false);
 | 
			
		||||
            if (hasColor) {
 | 
			
		||||
                let linkColor = color.to_string().substr(0, 7);
 | 
			
		||||
                if (linkColor != this._linkColor) {
 | 
			
		||||
                    this._linkColor = linkColor;
 | 
			
		||||
                    this._highlightUrls();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }));
 | 
			
		||||
        this.actor.clutter_text.line_wrap = lineWrap;
 | 
			
		||||
        this.actor.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
 | 
			
		||||
 | 
			
		||||
        this.setMarkup(text, allowMarkup);
 | 
			
		||||
        this.actor.connect('button-press-event', Lang.bind(this, function(actor, event) {
 | 
			
		||||
            // Don't try to URL highlight when invisible.
 | 
			
		||||
            // The MessageTray doesn't actually hide us, so
 | 
			
		||||
            // we need to check for paint opacities as well.
 | 
			
		||||
            if (!actor.visible || actor.get_paint_opacity() == 0)
 | 
			
		||||
                return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
            // Keep Notification.actor from seeing this and taking
 | 
			
		||||
            // a pointer grab, which would block our button-release-event
 | 
			
		||||
            // handler, if an URL is clicked
 | 
			
		||||
            return this._findUrlAtPos(event) != -1;
 | 
			
		||||
        }));
 | 
			
		||||
        this.actor.connect('button-release-event', Lang.bind(this, function (actor, event) {
 | 
			
		||||
            if (!actor.visible || actor.get_paint_opacity() == 0)
 | 
			
		||||
                return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
            let urlId = this._findUrlAtPos(event);
 | 
			
		||||
            if (urlId != -1) {
 | 
			
		||||
                let url = this._urls[urlId].url;
 | 
			
		||||
                if (url.indexOf(':') == -1)
 | 
			
		||||
                    url = 'http://' + url;
 | 
			
		||||
 | 
			
		||||
                Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context(0, -1));
 | 
			
		||||
                return Clutter.EVENT_STOP;
 | 
			
		||||
            }
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
        }));
 | 
			
		||||
        this.actor.connect('motion-event', Lang.bind(this, function(actor, event) {
 | 
			
		||||
            if (!actor.visible || actor.get_paint_opacity() == 0)
 | 
			
		||||
                return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
            let urlId = this._findUrlAtPos(event);
 | 
			
		||||
            if (urlId != -1 && !this._cursorChanged) {
 | 
			
		||||
                global.screen.set_cursor(Meta.Cursor.POINTING_HAND);
 | 
			
		||||
                this._cursorChanged = true;
 | 
			
		||||
            } else if (urlId == -1) {
 | 
			
		||||
                global.screen.set_cursor(Meta.Cursor.DEFAULT);
 | 
			
		||||
                this._cursorChanged = false;
 | 
			
		||||
            }
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
        }));
 | 
			
		||||
        this.actor.connect('leave-event', Lang.bind(this, function() {
 | 
			
		||||
            if (!this.actor.visible || this.actor.get_paint_opacity() == 0)
 | 
			
		||||
                return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
            if (this._cursorChanged) {
 | 
			
		||||
                this._cursorChanged = false;
 | 
			
		||||
                global.screen.set_cursor(Meta.Cursor.DEFAULT);
 | 
			
		||||
            }
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setMarkup: function(text, allowMarkup) {
 | 
			
		||||
        text = text ? _fixMarkup(text, allowMarkup) : '';
 | 
			
		||||
        this._text = text;
 | 
			
		||||
 | 
			
		||||
        this.actor.clutter_text.set_markup(text);
 | 
			
		||||
        /* clutter_text.text contain text without markup */
 | 
			
		||||
        this._urls = Util.findUrls(this.actor.clutter_text.text);
 | 
			
		||||
        this._highlightUrls();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _highlightUrls: function() {
 | 
			
		||||
        // text here contain markup
 | 
			
		||||
        let urls = Util.findUrls(this._text);
 | 
			
		||||
        let markup = '';
 | 
			
		||||
        let pos = 0;
 | 
			
		||||
        for (let i = 0; i < urls.length; i++) {
 | 
			
		||||
            let url = urls[i];
 | 
			
		||||
            let str = this._text.substr(pos, url.pos - pos);
 | 
			
		||||
            markup += str + '<span foreground="' + this._linkColor + '"><u>' + url.url + '</u></span>';
 | 
			
		||||
            pos = url.pos + url.url.length;
 | 
			
		||||
        }
 | 
			
		||||
        markup += this._text.substr(pos);
 | 
			
		||||
        this.actor.clutter_text.set_markup(markup);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _findUrlAtPos: function(event) {
 | 
			
		||||
        let success;
 | 
			
		||||
        let [x, y] = event.get_coords();
 | 
			
		||||
        [success, x, y] = this.actor.transform_stage_point(x, y);
 | 
			
		||||
        let find_pos = -1;
 | 
			
		||||
        for (let i = 0; i < this.actor.clutter_text.text.length; i++) {
 | 
			
		||||
            let [success, px, py, line_height] = this.actor.clutter_text.position_to_coords(i);
 | 
			
		||||
            if (py > y || py + line_height < y || x < px)
 | 
			
		||||
                continue;
 | 
			
		||||
            find_pos = i;
 | 
			
		||||
        }
 | 
			
		||||
        if (find_pos != -1) {
 | 
			
		||||
            for (let i = 0; i < this._urls.length; i++)
 | 
			
		||||
            if (find_pos >= this._urls[i].pos &&
 | 
			
		||||
                this._urls[i].pos + this._urls[i].url.length > find_pos)
 | 
			
		||||
                return i;
 | 
			
		||||
        }
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Abstraction for an appointment/event in a calendar
 | 
			
		||||
 | 
			
		||||
const CalendarEvent = new Lang.Class({
 | 
			
		||||
@@ -542,7 +394,7 @@ const Calendar = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    // Sets the calendar to show a specific date
 | 
			
		||||
    setDate: function(date) {
 | 
			
		||||
        if (_sameDay(date, this._selectedDate))
 | 
			
		||||
        if (sameDay(date, this._selectedDate))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._selectedDate = date;
 | 
			
		||||
@@ -723,7 +575,8 @@ const Calendar = new Lang.Class({
 | 
			
		||||
        // nRows here means 6 weeks + one header + one navbar
 | 
			
		||||
        let nRows = 8;
 | 
			
		||||
        while (row < 8) {
 | 
			
		||||
            let button = new St.Button({ label: iter.getDate().toString(),
 | 
			
		||||
            // xgettext:no-javascript-format
 | 
			
		||||
            let button = new St.Button({ label: iter.toLocaleFormat(C_("date day number format", "%d")),
 | 
			
		||||
                                         can_focus: true });
 | 
			
		||||
            let rtl = button.get_text_direction() == Clutter.TextDirection.RTL;
 | 
			
		||||
 | 
			
		||||
@@ -754,7 +607,7 @@ const Calendar = new Lang.Class({
 | 
			
		||||
            if (leftMost)
 | 
			
		||||
                styleClass = 'calendar-day-left ' + styleClass;
 | 
			
		||||
 | 
			
		||||
            if (_sameDay(now, iter))
 | 
			
		||||
            if (sameDay(now, iter))
 | 
			
		||||
                styleClass += ' calendar-today';
 | 
			
		||||
            else if (iter.getMonth() != this._selectedDate.getMonth())
 | 
			
		||||
                styleClass += ' calendar-other-month-day';
 | 
			
		||||
@@ -797,16 +650,16 @@ const Calendar = new Lang.Class({
 | 
			
		||||
    _update: function() {
 | 
			
		||||
        let now = new Date();
 | 
			
		||||
 | 
			
		||||
        if (_sameYear(this._selectedDate, now))
 | 
			
		||||
        if (sameYear(this._selectedDate, now))
 | 
			
		||||
            this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormatWithoutYear);
 | 
			
		||||
        else
 | 
			
		||||
            this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormat);
 | 
			
		||||
 | 
			
		||||
        if (!this._calendarBegin || !_sameMonth(this._selectedDate, this._calendarBegin) || !_sameDay(now, this._markedAsToday))
 | 
			
		||||
        if (!this._calendarBegin || !sameMonth(this._selectedDate, this._calendarBegin) || !sameDay(now, this._markedAsToday))
 | 
			
		||||
            this._rebuildCalendar();
 | 
			
		||||
 | 
			
		||||
        this._buttons.forEach(Lang.bind(this, function(button) {
 | 
			
		||||
            if (_sameDay(button._date, this._selectedDate)) {
 | 
			
		||||
            if (sameDay(button._date, this._selectedDate)) {
 | 
			
		||||
                button.add_style_pseudo_class('active');
 | 
			
		||||
                if (this._shouldDateGrabFocus)
 | 
			
		||||
                    button.grab_key_focus();
 | 
			
		||||
@@ -818,354 +671,9 @@ const Calendar = new Lang.Class({
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(Calendar.prototype);
 | 
			
		||||
 | 
			
		||||
const ScaleLayout = new Lang.Class({
 | 
			
		||||
    Name: 'ScaleLayout',
 | 
			
		||||
    Extends: Clutter.BinLayout,
 | 
			
		||||
 | 
			
		||||
    _connectContainer: function(container) {
 | 
			
		||||
        if (this._container == container)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (this._container)
 | 
			
		||||
            for (let id of this._signals)
 | 
			
		||||
                this._container.disconnect(id);
 | 
			
		||||
 | 
			
		||||
        this._container = container;
 | 
			
		||||
        this._signals = [];
 | 
			
		||||
 | 
			
		||||
        if (this._container)
 | 
			
		||||
            for (let signal of ['notify::scale-x', 'notify::scale-y']) {
 | 
			
		||||
                let id = this._container.connect(signal, Lang.bind(this,
 | 
			
		||||
                    function() {
 | 
			
		||||
                        this.layout_changed();
 | 
			
		||||
                    }));
 | 
			
		||||
                this._signals.push(id);
 | 
			
		||||
            }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_width: function(container, forHeight) {
 | 
			
		||||
        this._connectContainer(container);
 | 
			
		||||
 | 
			
		||||
        let [min, nat] = this.parent(container, forHeight);
 | 
			
		||||
        return [Math.floor(min * container.scale_x),
 | 
			
		||||
                Math.floor(nat * container.scale_x)];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_height: function(container, forWidth) {
 | 
			
		||||
        this._connectContainer(container);
 | 
			
		||||
 | 
			
		||||
        let [min, nat] = this.parent(container, forWidth);
 | 
			
		||||
        return [Math.floor(min * container.scale_y),
 | 
			
		||||
                Math.floor(nat * container.scale_y)];
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const LabelExpanderLayout = new Lang.Class({
 | 
			
		||||
    Name: 'LabelExpanderLayout',
 | 
			
		||||
    Extends: Clutter.LayoutManager,
 | 
			
		||||
    Properties: { 'expansion': GObject.ParamSpec.double('expansion',
 | 
			
		||||
                                                        'Expansion',
 | 
			
		||||
                                                        'Expansion of the layout, between 0 (collapsed) ' +
 | 
			
		||||
                                                        'and 1 (fully expanded',
 | 
			
		||||
                                                         GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
 | 
			
		||||
                                                         0, 1, 0)},
 | 
			
		||||
 | 
			
		||||
    _init: function(params) {
 | 
			
		||||
        this._expansion = 0;
 | 
			
		||||
        this._expandLines = DEFAULT_EXPAND_LINES;
 | 
			
		||||
 | 
			
		||||
        this.parent(params);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get expansion() {
 | 
			
		||||
        return this._expansion;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    set expansion(v) {
 | 
			
		||||
        if (v == this._expansion)
 | 
			
		||||
            return;
 | 
			
		||||
        this._expansion = v;
 | 
			
		||||
        this.notify('expansion');
 | 
			
		||||
 | 
			
		||||
        let visibleIndex = this._expansion > 0 ? 1 : 0;
 | 
			
		||||
        for (let i = 0; this._container && i < this._container.get_n_children(); i++)
 | 
			
		||||
            this._container.get_child_at_index(i).visible = (i == visibleIndex);
 | 
			
		||||
 | 
			
		||||
        this.layout_changed();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    set expandLines(v) {
 | 
			
		||||
        if (v == this._expandLines)
 | 
			
		||||
            return;
 | 
			
		||||
        this._expandLines = v;
 | 
			
		||||
        if (this._expansion > 0)
 | 
			
		||||
            this.layout_changed();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_set_container: function(container) {
 | 
			
		||||
        this._container = container;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_width: function(container, forHeight) {
 | 
			
		||||
        let [min, nat] = [0, 0];
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < container.get_n_children(); i++) {
 | 
			
		||||
            if (i > 1)
 | 
			
		||||
                break; // we support one unexpanded + one expanded child
 | 
			
		||||
 | 
			
		||||
            let child = container.get_child_at_index(i);
 | 
			
		||||
            let [childMin, childNat] = child.get_preferred_width(forHeight);
 | 
			
		||||
            [min, nat] = [Math.max(min, childMin), Math.max(nat, childNat)];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return [min, nat];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_height: function(container, forWidth) {
 | 
			
		||||
        let [min, nat] = [0, 0];
 | 
			
		||||
 | 
			
		||||
        let children = container.get_children();
 | 
			
		||||
        if (children[0])
 | 
			
		||||
            [min, nat] = children[0].get_preferred_height(forWidth);
 | 
			
		||||
 | 
			
		||||
        if (children[1]) {
 | 
			
		||||
            let [min2, nat2] = children[1].get_preferred_height(forWidth);
 | 
			
		||||
            let [expMin, expNat] = [Math.min(min2, min * this._expandLines),
 | 
			
		||||
                                    Math.min(nat2, nat * this._expandLines)];
 | 
			
		||||
            [min, nat] = [min + this._expansion * (expMin - min),
 | 
			
		||||
                          nat + this._expansion * (expNat - nat)];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return [min, nat];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate: function(container, box, flags) {
 | 
			
		||||
        for (let i = 0; i < container.get_n_children(); i++) {
 | 
			
		||||
            let child = container.get_child_at_index(i);
 | 
			
		||||
 | 
			
		||||
            if (child.visible)
 | 
			
		||||
                child.allocate(box, flags);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const Message = new Lang.Class({
 | 
			
		||||
    Name: 'Message',
 | 
			
		||||
 | 
			
		||||
    _init: function(title, body) {
 | 
			
		||||
        this.expanded = false;
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.Button({ style_class: 'message',
 | 
			
		||||
                                     accessible_role: Atk.Role.NOTIFICATION,
 | 
			
		||||
                                     can_focus: true,
 | 
			
		||||
                                     x_expand: true, x_fill: true });
 | 
			
		||||
        this.actor.connect('key-press-event',
 | 
			
		||||
                           Lang.bind(this, this._onKeyPressed));
 | 
			
		||||
 | 
			
		||||
        let vbox = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        this.actor.set_child(vbox);
 | 
			
		||||
 | 
			
		||||
        let hbox = new St.BoxLayout();
 | 
			
		||||
        vbox.add_actor(hbox);
 | 
			
		||||
 | 
			
		||||
        this._actionBin = new St.Widget({ layout_manager: new ScaleLayout(),
 | 
			
		||||
                                          visible: false });
 | 
			
		||||
        vbox.add_actor(this._actionBin);
 | 
			
		||||
 | 
			
		||||
        this._iconBin = new St.Bin({ style_class: 'message-icon-bin',
 | 
			
		||||
                                     y_expand: true,
 | 
			
		||||
                                     visible: false });
 | 
			
		||||
        this._iconBin.set_y_align(Clutter.ActorAlign.START);
 | 
			
		||||
        hbox.add_actor(this._iconBin);
 | 
			
		||||
 | 
			
		||||
        let contentBox = new St.BoxLayout({ style_class: 'message-content',
 | 
			
		||||
                                            vertical: true, x_expand: true });
 | 
			
		||||
        hbox.add_actor(contentBox);
 | 
			
		||||
 | 
			
		||||
        let titleBox = new St.BoxLayout();
 | 
			
		||||
        contentBox.add_actor(titleBox);
 | 
			
		||||
 | 
			
		||||
        this.titleLabel = new St.Label({ style_class: 'message-title',
 | 
			
		||||
                                         x_expand: true,
 | 
			
		||||
                                         x_align: Clutter.ActorAlign.START });
 | 
			
		||||
        this.setTitle(title);
 | 
			
		||||
        titleBox.add_actor(this.titleLabel);
 | 
			
		||||
 | 
			
		||||
        this._secondaryBin = new St.Bin({ style_class: 'message-secondary-bin' });
 | 
			
		||||
        titleBox.add_actor(this._secondaryBin);
 | 
			
		||||
 | 
			
		||||
        let closeIcon = new St.Icon({ icon_name: 'window-close-symbolic',
 | 
			
		||||
                                      icon_size: 16 });
 | 
			
		||||
        this._closeButton = new St.Button({ child: closeIcon, visible: false });
 | 
			
		||||
        titleBox.add_actor(this._closeButton);
 | 
			
		||||
 | 
			
		||||
        this._bodyStack = new St.Widget({ x_expand: true });
 | 
			
		||||
        this._bodyStack.layout_manager = new LabelExpanderLayout();
 | 
			
		||||
        contentBox.add_actor(this._bodyStack);
 | 
			
		||||
 | 
			
		||||
        this.bodyLabel = new URLHighlighter('', false, this._useBodyMarkup);
 | 
			
		||||
        this.bodyLabel.actor.add_style_class_name('message-body');
 | 
			
		||||
        this._bodyStack.add_actor(this.bodyLabel.actor);
 | 
			
		||||
        this.setBody(body);
 | 
			
		||||
 | 
			
		||||
        this._closeButton.connect('clicked', Lang.bind(this, this.close));
 | 
			
		||||
        this.actor.connect('notify::hover', Lang.bind(this, this._sync));
 | 
			
		||||
        this.actor.connect('clicked', Lang.bind(this, this._onClicked));
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 | 
			
		||||
        this._sync();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    close: function() {
 | 
			
		||||
        this.emit('close');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setIcon: function(actor) {
 | 
			
		||||
        this._iconBin.child = actor;
 | 
			
		||||
        this._iconBin.visible = (actor != null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setSecondaryActor: function(actor) {
 | 
			
		||||
        this._secondaryBin.child = actor;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setTitle: function(text) {
 | 
			
		||||
        let title = text ? _fixMarkup(text.replace(/\n/g, ' '), false) : '';
 | 
			
		||||
        this.titleLabel.clutter_text.set_markup(title);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setBody: function(text) {
 | 
			
		||||
        this._bodyText = text;
 | 
			
		||||
        this.bodyLabel.setMarkup(text ? text.replace(/\n/g, ' ') : '',
 | 
			
		||||
                                 this._useBodyMarkup);
 | 
			
		||||
        if (this._expandedLabel)
 | 
			
		||||
            this._expandedLabel.setMarkup(text, this._useBodyMarkup);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setUseBodyMarkup: function(enable) {
 | 
			
		||||
        if (this._useBodyMarkup === enable)
 | 
			
		||||
            return;
 | 
			
		||||
        this._useBodyMarkup = enable;
 | 
			
		||||
        if (this.bodyLabel)
 | 
			
		||||
            this.setBody(this._bodyText);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setActionArea: function(actor) {
 | 
			
		||||
        if (actor == null) {
 | 
			
		||||
            if (this._actionBin.get_n_children() > 0)
 | 
			
		||||
                this._actionBin.get_child_at_index(0).destroy();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._actionBin.get_n_children() > 0)
 | 
			
		||||
            throw new Error('Message already has an action area');
 | 
			
		||||
 | 
			
		||||
        this._actionBin.add_actor(actor);
 | 
			
		||||
        this._actionBin.visible = this.expanded;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setExpandedBody: function(actor) {
 | 
			
		||||
        if (actor == null) {
 | 
			
		||||
            if (this._bodyStack.get_n_children() > 1)
 | 
			
		||||
                this._bodyStack.get_child_at_index(1).destroy();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._bodyStack.get_n_children() > 1)
 | 
			
		||||
            throw new Error('Message already has an expanded body actor');
 | 
			
		||||
 | 
			
		||||
        this._bodyStack.insert_child_at_index(actor, 1);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setExpandedLines: function(nLines) {
 | 
			
		||||
        this._bodyStack.layout_manager.expandLines = nLines;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    expand: function(animate) {
 | 
			
		||||
        this.expanded = true;
 | 
			
		||||
 | 
			
		||||
        this._actionBin.visible = (this._actionBin.get_n_children() > 0);
 | 
			
		||||
 | 
			
		||||
        if (this._bodyStack.get_n_children() < 2) {
 | 
			
		||||
            this._expandedLabel = new URLHighlighter(this._bodyText,
 | 
			
		||||
                                                     true, this._useBodyMarkup);
 | 
			
		||||
            this.setExpandedBody(this._expandedLabel.actor);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (animate) {
 | 
			
		||||
            Tweener.addTween(this._bodyStack.layout_manager,
 | 
			
		||||
                             { expansion: 1,
 | 
			
		||||
                               time: MessageTray.ANIMATION_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad' });
 | 
			
		||||
            this._actionBin.scale_y = 0;
 | 
			
		||||
            Tweener.addTween(this._actionBin,
 | 
			
		||||
                             { scale_y: 1,
 | 
			
		||||
                               time: MessageTray.ANIMATION_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad' });
 | 
			
		||||
        } else {
 | 
			
		||||
            this._bodyStack.layout_manager.expansion = 1;
 | 
			
		||||
            this._actionBin.scale_y = 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.emit('expanded');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    unexpand: function(animate) {
 | 
			
		||||
        if (animate) {
 | 
			
		||||
            Tweener.addTween(this._bodyStack.layout_manager,
 | 
			
		||||
                             { expansion: 0,
 | 
			
		||||
                               time: MessageTray.ANIMATION_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad' });
 | 
			
		||||
            Tweener.addTween(this._actionBin,
 | 
			
		||||
                             { scale_y: 0,
 | 
			
		||||
                               time: MessageTray.ANIMATION_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad',
 | 
			
		||||
                               onCompleteScope: this,
 | 
			
		||||
                               onComplete: function() {
 | 
			
		||||
                                   this._actionBin.hide();
 | 
			
		||||
                                   this.expanded = false;
 | 
			
		||||
                               }});
 | 
			
		||||
        } else {
 | 
			
		||||
            this._bodyStack.layout_manager.expansion = 0;
 | 
			
		||||
            this._actionBin.scale_y = 0;
 | 
			
		||||
            this.expanded = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.emit('unexpanded');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    canClose: function() {
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _sync: function() {
 | 
			
		||||
        let hovered = this.actor.hover;
 | 
			
		||||
        this._closeButton.visible = hovered && this.canClose();
 | 
			
		||||
        this._secondaryBin.visible = !hovered;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onClicked: function() {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDestroy: function() {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeyPressed: function(a, event) {
 | 
			
		||||
        let keysym = event.get_key_symbol();
 | 
			
		||||
 | 
			
		||||
        if (keysym == Clutter.KEY_Delete ||
 | 
			
		||||
            keysym == Clutter.KEY_KP_Delete) {
 | 
			
		||||
            this.close();
 | 
			
		||||
            return Clutter.EVENT_STOP;
 | 
			
		||||
        }
 | 
			
		||||
        return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(Message.prototype);
 | 
			
		||||
 | 
			
		||||
const EventMessage = new Lang.Class({
 | 
			
		||||
    Name: 'EventMessage',
 | 
			
		||||
    Extends: Message,
 | 
			
		||||
    Extends: MessageList.Message,
 | 
			
		||||
 | 
			
		||||
    _init: function(event, date) {
 | 
			
		||||
        this._event = event;
 | 
			
		||||
@@ -1208,13 +716,13 @@ const EventMessage = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    canClose: function() {
 | 
			
		||||
        return _isToday(this._date);
 | 
			
		||||
        return isToday(this._date);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const NotificationMessage = new Lang.Class({
 | 
			
		||||
    Name: 'NotificationMessage',
 | 
			
		||||
    Extends: Message,
 | 
			
		||||
    Extends: MessageList.Message,
 | 
			
		||||
 | 
			
		||||
    _init: function(notification) {
 | 
			
		||||
        this.notification = notification;
 | 
			
		||||
@@ -1229,7 +737,7 @@ const NotificationMessage = new Lang.Class({
 | 
			
		||||
                this._closed = true;
 | 
			
		||||
                this.notification.destroy(MessageTray.NotificationDestroyedReason.DISMISSED);
 | 
			
		||||
            }));
 | 
			
		||||
        notification.connect('destroy', Lang.bind(this,
 | 
			
		||||
        this._destroyId = notification.connect('destroy', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
                if (!this._closed)
 | 
			
		||||
                    this.close();
 | 
			
		||||
@@ -1240,9 +748,10 @@ const NotificationMessage = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _getIcon: function() {
 | 
			
		||||
        if (this.notification.gicon)
 | 
			
		||||
            return new St.Icon({ gicon: this.notification.gicon, icon_size: 48 });
 | 
			
		||||
            return new St.Icon({ gicon: this.notification.gicon,
 | 
			
		||||
                                 icon_size: MESSAGE_ICON_SIZE });
 | 
			
		||||
        else
 | 
			
		||||
            return this.notification.source.createIcon(48);
 | 
			
		||||
            return this.notification.source.createIcon(MESSAGE_ICON_SIZE);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onUpdated: function(n, clear) {
 | 
			
		||||
@@ -1260,220 +769,16 @@ const NotificationMessage = new Lang.Class({
 | 
			
		||||
        if (this._updatedId)
 | 
			
		||||
            this.notification.disconnect(this._updatedId);
 | 
			
		||||
        this._updatedId = 0;
 | 
			
		||||
 | 
			
		||||
        if (this._destroyId)
 | 
			
		||||
            this.notification.disconnect(this._destroyId);
 | 
			
		||||
        this._destroyId = 0;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const MessageListSection = new Lang.Class({
 | 
			
		||||
    Name: 'MessageListSection',
 | 
			
		||||
 | 
			
		||||
    _init: function(title) {
 | 
			
		||||
        this.actor = new St.BoxLayout({ style_class: 'message-list-section',
 | 
			
		||||
                                        clip_to_allocation: true,
 | 
			
		||||
                                        x_expand: true, vertical: true });
 | 
			
		||||
        let titleBox = new St.BoxLayout({ style_class: 'message-list-section-title-box' });
 | 
			
		||||
        this.actor.add_actor(titleBox);
 | 
			
		||||
 | 
			
		||||
        this._title = new St.Button({ style_class: 'message-list-section-title',
 | 
			
		||||
                                      label: title,
 | 
			
		||||
                                      can_focus: true,
 | 
			
		||||
                                      x_expand: true,
 | 
			
		||||
                                      x_align: St.Align.START });
 | 
			
		||||
        titleBox.add_actor(this._title);
 | 
			
		||||
 | 
			
		||||
        this._title.connect('clicked', Lang.bind(this, this._onTitleClicked));
 | 
			
		||||
        this._title.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
 | 
			
		||||
 | 
			
		||||
        let closeIcon = new St.Icon({ icon_name: 'window-close-symbolic' });
 | 
			
		||||
        this._closeButton = new St.Button({ style_class: 'message-list-section-close',
 | 
			
		||||
                                            child: closeIcon,
 | 
			
		||||
                                            accessible_name: _("Clear section"),
 | 
			
		||||
                                            can_focus: true });
 | 
			
		||||
        this._closeButton.set_x_align(Clutter.ActorAlign.END);
 | 
			
		||||
        titleBox.add_actor(this._closeButton);
 | 
			
		||||
 | 
			
		||||
        this._closeButton.connect('clicked', Lang.bind(this, this.clear));
 | 
			
		||||
 | 
			
		||||
        this._list = new St.BoxLayout({ style_class: 'message-list-section-list',
 | 
			
		||||
                                        vertical: true });
 | 
			
		||||
        this.actor.add_actor(this._list);
 | 
			
		||||
 | 
			
		||||
        this._list.connect('actor-added', Lang.bind(this, this._sync));
 | 
			
		||||
        this._list.connect('actor-removed', Lang.bind(this, this._sync));
 | 
			
		||||
 | 
			
		||||
        let id = Main.sessionMode.connect('updated',
 | 
			
		||||
                                          Lang.bind(this, this._sync));
 | 
			
		||||
        this.actor.connect('destroy', function() {
 | 
			
		||||
            Main.sessionMode.disconnect(id);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._messages = new Map();
 | 
			
		||||
        this._date = new Date();
 | 
			
		||||
        this.empty = true;
 | 
			
		||||
        this._sync();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onTitleClicked: function() {
 | 
			
		||||
        Main.overview.hide();
 | 
			
		||||
        Main.panel.closeCalendar();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeyFocusIn: function(actor) {
 | 
			
		||||
        this.emit('key-focus-in', actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get allowed() {
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setDate: function(date) {
 | 
			
		||||
        if (_sameDay(date, this._date))
 | 
			
		||||
            return;
 | 
			
		||||
        this._date = date;
 | 
			
		||||
        this._sync();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addMessage: function(message, animate) {
 | 
			
		||||
        this.addMessageAtIndex(message, -1, animate);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addMessageAtIndex: function(message, index, animate) {
 | 
			
		||||
        let obj = {
 | 
			
		||||
            container: null,
 | 
			
		||||
            destroyId: 0,
 | 
			
		||||
            keyFocusId: 0,
 | 
			
		||||
            closeId: 0
 | 
			
		||||
        };
 | 
			
		||||
        let pivot = new Clutter.Point({ x: .5, y: .5 });
 | 
			
		||||
        let scale = animate ? 0 : 1;
 | 
			
		||||
        obj.container = new St.Widget({ layout_manager: new ScaleLayout(),
 | 
			
		||||
                                        pivot_point: pivot,
 | 
			
		||||
                                        scale_x: scale, scale_y: scale });
 | 
			
		||||
        obj.keyFocusId = message.actor.connect('key-focus-in',
 | 
			
		||||
            Lang.bind(this, this._onKeyFocusIn));
 | 
			
		||||
        obj.destroyId = message.actor.connect('destroy',
 | 
			
		||||
            Lang.bind(this, function() {
 | 
			
		||||
                this.removeMessage(message, false);
 | 
			
		||||
            }));
 | 
			
		||||
        obj.closeId = message.connect('close',
 | 
			
		||||
            Lang.bind(this, function() {
 | 
			
		||||
                this.removeMessage(message, true);
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        this._messages.set(message, obj);
 | 
			
		||||
        obj.container.add_actor(message.actor);
 | 
			
		||||
 | 
			
		||||
        this._list.insert_child_at_index(obj.container, index);
 | 
			
		||||
 | 
			
		||||
        if (animate)
 | 
			
		||||
            Tweener.addTween(obj.container, { scale_x: 1,
 | 
			
		||||
                                              scale_y: 1,
 | 
			
		||||
                                              time: MESSAGE_ANIMATION_TIME,
 | 
			
		||||
                                              transition: 'easeOutQuad' });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    moveMessage: function(message, index, animate) {
 | 
			
		||||
        let obj = this._messages.get(message);
 | 
			
		||||
 | 
			
		||||
        if (!animate) {
 | 
			
		||||
            this._list.set_child_at_index(obj.container, index);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let onComplete = Lang.bind(this, function() {
 | 
			
		||||
            this._list.set_child_at_index(obj.container, index);
 | 
			
		||||
            Tweener.addTween(obj.container, { scale_x: 1,
 | 
			
		||||
                                              scale_y: 1,
 | 
			
		||||
                                              time: MESSAGE_ANIMATION_TIME,
 | 
			
		||||
                                              transition: 'easeOutQuad' });
 | 
			
		||||
        });
 | 
			
		||||
        Tweener.addTween(obj.container, { scale_x: 0,
 | 
			
		||||
                                          scale_y: 0,
 | 
			
		||||
                                          time: MESSAGE_ANIMATION_TIME,
 | 
			
		||||
                                          transition: 'easeOutQuad',
 | 
			
		||||
                                          onComplete: onComplete });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    removeMessage: function(message, animate) {
 | 
			
		||||
        let obj = this._messages.get(message);
 | 
			
		||||
 | 
			
		||||
        message.actor.disconnect(obj.destroyId);
 | 
			
		||||
        message.actor.disconnect(obj.keyFocusId);
 | 
			
		||||
        message.disconnect(obj.closeId);
 | 
			
		||||
 | 
			
		||||
        this._messages.delete(message);
 | 
			
		||||
 | 
			
		||||
        if (animate) {
 | 
			
		||||
            Tweener.addTween(obj.container, { scale_x: 0, scale_y: 0,
 | 
			
		||||
                                              time: MESSAGE_ANIMATION_TIME,
 | 
			
		||||
                                              transition: 'easeOutQuad',
 | 
			
		||||
                                              onComplete: function() {
 | 
			
		||||
                                                  obj.container.destroy();
 | 
			
		||||
                                                  global.sync_pointer();
 | 
			
		||||
                                              }});
 | 
			
		||||
        } else {
 | 
			
		||||
            obj.container.destroy();
 | 
			
		||||
            global.sync_pointer();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    clear: function() {
 | 
			
		||||
        let messages = [...this._messages.keys()].filter(function(message) {
 | 
			
		||||
            return message.canClose();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // If there are few messages, letting them all zoom out looks OK
 | 
			
		||||
        if (messages.length < 2) {
 | 
			
		||||
            messages.forEach(function(message) {
 | 
			
		||||
                message.close();
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            // Otherwise we slide them out one by one, and then zoom them
 | 
			
		||||
            // out "off-screen" in the end to smoothly shrink the parent
 | 
			
		||||
            let delay = MESSAGE_ANIMATION_TIME / Math.max(messages.length, 5);
 | 
			
		||||
            for (let i = 0; i < messages.length; i++) {
 | 
			
		||||
                let message = messages[i];
 | 
			
		||||
                let obj = this._messages.get(message);
 | 
			
		||||
                Tweener.addTween(obj.container,
 | 
			
		||||
                                 { anchor_x: this._list.width,
 | 
			
		||||
                                   opacity: 0,
 | 
			
		||||
                                   time: MESSAGE_ANIMATION_TIME,
 | 
			
		||||
                                   delay: i * delay,
 | 
			
		||||
                                   transition: 'easeOutQuad',
 | 
			
		||||
                                   onComplete: function() {
 | 
			
		||||
                                       message.close();
 | 
			
		||||
                                   }});
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _canClear: function() {
 | 
			
		||||
        for (let message of this._messages.keys())
 | 
			
		||||
            if (message.canClose())
 | 
			
		||||
                return true;
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _shouldShow: function() {
 | 
			
		||||
        return !this.empty;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _sync: function() {
 | 
			
		||||
        let empty = this._list.get_n_children() == 0;
 | 
			
		||||
        let changed = this.empty !== empty;
 | 
			
		||||
        this.empty = empty;
 | 
			
		||||
 | 
			
		||||
        if (changed)
 | 
			
		||||
            this.emit('empty-changed');
 | 
			
		||||
 | 
			
		||||
        this._closeButton.visible = this._canClear();
 | 
			
		||||
        this.actor.visible = this.allowed && this._shouldShow();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(MessageListSection.prototype);
 | 
			
		||||
 | 
			
		||||
const EventsSection = new Lang.Class({
 | 
			
		||||
    Name: 'EventsSection',
 | 
			
		||||
    Extends: MessageListSection,
 | 
			
		||||
    Extends: MessageList.MessageListSection,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
 | 
			
		||||
@@ -1512,14 +817,14 @@ const EventsSection = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateTitle: function() {
 | 
			
		||||
        if (_isToday(this._date)) {
 | 
			
		||||
        if (isToday(this._date)) {
 | 
			
		||||
            this._title.label = _("Events");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let dayFormat;
 | 
			
		||||
        let now = new Date();
 | 
			
		||||
        if (_sameYear(this._date, now))
 | 
			
		||||
        if (sameYear(this._date, now))
 | 
			
		||||
            /* Translators: Shown on calendar heading when selected day occurs on current year */
 | 
			
		||||
            dayFormat = Shell.util_translate_time_string(NC_("calendar heading",
 | 
			
		||||
                                                             "%A, %B %d"));
 | 
			
		||||
@@ -1595,7 +900,7 @@ const EventsSection = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _shouldShow: function() {
 | 
			
		||||
        return !this.empty || !_isToday(this._date);
 | 
			
		||||
        return !this.empty || !isToday(this._date);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _sync: function() {
 | 
			
		||||
@@ -1608,7 +913,7 @@ const EventsSection = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
const NotificationSection = new Lang.Class({
 | 
			
		||||
    Name: 'NotificationSection',
 | 
			
		||||
    Extends: MessageListSection,
 | 
			
		||||
    Extends: MessageList.MessageListSection,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.parent(_("Notifications"));
 | 
			
		||||
@@ -1714,7 +1019,7 @@ const NotificationSection = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _shouldShow: function() {
 | 
			
		||||
        return !this.empty && _isToday(this._date);
 | 
			
		||||
        return !this.empty && isToday(this._date);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _sync: function() {
 | 
			
		||||
@@ -1747,20 +1052,20 @@ const Placeholder = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setDate: function(date) {
 | 
			
		||||
        if (_sameDay(this._date, date))
 | 
			
		||||
        if (sameDay(this._date, date))
 | 
			
		||||
            return;
 | 
			
		||||
        this._date = date;
 | 
			
		||||
        this._sync();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _sync: function() {
 | 
			
		||||
        let isToday = _isToday(this._date);
 | 
			
		||||
        if (isToday && this._icon.gicon == this._todayIcon)
 | 
			
		||||
        let today = isToday(this._date);
 | 
			
		||||
        if (today && this._icon.gicon == this._todayIcon)
 | 
			
		||||
            return;
 | 
			
		||||
        if (!isToday && this._icon.gicon == this._otherIcon)
 | 
			
		||||
        if (!today && this._icon.gicon == this._otherIcon)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (isToday) {
 | 
			
		||||
        if (today) {
 | 
			
		||||
            this._icon.gicon = this._todayIcon;
 | 
			
		||||
            this._label.text = _("No Notifications");
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -1770,8 +1075,8 @@ const Placeholder = new Lang.Class({
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const MessageList = new Lang.Class({
 | 
			
		||||
    Name: 'MessageList',
 | 
			
		||||
const CalendarMessageList = new Lang.Class({
 | 
			
		||||
    Name: 'CalendarMessageList',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.actor = new St.Widget({ style_class: 'message-list',
 | 
			
		||||
@@ -1795,6 +1100,9 @@ const MessageList = new Lang.Class({
 | 
			
		||||
        this._scrollView.add_actor(this._sectionList);
 | 
			
		||||
        this._sections = new Map();
 | 
			
		||||
 | 
			
		||||
        this._mediaSection = new Mpris.MediaSection();
 | 
			
		||||
        this._addSection(this._mediaSection);
 | 
			
		||||
 | 
			
		||||
        this._notificationSection = new NotificationSection();
 | 
			
		||||
        this._addSection(this._notificationSection);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -313,6 +313,10 @@ const AutorunSource = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    getIcon: function() {
 | 
			
		||||
        return this.mount.get_icon();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createPolicy: function() {
 | 
			
		||||
        return new MessageTray.NotificationApplicationPolicy('org.gnome.Nautilus');
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -325,9 +329,6 @@ const AutorunNotification = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._manager = manager;
 | 
			
		||||
        this._mount = source.mount;
 | 
			
		||||
 | 
			
		||||
        // set the notification to urgent, so that it expands out
 | 
			
		||||
        this.setUrgency(MessageTray.Urgency.CRITICAL);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createBanner: function() {
 | 
			
		||||
 
 | 
			
		||||
@@ -9,9 +9,15 @@ const Gio = imports.gi.Gio;
 | 
			
		||||
const GObject = imports.gi.GObject;
 | 
			
		||||
const Gcr = imports.gi.Gcr;
 | 
			
		||||
 | 
			
		||||
const Animation = imports.ui.animation;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const ShellEntry = imports.ui.shellEntry;
 | 
			
		||||
const CheckBox = imports.ui.checkBox;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
const WORK_SPINNER_ICON_SIZE = 16;
 | 
			
		||||
const WORK_SPINNER_ANIMATION_DELAY = 1.0;
 | 
			
		||||
const WORK_SPINNER_ANIMATION_TIME = 0.3;
 | 
			
		||||
 | 
			
		||||
const KeyringDialog = new Lang.Class({
 | 
			
		||||
    Name: 'KeyringDialog',
 | 
			
		||||
@@ -58,27 +64,47 @@ const KeyringDialog = new Lang.Class({
 | 
			
		||||
                            { y_fill:  true,
 | 
			
		||||
                              y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        this._workSpinner = null;
 | 
			
		||||
        this._controlTable = null;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        this._cancelButton = this.addButton({ label: '',
 | 
			
		||||
                                              action: Lang.bind(this, this._onCancelButton),
 | 
			
		||||
                                              key: Clutter.Escape },
 | 
			
		||||
                                            { expand: true, x_fill: false, x_align: St.Align.START });
 | 
			
		||||
        this.placeSpinner({ expand: false,
 | 
			
		||||
                            x_fill: false,
 | 
			
		||||
                            y_fill: false,
 | 
			
		||||
                            x_align: St.Align.END,
 | 
			
		||||
                            y_align: St.Align.MIDDLE });
 | 
			
		||||
                                              key: Clutter.Escape });
 | 
			
		||||
        this._continueButton = this.addButton({ label: '',
 | 
			
		||||
                                                action: Lang.bind(this, this._onContinueButton),
 | 
			
		||||
                                                default: true },
 | 
			
		||||
                                              { expand: false, x_fill: false, x_align: St.Align.END });
 | 
			
		||||
                                                default: true });
 | 
			
		||||
 | 
			
		||||
        this.prompt.bind_property('cancel-label', this._cancelButton, 'label', GObject.BindingFlags.SYNC_CREATE);
 | 
			
		||||
        this.prompt.bind_property('continue-label', this._continueButton, 'label', GObject.BindingFlags.SYNC_CREATE);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setWorking: function(working) {
 | 
			
		||||
        if (!this._workSpinner)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Tweener.removeTweens(this._workSpinner.actor);
 | 
			
		||||
        if (working) {
 | 
			
		||||
            this._workSpinner.play();
 | 
			
		||||
            Tweener.addTween(this._workSpinner.actor,
 | 
			
		||||
                             { opacity: 255,
 | 
			
		||||
                               delay: WORK_SPINNER_ANIMATION_DELAY,
 | 
			
		||||
                               time: WORK_SPINNER_ANIMATION_TIME,
 | 
			
		||||
                               transition: 'linear'
 | 
			
		||||
                             });
 | 
			
		||||
        } else {
 | 
			
		||||
            Tweener.addTween(this._workSpinner.actor,
 | 
			
		||||
                             { opacity: 0,
 | 
			
		||||
                               time: WORK_SPINNER_ANIMATION_TIME,
 | 
			
		||||
                               transition: 'linear',
 | 
			
		||||
                               onCompleteScope: this,
 | 
			
		||||
                               onComplete: function() {
 | 
			
		||||
                                   if (this._workSpinner)
 | 
			
		||||
                                       this._workSpinner.stop();
 | 
			
		||||
                               }
 | 
			
		||||
                             });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _buildControlTable: function() {
 | 
			
		||||
        let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
 | 
			
		||||
        let table = new St.Widget({ style_class: 'keyring-dialog-control-table',
 | 
			
		||||
@@ -101,15 +127,22 @@ const KeyringDialog = new Lang.Class({
 | 
			
		||||
            ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
 | 
			
		||||
            this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onPasswordActivate));
 | 
			
		||||
 | 
			
		||||
            let spinnerIcon = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/process-working.svg');
 | 
			
		||||
            this._workSpinner = new Animation.AnimatedIcon(spinnerIcon, WORK_SPINNER_ICON_SIZE);
 | 
			
		||||
            this._workSpinner.actor.opacity = 0;
 | 
			
		||||
 | 
			
		||||
            if (rtl) {
 | 
			
		||||
                layout.attach(this._passwordEntry, 0, row, 1, 1);
 | 
			
		||||
                layout.attach(label, 1, row, 1, 1);
 | 
			
		||||
                layout.attach(this._workSpinner.actor, 0, row, 1, 1);
 | 
			
		||||
                layout.attach(this._passwordEntry, 1, row, 1, 1);
 | 
			
		||||
                layout.attach(label, 2, row, 1, 1);
 | 
			
		||||
            } else {
 | 
			
		||||
                layout.attach(label, 0, row, 1, 1);
 | 
			
		||||
                layout.attach(this._passwordEntry, 1, row, 1, 1);
 | 
			
		||||
                layout.attach(this._workSpinner.actor, 2, row, 1, 1);
 | 
			
		||||
            }
 | 
			
		||||
            row++;
 | 
			
		||||
        } else {
 | 
			
		||||
            this._workSpinner = null;
 | 
			
		||||
            this._passwordEntry = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -178,7 +211,7 @@ const KeyringDialog = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._continueButton.can_focus = sensitive;
 | 
			
		||||
        this._continueButton.reactive = sensitive;
 | 
			
		||||
        this.setWorking(!sensitive);
 | 
			
		||||
        this._setWorking(!sensitive);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _ensureOpen: function() {
 | 
			
		||||
 
 | 
			
		||||
@@ -796,10 +796,18 @@ const NetworkAgent = new Lang.Class({
 | 
			
		||||
                        path = GLib.build_filenamev([Config.LIBEXECDIR, path]);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (GLib.file_test(path, GLib.FileTest.IS_EXECUTABLE))
 | 
			
		||||
                    if (GLib.file_test(path, GLib.FileTest.IS_EXECUTABLE)) {
 | 
			
		||||
                        this._vpnBinaries[service] = { fileName: path, externalUIMode: externalUIMode, supportsHints: hints };
 | 
			
		||||
                    else
 | 
			
		||||
                        try {
 | 
			
		||||
                            let aliases = keyfile.get_string_list('VPN Connection', 'aliases');
 | 
			
		||||
 | 
			
		||||
                            for (let alias of aliases) {
 | 
			
		||||
                                this._vpnBinaries[alias] = { fileName: path, externalUIMode: externalUIMode, supportsHints: hints };
 | 
			
		||||
                            }
 | 
			
		||||
                        } catch(e) { } // ignore errors if key does not exist
 | 
			
		||||
                    } else {
 | 
			
		||||
                        throw new Error('VPN plugin at %s is not executable'.format(path));
 | 
			
		||||
                    }
 | 
			
		||||
                } catch(e) {
 | 
			
		||||
                    log('Error \'%s\' while processing VPN keyfile \'%s\''.
 | 
			
		||||
                        format(e.message, dir.get_child(name).get_path()));
 | 
			
		||||
 
 | 
			
		||||
@@ -13,13 +13,19 @@ const Mainloop = imports.mainloop;
 | 
			
		||||
const Polkit = imports.gi.Polkit;
 | 
			
		||||
const PolkitAgent = imports.gi.PolkitAgent;
 | 
			
		||||
 | 
			
		||||
const Animation = imports.ui.animation;
 | 
			
		||||
const Components = imports.ui.components;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const ShellEntry = imports.ui.shellEntry;
 | 
			
		||||
const UserWidget = imports.ui.userWidget;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
const DIALOG_ICON_SIZE = 48;
 | 
			
		||||
 | 
			
		||||
const WORK_SPINNER_ICON_SIZE = 16;
 | 
			
		||||
const WORK_SPINNER_ANIMATION_DELAY = 1.0;
 | 
			
		||||
const WORK_SPINNER_ANIMATION_TIME = 0.3;
 | 
			
		||||
 | 
			
		||||
const AuthenticationDialog = new Lang.Class({
 | 
			
		||||
    Name: 'AuthenticationDialog',
 | 
			
		||||
    Extends: ModalDialog.ModalDialog,
 | 
			
		||||
@@ -136,6 +142,13 @@ const AuthenticationDialog = new Lang.Class({
 | 
			
		||||
        this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivate));
 | 
			
		||||
        this._passwordBox.add(this._passwordEntry,
 | 
			
		||||
                              { expand: true });
 | 
			
		||||
 | 
			
		||||
        let spinnerIcon = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/process-working.svg');
 | 
			
		||||
        this._workSpinner = new Animation.AnimatedIcon(spinnerIcon, WORK_SPINNER_ICON_SIZE);
 | 
			
		||||
        this._workSpinner.actor.opacity = 0;
 | 
			
		||||
 | 
			
		||||
        this._passwordBox.add(this._workSpinner.actor);
 | 
			
		||||
 | 
			
		||||
        this.setInitialKeyFocus(this._passwordEntry);
 | 
			
		||||
        this._passwordBox.hide();
 | 
			
		||||
 | 
			
		||||
@@ -165,17 +178,10 @@ const AuthenticationDialog = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._cancelButton = this.addButton({ label: _("Cancel"),
 | 
			
		||||
                                              action: Lang.bind(this, this.cancel),
 | 
			
		||||
                                              key: Clutter.Escape },
 | 
			
		||||
                                            { expand: true, x_fill: false, x_align: St.Align.START });
 | 
			
		||||
        this.placeSpinner({ expand: false,
 | 
			
		||||
                            x_fill: false,
 | 
			
		||||
                            y_fill: false,
 | 
			
		||||
                            x_align: St.Align.END,
 | 
			
		||||
                            y_align: St.Align.MIDDLE });
 | 
			
		||||
                                              key: Clutter.Escape });
 | 
			
		||||
        this._okButton = this.addButton({ label:  _("Authenticate"),
 | 
			
		||||
                                          action: Lang.bind(this, this._onAuthenticateButtonPressed),
 | 
			
		||||
                                          default: true },
 | 
			
		||||
                                        { expand: false, x_fill: false, x_align: St.Align.END });
 | 
			
		||||
                                          default: true });
 | 
			
		||||
 | 
			
		||||
        this._doneEmitted = false;
 | 
			
		||||
 | 
			
		||||
@@ -183,6 +189,30 @@ const AuthenticationDialog = new Lang.Class({
 | 
			
		||||
        this._cookie = cookie;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setWorking: function(working) {
 | 
			
		||||
        Tweener.removeTweens(this._workSpinner.actor);
 | 
			
		||||
        if (working) {
 | 
			
		||||
            this._workSpinner.play();
 | 
			
		||||
            Tweener.addTween(this._workSpinner.actor,
 | 
			
		||||
                             { opacity: 255,
 | 
			
		||||
                               delay: WORK_SPINNER_ANIMATION_DELAY,
 | 
			
		||||
                               time: WORK_SPINNER_ANIMATION_TIME,
 | 
			
		||||
                               transition: 'linear'
 | 
			
		||||
                             });
 | 
			
		||||
        } else {
 | 
			
		||||
            Tweener.addTween(this._workSpinner.actor,
 | 
			
		||||
                             { opacity: 0,
 | 
			
		||||
                               time: WORK_SPINNER_ANIMATION_TIME,
 | 
			
		||||
                               transition: 'linear',
 | 
			
		||||
                               onCompleteScope: this,
 | 
			
		||||
                               onComplete: function() {
 | 
			
		||||
                                   if (this._workSpinner)
 | 
			
		||||
                                       this._workSpinner.stop();
 | 
			
		||||
                               }
 | 
			
		||||
                             });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    performAuthentication: function() {
 | 
			
		||||
        this.destroySession();
 | 
			
		||||
        this._session = new PolkitAgent.Session({ identity: this._identityToAuth,
 | 
			
		||||
@@ -229,7 +259,7 @@ const AuthenticationDialog = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._okButton.can_focus = sensitive;
 | 
			
		||||
        this._okButton.reactive = sensitive;
 | 
			
		||||
        this.setWorking(!sensitive);
 | 
			
		||||
        this._setWorking(!sensitive);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onEntryActivate: function() {
 | 
			
		||||
 
 | 
			
		||||
@@ -12,9 +12,9 @@ const St = imports.gi.St;
 | 
			
		||||
const Tpl = imports.gi.TelepathyLogger;
 | 
			
		||||
const Tp = imports.gi.TelepathyGLib;
 | 
			
		||||
 | 
			
		||||
const Calendar = imports.ui.calendar;
 | 
			
		||||
const History = imports.misc.history;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageList = imports.ui.messageList;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const PopupMenu = imports.ui.popupMenu;
 | 
			
		||||
@@ -303,6 +303,8 @@ const ChatSource = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createPolicy: function() {
 | 
			
		||||
        if (this._account.protocol_name == 'irc')
 | 
			
		||||
            return new MessageTray.NotificationApplicationPolicy('org.gnome.Polari');
 | 
			
		||||
        return new MessageTray.NotificationApplicationPolicy('empathy');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -467,6 +469,7 @@ const ChatSource = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    destroy: function(reason) {
 | 
			
		||||
        if (this._client.is_handling_channel(this._channel)) {
 | 
			
		||||
            this._ackMessages();
 | 
			
		||||
            // The chat box has been destroyed so it can't
 | 
			
		||||
            // handle the channel any more.
 | 
			
		||||
            this._channel.close_async(function(channel, result) {
 | 
			
		||||
@@ -864,7 +867,7 @@ const ChatNotificationBanner = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _addMessage: function(message) {
 | 
			
		||||
        let highlighter = new Calendar.URLHighlighter(message.body, true, true);
 | 
			
		||||
        let highlighter = new MessageList.URLHighlighter(message.body, true, true);
 | 
			
		||||
        let body = highlighter.actor;
 | 
			
		||||
 | 
			
		||||
        let styles = message.styles;
 | 
			
		||||
 
 | 
			
		||||
@@ -259,7 +259,7 @@ const ShowAppsIcon = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createIcon: function(size) {
 | 
			
		||||
        this._iconActor = new St.Icon({ icon_name: 'view-grid-symbolic',
 | 
			
		||||
        this._iconActor = new St.Icon({ icon_name: 'view-app-grid-symbolic',
 | 
			
		||||
                                        icon_size: size,
 | 
			
		||||
                                        style_class: 'show-apps-icon',
 | 
			
		||||
                                        track_hover: true });
 | 
			
		||||
@@ -644,15 +644,14 @@ const Dash = new Lang.Class({
 | 
			
		||||
        let firstIcon = firstButton._delegate.icon;
 | 
			
		||||
 | 
			
		||||
        let minHeight, natHeight;
 | 
			
		||||
        let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
 | 
			
		||||
 | 
			
		||||
        // Enforce the current icon size during the size request
 | 
			
		||||
        firstIcon.setIconSize(this.iconSize);
 | 
			
		||||
        firstIcon.icon.ensure_style();
 | 
			
		||||
        let [currentWidth, currentHeight] = firstIcon.icon.get_size();
 | 
			
		||||
        firstIcon.icon.set_size(this.iconSize * scaleFactor, this.iconSize * scaleFactor);
 | 
			
		||||
        [minHeight, natHeight] = firstButton.get_preferred_height(-1);
 | 
			
		||||
 | 
			
		||||
        let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
 | 
			
		||||
        let iconSizes = baseIconSizes.map(function(s) {
 | 
			
		||||
            return s * scaleFactor;
 | 
			
		||||
        });
 | 
			
		||||
        firstIcon.icon.set_size(currentWidth, currentHeight);
 | 
			
		||||
 | 
			
		||||
        // Subtract icon padding and box spacing from the available height
 | 
			
		||||
        availHeight -= iconChildren.length * (natHeight - this.iconSize * scaleFactor) +
 | 
			
		||||
@@ -660,6 +659,10 @@ const Dash = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        let availSize = availHeight / iconChildren.length;
 | 
			
		||||
 | 
			
		||||
        let iconSizes = baseIconSizes.map(function(s) {
 | 
			
		||||
            return s * scaleFactor;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let newIconSize = baseIconSizes[0];
 | 
			
		||||
        for (let i = 0; i < iconSizes.length; i++) {
 | 
			
		||||
            if (iconSizes[i] < availSize)
 | 
			
		||||
 
 | 
			
		||||
@@ -357,12 +357,10 @@ const DateMenuButton = new Lang.Class({
 | 
			
		||||
                this._date.setDate(now);
 | 
			
		||||
                this._messageList.setDate(now);
 | 
			
		||||
            }
 | 
			
		||||
            // Block notification banners while the menu is open
 | 
			
		||||
            Main.messageTray.bannerBlocked = isOpen;
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        // Fill up the first column
 | 
			
		||||
        this._messageList = new Calendar.MessageList();
 | 
			
		||||
        this._messageList = new Calendar.CalendarMessageList();
 | 
			
		||||
        hbox.add(this._messageList.actor, { expand: true, y_fill: false, y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        // Fill up the second column
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										141
									
								
								js/ui/dnd.js
									
									
									
									
									
								
							
							
						
						@@ -79,9 +79,12 @@ const _Draggable = new Lang.Class({
 | 
			
		||||
                                        dragActorOpacity: undefined });
 | 
			
		||||
 | 
			
		||||
        this.actor = actor;
 | 
			
		||||
        if (!params.manualMode)
 | 
			
		||||
        if (!params.manualMode) {
 | 
			
		||||
            this.actor.connect('button-press-event',
 | 
			
		||||
                               Lang.bind(this, this._onButtonPress));
 | 
			
		||||
            this.actor.connect('touch-event',
 | 
			
		||||
                               Lang.bind(this, this._onTouchEvent));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, function() {
 | 
			
		||||
            this._actorDestroyed = true;
 | 
			
		||||
@@ -121,8 +124,50 @@ const _Draggable = new Lang.Class({
 | 
			
		||||
        return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onTouchEvent: function (actor, event) {
 | 
			
		||||
        if (event.type() != Clutter.EventType.TOUCH_BEGIN ||
 | 
			
		||||
            !global.display.is_pointer_emulating_sequence(event.get_event_sequence()))
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
        if (Tweener.getTweenCount(actor))
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
        this._touchSequence = event.get_event_sequence();
 | 
			
		||||
 | 
			
		||||
        this._buttonDown = true;
 | 
			
		||||
        this._grabActor();
 | 
			
		||||
 | 
			
		||||
        let [stageX, stageY] = event.get_coords();
 | 
			
		||||
        this._dragStartX = stageX;
 | 
			
		||||
        this._dragStartY = stageY;
 | 
			
		||||
 | 
			
		||||
        return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _grabDevice: function(actor) {
 | 
			
		||||
        let manager = Clutter.DeviceManager.get_default();
 | 
			
		||||
        let pointer = manager.get_core_device(Clutter.InputDeviceType.POINTER_DEVICE);
 | 
			
		||||
 | 
			
		||||
        if (pointer && this._touchSequence)
 | 
			
		||||
            pointer.sequence_grab(this._touchSequence, actor);
 | 
			
		||||
        else if (pointer)
 | 
			
		||||
            pointer.grab (actor);
 | 
			
		||||
 | 
			
		||||
        this._grabbedDevice = pointer;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _ungrabDevice: function() {
 | 
			
		||||
        if (this._touchSequence)
 | 
			
		||||
            this._grabbedDevice.sequence_ungrab (this._touchSequence);
 | 
			
		||||
        else
 | 
			
		||||
            this._grabbedDevice.ungrab();
 | 
			
		||||
 | 
			
		||||
        this._touchSequence = null;
 | 
			
		||||
        this._grabbedDevice = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _grabActor: function() {
 | 
			
		||||
        Clutter.grab_pointer(this.actor);
 | 
			
		||||
        this._grabDevice(this.actor);
 | 
			
		||||
        this._onEventId = this.actor.connect('event',
 | 
			
		||||
                                             Lang.bind(this, this._onEvent));
 | 
			
		||||
    },
 | 
			
		||||
@@ -131,7 +176,7 @@ const _Draggable = new Lang.Class({
 | 
			
		||||
        if (!this._onEventId)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Clutter.ungrab_pointer();
 | 
			
		||||
        this._ungrabDevice();
 | 
			
		||||
        this.actor.disconnect(this._onEventId);
 | 
			
		||||
        this._onEventId = null;
 | 
			
		||||
    },
 | 
			
		||||
@@ -140,13 +185,13 @@ const _Draggable = new Lang.Class({
 | 
			
		||||
        if (!this._eventsGrabbed) {
 | 
			
		||||
            this._eventsGrabbed = Main.pushModal(_getEventHandlerActor());
 | 
			
		||||
            if (this._eventsGrabbed)
 | 
			
		||||
                Clutter.grab_pointer(_getEventHandlerActor());
 | 
			
		||||
                this._grabDevice(_getEventHandlerActor());
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _ungrabEvents: function() {
 | 
			
		||||
        if (this._eventsGrabbed) {
 | 
			
		||||
            Clutter.ungrab_pointer();
 | 
			
		||||
            this._ungrabDevice();
 | 
			
		||||
            Main.popModal(_getEventHandlerActor());
 | 
			
		||||
            this._eventsGrabbed = false;
 | 
			
		||||
        }
 | 
			
		||||
@@ -157,7 +202,9 @@ const _Draggable = new Lang.Class({
 | 
			
		||||
        // didn't start the drag, to drop the draggable in case the drag was in progress, and
 | 
			
		||||
        // to complete the drag and ensure that whatever happens to be under the pointer does
 | 
			
		||||
        // not get triggered if the drag was cancelled with Esc.
 | 
			
		||||
        if (event.type() == Clutter.EventType.BUTTON_RELEASE) {
 | 
			
		||||
        if (event.type() == Clutter.EventType.BUTTON_RELEASE ||
 | 
			
		||||
            (event.type() == Clutter.EventType.TOUCH_END &&
 | 
			
		||||
             global.display.is_pointer_emulating_sequence(event.get_event_sequence()))) {
 | 
			
		||||
            this._buttonDown = false;
 | 
			
		||||
            if (this._dragInProgress) {
 | 
			
		||||
                return this._dragActorDropped(event);
 | 
			
		||||
@@ -172,7 +219,9 @@ const _Draggable = new Lang.Class({
 | 
			
		||||
            }
 | 
			
		||||
        // We intercept MOTION event to figure out if the drag has started and to draw
 | 
			
		||||
        // this._dragActor under the pointer when dragging is in progress
 | 
			
		||||
        } else if (event.type() == Clutter.EventType.MOTION) {
 | 
			
		||||
        } else if (event.type() == Clutter.EventType.MOTION ||
 | 
			
		||||
                   (event.type() == Clutter.EventType.TOUCH_UPDATE &&
 | 
			
		||||
                    global.display.is_pointer_emulating_sequence(event.get_event_sequence()))) {
 | 
			
		||||
            if (this._dragInProgress) {
 | 
			
		||||
                return this._updateDragPosition(event);
 | 
			
		||||
            } else if (this._dragActor == null) {
 | 
			
		||||
@@ -214,7 +263,7 @@ const _Draggable = new Lang.Class({
 | 
			
		||||
     * This function is useful to call if you've specified manualMode
 | 
			
		||||
     * for the draggable.
 | 
			
		||||
     */
 | 
			
		||||
    startDrag: function (stageX, stageY, time) {
 | 
			
		||||
    startDrag: function (stageX, stageY, time, sequence) {
 | 
			
		||||
        currentDraggable = this;
 | 
			
		||||
        this._dragInProgress = true;
 | 
			
		||||
 | 
			
		||||
@@ -228,6 +277,8 @@ const _Draggable = new Lang.Class({
 | 
			
		||||
        this.emit('drag-begin', time);
 | 
			
		||||
        if (this._onEventId)
 | 
			
		||||
            this._ungrabActor();
 | 
			
		||||
 | 
			
		||||
        this._touchSequence = sequence;
 | 
			
		||||
        this._grabEvents();
 | 
			
		||||
        global.screen.set_cursor(Meta.Cursor.DND_IN_DRAG);
 | 
			
		||||
 | 
			
		||||
@@ -338,8 +389,8 @@ const _Draggable = new Lang.Class({
 | 
			
		||||
        let threshold = Gtk.Settings.get_default().gtk_dnd_drag_threshold;
 | 
			
		||||
        if ((Math.abs(stageX - this._dragStartX) > threshold ||
 | 
			
		||||
             Math.abs(stageY - this._dragStartY) > threshold)) {
 | 
			
		||||
                this.startDrag(stageX, stageY, event.get_time());
 | 
			
		||||
                this._updateDragPosition(event);
 | 
			
		||||
            this.startDrag(stageX, stageY, event.get_time(), this._touchSequence);
 | 
			
		||||
            this._updateDragPosition(event);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
@@ -520,20 +571,13 @@ const _Draggable = new Lang.Class({
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._animationInProgress = true;
 | 
			
		||||
        // No target, so snap back
 | 
			
		||||
        Tweener.addTween(this._dragActor,
 | 
			
		||||
                         { x: snapBackX,
 | 
			
		||||
                           y: snapBackY,
 | 
			
		||||
                           scale_x: snapBackScale,
 | 
			
		||||
                           scale_y: snapBackScale,
 | 
			
		||||
                           opacity: this._dragOrigOpacity,
 | 
			
		||||
                           time: SNAP_BACK_ANIMATION_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: this._onAnimationComplete,
 | 
			
		||||
                           onCompleteScope: this,
 | 
			
		||||
                           onCompleteParams: [this._dragActor, eventTime]
 | 
			
		||||
                         });
 | 
			
		||||
        this._animateDragEnd(eventTime,
 | 
			
		||||
                             { x: snapBackX,
 | 
			
		||||
                               y: snapBackY,
 | 
			
		||||
                               scale_x: snapBackScale,
 | 
			
		||||
                               scale_y: snapBackScale,
 | 
			
		||||
                               time: SNAP_BACK_ANIMATION_TIME,
 | 
			
		||||
                             });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _restoreDragActor: function(eventTime) {
 | 
			
		||||
@@ -545,18 +589,44 @@ const _Draggable = new Lang.Class({
 | 
			
		||||
        this._dragActor.set_scale(restoreScale, restoreScale);
 | 
			
		||||
        this._dragActor.opacity = 0;
 | 
			
		||||
 | 
			
		||||
        this._animateDragEnd(eventTime,
 | 
			
		||||
                             { time: REVERT_ANIMATION_TIME });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _animateDragEnd: function (eventTime, params) {
 | 
			
		||||
        this._animationInProgress = true;
 | 
			
		||||
        Tweener.addTween(this._dragActor,
 | 
			
		||||
                         { opacity: this._dragOrigOpacity,
 | 
			
		||||
                           time: REVERT_ANIMATION_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: this._onAnimationComplete,
 | 
			
		||||
                           onCompleteScope: this,
 | 
			
		||||
                           onCompleteParams: [this._dragActor, eventTime]
 | 
			
		||||
                         });
 | 
			
		||||
 | 
			
		||||
        // finish animation if the actor gets destroyed
 | 
			
		||||
        // during it
 | 
			
		||||
        this._dragActorDestroyId =
 | 
			
		||||
            this._dragActor.connect('destroy',
 | 
			
		||||
                                    Lang.bind(this, this._finishAnimation));
 | 
			
		||||
 | 
			
		||||
        params['opacity']          = this._dragOrigOpacity;
 | 
			
		||||
        params['transition']       = 'easeOutQuad';
 | 
			
		||||
        params['onComplete']       = this._onAnimationComplete;
 | 
			
		||||
        params['onCompleteScope']  = this;
 | 
			
		||||
        params['onCompleteParams'] = [this._dragActor, eventTime];
 | 
			
		||||
 | 
			
		||||
        // start the animation
 | 
			
		||||
        Tweener.addTween(this._dragActor, params)
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _finishAnimation : function () {
 | 
			
		||||
        if (!this._animationInProgress)
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        this._animationInProgress = false;
 | 
			
		||||
        if (!this._buttonDown)
 | 
			
		||||
            this._dragComplete();
 | 
			
		||||
 | 
			
		||||
        global.screen.set_cursor(Meta.Cursor.DEFAULT);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onAnimationComplete : function (dragActor, eventTime) {
 | 
			
		||||
        dragActor.disconnect(this._dragActorDestroyId);
 | 
			
		||||
        this._dragActorDestroyId = 0;
 | 
			
		||||
 | 
			
		||||
        if (this._dragOrigParent) {
 | 
			
		||||
            Main.uiGroup.remove_child(this._dragActor);
 | 
			
		||||
            this._dragOrigParent.add_actor(this._dragActor);
 | 
			
		||||
@@ -565,12 +635,9 @@ const _Draggable = new Lang.Class({
 | 
			
		||||
        } else {
 | 
			
		||||
            dragActor.destroy();
 | 
			
		||||
        }
 | 
			
		||||
        global.screen.set_cursor(Meta.Cursor.DEFAULT);
 | 
			
		||||
        this.emit('drag-end', eventTime, false);
 | 
			
		||||
 | 
			
		||||
        this._animationInProgress = false;
 | 
			
		||||
        if (!this._buttonDown)
 | 
			
		||||
            this._dragComplete();
 | 
			
		||||
        this.emit('drag-end', eventTime, false);
 | 
			
		||||
        this._finishAnimation();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _dragComplete: function() {
 | 
			
		||||
 
 | 
			
		||||
@@ -81,7 +81,6 @@ function init() {
 | 
			
		||||
 | 
			
		||||
    // Miscellaneous monkeypatching
 | 
			
		||||
    _patchContainerClass(St.BoxLayout);
 | 
			
		||||
    _patchContainerClass(St.Table);
 | 
			
		||||
 | 
			
		||||
    _patchLayoutClass(Clutter.TableLayout, { row_spacing: 'spacing-rows',
 | 
			
		||||
                                             column_spacing: 'spacing-columns' });
 | 
			
		||||
 
 | 
			
		||||
@@ -334,7 +334,7 @@ function _sessionUpdated() {
 | 
			
		||||
    // from allowExtensions in the future
 | 
			
		||||
    if (Main.sessionMode.allowExtensions) {
 | 
			
		||||
        if (initted)
 | 
			
		||||
            onEnabledExtensionsChanged();
 | 
			
		||||
            enabledExtensions = getEnabledExtensions();
 | 
			
		||||
        enableAllExtensions();
 | 
			
		||||
    } else {
 | 
			
		||||
        disableAllExtensions();
 | 
			
		||||
 
 | 
			
		||||
@@ -158,10 +158,22 @@ const CandidatePopup = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        panelService.connect('set-cursor-location',
 | 
			
		||||
                             Lang.bind(this, function(ps, x, y, w, h) {
 | 
			
		||||
                                 Main.layoutManager.setDummyCursorGeometry(x, y, w, h);
 | 
			
		||||
                                 if (this._boxPointer.actor.visible)
 | 
			
		||||
                                     this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
 | 
			
		||||
                                 this._setDummyCursorGeometry(x, y, w, h);
 | 
			
		||||
                             }));
 | 
			
		||||
        try {
 | 
			
		||||
            panelService.connect('set-cursor-location-relative',
 | 
			
		||||
                                 Lang.bind(this, function(ps, x, y, w, h) {
 | 
			
		||||
                                     if (!global.display.focus_window)
 | 
			
		||||
                                         return;
 | 
			
		||||
                                     let window = global.display.focus_window.get_compositor_private();
 | 
			
		||||
                                     this._setDummyCursorGeometry(window.x + x, window.y + y, w, h);
 | 
			
		||||
                                 }));
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            // Only recent IBus versions have support for this signal
 | 
			
		||||
            // which is used for wayland clients. In order to work
 | 
			
		||||
            // with older IBus versions we can silently ignore the
 | 
			
		||||
            // signal's absence.
 | 
			
		||||
        }
 | 
			
		||||
        panelService.connect('update-preedit-text',
 | 
			
		||||
                             Lang.bind(this, function(ps, text, cursorPosition, visible) {
 | 
			
		||||
                                 this._preeditText.visible = visible;
 | 
			
		||||
@@ -246,6 +258,12 @@ const CandidatePopup = new Lang.Class({
 | 
			
		||||
                             }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setDummyCursorGeometry: function(x, y, w, h) {
 | 
			
		||||
        Main.layoutManager.setDummyCursorGeometry(x, y, w, h);
 | 
			
		||||
        if (this._boxPointer.actor.visible)
 | 
			
		||||
            this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateVisibility: function() {
 | 
			
		||||
        let isVisible = (this._preeditText.visible ||
 | 
			
		||||
                         this._auxText.visible ||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,9 +24,6 @@ const KEYBOARD_TYPE = 'keyboard-type';
 | 
			
		||||
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
 | 
			
		||||
const SHOW_KEYBOARD = 'screen-keyboard-enabled';
 | 
			
		||||
 | 
			
		||||
const CURSOR_BUS_NAME = 'org.gnome.SettingsDaemon.Cursor';
 | 
			
		||||
const CURSOR_OBJECT_PATH = '/org/gnome/SettingsDaemon/Cursor';
 | 
			
		||||
 | 
			
		||||
const CARIBOU_BUS_NAME = 'org.gnome.Caribou.Daemon';
 | 
			
		||||
const CARIBOU_OBJECT_PATH = '/org/gnome/Caribou/Daemon';
 | 
			
		||||
 | 
			
		||||
@@ -114,6 +111,35 @@ const Key = new Lang.Class({
 | 
			
		||||
                key.release();
 | 
			
		||||
                return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
            }));
 | 
			
		||||
        button.connect('touch-event', Lang.bind(this,
 | 
			
		||||
            function (actor, event) {
 | 
			
		||||
                let device = event.get_device();
 | 
			
		||||
                let sequence = event.get_event_sequence();
 | 
			
		||||
 | 
			
		||||
                // We only handle touch events here on wayland. On X11
 | 
			
		||||
                // we do get emulated pointer events, which already works
 | 
			
		||||
                // for single-touch cases. Besides, the X11 passive touch grab
 | 
			
		||||
                // set up by Mutter will make us see first the touch events
 | 
			
		||||
                // and later the pointer events, so it will look like two
 | 
			
		||||
                // unrelated series of events, we want to avoid double handling
 | 
			
		||||
                // in these cases.
 | 
			
		||||
                if (!Meta.is_wayland_compositor())
 | 
			
		||||
                    return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
                if (!this._touchPressed &&
 | 
			
		||||
                    event.type() == Clutter.EventType.TOUCH_BEGIN) {
 | 
			
		||||
                    device.sequence_grab(sequence, actor);
 | 
			
		||||
                    this._touchPressed = true;
 | 
			
		||||
                    key.press();
 | 
			
		||||
                } else if (this._touchPressed &&
 | 
			
		||||
                           event.type() == Clutter.EventType.TOUCH_END &&
 | 
			
		||||
                           device.sequence_get_grabbed_actor(sequence) == actor) {
 | 
			
		||||
                    device.sequence_ungrab(sequence);
 | 
			
		||||
                    this._touchPressed = false;
 | 
			
		||||
                    key.release();
 | 
			
		||||
                }
 | 
			
		||||
                return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        return button;
 | 
			
		||||
    },
 | 
			
		||||
@@ -178,9 +204,6 @@ const Keyboard = new Lang.Class({
 | 
			
		||||
        this._keyboardSettings.connect('changed', Lang.bind(this, this._sync));
 | 
			
		||||
        this._a11yApplicationsSettings = new Gio.Settings({ schema_id: A11Y_APPLICATIONS_SCHEMA });
 | 
			
		||||
        this._a11yApplicationsSettings.connect('changed', Lang.bind(this, this._sync));
 | 
			
		||||
        this._watchNameId = Gio.bus_watch_name(Gio.BusType.SESSION, CURSOR_BUS_NAME, 0,
 | 
			
		||||
                                               Lang.bind(this, this._sync),
 | 
			
		||||
                                               Lang.bind(this, this._sync));
 | 
			
		||||
        this._daemonProxy = null;
 | 
			
		||||
        this._lastDeviceId = null;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -837,6 +837,7 @@ const LayoutManager = new Lang.Class({
 | 
			
		||||
        // need to connect to 'destroy' too.
 | 
			
		||||
 | 
			
		||||
        this._trackedActors.push(actorData);
 | 
			
		||||
        this._updateActorVisibility(actorData);
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -855,25 +856,23 @@ const LayoutManager = new Lang.Class({
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateActorVisibility: function(actorData) {
 | 
			
		||||
        if (!actorData.trackFullscreen)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let monitor = this.findMonitorForActor(actorData.actor);
 | 
			
		||||
        actorData.actor.visible = !(global.window_group.visible &&
 | 
			
		||||
                                    monitor &&
 | 
			
		||||
                                    monitor.inFullscreen);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateVisibility: function() {
 | 
			
		||||
        let windowsVisible = Main.sessionMode.hasWindows && !this._inOverview;
 | 
			
		||||
 | 
			
		||||
        global.window_group.visible = windowsVisible;
 | 
			
		||||
        global.top_window_group.visible = windowsVisible;
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._trackedActors.length; i++) {
 | 
			
		||||
            let actorData = this._trackedActors[i], visible;
 | 
			
		||||
            if (!actorData.trackFullscreen)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (!windowsVisible)
 | 
			
		||||
                visible = true;
 | 
			
		||||
            else if (this.findMonitorForActor(actorData.actor).inFullscreen)
 | 
			
		||||
                visible = false;
 | 
			
		||||
            else
 | 
			
		||||
                visible = true;
 | 
			
		||||
            actorData.actor.visible = visible;
 | 
			
		||||
        }
 | 
			
		||||
        this._trackedActors.forEach(Lang.bind(this, this._updateActorVisibility));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getWorkAreaForMonitor: function(monitorIndex) {
 | 
			
		||||
@@ -1316,8 +1315,11 @@ const PressureBarrier = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onBarrierLeft: function(barrier, event) {
 | 
			
		||||
        this._reset();
 | 
			
		||||
        this._isTriggered = false;
 | 
			
		||||
        barrier._isHit = false;
 | 
			
		||||
        if (this._barriers.every(function(b) { return !b._isHit; })) {
 | 
			
		||||
            this._reset();
 | 
			
		||||
            this._isTriggered = false;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _trigger: function() {
 | 
			
		||||
@@ -1327,6 +1329,8 @@ const PressureBarrier = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onBarrierHit: function(barrier, event) {
 | 
			
		||||
        barrier._isHit = true;
 | 
			
		||||
 | 
			
		||||
        // If we've triggered the barrier, wait until the pointer has the
 | 
			
		||||
        // left the barrier hitbox until we trigger it again.
 | 
			
		||||
        if (this._isTriggered)
 | 
			
		||||
 
 | 
			
		||||
@@ -50,15 +50,14 @@ const LegacyTray = new Lang.Class({
 | 
			
		||||
        this._slideLayout.translationX = 0;
 | 
			
		||||
        this._slideLayout.slideDirection = OverviewControls.SlideDirection.LEFT;
 | 
			
		||||
 | 
			
		||||
        this._slider = new St.Widget({ style_class: 'legacy-tray',
 | 
			
		||||
                                       x_expand: true, y_expand: true,
 | 
			
		||||
        this._slider = new St.Widget({ x_expand: true, y_expand: true,
 | 
			
		||||
                                       x_align: Clutter.ActorAlign.START,
 | 
			
		||||
                                       y_align: Clutter.ActorAlign.END,
 | 
			
		||||
                                       layout_manager: this._slideLayout });
 | 
			
		||||
        this.actor.add_actor(this._slider);
 | 
			
		||||
        this._slider.connect('notify::allocation', Lang.bind(this, this._syncBarrier));
 | 
			
		||||
 | 
			
		||||
        this._box = new St.BoxLayout();
 | 
			
		||||
        this._box = new St.BoxLayout({ style_class: 'legacy-tray' });
 | 
			
		||||
        this._slider.add_actor(this._box);
 | 
			
		||||
 | 
			
		||||
        this._concealHandle = new St.Button({ style_class: 'legacy-tray-handle',
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ const Atspi = imports.gi.Atspi;
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const GDesktopEnums = imports.gi.GDesktopEnums;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
@@ -22,6 +23,8 @@ const MOUSE_POLL_FREQUENCY = 50;
 | 
			
		||||
const CROSSHAIRS_CLIP_SIZE = [100, 100];
 | 
			
		||||
const NO_CHANGE = 0.0;
 | 
			
		||||
 | 
			
		||||
const POINTER_REST_TIME = 1000; // milliseconds
 | 
			
		||||
 | 
			
		||||
// Settings
 | 
			
		||||
const APPLICATIONS_SCHEMA       = 'org.gnome.desktop.a11y.applications';
 | 
			
		||||
const SHOW_KEY                  = 'screen-magnifier-enabled';
 | 
			
		||||
@@ -709,6 +712,9 @@ const ZoomRegion = new Lang.Class({
 | 
			
		||||
        this._xCaret = 0;
 | 
			
		||||
        this._yCaret = 0;
 | 
			
		||||
 | 
			
		||||
        this._pointerIdleMonitor = Meta.IdleMonitor.get_for_device(Meta.VIRTUAL_CORE_POINTER_ID);
 | 
			
		||||
        this._scrollContentsTimerId = 0;
 | 
			
		||||
 | 
			
		||||
        Main.layoutManager.connect('monitors-changed',
 | 
			
		||||
                                   Lang.bind(this, this._monitorsChanged));
 | 
			
		||||
        this._focusCaretTracker.connect('caret-moved',
 | 
			
		||||
@@ -1068,6 +1074,26 @@ const ZoomRegion = new Lang.Class({
 | 
			
		||||
        return this._isMouseOverRegion();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _clearScrollContentsTimer: function() {
 | 
			
		||||
        if (this._scrollContentsTimerId != 0) {
 | 
			
		||||
            Mainloop.source_remove(this._scrollContentsTimerId);
 | 
			
		||||
            this._scrollContentsTimerId = 0;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _scrollContentsToDelayed: function(x, y) {
 | 
			
		||||
        if (this._pointerIdleMonitor.get_idletime() >= POINTER_REST_TIME) {
 | 
			
		||||
            this.scrollContentsTo(x, y);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._clearScrollContentsTimer();
 | 
			
		||||
        this._scrollContentsTimerId = Mainloop.timeout_add(POINTER_REST_TIME, Lang.bind(this, function() {
 | 
			
		||||
            this._scrollContentsToDelayed(x, y);
 | 
			
		||||
            return GLib.SOURCE_REMOVE;
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * scrollContentsTo:
 | 
			
		||||
     * Shift the contents of the magnified view such it is centered on the given
 | 
			
		||||
@@ -1076,6 +1102,8 @@ const ZoomRegion = new Lang.Class({
 | 
			
		||||
     * @y:      The y-coord of the point to center on.
 | 
			
		||||
     */
 | 
			
		||||
    scrollContentsTo: function(x, y) {
 | 
			
		||||
        this._clearScrollContentsTimer();
 | 
			
		||||
 | 
			
		||||
        this._followingCursor = false;
 | 
			
		||||
        this._changeROI({ xCenter: x,
 | 
			
		||||
                          yCenter: y });
 | 
			
		||||
@@ -1381,7 +1409,7 @@ const ZoomRegion = new Lang.Class({
 | 
			
		||||
        else if (this._caretTrackingMode == GDesktopEnums.MagnifierCaretTrackingMode.CENTERED)
 | 
			
		||||
            [xCaret, yCaret] = this._centerFromPointCentered(xCaret, yCaret);
 | 
			
		||||
 | 
			
		||||
        this.scrollContentsTo(xCaret, yCaret);
 | 
			
		||||
        this._scrollContentsToDelayed(xCaret, yCaret);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _centerFromFocusPosition: function() {
 | 
			
		||||
@@ -1395,7 +1423,7 @@ const ZoomRegion = new Lang.Class({
 | 
			
		||||
        else if (this._focusTrackingMode == GDesktopEnums.MagnifierFocusTrackingMode.CENTERED)
 | 
			
		||||
            [xFocus, yFocus] = this._centerFromPointCentered(xFocus, yFocus);
 | 
			
		||||
 | 
			
		||||
        this.scrollContentsTo(xFocus, yFocus);
 | 
			
		||||
        this._scrollContentsToDelayed(xFocus, yFocus);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _centerFromPointPush: function(xPoint, yPoint) {
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ const Meta = imports.gi.Meta;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const AudioDeviceSelection = imports.ui.audioDeviceSelection;
 | 
			
		||||
const Components = imports.ui.components;
 | 
			
		||||
const CtrlAltTab = imports.ui.ctrlAltTab;
 | 
			
		||||
const EndSessionDialog = imports.ui.endSessionDialog;
 | 
			
		||||
@@ -62,6 +63,7 @@ let ctrlAltTabManager = null;
 | 
			
		||||
let osdWindowManager = null;
 | 
			
		||||
let osdMonitorLabeler = null;
 | 
			
		||||
let sessionMode = null;
 | 
			
		||||
let shellAudioSelectionDBusService = null;
 | 
			
		||||
let shellDBusService = null;
 | 
			
		||||
let shellMountOpDBusService = null;
 | 
			
		||||
let screenSaverDBus = null;
 | 
			
		||||
@@ -78,6 +80,7 @@ let _startDate;
 | 
			
		||||
let _defaultCssStylesheet = null;
 | 
			
		||||
let _cssStylesheet = null;
 | 
			
		||||
let _a11ySettings = null;
 | 
			
		||||
let _themeResource = null;
 | 
			
		||||
 | 
			
		||||
function _sessionUpdated() {
 | 
			
		||||
    if (sessionMode.isPrimary)
 | 
			
		||||
@@ -119,6 +122,7 @@ function start() {
 | 
			
		||||
                                       _loadDefaultStylesheet);
 | 
			
		||||
    _initializeUI();
 | 
			
		||||
 | 
			
		||||
    shellAudioSelectionDBusService = new AudioDeviceSelection.AudioDeviceSelectionDBus();
 | 
			
		||||
    shellDBusService = new ShellDBus.GnomeShell();
 | 
			
		||||
    shellMountOpDBusService = new ShellMountOperation.GnomeShellMountOpHandler();
 | 
			
		||||
 | 
			
		||||
@@ -137,9 +141,7 @@ function _initializeUI() {
 | 
			
		||||
    Shell.WindowTracker.get_default();
 | 
			
		||||
    Shell.AppUsage.get_default();
 | 
			
		||||
 | 
			
		||||
    let resource = Gio.Resource.load(global.datadir + '/gnome-shell-theme.gresource');
 | 
			
		||||
    resource._register();
 | 
			
		||||
 | 
			
		||||
    reloadThemeResource();
 | 
			
		||||
    _loadDefaultStylesheet();
 | 
			
		||||
 | 
			
		||||
    // Setup the stage hierarchy early
 | 
			
		||||
@@ -290,6 +292,14 @@ function setThemeStylesheet(cssStylesheet) {
 | 
			
		||||
    _cssStylesheet = cssStylesheet ? Gio.File.new_for_path(cssStylesheet) : null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function reloadThemeResource() {
 | 
			
		||||
    if (_themeResource)
 | 
			
		||||
        _themeResource._unregister();
 | 
			
		||||
 | 
			
		||||
    _themeResource = Gio.Resource.load(global.datadir + '/gnome-shell-theme.gresource');
 | 
			
		||||
    _themeResource._register();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * loadTheme:
 | 
			
		||||
 *
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										726
									
								
								js/ui/messageList.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,726 @@
 | 
			
		||||
const Atk = imports.gi.Atk;
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const GObject = imports.gi.GObject;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const Pango = imports.gi.Pango;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const Calendar = imports.ui.calendar;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const Util = imports.misc.util;
 | 
			
		||||
 | 
			
		||||
const MESSAGE_ANIMATION_TIME = 0.1;
 | 
			
		||||
 | 
			
		||||
const DEFAULT_EXPAND_LINES = 6;
 | 
			
		||||
 | 
			
		||||
function _fixMarkup(text, allowMarkup) {
 | 
			
		||||
    if (allowMarkup) {
 | 
			
		||||
        // Support &, ", ', < and >, escape all other
 | 
			
		||||
        // occurrences of '&'.
 | 
			
		||||
        let _text = text.replace(/&(?!amp;|quot;|apos;|lt;|gt;)/g, '&');
 | 
			
		||||
 | 
			
		||||
        // Support <b>, <i>, and <u>, escape anything else
 | 
			
		||||
        // so it displays as raw markup.
 | 
			
		||||
        _text = _text.replace(/<(?!\/?[biu]>)/g, '<');
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            Pango.parse_markup(_text, -1, '');
 | 
			
		||||
            return _text;
 | 
			
		||||
        } catch (e) {}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // !allowMarkup, or invalid markup
 | 
			
		||||
    return GLib.markup_escape_text(text, -1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const URLHighlighter = new Lang.Class({
 | 
			
		||||
    Name: 'URLHighlighter',
 | 
			
		||||
 | 
			
		||||
    _init: function(text, lineWrap, allowMarkup) {
 | 
			
		||||
        if (!text)
 | 
			
		||||
            text = '';
 | 
			
		||||
        this.actor = new St.Label({ reactive: true, style_class: 'url-highlighter',
 | 
			
		||||
                                    x_expand: true, x_align: Clutter.ActorAlign.START });
 | 
			
		||||
        this._linkColor = '#ccccff';
 | 
			
		||||
        this.actor.connect('style-changed', Lang.bind(this, function() {
 | 
			
		||||
            let [hasColor, color] = this.actor.get_theme_node().lookup_color('link-color', false);
 | 
			
		||||
            if (hasColor) {
 | 
			
		||||
                let linkColor = color.to_string().substr(0, 7);
 | 
			
		||||
                if (linkColor != this._linkColor) {
 | 
			
		||||
                    this._linkColor = linkColor;
 | 
			
		||||
                    this._highlightUrls();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }));
 | 
			
		||||
        this.actor.clutter_text.line_wrap = lineWrap;
 | 
			
		||||
        this.actor.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
 | 
			
		||||
 | 
			
		||||
        this.setMarkup(text, allowMarkup);
 | 
			
		||||
        this.actor.connect('button-press-event', Lang.bind(this, function(actor, event) {
 | 
			
		||||
            // Don't try to URL highlight when invisible.
 | 
			
		||||
            // The MessageTray doesn't actually hide us, so
 | 
			
		||||
            // we need to check for paint opacities as well.
 | 
			
		||||
            if (!actor.visible || actor.get_paint_opacity() == 0)
 | 
			
		||||
                return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
            // Keep Notification.actor from seeing this and taking
 | 
			
		||||
            // a pointer grab, which would block our button-release-event
 | 
			
		||||
            // handler, if an URL is clicked
 | 
			
		||||
            return this._findUrlAtPos(event) != -1;
 | 
			
		||||
        }));
 | 
			
		||||
        this.actor.connect('button-release-event', Lang.bind(this, function (actor, event) {
 | 
			
		||||
            if (!actor.visible || actor.get_paint_opacity() == 0)
 | 
			
		||||
                return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
            let urlId = this._findUrlAtPos(event);
 | 
			
		||||
            if (urlId != -1) {
 | 
			
		||||
                let url = this._urls[urlId].url;
 | 
			
		||||
                if (url.indexOf(':') == -1)
 | 
			
		||||
                    url = 'http://' + url;
 | 
			
		||||
 | 
			
		||||
                Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context(0, -1));
 | 
			
		||||
                return Clutter.EVENT_STOP;
 | 
			
		||||
            }
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
        }));
 | 
			
		||||
        this.actor.connect('motion-event', Lang.bind(this, function(actor, event) {
 | 
			
		||||
            if (!actor.visible || actor.get_paint_opacity() == 0)
 | 
			
		||||
                return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
            let urlId = this._findUrlAtPos(event);
 | 
			
		||||
            if (urlId != -1 && !this._cursorChanged) {
 | 
			
		||||
                global.screen.set_cursor(Meta.Cursor.POINTING_HAND);
 | 
			
		||||
                this._cursorChanged = true;
 | 
			
		||||
            } else if (urlId == -1) {
 | 
			
		||||
                global.screen.set_cursor(Meta.Cursor.DEFAULT);
 | 
			
		||||
                this._cursorChanged = false;
 | 
			
		||||
            }
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
        }));
 | 
			
		||||
        this.actor.connect('leave-event', Lang.bind(this, function() {
 | 
			
		||||
            if (!this.actor.visible || this.actor.get_paint_opacity() == 0)
 | 
			
		||||
                return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
            if (this._cursorChanged) {
 | 
			
		||||
                this._cursorChanged = false;
 | 
			
		||||
                global.screen.set_cursor(Meta.Cursor.DEFAULT);
 | 
			
		||||
            }
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setMarkup: function(text, allowMarkup) {
 | 
			
		||||
        text = text ? _fixMarkup(text, allowMarkup) : '';
 | 
			
		||||
        this._text = text;
 | 
			
		||||
 | 
			
		||||
        this.actor.clutter_text.set_markup(text);
 | 
			
		||||
        /* clutter_text.text contain text without markup */
 | 
			
		||||
        this._urls = Util.findUrls(this.actor.clutter_text.text);
 | 
			
		||||
        this._highlightUrls();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _highlightUrls: function() {
 | 
			
		||||
        // text here contain markup
 | 
			
		||||
        let urls = Util.findUrls(this._text);
 | 
			
		||||
        let markup = '';
 | 
			
		||||
        let pos = 0;
 | 
			
		||||
        for (let i = 0; i < urls.length; i++) {
 | 
			
		||||
            let url = urls[i];
 | 
			
		||||
            let str = this._text.substr(pos, url.pos - pos);
 | 
			
		||||
            markup += str + '<span foreground="' + this._linkColor + '"><u>' + url.url + '</u></span>';
 | 
			
		||||
            pos = url.pos + url.url.length;
 | 
			
		||||
        }
 | 
			
		||||
        markup += this._text.substr(pos);
 | 
			
		||||
        this.actor.clutter_text.set_markup(markup);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _findUrlAtPos: function(event) {
 | 
			
		||||
        let success;
 | 
			
		||||
        let [x, y] = event.get_coords();
 | 
			
		||||
        [success, x, y] = this.actor.transform_stage_point(x, y);
 | 
			
		||||
        let find_pos = -1;
 | 
			
		||||
        for (let i = 0; i < this.actor.clutter_text.text.length; i++) {
 | 
			
		||||
            let [success, px, py, line_height] = this.actor.clutter_text.position_to_coords(i);
 | 
			
		||||
            if (py > y || py + line_height < y || x < px)
 | 
			
		||||
                continue;
 | 
			
		||||
            find_pos = i;
 | 
			
		||||
        }
 | 
			
		||||
        if (find_pos != -1) {
 | 
			
		||||
            for (let i = 0; i < this._urls.length; i++)
 | 
			
		||||
            if (find_pos >= this._urls[i].pos &&
 | 
			
		||||
                this._urls[i].pos + this._urls[i].url.length > find_pos)
 | 
			
		||||
                return i;
 | 
			
		||||
        }
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const ScaleLayout = new Lang.Class({
 | 
			
		||||
    Name: 'ScaleLayout',
 | 
			
		||||
    Extends: Clutter.BinLayout,
 | 
			
		||||
 | 
			
		||||
    _connectContainer: function(container) {
 | 
			
		||||
        if (this._container == container)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (this._container)
 | 
			
		||||
            for (let id of this._signals)
 | 
			
		||||
                this._container.disconnect(id);
 | 
			
		||||
 | 
			
		||||
        this._container = container;
 | 
			
		||||
        this._signals = [];
 | 
			
		||||
 | 
			
		||||
        if (this._container)
 | 
			
		||||
            for (let signal of ['notify::scale-x', 'notify::scale-y']) {
 | 
			
		||||
                let id = this._container.connect(signal, Lang.bind(this,
 | 
			
		||||
                    function() {
 | 
			
		||||
                        this.layout_changed();
 | 
			
		||||
                    }));
 | 
			
		||||
                this._signals.push(id);
 | 
			
		||||
            }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_width: function(container, forHeight) {
 | 
			
		||||
        this._connectContainer(container);
 | 
			
		||||
 | 
			
		||||
        let [min, nat] = this.parent(container, forHeight);
 | 
			
		||||
        return [Math.floor(min * container.scale_x),
 | 
			
		||||
                Math.floor(nat * container.scale_x)];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_height: function(container, forWidth) {
 | 
			
		||||
        this._connectContainer(container);
 | 
			
		||||
 | 
			
		||||
        let [min, nat] = this.parent(container, forWidth);
 | 
			
		||||
        return [Math.floor(min * container.scale_y),
 | 
			
		||||
                Math.floor(nat * container.scale_y)];
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const LabelExpanderLayout = new Lang.Class({
 | 
			
		||||
    Name: 'LabelExpanderLayout',
 | 
			
		||||
    Extends: Clutter.LayoutManager,
 | 
			
		||||
    Properties: { 'expansion': GObject.ParamSpec.double('expansion',
 | 
			
		||||
                                                        'Expansion',
 | 
			
		||||
                                                        'Expansion of the layout, between 0 (collapsed) ' +
 | 
			
		||||
                                                        'and 1 (fully expanded',
 | 
			
		||||
                                                         GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
 | 
			
		||||
                                                         0, 1, 0)},
 | 
			
		||||
 | 
			
		||||
    _init: function(params) {
 | 
			
		||||
        this._expansion = 0;
 | 
			
		||||
        this._expandLines = DEFAULT_EXPAND_LINES;
 | 
			
		||||
 | 
			
		||||
        this.parent(params);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get expansion() {
 | 
			
		||||
        return this._expansion;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    set expansion(v) {
 | 
			
		||||
        if (v == this._expansion)
 | 
			
		||||
            return;
 | 
			
		||||
        this._expansion = v;
 | 
			
		||||
        this.notify('expansion');
 | 
			
		||||
 | 
			
		||||
        let visibleIndex = this._expansion > 0 ? 1 : 0;
 | 
			
		||||
        for (let i = 0; this._container && i < this._container.get_n_children(); i++)
 | 
			
		||||
            this._container.get_child_at_index(i).visible = (i == visibleIndex);
 | 
			
		||||
 | 
			
		||||
        this.layout_changed();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    set expandLines(v) {
 | 
			
		||||
        if (v == this._expandLines)
 | 
			
		||||
            return;
 | 
			
		||||
        this._expandLines = v;
 | 
			
		||||
        if (this._expansion > 0)
 | 
			
		||||
            this.layout_changed();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_set_container: function(container) {
 | 
			
		||||
        this._container = container;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_width: function(container, forHeight) {
 | 
			
		||||
        let [min, nat] = [0, 0];
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < container.get_n_children(); i++) {
 | 
			
		||||
            if (i > 1)
 | 
			
		||||
                break; // we support one unexpanded + one expanded child
 | 
			
		||||
 | 
			
		||||
            let child = container.get_child_at_index(i);
 | 
			
		||||
            let [childMin, childNat] = child.get_preferred_width(forHeight);
 | 
			
		||||
            [min, nat] = [Math.max(min, childMin), Math.max(nat, childNat)];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return [min, nat];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_height: function(container, forWidth) {
 | 
			
		||||
        let [min, nat] = [0, 0];
 | 
			
		||||
 | 
			
		||||
        let children = container.get_children();
 | 
			
		||||
        if (children[0])
 | 
			
		||||
            [min, nat] = children[0].get_preferred_height(forWidth);
 | 
			
		||||
 | 
			
		||||
        if (children[1]) {
 | 
			
		||||
            let [min2, nat2] = children[1].get_preferred_height(forWidth);
 | 
			
		||||
            let [expMin, expNat] = [Math.min(min2, min * this._expandLines),
 | 
			
		||||
                                    Math.min(nat2, nat * this._expandLines)];
 | 
			
		||||
            [min, nat] = [min + this._expansion * (expMin - min),
 | 
			
		||||
                          nat + this._expansion * (expNat - nat)];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return [min, nat];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate: function(container, box, flags) {
 | 
			
		||||
        for (let i = 0; i < container.get_n_children(); i++) {
 | 
			
		||||
            let child = container.get_child_at_index(i);
 | 
			
		||||
 | 
			
		||||
            if (child.visible)
 | 
			
		||||
                child.allocate(box, flags);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const Message = new Lang.Class({
 | 
			
		||||
    Name: 'Message',
 | 
			
		||||
 | 
			
		||||
    _init: function(title, body) {
 | 
			
		||||
        this.expanded = false;
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.Button({ style_class: 'message',
 | 
			
		||||
                                     accessible_role: Atk.Role.NOTIFICATION,
 | 
			
		||||
                                     can_focus: true,
 | 
			
		||||
                                     x_expand: true, x_fill: true });
 | 
			
		||||
        this.actor.connect('key-press-event',
 | 
			
		||||
                           Lang.bind(this, this._onKeyPressed));
 | 
			
		||||
 | 
			
		||||
        let vbox = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        this.actor.set_child(vbox);
 | 
			
		||||
 | 
			
		||||
        let hbox = new St.BoxLayout();
 | 
			
		||||
        vbox.add_actor(hbox);
 | 
			
		||||
 | 
			
		||||
        this._actionBin = new St.Widget({ layout_manager: new ScaleLayout(),
 | 
			
		||||
                                          visible: false });
 | 
			
		||||
        vbox.add_actor(this._actionBin);
 | 
			
		||||
 | 
			
		||||
        this._iconBin = new St.Bin({ style_class: 'message-icon-bin',
 | 
			
		||||
                                     y_expand: true,
 | 
			
		||||
                                     visible: false });
 | 
			
		||||
        hbox.add_actor(this._iconBin);
 | 
			
		||||
 | 
			
		||||
        let contentBox = new St.BoxLayout({ style_class: 'message-content',
 | 
			
		||||
                                            vertical: true, x_expand: true });
 | 
			
		||||
        hbox.add_actor(contentBox);
 | 
			
		||||
 | 
			
		||||
        this._mediaControls = new St.BoxLayout();
 | 
			
		||||
        hbox.add_actor(this._mediaControls);
 | 
			
		||||
 | 
			
		||||
        let titleBox = new St.BoxLayout();
 | 
			
		||||
        contentBox.add_actor(titleBox);
 | 
			
		||||
 | 
			
		||||
        this.titleLabel = new St.Label({ style_class: 'message-title',
 | 
			
		||||
                                         x_expand: true,
 | 
			
		||||
                                         x_align: Clutter.ActorAlign.START });
 | 
			
		||||
        this.setTitle(title);
 | 
			
		||||
        titleBox.add_actor(this.titleLabel);
 | 
			
		||||
 | 
			
		||||
        this._secondaryBin = new St.Bin({ style_class: 'message-secondary-bin' });
 | 
			
		||||
        titleBox.add_actor(this._secondaryBin);
 | 
			
		||||
 | 
			
		||||
        let closeIcon = new St.Icon({ icon_name: 'window-close-symbolic',
 | 
			
		||||
                                      icon_size: 16 });
 | 
			
		||||
        this._closeButton = new St.Button({ child: closeIcon, visible: false });
 | 
			
		||||
        titleBox.add_actor(this._closeButton);
 | 
			
		||||
 | 
			
		||||
        this._bodyStack = new St.Widget({ x_expand: true });
 | 
			
		||||
        this._bodyStack.layout_manager = new LabelExpanderLayout();
 | 
			
		||||
        contentBox.add_actor(this._bodyStack);
 | 
			
		||||
 | 
			
		||||
        this.bodyLabel = new URLHighlighter('', false, this._useBodyMarkup);
 | 
			
		||||
        this.bodyLabel.actor.add_style_class_name('message-body');
 | 
			
		||||
        this._bodyStack.add_actor(this.bodyLabel.actor);
 | 
			
		||||
        this.setBody(body);
 | 
			
		||||
 | 
			
		||||
        this._closeButton.connect('clicked', Lang.bind(this, this.close));
 | 
			
		||||
        this.actor.connect('notify::hover', Lang.bind(this, this._sync));
 | 
			
		||||
        this.actor.connect('clicked', Lang.bind(this, this._onClicked));
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 | 
			
		||||
        this._sync();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    close: function() {
 | 
			
		||||
        this.emit('close');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setIcon: function(actor) {
 | 
			
		||||
        this._iconBin.child = actor;
 | 
			
		||||
        this._iconBin.visible = (actor != null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setSecondaryActor: function(actor) {
 | 
			
		||||
        this._secondaryBin.child = actor;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setTitle: function(text) {
 | 
			
		||||
        let title = text ? _fixMarkup(text.replace(/\n/g, ' '), false) : '';
 | 
			
		||||
        this.titleLabel.clutter_text.set_markup(title);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setBody: function(text) {
 | 
			
		||||
        this._bodyText = text;
 | 
			
		||||
        this.bodyLabel.setMarkup(text ? text.replace(/\n/g, ' ') : '',
 | 
			
		||||
                                 this._useBodyMarkup);
 | 
			
		||||
        if (this._expandedLabel)
 | 
			
		||||
            this._expandedLabel.setMarkup(text, this._useBodyMarkup);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setUseBodyMarkup: function(enable) {
 | 
			
		||||
        if (this._useBodyMarkup === enable)
 | 
			
		||||
            return;
 | 
			
		||||
        this._useBodyMarkup = enable;
 | 
			
		||||
        if (this.bodyLabel)
 | 
			
		||||
            this.setBody(this._bodyText);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setActionArea: function(actor) {
 | 
			
		||||
        if (actor == null) {
 | 
			
		||||
            if (this._actionBin.get_n_children() > 0)
 | 
			
		||||
                this._actionBin.get_child_at_index(0).destroy();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._actionBin.get_n_children() > 0)
 | 
			
		||||
            throw new Error('Message already has an action area');
 | 
			
		||||
 | 
			
		||||
        this._actionBin.add_actor(actor);
 | 
			
		||||
        this._actionBin.visible = this.expanded;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addMediaControl: function(iconName, callback) {
 | 
			
		||||
        let icon = new St.Icon({ icon_name: iconName, icon_size: 16 });
 | 
			
		||||
        let button = new St.Button({ style_class: 'message-media-control',
 | 
			
		||||
                                     child: icon });
 | 
			
		||||
        button.connect('clicked', callback);
 | 
			
		||||
        this._mediaControls.add_actor(button);
 | 
			
		||||
        return button;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setExpandedBody: function(actor) {
 | 
			
		||||
        if (actor == null) {
 | 
			
		||||
            if (this._bodyStack.get_n_children() > 1)
 | 
			
		||||
                this._bodyStack.get_child_at_index(1).destroy();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._bodyStack.get_n_children() > 1)
 | 
			
		||||
            throw new Error('Message already has an expanded body actor');
 | 
			
		||||
 | 
			
		||||
        this._bodyStack.insert_child_at_index(actor, 1);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setExpandedLines: function(nLines) {
 | 
			
		||||
        this._bodyStack.layout_manager.expandLines = nLines;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    expand: function(animate) {
 | 
			
		||||
        this.expanded = true;
 | 
			
		||||
 | 
			
		||||
        this._actionBin.visible = (this._actionBin.get_n_children() > 0);
 | 
			
		||||
 | 
			
		||||
        if (this._bodyStack.get_n_children() < 2) {
 | 
			
		||||
            this._expandedLabel = new URLHighlighter(this._bodyText,
 | 
			
		||||
                                                     true, this._useBodyMarkup);
 | 
			
		||||
            this.setExpandedBody(this._expandedLabel.actor);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (animate) {
 | 
			
		||||
            Tweener.addTween(this._bodyStack.layout_manager,
 | 
			
		||||
                             { expansion: 1,
 | 
			
		||||
                               time: MessageTray.ANIMATION_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad' });
 | 
			
		||||
            this._actionBin.scale_y = 0;
 | 
			
		||||
            Tweener.addTween(this._actionBin,
 | 
			
		||||
                             { scale_y: 1,
 | 
			
		||||
                               time: MessageTray.ANIMATION_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad' });
 | 
			
		||||
        } else {
 | 
			
		||||
            this._bodyStack.layout_manager.expansion = 1;
 | 
			
		||||
            this._actionBin.scale_y = 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.emit('expanded');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    unexpand: function(animate) {
 | 
			
		||||
        if (animate) {
 | 
			
		||||
            Tweener.addTween(this._bodyStack.layout_manager,
 | 
			
		||||
                             { expansion: 0,
 | 
			
		||||
                               time: MessageTray.ANIMATION_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad' });
 | 
			
		||||
            Tweener.addTween(this._actionBin,
 | 
			
		||||
                             { scale_y: 0,
 | 
			
		||||
                               time: MessageTray.ANIMATION_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad',
 | 
			
		||||
                               onCompleteScope: this,
 | 
			
		||||
                               onComplete: function() {
 | 
			
		||||
                                   this._actionBin.hide();
 | 
			
		||||
                                   this.expanded = false;
 | 
			
		||||
                               }});
 | 
			
		||||
        } else {
 | 
			
		||||
            this._bodyStack.layout_manager.expansion = 0;
 | 
			
		||||
            this._actionBin.scale_y = 0;
 | 
			
		||||
            this.expanded = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.emit('unexpanded');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    canClose: function() {
 | 
			
		||||
        return this._mediaControls.get_n_children() == 0;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _sync: function() {
 | 
			
		||||
        let hovered = this.actor.hover;
 | 
			
		||||
        this._closeButton.visible = hovered && this.canClose();
 | 
			
		||||
        this._secondaryBin.visible = !hovered;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onClicked: function() {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDestroy: function() {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeyPressed: function(a, event) {
 | 
			
		||||
        let keysym = event.get_key_symbol();
 | 
			
		||||
 | 
			
		||||
        if (keysym == Clutter.KEY_Delete ||
 | 
			
		||||
            keysym == Clutter.KEY_KP_Delete) {
 | 
			
		||||
            this.close();
 | 
			
		||||
            return Clutter.EVENT_STOP;
 | 
			
		||||
        }
 | 
			
		||||
        return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(Message.prototype);
 | 
			
		||||
 | 
			
		||||
const MessageListSection = new Lang.Class({
 | 
			
		||||
    Name: 'MessageListSection',
 | 
			
		||||
 | 
			
		||||
    _init: function(title) {
 | 
			
		||||
        this.actor = new St.BoxLayout({ style_class: 'message-list-section',
 | 
			
		||||
                                        clip_to_allocation: true,
 | 
			
		||||
                                        x_expand: true, vertical: true });
 | 
			
		||||
        let titleBox = new St.BoxLayout({ style_class: 'message-list-section-title-box' });
 | 
			
		||||
        this.actor.add_actor(titleBox);
 | 
			
		||||
 | 
			
		||||
        this._title = new St.Button({ style_class: 'message-list-section-title',
 | 
			
		||||
                                      label: title,
 | 
			
		||||
                                      can_focus: true,
 | 
			
		||||
                                      x_expand: true,
 | 
			
		||||
                                      x_align: St.Align.START });
 | 
			
		||||
        titleBox.add_actor(this._title);
 | 
			
		||||
 | 
			
		||||
        this._title.connect('clicked', Lang.bind(this, this._onTitleClicked));
 | 
			
		||||
        this._title.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
 | 
			
		||||
 | 
			
		||||
        let closeIcon = new St.Icon({ icon_name: 'window-close-symbolic' });
 | 
			
		||||
        this._closeButton = new St.Button({ style_class: 'message-list-section-close',
 | 
			
		||||
                                            child: closeIcon,
 | 
			
		||||
                                            accessible_name: _("Clear section"),
 | 
			
		||||
                                            can_focus: true });
 | 
			
		||||
        this._closeButton.set_x_align(Clutter.ActorAlign.END);
 | 
			
		||||
        titleBox.add_actor(this._closeButton);
 | 
			
		||||
 | 
			
		||||
        this._closeButton.connect('clicked', Lang.bind(this, this.clear));
 | 
			
		||||
 | 
			
		||||
        this._list = new St.BoxLayout({ style_class: 'message-list-section-list',
 | 
			
		||||
                                        vertical: true });
 | 
			
		||||
        this.actor.add_actor(this._list);
 | 
			
		||||
 | 
			
		||||
        this._list.connect('actor-added', Lang.bind(this, this._sync));
 | 
			
		||||
        this._list.connect('actor-removed', Lang.bind(this, this._sync));
 | 
			
		||||
 | 
			
		||||
        let id = Main.sessionMode.connect('updated',
 | 
			
		||||
                                          Lang.bind(this, this._sync));
 | 
			
		||||
        this.actor.connect('destroy', function() {
 | 
			
		||||
            Main.sessionMode.disconnect(id);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._messages = new Map();
 | 
			
		||||
        this._date = new Date();
 | 
			
		||||
        this.empty = true;
 | 
			
		||||
        this._sync();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onTitleClicked: function() {
 | 
			
		||||
        Main.overview.hide();
 | 
			
		||||
        Main.panel.closeCalendar();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeyFocusIn: function(actor) {
 | 
			
		||||
        this.emit('key-focus-in', actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get allowed() {
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setDate: function(date) {
 | 
			
		||||
        if (Calendar.sameDay(date, this._date))
 | 
			
		||||
            return;
 | 
			
		||||
        this._date = date;
 | 
			
		||||
        this._sync();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addMessage: function(message, animate) {
 | 
			
		||||
        this.addMessageAtIndex(message, -1, animate);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addMessageAtIndex: function(message, index, animate) {
 | 
			
		||||
        let obj = {
 | 
			
		||||
            container: null,
 | 
			
		||||
            destroyId: 0,
 | 
			
		||||
            keyFocusId: 0,
 | 
			
		||||
            closeId: 0
 | 
			
		||||
        };
 | 
			
		||||
        let pivot = new Clutter.Point({ x: .5, y: .5 });
 | 
			
		||||
        let scale = animate ? 0 : 1;
 | 
			
		||||
        obj.container = new St.Widget({ layout_manager: new ScaleLayout(),
 | 
			
		||||
                                        pivot_point: pivot,
 | 
			
		||||
                                        scale_x: scale, scale_y: scale });
 | 
			
		||||
        obj.keyFocusId = message.actor.connect('key-focus-in',
 | 
			
		||||
            Lang.bind(this, this._onKeyFocusIn));
 | 
			
		||||
        obj.destroyId = message.actor.connect('destroy',
 | 
			
		||||
            Lang.bind(this, function() {
 | 
			
		||||
                this.removeMessage(message, false);
 | 
			
		||||
            }));
 | 
			
		||||
        obj.closeId = message.connect('close',
 | 
			
		||||
            Lang.bind(this, function() {
 | 
			
		||||
                this.removeMessage(message, true);
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        this._messages.set(message, obj);
 | 
			
		||||
        obj.container.add_actor(message.actor);
 | 
			
		||||
 | 
			
		||||
        this._list.insert_child_at_index(obj.container, index);
 | 
			
		||||
 | 
			
		||||
        if (animate)
 | 
			
		||||
            Tweener.addTween(obj.container, { scale_x: 1,
 | 
			
		||||
                                              scale_y: 1,
 | 
			
		||||
                                              time: MESSAGE_ANIMATION_TIME,
 | 
			
		||||
                                              transition: 'easeOutQuad' });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    moveMessage: function(message, index, animate) {
 | 
			
		||||
        let obj = this._messages.get(message);
 | 
			
		||||
 | 
			
		||||
        if (!animate) {
 | 
			
		||||
            this._list.set_child_at_index(obj.container, index);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let onComplete = Lang.bind(this, function() {
 | 
			
		||||
            this._list.set_child_at_index(obj.container, index);
 | 
			
		||||
            Tweener.addTween(obj.container, { scale_x: 1,
 | 
			
		||||
                                              scale_y: 1,
 | 
			
		||||
                                              time: MESSAGE_ANIMATION_TIME,
 | 
			
		||||
                                              transition: 'easeOutQuad' });
 | 
			
		||||
        });
 | 
			
		||||
        Tweener.addTween(obj.container, { scale_x: 0,
 | 
			
		||||
                                          scale_y: 0,
 | 
			
		||||
                                          time: MESSAGE_ANIMATION_TIME,
 | 
			
		||||
                                          transition: 'easeOutQuad',
 | 
			
		||||
                                          onComplete: onComplete });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    removeMessage: function(message, animate) {
 | 
			
		||||
        let obj = this._messages.get(message);
 | 
			
		||||
 | 
			
		||||
        message.actor.disconnect(obj.destroyId);
 | 
			
		||||
        message.actor.disconnect(obj.keyFocusId);
 | 
			
		||||
        message.disconnect(obj.closeId);
 | 
			
		||||
 | 
			
		||||
        this._messages.delete(message);
 | 
			
		||||
 | 
			
		||||
        if (animate) {
 | 
			
		||||
            Tweener.addTween(obj.container, { scale_x: 0, scale_y: 0,
 | 
			
		||||
                                              time: MESSAGE_ANIMATION_TIME,
 | 
			
		||||
                                              transition: 'easeOutQuad',
 | 
			
		||||
                                              onComplete: function() {
 | 
			
		||||
                                                  obj.container.destroy();
 | 
			
		||||
                                                  global.sync_pointer();
 | 
			
		||||
                                              }});
 | 
			
		||||
        } else {
 | 
			
		||||
            obj.container.destroy();
 | 
			
		||||
            global.sync_pointer();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    clear: function() {
 | 
			
		||||
        let messages = [...this._messages.keys()].filter(function(message) {
 | 
			
		||||
            return message.canClose();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // If there are few messages, letting them all zoom out looks OK
 | 
			
		||||
        if (messages.length < 2) {
 | 
			
		||||
            messages.forEach(function(message) {
 | 
			
		||||
                message.close();
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            // Otherwise we slide them out one by one, and then zoom them
 | 
			
		||||
            // out "off-screen" in the end to smoothly shrink the parent
 | 
			
		||||
            let delay = MESSAGE_ANIMATION_TIME / Math.max(messages.length, 5);
 | 
			
		||||
            for (let i = 0; i < messages.length; i++) {
 | 
			
		||||
                let message = messages[i];
 | 
			
		||||
                let obj = this._messages.get(message);
 | 
			
		||||
                Tweener.addTween(obj.container,
 | 
			
		||||
                                 { anchor_x: this._list.width,
 | 
			
		||||
                                   opacity: 0,
 | 
			
		||||
                                   time: MESSAGE_ANIMATION_TIME,
 | 
			
		||||
                                   delay: i * delay,
 | 
			
		||||
                                   transition: 'easeOutQuad',
 | 
			
		||||
                                   onComplete: function() {
 | 
			
		||||
                                       message.close();
 | 
			
		||||
                                   }});
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _canClear: function() {
 | 
			
		||||
        for (let message of this._messages.keys())
 | 
			
		||||
            if (message.canClose())
 | 
			
		||||
                return true;
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _shouldShow: function() {
 | 
			
		||||
        return !this.empty;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _sync: function() {
 | 
			
		||||
        let empty = this._list.get_n_children() == 0;
 | 
			
		||||
        let changed = this.empty !== empty;
 | 
			
		||||
        this.empty = empty;
 | 
			
		||||
 | 
			
		||||
        if (changed)
 | 
			
		||||
            this.emit('empty-changed');
 | 
			
		||||
 | 
			
		||||
        this._closeButton.visible = this._canClear();
 | 
			
		||||
        this.actor.visible = this.allowed && this._shouldShow();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(MessageListSection.prototype);
 | 
			
		||||
@@ -69,26 +69,6 @@ const Urgency = {
 | 
			
		||||
    CRITICAL: 3
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function _fixMarkup(text, allowMarkup) {
 | 
			
		||||
    if (allowMarkup) {
 | 
			
		||||
        // Support &, ", ', < and >, escape all other
 | 
			
		||||
        // occurrences of '&'.
 | 
			
		||||
        let _text = text.replace(/&(?!amp;|quot;|apos;|lt;|gt;)/g, '&');
 | 
			
		||||
 | 
			
		||||
        // Support <b>, <i>, and <u>, escape anything else
 | 
			
		||||
        // so it displays as raw markup.
 | 
			
		||||
        _text = _text.replace(/<(?!\/?[biu]>)/g, '<');
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            Pango.parse_markup(_text, -1, '');
 | 
			
		||||
            return _text;
 | 
			
		||||
        } catch (e) {}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // !allowMarkup, or invalid markup
 | 
			
		||||
    return GLib.markup_escape_text(text, -1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const FocusGrabber = new Lang.Class({
 | 
			
		||||
    Name: 'FocusGrabber',
 | 
			
		||||
 | 
			
		||||
@@ -258,6 +238,8 @@ const NotificationApplicationPolicy = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _changed: function(settings, key) {
 | 
			
		||||
        this.emit('policy-changed', key);
 | 
			
		||||
        if (key == 'enable')
 | 
			
		||||
            this.emit('enable-changed');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _canonicalizeId: function(id) {
 | 
			
		||||
@@ -508,6 +490,7 @@ const NotificationBanner = new Lang.Class({
 | 
			
		||||
    _init: function(notification) {
 | 
			
		||||
        this.parent(notification);
 | 
			
		||||
 | 
			
		||||
        this.actor.can_focus = false;
 | 
			
		||||
        this.actor.add_style_class_name('notification-banner');
 | 
			
		||||
 | 
			
		||||
        this._buttonBox = null;
 | 
			
		||||
@@ -975,6 +958,14 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
        Shell.util_set_hidden_from_pick(this.actor, false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get bannerAlignment() {
 | 
			
		||||
        return this._bannerBin.get_x_align();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    set bannerAlignment(align) {
 | 
			
		||||
        this._bannerBin.set_x_align(align);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onNotificationKeyRelease: function(actor, event) {
 | 
			
		||||
        if (event.get_key_symbol() == Clutter.KEY_Escape && event.get_state() == 0) {
 | 
			
		||||
            this._expireNotification();
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,6 @@ const Atk = imports.gi.Atk;
 | 
			
		||||
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
 | 
			
		||||
const Animation = imports.ui.animation;
 | 
			
		||||
const Layout = imports.ui.layout;
 | 
			
		||||
const Lightbox = imports.ui.lightbox;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
@@ -23,10 +22,6 @@ const Tweener = imports.ui.tweener;
 | 
			
		||||
const OPEN_AND_CLOSE_TIME = 0.1;
 | 
			
		||||
const FADE_OUT_DIALOG_TIME = 1.0;
 | 
			
		||||
 | 
			
		||||
const WORK_SPINNER_ICON_SIZE = 24;
 | 
			
		||||
const WORK_SPINNER_ANIMATION_DELAY = 1.0;
 | 
			
		||||
const WORK_SPINNER_ANIMATION_TIME = 0.3;
 | 
			
		||||
 | 
			
		||||
const State = {
 | 
			
		||||
    OPENED: 0,
 | 
			
		||||
    CLOSED: 1,
 | 
			
		||||
@@ -79,7 +74,9 @@ const ModalDialog = new Lang.Class({
 | 
			
		||||
        this._group.add_actor(this._backgroundBin);
 | 
			
		||||
 | 
			
		||||
        this.dialogLayout = new St.BoxLayout({ style_class: 'modal-dialog',
 | 
			
		||||
                                               vertical:    true });
 | 
			
		||||
                                               x_align:      Clutter.ActorAlign.CENTER,
 | 
			
		||||
                                               y_align:      Clutter.ActorAlign.CENTER,
 | 
			
		||||
                                               vertical:     true });
 | 
			
		||||
        // modal dialogs are fixed width and grow vertically; set the request
 | 
			
		||||
        // mode accordingly so wrapped labels are handled correctly during
 | 
			
		||||
        // size requests.
 | 
			
		||||
@@ -100,7 +97,8 @@ const ModalDialog = new Lang.Class({
 | 
			
		||||
        this.backgroundStack.add_actor(this.dialogLayout);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        this.contentLayout = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        this.contentLayout = new St.BoxLayout({ vertical: true,
 | 
			
		||||
                                                style_class: "modal-dialog-content-box" });
 | 
			
		||||
        this.dialogLayout.add(this.contentLayout,
 | 
			
		||||
                              { expand:  true,
 | 
			
		||||
                                x_fill:  true,
 | 
			
		||||
@@ -108,8 +106,7 @@ const ModalDialog = new Lang.Class({
 | 
			
		||||
                                x_align: St.Align.MIDDLE,
 | 
			
		||||
                                y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        this.buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box',
 | 
			
		||||
                                               vertical: false });
 | 
			
		||||
        this.buttonLayout = new St.Widget ({ layout_manager: new Clutter.BoxLayout ({ homogeneous:true }) });
 | 
			
		||||
        this.dialogLayout.add(this.buttonLayout,
 | 
			
		||||
                              { x_align: St.Align.MIDDLE,
 | 
			
		||||
                                y_align: St.Align.END });
 | 
			
		||||
@@ -118,8 +115,6 @@ const ModalDialog = new Lang.Class({
 | 
			
		||||
        this._initialKeyFocus = this.dialogLayout;
 | 
			
		||||
        this._initialKeyFocusDestroyId = 0;
 | 
			
		||||
        this._savedKeyFocus = null;
 | 
			
		||||
 | 
			
		||||
        this._workSpinner = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
@@ -147,16 +142,12 @@ const ModalDialog = new Lang.Class({
 | 
			
		||||
            else
 | 
			
		||||
                x_alignment = St.Align.MIDDLE;
 | 
			
		||||
 | 
			
		||||
            this.addButton(buttonInfo, { expand: true,
 | 
			
		||||
                                         x_fill: false,
 | 
			
		||||
                                         y_fill: false,
 | 
			
		||||
                                         x_align: x_alignment,
 | 
			
		||||
                                         y_align: St.Align.MIDDLE });
 | 
			
		||||
            this.addButton(buttonInfo);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addButton: function(buttonInfo, layoutInfo) {
 | 
			
		||||
        let label = buttonInfo['label'];
 | 
			
		||||
    addButton: function(buttonInfo) {
 | 
			
		||||
        let label = buttonInfo['label']
 | 
			
		||||
        let action = buttonInfo['action'];
 | 
			
		||||
        let key = buttonInfo['key'];
 | 
			
		||||
        let isDefault = buttonInfo['default'];
 | 
			
		||||
@@ -170,10 +161,12 @@ const ModalDialog = new Lang.Class({
 | 
			
		||||
        else
 | 
			
		||||
            keys = [];
 | 
			
		||||
 | 
			
		||||
        let button = new St.Button({ style_class: 'modal-dialog-button button',
 | 
			
		||||
        let button = new St.Button({ style_class: 'modal-dialog-linked-button',
 | 
			
		||||
                                     button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
 | 
			
		||||
                                     reactive:    true,
 | 
			
		||||
                                     can_focus:   true,
 | 
			
		||||
                                     x_expand:    true,
 | 
			
		||||
                                     y_expand:    true,
 | 
			
		||||
                                     label:       label });
 | 
			
		||||
        button.connect('clicked', action);
 | 
			
		||||
 | 
			
		||||
@@ -188,47 +181,11 @@ const ModalDialog = new Lang.Class({
 | 
			
		||||
        for (let i in keys)
 | 
			
		||||
            this._buttonKeys[keys[i]] = buttonInfo;
 | 
			
		||||
 | 
			
		||||
        this.buttonLayout.add(button, layoutInfo);
 | 
			
		||||
        this.buttonLayout.add_actor(button);
 | 
			
		||||
 | 
			
		||||
        return button;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    placeSpinner: function(layoutInfo) {
 | 
			
		||||
        let spinnerIcon = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/process-working.svg');
 | 
			
		||||
        this._workSpinner = new Animation.AnimatedIcon(spinnerIcon, WORK_SPINNER_ICON_SIZE);
 | 
			
		||||
        this._workSpinner.actor.opacity = 0;
 | 
			
		||||
        this._workSpinner.actor.show();
 | 
			
		||||
 | 
			
		||||
        this.buttonLayout.add(this._workSpinner.actor, layoutInfo);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setWorking: function(working) {
 | 
			
		||||
        if (!this._workSpinner)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Tweener.removeTweens(this._workSpinner.actor);
 | 
			
		||||
        if (working) {
 | 
			
		||||
            this._workSpinner.play();
 | 
			
		||||
            Tweener.addTween(this._workSpinner.actor,
 | 
			
		||||
                             { opacity: 255,
 | 
			
		||||
                               delay: WORK_SPINNER_ANIMATION_DELAY,
 | 
			
		||||
                               time: WORK_SPINNER_ANIMATION_TIME,
 | 
			
		||||
                               transition: 'linear'
 | 
			
		||||
                             });
 | 
			
		||||
        } else {
 | 
			
		||||
            Tweener.addTween(this._workSpinner.actor,
 | 
			
		||||
                             { opacity: 0,
 | 
			
		||||
                               time: WORK_SPINNER_ANIMATION_TIME,
 | 
			
		||||
                               transition: 'linear',
 | 
			
		||||
                               onCompleteScope: this,
 | 
			
		||||
                               onComplete: function() {
 | 
			
		||||
                                   if (this._workSpinner)
 | 
			
		||||
                                       this._workSpinner.stop();
 | 
			
		||||
                               }
 | 
			
		||||
                             });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeyPressEvent: function(object, event) {
 | 
			
		||||
        this._pressedKey = event.get_key_symbol();
 | 
			
		||||
        return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
@@ -302,7 +259,7 @@ const ModalDialog = new Lang.Class({
 | 
			
		||||
        if (this.state == State.OPENED || this.state == State.OPENING)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        if (!this.pushModal({ timestamp: timestamp }))
 | 
			
		||||
        if (!this.pushModal(timestamp))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        this._fadeOpen(onPrimary);
 | 
			
		||||
@@ -361,8 +318,11 @@ const ModalDialog = new Lang.Class({
 | 
			
		||||
    pushModal: function (timestamp) {
 | 
			
		||||
        if (this._hasModal)
 | 
			
		||||
            return true;
 | 
			
		||||
        if (!Main.pushModal(this._group, { timestamp: timestamp,
 | 
			
		||||
                                           actionMode: this._actionMode }))
 | 
			
		||||
 | 
			
		||||
        let params = { actionMode: this._actionMode };
 | 
			
		||||
        if (timestamp)
 | 
			
		||||
            params['timestamp'] = timestamp;
 | 
			
		||||
        if (!Main.pushModal(this._group, params))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        this._hasModal = true;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										270
									
								
								js/ui/mpris.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,270 @@
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const Calendar = imports.ui.calendar;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageList = imports.ui.messageList;
 | 
			
		||||
 | 
			
		||||
const DBusIface = '<node> \
 | 
			
		||||
<interface name="org.freedesktop.DBus"> \
 | 
			
		||||
  <method name="ListNames"> \
 | 
			
		||||
    <arg type="as" direction="out" name="names" /> \
 | 
			
		||||
  </method> \
 | 
			
		||||
  <signal name="NameOwnerChanged"> \
 | 
			
		||||
    <arg type="s" direction="out" name="name" /> \
 | 
			
		||||
    <arg type="s" direction="out" name="oldOwner" /> \
 | 
			
		||||
    <arg type="s" direction="out" name="newOwner" /> \
 | 
			
		||||
  </signal> \
 | 
			
		||||
</interface> \
 | 
			
		||||
</node>';
 | 
			
		||||
const DBusProxy = Gio.DBusProxy.makeProxyWrapper(DBusIface);
 | 
			
		||||
 | 
			
		||||
const MprisIface = '<node> \
 | 
			
		||||
<interface name="org.mpris.MediaPlayer2"> \
 | 
			
		||||
  <method name="Raise" /> \
 | 
			
		||||
  <property name="CanRaise" type="b" access="read" /> \
 | 
			
		||||
  <property name="DesktopEntry" type="s" access="read" /> \
 | 
			
		||||
</interface> \
 | 
			
		||||
</node>';
 | 
			
		||||
const MprisProxy = Gio.DBusProxy.makeProxyWrapper(MprisIface);
 | 
			
		||||
 | 
			
		||||
const MprisPlayerIface = '<node> \
 | 
			
		||||
<interface name="org.mpris.MediaPlayer2.Player"> \
 | 
			
		||||
  <method name="PlayPause" /> \
 | 
			
		||||
  <method name="Next" /> \
 | 
			
		||||
  <method name="Previous" /> \
 | 
			
		||||
  <property name="CanPlay" type="b" access="read" /> \
 | 
			
		||||
  <property name="Metadata" type="a{sv}" access="read" /> \
 | 
			
		||||
  <property name="PlaybackStatus" type="s" access="read" /> \
 | 
			
		||||
</interface> \
 | 
			
		||||
</node>';
 | 
			
		||||
const MprisPlayerProxy = Gio.DBusProxy.makeProxyWrapper(MprisPlayerIface);
 | 
			
		||||
 | 
			
		||||
const MPRIS_PLAYER_PREFIX = 'org.mpris.MediaPlayer2.';
 | 
			
		||||
 | 
			
		||||
const MediaMessage = new Lang.Class({
 | 
			
		||||
    Name: 'MediaMessage',
 | 
			
		||||
    Extends: MessageList.Message,
 | 
			
		||||
 | 
			
		||||
    _init: function(player) {
 | 
			
		||||
        this._player = player;
 | 
			
		||||
 | 
			
		||||
        this.parent('', '');
 | 
			
		||||
 | 
			
		||||
        this._icon = new St.Icon({ style_class: 'media-message-cover-icon' });
 | 
			
		||||
        this.setIcon(this._icon);
 | 
			
		||||
 | 
			
		||||
        this.addMediaControl('media-skip-backward-symbolic',
 | 
			
		||||
            Lang.bind(this, function() {
 | 
			
		||||
                this._player.previous();
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        this._playPauseButton = this.addMediaControl(null,
 | 
			
		||||
            Lang.bind(this, function() {
 | 
			
		||||
                this._player.playPause();
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        this.addMediaControl('media-skip-forward-symbolic',
 | 
			
		||||
            Lang.bind(this, function() {
 | 
			
		||||
                this._player.next();
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        this._player.connect('changed', Lang.bind(this, this._update));
 | 
			
		||||
        this._player.connect('closed', Lang.bind(this, this.close));
 | 
			
		||||
        this._update();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onClicked: function() {
 | 
			
		||||
        this._player.raise();
 | 
			
		||||
        Main.panel.closeCalendar();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _update: function() {
 | 
			
		||||
        this.setTitle(this._player.trackArtists.join(', '));
 | 
			
		||||
        this.setBody(this._player.trackTitle);
 | 
			
		||||
 | 
			
		||||
        if (this._player.trackCoverUrl) {
 | 
			
		||||
            let file = Gio.File.new_for_uri(this._player.trackCoverUrl);
 | 
			
		||||
            this._icon.gicon = new Gio.FileIcon({ file: file });
 | 
			
		||||
            this._icon.remove_style_class_name('fallback');
 | 
			
		||||
        } else {
 | 
			
		||||
            this._icon.icon_name = 'audio-x-generic-symbolic';
 | 
			
		||||
            this._icon.add_style_class_name('fallback');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let isPlaying = this._player.status == 'Playing';
 | 
			
		||||
        let iconName = isPlaying ? 'media-playback-pause-symbolic'
 | 
			
		||||
                                 : 'media-playback-start-symbolic';
 | 
			
		||||
        this._playPauseButton.child.icon_name = iconName;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const MprisPlayer = new Lang.Class({
 | 
			
		||||
    Name: 'MprisPlayer',
 | 
			
		||||
 | 
			
		||||
    _init: function(busName) {
 | 
			
		||||
        this._mprisProxy = new MprisProxy(Gio.DBus.session, busName,
 | 
			
		||||
                                          '/org/mpris/MediaPlayer2',
 | 
			
		||||
                                          Lang.bind(this, this._onMprisProxyReady));
 | 
			
		||||
        this._playerProxy = new MprisPlayerProxy(Gio.DBus.session, busName,
 | 
			
		||||
                                                 '/org/mpris/MediaPlayer2',
 | 
			
		||||
                                                 Lang.bind(this, this._onPlayerProxyReady));
 | 
			
		||||
 | 
			
		||||
        this._visible = false;
 | 
			
		||||
        this._trackArtists = [];
 | 
			
		||||
        this._trackTitle = '';
 | 
			
		||||
        this._trackCoverUrl = '';
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get status() {
 | 
			
		||||
        return this._playerProxy.PlaybackStatus;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get trackArtists() {
 | 
			
		||||
        return this._trackArtists;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get trackTitle() {
 | 
			
		||||
        return this._trackTitle;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get trackCoverUrl() {
 | 
			
		||||
        return this._trackCoverUrl;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    playPause: function() {
 | 
			
		||||
        this._playerProxy.PlayPauseRemote();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    next: function() {
 | 
			
		||||
        this._playerProxy.NextRemote();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    previous: function() {
 | 
			
		||||
        this._playerProxy.PreviousRemote();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    raise: function() {
 | 
			
		||||
        // The remote Raise() method may run into focus stealing prevention,
 | 
			
		||||
        // so prefer activating the app via .desktop file if possible
 | 
			
		||||
        let app = null;
 | 
			
		||||
        if (this._mprisProxy.DesktopEntry) {
 | 
			
		||||
            let desktopId = this._mprisProxy.DesktopEntry + '.desktop';
 | 
			
		||||
            app = Shell.AppSystem.get_default().lookup_app(desktopId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (app)
 | 
			
		||||
            app.activate();
 | 
			
		||||
        else if (this._mprisProxy.CanRaise)
 | 
			
		||||
            this._mprisProxy.RaiseRemote();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _close: function() {
 | 
			
		||||
        this._mprisProxy.disconnect(this._ownerNotifyId);
 | 
			
		||||
        this._mprisProxy = null;
 | 
			
		||||
 | 
			
		||||
        this._playerProxy.disconnect(this._propsChangedId);
 | 
			
		||||
        this._playerProxy = null;
 | 
			
		||||
 | 
			
		||||
        this.emit('closed');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onMprisProxyReady: function() {
 | 
			
		||||
        this._ownerNotifyId = this._mprisProxy.connect('notify::g-name-owner',
 | 
			
		||||
            Lang.bind(this, function() {
 | 
			
		||||
                if (!this._mprisProxy.g_name_owner)
 | 
			
		||||
                    this._close();
 | 
			
		||||
            }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onPlayerProxyReady: function() {
 | 
			
		||||
        this._propsChangedId = this._playerProxy.connect('g-properties-changed',
 | 
			
		||||
                                                         Lang.bind(this, this._updateState));
 | 
			
		||||
        this._updateState();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateState: function() {
 | 
			
		||||
        let metadata = {};
 | 
			
		||||
        for (let prop in this._playerProxy.Metadata)
 | 
			
		||||
            metadata[prop] = this._playerProxy.Metadata[prop].deep_unpack();
 | 
			
		||||
 | 
			
		||||
        this._trackArtists = metadata['xesam:artist'] || [_("Unknown artist")];
 | 
			
		||||
        this._trackTitle = metadata['xesam:title'] || _("Unknown title");
 | 
			
		||||
        this._trackCoverUrl = metadata['mpris:artUrl'] || '';
 | 
			
		||||
        this.emit('changed');
 | 
			
		||||
 | 
			
		||||
        let visible = this._playerProxy.CanPlay;
 | 
			
		||||
 | 
			
		||||
        if (this._visible != visible) {
 | 
			
		||||
            this._visible = visible;
 | 
			
		||||
            if (visible)
 | 
			
		||||
                this.emit('show');
 | 
			
		||||
            else
 | 
			
		||||
                this._close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(MprisPlayer.prototype);
 | 
			
		||||
 | 
			
		||||
const MediaSection = new Lang.Class({
 | 
			
		||||
    Name: 'MediaSection',
 | 
			
		||||
    Extends: MessageList.MessageListSection,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.parent(_("Media"));
 | 
			
		||||
 | 
			
		||||
        this._players = new Map();
 | 
			
		||||
 | 
			
		||||
        this._proxy = new DBusProxy(Gio.DBus.session,
 | 
			
		||||
                                    'org.freedesktop.DBus',
 | 
			
		||||
                                    '/org/freedesktop/DBus',
 | 
			
		||||
                                    Lang.bind(this, this._onProxyReady));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _shouldShow: function() {
 | 
			
		||||
        return !this.empty && Calendar.isToday(this._date);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _addPlayer: function(busName) {
 | 
			
		||||
        if (this._players.get(busName))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let player = new MprisPlayer(busName);
 | 
			
		||||
        player.connect('closed', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
                this._players.delete(busName);
 | 
			
		||||
            }));
 | 
			
		||||
        player.connect('show', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
                let message = new MediaMessage(player);
 | 
			
		||||
                this.addMessage(message, true);
 | 
			
		||||
            }));
 | 
			
		||||
        this._players.set(busName, player);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onProxyReady: function() {
 | 
			
		||||
        this._proxy.ListNamesRemote(Lang.bind(this,
 | 
			
		||||
            function([names]) {
 | 
			
		||||
                names.forEach(Lang.bind(this,
 | 
			
		||||
                    function(name) {
 | 
			
		||||
                        if (!name.startsWith(MPRIS_PLAYER_PREFIX))
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        this._addPlayer(name);
 | 
			
		||||
                    }));
 | 
			
		||||
            }));
 | 
			
		||||
        this._proxy.connectSignal('NameOwnerChanged',
 | 
			
		||||
                                  Lang.bind(this, this._onNameOwnerChanged));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onNameOwnerChanged: function(proxy, sender, [name, oldOwner, newOwner]) {
 | 
			
		||||
        if (!name.startsWith(MPRIS_PLAYER_PREFIX))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (newOwner && !oldOwner)
 | 
			
		||||
            this._addPlayer(name);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
@@ -15,8 +15,7 @@ const OsdMonitorLabel = new Lang.Class({
 | 
			
		||||
    Name: 'OsdMonitorLabel',
 | 
			
		||||
 | 
			
		||||
    _init: function(monitor, label) {
 | 
			
		||||
        this._actor = new St.Widget({ opacity: 0,
 | 
			
		||||
                                      x_expand: true,
 | 
			
		||||
        this._actor = new St.Widget({ x_expand: true,
 | 
			
		||||
                                      y_expand: true });
 | 
			
		||||
 | 
			
		||||
        this._monitor = monitor;
 | 
			
		||||
@@ -34,10 +33,6 @@ const OsdMonitorLabel = new Lang.Class({
 | 
			
		||||
        this._position();
 | 
			
		||||
 | 
			
		||||
        Meta.disable_unredirect_for_screen(global.screen);
 | 
			
		||||
        Tweener.addTween(this._actor,
 | 
			
		||||
                         { opacity: 255,
 | 
			
		||||
                           time: FADE_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad' });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _position: function() {
 | 
			
		||||
@@ -52,15 +47,8 @@ const OsdMonitorLabel = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
        Tweener.addTween(this._actor,
 | 
			
		||||
                         { opacity: 0,
 | 
			
		||||
                           time: FADE_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: Lang.bind(this, function() {
 | 
			
		||||
                               this._actor.destroy();
 | 
			
		||||
                               Meta.enable_unredirect_for_screen(global.screen);
 | 
			
		||||
                           })
 | 
			
		||||
                         });
 | 
			
		||||
        this._actor.destroy();
 | 
			
		||||
        Meta.enable_unredirect_for_screen(global.screen);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -107,13 +107,6 @@ const Overview = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._overviewCreated = true;
 | 
			
		||||
 | 
			
		||||
        // The main Background actors are inside global.window_group which are
 | 
			
		||||
        // hidden when displaying the overview, so we create a new
 | 
			
		||||
        // one. Instances of this class share a single CoglTexture behind the
 | 
			
		||||
        // scenes which allows us to show the background with different
 | 
			
		||||
        // rendering options without duplicating the texture data.
 | 
			
		||||
        let monitor = Main.layoutManager.primaryMonitor;
 | 
			
		||||
 | 
			
		||||
        let layout = new Clutter.BinLayout();
 | 
			
		||||
        this._stack = new Clutter.Actor({ layout_manager: layout });
 | 
			
		||||
        this._stack.add_constraint(new LayoutManager.MonitorConstraint({ primary: true }));
 | 
			
		||||
@@ -128,6 +121,11 @@ const Overview = new Lang.Class({
 | 
			
		||||
                                            y_expand: true });
 | 
			
		||||
        this._overview._delegate = this;
 | 
			
		||||
 | 
			
		||||
        // The main Background actors are inside global.window_group which are
 | 
			
		||||
        // hidden when displaying the overview, so we create a new
 | 
			
		||||
        // one. Instances of this class share a single CoglTexture behind the
 | 
			
		||||
        // scenes which allows us to show the background with different
 | 
			
		||||
        // rendering options without duplicating the texture data.
 | 
			
		||||
        this._backgroundGroup = new Meta.BackgroundGroup();
 | 
			
		||||
        Main.layoutManager.overviewGroup.add_child(this._backgroundGroup);
 | 
			
		||||
        this._bgManagers = [];
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										100
									
								
								js/ui/panel.js
									
									
									
									
									
								
							
							
						
						@@ -25,12 +25,12 @@ const RemoteMenu = imports.ui.remoteMenu;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
const PANEL_ICON_SIZE = 24;
 | 
			
		||||
const APP_MENU_ICON_MARGIN = 2;
 | 
			
		||||
const PANEL_ICON_SIZE = 16;
 | 
			
		||||
const APP_MENU_ICON_MARGIN = 0;
 | 
			
		||||
 | 
			
		||||
const BUTTON_DND_ACTIVATION_TIMEOUT = 250;
 | 
			
		||||
 | 
			
		||||
const SPINNER_ANIMATION_TIME = 0.2;
 | 
			
		||||
const SPINNER_ANIMATION_TIME = 1.0;
 | 
			
		||||
 | 
			
		||||
// To make sure the panel corners blend nicely with the panel,
 | 
			
		||||
// we draw background and borders the same way, e.g. drawing
 | 
			
		||||
@@ -95,6 +95,7 @@ const AppMenuButton = new Lang.Class({
 | 
			
		||||
        this._startingApps = [];
 | 
			
		||||
 | 
			
		||||
        this._menuManager = panel.menuManager;
 | 
			
		||||
        this._gtkSettings = Gtk.Settings.get_default();
 | 
			
		||||
        this._targetApp = null;
 | 
			
		||||
        this._appMenuNotifyId = 0;
 | 
			
		||||
        this._actionGroupNotifyId = 0;
 | 
			
		||||
@@ -123,11 +124,14 @@ const AppMenuButton = new Lang.Class({
 | 
			
		||||
        this._arrow = PopupMenu.arrowIcon(St.Side.BOTTOM);
 | 
			
		||||
        this._container.add_actor(this._arrow);
 | 
			
		||||
 | 
			
		||||
        this._visible = !Main.overview.visible;
 | 
			
		||||
        this._visible = this._gtkSettings.gtk_shell_shows_app_menu &&
 | 
			
		||||
                        !Main.overview.visible;
 | 
			
		||||
        if (!this._visible)
 | 
			
		||||
            this.actor.hide();
 | 
			
		||||
        this._overviewHidingId = Main.overview.connect('hiding', Lang.bind(this, this._sync));
 | 
			
		||||
        this._overviewShowingId = Main.overview.connect('showing', Lang.bind(this, this._sync));
 | 
			
		||||
        this._showsAppMenuId = this._gtkSettings.connect('notify::gtk-shell-shows-app-menu',
 | 
			
		||||
                                                         Lang.bind(this, this._sync));
 | 
			
		||||
 | 
			
		||||
        this._stop = true;
 | 
			
		||||
 | 
			
		||||
@@ -305,7 +309,9 @@ const AppMenuButton = new Lang.Class({
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let visible = (this._targetApp != null && !Main.overview.visibleTarget);
 | 
			
		||||
        let visible = (this._targetApp != null &&
 | 
			
		||||
                       this._gtkSettings.gtk_shell_shows_app_menu &&
 | 
			
		||||
                       !Main.overview.visibleTarget);
 | 
			
		||||
        if (visible)
 | 
			
		||||
            this.show();
 | 
			
		||||
        else
 | 
			
		||||
@@ -378,6 +384,10 @@ const AppMenuButton = new Lang.Class({
 | 
			
		||||
            Main.overview.disconnect(this._overviewShowingId);
 | 
			
		||||
            this._overviewShowingId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (this._showsAppMenuId > 0) {
 | 
			
		||||
            this._gtkSettings.disconnect(this._showsAppMenuId);
 | 
			
		||||
            this._showsAppMenuId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (this._switchWorkspaceNotifyId > 0) {
 | 
			
		||||
            global.window_manager.disconnect(this._switchWorkspaceNotifyId);
 | 
			
		||||
            this._switchWorkspaceNotifyId = 0;
 | 
			
		||||
@@ -449,7 +459,8 @@ const ActivitiesButton = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        if (event.type() == Clutter.EventType.TOUCH_END ||
 | 
			
		||||
            event.type() == Clutter.EventType.BUTTON_RELEASE)
 | 
			
		||||
            Main.overview.toggle();
 | 
			
		||||
            if (Main.overview.shouldToggleByCornerOrButton())
 | 
			
		||||
                Main.overview.toggle();
 | 
			
		||||
 | 
			
		||||
        return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
    },
 | 
			
		||||
@@ -457,7 +468,8 @@ const ActivitiesButton = new Lang.Class({
 | 
			
		||||
    _onKeyRelease: function(actor, event) {
 | 
			
		||||
        let symbol = event.get_key_symbol();
 | 
			
		||||
        if (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_space) {
 | 
			
		||||
            Main.overview.toggle();
 | 
			
		||||
            if (Main.overview.shouldToggleByCornerOrButton())
 | 
			
		||||
                Main.overview.toggle();
 | 
			
		||||
        }
 | 
			
		||||
        return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
    },
 | 
			
		||||
@@ -642,14 +654,50 @@ const PanelCorner = new Lang.Class({
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AggregateLayout = new Lang.Class({
 | 
			
		||||
    Name: 'AggregateLayout',
 | 
			
		||||
    Extends: Clutter.BoxLayout,
 | 
			
		||||
 | 
			
		||||
    _init: function(params) {
 | 
			
		||||
        if (!params)
 | 
			
		||||
            params = {};
 | 
			
		||||
        params['orientation'] = Clutter.Orientation.VERTICAL;
 | 
			
		||||
        this.parent(params);
 | 
			
		||||
 | 
			
		||||
        this._sizeChildren = [];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addSizeChild: function(actor) {
 | 
			
		||||
        this._sizeChildren.push(actor);
 | 
			
		||||
        this.layout_changed();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_width: function(container, forHeight) {
 | 
			
		||||
        let themeNode = container.get_theme_node();
 | 
			
		||||
        let minWidth = themeNode.get_min_width();
 | 
			
		||||
        let natWidth = minWidth;
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._sizeChildren.length; i++) {
 | 
			
		||||
            let child = this._sizeChildren[i];
 | 
			
		||||
            let [childMin, childNat] = child.get_preferred_width(forHeight);
 | 
			
		||||
            minWidth = Math.max(minWidth, childMin);
 | 
			
		||||
            natWidth = Math.max(minWidth, childNat);
 | 
			
		||||
        }
 | 
			
		||||
        return [minWidth, natWidth];
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AggregateMenu = new Lang.Class({
 | 
			
		||||
    Name: 'AggregateMenu',
 | 
			
		||||
    Extends: PanelMenu.Button,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.parent(0.0, _("Settings"), false);
 | 
			
		||||
        this.parent(0.0, C_("System menu in the top bar", "System"), false);
 | 
			
		||||
        this.menu.actor.add_style_class_name('aggregate-menu');
 | 
			
		||||
 | 
			
		||||
        let menuLayout = new AggregateLayout();
 | 
			
		||||
        this.menu.box.set_layout_manager(menuLayout);
 | 
			
		||||
 | 
			
		||||
        this._indicators = new St.BoxLayout({ style_class: 'panel-status-indicators-box' });
 | 
			
		||||
        this.actor.add_child(this._indicators);
 | 
			
		||||
 | 
			
		||||
@@ -697,8 +745,12 @@ const AggregateMenu = new Lang.Class({
 | 
			
		||||
        this.menu.addMenuItem(this._location.menu);
 | 
			
		||||
        this.menu.addMenuItem(this._rfkill.menu);
 | 
			
		||||
        this.menu.addMenuItem(this._power.menu);
 | 
			
		||||
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
 | 
			
		||||
        this.menu.addMenuItem(this._system.menu);
 | 
			
		||||
 | 
			
		||||
        menuLayout.addSizeChild(this._location.menu.actor);
 | 
			
		||||
        menuLayout.addSizeChild(this._rfkill.menu.actor);
 | 
			
		||||
        menuLayout.addSizeChild(this._power.menu.actor);
 | 
			
		||||
        menuLayout.addSizeChild(this._system.menu.actor);
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -933,6 +985,14 @@ const Panel = new Lang.Class({
 | 
			
		||||
        this._updateBox(panel.center, this._centerBox);
 | 
			
		||||
        this._updateBox(panel.right, this._rightBox);
 | 
			
		||||
 | 
			
		||||
        if (panel.left.indexOf('dateMenu') != -1)
 | 
			
		||||
            Main.messageTray.bannerAlignment = Clutter.ActorAlign.START;
 | 
			
		||||
        else if (panel.right.indexOf('dateMenu') != -1)
 | 
			
		||||
            Main.messageTray.bannerAlignment = Clutter.ActorAlign.END;
 | 
			
		||||
        // Default to center if there is no dateMenu
 | 
			
		||||
        else
 | 
			
		||||
            Main.messageTray.bannerAlignment = Clutter.ActorAlign.CENTER;
 | 
			
		||||
 | 
			
		||||
        if (this._sessionStyle)
 | 
			
		||||
            this._removeStyleClassName(this._sessionStyle);
 | 
			
		||||
 | 
			
		||||
@@ -995,6 +1055,7 @@ const Panel = new Lang.Class({
 | 
			
		||||
        if (parent)
 | 
			
		||||
            parent.remove_actor(container);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        box.insert_child_at_index(container, position);
 | 
			
		||||
        if (indicator.menu)
 | 
			
		||||
            this.menuManager.addMenu(indicator.menu);
 | 
			
		||||
@@ -1004,6 +1065,8 @@ const Panel = new Lang.Class({
 | 
			
		||||
            emitter.disconnect(destroyId);
 | 
			
		||||
            container.destroy();
 | 
			
		||||
        }));
 | 
			
		||||
        indicator.connect('menu-set', Lang.bind(this, this._onMenuSet));
 | 
			
		||||
        this._onMenuSet(indicator);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addToStatusArea: function(role, indicator, position, box) {
 | 
			
		||||
@@ -1035,5 +1098,24 @@ const Panel = new Lang.Class({
 | 
			
		||||
        this.actor.remove_style_class_name(className);
 | 
			
		||||
        this._rightCorner.actor.remove_style_class_name(className);
 | 
			
		||||
        this._leftCorner.actor.remove_style_class_name(className);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onMenuSet: function(indicator) {
 | 
			
		||||
        if (!indicator.menu || indicator.menu._openChangedId > 0)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        indicator.menu._openChangedId = indicator.menu.connect('open-state-changed',
 | 
			
		||||
            Lang.bind(this, function(menu, isOpen) {
 | 
			
		||||
                let boxAlignment;
 | 
			
		||||
                if (this._leftBox.contains(indicator.container))
 | 
			
		||||
                    boxAlignment = Clutter.ActorAlign.START;
 | 
			
		||||
                else if (this._centerBox.contains(indicator.container))
 | 
			
		||||
                    boxAlignment = Clutter.ActorAlign.CENTER;
 | 
			
		||||
                else if (this._rightBox.contains(indicator.container))
 | 
			
		||||
                    boxAlignment = Clutter.ActorAlign.END;
 | 
			
		||||
 | 
			
		||||
                if (boxAlignment == Main.messageTray.bannerAlignment)
 | 
			
		||||
                    Main.messageTray.bannerBlocked = isOpen;
 | 
			
		||||
            }));
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -128,6 +128,7 @@ const Button = new Lang.Class({
 | 
			
		||||
            Main.uiGroup.add_actor(this.menu.actor);
 | 
			
		||||
            this.menu.actor.hide();
 | 
			
		||||
        }
 | 
			
		||||
        this.emit('menu-set');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onEvent: function(actor, event) {
 | 
			
		||||
 
 | 
			
		||||
@@ -396,6 +396,7 @@ const PopupImageMenuItem = new Lang.Class({
 | 
			
		||||
        this.actor.add_child(this.label);
 | 
			
		||||
        this._icon = new St.Icon({ style_class: 'popup-menu-icon' });
 | 
			
		||||
        this.actor.add_child(this._icon, { align: St.Align.END });
 | 
			
		||||
        this.actor.label_actor = this.label;
 | 
			
		||||
 | 
			
		||||
        this.setIcon(iconName);
 | 
			
		||||
    },
 | 
			
		||||
@@ -1059,11 +1060,6 @@ const PopupSubMenuMenuItem = new Lang.Class({
 | 
			
		||||
        let expander = new St.Bin({ style_class: 'popup-menu-item-expander' });
 | 
			
		||||
        this.actor.add(expander, { expand: true });
 | 
			
		||||
 | 
			
		||||
        this.status = new St.Label({ style_class: 'popup-status-menu-item',
 | 
			
		||||
                                     y_expand: true,
 | 
			
		||||
                                     y_align: Clutter.ActorAlign.CENTER });
 | 
			
		||||
        this.actor.add_child(this.status);
 | 
			
		||||
 | 
			
		||||
        this._triangle = arrowIcon(St.Side.RIGHT);
 | 
			
		||||
        this._triangle.pivot_point = new Clutter.Point({ x: 0.5, y: 0.6 });
 | 
			
		||||
 | 
			
		||||
@@ -1150,6 +1146,16 @@ const PopupSubMenuMenuItem = new Lang.Class({
 | 
			
		||||
        this.actor.remove_style_pseudo_class ('active');
 | 
			
		||||
        this._setOpenState(!this._getOpenState());
 | 
			
		||||
        return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onTouchEvent: function(actor, event) {
 | 
			
		||||
        if (event.type() == Clutter.EventType.TOUCH_END) {
 | 
			
		||||
            // Since we override the parent, we need to manage what the parent does
 | 
			
		||||
            // with the active style class
 | 
			
		||||
            this.actor.remove_style_pseudo_class ('active');
 | 
			
		||||
            this._setOpenState(!this._getOpenState());
 | 
			
		||||
        }
 | 
			
		||||
        return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -61,6 +61,7 @@ const RunDialog = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
                                   // rt is short for "reload theme"
 | 
			
		||||
                                   'rt': Lang.bind(this, function() {
 | 
			
		||||
                                       Main.reloadThemeResource();
 | 
			
		||||
                                       Main.loadTheme();
 | 
			
		||||
                                   })
 | 
			
		||||
                                 };
 | 
			
		||||
 
 | 
			
		||||
@@ -507,21 +507,22 @@ const ScreenShield = new Lang.Class({
 | 
			
		||||
                                                      this._liftShield(true, 0);
 | 
			
		||||
                                              }));
 | 
			
		||||
 | 
			
		||||
        this._inhibitor = null;
 | 
			
		||||
        this._aboutToSuspend = false;
 | 
			
		||||
        this._loginManager = LoginManager.getLoginManager();
 | 
			
		||||
        this._loginManager.connect('prepare-for-sleep',
 | 
			
		||||
                                   Lang.bind(this, this._prepareForSleep));
 | 
			
		||||
        this._inhibitSuspend();
 | 
			
		||||
 | 
			
		||||
        this._loginSession = null;
 | 
			
		||||
        this._loginManager.getCurrentSessionProxy(Lang.bind(this,
 | 
			
		||||
            function(sessionProxy) {
 | 
			
		||||
                this._loginSession = sessionProxy;
 | 
			
		||||
                this._loginSession.connectSignal('Lock', Lang.bind(this, function() { this.lock(false); }));
 | 
			
		||||
                this._loginSession.connectSignal('Unlock', Lang.bind(this, function() { this.deactivate(false); }));
 | 
			
		||||
                this._loginSession.connect('g-properties-changed', Lang.bind(this, this._syncInhibitor));
 | 
			
		||||
                this._syncInhibitor();
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        this._settings = new Gio.Settings({ schema_id: SCREENSAVER_SCHEMA });
 | 
			
		||||
        this._settings.connect('changed::' + LOCK_ENABLED_KEY, Lang.bind(this, this._syncInhibitor));
 | 
			
		||||
 | 
			
		||||
        this._isModal = false;
 | 
			
		||||
        this._hasLockScreen = false;
 | 
			
		||||
@@ -547,6 +548,18 @@ const ScreenShield = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this.idleMonitor = Meta.IdleMonitor.get_core();
 | 
			
		||||
        this._cursorTracker = Meta.CursorTracker.get_for_screen(global.screen);
 | 
			
		||||
 | 
			
		||||
        this._syncInhibitor();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setActive: function(active) {
 | 
			
		||||
        let prevIsActive = this._isActive;
 | 
			
		||||
        this._isActive = active;
 | 
			
		||||
 | 
			
		||||
        if (prevIsActive != this._isActive)
 | 
			
		||||
            this.emit('active-changed');
 | 
			
		||||
 | 
			
		||||
        this._syncInhibitor();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createBackground: function(monitorIndex) {
 | 
			
		||||
@@ -664,31 +677,28 @@ const ScreenShield = new Lang.Class({
 | 
			
		||||
        return Clutter.EVENT_STOP;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _inhibitSuspend: function() {
 | 
			
		||||
        this._loginManager.inhibit(_("GNOME needs to lock the screen"),
 | 
			
		||||
                                   Lang.bind(this, function(inhibitor) {
 | 
			
		||||
                                       this._inhibitor = inhibitor;
 | 
			
		||||
                                   }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _uninhibitSuspend: function() {
 | 
			
		||||
        if (this._inhibitor)
 | 
			
		||||
            this._inhibitor.close(null);
 | 
			
		||||
        this._inhibitor = null;
 | 
			
		||||
    _syncInhibitor: function() {
 | 
			
		||||
        let inhibit = (this._loginSession && this._loginSession.Active &&
 | 
			
		||||
                       !this._isActive && this._settings.get_boolean(LOCK_ENABLED_KEY));
 | 
			
		||||
        if (inhibit) {
 | 
			
		||||
            this._loginManager.inhibit(_("GNOME needs to lock the screen"),
 | 
			
		||||
                                       Lang.bind(this, function(inhibitor) {
 | 
			
		||||
                                           if (this._inhibitor)
 | 
			
		||||
                                               this._inhibitor.close(null);
 | 
			
		||||
                                           this._inhibitor = inhibitor;
 | 
			
		||||
                                       }));
 | 
			
		||||
        } else {
 | 
			
		||||
            if (this._inhibitor)
 | 
			
		||||
                this._inhibitor.close(null);
 | 
			
		||||
            this._inhibitor = null;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _prepareForSleep: function(loginManager, aboutToSuspend) {
 | 
			
		||||
        this._aboutToSuspend = aboutToSuspend;
 | 
			
		||||
 | 
			
		||||
        if (aboutToSuspend) {
 | 
			
		||||
            if (!this._settings.get_boolean(LOCK_ENABLED_KEY)) {
 | 
			
		||||
                this._uninhibitSuspend();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            this.lock(true);
 | 
			
		||||
            if (this._settings.get_boolean(LOCK_ENABLED_KEY))
 | 
			
		||||
                this.lock(true);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._inhibitSuspend();
 | 
			
		||||
 | 
			
		||||
            this._wakeUpScreen();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
@@ -1083,15 +1093,7 @@ const ScreenShield = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _completeLockScreenShown: function() {
 | 
			
		||||
        let prevIsActive = this._isActive;
 | 
			
		||||
        this._isActive = true;
 | 
			
		||||
 | 
			
		||||
        if (prevIsActive != this._isActive)
 | 
			
		||||
            this.emit('active-changed');
 | 
			
		||||
 | 
			
		||||
        if (this._aboutToSuspend)
 | 
			
		||||
            this._uninhibitSuspend();
 | 
			
		||||
 | 
			
		||||
        this._setActive(true);
 | 
			
		||||
        this.emit('lock-screen-shown');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -1185,8 +1187,7 @@ const ScreenShield = new Lang.Class({
 | 
			
		||||
            // gnome-settings-daemon will stop blanking the screen
 | 
			
		||||
 | 
			
		||||
            this._activationTime = 0;
 | 
			
		||||
            this._isActive = false;
 | 
			
		||||
            this.emit('active-changed');
 | 
			
		||||
            this._setActive(false);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -1229,9 +1230,8 @@ const ScreenShield = new Lang.Class({
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._activationTime = 0;
 | 
			
		||||
        this._isActive = false;
 | 
			
		||||
        this._setActive(false);
 | 
			
		||||
        this._isLocked = false;
 | 
			
		||||
        this.emit('active-changed');
 | 
			
		||||
        this.emit('locked-changed');
 | 
			
		||||
        global.set_runtime_state(LOCKED_STATE_STR, null);
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -137,6 +137,10 @@ const Slider = new Lang.Class({
 | 
			
		||||
            this._motionId = this.actor.connect('motion-event', Lang.bind(this, this._motionEvent));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // We need to emit 'drag-begin' before moving the handle to make
 | 
			
		||||
        // sure that no 'value-changed' signal is emitted before this one.
 | 
			
		||||
        this.emit('drag-begin');
 | 
			
		||||
 | 
			
		||||
        let absX, absY;
 | 
			
		||||
        [absX, absY] = event.get_coords();
 | 
			
		||||
        this._moveHandle(absX, absY);
 | 
			
		||||
@@ -224,6 +228,7 @@ const Slider = new Lang.Class({
 | 
			
		||||
            let delta = key == Clutter.KEY_Right ? 0.1 : -0.1;
 | 
			
		||||
            this._value = Math.max(0, Math.min(this._value + delta, 1));
 | 
			
		||||
            this.actor.queue_repaint();
 | 
			
		||||
            this.emit('drag-begin');
 | 
			
		||||
            this.emit('value-changed', this._value);
 | 
			
		||||
            this.emit('drag-end');
 | 
			
		||||
            return Clutter.EVENT_STOP;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,8 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GnomeBluetooth = imports.gi.GnomeBluetooth;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const PanelMenu = imports.ui.panelMenu;
 | 
			
		||||
@@ -23,6 +20,8 @@ const RfkillManagerInterface = '<node> \
 | 
			
		||||
 | 
			
		||||
const RfkillManagerProxy = Gio.DBusProxy.makeProxyWrapper(RfkillManagerInterface);
 | 
			
		||||
 | 
			
		||||
const HAD_BLUETOOTH_DEVICES_SETUP = 'had-bluetooth-devices-setup';
 | 
			
		||||
 | 
			
		||||
const Indicator = new Lang.Class({
 | 
			
		||||
    Name: 'BTIndicator',
 | 
			
		||||
    Extends: PanelMenu.SystemIndicator,
 | 
			
		||||
@@ -32,6 +31,7 @@ const Indicator = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._indicator = this._addIndicator();
 | 
			
		||||
        this._indicator.icon_name = 'bluetooth-active-symbolic';
 | 
			
		||||
        this._hadSetupDevices = global.settings.get_boolean(HAD_BLUETOOTH_DEVICES_SETUP);
 | 
			
		||||
 | 
			
		||||
        this._proxy = new RfkillManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
 | 
			
		||||
                                             Lang.bind(this, function(proxy, error) {
 | 
			
		||||
@@ -44,13 +44,15 @@ const Indicator = new Lang.Class({
 | 
			
		||||
                                             }));
 | 
			
		||||
        this._proxy.connect('g-properties-changed', Lang.bind(this, this._sync));
 | 
			
		||||
 | 
			
		||||
        // The Bluetooth menu only appears when Bluetooth is in use,
 | 
			
		||||
        // so just statically build it with a "Turn Off" menu item.
 | 
			
		||||
        this._item = new PopupMenu.PopupSubMenuMenuItem(_("Bluetooth"), true);
 | 
			
		||||
        this._item.icon.icon_name = 'bluetooth-active-symbolic';
 | 
			
		||||
        this._item.menu.addAction(_("Turn Off"), Lang.bind(this, function() {
 | 
			
		||||
            this._proxy.BluetoothAirplaneMode = true;
 | 
			
		||||
 | 
			
		||||
        this._toggleItem = new PopupMenu.PopupMenuItem('');
 | 
			
		||||
        this._toggleItem.connect('activate', Lang.bind(this, function() {
 | 
			
		||||
            this._proxy.BluetoothAirplaneMode = !this._proxy.BluetoothAirplaneMode;
 | 
			
		||||
        }));
 | 
			
		||||
        this._item.menu.addMenuItem(this._toggleItem);
 | 
			
		||||
 | 
			
		||||
        this._item.menu.addSettingsAction(_("Bluetooth Settings"), 'gnome-bluetooth-panel.desktop');
 | 
			
		||||
        this.menu.addMenuItem(this._item);
 | 
			
		||||
 | 
			
		||||
@@ -68,41 +70,75 @@ const Indicator = new Lang.Class({
 | 
			
		||||
        while (ret) {
 | 
			
		||||
            let isDefault = this._model.get_value(iter,
 | 
			
		||||
                                                  GnomeBluetooth.Column.DEFAULT);
 | 
			
		||||
            if (isDefault)
 | 
			
		||||
            let isPowered = this._model.get_value(iter,
 | 
			
		||||
                                                  GnomeBluetooth.Column.POWERED);
 | 
			
		||||
            if (isDefault && isPowered)
 | 
			
		||||
                return iter;
 | 
			
		||||
            ret = this._model.iter_next(iter);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getNConnectedDevices: function() {
 | 
			
		||||
    // nDevices is the number of devices setup for the current default
 | 
			
		||||
    // adapter if one exists and is powered. If unpowered or unavailable,
 | 
			
		||||
    // nDevice is "1" if it had setup devices associated to it the last
 | 
			
		||||
    // time it was seen, and "-1" if not.
 | 
			
		||||
    //
 | 
			
		||||
    // nConnectedDevices is the number of devices connected to the default
 | 
			
		||||
    // adapter if one exists and is powered, or -1 if it's not available.
 | 
			
		||||
    _getNDevices: function() {
 | 
			
		||||
        let adapter = this._getDefaultAdapter();
 | 
			
		||||
        if (!adapter)
 | 
			
		||||
            return 0;
 | 
			
		||||
            return [ this._hadSetupDevices ? 1 : -1, -1 ];
 | 
			
		||||
 | 
			
		||||
        let nConnectedDevices = 0;
 | 
			
		||||
        let nDevices = 0;
 | 
			
		||||
        let [ret, iter] = this._model.iter_children(adapter);
 | 
			
		||||
        while (ret) {
 | 
			
		||||
            let isConnected = this._model.get_value(iter,
 | 
			
		||||
                                                    GnomeBluetooth.Column.CONNECTED);
 | 
			
		||||
            if (isConnected)
 | 
			
		||||
                nConnectedDevices++;
 | 
			
		||||
 | 
			
		||||
            let isPaired = this._model.get_value(iter,
 | 
			
		||||
                                                 GnomeBluetooth.Column.PAIRED);
 | 
			
		||||
            let isTrusted = this._model.get_value(iter,
 | 
			
		||||
                                                  GnomeBluetooth.Column.TRUSTED);
 | 
			
		||||
            if (isPaired || isTrusted)
 | 
			
		||||
                nDevices++;
 | 
			
		||||
            ret = this._model.iter_next(iter);
 | 
			
		||||
        }
 | 
			
		||||
        return nDevices;
 | 
			
		||||
 | 
			
		||||
        if (this._hadSetupDevices != (nDevices > 0)) {
 | 
			
		||||
            this._hadSetupDevices = !this._hadSetupDevices;
 | 
			
		||||
            global.settings.set_boolean(HAD_BLUETOOTH_DEVICES_SETUP, this._hadSetupDevices);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return [ nDevices, nConnectedDevices];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _sync: function() {
 | 
			
		||||
        let nDevices = this._getNConnectedDevices();
 | 
			
		||||
        let [ nDevices, nConnectedDevices ] = this._getNDevices();
 | 
			
		||||
        let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
 | 
			
		||||
 | 
			
		||||
        this.menu.setSensitive(sensitive);
 | 
			
		||||
        this._indicator.visible = nDevices > 0;
 | 
			
		||||
        this._item.actor.visible = this._proxy.BluetoothHasAirplaneMode && !this._proxy.BluetoothAirplaneMode;
 | 
			
		||||
        this._indicator.visible = nConnectedDevices > 0;
 | 
			
		||||
 | 
			
		||||
        // Remember if there were setup devices and show the menu
 | 
			
		||||
        // if we've seen setup devices and we're not hard blocked
 | 
			
		||||
        if (nDevices > 0)
 | 
			
		||||
            this._item.status.text = ngettext("%d Connected Device", "%d Connected Devices", nDevices).format(nDevices);
 | 
			
		||||
            this._item.actor.visible = !this._proxy.BluetoothHardwareAirplaneMode;
 | 
			
		||||
        else
 | 
			
		||||
            this._item.status.text = _("Not Connected");
 | 
			
		||||
            this._item.actor.visible = this._proxy.BluetoothHasAirplaneMode && !this._proxy.BluetoothAirplaneMode;
 | 
			
		||||
 | 
			
		||||
        if (nConnectedDevices > 0)
 | 
			
		||||
            /* Translators: this is the number of connected bluetooth devices */
 | 
			
		||||
            this._item.label.text = ngettext("%d Connected", "%d Connected", nConnectedDevices).format(nConnectedDevices);
 | 
			
		||||
        else if (nConnectedDevices == -1)
 | 
			
		||||
            this._item.label.text = _("Off");
 | 
			
		||||
        else
 | 
			
		||||
            this._item.label.text = _("Not In Use");
 | 
			
		||||
 | 
			
		||||
        this._toggleItem.label.text = this._proxy.BluetoothAirplaneMode ? _("Turn On") : _("Turn Off");
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
@@ -7,12 +8,18 @@ const Lang = imports.lang;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const PanelMenu = imports.ui.panelMenu;
 | 
			
		||||
const PopupMenu = imports.ui.popupMenu;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const LOCATION_SCHEMA = 'org.gnome.system.location';
 | 
			
		||||
const MAX_ACCURACY_LEVEL = 'max-accuracy-level';
 | 
			
		||||
const ENABLED = 'enabled';
 | 
			
		||||
 | 
			
		||||
const APP_PERMISSIONS_TABLE = 'gnome';
 | 
			
		||||
const APP_PERMISSIONS_ID = 'geolocation';
 | 
			
		||||
 | 
			
		||||
const GeoclueAccuracyLevel = {
 | 
			
		||||
    NONE: 0,
 | 
			
		||||
    COUNTRY: 1,
 | 
			
		||||
@@ -22,6 +29,15 @@ const GeoclueAccuracyLevel = {
 | 
			
		||||
    EXACT: 8
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function accuracyLevelToString(accuracyLevel) {
 | 
			
		||||
    for (let key in GeoclueAccuracyLevel) {
 | 
			
		||||
        if (GeoclueAccuracyLevel[key] == accuracyLevel)
 | 
			
		||||
            return key;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 'NONE';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var GeoclueIface = '<node> \
 | 
			
		||||
  <interface name="org.freedesktop.GeoClue2.Manager"> \
 | 
			
		||||
    <property name="InUse" type="b" access="read"/> \
 | 
			
		||||
@@ -46,6 +62,26 @@ var AgentIface = '<node> \
 | 
			
		||||
  </interface> \
 | 
			
		||||
</node>';
 | 
			
		||||
 | 
			
		||||
var PermissionStoreIface = '<node> \
 | 
			
		||||
  <interface name="org.freedesktop.impl.portal.PermissionStore"> \
 | 
			
		||||
    <method name="Lookup"> \
 | 
			
		||||
      <arg name="table" type="s" direction="in"/> \
 | 
			
		||||
      <arg name="id" type="s" direction="in"/> \
 | 
			
		||||
      <arg name="permissions" type="a{sas}" direction="out"/> \
 | 
			
		||||
      <arg name="data" type="v" direction="out"/> \
 | 
			
		||||
    </method> \
 | 
			
		||||
    <method name="Set"> \
 | 
			
		||||
      <arg name="table" type="s" direction="in"/> \
 | 
			
		||||
      <arg name="create" type="b" direction="in"/> \
 | 
			
		||||
      <arg name="id" type="s" direction="in"/> \
 | 
			
		||||
      <arg name="app_permissions" type="a{sas}" direction="in"/> \
 | 
			
		||||
      <arg name="data" type="v" direction="in"/> \
 | 
			
		||||
    </method> \
 | 
			
		||||
  </interface> \
 | 
			
		||||
</node>';
 | 
			
		||||
 | 
			
		||||
const PermissionStore = Gio.DBusProxy.makeProxyWrapper(PermissionStoreIface);
 | 
			
		||||
 | 
			
		||||
const Indicator = new Lang.Class({
 | 
			
		||||
    Name: 'LocationIndicator',
 | 
			
		||||
    Extends: PanelMenu.SystemIndicator,
 | 
			
		||||
@@ -62,13 +98,13 @@ const Indicator = new Lang.Class({
 | 
			
		||||
        this._indicator = this._addIndicator();
 | 
			
		||||
        this._indicator.icon_name = 'find-location-symbolic';
 | 
			
		||||
 | 
			
		||||
        this._item = new PopupMenu.PopupSubMenuMenuItem(_("Location"), true);
 | 
			
		||||
        this._item = new PopupMenu.PopupSubMenuMenuItem('', true);
 | 
			
		||||
        this._item.icon.icon_name = 'find-location-symbolic';
 | 
			
		||||
 | 
			
		||||
        this._agent = Gio.DBusExportedObject.wrapJSObject(AgentIface, this);
 | 
			
		||||
        this._agent.export(Gio.DBus.system, '/org/freedesktop/GeoClue2/Agent');
 | 
			
		||||
 | 
			
		||||
        this._item.status.text = _("Enabled");
 | 
			
		||||
        this._item.label.text = _("Location Enabled");
 | 
			
		||||
        this._onOffAction = this._item.menu.addAction(_("Disable"), Lang.bind(this, this._onOnOffAction));
 | 
			
		||||
        this._item.menu.addSettingsAction(_("Privacy Settings"), 'gnome-privacy-panel.desktop');
 | 
			
		||||
 | 
			
		||||
@@ -83,64 +119,66 @@ const Indicator = new Lang.Class({
 | 
			
		||||
        this._onSessionUpdated();
 | 
			
		||||
        this._onMaxAccuracyLevelChanged();
 | 
			
		||||
        this._connectToGeoclue();
 | 
			
		||||
        this._connectToPermissionStore();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get MaxAccuracyLevel() {
 | 
			
		||||
        return this._getMaxAccuracyLevel();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // We (and geoclue) have currently no way to reliably identifying apps so
 | 
			
		||||
    // for now, lets just authorize all apps as long as they provide a valid
 | 
			
		||||
    // desktop ID. We also ensure they don't get more accuracy than global max.
 | 
			
		||||
    AuthorizeApp: function(desktop_id, reqAccuracyLevel) {
 | 
			
		||||
        var appSystem = Shell.AppSystem.get_default();
 | 
			
		||||
        var app = appSystem.lookup_app(desktop_id + ".desktop");
 | 
			
		||||
        if (app == null) {
 | 
			
		||||
            return [false, 0];
 | 
			
		||||
        }
 | 
			
		||||
    AuthorizeAppAsync: function(params, invocation) {
 | 
			
		||||
        let [desktopId, reqAccuracyLevel] = params;
 | 
			
		||||
 | 
			
		||||
        let allowedAccuracyLevel = clamp(reqAccuracyLevel, 0, this._getMaxAccuracyLevel());
 | 
			
		||||
        return [true, allowedAccuracyLevel];
 | 
			
		||||
        let authorizer = new AppAuthorizer(desktopId,
 | 
			
		||||
                                           reqAccuracyLevel,
 | 
			
		||||
                                           this._permStoreProxy,
 | 
			
		||||
                                           this._getMaxAccuracyLevel());
 | 
			
		||||
 | 
			
		||||
        authorizer.authorize(Lang.bind(this, function(accuracyLevel) {
 | 
			
		||||
            let ret = (accuracyLevel != GeoclueAccuracyLevel.NONE);
 | 
			
		||||
            invocation.return_value(GLib.Variant.new('(bu)',
 | 
			
		||||
                                                     [ret, accuracyLevel]));
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _syncIndicator: function() {
 | 
			
		||||
        if (this._proxy == null) {
 | 
			
		||||
        if (this._managerProxy == null) {
 | 
			
		||||
            this._indicator.visible = false;
 | 
			
		||||
            this._item.actor.visible = false;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._indicator.visible = this._proxy.InUse;
 | 
			
		||||
        this._indicator.visible = this._managerProxy.InUse;
 | 
			
		||||
        this._item.actor.visible = this._indicator.visible;
 | 
			
		||||
        this._updateMenuLabels();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _connectToGeoclue: function() {
 | 
			
		||||
        if (this._proxy != null || this._connecting)
 | 
			
		||||
        if (this._managerProxy != null || this._connecting)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        this._connecting = true;
 | 
			
		||||
        new GeoclueManager(Gio.DBus.system,
 | 
			
		||||
                           'org.freedesktop.GeoClue2',
 | 
			
		||||
                           '/org/freedesktop/GeoClue2/Manager',
 | 
			
		||||
                           Lang.bind(this, this._onProxyReady));
 | 
			
		||||
                           Lang.bind(this, this._onManagerProxyReady));
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onProxyReady: function(proxy, error) {
 | 
			
		||||
    _onManagerProxyReady: function(proxy, error) {
 | 
			
		||||
        if (error != null) {
 | 
			
		||||
            log(error.message);
 | 
			
		||||
            this._connecting = false;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._proxy = proxy;
 | 
			
		||||
        this._propertiesChangedId = this._proxy.connect('g-properties-changed',
 | 
			
		||||
        this._managerProxy = proxy;
 | 
			
		||||
        this._propertiesChangedId = this._managerProxy.connect('g-properties-changed',
 | 
			
		||||
                                                        Lang.bind(this, this._onGeocluePropsChanged));
 | 
			
		||||
 | 
			
		||||
        this._syncIndicator();
 | 
			
		||||
 | 
			
		||||
        this._proxy.AddAgentRemote('gnome-shell', Lang.bind(this, this._onAgentRegistered));
 | 
			
		||||
        this._managerProxy.AddAgentRemote('gnome-shell', Lang.bind(this, this._onAgentRegistered));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onAgentRegistered: function(result, error) {
 | 
			
		||||
@@ -153,10 +191,10 @@ const Indicator = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _onGeoclueVanished: function() {
 | 
			
		||||
        if (this._propertiesChangedId) {
 | 
			
		||||
            this._proxy.disconnect(this._propertiesChangedId);
 | 
			
		||||
            this._managerProxy.disconnect(this._propertiesChangedId);
 | 
			
		||||
            this._propertiesChangedId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        this._proxy = null;
 | 
			
		||||
        this._managerProxy = null;
 | 
			
		||||
 | 
			
		||||
        this._syncIndicator();
 | 
			
		||||
    },
 | 
			
		||||
@@ -173,10 +211,11 @@ const Indicator = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _updateMenuLabels: function() {
 | 
			
		||||
        if (this._settings.get_boolean(ENABLED)) {
 | 
			
		||||
            this._item.status.text = this._indicator.visible ? _("In Use") : _("Enabled");
 | 
			
		||||
            this._item.label.text = this._indicator.visible ? _("Location In Use")
 | 
			
		||||
                                                            : _("Location Enabled");
 | 
			
		||||
            this._onOffAction.label.text = _("Disable");
 | 
			
		||||
        } else {
 | 
			
		||||
            this._item.status.text = _("Disabled");
 | 
			
		||||
            this._item.label.text = _("Location Disabled");
 | 
			
		||||
            this._onOffAction.label.text = _("Enable");
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
@@ -210,9 +249,206 @@ const Indicator = new Lang.Class({
 | 
			
		||||
        let unpacked = properties.deep_unpack();
 | 
			
		||||
        if ("InUse" in unpacked)
 | 
			
		||||
            this._syncIndicator();
 | 
			
		||||
    }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _connectToPermissionStore: function() {
 | 
			
		||||
        this._permStoreProxy = null;
 | 
			
		||||
        new PermissionStore(Gio.DBus.session,
 | 
			
		||||
                           'org.freedesktop.impl.portal.PermissionStore',
 | 
			
		||||
                           '/org/freedesktop/impl/portal/PermissionStore',
 | 
			
		||||
                           Lang.bind(this, this._onPermStoreProxyReady));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onPermStoreProxyReady: function(proxy, error) {
 | 
			
		||||
        if (error != null) {
 | 
			
		||||
            log(error.message);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._permStoreProxy = proxy;
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function clamp(value, min, max) {
 | 
			
		||||
    return Math.max(min, Math.min(max, value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const AppAuthorizer = new Lang.Class({
 | 
			
		||||
    Name: 'LocationAppAuthorizer',
 | 
			
		||||
 | 
			
		||||
    _init: function(desktopId,
 | 
			
		||||
                    reqAccuracyLevel,
 | 
			
		||||
                    permStoreProxy,
 | 
			
		||||
                    maxAccuracyLevel) {
 | 
			
		||||
        this.desktopId = desktopId;
 | 
			
		||||
        this.reqAccuracyLevel = reqAccuracyLevel;
 | 
			
		||||
        this._permStoreProxy = permStoreProxy;
 | 
			
		||||
        this._maxAccuracyLevel = maxAccuracyLevel;
 | 
			
		||||
 | 
			
		||||
        this._accuracyLevel = GeoclueAccuracyLevel.NONE;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    authorize: function(onAuthDone) {
 | 
			
		||||
        this._onAuthDone = onAuthDone;
 | 
			
		||||
 | 
			
		||||
        let appSystem = Shell.AppSystem.get_default();
 | 
			
		||||
        this._app = appSystem.lookup_app(this.desktopId + ".desktop");
 | 
			
		||||
        if (this._app == null || this._permStoreProxy == null) {
 | 
			
		||||
            this._completeAuth();
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._permStoreProxy.LookupRemote(APP_PERMISSIONS_TABLE,
 | 
			
		||||
                                          APP_PERMISSIONS_ID,
 | 
			
		||||
                                          Lang.bind(this,
 | 
			
		||||
                                                    this._onPermLookupDone));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onPermLookupDone: function(result, error) {
 | 
			
		||||
        if (error != null) {
 | 
			
		||||
            if (error.domain == Gio.DBusError) {
 | 
			
		||||
                // Likely no xdg-app installed, just authorize the app
 | 
			
		||||
                this._accuracyLevel = this.reqAccuracyLevel;
 | 
			
		||||
                this._permStoreProxy = null;
 | 
			
		||||
                this._completeAuth();
 | 
			
		||||
            } else {
 | 
			
		||||
                // Currently xdg-app throws an error if we lookup for
 | 
			
		||||
                // unknown ID (which would be the case first time this code
 | 
			
		||||
                // runs) so we continue with user authorization as normal
 | 
			
		||||
                // and ID is added to the store if user says "yes".
 | 
			
		||||
                log(error.message);
 | 
			
		||||
                this._permissions = {};
 | 
			
		||||
                this._userAuthorizeApp();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [this._permissions] = result;
 | 
			
		||||
        let permission = this._permissions[this.desktopId];
 | 
			
		||||
 | 
			
		||||
        if (permission == null) {
 | 
			
		||||
            this._userAuthorizeApp();
 | 
			
		||||
        } else {
 | 
			
		||||
            let [levelStr] = permission || ['NONE'];
 | 
			
		||||
            this._accuracyLevel = GeoclueAccuracyLevel[levelStr] ||
 | 
			
		||||
                                  GeoclueAccuracyLevel.NONE;
 | 
			
		||||
            this._completeAuth();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _userAuthorizeApp: function() {
 | 
			
		||||
        let name = this._app.get_name();
 | 
			
		||||
        let appInfo = this._app.get_app_info();
 | 
			
		||||
        let reason = appInfo.get_string("X-Geoclue-Reason");
 | 
			
		||||
 | 
			
		||||
        this._showAppAuthDialog(name, reason);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showAppAuthDialog: function(name, reason) {
 | 
			
		||||
        this._dialog = new GeolocationDialog(name,
 | 
			
		||||
                                             reason,
 | 
			
		||||
                                             this.reqAccuracyLevel);
 | 
			
		||||
 | 
			
		||||
        let responseId = this._dialog.connect('response', Lang.bind(this,
 | 
			
		||||
            function(dialog, level) {
 | 
			
		||||
                this._dialog.disconnect(responseId);
 | 
			
		||||
                this._accuracyLevel = level;
 | 
			
		||||
                this._completeAuth();
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        this._dialog.open();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _completeAuth: function() {
 | 
			
		||||
        if (this._accuracyLevel != GeoclueAccuracyLevel.NONE) {
 | 
			
		||||
            this._accuracyLevel = clamp(this._accuracyLevel,
 | 
			
		||||
                                        0,
 | 
			
		||||
                                        this._maxAccuracyLevel);
 | 
			
		||||
        }
 | 
			
		||||
        this._saveToPermissionStore();
 | 
			
		||||
 | 
			
		||||
        this._onAuthDone(this._accuracyLevel);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _saveToPermissionStore: function() {
 | 
			
		||||
        if (this._permStoreProxy == null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let levelStr = accuracyLevelToString(this._accuracyLevel);
 | 
			
		||||
        let dateStr = Math.round(Date.now() / 1000).toString();
 | 
			
		||||
        this._permissions[this.desktopId] = [levelStr, dateStr];
 | 
			
		||||
 | 
			
		||||
        let data = GLib.Variant.new('av', {});
 | 
			
		||||
 | 
			
		||||
        this._permStoreProxy.SetRemote(APP_PERMISSIONS_TABLE,
 | 
			
		||||
                                       true,
 | 
			
		||||
                                       APP_PERMISSIONS_ID,
 | 
			
		||||
                                       this._permissions,
 | 
			
		||||
                                       data,
 | 
			
		||||
                                       function (result, error) {
 | 
			
		||||
            if (error != null)
 | 
			
		||||
                log(error.message);
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const GeolocationDialog = new Lang.Class({
 | 
			
		||||
    Name: 'GeolocationDialog',
 | 
			
		||||
    Extends: ModalDialog.ModalDialog,
 | 
			
		||||
 | 
			
		||||
    _init: function(name, reason, reqAccuracyLevel) {
 | 
			
		||||
        this.parent({ styleClass: 'geolocation-dialog' });
 | 
			
		||||
        this.reqAccuracyLevel = reqAccuracyLevel;
 | 
			
		||||
 | 
			
		||||
        let mainContentBox = new St.BoxLayout({ style_class: 'geolocation-dialog-main-layout' });
 | 
			
		||||
        this.contentLayout.add_actor(mainContentBox);
 | 
			
		||||
 | 
			
		||||
        let icon = new St.Icon({ style_class: 'geolocation-dialog-icon',
 | 
			
		||||
                                 icon_name: 'find-location-symbolic',
 | 
			
		||||
                                 y_align: Clutter.ActorAlign.START });
 | 
			
		||||
        mainContentBox.add_actor(icon);
 | 
			
		||||
 | 
			
		||||
        let messageBox = new St.BoxLayout({ style_class: 'geolocation-dialog-content',
 | 
			
		||||
                                            vertical: true });
 | 
			
		||||
        mainContentBox.add_actor(messageBox);
 | 
			
		||||
 | 
			
		||||
        this._title = new St.Label({ style_class: 'geolocation-dialog-title headline' });
 | 
			
		||||
        messageBox.add_actor(this._title);
 | 
			
		||||
 | 
			
		||||
        this._reason = new St.Label({ style_class: 'geolocation-dialog-reason' });
 | 
			
		||||
        messageBox.add_actor(this._reason);
 | 
			
		||||
 | 
			
		||||
        this._privacyNote = new St.Label();
 | 
			
		||||
        messageBox.add_actor(this._privacyNote);
 | 
			
		||||
 | 
			
		||||
        let button = this.addButton({ label: _("Deny Access"),
 | 
			
		||||
                                      action: Lang.bind(this, this._onDenyClicked),
 | 
			
		||||
                                      key: Clutter.KEY_Escape });
 | 
			
		||||
        this.addButton({ label: _("Grant Access"),
 | 
			
		||||
                         action: Lang.bind(this, this._onGrantClicked) });
 | 
			
		||||
 | 
			
		||||
        this.setInitialKeyFocus(button);
 | 
			
		||||
 | 
			
		||||
        /* Translators: %s is an application name */
 | 
			
		||||
        this._title.text = _("Give %s access to your location?").format(name);
 | 
			
		||||
 | 
			
		||||
        this._privacyNote.text = _("Location access can be changed at any time from the privacy settings.");
 | 
			
		||||
 | 
			
		||||
        if (reason)
 | 
			
		||||
            this._reason.text = reason;
 | 
			
		||||
        this._reason.visible = (reason != null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onGrantClicked: function() {
 | 
			
		||||
        this.emit('response', this.reqAccuracyLevel);
 | 
			
		||||
        this.close();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDenyClicked: function() {
 | 
			
		||||
        this.emit('response', GeoclueAccuracyLevel.NONE);
 | 
			
		||||
        this.close();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(GeolocationDialog.prototype);
 | 
			
		||||
 
 | 
			
		||||
@@ -257,16 +257,8 @@ const NMConnectionSection = new Lang.Class({
 | 
			
		||||
        this._radioSection.actor.visible = (nItems > 1);
 | 
			
		||||
        this._labelSection.actor.visible = (nItems == 1);
 | 
			
		||||
 | 
			
		||||
        this.item.status.text = this._getStatus();
 | 
			
		||||
        this.item.label.text = this._getStatus();
 | 
			
		||||
        this.item.icon.icon_name = this._getMenuIcon();
 | 
			
		||||
 | 
			
		||||
        // desc can be undefined at cold-plug, before we called
 | 
			
		||||
        // NMGtk.disambiguate_device_names() at least once
 | 
			
		||||
        let desc = this._getDescription();
 | 
			
		||||
        if (desc)
 | 
			
		||||
            this.item.label.text = desc;
 | 
			
		||||
        else
 | 
			
		||||
            this.item.label.text = '';
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getMenuIcon: function() {
 | 
			
		||||
@@ -355,6 +347,7 @@ const NMConnectionDevice = new Lang.Class({
 | 
			
		||||
        this.parent(client);
 | 
			
		||||
        this._device = device;
 | 
			
		||||
        this._settings = settings;
 | 
			
		||||
        this._description = '';
 | 
			
		||||
 | 
			
		||||
        this._autoConnectItem = this.item.menu.addAction(_("Connect"), Lang.bind(this, this._autoConnect));
 | 
			
		||||
        this._deactivateItem = this._radioSection.addAction(_("Turn Off"), Lang.bind(this, this.deactivateConnection));
 | 
			
		||||
@@ -454,38 +447,44 @@ const NMConnectionDevice = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        switch(this._device.state) {
 | 
			
		||||
        case NetworkManager.DeviceState.DISCONNECTED:
 | 
			
		||||
            return _("Off");
 | 
			
		||||
            /* Translators: %s is a network identifier */
 | 
			
		||||
            return _("%s Off").format(this._getDescription());
 | 
			
		||||
        case NetworkManager.DeviceState.ACTIVATED:
 | 
			
		||||
            return _("Connected");
 | 
			
		||||
            /* Translators: %s is a network identifier */
 | 
			
		||||
            return _("%s Connected").format(this._getDescription());
 | 
			
		||||
        case NetworkManager.DeviceState.UNMANAGED:
 | 
			
		||||
            /* Translators: this is for network devices that are physically present but are not
 | 
			
		||||
               under NetworkManager's control (and thus cannot be used in the menu) */
 | 
			
		||||
            return _("Unmanaged");
 | 
			
		||||
               under NetworkManager's control (and thus cannot be used in the menu);
 | 
			
		||||
               %s is a network identifier */
 | 
			
		||||
            return _("%s Unmanaged").format(this._getDescription());
 | 
			
		||||
        case NetworkManager.DeviceState.DEACTIVATING:
 | 
			
		||||
            return _("Disconnecting");
 | 
			
		||||
            /* Translators: %s is a network identifier */
 | 
			
		||||
            return _("%s Disconnecting").format(this._getDescription());
 | 
			
		||||
        case NetworkManager.DeviceState.PREPARE:
 | 
			
		||||
        case NetworkManager.DeviceState.CONFIG:
 | 
			
		||||
        case NetworkManager.DeviceState.IP_CONFIG:
 | 
			
		||||
        case NetworkManager.DeviceState.IP_CHECK:
 | 
			
		||||
        case NetworkManager.DeviceState.SECONDARIES:
 | 
			
		||||
            return _("Connecting");
 | 
			
		||||
            /* Translators: %s is a network identifier */
 | 
			
		||||
            return _("%s Connecting").format(this._getDescription());
 | 
			
		||||
        case NetworkManager.DeviceState.NEED_AUTH:
 | 
			
		||||
            /* Translators: this is for network connections that require some kind of key or password */
 | 
			
		||||
            return _("Authentication required");
 | 
			
		||||
            /* Translators: this is for network connections that require some kind of key or password; %s is a network identifier */
 | 
			
		||||
            return _("%s Requires Authentication").format(this._getDescription());
 | 
			
		||||
        case NetworkManager.DeviceState.UNAVAILABLE:
 | 
			
		||||
            // This state is actually a compound of various states (generically unavailable,
 | 
			
		||||
            // firmware missing), that are exposed by different properties (whose state may
 | 
			
		||||
            // or may not updated when we receive state-changed).
 | 
			
		||||
            if (this._device.firmware_missing) {
 | 
			
		||||
                /* Translators: this is for devices that require some kind of firmware or kernel
 | 
			
		||||
                   module, which is missing */
 | 
			
		||||
                return _("Firmware missing");
 | 
			
		||||
                   module, which is missing; %s is a network identifier */
 | 
			
		||||
                return _("Firmware Missing For %s").format(this._getDescription());
 | 
			
		||||
            }
 | 
			
		||||
            /* Translators: this is for a network device that cannot be activated (for example it
 | 
			
		||||
               is disabled by rfkill, or it has no coverage */
 | 
			
		||||
            return _("Unavailable");
 | 
			
		||||
               is disabled by rfkill, or it has no coverage; %s is a network identifier */
 | 
			
		||||
            return _("%s Unavailable").format(this._getDescription());
 | 
			
		||||
        case NetworkManager.DeviceState.FAILED:
 | 
			
		||||
            return _("Connection failed");
 | 
			
		||||
            /* Translators: %s is a network identifier */
 | 
			
		||||
            return _("%s Connection Failed").format(this._getDescription());
 | 
			
		||||
        default:
 | 
			
		||||
            log('Device state invalid, is %d'.format(this._device.state));
 | 
			
		||||
            return 'invalid';
 | 
			
		||||
@@ -585,11 +584,12 @@ const NMDeviceModem = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _getStatus: function() {
 | 
			
		||||
        if (!this._client.wwan_hardware_enabled)
 | 
			
		||||
            return _("Hardware Disabled");
 | 
			
		||||
            /* Translators: %s is a network identifier */
 | 
			
		||||
            return _("%s Hardware Disabled").format(this._getDescription());
 | 
			
		||||
        else if (!this._client.wwan_enabled)
 | 
			
		||||
            /* Translators: this is for a network device that cannot be activated
 | 
			
		||||
               because it's disabled by rfkill (airplane mode) */
 | 
			
		||||
            return _("Disabled");
 | 
			
		||||
               because it's disabled by rfkill (airplane mode); %s is a network identifier */
 | 
			
		||||
            return _("%s Disabled").format(this._getDescription());
 | 
			
		||||
        else if (this._device.state == NetworkManager.DeviceState.ACTIVATED &&
 | 
			
		||||
                 this._mobileDevice && this._mobileDevice.operator_name)
 | 
			
		||||
            return this._mobileDevice.operator_name;
 | 
			
		||||
@@ -877,7 +877,7 @@ const NMWirelessDialog = new Lang.Class({
 | 
			
		||||
                                                 y_align: Clutter.ActorAlign.CENTER });
 | 
			
		||||
 | 
			
		||||
        let file = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/process-working.svg');
 | 
			
		||||
        this._noNetworksSpinner = new Animation.AnimatedIcon(file, 24, 24);
 | 
			
		||||
        this._noNetworksSpinner = new Animation.AnimatedIcon(file, 16, 16);
 | 
			
		||||
        this._noNetworksBox.add_actor(this._noNetworksSpinner.actor);
 | 
			
		||||
        this._noNetworksBox.add_actor(new St.Label({ style_class: 'no-networks-label',
 | 
			
		||||
                                                     text: _("No Networks") }));
 | 
			
		||||
@@ -917,10 +917,7 @@ const NMWirelessDialog = new Lang.Class({
 | 
			
		||||
                                                  key: Clutter.Escape });
 | 
			
		||||
        this._connectButton = this.addButton({ action: Lang.bind(this, this._connect),
 | 
			
		||||
                                               label: _("Connect"),
 | 
			
		||||
                                               key: Clutter.Return },
 | 
			
		||||
                                             { expand: true,
 | 
			
		||||
                                               x_fill: false,
 | 
			
		||||
                                               x_align: St.Align.END });
 | 
			
		||||
                                               key: Clutter.Return });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _connect: function() {
 | 
			
		||||
@@ -1282,9 +1279,8 @@ const NMDeviceWireless = new Lang.Class({
 | 
			
		||||
        this._toggleItem.label.text = this._client.wireless_enabled ? _("Turn Off") : _("Turn On");
 | 
			
		||||
        this._toggleItem.actor.visible = this._client.wireless_hardware_enabled;
 | 
			
		||||
 | 
			
		||||
        this.item.status.text = this._getStatus();
 | 
			
		||||
        this.item.icon.icon_name = this._getMenuIcon();
 | 
			
		||||
        this.item.label.text = this._description;
 | 
			
		||||
        this.item.label.text = this._getStatus();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setDeviceDescription: function(desc) {
 | 
			
		||||
@@ -1296,18 +1292,23 @@ const NMDeviceWireless = new Lang.Class({
 | 
			
		||||
        let ap = this._device.active_access_point;
 | 
			
		||||
 | 
			
		||||
        if (this._isHotSpotMaster())
 | 
			
		||||
            return _("Hotspot Active");
 | 
			
		||||
            /* Translators: %s is a network identifier */
 | 
			
		||||
            return _("%s Hotspot Active").format(this._description);
 | 
			
		||||
        else if (this._device.state >= NetworkManager.DeviceState.PREPARE &&
 | 
			
		||||
                 this._device.state < NetworkManager.DeviceState.ACTIVATED)
 | 
			
		||||
            return _("Connecting");
 | 
			
		||||
            /* Translators: %s is a network identifier */
 | 
			
		||||
            return _("%s Connecting").format(this._description);
 | 
			
		||||
        else if (ap)
 | 
			
		||||
            return ssidToLabel(ap.get_ssid());
 | 
			
		||||
        else if (!this._client.wireless_hardware_enabled)
 | 
			
		||||
            return _("Hardware Disabled");
 | 
			
		||||
            /* Translators: %s is a network identifier */
 | 
			
		||||
            return _("%s Hardware Disabled").format(this._description);
 | 
			
		||||
        else if (!this._client.wireless_enabled)
 | 
			
		||||
            return _("Off");
 | 
			
		||||
            /* Translators: %s is a network identifier */
 | 
			
		||||
            return _("%s Off").format(this._description);
 | 
			
		||||
        else if (this._device.state == NetworkManager.DeviceState.DISCONNECTED)
 | 
			
		||||
            return _("Not Connected");
 | 
			
		||||
            /* Translators: %s is a network identifier */
 | 
			
		||||
            return _("%s Not Connected").format(this._description);
 | 
			
		||||
        else
 | 
			
		||||
            return '';
 | 
			
		||||
    },
 | 
			
		||||
@@ -1509,7 +1510,7 @@ const NMVPNSection = new Lang.Class({
 | 
			
		||||
                return item.getName();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return _("Off");
 | 
			
		||||
        return _("VPN Off");
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getMenuIcon: function() {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const UPower = imports.gi.UPowerGlib;
 | 
			
		||||
 | 
			
		||||
@@ -25,6 +27,8 @@ const DisplayDeviceInterface = '<node> \
 | 
			
		||||
 | 
			
		||||
const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(DisplayDeviceInterface);
 | 
			
		||||
 | 
			
		||||
const SHOW_BATTERY_PERCENTAGE       = 'show-battery-percentage';
 | 
			
		||||
 | 
			
		||||
const Indicator = new Lang.Class({
 | 
			
		||||
    Name: 'PowerIndicator',
 | 
			
		||||
    Extends: PanelMenu.SystemIndicator,
 | 
			
		||||
@@ -32,7 +36,15 @@ const Indicator = new Lang.Class({
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.parent();
 | 
			
		||||
 | 
			
		||||
        this._desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
 | 
			
		||||
        this._desktopSettings.connect('changed::' + SHOW_BATTERY_PERCENTAGE,
 | 
			
		||||
                                      Lang.bind(this, this._sync));
 | 
			
		||||
 | 
			
		||||
        this._indicator = this._addIndicator();
 | 
			
		||||
        this._percentageLabel = new St.Label({ y_expand: true,
 | 
			
		||||
                                               y_align: Clutter.ActorAlign.CENTER });
 | 
			
		||||
        this.indicators.add(this._percentageLabel, { expand: true, y_fill: true });
 | 
			
		||||
        this.indicators.add_style_class_name('power-status');
 | 
			
		||||
 | 
			
		||||
        this._proxy = new PowerManagerProxy(Gio.DBus.system, BUS_NAME, OBJECT_PATH,
 | 
			
		||||
                                            Lang.bind(this, function(proxy, error) {
 | 
			
		||||
@@ -83,12 +95,12 @@ const Indicator = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        if (this._proxy.State == UPower.DeviceState.DISCHARGING) {
 | 
			
		||||
            // Translators: this is <hours>:<minutes> Remaining (<percentage>)
 | 
			
		||||
            return _("%d\u2236%02d Remaining (%d%%)").format(hours, minutes, this._proxy.Percentage);
 | 
			
		||||
            return _("%d\u2236%02d Remaining (%d\u2009%%)").format(hours, minutes, this._proxy.Percentage);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._proxy.State == UPower.DeviceState.CHARGING) {
 | 
			
		||||
            // Translators: this is <hours>:<minutes> Until Full (<percentage>)
 | 
			
		||||
            return _("%d\u2236%02d Until Full (%d%%)").format(hours, minutes, this._proxy.Percentage);
 | 
			
		||||
            return _("%d\u2236%02d Until Full (%d\u2009%%)").format(hours, minutes, this._proxy.Percentage);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
@@ -99,10 +111,12 @@ const Indicator = new Lang.Class({
 | 
			
		||||
        let visible = this._proxy.IsPresent;
 | 
			
		||||
        if (visible) {
 | 
			
		||||
            this._item.actor.show();
 | 
			
		||||
            this._percentageLabel.visible = this._desktopSettings.get_boolean(SHOW_BATTERY_PERCENTAGE);
 | 
			
		||||
        } else {
 | 
			
		||||
            // If there's no battery, then we use the power icon.
 | 
			
		||||
            this._item.actor.hide();
 | 
			
		||||
            this._indicator.icon_name = 'system-shutdown-symbolic';
 | 
			
		||||
            this._percentageLabel.hide();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -111,13 +125,15 @@ const Indicator = new Lang.Class({
 | 
			
		||||
        this._indicator.icon_name = icon;
 | 
			
		||||
        this._item.icon.icon_name = icon;
 | 
			
		||||
 | 
			
		||||
        // The status label
 | 
			
		||||
        this._item.status.text = this._getStatus();
 | 
			
		||||
 | 
			
		||||
        // The sub-menu heading
 | 
			
		||||
        if (this._proxy.Type == UPower.DeviceKind.UPS)
 | 
			
		||||
            this._item.label.text = _("UPS");
 | 
			
		||||
        // The icon label
 | 
			
		||||
        let label
 | 
			
		||||
        if (this._proxy.State == UPower.DeviceState.FULLY_CHARGED)
 | 
			
		||||
          label = _("%d\u2009%%").format(100);
 | 
			
		||||
        else
 | 
			
		||||
            this._item.label.text = _("Battery");
 | 
			
		||||
          label = _("%d\u2009%%").format(this._proxy.Percentage);
 | 
			
		||||
        this._percentageLabel.clutter_text.set_markup('<span size="smaller">' + label + '</span>');
 | 
			
		||||
 | 
			
		||||
        // The status label
 | 
			
		||||
        this._item.label.text = this._getStatus();
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -85,9 +85,8 @@ const Indicator = new Lang.Class({
 | 
			
		||||
        // The menu only appears when airplane mode is on, so just
 | 
			
		||||
        // statically build it as if it was on, rather than dynamically
 | 
			
		||||
        // changing the menu contents.
 | 
			
		||||
        this._item = new PopupMenu.PopupSubMenuMenuItem(_("Airplane Mode"), true);
 | 
			
		||||
        this._item = new PopupMenu.PopupSubMenuMenuItem(_("Airplane Mode On"), true);
 | 
			
		||||
        this._item.icon.icon_name = 'airplane-mode-symbolic';
 | 
			
		||||
        this._item.status.text = _("On");
 | 
			
		||||
        this._offItem = this._item.menu.addAction(_("Turn Off"), Lang.bind(this, function() {
 | 
			
		||||
            this._manager.airplaneMode = false;
 | 
			
		||||
        }));
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ const Gdm = imports.gi.Gdm;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
@@ -24,6 +25,17 @@ const DISABLE_LOG_OUT_KEY = 'disable-log-out';
 | 
			
		||||
const DISABLE_RESTART_KEY = 'disable-restart-buttons';
 | 
			
		||||
const ALWAYS_SHOW_LOG_OUT_KEY = 'always-show-log-out';
 | 
			
		||||
 | 
			
		||||
const SENSOR_BUS_NAME = 'net.hadess.SensorProxy';
 | 
			
		||||
const SENSOR_OBJECT_PATH = '/net/hadess/SensorProxy';
 | 
			
		||||
 | 
			
		||||
const SensorProxyInterface = '<node> \
 | 
			
		||||
<interface name="net.hadess.SensorProxy"> \
 | 
			
		||||
  <property name="HasAccelerometer" type="b" access="read"/> \
 | 
			
		||||
</interface> \
 | 
			
		||||
</node>';
 | 
			
		||||
 | 
			
		||||
const SensorProxy = Gio.DBusProxy.makeProxyWrapper(SensorProxyInterface);
 | 
			
		||||
 | 
			
		||||
const AltSwitcher = new Lang.Class({
 | 
			
		||||
    Name: 'AltSwitcher',
 | 
			
		||||
 | 
			
		||||
@@ -99,6 +111,7 @@ const Indicator = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._session = new GnomeSession.SessionManager();
 | 
			
		||||
        this._loginManager = LoginManager.getLoginManager();
 | 
			
		||||
        this._monitorManager = Meta.MonitorManager.get();
 | 
			
		||||
        this._haveShutdown = true;
 | 
			
		||||
        this._haveSuspend = true;
 | 
			
		||||
 | 
			
		||||
@@ -144,23 +157,34 @@ const Indicator = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._orientationSettings.connect('changed::orientation-lock',
 | 
			
		||||
                                          Lang.bind(this, this._updateOrientationLock));
 | 
			
		||||
        this._orientationExists = false;
 | 
			
		||||
        Gio.DBus.session.watch_name('org.gnome.SettingsDaemon.Orientation',
 | 
			
		||||
                                    Gio.BusNameWatcherFlags.NONE,
 | 
			
		||||
                                    Lang.bind(this, function() {
 | 
			
		||||
                                        this._orientationExists = true;
 | 
			
		||||
                                        this._updateOrientationLock();
 | 
			
		||||
                                    }),
 | 
			
		||||
                                    Lang.bind(this, function() {
 | 
			
		||||
                                        this._orientationExists = false;
 | 
			
		||||
                                        this._updateOrientationLock();
 | 
			
		||||
                                    }));
 | 
			
		||||
        Main.layoutManager.connect('monitors-changed',
 | 
			
		||||
                                   Lang.bind(this, this._updateOrientationLock));
 | 
			
		||||
        Gio.DBus.system.watch_name(SENSOR_BUS_NAME,
 | 
			
		||||
                                   Gio.BusNameWatcherFlags.NONE,
 | 
			
		||||
                                   Lang.bind(this, this._sensorProxyAppeared),
 | 
			
		||||
                                   Lang.bind(this, function() {
 | 
			
		||||
                                       this._sensorProxy = null;
 | 
			
		||||
                                       this._updateOrientationLock();
 | 
			
		||||
                                   }));
 | 
			
		||||
        this._updateOrientationLock();
 | 
			
		||||
 | 
			
		||||
        Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
 | 
			
		||||
        this._sessionUpdated();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _sensorProxyAppeared: function() {
 | 
			
		||||
        this._sensorProxy = new SensorProxy(Gio.DBus.system, SENSOR_BUS_NAME, SENSOR_OBJECT_PATH,
 | 
			
		||||
            Lang.bind(this, function(proxy, error) {
 | 
			
		||||
                if (error) {
 | 
			
		||||
                    log(error.message);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                this._sensorProxy.connect('g-properties-changed',
 | 
			
		||||
                                          Lang.bind(this, this._updateOrientationLock));
 | 
			
		||||
                this._updateOrientationLock();
 | 
			
		||||
            }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateActionsVisibility: function() {
 | 
			
		||||
        let visible = (this._settingsAction.visible ||
 | 
			
		||||
                       this._orientationLockAction.visible ||
 | 
			
		||||
@@ -231,13 +255,23 @@ const Indicator = new Lang.Class({
 | 
			
		||||
            let file = Gio.File.new_for_path(iconFile);
 | 
			
		||||
            let gicon = new Gio.FileIcon({ file: file });
 | 
			
		||||
            this._switchUserSubMenu.icon.gicon = gicon;
 | 
			
		||||
 | 
			
		||||
            this._switchUserSubMenu.icon.add_style_class_name('user-icon');
 | 
			
		||||
            this._switchUserSubMenu.icon.remove_style_class_name('default-icon');
 | 
			
		||||
        } else {
 | 
			
		||||
            this._switchUserSubMenu.icon.icon_name = 'avatar-default-symbolic';
 | 
			
		||||
 | 
			
		||||
            this._switchUserSubMenu.icon.add_style_class_name('default-icon');
 | 
			
		||||
            this._switchUserSubMenu.icon.remove_style_class_name('user-icon');
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateOrientationLock: function() {
 | 
			
		||||
        this._orientationLockAction.visible = this._orientationExists;
 | 
			
		||||
        if (this._sensorProxy)
 | 
			
		||||
            this._orientationLockAction.visible = this._sensorProxy.HasAccelerometer &&
 | 
			
		||||
                                                  this._monitorManager.get_is_builtin_display_on();
 | 
			
		||||
        else
 | 
			
		||||
            this._orientationLockAction.visible = false;
 | 
			
		||||
 | 
			
		||||
        let locked = this._orientationSettings.get_boolean('orientation-lock');
 | 
			
		||||
        let icon = this._orientationLockAction.child;
 | 
			
		||||
@@ -321,6 +355,9 @@ const Indicator = new Lang.Class({
 | 
			
		||||
        this._switchUserSubMenu.menu.addMenuItem(item);
 | 
			
		||||
        this._logoutItem = item;
 | 
			
		||||
 | 
			
		||||
        this._switchUserSubMenu.menu.addSettingsAction(_("Account Settings"),
 | 
			
		||||
                                                       'gnome-user-accounts-panel.desktop');
 | 
			
		||||
 | 
			
		||||
        this._user.connect('notify::is-loaded', Lang.bind(this, this._updateSwitchUserSubMenu));
 | 
			
		||||
        this._user.connect('changed', Lang.bind(this, this._updateSwitchUserSubMenu));
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -156,7 +156,7 @@ const ViewSelector = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this.appDisplay = new AppDisplay.AppDisplay();
 | 
			
		||||
        this._appsPage = this._addPage(this.appDisplay.actor,
 | 
			
		||||
                                       _("Applications"), 'view-grid-symbolic');
 | 
			
		||||
                                       _("Applications"), 'view-app-grid-symbolic');
 | 
			
		||||
 | 
			
		||||
        this._searchResults = new Search.SearchResults();
 | 
			
		||||
        this._searchPage = this._addPage(this._searchResults.actor,
 | 
			
		||||
@@ -465,6 +465,12 @@ const ViewSelector = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _shouldTriggerSearch: function(symbol) {
 | 
			
		||||
        if (symbol == Clutter.Multi_key)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        if (symbol == Clutter.BackSpace && this._searchActive)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        let unicode = Clutter.keysym_to_unicode(symbol);
 | 
			
		||||
        if (unicode == 0)
 | 
			
		||||
            return false;
 | 
			
		||||
@@ -472,7 +478,7 @@ const ViewSelector = new Lang.Class({
 | 
			
		||||
        if (getTermsForSearchString(String.fromCharCode(unicode)).length > 0)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        return symbol == Clutter.BackSpace && this._searchActive;
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    startSearch: function(event) {
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,8 @@ const WindowAttentionHandler = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        this._tracker = Shell.WindowTracker.get_default();
 | 
			
		||||
        global.display.connect('window-demands-attention', Lang.bind(this, this._onWindowDemandsAttention));
 | 
			
		||||
        this._windowDemandsAttentionId = global.display.connect('window-demands-attention',
 | 
			
		||||
                                                                Lang.bind(this, this._onWindowDemandsAttention));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getTitleAndBanner: function(app, window) {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,8 +19,6 @@ const Tweener = imports.ui.tweener;
 | 
			
		||||
const WindowMenu = imports.ui.windowMenu;
 | 
			
		||||
 | 
			
		||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
 | 
			
		||||
const MAXIMIZE_WINDOW_ANIMATION_TIME = 0.15;
 | 
			
		||||
const UNMAXIMIZE_WINDOW_ANIMATION_TIME = 0.15;
 | 
			
		||||
const MINIMIZE_WINDOW_ANIMATION_TIME = 0.2;
 | 
			
		||||
const SHOW_WINDOW_ANIMATION_TIME = 0.15;
 | 
			
		||||
const DIALOG_SHOW_WINDOW_ANIMATION_TIME = 0.1;
 | 
			
		||||
@@ -83,12 +81,10 @@ const DisplayChangeDialog = new Lang.Class({
 | 
			
		||||
        */
 | 
			
		||||
        this._cancelButton = this.addButton({ label: _("Revert Settings"),
 | 
			
		||||
                                              action: Lang.bind(this, this._onFailure),
 | 
			
		||||
                                              key: Clutter.Escape },
 | 
			
		||||
                                            { expand: true, x_fill: false, x_align: St.Align.START });
 | 
			
		||||
                                              key: Clutter.Escape });
 | 
			
		||||
        this._okButton = this.addButton({ label:  _("Keep Changes"),
 | 
			
		||||
                                          action: Lang.bind(this, this._onSuccess),
 | 
			
		||||
                                          default: true },
 | 
			
		||||
                                        { expand: false, x_fill: false, x_align: St.Align.END });
 | 
			
		||||
                                          default: true });
 | 
			
		||||
 | 
			
		||||
        this._timeoutId = Mainloop.timeout_add(ONE_SECOND, Lang.bind(this, this._tick));
 | 
			
		||||
        GLib.Source.set_name_by_id(this._timeoutId, '[gnome-shell] this._tick');
 | 
			
		||||
@@ -217,7 +213,8 @@ const WorkspaceTracker = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _getWorkspaceSettings: function() {
 | 
			
		||||
        let settings = global.get_overrides_settings();
 | 
			
		||||
        if (settings.list_keys().indexOf('dynamic-workspaces') > -1)
 | 
			
		||||
        if (settings &&
 | 
			
		||||
            settings.settings_schema.list_keys().indexOf('dynamic-workspaces') > -1)
 | 
			
		||||
            return settings;
 | 
			
		||||
        return new Gio.Settings({ schema_id: 'org.gnome.mutter' });
 | 
			
		||||
    },
 | 
			
		||||
@@ -478,52 +475,100 @@ const TilePreview = new Lang.Class({
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const TouchpadWorkspaceSwitchAction = new Lang.Class({
 | 
			
		||||
    Name: 'TouchpadWorkspaceSwitchAction',
 | 
			
		||||
 | 
			
		||||
    _init: function(actor) {
 | 
			
		||||
        this._dx = 0;
 | 
			
		||||
        this._dy = 0;
 | 
			
		||||
        actor.connect('captured-event', Lang.bind(this, this._handleEvent));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _checkActivated: function() {
 | 
			
		||||
        const MOTION_THRESHOLD = 50;
 | 
			
		||||
        let allowedModes = Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW;
 | 
			
		||||
        let dir;
 | 
			
		||||
 | 
			
		||||
        if ((allowedModes & Main.actionMode) == 0)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (this._dy < -MOTION_THRESHOLD)
 | 
			
		||||
            dir = Meta.MotionDirection.DOWN;
 | 
			
		||||
        else if (this._dy > MOTION_THRESHOLD)
 | 
			
		||||
            dir = Meta.MotionDirection.UP;
 | 
			
		||||
        else if (this._dx < -MOTION_THRESHOLD)
 | 
			
		||||
            dir = Meta.MotionDirection.RIGHT;
 | 
			
		||||
        else if (this._dx > MOTION_THRESHOLD)
 | 
			
		||||
            dir = Meta.MotionDirection.LEFT;
 | 
			
		||||
        else
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.emit('activated', dir);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _handleEvent: function(actor, event) {
 | 
			
		||||
        if (event.type() != Clutter.EventType.TOUCHPAD_SWIPE)
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
        if (event.get_gesture_swipe_finger_count() != 4)
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
        if (event.get_gesture_phase() == Clutter.TouchpadGesturePhase.UPDATE) {
 | 
			
		||||
            let [dx, dy] = event.get_gesture_motion_delta(event);
 | 
			
		||||
 | 
			
		||||
            this._dx += dx;
 | 
			
		||||
            this._dy += dy;
 | 
			
		||||
        } else {
 | 
			
		||||
            if (event.get_gesture_phase() == Clutter.TouchpadGesturePhase.END)
 | 
			
		||||
                this._checkActivated();
 | 
			
		||||
 | 
			
		||||
            this._dx = 0;
 | 
			
		||||
            this._dy = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return Clutter.EVENT_STOP;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(TouchpadWorkspaceSwitchAction.prototype);
 | 
			
		||||
 | 
			
		||||
const WorkspaceSwitchAction = new Lang.Class({
 | 
			
		||||
    Name: 'WorkspaceSwitchAction',
 | 
			
		||||
    Extends: Clutter.GestureAction,
 | 
			
		||||
    Extends: Clutter.SwipeAction,
 | 
			
		||||
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        const MOTION_THRESHOLD = 50;
 | 
			
		||||
 | 
			
		||||
        this.parent();
 | 
			
		||||
        this.set_n_touch_points(4);
 | 
			
		||||
        this.set_threshold_trigger_distance(MOTION_THRESHOLD, MOTION_THRESHOLD);
 | 
			
		||||
 | 
			
		||||
        global.display.connect('grab-op-begin', Lang.bind(this, function() {
 | 
			
		||||
            this.cancel();
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_gesture_prepare : function(action, actor) {
 | 
			
		||||
    vfunc_gesture_prepare : function(actor) {
 | 
			
		||||
        let allowedModes = Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW;
 | 
			
		||||
        return this.get_n_current_points() == this.get_n_touch_points() &&
 | 
			
		||||
               (allowedModes & Main.actionMode);
 | 
			
		||||
 | 
			
		||||
        if (!this.parent(actor))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        return (allowedModes & Main.actionMode);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_gesture_end : function(action, actor) {
 | 
			
		||||
        const MOTION_THRESHOLD = 50;
 | 
			
		||||
    vfunc_swept : function(actor, direction) {
 | 
			
		||||
        let dir;
 | 
			
		||||
 | 
			
		||||
        // Just check one touchpoint here
 | 
			
		||||
        let [startX, startY] = this.get_press_coords(0);
 | 
			
		||||
        let [x, y] = this.get_motion_coords(0);
 | 
			
		||||
        let offsetX = x - startX;
 | 
			
		||||
        let offsetY = y - startY;
 | 
			
		||||
        let direction;
 | 
			
		||||
        if (direction & Clutter.SwipeDirection.UP)
 | 
			
		||||
            dir = Meta.MotionDirection.DOWN;
 | 
			
		||||
        else if (direction & Clutter.SwipeDirection.DOWN)
 | 
			
		||||
            dir = Meta.MotionDirection.UP;
 | 
			
		||||
        else if (direction & Clutter.SwipeDirection.LEFT)
 | 
			
		||||
            dir = Meta.MotionDirection.RIGHT;
 | 
			
		||||
        else if (direction & Clutter.SwipeDirection.RIGHT)
 | 
			
		||||
            dir = Meta.MotionDirection.LEFT;
 | 
			
		||||
 | 
			
		||||
        if (Math.abs(offsetX) < MOTION_THRESHOLD &&
 | 
			
		||||
            Math.abs(offsetY) < MOTION_THRESHOLD)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (Math.abs(offsetY) > Math.abs(offsetX)) {
 | 
			
		||||
            if (offsetY > 0)
 | 
			
		||||
                direction = Meta.MotionDirection.UP;
 | 
			
		||||
            else
 | 
			
		||||
                direction = Meta.MotionDirection.DOWN;
 | 
			
		||||
        } else {
 | 
			
		||||
            if (offsetX > 0)
 | 
			
		||||
                direction = Meta.MotionDirection.LEFT;
 | 
			
		||||
            else
 | 
			
		||||
                direction = Meta.MotionDirection.RIGHT;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.emit('activated', direction);
 | 
			
		||||
        this.emit('activated', dir);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(WorkspaceSwitchAction.prototype);
 | 
			
		||||
@@ -631,9 +676,8 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._minimizing = [];
 | 
			
		||||
        this._unminimizing = [];
 | 
			
		||||
        this._maximizing = [];
 | 
			
		||||
        this._unmaximizing = [];
 | 
			
		||||
        this._mapping = [];
 | 
			
		||||
        this._resizing = [];
 | 
			
		||||
        this._destroying = [];
 | 
			
		||||
        this._movingWindow = null;
 | 
			
		||||
 | 
			
		||||
@@ -647,10 +691,9 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
        this._shellwm.connect('kill-switch-workspace', Lang.bind(this, this._switchWorkspaceDone));
 | 
			
		||||
        this._shellwm.connect('kill-window-effects', Lang.bind(this, function (shellwm, actor) {
 | 
			
		||||
            this._minimizeWindowDone(shellwm, actor);
 | 
			
		||||
            this._maximizeWindowDone(shellwm, actor);
 | 
			
		||||
            this._unmaximizeWindowDone(shellwm, actor);
 | 
			
		||||
            this._mapWindowDone(shellwm, actor);
 | 
			
		||||
            this._destroyWindowDone(shellwm, actor);
 | 
			
		||||
            this._sizeChangeWindowDone(shellwm, actor);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        this._shellwm.connect('switch-workspace', Lang.bind(this, this._switchWorkspace));
 | 
			
		||||
@@ -659,8 +702,7 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
        this._shellwm.connect('show-window-menu', Lang.bind(this, this._showWindowMenu));
 | 
			
		||||
        this._shellwm.connect('minimize', Lang.bind(this, this._minimizeWindow));
 | 
			
		||||
        this._shellwm.connect('unminimize', Lang.bind(this, this._unminimizeWindow));
 | 
			
		||||
        this._shellwm.connect('maximize', Lang.bind(this, this._maximizeWindow));
 | 
			
		||||
        this._shellwm.connect('unmaximize', Lang.bind(this, this._unmaximizeWindow));
 | 
			
		||||
        this._shellwm.connect('size-change', Lang.bind(this, this._sizeChangeWindow));
 | 
			
		||||
        this._shellwm.connect('map', Lang.bind(this, this._mapWindow));
 | 
			
		||||
        this._shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
 | 
			
		||||
        this._shellwm.connect('filter-keybinding', Lang.bind(this, this._filterKeybinding));
 | 
			
		||||
@@ -824,6 +866,18 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
        this.setCustomKeybindingHandler('switch-windows-backward',
 | 
			
		||||
                                        Shell.ActionMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._startWindowSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('cycle-windows',
 | 
			
		||||
                                        Shell.ActionMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._startWindowCycler));
 | 
			
		||||
        this.setCustomKeybindingHandler('cycle-windows-backward',
 | 
			
		||||
                                        Shell.ActionMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._startWindowCycler));
 | 
			
		||||
        this.setCustomKeybindingHandler('cycle-group',
 | 
			
		||||
                                        Shell.ActionMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._startGroupCycler));
 | 
			
		||||
        this.setCustomKeybindingHandler('cycle-group-backward',
 | 
			
		||||
                                        Shell.ActionMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._startGroupCycler));
 | 
			
		||||
        this.setCustomKeybindingHandler('switch-panels',
 | 
			
		||||
                                        Shell.ActionMode.NORMAL |
 | 
			
		||||
                                        Shell.ActionMode.OVERVIEW |
 | 
			
		||||
@@ -880,15 +934,22 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
                                                false, -1, 1);
 | 
			
		||||
 | 
			
		||||
        let gesture = new WorkspaceSwitchAction();
 | 
			
		||||
        gesture.connect('activated', Lang.bind(this, function(action, direction) {
 | 
			
		||||
            let newWs = global.screen.get_active_workspace().get_neighbor(direction);
 | 
			
		||||
            this.actionMoveWorkspace(newWs);
 | 
			
		||||
        }));
 | 
			
		||||
        gesture.connect('activated', Lang.bind(this, this._actionSwitchWorkspace));
 | 
			
		||||
        global.stage.add_action(gesture);
 | 
			
		||||
 | 
			
		||||
        // This is not a normal Clutter.GestureAction, doesn't need add_action()
 | 
			
		||||
        gesture = new TouchpadWorkspaceSwitchAction(global.stage);
 | 
			
		||||
        gesture.connect('activated', Lang.bind(this, this._actionSwitchWorkspace));
 | 
			
		||||
 | 
			
		||||
        gesture = new AppSwitchAction();
 | 
			
		||||
        gesture.connect('activated', Lang.bind(this, this._switchApp));
 | 
			
		||||
        global.stage.add_action(gesture);
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _actionSwitchWorkspace: function(action, direction) {
 | 
			
		||||
            let newWs = global.screen.get_active_workspace().get_neighbor(direction);
 | 
			
		||||
            this.actionMoveWorkspace(newWs);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _lookupIndex: function (windows, metaWindow) {
 | 
			
		||||
@@ -1170,22 +1231,119 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _sizeChangeWindow : function(shellwm, actor, whichChange, oldFrameRect, oldBufferRect) {
 | 
			
		||||
        let types = [Meta.WindowType.NORMAL];
 | 
			
		||||
        if (!this._shouldAnimateActor(actor, types)) {
 | 
			
		||||
            shellwm.completed_size_change(actor);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    _maximizeWindow : function(shellwm, actor, targetX, targetY, targetWidth, targetHeight) {
 | 
			
		||||
        shellwm.completed_maximize(actor);
 | 
			
		||||
        if (whichChange == Meta.SizeChange.FULLSCREEN)
 | 
			
		||||
            this._fullscreenWindow(shellwm, actor, oldFrameRect, oldBufferRect);
 | 
			
		||||
        else if (whichChange == Meta.SizeChange.UNFULLSCREEN)
 | 
			
		||||
            this._unfullscreenWindow(shellwm, actor, oldFrameRect, oldBufferRect);
 | 
			
		||||
        else
 | 
			
		||||
            shellwm.completed_size_change(actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _maximizeWindowDone : function(shellwm, actor) {
 | 
			
		||||
    _fullscreenWindow: function(shellwm, actor, oldFrameRect, oldBufferRect) {
 | 
			
		||||
        let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
 | 
			
		||||
        actor.translation_x = oldFrameRect.x - monitor.x;
 | 
			
		||||
        actor.translation_y = oldFrameRect.y - monitor.y;
 | 
			
		||||
        this._fullscreenAnimation(shellwm, actor, oldFrameRect);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _maximizeWindowOverwrite : function(shellwm, actor) {
 | 
			
		||||
    _unfullscreenWindow: function(shellwm, actor, oldFrameRect, oldBufferRect) {
 | 
			
		||||
        let targetRect = actor.meta_window.get_frame_rect();
 | 
			
		||||
        let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
 | 
			
		||||
        actor.translation_x = -(targetRect.x - monitor.x);
 | 
			
		||||
        actor.translation_y = -(targetRect.y - monitor.y);
 | 
			
		||||
        this._fullscreenAnimation(shellwm, actor, oldFrameRect);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _unmaximizeWindow : function(shellwm, actor, targetX, targetY, targetWidth, targetHeight) {
 | 
			
		||||
        shellwm.completed_unmaximize(actor);
 | 
			
		||||
    _fullscreenAnimation: function(shellwm, actor, oldFrameRect) {
 | 
			
		||||
        this._resizing.push(actor);
 | 
			
		||||
 | 
			
		||||
        // Position a clone of the window on top of the old position,
 | 
			
		||||
        // while actor updates are frozen.
 | 
			
		||||
        // Note that the MetaWindow has up to date sizing information for
 | 
			
		||||
        // the new geometry already.
 | 
			
		||||
        let targetRect = actor.meta_window.get_frame_rect();
 | 
			
		||||
        let actorContent = Shell.util_get_content_for_window_actor(actor, oldFrameRect);
 | 
			
		||||
        let actorClone = new St.Widget({ content: actorContent });
 | 
			
		||||
        actorClone.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
 | 
			
		||||
        actorClone.set_position(oldFrameRect.x, oldFrameRect.y);
 | 
			
		||||
        actorClone.set_size(oldFrameRect.width, oldFrameRect.height);
 | 
			
		||||
        Main.uiGroup.add_actor(actorClone);
 | 
			
		||||
 | 
			
		||||
        actor.__fullscreenClone = actorClone;
 | 
			
		||||
 | 
			
		||||
        let scaleX = targetRect.width / oldFrameRect.width;
 | 
			
		||||
        let scaleY = targetRect.height / oldFrameRect.height;
 | 
			
		||||
 | 
			
		||||
        // Now scale and fade out the clone
 | 
			
		||||
        Tweener.addTween(actorClone,
 | 
			
		||||
                         { x: targetRect.x,
 | 
			
		||||
                           y: targetRect.y,
 | 
			
		||||
                           scale_x: scaleX,
 | 
			
		||||
                           scale_y: scaleY,
 | 
			
		||||
                           opacity: 0,
 | 
			
		||||
                           time: WINDOW_ANIMATION_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad'
 | 
			
		||||
                         });
 | 
			
		||||
 | 
			
		||||
        // Now set scale the actor to size it as the clone.
 | 
			
		||||
        // Note that the caller of this function already set a translation
 | 
			
		||||
        // on the actor.
 | 
			
		||||
        actor.scale_x = 1 / scaleX;
 | 
			
		||||
        actor.scale_y = 1 / scaleY;
 | 
			
		||||
 | 
			
		||||
        // Scale it to its actual new size
 | 
			
		||||
        Tweener.addTween(actor,
 | 
			
		||||
                         { scale_x: 1.0,
 | 
			
		||||
                           scale_y: 1.0,
 | 
			
		||||
                           translation_x: 0,
 | 
			
		||||
                           translation_y: 0,
 | 
			
		||||
                           time: WINDOW_ANIMATION_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: this._sizeChangeWindowDone,
 | 
			
		||||
                           onCompleteScope: this,
 | 
			
		||||
                           onCompleteParams: [shellwm, actor],
 | 
			
		||||
                           onOverwrite: this._sizeChangeWindowOverwritten,
 | 
			
		||||
                           onOverwriteScope: this,
 | 
			
		||||
                           onOverwriteParams: [shellwm, actor]
 | 
			
		||||
                         });
 | 
			
		||||
 | 
			
		||||
        // Now unfreeze actor updates, to get it to the new size.
 | 
			
		||||
        // It's important that we don't wait until the animation is completed to
 | 
			
		||||
        // do this, otherwise our scale will be applied to the old texture size.
 | 
			
		||||
        shellwm.completed_size_change(actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _unmaximizeWindowDone : function(shellwm, actor) {
 | 
			
		||||
    _sizeChangeWindowDone: function(shellwm, actor) {
 | 
			
		||||
        if (this._removeEffect(this._resizing, actor)) {
 | 
			
		||||
            Tweener.removeTweens(actor);
 | 
			
		||||
            actor.scale_x = 1.0;
 | 
			
		||||
            actor.scale_y = 1.0;
 | 
			
		||||
            actor.translation_x = 0;
 | 
			
		||||
            actor.translation_y = 0;
 | 
			
		||||
 | 
			
		||||
            let actorClone = actor.__fullscreenClone;
 | 
			
		||||
            if (actorClone) {
 | 
			
		||||
                actorClone.destroy();
 | 
			
		||||
                delete actor.__fullscreenClone;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _sizeChangeWindowOverwritten: function(shellwm, actor) {
 | 
			
		||||
        if (this._removeEffect(this._resizing, actor)) {
 | 
			
		||||
            let actorClone = actor.__fullscreenClone;
 | 
			
		||||
            if (actorClone) {
 | 
			
		||||
                actorClone.destroy();
 | 
			
		||||
                delete actor.__fullscreenClone;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _hasAttachedDialogs: function(window, ignoreWindow) {
 | 
			
		||||
@@ -1221,11 +1379,14 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
        let dimmer = getWindowDimmer(actor);
 | 
			
		||||
        if (!dimmer)
 | 
			
		||||
            return;
 | 
			
		||||
        Tweener.addTween(dimmer,
 | 
			
		||||
                         { dimFactor: 1.0,
 | 
			
		||||
                           time: DIM_TIME,
 | 
			
		||||
                           transition: 'linear'
 | 
			
		||||
                         });
 | 
			
		||||
        if (this._shouldAnimate())
 | 
			
		||||
            Tweener.addTween(dimmer,
 | 
			
		||||
                             { dimFactor: 1.0,
 | 
			
		||||
                               time: DIM_TIME,
 | 
			
		||||
                               transition: 'linear'
 | 
			
		||||
                             });
 | 
			
		||||
        else
 | 
			
		||||
            dimmer.dimFactor = 1.0;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _undimWindow: function(window) {
 | 
			
		||||
@@ -1235,10 +1396,13 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
        let dimmer = getWindowDimmer(actor);
 | 
			
		||||
        if (!dimmer)
 | 
			
		||||
            return;
 | 
			
		||||
        Tweener.addTween(dimmer,
 | 
			
		||||
                         { dimFactor: 0.0,
 | 
			
		||||
                           time: UNDIM_TIME,
 | 
			
		||||
                           transition: 'linear' });
 | 
			
		||||
        if (this._shouldAnimate())
 | 
			
		||||
            Tweener.addTween(dimmer,
 | 
			
		||||
                             { dimFactor: 0.0,
 | 
			
		||||
                               time: UNDIM_TIME,
 | 
			
		||||
                               transition: 'linear' });
 | 
			
		||||
        else
 | 
			
		||||
            dimmer.dimFactor = 0.0;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _mapWindow : function(shellwm, actor) {
 | 
			
		||||
@@ -1257,6 +1421,9 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
            actor._windowType = type;
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        if (actor.meta_window.is_attached_dialog())
 | 
			
		||||
            this._checkDimming(actor.get_meta_window().get_transient_for());
 | 
			
		||||
 | 
			
		||||
        let types = [Meta.WindowType.NORMAL,
 | 
			
		||||
                     Meta.WindowType.DIALOG,
 | 
			
		||||
                     Meta.WindowType.MODAL_DIALOG];
 | 
			
		||||
@@ -1265,9 +1432,6 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (actor.meta_window.is_attached_dialog())
 | 
			
		||||
            this._checkDimming(actor.get_meta_window().get_transient_for());
 | 
			
		||||
 | 
			
		||||
        switch (actor._windowType) {
 | 
			
		||||
        case Meta.WindowType.NORMAL:
 | 
			
		||||
            actor.set_pivot_point(0.5, 1.0);
 | 
			
		||||
@@ -1350,6 +1514,9 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
                                                             });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (window.is_attached_dialog())
 | 
			
		||||
            this._checkDimming(window.get_transient_for(), window);
 | 
			
		||||
 | 
			
		||||
        let types = [Meta.WindowType.NORMAL,
 | 
			
		||||
                     Meta.WindowType.DIALOG,
 | 
			
		||||
                     Meta.WindowType.MODAL_DIALOG];
 | 
			
		||||
@@ -1384,7 +1551,6 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
            if (window.is_attached_dialog()) {
 | 
			
		||||
                let parent = window.get_transient_for();
 | 
			
		||||
                this._checkDimming(parent, window);
 | 
			
		||||
                actor._parentDestroyId = parent.connect('unmanaged', Lang.bind(this, function () {
 | 
			
		||||
                    Tweener.removeTweens(actor);
 | 
			
		||||
                    this._destroyWindowDone(shellwm, actor);
 | 
			
		||||
@@ -1612,6 +1778,28 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
            tabPopup.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _startWindowCycler : function(display, screen, window, binding) {
 | 
			
		||||
        /* prevent a corner case where both popups show up at once */
 | 
			
		||||
        if (this._workspaceSwitcherPopup != null)
 | 
			
		||||
            this._workspaceSwitcherPopup.destroy();
 | 
			
		||||
 | 
			
		||||
        let tabPopup = new AltTab.WindowCyclerPopup();
 | 
			
		||||
 | 
			
		||||
        if (!tabPopup.show(binding.is_reversed(), binding.get_name(), binding.get_mask()))
 | 
			
		||||
            tabPopup.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _startGroupCycler : function(display, screen, window, binding) {
 | 
			
		||||
        /* prevent a corner case where both popups show up at once */
 | 
			
		||||
        if (this._workspaceSwitcherPopup != null)
 | 
			
		||||
            this._workspaceSwitcherPopup.destroy();
 | 
			
		||||
 | 
			
		||||
        let tabPopup = new AltTab.GroupCyclerPopup();
 | 
			
		||||
 | 
			
		||||
        if (!tabPopup.show(binding.is_reversed(), binding.get_name(), binding.get_mask()))
 | 
			
		||||
            tabPopup.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _startA11ySwitcher : function(display, screen, window, binding) {
 | 
			
		||||
        Main.ctrlAltTabManager.popup(binding.is_reversed(), binding.get_name(), binding.get_mask());
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -74,7 +74,7 @@ const WindowMenu = new Lang.Class({
 | 
			
		||||
                window.make_above();
 | 
			
		||||
        }));
 | 
			
		||||
        if (window.is_above())
 | 
			
		||||
            item.setOrnament(PopupMenu.Ornament.DOT);
 | 
			
		||||
            item.setOrnament(PopupMenu.Ornament.CHECK);
 | 
			
		||||
        if (window.get_maximized() == Meta.MaximizeFlags.BOTH ||
 | 
			
		||||
            type == Meta.WindowType.DOCK ||
 | 
			
		||||
            type == Meta.WindowType.DESKTOP ||
 | 
			
		||||
@@ -93,7 +93,7 @@ const WindowMenu = new Lang.Class({
 | 
			
		||||
                    window.stick();
 | 
			
		||||
            }));
 | 
			
		||||
            if (isSticky)
 | 
			
		||||
                item.setOrnament(PopupMenu.Ornament.DOT);
 | 
			
		||||
                item.setOrnament(PopupMenu.Ornament.CHECK);
 | 
			
		||||
            if (window.is_always_on_all_workspaces())
 | 
			
		||||
                item.setSensitive(false);
 | 
			
		||||
 | 
			
		||||
@@ -101,13 +101,22 @@ const WindowMenu = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
            if (!isSticky) {
 | 
			
		||||
                let workspace = window.get_workspace();
 | 
			
		||||
                let idx = workspace.index();
 | 
			
		||||
                if (idx > 0) {
 | 
			
		||||
                if (workspace != workspace.get_neighbor(Meta.MotionDirection.LEFT)) {
 | 
			
		||||
                     this.addAction(_("Move to Workspace Left"), Lang.bind(this, function(event) {
 | 
			
		||||
                        window.change_workspace(workspace.get_neighbor(Meta.MotionDirection.LEFT));
 | 
			
		||||
                    }));
 | 
			
		||||
                }
 | 
			
		||||
                if (workspace != workspace.get_neighbor(Meta.MotionDirection.RIGHT)) {
 | 
			
		||||
                     this.addAction(_("Move to Workspace Right"), Lang.bind(this, function(event) {
 | 
			
		||||
                        window.change_workspace(workspace.get_neighbor(Meta.MotionDirection.RIGHT));
 | 
			
		||||
                    }));
 | 
			
		||||
                }
 | 
			
		||||
                if (workspace != workspace.get_neighbor(Meta.MotionDirection.UP)) {
 | 
			
		||||
                    this.addAction(_("Move to Workspace Up"), Lang.bind(this, function(event) {
 | 
			
		||||
                        window.change_workspace(workspace.get_neighbor(Meta.MotionDirection.UP));
 | 
			
		||||
                    }));
 | 
			
		||||
                }
 | 
			
		||||
                if (idx < nWorkspaces) {
 | 
			
		||||
                if (workspace != workspace.get_neighbor(Meta.MotionDirection.DOWN)) {
 | 
			
		||||
                     this.addAction(_("Move to Workspace Down"), Lang.bind(this, function(event) {
 | 
			
		||||
                        window.change_workspace(workspace.get_neighbor(Meta.MotionDirection.DOWN));
 | 
			
		||||
                    }));
 | 
			
		||||
@@ -115,6 +124,39 @@ const WindowMenu = new Lang.Class({
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let screen = global.screen;
 | 
			
		||||
        let nMonitors = screen.get_n_monitors();
 | 
			
		||||
        if (nMonitors > 1) {
 | 
			
		||||
          this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
 | 
			
		||||
 | 
			
		||||
          let monitorIndex = window.get_monitor();
 | 
			
		||||
 | 
			
		||||
          let upMonitorIndex = screen.get_monitor_neighbor_index(monitorIndex, Meta.ScreenDirection.UP);
 | 
			
		||||
          if (upMonitorIndex != -1) {
 | 
			
		||||
            this.addAction(_("Move to Monitor Up"), Lang.bind(this, function(event) {
 | 
			
		||||
              window.move_to_monitor(upMonitorIndex);
 | 
			
		||||
            }));
 | 
			
		||||
          }
 | 
			
		||||
          let downMonitorIndex = screen.get_monitor_neighbor_index(monitorIndex, Meta.ScreenDirection.DOWN);
 | 
			
		||||
          if (downMonitorIndex != -1) {
 | 
			
		||||
            this.addAction(_("Move to Monitor Down"), Lang.bind(this, function(event) {
 | 
			
		||||
              window.move_to_monitor(downMonitorIndex);
 | 
			
		||||
            }));
 | 
			
		||||
          }
 | 
			
		||||
          let leftMonitorIndex = screen.get_monitor_neighbor_index(monitorIndex, Meta.ScreenDirection.LEFT);
 | 
			
		||||
          if (leftMonitorIndex != -1) {
 | 
			
		||||
            this.addAction(_("Move to Monitor Left"), Lang.bind(this, function(event) {
 | 
			
		||||
              window.move_to_monitor(leftMonitorIndex);
 | 
			
		||||
            }));
 | 
			
		||||
          }
 | 
			
		||||
          let rightMonitorIndex = screen.get_monitor_neighbor_index(monitorIndex, Meta.ScreenDirection.RIGHT);
 | 
			
		||||
          if (rightMonitorIndex != -1) {
 | 
			
		||||
            this.addAction(_("Move to Monitor Right"), Lang.bind(this, function(event) {
 | 
			
		||||
              window.move_to_monitor(rightMonitorIndex);
 | 
			
		||||
            }));
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
 | 
			
		||||
 | 
			
		||||
        item = this.addAction(_("Close"), Lang.bind(this, function(event) {
 | 
			
		||||
@@ -167,8 +209,12 @@ const WindowMenuManager = new Lang.Class({
 | 
			
		||||
        menu.connect('activate', function() {
 | 
			
		||||
            window.check_alive(global.get_current_time());
 | 
			
		||||
        });
 | 
			
		||||
        let destroyId = window.connect('unmanaged',
 | 
			
		||||
            function() {
 | 
			
		||||
                menu.close();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        this._sourceActor.set_size(rect.width, rect.height);
 | 
			
		||||
        this._sourceActor.set_size(Math.max(1, rect.width), Math.max(1, rect.height));
 | 
			
		||||
        this._sourceActor.set_position(rect.x, rect.y);
 | 
			
		||||
        this._sourceActor.show();
 | 
			
		||||
 | 
			
		||||
@@ -180,6 +226,7 @@ const WindowMenuManager = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
            this._sourceActor.hide();
 | 
			
		||||
            menu.destroy();
 | 
			
		||||
            window.disconnect(destroyId);
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -361,6 +361,9 @@ const WindowClone = new Lang.Class({
 | 
			
		||||
        // a long-press canceled when the pointer movement
 | 
			
		||||
        // exceeds dnd-drag-threshold to manually start the drag
 | 
			
		||||
        if (state == Clutter.LongPressState.CANCEL) {
 | 
			
		||||
            let event = Clutter.get_current_event();
 | 
			
		||||
            this._dragTouchSequence = event.get_event_sequence();
 | 
			
		||||
 | 
			
		||||
            // 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,
 | 
			
		||||
@@ -369,7 +372,7 @@ const WindowClone = new Lang.Class({
 | 
			
		||||
                        return;
 | 
			
		||||
                    let [x, y] = action.get_coords();
 | 
			
		||||
                    action.release();
 | 
			
		||||
                    this._draggable.startDrag(x, y, global.get_current_time());
 | 
			
		||||
                    this._draggable.startDrag(x, y, global.get_current_time(), this._dragTouchSequence);
 | 
			
		||||
                }));
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
 
 | 
			
		||||
@@ -45,11 +45,11 @@ const PrimaryActorLayout = new Lang.Class({
 | 
			
		||||
        this.primaryActor = primaryActor;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_width: function(forHeight) {
 | 
			
		||||
    vfunc_get_preferred_width: function(container, forHeight) {
 | 
			
		||||
        return this.primaryActor.get_preferred_width(forHeight);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_height: function(forWidth) {
 | 
			
		||||
    vfunc_get_preferred_height: function(container, forWidth) {
 | 
			
		||||
        return this.primaryActor.get_preferred_height(forWidth);
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
@@ -80,6 +80,8 @@ const WindowClone = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('button-release-event',
 | 
			
		||||
                           Lang.bind(this, this._onButtonRelease));
 | 
			
		||||
        this.actor.connect('touch-event',
 | 
			
		||||
                           Lang.bind(this, this._onTouchEvent));
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 | 
			
		||||
 | 
			
		||||
@@ -200,6 +202,15 @@ const WindowClone = new Lang.Class({
 | 
			
		||||
        return Clutter.EVENT_STOP;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onTouchEvent : function (actor, event) {
 | 
			
		||||
        if (event.type() != Clutter.EventType.TOUCH_END ||
 | 
			
		||||
            !global.display.is_pointer_emulating_sequence(event.get_event_sequence()))
 | 
			
		||||
            return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
 | 
			
		||||
        this.emit('selected', event.get_time());
 | 
			
		||||
        return Clutter.EVENT_STOP;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDragBegin : function (draggable, time) {
 | 
			
		||||
        this.inDrag = true;
 | 
			
		||||
        this.emit('drag-begin');
 | 
			
		||||
@@ -642,6 +653,7 @@ const ThumbnailsBox = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('button-press-event', function() { return Clutter.EVENT_STOP; });
 | 
			
		||||
        this.actor.connect('button-release-event', Lang.bind(this, this._onButtonRelease));
 | 
			
		||||
        this.actor.connect('touch-event', Lang.bind(this, this._onTouchEvent));
 | 
			
		||||
 | 
			
		||||
        Main.overview.connect('showing',
 | 
			
		||||
                              Lang.bind(this, this._createThumbnails));
 | 
			
		||||
@@ -672,18 +684,31 @@ const ThumbnailsBox = new Lang.Class({
 | 
			
		||||
                global.screen.n_workspaces > 1;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onButtonRelease: function(actor, event) {
 | 
			
		||||
        let [stageX, stageY] = event.get_coords();
 | 
			
		||||
    _activateThumbnailAtPoint: function (stageX, stageY, time) {
 | 
			
		||||
        let [r, x, y] = this.actor.transform_stage_point(stageX, stageY);
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._thumbnails.length; i++) {
 | 
			
		||||
            let thumbnail = this._thumbnails[i]
 | 
			
		||||
            let [w, h] = thumbnail.actor.get_transformed_size();
 | 
			
		||||
            if (y >= thumbnail.actor.y && y <= thumbnail.actor.y + h) {
 | 
			
		||||
                thumbnail.activate(event.get_time());
 | 
			
		||||
                thumbnail.activate(time);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onButtonRelease: function(actor, event) {
 | 
			
		||||
        let [stageX, stageY] = event.get_coords();
 | 
			
		||||
        this._activateThumbnailAtPoint(stageX, stageY, event.get_time());
 | 
			
		||||
        return Clutter.EVENT_STOP;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onTouchEvent: function (actor, event) {
 | 
			
		||||
        if (event.type() == Clutter.EventType.TOUCH_END &&
 | 
			
		||||
            global.display.is_pointer_emulating_sequence(event.get_event_sequence())) {
 | 
			
		||||
            let [stageX, stageY] = event.get_coords();
 | 
			
		||||
            this._activateThumbnailAtPoint(stageX, stageY, event.get_time());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return Clutter.EVENT_STOP;
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -421,7 +421,7 @@ const WorkspacesDisplay = new Lang.Class({
 | 
			
		||||
            // Only switch to the workspace when there's no application
 | 
			
		||||
            // windows open. The problem is that it's too easy to miss
 | 
			
		||||
            // an app window and get the wrong one focused.
 | 
			
		||||
            if (action.get_button() == 1 &&
 | 
			
		||||
            if ((action.get_button() == 1 || action.get_button() == 0) &&
 | 
			
		||||
                this._getPrimaryView().getActiveWorkspace().isEmpty())
 | 
			
		||||
                Main.overview.hide();
 | 
			
		||||
        }));
 | 
			
		||||
 
 | 
			
		||||
@@ -140,7 +140,7 @@
 | 
			
		||||
 | 
			
		||||
                <para>
 | 
			
		||||
                        <filename>/usr/share/gnome-session/sessions/gnome.session</filename>,
 | 
			
		||||
                        <filename>/usr/share/applications/gnome-shell.desktop</filename>.</para>
 | 
			
		||||
                        <filename>/usr/share/applications/org.gnome.Shell.desktop</filename>.</para>
 | 
			
		||||
        </refsect1>
 | 
			
		||||
 | 
			
		||||
        <refsect1>
 | 
			
		||||
 
 | 
			
		||||
@@ -24,10 +24,12 @@ fi
 | 
			
		||||
fr
 | 
			
		||||
fur
 | 
			
		||||
ga
 | 
			
		||||
gd
 | 
			
		||||
gl
 | 
			
		||||
gu
 | 
			
		||||
he
 | 
			
		||||
hi
 | 
			
		||||
hr
 | 
			
		||||
hu
 | 
			
		||||
ia
 | 
			
		||||
id
 | 
			
		||||
@@ -50,6 +52,7 @@ nb
 | 
			
		||||
ne
 | 
			
		||||
nl
 | 
			
		||||
nn
 | 
			
		||||
oc
 | 
			
		||||
or
 | 
			
		||||
pa
 | 
			
		||||
pl
 | 
			
		||||
 
 | 
			
		||||
@@ -2,9 +2,8 @@
 | 
			
		||||
# Please keep this file sorted alphabetically.
 | 
			
		||||
[encoding: UTF-8]
 | 
			
		||||
data/50-gnome-shell-system.xml.in
 | 
			
		||||
data/gnome-shell.desktop.in.in
 | 
			
		||||
data/gnome-shell-extension-prefs.desktop.in.in
 | 
			
		||||
data/gnome-shell-wayland.desktop.in.in
 | 
			
		||||
data/org.gnome.Shell.desktop.in.in
 | 
			
		||||
data/org.gnome.shell.gschema.xml.in.in
 | 
			
		||||
data/org.gnome.Shell.PortalHelper.desktop.in
 | 
			
		||||
js/extensionPrefs/main.js
 | 
			
		||||
@@ -15,6 +14,7 @@ js/misc/util.js
 | 
			
		||||
js/portalHelper/main.js
 | 
			
		||||
js/ui/appDisplay.js
 | 
			
		||||
js/ui/appFavorites.js
 | 
			
		||||
js/ui/audioDeviceSelection.js
 | 
			
		||||
js/ui/backgroundMenu.js
 | 
			
		||||
js/ui/calendar.js
 | 
			
		||||
js/ui/components/automountManager.js
 | 
			
		||||
@@ -33,7 +33,9 @@ js/ui/keyboard.js
 | 
			
		||||
js/ui/legacyTray.js
 | 
			
		||||
js/ui/lookingGlass.js
 | 
			
		||||
js/ui/main.js
 | 
			
		||||
js/ui/messageList.js
 | 
			
		||||
js/ui/messageTray.js
 | 
			
		||||
js/ui/mpris.js
 | 
			
		||||
js/ui/notificationDaemon.js
 | 
			
		||||
js/ui/overviewControls.js
 | 
			
		||||
js/ui/overview.js
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										297
									
								
								po/an.po
									
									
									
									
									
								
							
							
						
						@@ -9,24 +9,23 @@ msgstr ""
 | 
			
		||||
"Project-Id-Version: gnome-shell master\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
 | 
			
		||||
"shell&keywords=I18N+L10N&component=general\n"
 | 
			
		||||
"POT-Creation-Date: 2015-03-17 12:39+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2015-03-17 19:50+0100\n"
 | 
			
		||||
"Last-Translator: Daniel Martinez <entaltoaragon@gmail.com>\n"
 | 
			
		||||
"POT-Creation-Date: 2015-07-23 08:08+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2015-04-28 08:40+0200\n"
 | 
			
		||||
"Last-Translator: Daniel <entaltoaragon@gmail.com>\n"
 | 
			
		||||
"Language-Team: Aragonés <softaragones@googlegroups.com>\n"
 | 
			
		||||
"Language: an\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 | 
			
		||||
"X-Generator: Gtranslator 2.91.6\n"
 | 
			
		||||
"X-Generator: Pootle 2.5.1.1\n"
 | 
			
		||||
"X-POOTLE-MTIME: 1430206804.000000\n"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:1
 | 
			
		||||
msgid "System"
 | 
			
		||||
msgstr "Sistema"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:2
 | 
			
		||||
#| msgid "%d new notification"
 | 
			
		||||
#| msgid_plural "%d new notifications"
 | 
			
		||||
msgid "Show the notification list"
 | 
			
		||||
msgstr "Amostrar a lista de notificacions"
 | 
			
		||||
 | 
			
		||||
@@ -136,17 +135,18 @@ msgstr "Indiz de l'anvista seleccionada actual en o selector d'aplicacion."
 | 
			
		||||
msgid "History for command (Alt-F2) dialog"
 | 
			
		||||
msgstr "Historico d'o dialogo de comandos (Alt+F2)"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:12
 | 
			
		||||
#. Translators: looking glass is a debugger and inspector tool, see https://live.gnome.org/GnomeShell/LookingGlass
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
 | 
			
		||||
msgid "History for the looking glass dialog"
 | 
			
		||||
msgstr "Historico d'o dialogo de \"looking glass\""
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
 | 
			
		||||
msgid "Always show the 'Log out' menu item in the user menu."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Amostrar siempre l'elemento de menú \"Trancar sesión\" en o menú de "
 | 
			
		||||
"l'usuario."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
 | 
			
		||||
msgid ""
 | 
			
		||||
"This key overrides the automatic hiding of the 'Log out' menu item in single-"
 | 
			
		||||
"user, single-session situations."
 | 
			
		||||
@@ -154,14 +154,14 @@ msgstr ""
 | 
			
		||||
"Ista clau sobrescribe a ocultación automatica de l'elemento de menú "
 | 
			
		||||
"\"Trancar sesión\" en situacions d'un solo usuario u d'una sola sesión."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
 | 
			
		||||
msgid ""
 | 
			
		||||
"Whether to remember password for mounting encrypted or remote filesystems"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Indica si se debe recordar a clau ta amontar sistemas de fichers remotos u "
 | 
			
		||||
"zifraus"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
 | 
			
		||||
msgid ""
 | 
			
		||||
"The shell will request a password when an encrypted device or a remote "
 | 
			
		||||
"filesystem is mounted. If the password can be saved for future use a "
 | 
			
		||||
@@ -173,81 +173,79 @@ msgstr ""
 | 
			
		||||
"s'amostrará a caixeta \"Remerar clau\". Ista clau estableix a valor "
 | 
			
		||||
"predeterminada d'a caixeta."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
 | 
			
		||||
msgid "Show the week date in the calendar"
 | 
			
		||||
msgstr "Amostrar a calendata d'a semana en o calendario"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
 | 
			
		||||
msgid "If true, display the ISO week date in the calendar."
 | 
			
		||||
msgstr "Si ye cierta, amuestra a calendata de semana ISO en o calandario."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
 | 
			
		||||
msgid "Keybinding to open the application menu"
 | 
			
		||||
msgstr "Asociación de teclas ta ubrir o menú de l'aplicación"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
 | 
			
		||||
msgid "Keybinding to open the application menu."
 | 
			
		||||
msgstr "Asociación de teclas ta ubrir o menú de l'aplicación."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
 | 
			
		||||
msgid "Keybinding to open the \"Show Applications\" view"
 | 
			
		||||
msgstr "Asociación de teclas ta la vista \"Amostrar aplicacions\""
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
 | 
			
		||||
msgid ""
 | 
			
		||||
"Keybinding to open the \"Show Applications\" view of the Activities Overview."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Asociación de teclas ta ubrir la vista \"Amostrar aplicacions\" de la vista "
 | 
			
		||||
"d'actividatz."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
 | 
			
		||||
msgid "Keybinding to open the overview"
 | 
			
		||||
msgstr "Asociación de teclas ta l'anvista cheneral"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
 | 
			
		||||
msgid "Keybinding to open the Activities Overview."
 | 
			
		||||
msgstr "Asociación de teclas ta ubrir l'anvista d'actividatz"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
 | 
			
		||||
#| msgid "Keybinding to toggle the visibility of the message tray"
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
 | 
			
		||||
msgid "Keybinding to toggle the visibility of the notification list"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Asociación de teclas ta cambiar a visibilidat d'a lista de notificacions"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
 | 
			
		||||
#| msgid "Keybinding to toggle the visibility of the message tray."
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
 | 
			
		||||
msgid "Keybinding to toggle the visibility of the notification list."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Asociación de teclas ta cambiar a visibilidat d'a lista de notificacions."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
 | 
			
		||||
msgid "Keybinding to focus the active notification"
 | 
			
		||||
msgstr "Asociación de teclas ta dar o foco a la notificación activa"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
 | 
			
		||||
msgid "Keybinding to focus the active notification."
 | 
			
		||||
msgstr "Asociación de teclas ta dar o foco a la notificación activa."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
 | 
			
		||||
msgid ""
 | 
			
		||||
"Keybinding that pauses and resumes all running tweens, for debugging purposes"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Asociación de teclas que pausan y continan todas as execucions de «tweens», "
 | 
			
		||||
"ta propositos de depuraci'on"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
 | 
			
		||||
msgid "Which keyboard to use"
 | 
			
		||||
msgstr "Que teclau usar"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:32
 | 
			
		||||
msgid "The type of keyboard to use."
 | 
			
		||||
msgstr "O tipo de teclau que usar."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:32
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:33
 | 
			
		||||
msgid "Limit switcher to current workspace."
 | 
			
		||||
msgstr "Selector de limite ta l'aria de treballo actual."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:33
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:34
 | 
			
		||||
msgid ""
 | 
			
		||||
"If true, only applications that have windows on the current workspace are "
 | 
			
		||||
"shown in the switcher. Otherwise, all applications are included."
 | 
			
		||||
@@ -256,21 +254,21 @@ msgstr ""
 | 
			
		||||
"finestras en l'aria de treballo actual. D'atra man, s'incluirán todas as "
 | 
			
		||||
"aplicacions."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:34
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:35
 | 
			
		||||
msgid "The application icon mode."
 | 
			
		||||
msgstr "O modo d'icono de l'aplicación."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:35
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:36
 | 
			
		||||
msgid ""
 | 
			
		||||
"Configures how the windows are shown in the switcher. Valid possibilities "
 | 
			
		||||
"are 'thumbnail-only' (shows a thumbnail of the window), 'app-icon-"
 | 
			
		||||
"only' (shows only the application icon) or 'both'."
 | 
			
		||||
"are 'thumbnail-only' (shows a thumbnail of the window), 'app-icon-only' "
 | 
			
		||||
"(shows only the application icon) or 'both'."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Configura cómo s'amuestran as finestras en o selector. Os valore posibles "
 | 
			
		||||
"son \"thumbnail-only\" (amuestra una miniatura d'a finestra), \"app-icon-only"
 | 
			
		||||
"\" (solament amuestra l'icono de l'aplicación) u \"both\"."
 | 
			
		||||
"son \"thumbnail-only\" (amuestra una miniatura d'a finestra), \"app-icon-"
 | 
			
		||||
"only\" (solament amuestra l'icono de l'aplicación) u \"both\"."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:36
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:37
 | 
			
		||||
msgid ""
 | 
			
		||||
"If true, only windows from the current workspace are shown in the switcher. "
 | 
			
		||||
"Otherwise, all windows are included."
 | 
			
		||||
@@ -278,31 +276,31 @@ msgstr ""
 | 
			
		||||
"Si en ye verdadero, nomás s'amostrarán en o selector finestras de l'aria de "
 | 
			
		||||
"treballo actual. D'atra man, s'incluirán todas as finestras."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:37
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:38
 | 
			
		||||
msgid "Attach modal dialog to the parent window"
 | 
			
		||||
msgstr "Acoplar un dialogo modal a la finestra pai"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:38
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:39
 | 
			
		||||
msgid ""
 | 
			
		||||
"This key overrides the key in org.gnome.mutter when running GNOME Shell."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Ista clau sobrescribe a clau en org.gnome.mutter en executar GNOME Shell."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:39
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:40
 | 
			
		||||
msgid "Enable edge tiling when dropping windows on screen edges"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Activar o mosaico en os bordes en arrocegar finestras a os bordes d'a "
 | 
			
		||||
"finestra"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:40
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:41
 | 
			
		||||
msgid "Workspaces are managed dynamically"
 | 
			
		||||
msgstr "As arias de treballo se chestionan dinámicamente"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:41
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:42
 | 
			
		||||
msgid "Workspaces only on primary monitor"
 | 
			
		||||
msgstr "Arias de treballo solament en a pantalla prencipal"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:42
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:43
 | 
			
		||||
msgid "Delay focus changes in mouse mode until the pointer stops moving"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Retardo en cambiar o foco d'o churi dica que o puntero deixa de mover-se"
 | 
			
		||||
@@ -311,12 +309,12 @@ msgstr ""
 | 
			
		||||
msgid "Network Login"
 | 
			
		||||
msgstr "Encetar sesión en o rete"
 | 
			
		||||
 | 
			
		||||
#: ../js/extensionPrefs/main.js:123
 | 
			
		||||
#: ../js/extensionPrefs/main.js:122
 | 
			
		||||
#, javascript-format
 | 
			
		||||
msgid "There was an error loading the preferences dialog for %s:"
 | 
			
		||||
msgstr "I habió una error en lanzar o diálogo de preferencias ta %s:"
 | 
			
		||||
 | 
			
		||||
#: ../js/extensionPrefs/main.js:155
 | 
			
		||||
#: ../js/extensionPrefs/main.js:154
 | 
			
		||||
msgid "GNOME Shell Extensions"
 | 
			
		||||
msgstr "Extensions de GNOME Shell"
 | 
			
		||||
 | 
			
		||||
@@ -327,39 +325,39 @@ msgstr "Extensions de GNOME Shell"
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "Cancelar"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/authPrompt.js:169 ../js/gdm/authPrompt.js:217
 | 
			
		||||
#: ../js/gdm/authPrompt.js:169 ../js/gdm/authPrompt.js:215
 | 
			
		||||
msgid "Next"
 | 
			
		||||
msgstr "Siguient"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/authPrompt.js:213 ../js/ui/shellMountOperation.js:403
 | 
			
		||||
#: ../js/gdm/authPrompt.js:211 ../js/ui/shellMountOperation.js:403
 | 
			
		||||
#: ../js/ui/unlockDialog.js:59
 | 
			
		||||
msgid "Unlock"
 | 
			
		||||
msgstr "Desbloquiar"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/authPrompt.js:215
 | 
			
		||||
#: ../js/gdm/authPrompt.js:213
 | 
			
		||||
msgctxt "button"
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr "Encetar sesión"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:280
 | 
			
		||||
#: ../js/gdm/loginDialog.js:281
 | 
			
		||||
msgid "Choose Session"
 | 
			
		||||
msgstr "Esleyir a sesión"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:420
 | 
			
		||||
#: ../js/gdm/loginDialog.js:431
 | 
			
		||||
msgid "Not listed?"
 | 
			
		||||
msgstr "No ye en a lista?"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:829
 | 
			
		||||
#: ../js/gdm/loginDialog.js:847
 | 
			
		||||
#, javascript-format
 | 
			
		||||
msgid "(e.g., user or %s)"
 | 
			
		||||
msgstr "(eix., usuario u %s)"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:834 ../js/ui/components/networkAgent.js:271
 | 
			
		||||
#: ../js/gdm/loginDialog.js:852 ../js/ui/components/networkAgent.js:271
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:289
 | 
			
		||||
msgid "Username: "
 | 
			
		||||
msgstr "Nombre d'usuario:"
 | 
			
		||||
msgstr "Nombre d'usuario: "
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:1169
 | 
			
		||||
#: ../js/gdm/loginDialog.js:1180
 | 
			
		||||
msgid "Login Window"
 | 
			
		||||
msgstr "Finestra d'inicio de sesión"
 | 
			
		||||
 | 
			
		||||
@@ -452,31 +450,31 @@ msgstr "%d de %B de %Y, %l∶%M %"
 | 
			
		||||
msgid "Web Authentication Redirect"
 | 
			
		||||
msgstr "Rendrecera ta autentiación web"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:792
 | 
			
		||||
#: ../js/ui/appDisplay.js:789
 | 
			
		||||
msgid "Frequently used applications will appear here"
 | 
			
		||||
msgstr "As aplicaciones usadas freqüentment amaneixerán aquí"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:912
 | 
			
		||||
#: ../js/ui/appDisplay.js:909
 | 
			
		||||
msgid "Frequent"
 | 
			
		||||
msgstr "Freqüent"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:919
 | 
			
		||||
#: ../js/ui/appDisplay.js:916
 | 
			
		||||
msgid "All"
 | 
			
		||||
msgstr "Todas"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:1850
 | 
			
		||||
#: ../js/ui/appDisplay.js:1845
 | 
			
		||||
msgid "New Window"
 | 
			
		||||
msgstr "Finestra nueva"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:1878 ../js/ui/dash.js:291
 | 
			
		||||
#: ../js/ui/appDisplay.js:1873 ../js/ui/dash.js:289
 | 
			
		||||
msgid "Remove from Favorites"
 | 
			
		||||
msgstr "Sacar d'os favoritos"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:1884
 | 
			
		||||
#: ../js/ui/appDisplay.js:1879
 | 
			
		||||
msgid "Add to Favorites"
 | 
			
		||||
msgstr "Anyadir a os favoritos"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:1894
 | 
			
		||||
#: ../js/ui/appDisplay.js:1889
 | 
			
		||||
msgid "Show Details"
 | 
			
		||||
msgstr "Amostrar detalles"
 | 
			
		||||
 | 
			
		||||
@@ -490,15 +488,19 @@ msgstr "S'ha anyadiu %s a os suyos favoritos."
 | 
			
		||||
msgid "%s has been removed from your favorites."
 | 
			
		||||
msgstr "S'ha sacau %s d'os suyos favoritos"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/backgroundMenu.js:19 ../js/ui/panel.js:650
 | 
			
		||||
#: ../js/ui/status/system.js:337
 | 
			
		||||
msgid "Settings"
 | 
			
		||||
msgstr "Configuración"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/backgroundMenu.js:21
 | 
			
		||||
#: ../js/ui/backgroundMenu.js:19
 | 
			
		||||
msgid "Change Background…"
 | 
			
		||||
msgstr "Cambiar o fondo…"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/backgroundMenu.js:21
 | 
			
		||||
msgid "Display Settings"
 | 
			
		||||
msgstr "Preferencias de pantalla"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/backgroundMenu.js:22 ../js/ui/panel.js:650
 | 
			
		||||
#: ../js/ui/status/system.js:357
 | 
			
		||||
msgid "Settings"
 | 
			
		||||
msgstr "Configuración"
 | 
			
		||||
 | 
			
		||||
#. Translators: Enter 0-6 (Sunday-Saturday) for non-work days. Examples: "0" (Sunday) "6" (Saturday) "06" (Sunday and Saturday). */
 | 
			
		||||
#: ../js/ui/calendar.js:53
 | 
			
		||||
msgctxt "calendar-no-work"
 | 
			
		||||
@@ -551,54 +553,53 @@ msgctxt "grid saturday"
 | 
			
		||||
msgid "S"
 | 
			
		||||
msgstr "S"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:563
 | 
			
		||||
#: ../js/ui/calendar.js:564
 | 
			
		||||
msgid "Previous month"
 | 
			
		||||
msgstr "Mes anterior"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:573
 | 
			
		||||
#: ../js/ui/calendar.js:574
 | 
			
		||||
msgid "Next month"
 | 
			
		||||
msgstr "Mes siguient"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:780
 | 
			
		||||
#: ../js/ui/calendar.js:781
 | 
			
		||||
msgid "Week %V"
 | 
			
		||||
msgstr "Semana %V"
 | 
			
		||||
 | 
			
		||||
#. Translators: Shown in calendar event list for all day events
 | 
			
		||||
#. * Keep it short, best if you can use less then 10 characters
 | 
			
		||||
#. */
 | 
			
		||||
#: ../js/ui/calendar.js:1182
 | 
			
		||||
#: ../js/ui/calendar.js:1187
 | 
			
		||||
msgctxt "event list time"
 | 
			
		||||
msgid "All Day"
 | 
			
		||||
msgstr "Tot o diya"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:1288
 | 
			
		||||
#: ../js/ui/calendar.js:1289
 | 
			
		||||
msgid "Clear section"
 | 
			
		||||
msgstr "Limpiar a sección"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:1515
 | 
			
		||||
#: ../js/ui/calendar.js:1516
 | 
			
		||||
msgid "Events"
 | 
			
		||||
msgstr "Eventos"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:1524
 | 
			
		||||
#: ../js/ui/calendar.js:1525
 | 
			
		||||
msgctxt "calendar heading"
 | 
			
		||||
msgid "%A, %B %d"
 | 
			
		||||
msgstr "%A, %d de %B"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:1528
 | 
			
		||||
#: ../js/ui/calendar.js:1529
 | 
			
		||||
msgctxt "calendar heading"
 | 
			
		||||
msgid "%A, %B %d, %Y"
 | 
			
		||||
msgstr "%A, %d de %B de %Y"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:1613
 | 
			
		||||
#: ../js/ui/calendar.js:1614
 | 
			
		||||
msgid "Notifications"
 | 
			
		||||
msgstr "Notificacions"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:1764
 | 
			
		||||
#| msgid "Notifications"
 | 
			
		||||
#: ../js/ui/calendar.js:1765
 | 
			
		||||
msgid "No Notifications"
 | 
			
		||||
msgstr "No i hai notificacions"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:1767
 | 
			
		||||
#: ../js/ui/calendar.js:1768
 | 
			
		||||
msgid "No Events"
 | 
			
		||||
msgstr "No i hai eventos"
 | 
			
		||||
 | 
			
		||||
@@ -634,23 +635,23 @@ msgstr "Connectar"
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:293
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:303
 | 
			
		||||
msgid "Password: "
 | 
			
		||||
msgstr "Clau de paso:"
 | 
			
		||||
msgstr "Clau de paso: "
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:238
 | 
			
		||||
msgid "Key: "
 | 
			
		||||
msgstr "Clau:"
 | 
			
		||||
msgstr "Clau: "
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:277
 | 
			
		||||
msgid "Identity: "
 | 
			
		||||
msgstr "Identidat:"
 | 
			
		||||
msgstr "Identidat: "
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:279
 | 
			
		||||
msgid "Private key password: "
 | 
			
		||||
msgstr "Clau d'a clau privada:"
 | 
			
		||||
msgstr "Clau d'a clau privada: "
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:291
 | 
			
		||||
msgid "Service: "
 | 
			
		||||
msgstr "Servicio:"
 | 
			
		||||
msgstr "Servicio: "
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:320
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:658
 | 
			
		||||
@@ -661,8 +662,8 @@ msgstr "O ret sin cordón requiere autenticación"
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:659
 | 
			
		||||
#, javascript-format
 | 
			
		||||
msgid ""
 | 
			
		||||
"Passwords or encryption keys are required to access the wireless network "
 | 
			
		||||
"“%s”."
 | 
			
		||||
"Passwords or encryption keys are required to access the wireless network “"
 | 
			
		||||
"%s”."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"S'amenesten claus u claus de zifrau ta accedir a o ret inalambrico\"%s\"."
 | 
			
		||||
 | 
			
		||||
@@ -673,7 +674,7 @@ msgstr "Autenticación 802.1X cableada"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:327
 | 
			
		||||
msgid "Network name: "
 | 
			
		||||
msgstr "Nombre d'o ret:"
 | 
			
		||||
msgstr "Nombre d'o ret: "
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:332
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:666
 | 
			
		||||
@@ -733,7 +734,7 @@ msgstr "Prebe atra vegada."
 | 
			
		||||
 | 
			
		||||
#. Translators: this is the other person changing their old IM name to their new
 | 
			
		||||
#. IM name. */
 | 
			
		||||
#: ../js/ui/components/telepathyClient.js:768
 | 
			
		||||
#: ../js/ui/components/telepathyClient.js:757
 | 
			
		||||
#, javascript-format
 | 
			
		||||
msgid "%s is now known as %s"
 | 
			
		||||
msgstr "Agora %s se dice %s"
 | 
			
		||||
@@ -742,11 +743,11 @@ msgstr "Agora %s se dice %s"
 | 
			
		||||
msgid "Windows"
 | 
			
		||||
msgstr "Finestras"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/dash.js:252 ../js/ui/dash.js:293
 | 
			
		||||
#: ../js/ui/dash.js:250 ../js/ui/dash.js:291
 | 
			
		||||
msgid "Show Applications"
 | 
			
		||||
msgstr "Amostrar aplicacions"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/dash.js:453
 | 
			
		||||
#: ../js/ui/dash.js:449
 | 
			
		||||
msgid "Dash"
 | 
			
		||||
msgstr "Tablero"
 | 
			
		||||
 | 
			
		||||
@@ -754,7 +755,6 @@ msgstr "Tablero"
 | 
			
		||||
#. * shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
 | 
			
		||||
#. */
 | 
			
		||||
#: ../js/ui/dateMenu.js:73
 | 
			
		||||
#| msgid "%A %B %e, %Y"
 | 
			
		||||
msgid "%B %e %Y"
 | 
			
		||||
msgstr "%B %e %Y"
 | 
			
		||||
 | 
			
		||||
@@ -763,7 +763,6 @@ msgstr "%B %e %Y"
 | 
			
		||||
#. * date, e.g. "Tuesday February 17 2015".
 | 
			
		||||
#. */
 | 
			
		||||
#: ../js/ui/dateMenu.js:80
 | 
			
		||||
#| msgid "%A %B %e, %Y"
 | 
			
		||||
msgid "%A %B %e %Y"
 | 
			
		||||
msgstr "%A %e de %B de %Y"
 | 
			
		||||
 | 
			
		||||
@@ -772,7 +771,6 @@ msgid "Add world clocks…"
 | 
			
		||||
msgstr "Adhibir reloches d'o mundo…"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/dateMenu.js:161
 | 
			
		||||
#| msgid "Open Clocks"
 | 
			
		||||
msgid "World Clocks"
 | 
			
		||||
msgstr "Reloches d'o mundo"
 | 
			
		||||
 | 
			
		||||
@@ -916,17 +914,16 @@ msgstr "Instalar"
 | 
			
		||||
msgid "Download and install “%s” from extensions.gnome.org?"
 | 
			
		||||
msgstr "Descargar y instalar \"%s\" dende extensions.gnome.org?"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/keyboard.js:714 ../js/ui/status/keyboard.js:580
 | 
			
		||||
#: ../js/ui/keyboard.js:747 ../js/ui/status/keyboard.js:713
 | 
			
		||||
msgid "Keyboard"
 | 
			
		||||
msgstr "Teclau"
 | 
			
		||||
 | 
			
		||||
#. translators: 'Hide' is a verb */
 | 
			
		||||
#: ../js/ui/legacyTray.js:64
 | 
			
		||||
#| msgid "Hide Text"
 | 
			
		||||
#: ../js/ui/legacyTray.js:66
 | 
			
		||||
msgid "Hide tray"
 | 
			
		||||
msgstr "Amagar servilla"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/legacyTray.js:104
 | 
			
		||||
#: ../js/ui/legacyTray.js:107
 | 
			
		||||
msgid "Status Icons"
 | 
			
		||||
msgstr "Iconos d'estau"
 | 
			
		||||
 | 
			
		||||
@@ -982,7 +979,7 @@ msgstr "Veyer fuent"
 | 
			
		||||
msgid "Web Page"
 | 
			
		||||
msgstr "Pachina web"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:2133
 | 
			
		||||
#: ../js/ui/messageTray.js:1486
 | 
			
		||||
msgid "System Information"
 | 
			
		||||
msgstr "Informacion d'o sistema"
 | 
			
		||||
 | 
			
		||||
@@ -1024,7 +1021,7 @@ msgstr "toggle-switch-intl"
 | 
			
		||||
msgid "Enter a Command"
 | 
			
		||||
msgstr "Introducir un comando"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/runDialog.js:110 ../js/ui/windowMenu.js:120
 | 
			
		||||
#: ../js/ui/runDialog.js:110 ../js/ui/windowMenu.js:162
 | 
			
		||||
msgid "Close"
 | 
			
		||||
msgstr "Trancar"
 | 
			
		||||
 | 
			
		||||
@@ -1052,27 +1049,27 @@ msgid_plural "%d new notifications"
 | 
			
		||||
msgstr[0] "%d notificación nueva"
 | 
			
		||||
msgstr[1] "%d notificacions nuevas"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:432 ../js/ui/status/system.js:345
 | 
			
		||||
#: ../js/ui/screenShield.js:432 ../js/ui/status/system.js:365
 | 
			
		||||
msgid "Lock"
 | 
			
		||||
msgstr "Blocar"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:668
 | 
			
		||||
#: ../js/ui/screenShield.js:684
 | 
			
		||||
msgid "GNOME needs to lock the screen"
 | 
			
		||||
msgstr "GNOME ameneste blocar a pantalla"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:795 ../js/ui/screenShield.js:1271
 | 
			
		||||
#: ../js/ui/screenShield.js:805 ../js/ui/screenShield.js:1271
 | 
			
		||||
msgid "Unable to lock"
 | 
			
		||||
msgstr "No se podió blocar"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:796 ../js/ui/screenShield.js:1272
 | 
			
		||||
#: ../js/ui/screenShield.js:806 ../js/ui/screenShield.js:1272
 | 
			
		||||
msgid "Lock was blocked by an application"
 | 
			
		||||
msgstr "Una aplicación impidió o bloqueyo"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/search.js:616
 | 
			
		||||
#: ../js/ui/search.js:617
 | 
			
		||||
msgid "Searching…"
 | 
			
		||||
msgstr "Mirando…"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/search.js:618
 | 
			
		||||
#: ../js/ui/search.js:619
 | 
			
		||||
msgid "No results."
 | 
			
		||||
msgstr "No se troboron resultaus."
 | 
			
		||||
 | 
			
		||||
@@ -1136,11 +1133,11 @@ msgstr "Refuso de teclas"
 | 
			
		||||
msgid "Mouse Keys"
 | 
			
		||||
msgstr "Teclas d'o ratet"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/accessibility.js:144
 | 
			
		||||
#: ../js/ui/status/accessibility.js:167
 | 
			
		||||
msgid "High Contrast"
 | 
			
		||||
msgstr "Contraste alto"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/accessibility.js:193
 | 
			
		||||
#: ../js/ui/status/accessibility.js:202
 | 
			
		||||
msgid "Large Text"
 | 
			
		||||
msgstr "Texto gran"
 | 
			
		||||
 | 
			
		||||
@@ -1174,7 +1171,7 @@ msgstr "No connectau"
 | 
			
		||||
msgid "Brightness"
 | 
			
		||||
msgstr "Brilo"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/keyboard.js:603
 | 
			
		||||
#: ../js/ui/status/keyboard.js:736
 | 
			
		||||
msgid "Show Keyboard Layout"
 | 
			
		||||
msgstr "Amostrar a distribución d'o teclau"
 | 
			
		||||
 | 
			
		||||
@@ -1268,7 +1265,7 @@ msgstr "O modo avión ye enchegau"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:814
 | 
			
		||||
msgid "Wi-Fi is disabled when airplane mode is on."
 | 
			
		||||
msgstr "O Wi-Fi ye desactivau quan o modo avión  ye enchegau."
 | 
			
		||||
msgstr "O Wi-Fi ye desactivau quan o modo avión ye enchegau."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:815
 | 
			
		||||
msgid "Turn Off Airplane Mode"
 | 
			
		||||
@@ -1385,23 +1382,23 @@ msgstr "Modo avión"
 | 
			
		||||
msgid "On"
 | 
			
		||||
msgstr "Enchegau"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/system.js:317
 | 
			
		||||
#: ../js/ui/status/system.js:337
 | 
			
		||||
msgid "Switch User"
 | 
			
		||||
msgstr "Cambear d'usuario"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/system.js:322
 | 
			
		||||
#: ../js/ui/status/system.js:342
 | 
			
		||||
msgid "Log Out"
 | 
			
		||||
msgstr "Trancar sesion"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/system.js:341
 | 
			
		||||
#: ../js/ui/status/system.js:361
 | 
			
		||||
msgid "Orientation Lock"
 | 
			
		||||
msgstr "Bloqueyo d'Orientación"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/system.js:349
 | 
			
		||||
#: ../js/ui/status/system.js:369
 | 
			
		||||
msgid "Suspend"
 | 
			
		||||
msgstr "Suspender"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/system.js:352
 | 
			
		||||
#: ../js/ui/status/system.js:372
 | 
			
		||||
msgid "Power Off"
 | 
			
		||||
msgstr "Amortar"
 | 
			
		||||
 | 
			
		||||
@@ -1433,27 +1430,27 @@ msgstr "Aplicacions"
 | 
			
		||||
msgid "Search"
 | 
			
		||||
msgstr "Mirar"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/windowAttentionHandler.js:19
 | 
			
		||||
#: ../js/ui/windowAttentionHandler.js:20
 | 
			
		||||
#, javascript-format
 | 
			
		||||
msgid "“%s” is ready"
 | 
			
		||||
msgstr "\"%s\" ye parau"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/windowManager.js:65
 | 
			
		||||
#: ../js/ui/windowManager.js:63
 | 
			
		||||
msgid "Do you want to keep these display settings?"
 | 
			
		||||
msgstr "Quiers mantener istas opcions de pantalla?"
 | 
			
		||||
 | 
			
		||||
#. Translators: this and the following message should be limited in lenght,
 | 
			
		||||
#. to avoid ellipsizing the labels.
 | 
			
		||||
#. */
 | 
			
		||||
#: ../js/ui/windowManager.js:84
 | 
			
		||||
#: ../js/ui/windowManager.js:82
 | 
			
		||||
msgid "Revert Settings"
 | 
			
		||||
msgstr "Revertir as opcions"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/windowManager.js:88
 | 
			
		||||
#: ../js/ui/windowManager.js:86
 | 
			
		||||
msgid "Keep Changes"
 | 
			
		||||
msgstr "Mantener os cambeos"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/windowManager.js:107
 | 
			
		||||
#: ../js/ui/windowManager.js:105
 | 
			
		||||
#, javascript-format
 | 
			
		||||
msgid "Settings changes will revert in %d second"
 | 
			
		||||
msgid_plural "Settings changes will revert in %d seconds"
 | 
			
		||||
@@ -1462,7 +1459,7 @@ msgstr[1] "Os cambeos d'as opcions serán revertius en %d segundos"
 | 
			
		||||
 | 
			
		||||
#. Translators: This represents the size of a window. The first number is
 | 
			
		||||
#. * the width of the window and the second is the height. */
 | 
			
		||||
#: ../js/ui/windowManager.js:599
 | 
			
		||||
#: ../js/ui/windowManager.js:660
 | 
			
		||||
#, javascript-format
 | 
			
		||||
msgid "%d x %d"
 | 
			
		||||
msgstr "%d x %d"
 | 
			
		||||
@@ -1499,14 +1496,48 @@ msgstr "Siempre veyible"
 | 
			
		||||
msgid "Always on Visible Workspace"
 | 
			
		||||
msgstr "Siempre en l'aria de treballo veyible"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/windowMenu.js:106
 | 
			
		||||
#: ../js/ui/windowMenu.js:105
 | 
			
		||||
#, fuzzy
 | 
			
		||||
#| msgid "Move to Workspace Up"
 | 
			
		||||
msgid "Move to Workspace Left"
 | 
			
		||||
msgstr "Mover a l'aria de treballo d'a cucha"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/windowMenu.js:110
 | 
			
		||||
#, fuzzy
 | 
			
		||||
#| msgid "Move to Workspace Up"
 | 
			
		||||
msgid "Move to Workspace Right"
 | 
			
		||||
msgstr "Mover a l'aria de treballo d'a dreita"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/windowMenu.js:115
 | 
			
		||||
msgid "Move to Workspace Up"
 | 
			
		||||
msgstr "Mover ta l'aria de treballo d'alto"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/windowMenu.js:111
 | 
			
		||||
#: ../js/ui/windowMenu.js:120
 | 
			
		||||
msgid "Move to Workspace Down"
 | 
			
		||||
msgstr "Mover ta l'aria de treballo d'abaixo"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/windowMenu.js:136
 | 
			
		||||
#, fuzzy
 | 
			
		||||
#| msgid "Move to Workspace Up"
 | 
			
		||||
msgid "Move to Monitor Up"
 | 
			
		||||
msgstr "Mover a la pantalla d'alto"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/windowMenu.js:142
 | 
			
		||||
#, fuzzy
 | 
			
		||||
#| msgid "Move to Workspace Down"
 | 
			
		||||
msgid "Move to Monitor Down"
 | 
			
		||||
msgstr "Mover a la pantalla d'abaixo"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/windowMenu.js:148
 | 
			
		||||
#, fuzzy
 | 
			
		||||
msgid "Move to Monitor Left"
 | 
			
		||||
msgstr "Mover a la pantalla d'a cucha"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/windowMenu.js:154
 | 
			
		||||
#, fuzzy
 | 
			
		||||
msgid "Move to Monitor Right"
 | 
			
		||||
msgstr "Mover a la pantalla d'a dreita"
 | 
			
		||||
 | 
			
		||||
#: ../src/calendar-server/evolution-calendar.desktop.in.in.h:1
 | 
			
		||||
msgid "Evolution Calendar"
 | 
			
		||||
msgstr "Calandario d'Evolution"
 | 
			
		||||
@@ -1561,11 +1592,11 @@ msgstr "Desconoxiu"
 | 
			
		||||
msgid "Failed to launch “%s”"
 | 
			
		||||
msgstr "Ha fallau en aventar \"%s\""
 | 
			
		||||
 | 
			
		||||
#: ../src/shell-keyring-prompt.c:714
 | 
			
		||||
#: ../src/shell-keyring-prompt.c:742
 | 
			
		||||
msgid "Passwords do not match."
 | 
			
		||||
msgstr "As claus de paso no coinciden."
 | 
			
		||||
 | 
			
		||||
#: ../src/shell-keyring-prompt.c:722
 | 
			
		||||
#: ../src/shell-keyring-prompt.c:750
 | 
			
		||||
msgid "Password cannot be blank"
 | 
			
		||||
msgstr "A clau de paso no puede estar vueda"
 | 
			
		||||
 | 
			
		||||
@@ -1803,14 +1834,6 @@ msgstr "L'usuario refusó o dialogo d'autenticación"
 | 
			
		||||
#~ msgid "The maximum accuracy level of location."
 | 
			
		||||
#~ msgstr "O maximo libel de precisión d'ubicación."
 | 
			
		||||
 | 
			
		||||
#~| msgid ""
 | 
			
		||||
#~| "Configures the maximum level of location accuracy applications are "
 | 
			
		||||
#~| "allowed to see. Valid options are 'off' (disable location tracking), "
 | 
			
		||||
#~| "'country', 'city', 'neighborhood', 'street', and 'exact' (typically "
 | 
			
		||||
#~| "requires GPS receiver). Please keep in mind that this only controls what "
 | 
			
		||||
#~| "Geoclue will allow applications to see and they can find user's location "
 | 
			
		||||
#~| "on their own using network resources (albeit with street-level accuracy "
 | 
			
		||||
#~| "at best)."
 | 
			
		||||
#~ msgid ""
 | 
			
		||||
#~ "Configures the maximum level of location accuracy applications are "
 | 
			
		||||
#~ "allowed to see. Valid options are 'off' (disable location tracking), "
 | 
			
		||||
@@ -1822,8 +1845,8 @@ msgstr "L'usuario refusó o dialogo d'autenticación"
 | 
			
		||||
#~ msgstr ""
 | 
			
		||||
#~ "Configura o ran maximo de precisión d'ubicación que as aplicacions  "
 | 
			
		||||
#~ "pueden veyer. As opcions validas son 'off' (seguimiento d'ubicación "
 | 
			
		||||
#~ "desenchegau), 'country', 'city', 'neighborhood', 'street', and "
 | 
			
		||||
#~ "'exact' (typicament requier GPS "
 | 
			
		||||
#~ "desenchegau), 'country', 'city', 'neighborhood', 'street', and 'exact' "
 | 
			
		||||
#~ "(typicament requier GPS "
 | 
			
		||||
 | 
			
		||||
#~ msgid "Arrangement of buttons on the titlebar"
 | 
			
		||||
#~ msgstr "Orden d'os botons en a barra de titol"
 | 
			
		||||
@@ -1968,7 +1991,6 @@ msgstr "L'usuario refusó o dialogo d'autenticación"
 | 
			
		||||
#~ msgid "Session…"
 | 
			
		||||
#~ msgstr "Sesión…"
 | 
			
		||||
 | 
			
		||||
#~| msgid "Power Off"
 | 
			
		||||
#~ msgid "Power"
 | 
			
		||||
#~ msgstr "Enerchía"
 | 
			
		||||
 | 
			
		||||
@@ -2132,11 +2154,9 @@ msgstr "L'usuario refusó o dialogo d'autenticación"
 | 
			
		||||
#~ msgid "%d%%"
 | 
			
		||||
#~ msgstr "%d%%"
 | 
			
		||||
 | 
			
		||||
#~| msgid "AC adapter"
 | 
			
		||||
#~ msgid "AC Adapter"
 | 
			
		||||
#~ msgstr "Adaptador de corrient"
 | 
			
		||||
 | 
			
		||||
#~| msgid "Laptop battery"
 | 
			
		||||
#~ msgid "Laptop Battery"
 | 
			
		||||
#~ msgstr "Bateria d'o portatil"
 | 
			
		||||
 | 
			
		||||
@@ -2149,11 +2169,9 @@ msgstr "L'usuario refusó o dialogo d'autenticación"
 | 
			
		||||
#~ msgid "PDA"
 | 
			
		||||
#~ msgstr "PDA"
 | 
			
		||||
 | 
			
		||||
#~| msgid "Cell phone"
 | 
			
		||||
#~ msgid "Cell Phone"
 | 
			
		||||
#~ msgstr "Telefono movil"
 | 
			
		||||
 | 
			
		||||
#~| msgid "Media player"
 | 
			
		||||
#~ msgid "Media Player"
 | 
			
		||||
#~ msgstr "Reproductor multimeya"
 | 
			
		||||
 | 
			
		||||
@@ -2163,7 +2181,6 @@ msgstr "L'usuario refusó o dialogo d'autenticación"
 | 
			
		||||
#~ msgid "Computer"
 | 
			
		||||
#~ msgstr "Equipo"
 | 
			
		||||
 | 
			
		||||
#~| msgid "Unknown"
 | 
			
		||||
#~ msgctxt "device"
 | 
			
		||||
#~ msgid "Unknown"
 | 
			
		||||
#~ msgstr "Desconoxiu"
 | 
			
		||||
 
 | 
			
		||||