Compare commits
	
		
			1627 Commits
		
	
	
		
			2.91.90
			...
			wip/menus-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					94d01bed12 | ||
| 
						 | 
					9daf358122 | ||
| 
						 | 
					b4b3f5a669 | ||
| 
						 | 
					5290a9dd08 | ||
| 
						 | 
					ab4a7c5237 | ||
| 
						 | 
					95e5c5cfb1 | ||
| 
						 | 
					757fb5796e | ||
| 
						 | 
					75e9fa9cfb | ||
| 
						 | 
					8997aa45b1 | ||
| 
						 | 
					f884dbbfb2 | ||
| 
						 | 
					d0c36bb732 | ||
| 
						 | 
					17c46c2452 | ||
| 
						 | 
					0996174b3d | ||
| 
						 | 
					d6b6f814d3 | ||
| 
						 | 
					987099ea55 | ||
| 
						 | 
					b356aa8e3b | ||
| 
						 | 
					566bdb50c2 | ||
| 
						 | 
					2b57603271 | ||
| 
						 | 
					c3528f5b6b | ||
| 
						 | 
					4c7cc94cdc | ||
| 
						 | 
					5ff2285707 | ||
| 
						 | 
					d714dfd82e | ||
| 
						 | 
					b1064cbe50 | ||
| 
						 | 
					8d3e5ea507 | ||
| 
						 | 
					001b6afc7e | ||
| 
						 | 
					55d6c5ea8f | ||
| 
						 | 
					fa2ff8158f | ||
| 
						 | 
					97e7ea0b5d | ||
| 
						 | 
					65dec2b72a | ||
| 
						 | 
					5fd3ca8d09 | ||
| 
						 | 
					dc9a8d505d | ||
| 
						 | 
					fc8d13f4bd | ||
| 
						 | 
					d1aa7de5d0 | ||
| 
						 | 
					e279ef1c7c | ||
| 
						 | 
					b88657ab83 | ||
| 
						 | 
					d20e646ed6 | ||
| 
						 | 
					8678b87120 | ||
| 
						 | 
					960571a589 | ||
| 
						 | 
					d856338f86 | ||
| 
						 | 
					2b6b2d93a9 | ||
| 
						 | 
					363bd04166 | ||
| 
						 | 
					9bc1a68fe4 | ||
| 
						 | 
					2c2729f7be | ||
| 
						 | 
					9011959356 | ||
| 
						 | 
					c79b8bbe7e | ||
| 
						 | 
					da59eebf8e | ||
| 
						 | 
					7854024326 | ||
| 
						 | 
					a9ab8784c4 | ||
| 
						 | 
					de5b00fd52 | ||
| 
						 | 
					6547f75b12 | ||
| 
						 | 
					827bf506a7 | ||
| 
						 | 
					adc187c32e | ||
| 
						 | 
					5350302b09 | ||
| 
						 | 
					167ca75388 | ||
| 
						 | 
					46cea67258 | ||
| 
						 | 
					463e0919d4 | ||
| 
						 | 
					98906c1da3 | ||
| 
						 | 
					b71e66c335 | ||
| 
						 | 
					2b6c5bb416 | ||
| 
						 | 
					628e59894b | ||
| 
						 | 
					703d2ead33 | ||
| 
						 | 
					43f53a708f | ||
| 
						 | 
					07e7331e7b | ||
| 
						 | 
					c516af3130 | ||
| 
						 | 
					39727d1156 | ||
| 
						 | 
					85cd189a69 | ||
| 
						 | 
					a8e35422f2 | ||
| 
						 | 
					3941961f8b | ||
| 
						 | 
					d9c6485cbf | ||
| 
						 | 
					c52ccc76a3 | ||
| 
						 | 
					be1c4f26b5 | ||
| 
						 | 
					a6ee6739e0 | ||
| 
						 | 
					54a8ad8bc6 | ||
| 
						 | 
					2541bfcdf2 | ||
| 
						 | 
					d7d5da0301 | ||
| 
						 | 
					d2bd9efc25 | ||
| 
						 | 
					779b18bf48 | ||
| 
						 | 
					618a53b34f | ||
| 
						 | 
					f4eaadb948 | ||
| 
						 | 
					ea061b0f46 | ||
| 
						 | 
					3652e42699 | ||
| 
						 | 
					398489f661 | ||
| 
						 | 
					70fc13500d | ||
| 
						 | 
					18541c447e | ||
| 
						 | 
					3294a6e1a7 | ||
| 
						 | 
					38563c38e8 | ||
| 
						 | 
					a465c5f996 | ||
| 
						 | 
					1760ba1279 | ||
| 
						 | 
					3d3c9546a2 | ||
| 
						 | 
					203c5db5eb | ||
| 
						 | 
					cf44234323 | ||
| 
						 | 
					cc94076ffb | ||
| 
						 | 
					8d137eae5b | ||
| 
						 | 
					51fa9ae513 | ||
| 
						 | 
					9951c92459 | ||
| 
						 | 
					ee77e5d582 | ||
| 
						 | 
					d74721f229 | ||
| 
						 | 
					1aa97b19f7 | ||
| 
						 | 
					95de48e986 | ||
| 
						 | 
					a147d0428d | ||
| 
						 | 
					90b3f7b7f6 | ||
| 
						 | 
					c80acfda08 | ||
| 
						 | 
					8a39145e3c | ||
| 
						 | 
					b62f5ef07d | ||
| 
						 | 
					bd5c6c5cd6 | ||
| 
						 | 
					f874a57439 | ||
| 
						 | 
					6a4525e554 | ||
| 
						 | 
					d553a5bdc0 | ||
| 
						 | 
					80076965a7 | ||
| 
						 | 
					84e8d38d4c | ||
| 
						 | 
					33f3f9d997 | ||
| 
						 | 
					be72b1d066 | ||
| 
						 | 
					dc5d2b83ef | ||
| 
						 | 
					3dabe645c2 | ||
| 
						 | 
					e9ede362dc | ||
| 
						 | 
					01357aca35 | ||
| 
						 | 
					c944dd6768 | ||
| 
						 | 
					ff01ed5e4b | ||
| 
						 | 
					d23c374326 | ||
| 
						 | 
					a69ebc8a68 | ||
| 
						 | 
					f4d8a35b9d | ||
| 
						 | 
					2b140f8fb7 | ||
| 
						 | 
					ab603bdbbf | ||
| 
						 | 
					44e2f7f555 | ||
| 
						 | 
					fd1b3b4fee | ||
| 
						 | 
					4ae2a0b2a5 | ||
| 
						 | 
					0cb415b3bd | ||
| 
						 | 
					c1fa9a82e6 | ||
| 
						 | 
					dde124ab5a | ||
| 
						 | 
					668920cec4 | ||
| 
						 | 
					9b38c5b304 | ||
| 
						 | 
					e63c2da433 | ||
| 
						 | 
					38c768fdb3 | ||
| 
						 | 
					0dd4584157 | ||
| 
						 | 
					b7bf712b97 | ||
| 
						 | 
					615723d8df | ||
| 
						 | 
					de352a309d | ||
| 
						 | 
					c573e7f9a1 | ||
| 
						 | 
					d59fd1a75d | ||
| 
						 | 
					18d69d7032 | ||
| 
						 | 
					5d25716cee | ||
| 
						 | 
					840e79c18c | ||
| 
						 | 
					ddf562e306 | ||
| 
						 | 
					20a6ce7003 | ||
| 
						 | 
					8c43298af0 | ||
| 
						 | 
					4bb48e56d2 | ||
| 
						 | 
					338ba10ca2 | ||
| 
						 | 
					36eb745ecc | ||
| 
						 | 
					b07e45e214 | ||
| 
						 | 
					bba5198e63 | ||
| 
						 | 
					9e2bab008a | ||
| 
						 | 
					5ea032bbf7 | ||
| 
						 | 
					897fadfb40 | ||
| 
						 | 
					b05f71eb9b | ||
| 
						 | 
					4ce0e80956 | ||
| 
						 | 
					577ccc4d56 | ||
| 
						 | 
					39d12351ba | ||
| 
						 | 
					e37bc6d7f0 | ||
| 
						 | 
					9593ff3582 | ||
| 
						 | 
					ad8dfd7b04 | ||
| 
						 | 
					ca5ab20f67 | ||
| 
						 | 
					0eab448221 | ||
| 
						 | 
					a26a77f9db | ||
| 
						 | 
					c3df6bb8bd | ||
| 
						 | 
					ce3a26cf37 | ||
| 
						 | 
					04482c23c4 | ||
| 
						 | 
					ff20fe856e | ||
| 
						 | 
					12e3921f81 | ||
| 
						 | 
					928fbee15b | ||
| 
						 | 
					a103c028f9 | ||
| 
						 | 
					775347d865 | ||
| 
						 | 
					6d0be86a4e | ||
| 
						 | 
					a4b69db8af | ||
| 
						 | 
					790b9d3371 | ||
| 
						 | 
					adef2009a5 | ||
| 
						 | 
					1721db6d8d | ||
| 
						 | 
					6d95e8b988 | ||
| 
						 | 
					b07f9932db | ||
| 
						 | 
					9439da81c4 | ||
| 
						 | 
					6257e64d03 | ||
| 
						 | 
					ba110f2d2e | ||
| 
						 | 
					6bdf621d05 | ||
| 
						 | 
					1c4db98c95 | ||
| 
						 | 
					dadac957e4 | ||
| 
						 | 
					cf3976d496 | ||
| 
						 | 
					82ed80c9c3 | ||
| 
						 | 
					67222525ad | ||
| 
						 | 
					fff0861773 | ||
| 
						 | 
					13ffe41498 | ||
| 
						 | 
					96e0528a7b | ||
| 
						 | 
					3df30fbd57 | ||
| 
						 | 
					b57d8b336b | ||
| 
						 | 
					3169b2c440 | ||
| 
						 | 
					6bc34e0f32 | ||
| 
						 | 
					cecb1a41fb | ||
| 
						 | 
					b9069df85c | ||
| 
						 | 
					aee3c6f041 | ||
| 
						 | 
					c427bba9f1 | ||
| 
						 | 
					da83ad561b | ||
| 
						 | 
					85520e34ab | ||
| 
						 | 
					d0edd970e1 | ||
| 
						 | 
					8529ca70af | ||
| 
						 | 
					1a8d78212f | ||
| 
						 | 
					4270a2806d | ||
| 
						 | 
					4333bdc709 | ||
| 
						 | 
					75b824d032 | ||
| 
						 | 
					7bc2573d85 | ||
| 
						 | 
					67b7b7a950 | ||
| 
						 | 
					786cfbd397 | ||
| 
						 | 
					9df8b583cf | ||
| 
						 | 
					8e32290dc9 | ||
| 
						 | 
					23478f3336 | ||
| 
						 | 
					2e244ecb63 | ||
| 
						 | 
					e307680206 | ||
| 
						 | 
					6bb1a3e2c4 | ||
| 
						 | 
					8a1ac6b13f | ||
| 
						 | 
					61b8af2252 | ||
| 
						 | 
					c99afed012 | ||
| 
						 | 
					2947b92148 | ||
| 
						 | 
					39c5d23a87 | ||
| 
						 | 
					d839670f54 | ||
| 
						 | 
					0d1b7e15d1 | ||
| 
						 | 
					ac678f63ee | ||
| 
						 | 
					d862c0879b | ||
| 
						 | 
					23a4d4c69e | ||
| 
						 | 
					472b20d933 | ||
| 
						 | 
					492dd718fb | ||
| 
						 | 
					0d5618fdd1 | ||
| 
						 | 
					503508af41 | ||
| 
						 | 
					4ec5e55122 | ||
| 
						 | 
					8daca865ca | ||
| 
						 | 
					f9b37a21e8 | ||
| 
						 | 
					c398f319fc | ||
| 
						 | 
					1e049f88b8 | ||
| 
						 | 
					4831d9c3a3 | ||
| 
						 | 
					f13f5bc1bb | ||
| 
						 | 
					4e114107ed | ||
| 
						 | 
					0ccb280008 | ||
| 
						 | 
					28c3e0693e | ||
| 
						 | 
					c321c8a02f | ||
| 
						 | 
					2407ec7b47 | ||
| 
						 | 
					70eeb75716 | ||
| 
						 | 
					751d250471 | ||
| 
						 | 
					c28217db80 | ||
| 
						 | 
					0968e556fa | ||
| 
						 | 
					130f2cf808 | ||
| 
						 | 
					4eec7413c7 | ||
| 
						 | 
					efc3246d26 | ||
| 
						 | 
					9930dbc0ff | ||
| 
						 | 
					754f87dac3 | ||
| 
						 | 
					51139bd096 | ||
| 
						 | 
					6e0119d620 | ||
| 
						 | 
					a3528bf973 | ||
| 
						 | 
					77c36af588 | ||
| 
						 | 
					69c0a52a33 | ||
| 
						 | 
					a7442cd0a5 | ||
| 
						 | 
					d47a013931 | ||
| 
						 | 
					745f9c0e6e | ||
| 
						 | 
					414f49fd80 | ||
| 
						 | 
					e49a595f54 | ||
| 
						 | 
					77485c2a04 | ||
| 
						 | 
					e9b28634e5 | ||
| 
						 | 
					b43dcb8876 | ||
| 
						 | 
					f0c1eeece8 | ||
| 
						 | 
					1e6b824ede | ||
| 
						 | 
					1e2d16273c | ||
| 
						 | 
					32dc24c59b | ||
| 
						 | 
					7a8a189c48 | ||
| 
						 | 
					6aa411fecc | ||
| 
						 | 
					9c76318df8 | ||
| 
						 | 
					6510904711 | ||
| 
						 | 
					a9817f4832 | ||
| 
						 | 
					9067689839 | ||
| 
						 | 
					4e9e91fdce | ||
| 
						 | 
					73cc91ba60 | ||
| 
						 | 
					0ab0d0860f | ||
| 
						 | 
					337b399a75 | ||
| 
						 | 
					46f21e81e3 | ||
| 
						 | 
					c1300ddbbc | ||
| 
						 | 
					8bd5b1e696 | ||
| 
						 | 
					40c5db397d | ||
| 
						 | 
					8b52919b4d | ||
| 
						 | 
					2859f23038 | ||
| 
						 | 
					00384ccb47 | ||
| 
						 | 
					0191cc589a | ||
| 
						 | 
					dae6db9b51 | ||
| 
						 | 
					4d912c9feb | ||
| 
						 | 
					07c4b46466 | ||
| 
						 | 
					e9cdce49a3 | ||
| 
						 | 
					84c3ce8778 | ||
| 
						 | 
					d5a32a7fe4 | ||
| 
						 | 
					cc4dfda21b | ||
| 
						 | 
					703b37aa7b | ||
| 
						 | 
					b433de9022 | ||
| 
						 | 
					0c1a22ff95 | ||
| 
						 | 
					4d526e40c3 | ||
| 
						 | 
					4586c7b36b | ||
| 
						 | 
					3d60b73b60 | ||
| 
						 | 
					4ef5cd8ef6 | ||
| 
						 | 
					6959bd19f1 | ||
| 
						 | 
					17e4ce5ea8 | ||
| 
						 | 
					33094b4988 | ||
| 
						 | 
					a8fdcffd44 | ||
| 
						 | 
					5adb5411fa | ||
| 
						 | 
					ff0d11c89c | ||
| 
						 | 
					5f6dce2b5c | ||
| 
						 | 
					a7405e8b39 | ||
| 
						 | 
					d87c520bad | ||
| 
						 | 
					24959f8d34 | ||
| 
						 | 
					6d1432e166 | ||
| 
						 | 
					2c7ba2c125 | ||
| 
						 | 
					a0ba664c64 | ||
| 
						 | 
					131da5f523 | ||
| 
						 | 
					7c6144450a | ||
| 
						 | 
					4c7369db16 | ||
| 
						 | 
					f4355de896 | ||
| 
						 | 
					4a3db9f44d | ||
| 
						 | 
					6c0a9ff9cc | ||
| 
						 | 
					57b1695fcf | ||
| 
						 | 
					045c6546cc | ||
| 
						 | 
					ce5bd954bf | ||
| 
						 | 
					6ef00a4a3b | ||
| 
						 | 
					569d9718a0 | ||
| 
						 | 
					00a3a8697f | ||
| 
						 | 
					c93444e390 | ||
| 
						 | 
					5e5788ab14 | ||
| 
						 | 
					abf57e6362 | ||
| 
						 | 
					74c2074d5a | ||
| 
						 | 
					b74606312e | ||
| 
						 | 
					0c849df4d5 | ||
| 
						 | 
					38690d4a09 | ||
| 
						 | 
					b64c237cb3 | ||
| 
						 | 
					3fbee8e027 | ||
| 
						 | 
					a68e6e3c63 | ||
| 
						 | 
					db5a72774d | ||
| 
						 | 
					966f90f24a | ||
| 
						 | 
					eaa664c023 | ||
| 
						 | 
					e9282c3987 | ||
| 
						 | 
					ed1f8ed339 | ||
| 
						 | 
					5d0d637eb8 | ||
| 
						 | 
					7e70dfdf4c | ||
| 
						 | 
					3f61f39ae3 | ||
| 
						 | 
					371f623a3e | ||
| 
						 | 
					566d566f26 | ||
| 
						 | 
					fb30822860 | ||
| 
						 | 
					526a53bdd4 | ||
| 
						 | 
					3833124d66 | ||
| 
						 | 
					e5e1b52abf | ||
| 
						 | 
					82fc66305d | ||
| 
						 | 
					05e0d5066f | ||
| 
						 | 
					ce2dc84e49 | ||
| 
						 | 
					eb14ed32ea | ||
| 
						 | 
					f97987d0d8 | ||
| 
						 | 
					d23d9c3b05 | ||
| 
						 | 
					3ebf6e3bea | ||
| 
						 | 
					9f41f5c740 | ||
| 
						 | 
					ae00f86887 | ||
| 
						 | 
					ab67c0f8b0 | ||
| 
						 | 
					ed7d4928e5 | ||
| 
						 | 
					f23239a923 | ||
| 
						 | 
					d949920e68 | ||
| 
						 | 
					a1def85c18 | ||
| 
						 | 
					dc624f65e4 | ||
| 
						 | 
					361652d028 | ||
| 
						 | 
					92024b7e54 | ||
| 
						 | 
					4e4ce0dd21 | ||
| 
						 | 
					bc0c490ec3 | ||
| 
						 | 
					6d92af17fd | ||
| 
						 | 
					2140a498a2 | ||
| 
						 | 
					28349d362c | ||
| 
						 | 
					e7af9f98e3 | ||
| 
						 | 
					dd6053c5e1 | ||
| 
						 | 
					37726a4cb6 | ||
| 
						 | 
					4352cc231e | ||
| 
						 | 
					824220356f | ||
| 
						 | 
					247ad9d7ab | ||
| 
						 | 
					09fe12d0c1 | ||
| 
						 | 
					127ef8383b | ||
| 
						 | 
					82eccb566c | ||
| 
						 | 
					543b29efe7 | ||
| 
						 | 
					0f4ce5dd4e | ||
| 
						 | 
					c23919df15 | ||
| 
						 | 
					2b2a8b4747 | ||
| 
						 | 
					2e48dbf6ee | ||
| 
						 | 
					207917ba45 | ||
| 
						 | 
					f824b97f3a | ||
| 
						 | 
					a5ff2fc68f | ||
| 
						 | 
					4906806c0b | ||
| 
						 | 
					d98336a906 | ||
| 
						 | 
					9ddd11cdb8 | ||
| 
						 | 
					554ad4ef05 | ||
| 
						 | 
					45d8550044 | ||
| 
						 | 
					f2b44c1494 | ||
| 
						 | 
					bdb28e87a9 | ||
| 
						 | 
					8b9592e53e | ||
| 
						 | 
					84f89648a6 | ||
| 
						 | 
					1174992099 | ||
| 
						 | 
					391a220dc1 | ||
| 
						 | 
					43f1d0578b | ||
| 
						 | 
					d3e35028ca | ||
| 
						 | 
					61c7d87003 | ||
| 
						 | 
					20f2fa84a4 | ||
| 
						 | 
					17e269b96c | ||
| 
						 | 
					6a57ac92ba | ||
| 
						 | 
					07ad03556f | ||
| 
						 | 
					04c33230c8 | ||
| 
						 | 
					083dac630f | ||
| 
						 | 
					6375724196 | ||
| 
						 | 
					922957c1ae | ||
| 
						 | 
					cbf7d0e738 | ||
| 
						 | 
					fb81efeecf | ||
| 
						 | 
					8466198626 | ||
| 
						 | 
					33718ef7a5 | ||
| 
						 | 
					a94a62764d | ||
| 
						 | 
					12c98df3db | ||
| 
						 | 
					81909a406f | ||
| 
						 | 
					d291aaa4f2 | ||
| 
						 | 
					da36d87e46 | ||
| 
						 | 
					42bc09a7ef | ||
| 
						 | 
					d0defc592e | ||
| 
						 | 
					700f7fbaf3 | ||
| 
						 | 
					74f2d02ac3 | ||
| 
						 | 
					c865d96f4b | ||
| 
						 | 
					cd7b9e108c | ||
| 
						 | 
					f54b82f64c | ||
| 
						 | 
					36bfe8c533 | ||
| 
						 | 
					a40d063cb8 | ||
| 
						 | 
					ac88a88bfb | ||
| 
						 | 
					d89c9b4556 | ||
| 
						 | 
					a07056f5e2 | ||
| 
						 | 
					f91bea3ea5 | ||
| 
						 | 
					9fbd79316a | ||
| 
						 | 
					6d89d0b02a | ||
| 
						 | 
					0febcbfa2a | ||
| 
						 | 
					f2f2898fe3 | ||
| 
						 | 
					f65826b3ba | ||
| 
						 | 
					a869007180 | ||
| 
						 | 
					b5fa48f485 | ||
| 
						 | 
					36d564526c | ||
| 
						 | 
					063f34b5d3 | ||
| 
						 | 
					9486ca5975 | ||
| 
						 | 
					63ead272a9 | ||
| 
						 | 
					9dfa2ad84e | ||
| 
						 | 
					523e431ece | ||
| 
						 | 
					768c4a0dd5 | ||
| 
						 | 
					fd25cf30ff | ||
| 
						 | 
					1d14488a4f | ||
| 
						 | 
					6e32c97c43 | ||
| 
						 | 
					020fe35d98 | ||
| 
						 | 
					e0cf946611 | ||
| 
						 | 
					a42ae6fe3a | ||
| 
						 | 
					196ab6a7c3 | ||
| 
						 | 
					f3235882f3 | ||
| 
						 | 
					0518d69b72 | ||
| 
						 | 
					c9ba94d4d8 | ||
| 
						 | 
					50e4a40bb2 | ||
| 
						 | 
					351421c158 | ||
| 
						 | 
					c3ac2df9ca | ||
| 
						 | 
					7c4f632e06 | ||
| 
						 | 
					a4eb3c17eb | ||
| 
						 | 
					e81cee3949 | ||
| 
						 | 
					e943dcafa4 | ||
| 
						 | 
					a324c390f0 | ||
| 
						 | 
					1cf64b5471 | ||
| 
						 | 
					234a4f3a1b | ||
| 
						 | 
					e69d561e8e | ||
| 
						 | 
					b8f2abcbfa | ||
| 
						 | 
					189617dfb2 | ||
| 
						 | 
					c4bfb1e400 | ||
| 
						 | 
					7db92ad5d9 | ||
| 
						 | 
					fa593a3e15 | ||
| 
						 | 
					8424236daa | ||
| 
						 | 
					5c14be28f3 | ||
| 
						 | 
					9ef80f6ac6 | ||
| 
						 | 
					daf81b5cae | ||
| 
						 | 
					7b407dda91 | ||
| 
						 | 
					4c50293f06 | ||
| 
						 | 
					02b8804b96 | ||
| 
						 | 
					7928f90cf6 | ||
| 
						 | 
					d5e6ea6ebd | ||
| 
						 | 
					52273b6c03 | ||
| 
						 | 
					b3d663b758 | ||
| 
						 | 
					c0028694d4 | ||
| 
						 | 
					3b0110849c | ||
| 
						 | 
					7b1deba590 | ||
| 
						 | 
					7a91f318f0 | ||
| 
						 | 
					2dfde89008 | ||
| 
						 | 
					23146c00ba | ||
| 
						 | 
					cdd95fbbdc | ||
| 
						 | 
					01064af20e | ||
| 
						 | 
					01a9c3fc8e | ||
| 
						 | 
					c1734b279b | ||
| 
						 | 
					b00dc31b55 | ||
| 
						 | 
					c5f8c8c77b | ||
| 
						 | 
					9361c7223d | ||
| 
						 | 
					b43cc22704 | ||
| 
						 | 
					8af4fd64c1 | ||
| 
						 | 
					5b39b87199 | ||
| 
						 | 
					092338a4c7 | ||
| 
						 | 
					7907b19e28 | ||
| 
						 | 
					5790309e88 | ||
| 
						 | 
					9496b64c86 | ||
| 
						 | 
					f7fb6b2160 | ||
| 
						 | 
					98649f9397 | ||
| 
						 | 
					45a1ceaa54 | ||
| 
						 | 
					6496205081 | ||
| 
						 | 
					e2898bea5c | ||
| 
						 | 
					563221698c | ||
| 
						 | 
					92a85071bc | ||
| 
						 | 
					9ae8d90be4 | ||
| 
						 | 
					caade78e79 | ||
| 
						 | 
					4f22c61b16 | ||
| 
						 | 
					5e220e9e47 | ||
| 
						 | 
					857cb9c501 | ||
| 
						 | 
					09fa5d98c2 | ||
| 
						 | 
					268fe464de | ||
| 
						 | 
					27095d1a02 | ||
| 
						 | 
					dd061fed38 | ||
| 
						 | 
					7ddaa8968a | ||
| 
						 | 
					cec1557d04 | ||
| 
						 | 
					84a49a5eef | ||
| 
						 | 
					06ea16bdbf | ||
| 
						 | 
					361d38f93b | ||
| 
						 | 
					016e384fa1 | ||
| 
						 | 
					ef57c9ff83 | ||
| 
						 | 
					627fff967f | ||
| 
						 | 
					e79c093d80 | ||
| 
						 | 
					cbb3831c7b | ||
| 
						 | 
					9752fda1f6 | ||
| 
						 | 
					d99f08b9c4 | ||
| 
						 | 
					bf0bcaa306 | ||
| 
						 | 
					a199c1290b | ||
| 
						 | 
					28bb0c1fb2 | ||
| 
						 | 
					49259b3d19 | ||
| 
						 | 
					a5d0ac7955 | ||
| 
						 | 
					f326dde09c | ||
| 
						 | 
					3b6d907577 | ||
| 
						 | 
					0af108211c | ||
| 
						 | 
					902e78d910 | ||
| 
						 | 
					885e194c25 | ||
| 
						 | 
					d99a2f19a5 | ||
| 
						 | 
					152a7fd1ef | ||
| 
						 | 
					6ceb6545ee | ||
| 
						 | 
					a167b16860 | ||
| 
						 | 
					595be5083c | ||
| 
						 | 
					8b796e745d | ||
| 
						 | 
					d5314736de | ||
| 
						 | 
					a517ab964e | ||
| 
						 | 
					b6c0a2c197 | ||
| 
						 | 
					0151c92a92 | ||
| 
						 | 
					a39440fff5 | ||
| 
						 | 
					5af7e9f6fe | ||
| 
						 | 
					b8d9273a7c | ||
| 
						 | 
					77c4cbb974 | ||
| 
						 | 
					8adc193d73 | ||
| 
						 | 
					86aa4fe0a9 | ||
| 
						 | 
					8c9eb6702d | ||
| 
						 | 
					b245ee6212 | ||
| 
						 | 
					98fa71ba18 | ||
| 
						 | 
					22dcb46bff | ||
| 
						 | 
					3aa904da0a | ||
| 
						 | 
					794f773620 | ||
| 
						 | 
					bbba77c275 | ||
| 
						 | 
					88f2bbba61 | ||
| 
						 | 
					cc8d4e4ab3 | ||
| 
						 | 
					32a11bd8c7 | ||
| 
						 | 
					55c82a389c | ||
| 
						 | 
					a1aa58bb64 | ||
| 
						 | 
					82ffe233dc | ||
| 
						 | 
					9e16bb85e3 | ||
| 
						 | 
					887b41bce3 | ||
| 
						 | 
					63eef286c9 | ||
| 
						 | 
					14e8cba2b1 | ||
| 
						 | 
					3418e6e85e | ||
| 
						 | 
					8f0c980d3c | ||
| 
						 | 
					c86f3b8d48 | ||
| 
						 | 
					8cf6b4c728 | ||
| 
						 | 
					612b9e9faf | ||
| 
						 | 
					c2c4c26f72 | ||
| 
						 | 
					be4d504e27 | ||
| 
						 | 
					9ed0bbb3a9 | ||
| 
						 | 
					e5bc3a2ba8 | ||
| 
						 | 
					1dee10c575 | ||
| 
						 | 
					352fb7b833 | ||
| 
						 | 
					81cee34c17 | ||
| 
						 | 
					fa786fd3ef | ||
| 
						 | 
					0751a90bd9 | ||
| 
						 | 
					709193d680 | ||
| 
						 | 
					d0d82cdf7e | ||
| 
						 | 
					5d2b7e2c9e | ||
| 
						 | 
					07660f7fcf | ||
| 
						 | 
					5d138e1b79 | ||
| 
						 | 
					0133c6e174 | ||
| 
						 | 
					2054f77e2b | ||
| 
						 | 
					e4911e2f7a | ||
| 
						 | 
					eabc2e6781 | ||
| 
						 | 
					71cf87cbb1 | ||
| 
						 | 
					155997b5fa | ||
| 
						 | 
					82ce8fe3ff | ||
| 
						 | 
					9f1da20161 | ||
| 
						 | 
					d4239d570d | ||
| 
						 | 
					1ecbabc69a | ||
| 
						 | 
					7f767c49d8 | ||
| 
						 | 
					aabe56ba79 | ||
| 
						 | 
					d227ddfc88 | ||
| 
						 | 
					021d3dadbb | ||
| 
						 | 
					4902a600d5 | ||
| 
						 | 
					db39ba3b9f | ||
| 
						 | 
					239a9e4816 | ||
| 
						 | 
					35e99266ba | ||
| 
						 | 
					67ae8ed8e9 | ||
| 
						 | 
					356e4c0967 | ||
| 
						 | 
					80a9d2e7c9 | ||
| 
						 | 
					5088f22388 | ||
| 
						 | 
					4156a4c2d0 | ||
| 
						 | 
					b6c2399a17 | ||
| 
						 | 
					5be9326192 | ||
| 
						 | 
					388cfa3695 | ||
| 
						 | 
					e8914c6699 | ||
| 
						 | 
					13bf64a53d | ||
| 
						 | 
					f96b2ee858 | ||
| 
						 | 
					b12967b930 | ||
| 
						 | 
					d896248ff8 | ||
| 
						 | 
					2ebdc81c8f | ||
| 
						 | 
					2af5e851b3 | ||
| 
						 | 
					bd9455ec8e | ||
| 
						 | 
					fefee3b49e | ||
| 
						 | 
					071c49b7c6 | ||
| 
						 | 
					4e9e6e75d3 | ||
| 
						 | 
					a13af7fbcc | ||
| 
						 | 
					4fa8e2b59d | ||
| 
						 | 
					90783c7cdf | ||
| 
						 | 
					f99b4da4ec | ||
| 
						 | 
					a64e0e1f49 | ||
| 
						 | 
					270e82e3db | ||
| 
						 | 
					8f4a4d93f2 | ||
| 
						 | 
					83265bb12a | ||
| 
						 | 
					5be8d5f9cf | ||
| 
						 | 
					08126e5a38 | ||
| 
						 | 
					b76efe17d6 | ||
| 
						 | 
					ca2678446d | ||
| 
						 | 
					06d906b962 | ||
| 
						 | 
					023f5149e5 | ||
| 
						 | 
					2e45508529 | ||
| 
						 | 
					6241a8269f | ||
| 
						 | 
					465d03ab2c | ||
| 
						 | 
					a56cd3c3d6 | ||
| 
						 | 
					d8a98e5467 | ||
| 
						 | 
					2d813cbdd8 | ||
| 
						 | 
					6d3434f3a5 | ||
| 
						 | 
					fa0268f35a | ||
| 
						 | 
					712ea9b9b6 | ||
| 
						 | 
					b7fd78b254 | ||
| 
						 | 
					a2e6b3167b | ||
| 
						 | 
					72037af241 | ||
| 
						 | 
					62048abbf5 | ||
| 
						 | 
					7b61aca956 | ||
| 
						 | 
					6709e5e458 | ||
| 
						 | 
					11c8405879 | ||
| 
						 | 
					6028628261 | ||
| 
						 | 
					3d8a1537d2 | ||
| 
						 | 
					c5b4decdae | ||
| 
						 | 
					c7237be3e3 | ||
| 
						 | 
					aa39166b74 | ||
| 
						 | 
					e7b9933036 | ||
| 
						 | 
					54d51c713c | ||
| 
						 | 
					72e0c2fe11 | ||
| 
						 | 
					7458d3ef39 | ||
| 
						 | 
					52c5f9b144 | ||
| 
						 | 
					8c7085acd4 | ||
| 
						 | 
					083ca7d39b | ||
| 
						 | 
					68e716ae27 | ||
| 
						 | 
					ef8772916d | ||
| 
						 | 
					b54e374bc5 | ||
| 
						 | 
					b3228258ee | ||
| 
						 | 
					e5036a458e | ||
| 
						 | 
					c714a66ba3 | ||
| 
						 | 
					d80b7be6ca | ||
| 
						 | 
					77de611ec7 | ||
| 
						 | 
					60b54c0052 | ||
| 
						 | 
					6a3130e25f | ||
| 
						 | 
					91cba1f8f4 | ||
| 
						 | 
					22b2661df9 | ||
| 
						 | 
					f8b397a5dc | ||
| 
						 | 
					44b475e746 | ||
| 
						 | 
					d25610903a | ||
| 
						 | 
					2efcbaf206 | ||
| 
						 | 
					7f1d2825fd | ||
| 
						 | 
					b9edb1dc01 | ||
| 
						 | 
					b0cc778c49 | ||
| 
						 | 
					ff840db708 | ||
| 
						 | 
					11f30e2e09 | ||
| 
						 | 
					4886275df4 | ||
| 
						 | 
					c5de239e25 | ||
| 
						 | 
					10dcc100e9 | ||
| 
						 | 
					8ada9b43ae | ||
| 
						 | 
					fd77225c3e | ||
| 
						 | 
					7ed3facf8f | ||
| 
						 | 
					6c97e2a5ab | ||
| 
						 | 
					f19e8b1e78 | ||
| 
						 | 
					08e669adde | ||
| 
						 | 
					bbd2c02b7f | ||
| 
						 | 
					0d9da86b7e | ||
| 
						 | 
					5810fcb14d | ||
| 
						 | 
					2466eb3132 | ||
| 
						 | 
					fc59e222d2 | ||
| 
						 | 
					ff983432d9 | ||
| 
						 | 
					67b4f9b3a9 | ||
| 
						 | 
					f279b6bf7e | ||
| 
						 | 
					daec53f4fe | ||
| 
						 | 
					cb1966612e | ||
| 
						 | 
					cda279f5c2 | ||
| 
						 | 
					31915cdc93 | ||
| 
						 | 
					329f803004 | ||
| 
						 | 
					7780c99de6 | ||
| 
						 | 
					d3ad857ba4 | ||
| 
						 | 
					aa1405e4ea | ||
| 
						 | 
					aa0a7f7816 | ||
| 
						 | 
					3850edced5 | ||
| 
						 | 
					ddd59f2e76 | ||
| 
						 | 
					10a0f2b614 | ||
| 
						 | 
					8bc85d4a79 | ||
| 
						 | 
					3dc07d48c5 | ||
| 
						 | 
					c1acf992fa | ||
| 
						 | 
					99149f9c41 | ||
| 
						 | 
					bcd307066a | ||
| 
						 | 
					446910cb10 | ||
| 
						 | 
					fde200d084 | ||
| 
						 | 
					a376cd1610 | ||
| 
						 | 
					dbeab0ef87 | ||
| 
						 | 
					7765d6a08f | ||
| 
						 | 
					aed50e2a39 | ||
| 
						 | 
					b262a42458 | ||
| 
						 | 
					3fd90dfcb1 | ||
| 
						 | 
					dec55a3291 | ||
| 
						 | 
					f6f3ded842 | ||
| 
						 | 
					004c5cf287 | ||
| 
						 | 
					aba5f2f7b8 | ||
| 
						 | 
					2a96964204 | ||
| 
						 | 
					a9fe2a1493 | ||
| 
						 | 
					8f3bdd4f1a | ||
| 
						 | 
					4322a20cbe | ||
| 
						 | 
					2403fd0680 | ||
| 
						 | 
					e01baf2a25 | ||
| 
						 | 
					d27b37fefe | ||
| 
						 | 
					acedb60abe | ||
| 
						 | 
					77556d181e | ||
| 
						 | 
					60612cace9 | ||
| 
						 | 
					f057502834 | ||
| 
						 | 
					21a1149532 | ||
| 
						 | 
					6724ca4f63 | ||
| 
						 | 
					7a6c25b3fb | ||
| 
						 | 
					0366e320af | ||
| 
						 | 
					f03793b825 | ||
| 
						 | 
					0907f030b4 | ||
| 
						 | 
					7542e68b6f | ||
| 
						 | 
					9003a34285 | ||
| 
						 | 
					3cc27eaabe | ||
| 
						 | 
					601b081bf3 | ||
| 
						 | 
					4405d993c9 | ||
| 
						 | 
					361308eb1b | ||
| 
						 | 
					d894dedaf6 | ||
| 
						 | 
					d12dd1491f | ||
| 
						 | 
					1625591598 | ||
| 
						 | 
					a50c30a4fd | ||
| 
						 | 
					02bfc74c1e | ||
| 
						 | 
					a012dd838d | ||
| 
						 | 
					e2b634e59a | ||
| 
						 | 
					80b98d8787 | ||
| 
						 | 
					bf2ba83cd5 | ||
| 
						 | 
					727c43dbab | ||
| 
						 | 
					203dedfb3a | ||
| 
						 | 
					8d5d4159a3 | ||
| 
						 | 
					cecba0269f | ||
| 
						 | 
					3c878793b5 | ||
| 
						 | 
					0549f42030 | ||
| 
						 | 
					50f248ec5b | ||
| 
						 | 
					544bdb4fb1 | ||
| 
						 | 
					88b295ff9f | ||
| 
						 | 
					602326bb57 | ||
| 
						 | 
					31857cf05f | ||
| 
						 | 
					896d8e830c | ||
| 
						 | 
					5f86e29830 | ||
| 
						 | 
					579ae59eca | ||
| 
						 | 
					90db743cc9 | ||
| 
						 | 
					fe82897064 | ||
| 
						 | 
					0f49f36519 | ||
| 
						 | 
					a92b7342ba | ||
| 
						 | 
					86818e9c52 | ||
| 
						 | 
					7a8a00c705 | ||
| 
						 | 
					c8d5e0a51c | ||
| 
						 | 
					524a7ff6fb | ||
| 
						 | 
					5f6ac33d59 | ||
| 
						 | 
					b4f5e4206d | ||
| 
						 | 
					5133c3e010 | ||
| 
						 | 
					0b77ea422a | ||
| 
						 | 
					5c1dd4ea18 | ||
| 
						 | 
					e1c687184e | ||
| 
						 | 
					297d1356a2 | ||
| 
						 | 
					98327b0c13 | ||
| 
						 | 
					6786aee5ed | ||
| 
						 | 
					0b9c726b4e | ||
| 
						 | 
					436dd6ee8c | ||
| 
						 | 
					acc053302d | ||
| 
						 | 
					534b371d42 | ||
| 
						 | 
					6004e3d2e1 | ||
| 
						 | 
					c632074ba7 | ||
| 
						 | 
					664245d2a6 | ||
| 
						 | 
					fda4fc674d | ||
| 
						 | 
					bf28c24c82 | ||
| 
						 | 
					32df0e80ca | ||
| 
						 | 
					297eab738f | ||
| 
						 | 
					5819dd3a5a | ||
| 
						 | 
					a007b1bb2d | ||
| 
						 | 
					5cb43b6bae | ||
| 
						 | 
					f524138a64 | ||
| 
						 | 
					0aa626b2fb | ||
| 
						 | 
					3ae1050f67 | ||
| 
						 | 
					67736642f3 | ||
| 
						 | 
					09f3c87d20 | ||
| 
						 | 
					9deca75de8 | ||
| 
						 | 
					5bc1dede81 | ||
| 
						 | 
					6d53d43766 | ||
| 
						 | 
					325462d9bf | ||
| 
						 | 
					ee4ae62946 | ||
| 
						 | 
					153768ef7f | ||
| 
						 | 
					7249a218ba | ||
| 
						 | 
					de348a4c49 | ||
| 
						 | 
					fda8ffd9ef | ||
| 
						 | 
					6cb707cc4f | ||
| 
						 | 
					998c5f17fc | ||
| 
						 | 
					c34b357051 | ||
| 
						 | 
					40f4e92461 | ||
| 
						 | 
					c727da823b | ||
| 
						 | 
					8d1b7962d8 | ||
| 
						 | 
					a6dfe20348 | ||
| 
						 | 
					ed46390bbc | ||
| 
						 | 
					80eb5bf535 | ||
| 
						 | 
					7596fdb460 | ||
| 
						 | 
					8db1ff8aef | ||
| 
						 | 
					1dfffdbc4e | ||
| 
						 | 
					64b2b4a7d4 | ||
| 
						 | 
					ae35d0e43c | ||
| 
						 | 
					b22c5eb167 | ||
| 
						 | 
					6d5e414863 | ||
| 
						 | 
					3e74dfb66d | ||
| 
						 | 
					1245628521 | ||
| 
						 | 
					c567690004 | ||
| 
						 | 
					2feff4207b | ||
| 
						 | 
					8c40b6f9a7 | ||
| 
						 | 
					fc759bff77 | ||
| 
						 | 
					3581c1d5b4 | ||
| 
						 | 
					64e7459d1c | ||
| 
						 | 
					f71afa9248 | ||
| 
						 | 
					1ebca2e6d5 | ||
| 
						 | 
					6222796b6a | ||
| 
						 | 
					dcecf41d18 | ||
| 
						 | 
					9d1fbffe75 | ||
| 
						 | 
					6a6ba94bb9 | ||
| 
						 | 
					ef5de3a5c0 | ||
| 
						 | 
					f042e43990 | ||
| 
						 | 
					620330db8f | ||
| 
						 | 
					3765acc0a5 | ||
| 
						 | 
					2e8654b96c | ||
| 
						 | 
					cc5c5e7e8a | ||
| 
						 | 
					9c849b0290 | ||
| 
						 | 
					ad314b362e | ||
| 
						 | 
					737a4f2816 | ||
| 
						 | 
					96e4128e3e | ||
| 
						 | 
					6f515f2327 | ||
| 
						 | 
					cbb9a7ab96 | ||
| 
						 | 
					e2e3b29ed1 | ||
| 
						 | 
					82a8ac1976 | ||
| 
						 | 
					bfec396ec2 | ||
| 
						 | 
					d0e7f880d7 | ||
| 
						 | 
					ff81659b9e | ||
| 
						 | 
					6b2b3475c8 | ||
| 
						 | 
					ed8acefc00 | ||
| 
						 | 
					737f395d6c | ||
| 
						 | 
					ab0a5d4a53 | ||
| 
						 | 
					9412ac2027 | ||
| 
						 | 
					c8670819dc | ||
| 
						 | 
					4132ccae33 | ||
| 
						 | 
					c450120409 | ||
| 
						 | 
					6ce07abf50 | ||
| 
						 | 
					e39e539ee9 | ||
| 
						 | 
					9563a8f8a0 | ||
| 
						 | 
					d5f37fa280 | ||
| 
						 | 
					5c6e5ef6d0 | ||
| 
						 | 
					42adc38609 | ||
| 
						 | 
					e5fadb3b42 | ||
| 
						 | 
					4c5f3aa971 | ||
| 
						 | 
					6fc49b79a4 | ||
| 
						 | 
					9e804b082f | ||
| 
						 | 
					1fb220beb7 | ||
| 
						 | 
					1fc1282fad | ||
| 
						 | 
					8834a7df10 | ||
| 
						 | 
					a34071e1c3 | ||
| 
						 | 
					52a342300a | ||
| 
						 | 
					b9456caeb0 | ||
| 
						 | 
					26aa4333a5 | ||
| 
						 | 
					04d2b0d282 | ||
| 
						 | 
					7def1a4aa5 | ||
| 
						 | 
					001b9868fb | ||
| 
						 | 
					59a3e393f9 | ||
| 
						 | 
					b846354787 | ||
| 
						 | 
					2674d96e54 | ||
| 
						 | 
					0c98fe8546 | ||
| 
						 | 
					f18ed3c6ae | ||
| 
						 | 
					644acf7018 | ||
| 
						 | 
					96dca48b3b | ||
| 
						 | 
					1309b64c33 | ||
| 
						 | 
					1301dee744 | ||
| 
						 | 
					efc194e36c | ||
| 
						 | 
					60f41a109f | ||
| 
						 | 
					890efa787a | ||
| 
						 | 
					60c88612f7 | ||
| 
						 | 
					82648bc86c | ||
| 
						 | 
					ea1e5a5210 | ||
| 
						 | 
					aa03734d39 | ||
| 
						 | 
					bb0f76f562 | ||
| 
						 | 
					8c2a290d09 | ||
| 
						 | 
					8e661c3780 | ||
| 
						 | 
					a03b6c419a | ||
| 
						 | 
					fb55dd677f | ||
| 
						 | 
					408790a630 | ||
| 
						 | 
					08371f073d | ||
| 
						 | 
					e7289378b7 | ||
| 
						 | 
					31bde574de | ||
| 
						 | 
					5aacfe4e6e | ||
| 
						 | 
					5cf7bdabfd | ||
| 
						 | 
					2021edd1fb | ||
| 
						 | 
					45c1a9eafb | ||
| 
						 | 
					0ae1556b94 | ||
| 
						 | 
					c0739bd1e3 | ||
| 
						 | 
					af51e8df7b | ||
| 
						 | 
					22ef63cc44 | ||
| 
						 | 
					03a5133e8c | ||
| 
						 | 
					7f2456c00d | ||
| 
						 | 
					aa4dbee362 | ||
| 
						 | 
					7b65735cc9 | ||
| 
						 | 
					7ef35fbec7 | ||
| 
						 | 
					8b10d85fee | ||
| 
						 | 
					d99b1e6c09 | ||
| 
						 | 
					57ab7aec5b | ||
| 
						 | 
					29a221bf62 | ||
| 
						 | 
					671c569a9e | ||
| 
						 | 
					492c033760 | ||
| 
						 | 
					33a3b8046d | ||
| 
						 | 
					88df183450 | ||
| 
						 | 
					6a9080c3d6 | ||
| 
						 | 
					019670b5ab | ||
| 
						 | 
					4cab0c95d3 | ||
| 
						 | 
					d51e79d483 | ||
| 
						 | 
					69a27911a7 | ||
| 
						 | 
					dd48514b24 | ||
| 
						 | 
					eb54662098 | ||
| 
						 | 
					545f0432c8 | ||
| 
						 | 
					fdefb317cb | ||
| 
						 | 
					4e0c8bfe67 | ||
| 
						 | 
					dbd629d5d2 | ||
| 
						 | 
					619a44a499 | ||
| 
						 | 
					c5ca4e3ff0 | ||
| 
						 | 
					55771b437b | ||
| 
						 | 
					8727680983 | ||
| 
						 | 
					ab9f21351f | ||
| 
						 | 
					0055cabc62 | ||
| 
						 | 
					fc70c2246b | ||
| 
						 | 
					f7b6acaff8 | ||
| 
						 | 
					91caa8e59f | ||
| 
						 | 
					4c44bb7f52 | ||
| 
						 | 
					df8a735aa9 | ||
| 
						 | 
					82aea3e8d6 | ||
| 
						 | 
					a8baf4a2a2 | ||
| 
						 | 
					bfd344cdec | ||
| 
						 | 
					a0fd4e195d | ||
| 
						 | 
					4b3fbc4c9b | ||
| 
						 | 
					63b1699a35 | ||
| 
						 | 
					48acc41698 | ||
| 
						 | 
					17672accfe | ||
| 
						 | 
					986d72d9de | ||
| 
						 | 
					ffd461cdb4 | ||
| 
						 | 
					71dfab9711 | ||
| 
						 | 
					c4f5274d74 | ||
| 
						 | 
					4bfc3bafcb | ||
| 
						 | 
					898b2b903d | ||
| 
						 | 
					7921954a31 | ||
| 
						 | 
					0e42de9149 | ||
| 
						 | 
					8e4a5f1ac5 | ||
| 
						 | 
					61577e176e | ||
| 
						 | 
					4b008b1ada | ||
| 
						 | 
					bee37b5bc4 | ||
| 
						 | 
					b5ab8b6ed5 | ||
| 
						 | 
					4d6bd91d16 | ||
| 
						 | 
					5428db5385 | ||
| 
						 | 
					6e6b1e6052 | ||
| 
						 | 
					bc2b47974d | ||
| 
						 | 
					2244b6ff1b | ||
| 
						 | 
					fb384fc291 | ||
| 
						 | 
					73cae8ce9a | ||
| 
						 | 
					dcd07eb23f | ||
| 
						 | 
					fa24448489 | ||
| 
						 | 
					c975740f92 | ||
| 
						 | 
					1e0187fa57 | ||
| 
						 | 
					cbdf060bca | ||
| 
						 | 
					19a8dff975 | ||
| 
						 | 
					72f9f482d6 | ||
| 
						 | 
					88de26138a | ||
| 
						 | 
					57bd964cb3 | ||
| 
						 | 
					74a39ae57c | ||
| 
						 | 
					5090a4ccce | ||
| 
						 | 
					ae0652d13f | ||
| 
						 | 
					101a07a3d7 | ||
| 
						 | 
					b012e93121 | ||
| 
						 | 
					c31109800b | ||
| 
						 | 
					c0dc363a3d | ||
| 
						 | 
					739bb28220 | ||
| 
						 | 
					aab2794e05 | ||
| 
						 | 
					75c8c1bfb6 | ||
| 
						 | 
					6f8bd96195 | ||
| 
						 | 
					25f0d098bd | ||
| 
						 | 
					56d584b7c6 | ||
| 
						 | 
					20bf53add1 | ||
| 
						 | 
					0d440bb0a2 | ||
| 
						 | 
					8ec62ce46b | ||
| 
						 | 
					79927faaec | ||
| 
						 | 
					e4c7f1f3c4 | ||
| 
						 | 
					68710c4647 | ||
| 
						 | 
					7d7cbde1f3 | ||
| 
						 | 
					bafd9c777a | ||
| 
						 | 
					42a5531f15 | ||
| 
						 | 
					227da25776 | ||
| 
						 | 
					2028f33e38 | ||
| 
						 | 
					145bf19636 | ||
| 
						 | 
					d1675c44e2 | ||
| 
						 | 
					6934e4db26 | ||
| 
						 | 
					cae3414854 | ||
| 
						 | 
					90d061edaf | ||
| 
						 | 
					2e02918323 | ||
| 
						 | 
					e77a1fd33b | ||
| 
						 | 
					dd01c24c34 | ||
| 
						 | 
					f88fbee80d | ||
| 
						 | 
					fe08edbe2b | ||
| 
						 | 
					d2a16bca10 | ||
| 
						 | 
					a87f51487e | ||
| 
						 | 
					76fce94b66 | ||
| 
						 | 
					d104f9210a | ||
| 
						 | 
					d0780d1622 | ||
| 
						 | 
					9d5906dae3 | ||
| 
						 | 
					07a0960265 | ||
| 
						 | 
					72bee6d7ca | ||
| 
						 | 
					249f26d23c | ||
| 
						 | 
					7813c5b93f | ||
| 
						 | 
					e38d83fd44 | ||
| 
						 | 
					d97657b151 | ||
| 
						 | 
					7e857dede3 | ||
| 
						 | 
					c3218f6b03 | ||
| 
						 | 
					1060d0db60 | ||
| 
						 | 
					b8925a091c | ||
| 
						 | 
					79cca07a41 | ||
| 
						 | 
					c1d189c9ad | ||
| 
						 | 
					b1a973ee5a | ||
| 
						 | 
					93ef560779 | ||
| 
						 | 
					c28d35ad86 | ||
| 
						 | 
					9c654a6ab5 | ||
| 
						 | 
					64a54e379c | ||
| 
						 | 
					8f4ec8583b | ||
| 
						 | 
					f4852d7264 | ||
| 
						 | 
					092e1a691d | ||
| 
						 | 
					16ac42421d | ||
| 
						 | 
					1d2eadb9c0 | ||
| 
						 | 
					35c85d9fac | ||
| 
						 | 
					f0622c1896 | ||
| 
						 | 
					6d11247417 | ||
| 
						 | 
					59c3e3a179 | ||
| 
						 | 
					42e26a8682 | ||
| 
						 | 
					db6caac9cc | ||
| 
						 | 
					ba4a57ba0b | ||
| 
						 | 
					018e3bc35f | ||
| 
						 | 
					a56bc9d933 | ||
| 
						 | 
					5b93525ce8 | ||
| 
						 | 
					6abb86dff6 | ||
| 
						 | 
					6a27d5ed80 | ||
| 
						 | 
					8232684672 | ||
| 
						 | 
					2d855ce5cf | ||
| 
						 | 
					b2b685e46d | ||
| 
						 | 
					ef552846d1 | ||
| 
						 | 
					c7dfd0894e | ||
| 
						 | 
					5b1a76aeff | ||
| 
						 | 
					529b6ca935 | ||
| 
						 | 
					625a4c0766 | ||
| 
						 | 
					3c3ea2f575 | ||
| 
						 | 
					57a332bb08 | ||
| 
						 | 
					73ac98b193 | ||
| 
						 | 
					59e3cbb36b | ||
| 
						 | 
					fb019a7cbf | ||
| 
						 | 
					09607f6aa7 | ||
| 
						 | 
					1c4a33eb78 | ||
| 
						 | 
					b7513097ea | ||
| 
						 | 
					a35677a9bf | ||
| 
						 | 
					89de3a81c6 | ||
| 
						 | 
					b9828bf5de | ||
| 
						 | 
					d6c3868a7c | ||
| 
						 | 
					a73f02ac23 | ||
| 
						 | 
					7e9594456b | ||
| 
						 | 
					d25418ba04 | ||
| 
						 | 
					a7df1a3d77 | ||
| 
						 | 
					50951d15ea | ||
| 
						 | 
					30076884ae | ||
| 
						 | 
					1eff22a90b | ||
| 
						 | 
					41bdbc203d | ||
| 
						 | 
					7932585656 | ||
| 
						 | 
					68bf4e7b70 | ||
| 
						 | 
					92f09a60f6 | ||
| 
						 | 
					d19f2bb6d2 | ||
| 
						 | 
					b06dce5bf8 | ||
| 
						 | 
					82e2ab89c5 | ||
| 
						 | 
					db198b183c | ||
| 
						 | 
					90bab650e2 | ||
| 
						 | 
					fa1cc556f9 | ||
| 
						 | 
					69b23b0e48 | ||
| 
						 | 
					af69945e5b | ||
| 
						 | 
					f36f7644c8 | ||
| 
						 | 
					20f1457d15 | ||
| 
						 | 
					38bcd52065 | ||
| 
						 | 
					38219fec99 | ||
| 
						 | 
					6c3300bc2f | ||
| 
						 | 
					d1a110d4ca | ||
| 
						 | 
					5b61485143 | ||
| 
						 | 
					6b95a357eb | ||
| 
						 | 
					60bdc726ce | ||
| 
						 | 
					429f809b71 | ||
| 
						 | 
					9396d736f2 | ||
| 
						 | 
					cc9b812466 | ||
| 
						 | 
					5b0f2dc0cf | ||
| 
						 | 
					7ffea1606d | ||
| 
						 | 
					342bc1e72d | ||
| 
						 | 
					0127eb5892 | ||
| 
						 | 
					39023269d6 | ||
| 
						 | 
					35e3cd97fe | ||
| 
						 | 
					a63a171ec3 | ||
| 
						 | 
					7f1763f32f | ||
| 
						 | 
					2d6326815c | ||
| 
						 | 
					ee4c8cca8c | ||
| 
						 | 
					2104e0f411 | ||
| 
						 | 
					84e69f57ea | ||
| 
						 | 
					aba43125f3 | ||
| 
						 | 
					de5fc58fcb | ||
| 
						 | 
					4831dde3fb | ||
| 
						 | 
					b5cbfc5e7a | ||
| 
						 | 
					1124d164ec | ||
| 
						 | 
					9d9391bd95 | ||
| 
						 | 
					0121d74b92 | ||
| 
						 | 
					f81af32963 | ||
| 
						 | 
					8f5198821e | ||
| 
						 | 
					96c2b5ef32 | ||
| 
						 | 
					c5eb324cf0 | ||
| 
						 | 
					f117d9bfd3 | ||
| 
						 | 
					b470736246 | ||
| 
						 | 
					b2a2a00cd8 | ||
| 
						 | 
					659130856c | ||
| 
						 | 
					9a21008177 | ||
| 
						 | 
					8f58bc5b19 | ||
| 
						 | 
					3a0220a875 | ||
| 
						 | 
					9f438d0ec6 | ||
| 
						 | 
					22c22e0d7a | ||
| 
						 | 
					bc48bd5f4a | ||
| 
						 | 
					905c4bb4a5 | ||
| 
						 | 
					94bfaf6896 | ||
| 
						 | 
					25b743b03c | ||
| 
						 | 
					8da4e6ce5e | ||
| 
						 | 
					cedd297ba6 | ||
| 
						 | 
					b6e0c5e0ea | ||
| 
						 | 
					bf3f7d0dc4 | ||
| 
						 | 
					7b42a84422 | ||
| 
						 | 
					8b7c065706 | ||
| 
						 | 
					c6a4b3d9b0 | ||
| 
						 | 
					0ef32f2b8d | ||
| 
						 | 
					f7fdcb7bf1 | ||
| 
						 | 
					848d36ff39 | ||
| 
						 | 
					07ce3e7cdf | ||
| 
						 | 
					cfec145ae2 | ||
| 
						 | 
					641d7a4ea4 | ||
| 
						 | 
					da0650fda6 | ||
| 
						 | 
					6724133927 | ||
| 
						 | 
					c0ded8ef5f | ||
| 
						 | 
					7382de51dc | ||
| 
						 | 
					96a1121e6b | ||
| 
						 | 
					323bbb0692 | ||
| 
						 | 
					59e235623a | ||
| 
						 | 
					40dc85d975 | ||
| 
						 | 
					6006a42cbb | ||
| 
						 | 
					c2e0278bd9 | ||
| 
						 | 
					c1ba920c86 | ||
| 
						 | 
					7b997e9374 | ||
| 
						 | 
					dfb97c1ed7 | ||
| 
						 | 
					fc49fb2f4f | ||
| 
						 | 
					63078fba5b | ||
| 
						 | 
					b0176546c2 | ||
| 
						 | 
					a234ba91a4 | ||
| 
						 | 
					526d11809f | ||
| 
						 | 
					3bbdecc6b3 | ||
| 
						 | 
					00fc4a2eb7 | ||
| 
						 | 
					924b31233b | ||
| 
						 | 
					475161f716 | ||
| 
						 | 
					31b12635d1 | ||
| 
						 | 
					d2de0865bf | ||
| 
						 | 
					9b4dbd0e83 | ||
| 
						 | 
					4577cd7497 | ||
| 
						 | 
					4ebf07c725 | ||
| 
						 | 
					da852a94bd | ||
| 
						 | 
					9b51ff7241 | ||
| 
						 | 
					aa0137e7ce | ||
| 
						 | 
					3889ae7627 | ||
| 
						 | 
					c97a8602a1 | ||
| 
						 | 
					affc9f9058 | ||
| 
						 | 
					1582819259 | ||
| 
						 | 
					05e8ae33dc | ||
| 
						 | 
					219d5fb66b | ||
| 
						 | 
					92ff57c0ea | ||
| 
						 | 
					5233429b6f | ||
| 
						 | 
					475cf7179e | ||
| 
						 | 
					f608c65962 | ||
| 
						 | 
					6cf0a35b4c | ||
| 
						 | 
					bac006ebc1 | ||
| 
						 | 
					be5f74e37f | ||
| 
						 | 
					5c29bff23d | ||
| 
						 | 
					68968d2b40 | ||
| 
						 | 
					038f4e8bde | ||
| 
						 | 
					f8874fec0f | ||
| 
						 | 
					ee6693e6e3 | ||
| 
						 | 
					bfba97647e | ||
| 
						 | 
					82d5194afe | ||
| 
						 | 
					bf449b9f61 | ||
| 
						 | 
					9530048867 | ||
| 
						 | 
					090d54516e | ||
| 
						 | 
					c91b716a63 | ||
| 
						 | 
					80cdb0dc4e | ||
| 
						 | 
					aaa6b54673 | ||
| 
						 | 
					a3b61ec8c8 | ||
| 
						 | 
					6c41d6b66a | ||
| 
						 | 
					1838ab1412 | ||
| 
						 | 
					72e8d38586 | ||
| 
						 | 
					9259e2221d | ||
| 
						 | 
					42ea979b06 | ||
| 
						 | 
					46824adb97 | ||
| 
						 | 
					3758f4952e | ||
| 
						 | 
					8fdbbe78f4 | ||
| 
						 | 
					5a86b0f9e3 | ||
| 
						 | 
					604722b775 | ||
| 
						 | 
					812812d817 | ||
| 
						 | 
					f07fe0a8e7 | ||
| 
						 | 
					1d7cef5bfe | ||
| 
						 | 
					34b12e6a6a | ||
| 
						 | 
					eb6ba563bd | ||
| 
						 | 
					281b2e9b0e | ||
| 
						 | 
					5437629e89 | ||
| 
						 | 
					e1df2f8ff5 | ||
| 
						 | 
					12fad6f05f | ||
| 
						 | 
					4208078750 | ||
| 
						 | 
					dba02f8f08 | ||
| 
						 | 
					35e410fe96 | ||
| 
						 | 
					7dcd2313d8 | ||
| 
						 | 
					40750f2dc6 | ||
| 
						 | 
					85c007431b | ||
| 
						 | 
					cbd187369e | ||
| 
						 | 
					d20d89a0b9 | ||
| 
						 | 
					80eb37ef60 | ||
| 
						 | 
					d19cdc206b | ||
| 
						 | 
					02078255ea | ||
| 
						 | 
					bea2d40f79 | ||
| 
						 | 
					a5d3259cfe | ||
| 
						 | 
					4a93ce703e | ||
| 
						 | 
					661ea906d9 | ||
| 
						 | 
					b382b4cb94 | ||
| 
						 | 
					087e86fb32 | ||
| 
						 | 
					afffa76c17 | ||
| 
						 | 
					69ca18f36b | ||
| 
						 | 
					f84c62f0be | ||
| 
						 | 
					90c554ad42 | ||
| 
						 | 
					e2cb6cc4da | ||
| 
						 | 
					02da366cc2 | ||
| 
						 | 
					54e3a54489 | ||
| 
						 | 
					8798ec653d | ||
| 
						 | 
					d1ffd3cf35 | ||
| 
						 | 
					133b854f1b | ||
| 
						 | 
					33125e78c8 | ||
| 
						 | 
					4118bf1a5e | ||
| 
						 | 
					8282db456b | ||
| 
						 | 
					7b5eacf671 | ||
| 
						 | 
					12bd374477 | ||
| 
						 | 
					9ef4cc0ab9 | ||
| 
						 | 
					528fc9bc47 | ||
| 
						 | 
					c58b8498b3 | ||
| 
						 | 
					c81c564941 | ||
| 
						 | 
					b16de0e374 | ||
| 
						 | 
					d38f41a459 | ||
| 
						 | 
					30346884fe | ||
| 
						 | 
					1518dc9b60 | ||
| 
						 | 
					fd3f2289c3 | ||
| 
						 | 
					22bfd4f7c3 | ||
| 
						 | 
					2782011ce8 | ||
| 
						 | 
					7f17fcfafc | ||
| 
						 | 
					a40daa3c22 | ||
| 
						 | 
					1e366aa56e | ||
| 
						 | 
					bad8dbc2d2 | ||
| 
						 | 
					d0dd37fe94 | ||
| 
						 | 
					b2df3fcd1d | ||
| 
						 | 
					96f89ce4ae | ||
| 
						 | 
					e886a3d891 | ||
| 
						 | 
					0eaf141ae4 | ||
| 
						 | 
					291ef07cf3 | ||
| 
						 | 
					b9066ac997 | ||
| 
						 | 
					206f4604a4 | ||
| 
						 | 
					adbc1d97a0 | ||
| 
						 | 
					70ae700461 | ||
| 
						 | 
					b81ad3ed39 | ||
| 
						 | 
					77cdb17cee | ||
| 
						 | 
					d4e329b76d | ||
| 
						 | 
					fb24585dd8 | ||
| 
						 | 
					bd5efd5968 | ||
| 
						 | 
					650f35c1f3 | ||
| 
						 | 
					14e65168c9 | ||
| 
						 | 
					f00c47c21a | ||
| 
						 | 
					547d105b2e | ||
| 
						 | 
					de671103ca | ||
| 
						 | 
					2c48efa3fd | ||
| 
						 | 
					7f35b2dc43 | ||
| 
						 | 
					6ae914da2f | ||
| 
						 | 
					06ea78af1b | ||
| 
						 | 
					2ea12a7699 | ||
| 
						 | 
					8ab25de6c6 | ||
| 
						 | 
					e0424a7017 | ||
| 
						 | 
					f259162d64 | ||
| 
						 | 
					6bb5cdeb2f | ||
| 
						 | 
					384c30b6fd | ||
| 
						 | 
					67a75d4439 | ||
| 
						 | 
					0d963df7b3 | ||
| 
						 | 
					99efde5673 | ||
| 
						 | 
					c8ff699c4b | ||
| 
						 | 
					0718a888d0 | ||
| 
						 | 
					b7be4df603 | ||
| 
						 | 
					8bece0b49e | ||
| 
						 | 
					47d6edc3c8 | ||
| 
						 | 
					26bb56396d | ||
| 
						 | 
					dd99ed73a9 | ||
| 
						 | 
					36ce460a39 | ||
| 
						 | 
					e92c845dfd | ||
| 
						 | 
					492263c2e9 | ||
| 
						 | 
					0c99f66547 | ||
| 
						 | 
					df440496ee | ||
| 
						 | 
					09f2028d6a | ||
| 
						 | 
					05736ba0a1 | ||
| 
						 | 
					e5f05bc9d8 | ||
| 
						 | 
					cdd1209b55 | ||
| 
						 | 
					0e6458a630 | ||
| 
						 | 
					a1a068a377 | ||
| 
						 | 
					2c5657e8a9 | ||
| 
						 | 
					87fbd715a3 | ||
| 
						 | 
					fc8cba9598 | ||
| 
						 | 
					147725bf7a | ||
| 
						 | 
					06d2c0af35 | ||
| 
						 | 
					708f1a97dd | ||
| 
						 | 
					d8bd9f5a66 | ||
| 
						 | 
					079953c3ee | ||
| 
						 | 
					fea8b6da2f | ||
| 
						 | 
					4bf1df0894 | ||
| 
						 | 
					b4f16c4df8 | ||
| 
						 | 
					61282737c5 | ||
| 
						 | 
					d8c2290099 | ||
| 
						 | 
					830ab599df | ||
| 
						 | 
					0de5c5e8a3 | ||
| 
						 | 
					c6170ed751 | ||
| 
						 | 
					2ea762cfc9 | ||
| 
						 | 
					2646741297 | ||
| 
						 | 
					f5df5faf71 | ||
| 
						 | 
					cab9a580e8 | ||
| 
						 | 
					c8ac3fd4f5 | ||
| 
						 | 
					7f67c34b39 | ||
| 
						 | 
					e27293edbc | ||
| 
						 | 
					8d57c5052c | ||
| 
						 | 
					1314559833 | ||
| 
						 | 
					735397aa89 | ||
| 
						 | 
					c0d0c792e1 | ||
| 
						 | 
					43020b20b7 | ||
| 
						 | 
					0a3d80b86e | ||
| 
						 | 
					a9505d0426 | ||
| 
						 | 
					4d804c2a29 | ||
| 
						 | 
					e8eec2d357 | ||
| 
						 | 
					971e3f679f | ||
| 
						 | 
					7c90f078e7 | ||
| 
						 | 
					5957bd1abb | ||
| 
						 | 
					b16380e7e5 | ||
| 
						 | 
					b72a32c70d | ||
| 
						 | 
					90f15b3c5a | ||
| 
						 | 
					44bbf26cb2 | ||
| 
						 | 
					fcfd17e973 | ||
| 
						 | 
					73853cf147 | ||
| 
						 | 
					ddbc263da2 | ||
| 
						 | 
					982d8a0dc0 | ||
| 
						 | 
					5a269db9d5 | ||
| 
						 | 
					525da01a62 | ||
| 
						 | 
					12df10b2d0 | ||
| 
						 | 
					e6aee5d7ea | ||
| 
						 | 
					6ff69da0de | ||
| 
						 | 
					ebcb87c163 | ||
| 
						 | 
					79d9df9bb1 | ||
| 
						 | 
					8c40c2086a | ||
| 
						 | 
					f4a000cb59 | ||
| 
						 | 
					4029202635 | ||
| 
						 | 
					29d473f2fa | ||
| 
						 | 
					7ad89dc46b | ||
| 
						 | 
					4b2d6f8a99 | ||
| 
						 | 
					9b55de1c6b | ||
| 
						 | 
					8b45211a8f | ||
| 
						 | 
					f079501cff | ||
| 
						 | 
					e375e1789b | ||
| 
						 | 
					30d2cfdf56 | ||
| 
						 | 
					44d61e6857 | ||
| 
						 | 
					3466829766 | ||
| 
						 | 
					d3703516d9 | ||
| 
						 | 
					bdebaa986b | ||
| 
						 | 
					c2d400846b | ||
| 
						 | 
					034e147910 | ||
| 
						 | 
					25015c9c3a | ||
| 
						 | 
					43cf60f563 | ||
| 
						 | 
					057348763b | ||
| 
						 | 
					7230452e23 | ||
| 
						 | 
					438317c1e9 | ||
| 
						 | 
					cfe719c962 | ||
| 
						 | 
					44e2d88628 | ||
| 
						 | 
					6e50e77709 | ||
| 
						 | 
					02ed28d68d | ||
| 
						 | 
					73274e201b | ||
| 
						 | 
					f6fc88cc2d | ||
| 
						 | 
					d16acc43d9 | ||
| 
						 | 
					239aa7b8d5 | ||
| 
						 | 
					44a1bc5396 | ||
| 
						 | 
					821583acae | ||
| 
						 | 
					c6a2814881 | ||
| 
						 | 
					1954a02352 | ||
| 
						 | 
					8a28022a6b | ||
| 
						 | 
					43a243b24a | ||
| 
						 | 
					7c937c8704 | ||
| 
						 | 
					bdd1f82777 | ||
| 
						 | 
					cbb8876815 | ||
| 
						 | 
					f8cdaaae30 | ||
| 
						 | 
					74314bacd7 | ||
| 
						 | 
					04473f607b | ||
| 
						 | 
					88958270cb | ||
| 
						 | 
					856f7ecee9 | ||
| 
						 | 
					9f5584a157 | ||
| 
						 | 
					eda8a94d5b | ||
| 
						 | 
					5956b13588 | ||
| 
						 | 
					162d029c81 | ||
| 
						 | 
					7f3920dbb7 | ||
| 
						 | 
					6d07c3a1df | ||
| 
						 | 
					a0a83428cf | ||
| 
						 | 
					dc2cae07b2 | ||
| 
						 | 
					f8b44cd30e | ||
| 
						 | 
					c3eca3d754 | ||
| 
						 | 
					1ea005f6a6 | ||
| 
						 | 
					16a675b7ce | ||
| 
						 | 
					df2f939f3a | ||
| 
						 | 
					5743224817 | ||
| 
						 | 
					a80e88e33e | ||
| 
						 | 
					0207f1f29b | ||
| 
						 | 
					72120bb87f | ||
| 
						 | 
					7eaca86bf1 | ||
| 
						 | 
					db5f72c868 | ||
| 
						 | 
					69d6ae4141 | ||
| 
						 | 
					edabafc0fc | ||
| 
						 | 
					e9f2aa6010 | ||
| 
						 | 
					e054dd7813 | ||
| 
						 | 
					76d788a186 | ||
| 
						 | 
					3944df1bd2 | ||
| 
						 | 
					49f6280645 | ||
| 
						 | 
					84eb66d5aa | ||
| 
						 | 
					026fc531ba | ||
| 
						 | 
					8d14df0ced | ||
| 
						 | 
					f27547dcff | ||
| 
						 | 
					6f15d1c4c4 | ||
| 
						 | 
					46ffff8438 | ||
| 
						 | 
					8dcd08f47e | ||
| 
						 | 
					2515d5ad6c | ||
| 
						 | 
					e6b1853908 | ||
| 
						 | 
					e2b26c4014 | ||
| 
						 | 
					d4b7a3478e | ||
| 
						 | 
					e187961d72 | ||
| 
						 | 
					ae96b0c971 | ||
| 
						 | 
					c4dad3d2c1 | ||
| 
						 | 
					36287fc33b | ||
| 
						 | 
					edd5a5f185 | ||
| 
						 | 
					bb7388a7fe | ||
| 
						 | 
					797368bf9f | ||
| 
						 | 
					0cccf1d4cc | ||
| 
						 | 
					7aa326a836 | ||
| 
						 | 
					fe16f2b058 | ||
| 
						 | 
					af4fcc831e | ||
| 
						 | 
					868bf5838d | ||
| 
						 | 
					4282748483 | ||
| 
						 | 
					7790a07c08 | ||
| 
						 | 
					ef6cce8988 | ||
| 
						 | 
					df848fdb4d | ||
| 
						 | 
					b4489d9ea6 | ||
| 
						 | 
					1496d6af2f | ||
| 
						 | 
					52a05090bf | ||
| 
						 | 
					38235ecb97 | ||
| 
						 | 
					bf8b9b4906 | ||
| 
						 | 
					727f2ce994 | ||
| 
						 | 
					8b3309f4f6 | ||
| 
						 | 
					5e08b248e8 | ||
| 
						 | 
					0b1bf5f642 | ||
| 
						 | 
					8ed191283a | ||
| 
						 | 
					fefe2df6b5 | ||
| 
						 | 
					aff9b419cf | ||
| 
						 | 
					cae081950d | ||
| 
						 | 
					06bf8d3470 | ||
| 
						 | 
					a532b70f70 | ||
| 
						 | 
					cf85477864 | ||
| 
						 | 
					614176b269 | ||
| 
						 | 
					03401bbb58 | ||
| 
						 | 
					75ae209653 | ||
| 
						 | 
					8ce97961b4 | ||
| 
						 | 
					8ffe5957e5 | ||
| 
						 | 
					47e2c4ae6c | ||
| 
						 | 
					0065e2cfac | ||
| 
						 | 
					2ee4f57395 | ||
| 
						 | 
					e01971eac7 | ||
| 
						 | 
					d6e29be980 | ||
| 
						 | 
					6fbf8fa9e4 | ||
| 
						 | 
					c64242c276 | ||
| 
						 | 
					440b222664 | ||
| 
						 | 
					1c759384fa | ||
| 
						 | 
					602fa1c657 | ||
| 
						 | 
					d964d2baae | ||
| 
						 | 
					d235c205d6 | ||
| 
						 | 
					b1654af406 | ||
| 
						 | 
					29e5768f9b | ||
| 
						 | 
					3a6b4f3eb5 | ||
| 
						 | 
					84889d6dea | ||
| 
						 | 
					34ce17c4b3 | ||
| 
						 | 
					7723e59a72 | ||
| 
						 | 
					7f5135016e | ||
| 
						 | 
					08e0485213 | ||
| 
						 | 
					04afea76e3 | ||
| 
						 | 
					aa9a0aaf17 | ||
| 
						 | 
					3f792df631 | ||
| 
						 | 
					b36aa6f41b | ||
| 
						 | 
					6a5345aeed | ||
| 
						 | 
					b9cb37da5e | ||
| 
						 | 
					6207c68439 | ||
| 
						 | 
					0b149a941d | ||
| 
						 | 
					5e8f7ec590 | ||
| 
						 | 
					6e3c15e2ab | ||
| 
						 | 
					3bee2e4228 | ||
| 
						 | 
					89dcd9027d | ||
| 
						 | 
					102b2e2ca6 | ||
| 
						 | 
					998ea53b46 | ||
| 
						 | 
					2337373a17 | ||
| 
						 | 
					af29174cb6 | ||
| 
						 | 
					412c6bf4b5 | ||
| 
						 | 
					7fc6a3670c | ||
| 
						 | 
					70fbfea5f5 | ||
| 
						 | 
					9616b45518 | ||
| 
						 | 
					3916b5973d | ||
| 
						 | 
					5b3974b6b4 | ||
| 
						 | 
					e8e36e8a66 | ||
| 
						 | 
					88bcd0a9ce | ||
| 
						 | 
					29eb3215b3 | ||
| 
						 | 
					7c534a87cf | ||
| 
						 | 
					e9e30138bd | ||
| 
						 | 
					ddc135839b | ||
| 
						 | 
					474ff2e997 | ||
| 
						 | 
					0d2eb76cee | ||
| 
						 | 
					6172cd3627 | ||
| 
						 | 
					c71a6073e3 | ||
| 
						 | 
					91b0e28b28 | ||
| 
						 | 
					e15a9f2e73 | ||
| 
						 | 
					cac134076b | ||
| 
						 | 
					39e67016b5 | ||
| 
						 | 
					c72241df5b | ||
| 
						 | 
					a78e75775d | ||
| 
						 | 
					91b84e0b06 | ||
| 
						 | 
					3403215698 | ||
| 
						 | 
					260e6662f0 | ||
| 
						 | 
					5137cee3d6 | ||
| 
						 | 
					9915038e9b | ||
| 
						 | 
					7ddf54c4d3 | ||
| 
						 | 
					cc72819579 | ||
| 
						 | 
					6d902633e9 | ||
| 
						 | 
					be775b9206 | ||
| 
						 | 
					15ec185be5 | ||
| 
						 | 
					e1f33739b0 | ||
| 
						 | 
					dff8d579ca | ||
| 
						 | 
					ef2265de4f | ||
| 
						 | 
					f7b4f99d4c | ||
| 
						 | 
					d5735496af | ||
| 
						 | 
					3755783d41 | ||
| 
						 | 
					5b8d3ba1d6 | ||
| 
						 | 
					63be52e191 | ||
| 
						 | 
					d15122c4b2 | ||
| 
						 | 
					6d6ec46f25 | ||
| 
						 | 
					8d78c3a2ab | ||
| 
						 | 
					7077e57d53 | ||
| 
						 | 
					031e606972 | ||
| 
						 | 
					d6601645d6 | ||
| 
						 | 
					97bb5b6680 | ||
| 
						 | 
					adb04eb010 | ||
| 
						 | 
					ff171e3651 | ||
| 
						 | 
					172d68d1fe | ||
| 
						 | 
					885f668d53 | ||
| 
						 | 
					7cf311dac0 | ||
| 
						 | 
					259c84ed9a | ||
| 
						 | 
					196d10454a | ||
| 
						 | 
					06198702c2 | ||
| 
						 | 
					12d991f336 | ||
| 
						 | 
					2b740dc34c | ||
| 
						 | 
					855bbd523c | ||
| 
						 | 
					a2a72d1998 | ||
| 
						 | 
					9a048af1fb | ||
| 
						 | 
					697139043f | ||
| 
						 | 
					29ce02b1d2 | ||
| 
						 | 
					60ae784c01 | ||
| 
						 | 
					e3511127c7 | ||
| 
						 | 
					fbf7528728 | ||
| 
						 | 
					e46a26aec1 | 
							
								
								
									
										29
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -3,11 +3,11 @@
 | 
			
		||||
*.o
 | 
			
		||||
.deps
 | 
			
		||||
.libs
 | 
			
		||||
ABOUT-NLS
 | 
			
		||||
ChangeLog
 | 
			
		||||
INSTALL
 | 
			
		||||
Makefile
 | 
			
		||||
Makefile.in
 | 
			
		||||
NEWS
 | 
			
		||||
aclocal.m4
 | 
			
		||||
autom4te.cache
 | 
			
		||||
config.h
 | 
			
		||||
@@ -21,6 +21,19 @@ data/gnome-shell.desktop.in
 | 
			
		||||
data/gschemas.compiled
 | 
			
		||||
data/org.gnome.shell.gschema.xml
 | 
			
		||||
data/org.gnome.shell.gschema.valid
 | 
			
		||||
docs/reference/*/*.args
 | 
			
		||||
docs/reference/*/*.bak
 | 
			
		||||
docs/reference/*/*.hierarchy
 | 
			
		||||
docs/reference/*/*.interfaces
 | 
			
		||||
docs/reference/*/*.prerequisites
 | 
			
		||||
docs/reference/*/*.sgml
 | 
			
		||||
docs/reference/*/*.signals
 | 
			
		||||
docs/reference/*/*.stamp
 | 
			
		||||
docs/reference/*/*.txt
 | 
			
		||||
docs/reference/*/*.types
 | 
			
		||||
docs/reference/*/html/
 | 
			
		||||
docs/reference/*/xml/
 | 
			
		||||
gtk-doc.make
 | 
			
		||||
js/misc/config.js
 | 
			
		||||
intltool-extract.in
 | 
			
		||||
intltool-merge.in
 | 
			
		||||
@@ -30,8 +43,13 @@ m4/
 | 
			
		||||
omf.make
 | 
			
		||||
po/*.gmo
 | 
			
		||||
po/gnome-shell.pot
 | 
			
		||||
po/*.header
 | 
			
		||||
po/*.sed
 | 
			
		||||
po/*.sin
 | 
			
		||||
po/Makefile.in.in
 | 
			
		||||
po/Makevars.template
 | 
			
		||||
po/POTFILES
 | 
			
		||||
po/Rules-quot
 | 
			
		||||
po/stamp-it
 | 
			
		||||
scripts/launcher.pyc
 | 
			
		||||
src/*.gir
 | 
			
		||||
@@ -40,8 +58,15 @@ src/*-enum-types.[ch]
 | 
			
		||||
src/*-marshal.[ch]
 | 
			
		||||
src/Makefile
 | 
			
		||||
src/Makefile.in
 | 
			
		||||
src/gnomeshell-taskpanel
 | 
			
		||||
src/calendar-server/org.gnome.Shell.CalendarServer.service
 | 
			
		||||
src/gnome-shell
 | 
			
		||||
src/gnome-shell-calendar-server
 | 
			
		||||
src/gnome-shell-extension-tool
 | 
			
		||||
src/gnome-shell-hotplug-sniffer
 | 
			
		||||
src/gnome-shell-jhbuild
 | 
			
		||||
src/gnome-shell-perf-helper
 | 
			
		||||
src/gnome-shell-real
 | 
			
		||||
src/hotplug-sniffer/org.gnome.Shell.HotplugSniffer.service
 | 
			
		||||
src/run-js-test
 | 
			
		||||
src/test-recorder
 | 
			
		||||
src/test-recorder.ogg
 | 
			
		||||
 
 | 
			
		||||
@@ -3,5 +3,5 @@ E-mail: otaylor@redhat.com
 | 
			
		||||
Userid: otaylor
 | 
			
		||||
 | 
			
		||||
Colin Walters
 | 
			
		||||
E-mail: walters@redhat.com
 | 
			
		||||
E-mail: walters@verbum.org
 | 
			
		||||
Userid: walters
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
# Point to our macro directory and pick up user flags from the environment
 | 
			
		||||
ACLOCAL_AMFLAGS  = -I m4 ${ACLOCAL_FLAGS}
 | 
			
		||||
 | 
			
		||||
SUBDIRS = data js src tests po man
 | 
			
		||||
SUBDIRS = data js src browser-plugin tests po man docs
 | 
			
		||||
 | 
			
		||||
EXTRA_DIST =		\
 | 
			
		||||
	.project	\
 | 
			
		||||
@@ -19,3 +19,5 @@ DIST_EXCLUDE =					\
 | 
			
		||||
distcheck-hook:
 | 
			
		||||
	@echo "Checking disted files against files in git"
 | 
			
		||||
	@$(srcdir)/tools/check-for-missing.py $(srcdir) $(distdir) $(DIST_EXCLUDE)
 | 
			
		||||
 | 
			
		||||
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										680
									
								
								NEWS
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,680 @@
 | 
			
		||||
3.3.2
 | 
			
		||||
=====
 | 
			
		||||
* Port D-Bus usage in the shell to GDBus [Giovanni, Marc-Antoine, Florian,
 | 
			
		||||
  Jasper, Matthias; #648651, #658078, #663902, #663941]
 | 
			
		||||
* Message tray
 | 
			
		||||
  - Add right-click option to chats to mute the conversation [Ana; #659962]
 | 
			
		||||
  - Don't steal the focus when popping up under the pointer [Rui; #661358]
 | 
			
		||||
* Looking Glass
 | 
			
		||||
  - Add alt-Tab completion [Jason; #661054]
 | 
			
		||||
  - Show errors from extensions in the extensions tab [Jasper; #660546]
 | 
			
		||||
  - Allow switching tabs with <Control>PageUp/PageDown
 | 
			
		||||
  - Theme consistently with the rest of the shell [Jason; 650900]
 | 
			
		||||
* Extension system
 | 
			
		||||
  - Don't try to load disabled extensions at all [Jasper; #661815, #662704]
 | 
			
		||||
  - Enable and disable plugins in a consistent order [Jasper; #661815, #662704]
 | 
			
		||||
  - Add options to enable/disable extensions to gnome-shell-extension-tool
 | 
			
		||||
    [Jasper; #661815]
 | 
			
		||||
* Adapt to Mutter change to GSettings [Florian, Matthias; #663429]
 | 
			
		||||
* Allow creating a new workspace by dragging a window or launcher in the
 | 
			
		||||
  middle of two existing ones [Jasper; #646409]
 | 
			
		||||
* Allow using Alt-Tab while during drag-and-drop and other operations
 | 
			
		||||
  that grab the pointer [Adel; #660457]
 | 
			
		||||
* Do a better job of finding the right user to authenticate
 | 
			
		||||
  as when showing a PolKit dialog [Matthias; #651547]
 | 
			
		||||
* Control the D-Bus Eval() method by the developer-tools GSetting which
 | 
			
		||||
  is used for looking glass and screen recorder. [Jasper; #662891]
 | 
			
		||||
* Fix browser plugin to work under WebKit-based browser [Jasper; #663823]
 | 
			
		||||
* Fix certain stacking issues with alt-Tab [Jasper; #660650]
 | 
			
		||||
* Fixes for GLib deprecations [Jasper; #662011]p
 | 
			
		||||
* Fixes for GTK+ deprecations [Florian, Rico; #662245]p
 | 
			
		||||
* Fixes for Clutter deprecations [Jasper; #662627]
 | 
			
		||||
* Visual improvements and UI tweaks [Florian, Jakub, Jasper;
 | 
			
		||||
  #662800, #658096, #662226]
 | 
			
		||||
* Hard-code "Home" as the name for the home dir, rather than looking
 | 
			
		||||
  it up via GSettings; avoids schema dependency [Cosimo; #559895]
 | 
			
		||||
* Don't show "Switch User" on single user machines [Florian; #657011]
 | 
			
		||||
* Generate documentation for St toolkit [Florian]
 | 
			
		||||
* Improve marking of strings for translation [Matthias, Piotr; #658664]
 | 
			
		||||
* Networking menu bug fixes [Giovanni; #650007, #651378, #659277, #663278]
 | 
			
		||||
* Code cleanups and leak fixes to StTextureCache
 | 
			
		||||
  [Jasper, Florian; #660968, #662998]
 | 
			
		||||
* Code cleanups [Adel, Florian, Jasper; #662238, #663584]
 | 
			
		||||
* Build fixes [Adel, Colin, Florian, Ming Han]
 | 
			
		||||
* Misc bug fixes [Adel, Florian, "Fry", Jasper, Giovanni, Ray, Rui, Stefan;
 | 
			
		||||
  #660520, #661029, #661231, #661623, #661921, #662235, #662236, #662502,
 | 
			
		||||
  #662394, #662799, #662969, #663175, #663277, #663815, #663891, #662967]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Giovanni Campagna, Cosimo Cecchi, Matthias Clasen, Piotr Drąg, Adel Gadllah,
 | 
			
		||||
 Rui Matos, Florian Müllner, Marc-Antoine Perennou, Ana Risteska,
 | 
			
		||||
 Jason Siefken, Jakub Steiner, Ray Strode, Jasper St. Pierre, Ming Han Teh,
 | 
			
		||||
 Rico Tzschichholz, Colin Walters, Stefan Zwanenburg
 | 
			
		||||
 | 
			
		||||
Translation:
 | 
			
		||||
 Alexander Shopov [bg], Marek Černocký [cs], Mario Blättermann [de],
 | 
			
		||||
 Kostas Papadimas [el], Bruce Cowan [en_GB], Kristjan Schmidt [eo],
 | 
			
		||||
 Jorge González, Daniel Mustieles, Benjamín Valero Espinosa [es],
 | 
			
		||||
 Mattias Põldaru [et], Arash Mousavi [fa], Ville-Pekka Vainio [fi],
 | 
			
		||||
 Fran Diéguez [gl], Yaron Shahrabani [he], Hideki Yamane [ja],
 | 
			
		||||
 Algimantas Margevičius [lt], Kjartan Maraas [nb], Daniel Nylander [se],
 | 
			
		||||
 Matej Urbančič [sl], Praveen Illa [te], Muhammet Kara [tr],
 | 
			
		||||
 Nguyễn Thái Ngọc Duy [vi], Cheng-Chia Tseng [zh_HK, zh_TW]
 | 
			
		||||
 | 
			
		||||
3.2.1
 | 
			
		||||
=====
 | 
			
		||||
* Restore the IM state on startup - if you were available in when you logged
 | 
			
		||||
  out, then you'll be set available again when you log in.
 | 
			
		||||
  [Florian; #65902, #661485]
 | 
			
		||||
* Improve searching for contacts in the overview: search more fields,
 | 
			
		||||
  show a more meaningful name, require that all search terms match.
 | 
			
		||||
  [Florian, Matthias; #660580]
 | 
			
		||||
* Improve search for applications in the overview: take frequency into
 | 
			
		||||
  account and tweak match algorithm [Florian; #623372]
 | 
			
		||||
* Remove the "Show Password" switch from network password prompts, and
 | 
			
		||||
  move the functionality to a right-click menu [Florian; #658948]
 | 
			
		||||
* Add context menus with Cut/Paste options to most entries [Florian; #659275]
 | 
			
		||||
* On screen keyboard:
 | 
			
		||||
 - Show the keyboard immediately when it's turned enabled [Dan; #659743]
 | 
			
		||||
 - Fix problem where keyboard would hide when starting to type
 | 
			
		||||
   in the search entry [Nohemi; #661340]
 | 
			
		||||
 - Fix problem with keyboard hiding when selected accented characters
 | 
			
		||||
   [Nohemi; 661707]
 | 
			
		||||
* Login mode:
 | 
			
		||||
  - Allow hitting Enter to select the first user [Ray; #657996]
 | 
			
		||||
  - Fix flicker of a fingerprint prompt that could show up [Ray; #660492]
 | 
			
		||||
  - Fix password bullets vanishing during login [Ray; #657894]
 | 
			
		||||
  - Misc bug fixes and visual tweaks [Ray; #659763, #660919, #661479]
 | 
			
		||||
* Display a caps-lock warning in password entries [Florian; #660806]
 | 
			
		||||
* Show the state of installed extensions in Looking Glass [Jasper; #660494]
 | 
			
		||||
* Load user extensions after system ones [Jasper; #661815]
 | 
			
		||||
* Fix problem with many applications showing extra-large icons in
 | 
			
		||||
  notifications [Marina; #659158]
 | 
			
		||||
* Fix a problem where alt-Tab had trouble tracking the current
 | 
			
		||||
  application with certain applications such as Emacs. [Dan; #645026]
 | 
			
		||||
* Fix confusion between different users avatar images [Florian; #660585]
 | 
			
		||||
* Remove behavior where you could switch workspaces by bumping
 | 
			
		||||
  a dragged window in the overview against a screen edge; it was
 | 
			
		||||
  leftover and just confusing. [Florian; #660838]
 | 
			
		||||
* Fix long-standing bug where the Dash in the overview could end up mis-sized
 | 
			
		||||
  and run off the screen [Florian; #649248]
 | 
			
		||||
* Fix automatic launching of applications when media is inserted
 | 
			
		||||
  [Cosimo; #660821]
 | 
			
		||||
* Fix handling of vertically stacked monitors with NVIDIA drivers
 | 
			
		||||
  [Florian; #661387]
 | 
			
		||||
* Translation marking fixes [Jasper, Wouter; #660600]
 | 
			
		||||
* Code cleanups and warning fixes [Adel, Dan, Florian, Jasper;
 | 
			
		||||
  #659822, #659940, #660122, #660358, #660968, #661231]
 | 
			
		||||
* Small memory leak fixes [Florian, Jasper; #661231]
 | 
			
		||||
* Misc bug fixes [Adel, Florian, Jasper; #659274, #659861, #660166, #660310,
 | 
			
		||||
  #660397, #660608,  #660606, #660674, #660774. #660848, #661151, #661617]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Wouter Bolsterlee, Cosimo Cecchi, Matthias Clasen, Nohemi Fernandez,
 | 
			
		||||
  Adel Gadllah, Florian Müllner, Jasper St. Pierre, Ray Strode, Dan Winship,
 | 
			
		||||
  Marina Zhurakhinskaya
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Tiffany Antopolski [eo], Xandru Armesto [ast], Alexander Shopov,
 | 
			
		||||
 Ivaylo Valkov [bg], Gil Forcada [ca], Carles Ferrando [ca@valencia],
 | 
			
		||||
 Mario Blättermann, Paul Seyfert [de], Bruce Cowan [en_GB],
 | 
			
		||||
 Jorge González, Daniel Mustieles [es], Arash Mousavi [fa], Bruno Brouard [fr],
 | 
			
		||||
 Seán de Búrca [ga], Fran Diéguez [gl], Gabor Kelemen [hu], Luca Ferretti [it],
 | 
			
		||||
 Takayuki Kusano [ja], Changwoo Ryu [ko], Erdal Ronahi [ku],
 | 
			
		||||
 Algimantas Margevičius [lt], Rudolfs Mazurs [lv], Wouter Bolsterlee [nl],
 | 
			
		||||
 Piotr Drąg [pl], Adorilson Bezerra [pt_BR], Yuri Myasoedov [ru],
 | 
			
		||||
 Matej Urbančič [sl], Daniel Nylander [sv], Miroslav Nikolić [sr, sr@latin],
 | 
			
		||||
 Tirumurti Vasudevan [ta], Krishnababu Krothapalli [te], Daniel Korostil [uk],
 | 
			
		||||
 Nguyễn Thái Ngọc Duy [vi], YunQiang Su [zh_CN]
 | 
			
		||||
 | 
			
		||||
3.2.0
 | 
			
		||||
=====
 | 
			
		||||
* Prevent the fallback on-screen keyboard from showing up while
 | 
			
		||||
  GNOME Shell is running [Dan, #659865]
 | 
			
		||||
* Disable code to reposition windows around the on-screen keyboard;
 | 
			
		||||
  it wasn't finished or working properly. [Dan; #659643]
 | 
			
		||||
* Fix interaction between on-screen keyboard and notifications
 | 
			
		||||
  [Dan; #658603]
 | 
			
		||||
* Fix menu-sizing problems in right-to-left locales. [Florian; #659827]
 | 
			
		||||
* Update chat icons in the message tray when an avatar image changes
 | 
			
		||||
  [Marina; #659768]
 | 
			
		||||
* Fix problem with empty notification bubbles being left [Marina; #659862]
 | 
			
		||||
* Fix problem with chat notifications bouncing when new messages come in.
 | 
			
		||||
  [Marina; #659768]
 | 
			
		||||
* Fix bug that was causing SIP calls to automatically be accepted in some
 | 
			
		||||
  circumstances [Guillaume; #660084]
 | 
			
		||||
* Fix string that should have been marked translatable [Frédéric]
 | 
			
		||||
* Fix a crash that could happen during CSS transitions [Florian; #659676]
 | 
			
		||||
* Build fixes [Colin, Florian]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Guillaume Desmottes, Florian Müllner, Frédéric Péters, Colin Walters,
 | 
			
		||||
 Dan Winship, Marina Zhurakhinskaya
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Friedel Wolff [af], Nilamdyuti Goswami [as], Ihar Hrachyshka [be],
 | 
			
		||||
 Ivaylo Valkov [bg], Gil Forcada [ca], Carles Ferrando [ca@valencia],
 | 
			
		||||
 Petr Kovar [cz], Mario Blättermann [de], Kris Thomsen [dk],
 | 
			
		||||
 Tiffany Antopolski, Kristjan Schmidt [eo], Daniel Mustieles [es],
 | 
			
		||||
 Inaki Larranaga Murgoitio [eu], Tommi Vainikainen [fi], Bruno Brouard [fr],
 | 
			
		||||
 Fran Dieguez [gl], Yaron Shahrabani [he], Gabor Kelemen [hu],
 | 
			
		||||
 Andika Triwidada [id], Jiro Matsuzawa [ja], Changwoo Ryu [ko],
 | 
			
		||||
 Rudolfs Mazurs [lv], Aurimas Černius [lt], Kjartan Maraas [nb],
 | 
			
		||||
 A S Alam [pa], Piotr Drąg [pl], Duarte Loreto [pt], Djavan Fagundes,
 | 
			
		||||
 Rodolfo Ribeiro Gomes, Gabriel F. Vilar [pt_BR], Yuri Myasoedov [ru],
 | 
			
		||||
 Daniel Nylander [se], Martin Srebotnjak [sl], Michal Štrba [sv],
 | 
			
		||||
 Krishnababu Krothapalli, Praveen Illa [te], Cheng-Chia Tseng [zh_KH, zh_TW]
 | 
			
		||||
 | 
			
		||||
3.1.92
 | 
			
		||||
======
 | 
			
		||||
 | 
			
		||||
* Login screen
 | 
			
		||||
  - Add the ability to set a logo at the top of the user list [Ray; #658062]
 | 
			
		||||
  - Add fingerprint reader support [Ray; #657823]
 | 
			
		||||
  - Add a power button offering the choice of Suspend/Restart/Power off
 | 
			
		||||
    [Ray; #657822]
 | 
			
		||||
  - Remove the option to view the current keyboad layout [Matthias; #659164]
 | 
			
		||||
  - Make Control-Alt-Tab work for full keyboard access [Ray; #659177]
 | 
			
		||||
* Frequently initiate a full garbage collection; Spidermonkey isn't very good
 | 
			
		||||
  at tracking the amount of resources we have allocated so this hopefully will
 | 
			
		||||
  improve memory usage without affecting performance too much [Colin; #659254]
 | 
			
		||||
* Stop adding a notification when the network connection is lost
 | 
			
		||||
  [Colin; #658954]
 | 
			
		||||
* When disabling notifications; display a notification
 | 
			
		||||
  "Your chat status will be set to busy" [Florian; #652718]
 | 
			
		||||
* Fix keynav in network dialogs [Florian; #659133]
 | 
			
		||||
* Improve calendar styling [Sean; #641135, #651299]
 | 
			
		||||
* Shrink padding around panel buttons for narrow screens [Dan; #651299]
 | 
			
		||||
* Allow enabling the onscreen keyboard through the accessibility menu
 | 
			
		||||
  [Dan; #612662]
 | 
			
		||||
* Fix problem that was causing VPN secret dialogs to be delayed before showing
 | 
			
		||||
  [Florian; #658484]
 | 
			
		||||
* Make custom-keybindings for the window switcher that don't use alt
 | 
			
		||||
  work correctly [Florian; #645200]
 | 
			
		||||
* Fix duplicate application icons in the Activities Overview [Colin; #659351]
 | 
			
		||||
* Bug fixes for dimming windows with attached modal dialogs
 | 
			
		||||
  [Jasper, Owen; #659302, 659634]
 | 
			
		||||
* Add build-time support for BROWSER_PLUGIN_DIR environment variable
 | 
			
		||||
  [Vincent; #659123]
 | 
			
		||||
* Build fixes [Vincent; #659194]
 | 
			
		||||
* Code cleanups and test cases
 | 
			
		||||
  [Adel, Dan, Florian, Jasper; #651299, #658092, #658939]
 | 
			
		||||
* Misc bug fixes
 | 
			
		||||
  [Adel, Colin, Cosimo, Dan, Florian, Giovanni, Jasper, Ray, Xavier;
 | 
			
		||||
  #651299, #652837, #657249, #658004, #658150, #658239, #658469, #658598,
 | 
			
		||||
  #658605, #659050, #659159, #659210, #659270, #659370, #659633]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Giovanni Campagna, Cosimo Cecchi, Xavier Claessens, Matthias Clasen,
 | 
			
		||||
 Rui Matos, Florian Müllner, Jasper St. Pierre, Owen Taylor,
 | 
			
		||||
 Vincent Untz, Colin Walters, Sean Wilson, Dan Winship
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Ihar Hrachyshka [be], Alexander Shopov, Ivaylo Valkov [bg],
 | 
			
		||||
 Mario Blättermann [de], Jorge González, Daniel Mustieles [es],
 | 
			
		||||
 Arash Mousavi [fa], Ville-Pekka Vainio [fi], Fran Dieguez [gl],
 | 
			
		||||
 Sweta Kothari [gu], Gabor Kelemen [hu], Jiro Matsuzawa [ja],
 | 
			
		||||
 Luca Ferretti [it], Rudolfs Mazurs [lv], Kjartan Maraas [nb], A S Alam [pa],
 | 
			
		||||
 Piotr Drąg [pl], Duarte Loreto [pt], Yuri Myasoedov [ru],
 | 
			
		||||
 Daniel Nylander [se], Matej Urbančič [sl], Miroslav Nikolić [sr, sr@latin],
 | 
			
		||||
 Michal Štrba [sv], Tirumurti Vasudevan [ta], Phương Lê Hoàng [vi],
 | 
			
		||||
 Aron Xu [zh_CN], Chao-Hsiung Liao [zh_HK, zh_TW]
 | 
			
		||||
 | 
			
		||||
3.1.91.1
 | 
			
		||||
========
 | 
			
		||||
 | 
			
		||||
* Add a browser plugin - this plugin, tied to extensions.gnome.org,
 | 
			
		||||
  allows users to download and install shell extensions, and enable,
 | 
			
		||||
  disable, and uninstall extensions they already have installed.
 | 
			
		||||
  [Jasper; #658070, #658612]
 | 
			
		||||
* Improve adding links to URLs in notifications [Dan; #636252]
 | 
			
		||||
* Remove "connection lost" notifications after reconnecting [Giovanni; #658049]
 | 
			
		||||
* Hide the onscreen keyboard when leaving a text entry [Dan; #658591]
 | 
			
		||||
* Fixes for translated strings [Florian; #639987, #644097, #645037]
 | 
			
		||||
* Bug fixes for network menu [Florian; #658492]
 | 
			
		||||
* Code cleanup [Dan; #646934]
 | 
			
		||||
* Build fixes [Javier, Rico]
 | 
			
		||||
* Misc bug fixes [Emmanuele, Florian, Jasper, Marina, Matthias, Ray;
 | 
			
		||||
  #652837, #658423, #658503, #658525, #658562, #658624, #658640, #658983]
 | 
			
		||||
 | 
			
		||||
Conributors:
 | 
			
		||||
 Emmanuele Bassi, Giovanni Campagna, Matthias Clasen, Javier Jardón,
 | 
			
		||||
 Florian Muellner, Jasper St. Pierre, Ray Strode, Rico Tzschichholz,
 | 
			
		||||
 Dan Winship, Marina Zhurakhinskaya
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Ihar Hrachyshka [be], Bruce Cowan [en_GB], Jorge González,
 | 
			
		||||
 Daniel Mustieles [es], Timo Jyrinki [fi], Bruno Brouard, Luc Guillemin,
 | 
			
		||||
 Claude Paroz, Luc Pionchon [fr], Fran Dieguez [gl], Rajesh Ranjan [hi],
 | 
			
		||||
 Andika Triwidada [id], Luca Ferretti [it], Changwoo Ryu [ko],
 | 
			
		||||
 Rudolfs Mazurs [lt], Kjartan Maraas [nb], Manoj Kumar Giri [or],
 | 
			
		||||
 A S Alam [pa], Piotr Drąg [pl], Duarte Loreto [pt], Henrique P. Machado,
 | 
			
		||||
 Gabriel F. Vilar [pt_BR], Daniel Nylander [se], Matej Urbančič [sl],
 | 
			
		||||
 Tirumurti Vasudevan [ta], Yinghua Wang [zh_CN],
 | 
			
		||||
 Chao-Hsiung Liao [zh_HK, zh_TW]
 | 
			
		||||
 | 
			
		||||
3.1.91
 | 
			
		||||
======
 | 
			
		||||
 | 
			
		||||
* Fix problem with applications vanishing from alt-Tab when
 | 
			
		||||
  desktop files change. [Colin; #657990]
 | 
			
		||||
* Fix interaction of on-screen keyboard with run-dialog and
 | 
			
		||||
  Looking Glass console [Dan; #657986]
 | 
			
		||||
* Add public API for adding and removing search providers
 | 
			
		||||
  [Philippe; #657548, #658113]
 | 
			
		||||
* Allow changing IM status with scroll wheel [Florian; #657973]
 | 
			
		||||
* Limit volume slider to 100% [Bastien; #657607]
 | 
			
		||||
* Change "Do Not Disturb" to "Notifications" in user menu [Florian; #652718]
 | 
			
		||||
* Switch browser in default favorites to Epiphany [Colin; #650616]
 | 
			
		||||
* Misc bug fixes [Dan, Florian, Jasper, Marc-Antoine, Rui;
 | 
			
		||||
  #649631, #655069, #656142, #657703, #657759, #658007, #658065, #658176]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Rui Matos, Florian Müllner, Philippe Normand, Marc-Antoine Perennou,
 | 
			
		||||
 Jasper St. Pierre, Colin Walters, Dan Winship
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Ihar Hrachyshka [be], Mario Blättermann [de], Kris Thomsen [da],
 | 
			
		||||
 Jorge González [es], Arash Mousavi [fa], Fran Dieguez [gl],
 | 
			
		||||
 Takayuki Kusano [ja],Aurimas Černius [lt], Kjartan Maraas [nb], A S Alam [pa],
 | 
			
		||||
 Stas Solovey [ru], Daniel Nylander [se], Tirumurti Vasudevan [ta],
 | 
			
		||||
 Chao-Hsiung Liao [zh_HK, zh_TW]
 | 
			
		||||
 | 
			
		||||
3.1.90.1
 | 
			
		||||
========
 | 
			
		||||
 | 
			
		||||
* Fix typo that was breaking the "Login Screen" mode [Marc-Antoine]
 | 
			
		||||
* Fix build with new gobject-introspection [Dan]
 | 
			
		||||
* Use a better icon for removable devices [Cosimo; #657757]
 | 
			
		||||
* Add support for asynchronous search provides [Philippe, Jasper, Seif; #655220]
 | 
			
		||||
* Misc bug fixes [Alex, Guillaume, Jasper; #657657, #657696]
 | 
			
		||||
* Misc build fixes [Adel; #657697]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Cosimo Cecchi, Guillaume Desmottes, Adel Gadllah, Alexander Larsson, Seif Lotfy,
 | 
			
		||||
 Philippe Normand, Marc-Antoine Perennou, Jasper St. Pierre, Dan Winship
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Jorge González, Daniel Mustieles [es], Stas Solovey [ru]
 | 
			
		||||
 | 
			
		||||
3.1.90
 | 
			
		||||
======
 | 
			
		||||
* Add an on-screen keyboard that uses Caribou as a backend
 | 
			
		||||
  [Nohemi, Dan; #612662]
 | 
			
		||||
* Allow searching for people in the overview using libfolks
 | 
			
		||||
  as the backend [Morten; #643018]
 | 
			
		||||
* Add a "Login Screen" mode to be used when GDM is running; this
 | 
			
		||||
  mode has a stripped down user interface, and also contains the
 | 
			
		||||
  code to display the user list and authentication. [Ray; #657082]
 | 
			
		||||
* Rework user menu to separate out "Do Not Disturb" from the IM
 | 
			
		||||
  status and to visually match GNOME Contacts. [Florian; #652837]
 | 
			
		||||
* Implement displaying images such as cover-art in notifications
 | 
			
		||||
  [Neha, Marina; #621009]
 | 
			
		||||
* Support default actions for notifications [Florian; #655818]
 | 
			
		||||
* Networking
 | 
			
		||||
  - Stop using nm-applet for dialogs; do them as proper system modal
 | 
			
		||||
    dialogs in the shell code. [Giovanni; #650244]
 | 
			
		||||
  - Fix handling of hidden access points [Giovanni; #646454]
 | 
			
		||||
* Telepathy integration
 | 
			
		||||
  - Support subscription requests [Guillaume, Xavier; #653941]
 | 
			
		||||
  - Notify on account connection errors [Alban, Jasper, Xavier; #654159]
 | 
			
		||||
  - Allow approving file transfers [Guillaume; #653940]
 | 
			
		||||
  - Improve styling of messages [Jasper; #640271]
 | 
			
		||||
* Extension system [Jasper; #654770]
 | 
			
		||||
  - Support live enabling and disabling of extensions
 | 
			
		||||
  - Add the ability to install extensions from HTTP
 | 
			
		||||
  - Enhance D-Bus interface for controlling extensions
 | 
			
		||||
  - Collect errors separately for each extension
 | 
			
		||||
* Add Main.panel.addToStatusArea for extension convenience
 | 
			
		||||
  [Giovanni, Jasper, Marc-Antoine; #653205]
 | 
			
		||||
* Port to the new gnome-menus API. Clean up and speed up
 | 
			
		||||
  application information loading [Colin; #648149, #656546]
 | 
			
		||||
* Use the accountsservice library rather than cut-and-pasted GDM code
 | 
			
		||||
  [Florian; #650893]
 | 
			
		||||
* Add a D-Bus interface to take a screenshot; this will avoid various race
 | 
			
		||||
  conditions with the current gnome-screenshot approach [Adel; #652952]
 | 
			
		||||
* Show numeric indicators to distinguish duplicate keyboard names
 | 
			
		||||
  [Giovanni; #650128]
 | 
			
		||||
* Add GNOME Documents to the favorites list [Adel; #657520]
 | 
			
		||||
* Update the clock immediately on resume from suspend [Colin; #656403]
 | 
			
		||||
* Remove animation support from StAdjustment [Ray; #657082]
 | 
			
		||||
* Support configuration of calendar applications via gsettings
 | 
			
		||||
  [Tassilo; #651190]
 | 
			
		||||
* Don't fade in alt-Tab - wait a bit and show it instantly [Rui; #652346]
 | 
			
		||||
* Darken workspace background on all workspaces [Rui; #656433]
 | 
			
		||||
* Improve detection of the starting day of the week [Florian; #649078]
 | 
			
		||||
* Add StButtonAccessible [Alejandro]
 | 
			
		||||
* Visual tweaks to match mockups
 | 
			
		||||
  [Allan, Dan, Jasper, Marina; #640271, #655627, #655428, #656732]
 | 
			
		||||
* Misc bug fixes [Dan, Florian, Giovanni, Guillaume, Jasper, Jeremy, Rui;
 | 
			
		||||
  #645708, #646761, #653119, #654398, #656125, #654707, #654898, #654638,
 | 
			
		||||
  #656335, #657111]
 | 
			
		||||
* Code cleanups [Colin, Dan, Guillaume, Ray;
 | 
			
		||||
  #652718, #654639, #648651, #655813, #657082]
 | 
			
		||||
* String tweaks [Jasper, Jeremy; #652984, #640271]
 | 
			
		||||
* Build fixes [Jasper, Nohemi; #644275, #655812]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Jeremy Bicha, Giovanni Campagna, Xavier Claessens, Alban Crequy,
 | 
			
		||||
 Guillaume Desmottes, Allan Day, Neha Doijode, Nohemi Fernandez,
 | 
			
		||||
 Tassilo Horn, Rui Matos, Morten Mjelva, Florian Müllner, Alejandro Piñeiro,
 | 
			
		||||
 Jasper St. Pierre, Ray Strode, Colin Walters, Dan Winship,
 | 
			
		||||
 Marina Zhurakhinskaya
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Ivaylo Valkov [bg], Mario Blättermann [de], Diego Escalante Urrelo,
 | 
			
		||||
 Jorge González, Daniel Mustieles [es], Arash Mousavi [fa], Fran Dieguez [gl],
 | 
			
		||||
 Yaron Shahrabani [he], Andika Triwidada, Wibiharto [id],
 | 
			
		||||
 Aurimas Černius [lt], Umarzuki Bin Mochlis Moktar [ml], Kjartan Maraas [nb],
 | 
			
		||||
 A S Alam [pa], Daniel Nylander [se], Ngô Chin, Nguyễn Thái Ngọc Duy [vi],
 | 
			
		||||
 Aron Xu [zh_CN], Chao-Hsiung Liao [zh_HK, zh_TW]
 | 
			
		||||
 | 
			
		||||
3.1.4
 | 
			
		||||
=====
 | 
			
		||||
* Take over inserted media handling and autorun from gnome-session [Cosimo]
 | 
			
		||||
* Message Tray
 | 
			
		||||
  - Display a count of unread notifications on icons
 | 
			
		||||
    [Jasper, Guillaume; #649356, #654139]
 | 
			
		||||
  - Only remove icons when the sender quits from D-Bus, not when it
 | 
			
		||||
    closes its last window [Neha, Marina; #645764]
 | 
			
		||||
  - Solve problems switching chats between shell and Empathy
 | 
			
		||||
    [Guillaume; #654237]
 | 
			
		||||
  - Fix handling of bad GMarkup in messages [Dan; #650298]
 | 
			
		||||
  - Never show notifications when the screensaver is active [Dan; #654550]
 | 
			
		||||
* Telepathy integrationpp
 | 
			
		||||
  - Implement Telepathy Debug interface to enable empathy-debugger
 | 
			
		||||
    [Guillaume; #652816]
 | 
			
		||||
  - Allow approving room invitations, and audio/video calls
 | 
			
		||||
    [Guillaume; #653740 #653939]
 | 
			
		||||
  - Send typing notifications [Jonny; #650196]
 | 
			
		||||
* Fix selection highlighting for light-on-dark entries [Jasper; #643768]
 | 
			
		||||
* Make control-Return in the overview open a new window [Maxim]
 | 
			
		||||
* Delay showing the alt-Tab switcher to reduce visual noise when
 | 
			
		||||
  flipping betweeen windows [Dan; #652346]
 | 
			
		||||
* When we have vertically stacked monitors, put the message tray
 | 
			
		||||
  on the bottom one [Dan; #636963]
 | 
			
		||||
* Fix various problems with keynav and the Activities button
 | 
			
		||||
  [Dan; #641253 #645759]
 | 
			
		||||
* Ensure screensaver is locked when switching users [Colin; #654565]
 | 
			
		||||
* Improve extension creation tool [Jasper; #653206]
 | 
			
		||||
* Fix compatibility with latest GJS [Giovanni; #654349]
 | 
			
		||||
* Code cleanups [Adel, Dan, Jasper; #645759 #654577 #654791 #654987]
 | 
			
		||||
* Misc bug fixes [Richard, Dan, Florian, Giovanni, Jasper, Marc-Antoine, Rui;
 | 
			
		||||
  #647175 #649513 #650452 #651082 #653700 #653989 #654105 #654791 #654267
 | 
			
		||||
  #654269 #654527 #655446]
 | 
			
		||||
* Build fixes [Florian, Siegfried; #654300]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Giovanni Campagna, Cosimo Cecchi, Guillaume Desmottes, Neha Doijode,
 | 
			
		||||
 Maxim Ermilov, Adel Gadllah, Siegfried-Angel Gevatter Pujals, Richard Hughes,
 | 
			
		||||
 Jonny Lamb, Rui Matos, Florian Müllner, Marc-Antoine Perennou, Colin Walters,
 | 
			
		||||
 Dan Winship, Marina Zhurakhinskaya
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Mario Blättermann, Paul Seyfert [de], Jorge González, Daniel Mustieles [es],
 | 
			
		||||
 Fran Dieguez [gl], Yaron Shahrabani [he], Luca Ferretti [it],
 | 
			
		||||
 Rudolfs Mazurs [lv], Kjartan Maraas [nb], A S Alam [pa], Yuri Kozlov [ru],
 | 
			
		||||
 Michal Štrba, Matej Urbančič [sl]
 | 
			
		||||
 | 
			
		||||
3.1.3
 | 
			
		||||
=====
 | 
			
		||||
* Fix problem with "user theme extension" breaking the CSS for other
 | 
			
		||||
  extensions [Giovanni; #650971]
 | 
			
		||||
* Telepathy IM framework integration
 | 
			
		||||
  - Switch to using telepathy-glib rather than talking to
 | 
			
		||||
    Telepathy via D-Bus [Guillaume, Jasper; #645585, #649633, #651138, #651227]
 | 
			
		||||
  - Acknowledge messages when the user clicks on them [Guillaume, #647893]
 | 
			
		||||
  - Fix problem with telepathy icon blinking for incoming messages
 | 
			
		||||
    even though the user has been notified of them [Guillaume; #643594]
 | 
			
		||||
* Networking
 | 
			
		||||
  - keep wirelesss networks in predictable order [Giovanni; #646580, #652313]
 | 
			
		||||
  - Show unmanaged devices in the menu [Giovanni; #646946]
 | 
			
		||||
  - Fix overflow when too many VPN connections [Giovanni; #651602]
 | 
			
		||||
* Bluetooth
 | 
			
		||||
  - Show "hardware disabled" when disabled by rfkill [Giovanni; #648048]
 | 
			
		||||
  - Fix bug updating status of devices [Giovanni; #647565]
 | 
			
		||||
* LookingGlass console:
 | 
			
		||||
  - Add a "Memory" tab [Colin; #650692]
 | 
			
		||||
  - Make escape work from any page [Dan Winship; #647303]
 | 
			
		||||
  - Provide a way to refer to panel items as, e.g.,
 | 
			
		||||
    Main.panel._activities [Dan Winship; #646915]
 | 
			
		||||
* User menu
 | 
			
		||||
  - Fix problem with suspend menu option locking the screen even when the user
 | 
			
		||||
    disabled that. [Florian; #652327]
 | 
			
		||||
  - Hide "power off..." option if shutdown is disabled via PolicyKit
 | 
			
		||||
    [Florian; #652038]
 | 
			
		||||
* Track changes to WM_CLASS (fixes problems with LibreOffice tracking)
 | 
			
		||||
  [Colin; #649315]
 | 
			
		||||
* Remove app tracking workarounds for Firefox and LibreOffice [Colin; #651015]
 | 
			
		||||
* Use upstream gettext autoconfigury rather than glib version [Javier; #631576]
 | 
			
		||||
* Show messages in the message tray when an application is fullscreen
 | 
			
		||||
  [Dan Winship; #608667]
 | 
			
		||||
* Don't autohide the workspace pager if there is more than one workspace
 | 
			
		||||
  [Florian; #652714, #653078, #653142]
 | 
			
		||||
* Don't always slide out the workspace pager at drag begin [Florian; #652730]
 | 
			
		||||
* Only offer to remove a favorite app when dragging it's icon [Owen; #642895]
 | 
			
		||||
* Allow dropping an icon anywhere on a workspace [Adel; #652079]
 | 
			
		||||
* st-scroll-view: Make the fade effect and offset themable [Jasper; #651813]
 | 
			
		||||
* Obey the user's preference when running an application in a terminal
 | 
			
		||||
  from the run dialog [Florian; #648422]
 | 
			
		||||
* Consistently exit overview when launching external applications
 | 
			
		||||
  [Colin; #653095]
 | 
			
		||||
* Adapt to changes in GJS for how GObject APIs are bound
 | 
			
		||||
  [Alex, Colin, Florian, Jasper, Marc-Antoine; #649981, #652597]
 | 
			
		||||
* Fix problems with scrolling in overflow for alt-Tab switcher
 | 
			
		||||
  [Dan Winship, Adel; #647807]
 | 
			
		||||
* Mark relationships between labels and actors for accessibility [Alejandro]
 | 
			
		||||
* Add org.gnome.shell.enabled-extensions complementing disabled-extensions
 | 
			
		||||
  GSetting [Tassilo; #651088]
 | 
			
		||||
* Visual tweaks [Jakub, Jasper; #646261, #652715]
 | 
			
		||||
* Switch to building against clutter-1.7 with independent Cogl [Adel; #653397]
 | 
			
		||||
* Code cleanups [Colin, Dan Winship, Florian; #633620, #645031, #648755, #648758,
 | 
			
		||||
  #648760, #649203, #649517, #650317, #652730]
 | 
			
		||||
* Memory leak fixes [Colin, Maxim; #649508, #650934]
 | 
			
		||||
* Build Fixes [Colin, Dan Winship, Florian, Ionut, Morten, Owen, Sean; #647395,
 | 
			
		||||
  #648006, #650869, #653199, #653275
 | 
			
		||||
* Miscellaneous bug fixes [Adam, Adel, Dan Williams, Dan Winship, Florian,
 | 
			
		||||
  Ionut, Jasper, Maxim, Ray; #620105, #639459, #641570, #642793, #643513,
 | 
			
		||||
  #645848, #646919, #647186, #648305, #648410, #648562, #648894, #649001,
 | 
			
		||||
  #645990, #647893, #647907, #651012, #651086, #651606, #651569, #651866,
 | 
			
		||||
  #652388,  #653511]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Ionut Biru, Giovanni Campagna, Guillaume Desmottes, Adam Dingle,
 | 
			
		||||
 Maxim Ermilov, Adel Gadllah, Tassilo Horn, Javier Jardón, Jonny Lamb,
 | 
			
		||||
 Alexander Larsson, Rui Matos, Morten Mjelva, Florian Müllner,
 | 
			
		||||
 Marc-Antoine Perennou, Alejandro Piñeiro, Jasper St. Pierre, Jakub Steiner,
 | 
			
		||||
 Ray Strode, Owen Taylor, Colin Walters, Dan Williams, Sean Wilson, Dan Winship
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Daniel Martinez Cucalon [ar], Ihar Hrachyshka [be], Carles Ferrando,
 | 
			
		||||
 Gil Forcada, Sílvia Miranda [ca], Kristjan Schmidt [eo], Jorge González,
 | 
			
		||||
 Daniel Mustieles [es], Seán de Búrca [ga], Fran Diéguez [gl],
 | 
			
		||||
 Yaron Shahrabani [he], Kjartan Maraas [nb], Misha Shnurapet,
 | 
			
		||||
 Yuri Myasoedov [ru], Daniel Nylander [se], Peter Mráz [sk],
 | 
			
		||||
 Matej Urbančič [sl], Krishnababu Krothapalli [te], Daniel Korostil [uk],
 | 
			
		||||
 Aron Xu [zh_CN]
 | 
			
		||||
 | 
			
		||||
3.0.2
 | 
			
		||||
=====
 | 
			
		||||
* Network Menu [Dan Williams]
 | 
			
		||||
  - Fix connecting to WPA2 Enterprise access points
 | 
			
		||||
    Fixes https://bugzilla.gnome.org/show_bug.cgi?id=648171
 | 
			
		||||
  - Show the mobile broadband wizard when selecting 3G network
 | 
			
		||||
    Fixes https://bugzilla.gnome.org/show_bug.cgi?id=649318
 | 
			
		||||
  - Miscellaneous bug fixes
 | 
			
		||||
    648648, 650124
 | 
			
		||||
* Fix duplicate icons in the application browser [Owen]
 | 
			
		||||
  https://bugzilla.gnome.org/show_bug.cgi?id=648739
 | 
			
		||||
* Make clicking anywhere on the volume icon slider work [Giovanni]
 | 
			
		||||
  https://bugzilla.gnome.org/show_bug.cgi?id=646660
 | 
			
		||||
* Fix a case where activating and clicking the hot corner
 | 
			
		||||
  at the same time could result in immediately leaving the
 | 
			
		||||
  overview [Rui]
 | 
			
		||||
  https://bugzilla.gnome.org/show_bug.cgi?id=649427
 | 
			
		||||
* Fix a case where applications became misordered in Alt-Tab [Jasper]
 | 
			
		||||
  https://bugzilla.gnome.org/show_bug.cgi?id=643302
 | 
			
		||||
* Fix a bug where messages you send could show up in
 | 
			
		||||
  notifications as if someone else sent them [Jonny]
 | 
			
		||||
  https://bugzilla.gnome.org/show_bug.cgi?id=650219
 | 
			
		||||
* Memory leak fixes [Colin, Maxim]
 | 
			
		||||
  642652, 649508, 649497
 | 
			
		||||
* Miscellaneous minor bug fixes [Adel, Christopher, Jasper]
 | 
			
		||||
  649596, 648765, 648983, 649632
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Christopher Aillon, Giovanni Campagna, Maxim Ermilov,
 | 
			
		||||
 Adel Gadllah, Jonny Lamb, Rui Matos, Jasper St. Pierre,
 | 
			
		||||
 Owen Taylor, Colin Walters, Dan Williams
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Arash Mousavi [fa], Seán de Búrca [ga], Timo Jyrinki [fi],
 | 
			
		||||
 Sigurd Gartmann [nb], Daniel Nylander [se], Peter Mráz [sl],
 | 
			
		||||
 Abduxukur Abdurixit [ug], Nguyễn Thái Ngọc Duy [vi]
 | 
			
		||||
 | 
			
		||||
3.0.1
 | 
			
		||||
=====
 | 
			
		||||
 | 
			
		||||
* Network menu
 | 
			
		||||
  - Fix problems updating the menu for mobile broadband devices [Giovanni]
 | 
			
		||||
    https://bugzilla.gnome.org/show_bug.cgi?id=646395
 | 
			
		||||
  - Fix missing device descriptions with multiple devices of the
 | 
			
		||||
    same type [Giovanni]
 | 
			
		||||
    https://bugzilla.gnome.org/show_bug.cgi?id=646074
 | 
			
		||||
  - Label ad-hoc neworks with an appropriate icon [Dan]
 | 
			
		||||
    https://bugzilla.gnome.org/show_bug.cgi?id=646141
 | 
			
		||||
  - Fix displaying some devices states as "invalid" [Dan]
 | 
			
		||||
    https://bugzilla.gnome.org/show_bug.cgi?id=646946
 | 
			
		||||
  - Fix problems with access points that don't report a SSID [Giovanni]
 | 
			
		||||
    https://bugzilla.gnome.org/show_bug.cgi?id=647040
 | 
			
		||||
  - Miscellaneous minor bug fixes [Dan, Giovanni, Owen]
 | 
			
		||||
    645981, 646558, 646443, 646708, 646968
 | 
			
		||||
* Application menu and icon
 | 
			
		||||
  - Fix bug where application menu icon was missing at GNOME Shell
 | 
			
		||||
    startup. [Florian]
 | 
			
		||||
    https://bugzilla.gnome.org/show_bug.cgi?id=644122
 | 
			
		||||
  - Fix missing application menu for dialog windows [Colin]
 | 
			
		||||
    https://bugzilla.gnome.org/show_bug.cgi?id=647082
 | 
			
		||||
 -  When launching an application through an alternate launcher
 | 
			
		||||
    (like for a System Settings pane), association the windows with
 | 
			
		||||
    the application, not the launcher. [Colin]
 | 
			
		||||
    https://bugzilla.gnome.org/show_bug.cgi?id=646689
 | 
			
		||||
* Activities overview
 | 
			
		||||
  - Load the applications view incrementally to avoid potentially freezing
 | 
			
		||||
    for multiple seconds [Colin]
 | 
			
		||||
    https://bugzilla.gnome.org/show_bug.cgi?id=647778
 | 
			
		||||
  - Fix bug where package installation while the overview
 | 
			
		||||
    was up could result in a corrupted application display. [Giovanni]
 | 
			
		||||
    https://bugzilla.gnome.org/show_bug.cgi?id=645801
 | 
			
		||||
  - Fix dragging from the search results to launch apps and docs [Florian]
 | 
			
		||||
    https://bugzilla.gnome.org/show_bug.cgi?id=645990
 | 
			
		||||
  - Fix flickering of selection when searching in the overview [Florian]
 | 
			
		||||
    https://bugzilla.gnome.org/show_bug.cgi?id=646019
 | 
			
		||||
  - Fix bug when typing into the search box when text was already
 | 
			
		||||
    selected [Nohemi]
 | 
			
		||||
    https://bugzilla.gnome.org/show_bug.cgi?id=636341
 | 
			
		||||
* Fix layout of notifications for right-to-left languages [Florian]
 | 
			
		||||
  https://bugzilla.gnome.org/show_bug.cgi?id=646921
 | 
			
		||||
* Remove a confusing special case where Alt-Tab sometimes switched
 | 
			
		||||
  to a different window of the same application rather than to
 | 
			
		||||
  a different application. [Rui]
 | 
			
		||||
  https://bugzilla.gnome.org/show_bug.cgi?id=648132
 | 
			
		||||
* Fix a crash that could happen when a window was opened on a
 | 
			
		||||
  workspace that was immediately removed [Dan]
 | 
			
		||||
  https://bugzilla.gnome.org/show_bug.cgi?id=648132
 | 
			
		||||
* Fix keyboard navigation in logout/reboot dialogs [Dan]
 | 
			
		||||
  https://bugzilla.gnome.org/show_bug.cgi?id=646740
 | 
			
		||||
* Fix missing inspector icon in Looking Glass console [Dan]
 | 
			
		||||
* Miscellaneous minor bug fixes [Adel, Colin, Dan, Florian, Nohemi]
 | 
			
		||||
  645648, 646205, 646257, 646855, 647098, 646730
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Giovanni Campagna, Nohemi Fernandez, Adel Gadllah, Rui Matos, Florian Müllner,
 | 
			
		||||
 Owen Taylor, Colin Walters, Dan Winship
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Hendrik Richter [de], Jorge González [es], Arash Mousavi [fa],
 | 
			
		||||
 Fran Diéguez [gl], Jiro Matsuzawa [ja], Piotr Drąg [pl], Daniel Nylander [sv],
 | 
			
		||||
 Sira Nokyoongtong [th], Muhammet Kara [tr], Nguyễn Thái Ngọc Duy [vi],
 | 
			
		||||
 Aron Xu [zh_CN], Chao-Hsiung Liao [zh_HK, zh_TW]
 | 
			
		||||
 | 
			
		||||
3.0.0.2
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
* Fix missing import that was preventing extensions from loading.
 | 
			
		||||
  [Maxim Ermilov]
 | 
			
		||||
  https://bugzilla.gnome.org/show_bug.cgi?id=646333
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Timo Jyrinki [fi]
 | 
			
		||||
 | 
			
		||||
3.0.0.1
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
* Fix problem with stuck event handling if network menu pops down while
 | 
			
		||||
  user is using the scrollbar. [Owen Taylor]
 | 
			
		||||
  https://bugzilla.gnome.org/show_bug.cgi?id=646825
 | 
			
		||||
 | 
			
		||||
Contributors to GNOME Shell 3.0
 | 
			
		||||
===============================
 | 
			
		||||
 | 
			
		||||
Code:
 | 
			
		||||
 | 
			
		||||
 Josh Adams, Kiyoshi Aman, Nuno Araujo, Emmanuele Bassi, Dirk-Jan C. Binnema,
 | 
			
		||||
 Wouter Bolsterlee, Raphael Bosshard, Milan Bouchet-Valat, Christina Boumpouka,
 | 
			
		||||
 Mathieu Bridon, Alban Browaeys, Phil Bull, Micro Cai, Giovanni Campagna,
 | 
			
		||||
 Cosimo Cecchi, Tor-björn Claesson, Matthias Clasen, Jason D. Clinton,
 | 
			
		||||
 Frederic Crozat, Guillaume Desmottes, Sander Dijkhuis, Neha Doijode,
 | 
			
		||||
 Maxim Ermilov, Diego Escalante Urrelo, Luca Ferretti, Steve Frécinaux,
 | 
			
		||||
 Takao Fujiwara, Adel Gadllah, Vadim Girlin, Nick Glynn, Guido Günther,
 | 
			
		||||
 Leon Handreke, Lex Hider, Richard Hughes, Javier Jardón, Abderrahim Kitouni,
 | 
			
		||||
 Andre Klapper, Alexander Larsson, Nickolas Lloyd, Ryan Lortie, Kjartan Maraas,
 | 
			
		||||
 Koop Mast, Rui Matos, Jonathan Matthew, William Jon McCann, Morten Mjelva,
 | 
			
		||||
 Federico Mena Quintero, Florian Müllner, Jon Nettleton, Hellyna Ng,
 | 
			
		||||
 Discardi Nicola, Carlos Martín Nieto, Bastien Nocera, Bill Nottingham,
 | 
			
		||||
 Matt Novenstern, Marc-Antoine Perennou, Neil Perry, Frédéric Péters,
 | 
			
		||||
 Alejandro Piñeiro, Siegfried-Angel Gevatter Pujals, "res", Neil Roberts,
 | 
			
		||||
 "Sardem FF7", Florian Scandella, Joseph Scheuhammer, Christian Schramm,
 | 
			
		||||
 Gustavo Noronha Silva, Jasper St. Pierre, Eric Springer, Jakub Steiner,
 | 
			
		||||
 Jonathan Strander, Ray Strode, Owen Taylor, Rico Tzschichholz,
 | 
			
		||||
 Sergey V. Udaltsov, Daiki Ueno, Vincent Untz, Marcelo Jorge Vieira,
 | 
			
		||||
 Mads Villadsen, Colin Walters, Dan Winship, William Wolf, Thomas Wood,
 | 
			
		||||
 Pierre Yager, David Zeuthen, Marina Zhurakhinskaya
 | 
			
		||||
 | 
			
		||||
Design:
 | 
			
		||||
 | 
			
		||||
 Allan Day, William Jon McCann, Jeremy Perry, Jakub Steiner
 | 
			
		||||
 2008 Boston GNOME design hackfest participants (especially Neil J. Patel
 | 
			
		||||
 for turning the resulting sketches into our first mockups.)
 | 
			
		||||
 Everybody on irc.gnome.org:#gnome-design
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 | 
			
		||||
 Friedel Wolff (af), Khaled Hosny (ar), Ivaylo Valkov (bg), Jamil Ahmed (bn)
 | 
			
		||||
 Runa Bhattacharjee (bn_IN), Gil Forcada, Siegfried-Angel Gevatter Pujals,
 | 
			
		||||
 Jordi Serratosa (ca), Andre Klapper, Petr Kovar (cs), Kenneth Nielsen,
 | 
			
		||||
 Kris Thomsen (da), Mario Blättermann, Hendrik Brandt, Christian Kirbach,
 | 
			
		||||
 Hendrik Richter, Wolfgang Stöggl (de), Michael Kotsarinis, Kostas Papadimas,
 | 
			
		||||
 Jennie Petoumenou, Sterios Prosiniklis, Fotis Tsamis, Simos Xenitellis (el),
 | 
			
		||||
 Bruce Cowan, Philip Withnall (en_GB), Jorge Gonzalez, Daniel Mustieles (es),
 | 
			
		||||
 Mattias Põldaru, Ivar Smolin (et), Inaki Larranaga Murgoitio (eu),
 | 
			
		||||
 Mahyar Moghimi (fa), Timo Jyrinki (fi), Cyril Arnaud, Bruno Brouard,
 | 
			
		||||
 Pablo Martin-Gomez, Claude Paroz, Frédéric Peters (fr), Seán de Búrca (ga)
 | 
			
		||||
 Francisco Diéguez, Antón Méixome (gl), Sweta Kothari (gu), Liel Fridman,
 | 
			
		||||
 Yaron Shahrabani (he), Rajesh Ranjan (hi), Gabor Kelemen (hu), Milo Casagrande,
 | 
			
		||||
 Luca Ferretti (it), Dirgita, Andika Triwidada (id), Takayuki KUSANO,
 | 
			
		||||
 Takayoshi OKANO, Kiyotaka NISHIBORI, Futoshi NISHIO (ja), Shankar Prasad (kn),
 | 
			
		||||
 Young-Ho Cha, Changwoo Ryu (ko), Žygimantas Beručka, Gintautas Miliauskas (lt),
 | 
			
		||||
 Rudolfs Mazurs (lv), Sandeep Shedmake (mr), Kjartan Maraas (nb),
 | 
			
		||||
 Wouter Bolsterlee, Sander Dijkhuis, Reinout van Schouwen (nl),
 | 
			
		||||
 Torstein Winterseth (nn), A S Alam (pa), Tomasz Dominikowski, Piotr Drąg (pl),
 | 
			
		||||
 Duarte Loreto (pt), Felipe Borges, Rodrigo Padula de Oliveira,
 | 
			
		||||
 Rodrigo L. M. Flores, Amanda Magalhães, Og B. Maciel, Gabriel F. Vilar,
 | 
			
		||||
 Jonh Wendell (pt_BR), Lucian Adrian Grijincu, Daniel Șerbănescu (ro),
 | 
			
		||||
 Sergey V. Kovylov, Andrey Korzinev, Yuri Myasoedov, Marina Zhurakhinskaya (ru),
 | 
			
		||||
 Daniel Nylander (se), Matej Urbančič, Andrej Žnidaršič (sl),
 | 
			
		||||
 Miloš Popović (sr, sr@latin), Miroslav Nikolić (sr), Tirumurti Vasudevan (ta),
 | 
			
		||||
 Sira Nokyoongtong (th), Baris Cicek (tr), Abduxukur Abdurixit,
 | 
			
		||||
 Gheyret T. Kenji (ug), Maxim V. Dziumanenko, Daniel Korostil (uk),
 | 
			
		||||
 Nguyễn Thái Ngọc Duy (vi), Jessica Ban, 'jiero', Wei Li, YunQiang Su, Ray Wang,
 | 
			
		||||
 Aron Xu (zh_CN), Chao-Hsiung Liao (zh_HK, zh_TW)
 | 
			
		||||
							
								
								
									
										21
									
								
								browser-plugin/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,21 @@
 | 
			
		||||
 | 
			
		||||
mozillalibdir = $(BROWSER_PLUGIN_DIR)
 | 
			
		||||
 | 
			
		||||
mozillalib_LTLIBRARIES = libgnome-shell-browser-plugin.la
 | 
			
		||||
 | 
			
		||||
libgnome_shell_browser_plugin_la_LDFLAGS = -module -avoid-version -no-undefined
 | 
			
		||||
 | 
			
		||||
libgnome_shell_browser_plugin_la_LIBADD = 	\
 | 
			
		||||
	$(BROWSER_PLUGIN_LIBS)
 | 
			
		||||
 | 
			
		||||
libgnome_shell_browser_plugin_la_SOURCES = 	\
 | 
			
		||||
	browser-plugin.c \
 | 
			
		||||
	npapi/npapi.h \
 | 
			
		||||
	npapi/npfunctions.h \
 | 
			
		||||
	npapi/npruntime.h \
 | 
			
		||||
	npapi/nptypes.h
 | 
			
		||||
 | 
			
		||||
libgnome_shell_browser_plugin_la_CFLAGS = 	\
 | 
			
		||||
	$(BROWSER_PLUGIN_CFLAGS)		\
 | 
			
		||||
	-DG_DISABLE_DEPRECATED			\
 | 
			
		||||
	-DG_LOG_DOMAIN=\"GnomeShellBrowserPlugin\"
 | 
			
		||||
							
								
								
									
										17
									
								
								browser-plugin/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,17 @@
 | 
			
		||||
The GNOME Shell Browser Plugin provides integration with gnome-shell and the
 | 
			
		||||
corresponding extensions repository, codenamed "SweetTooth". The plugin allows
 | 
			
		||||
the extensions repository to provide good integration, letting the website
 | 
			
		||||
know which extensions are enabled and disabled, and allowing the website to
 | 
			
		||||
enable, disable and install them.
 | 
			
		||||
 | 
			
		||||
Bugs should be reported at http://bugzilla.gnome.org against the 'gnome-shell'
 | 
			
		||||
product.
 | 
			
		||||
 | 
			
		||||
License
 | 
			
		||||
=======
 | 
			
		||||
The GNOME Shell Browser Plugin, like GNOME Shell itself is distributed under
 | 
			
		||||
the GNU General Public License, version 2 or later. The plugin also contains
 | 
			
		||||
header files from the "NPAPI SDK" project, tri-licensed under MPL 1.1, GPL 2.0
 | 
			
		||||
and LGPL 2.1. These headers are third-party sources and can be retrieved from:
 | 
			
		||||
 | 
			
		||||
  http://code.google.com/p/npapi-sdk/
 | 
			
		||||
							
								
								
									
										826
									
								
								browser-plugin/browser-plugin.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,826 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2011 Red Hat
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 | 
			
		||||
 * 02111-1307, USA.
 | 
			
		||||
 *
 | 
			
		||||
 * Authors:
 | 
			
		||||
 *      Jasper St. Pierre <jstpierre@mecheye.net>
 | 
			
		||||
 *      Giovanni Campagna <scampa.giovanni@gmail.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#define XP_UNIX 1
 | 
			
		||||
 | 
			
		||||
#include "npapi/npapi.h"
 | 
			
		||||
#include "npapi/npruntime.h"
 | 
			
		||||
#include "npapi/npfunctions.h"
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
#include <gio/gio.h>
 | 
			
		||||
#include <json-glib/json-glib.h>
 | 
			
		||||
 | 
			
		||||
#define ORIGIN "extensions.gnome.org"
 | 
			
		||||
#define PLUGIN_NAME "Gnome Shell Integration"
 | 
			
		||||
#define PLUGIN_DESCRIPTION "This plugin provides integration with Gnome Shell " \
 | 
			
		||||
      "for live extension enabling and disabling. " \
 | 
			
		||||
      "It can be used only by extensions.gnome.org"
 | 
			
		||||
#define PLUGIN_MIME_STRING "application/x-gnome-shell-integration::Gnome Shell Integration Dummy Content-Type";
 | 
			
		||||
 | 
			
		||||
#define PLUGIN_API_VERSION 1
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  GDBusProxy *proxy;
 | 
			
		||||
} PluginData;
 | 
			
		||||
 | 
			
		||||
static NPNetscapeFuncs funcs;
 | 
			
		||||
 | 
			
		||||
static inline gchar *
 | 
			
		||||
get_string_property (NPP         instance,
 | 
			
		||||
                     NPObject   *obj,
 | 
			
		||||
                     const char *name)
 | 
			
		||||
{
 | 
			
		||||
  NPVariant result = { NPVariantType_Void };
 | 
			
		||||
  NPString result_str;
 | 
			
		||||
  gchar *result_copy;
 | 
			
		||||
 | 
			
		||||
  result_copy = NULL;
 | 
			
		||||
 | 
			
		||||
  if (!funcs.getproperty (instance, obj,
 | 
			
		||||
                          funcs.getstringidentifier (name),
 | 
			
		||||
                          &result))
 | 
			
		||||
    goto out;
 | 
			
		||||
 | 
			
		||||
  if (!NPVARIANT_IS_STRING (result))
 | 
			
		||||
    goto out;
 | 
			
		||||
 | 
			
		||||
  result_str = NPVARIANT_TO_STRING (result);
 | 
			
		||||
  result_copy = g_strndup (result_str.UTF8Characters, result_str.UTF8Length);
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
  funcs.releasevariantvalue (&result);
 | 
			
		||||
  return result_copy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
check_origin_and_protocol (NPP instance)
 | 
			
		||||
{
 | 
			
		||||
  gboolean ret = FALSE;
 | 
			
		||||
  NPError error;
 | 
			
		||||
  NPObject *window = NULL;
 | 
			
		||||
  NPVariant document = { NPVariantType_Void };
 | 
			
		||||
  NPVariant location = { NPVariantType_Void };
 | 
			
		||||
  gchar *hostname = NULL;
 | 
			
		||||
  gchar *protocol = NULL;
 | 
			
		||||
 | 
			
		||||
  error = funcs.getvalue (instance, NPNVWindowNPObject, &window);
 | 
			
		||||
  if (error != NPERR_NO_ERROR)
 | 
			
		||||
    goto out;
 | 
			
		||||
 | 
			
		||||
  if (!funcs.getproperty (instance, window,
 | 
			
		||||
                          funcs.getstringidentifier ("document"),
 | 
			
		||||
                          &document))
 | 
			
		||||
    goto out;
 | 
			
		||||
 | 
			
		||||
  if (!NPVARIANT_IS_OBJECT (document))
 | 
			
		||||
    goto out;
 | 
			
		||||
 | 
			
		||||
  if (!funcs.getproperty (instance, NPVARIANT_TO_OBJECT (document),
 | 
			
		||||
                          funcs.getstringidentifier ("location"),
 | 
			
		||||
                          &location))
 | 
			
		||||
    goto out;
 | 
			
		||||
 | 
			
		||||
  if (!NPVARIANT_IS_OBJECT (document))
 | 
			
		||||
    goto out;
 | 
			
		||||
 | 
			
		||||
  hostname = get_string_property (instance,
 | 
			
		||||
                                  NPVARIANT_TO_OBJECT (location),
 | 
			
		||||
                                  "hostname");
 | 
			
		||||
 | 
			
		||||
  if (g_strcmp0 (hostname, ORIGIN))
 | 
			
		||||
    {
 | 
			
		||||
      g_debug ("origin does not match, is %s",
 | 
			
		||||
               hostname);
 | 
			
		||||
 | 
			
		||||
      goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  protocol = get_string_property (instance,
 | 
			
		||||
                                  NPVARIANT_TO_OBJECT (location),
 | 
			
		||||
                                  "protocol");
 | 
			
		||||
 | 
			
		||||
  if (g_strcmp0 (protocol, "https:") != 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_debug ("protocol does not match, is %s",
 | 
			
		||||
               protocol);
 | 
			
		||||
 | 
			
		||||
      goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  ret = TRUE;
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
  g_free (protocol);
 | 
			
		||||
  g_free (hostname);
 | 
			
		||||
 | 
			
		||||
  funcs.releasevariantvalue (&location);
 | 
			
		||||
  funcs.releasevariantvalue (&document);
 | 
			
		||||
 | 
			
		||||
  if (window != NULL)
 | 
			
		||||
    funcs.releaseobject (window);
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* =============== public entry points =================== */
 | 
			
		||||
 | 
			
		||||
NPError
 | 
			
		||||
NP_Initialize(NPNetscapeFuncs *pfuncs, NPPluginFuncs *plugin)
 | 
			
		||||
{
 | 
			
		||||
  /* global initialization routine, called once when plugin
 | 
			
		||||
     is loaded */
 | 
			
		||||
 | 
			
		||||
  g_debug ("plugin loaded");
 | 
			
		||||
 | 
			
		||||
  memcpy (&funcs, pfuncs, sizeof (funcs));
 | 
			
		||||
 | 
			
		||||
  plugin->size = sizeof(NPPluginFuncs);
 | 
			
		||||
  plugin->newp = NPP_New;
 | 
			
		||||
  plugin->destroy = NPP_Destroy;
 | 
			
		||||
  plugin->getvalue = NPP_GetValue;
 | 
			
		||||
 | 
			
		||||
  return NPERR_NO_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NPError
 | 
			
		||||
NP_Shutdown(void)
 | 
			
		||||
{
 | 
			
		||||
  return NPERR_NO_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char*
 | 
			
		||||
NP_GetMIMEDescription(void)
 | 
			
		||||
{
 | 
			
		||||
  return PLUGIN_MIME_STRING;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NPError
 | 
			
		||||
NP_GetValue(void         *instance,
 | 
			
		||||
            NPPVariable   variable,
 | 
			
		||||
            void         *value)
 | 
			
		||||
{
 | 
			
		||||
  switch (variable) {
 | 
			
		||||
  case NPPVpluginNameString:
 | 
			
		||||
    *(char**)value = PLUGIN_NAME;
 | 
			
		||||
    break;
 | 
			
		||||
  case NPPVpluginDescriptionString:
 | 
			
		||||
    *(char**)value = PLUGIN_DESCRIPTION;
 | 
			
		||||
    break;
 | 
			
		||||
  default:
 | 
			
		||||
    ;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return NPERR_NO_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NPError
 | 
			
		||||
NPP_New(NPMIMEType    mimetype,
 | 
			
		||||
        NPP           instance,
 | 
			
		||||
        uint16_t      mode,
 | 
			
		||||
        int16_t       argc,
 | 
			
		||||
        char        **argn,
 | 
			
		||||
        char        **argv,
 | 
			
		||||
        NPSavedData  *saved)
 | 
			
		||||
{
 | 
			
		||||
  /* instance initialization function */
 | 
			
		||||
  PluginData *data;
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
 | 
			
		||||
  g_debug ("plugin created");
 | 
			
		||||
 | 
			
		||||
  if (!check_origin_and_protocol (instance))
 | 
			
		||||
    return NPERR_GENERIC_ERROR;
 | 
			
		||||
 | 
			
		||||
  data = g_slice_new (PluginData);
 | 
			
		||||
  instance->pdata = data;
 | 
			
		||||
 | 
			
		||||
  data->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
 | 
			
		||||
                                               G_DBUS_PROXY_FLAGS_NONE,
 | 
			
		||||
                                               NULL, /* interface info */
 | 
			
		||||
                                               "org.gnome.Shell",
 | 
			
		||||
                                               "/org/gnome/Shell",
 | 
			
		||||
                                               "org.gnome.Shell",
 | 
			
		||||
                                               NULL, /* GCancellable */
 | 
			
		||||
                                               &error);
 | 
			
		||||
  if (!data->proxy)
 | 
			
		||||
    {
 | 
			
		||||
      /* ignore error if the shell is not running, otherwise warn */
 | 
			
		||||
      if (error->domain != G_DBUS_ERROR ||
 | 
			
		||||
          error->code != G_DBUS_ERROR_NAME_HAS_NO_OWNER)
 | 
			
		||||
        {
 | 
			
		||||
          g_warning ("Failed to set up Shell proxy: %s", error->message);
 | 
			
		||||
        }
 | 
			
		||||
      g_clear_error (&error);
 | 
			
		||||
      return NPERR_GENERIC_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_debug ("plugin created successfully");
 | 
			
		||||
 | 
			
		||||
  return NPERR_NO_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NPError
 | 
			
		||||
NPP_Destroy(NPP           instance,
 | 
			
		||||
	    NPSavedData **saved)
 | 
			
		||||
{
 | 
			
		||||
  /* instance finalization function */
 | 
			
		||||
 | 
			
		||||
  PluginData *data = instance->pdata;
 | 
			
		||||
 | 
			
		||||
  g_debug ("plugin destroyed");
 | 
			
		||||
 | 
			
		||||
  g_object_unref (data->proxy);
 | 
			
		||||
 | 
			
		||||
  g_slice_free (PluginData, data);
 | 
			
		||||
 | 
			
		||||
  return NPERR_NO_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* =================== scripting interface =================== */
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	NPObject     parent;
 | 
			
		||||
	NPP          instance;
 | 
			
		||||
	GDBusProxy  *proxy;
 | 
			
		||||
	NPObject    *listener;
 | 
			
		||||
	gint         signal_id;
 | 
			
		||||
} PluginObject;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_shell_signal (GDBusProxy *proxy,
 | 
			
		||||
                 gchar      *sender_name,
 | 
			
		||||
                 gchar      *signal_name,
 | 
			
		||||
                 GVariant   *parameters,
 | 
			
		||||
                 gpointer    user_data)
 | 
			
		||||
{
 | 
			
		||||
  PluginObject *obj = user_data;
 | 
			
		||||
 | 
			
		||||
  if (strcmp (signal_name, "ExtensionStatusChanged") == 0)
 | 
			
		||||
    {
 | 
			
		||||
      gchar *uuid;
 | 
			
		||||
      gint32 status;
 | 
			
		||||
      gchar *error;
 | 
			
		||||
      NPVariant args[3];
 | 
			
		||||
      NPVariant result;
 | 
			
		||||
 | 
			
		||||
      g_variant_get (parameters, "(sis)", &uuid, &status, &error);
 | 
			
		||||
      STRINGZ_TO_NPVARIANT (uuid, args[0]);
 | 
			
		||||
      INT32_TO_NPVARIANT (status, args[1]);
 | 
			
		||||
      STRINGZ_TO_NPVARIANT (error, args[2]);
 | 
			
		||||
 | 
			
		||||
      funcs.invokeDefault (obj->instance, obj->listener,
 | 
			
		||||
			   args, 3, &result);
 | 
			
		||||
 | 
			
		||||
      funcs.releasevariantvalue (&result);
 | 
			
		||||
      g_free (uuid);
 | 
			
		||||
      g_free (error);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static NPObject *
 | 
			
		||||
plugin_object_allocate (NPP      instance,
 | 
			
		||||
                        NPClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  PluginData *data = instance->pdata;
 | 
			
		||||
  PluginObject *obj = g_slice_new0 (PluginObject);
 | 
			
		||||
 | 
			
		||||
  obj->instance = instance;
 | 
			
		||||
  obj->proxy = g_object_ref (data->proxy);
 | 
			
		||||
  obj->signal_id = g_signal_connect (obj->proxy, "g-signal",
 | 
			
		||||
                                     G_CALLBACK (on_shell_signal), obj);
 | 
			
		||||
 | 
			
		||||
  g_debug ("plugin object created");
 | 
			
		||||
 | 
			
		||||
  return (NPObject*)obj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
plugin_object_deallocate (NPObject *npobj)
 | 
			
		||||
{
 | 
			
		||||
  PluginObject *obj = (PluginObject*)npobj;
 | 
			
		||||
 | 
			
		||||
  g_signal_handler_disconnect (obj->proxy, obj->signal_id);
 | 
			
		||||
  g_object_unref (obj->proxy);
 | 
			
		||||
 | 
			
		||||
  if (obj->listener)
 | 
			
		||||
    funcs.releaseobject (obj->listener);
 | 
			
		||||
 | 
			
		||||
  g_debug ("plugin object destroyed");
 | 
			
		||||
 | 
			
		||||
  g_slice_free (PluginObject, obj);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static NPIdentifier api_version_id;
 | 
			
		||||
static NPIdentifier shell_version_id;
 | 
			
		||||
static NPIdentifier get_info_id;
 | 
			
		||||
static NPIdentifier list_extensions_id;
 | 
			
		||||
static NPIdentifier enable_extension_id;
 | 
			
		||||
static NPIdentifier install_extension_id;
 | 
			
		||||
static NPIdentifier uninstall_extension_id;
 | 
			
		||||
static NPIdentifier onextension_changed_id;
 | 
			
		||||
static NPIdentifier get_errors_id;
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
plugin_object_has_method (NPObject     *npobj,
 | 
			
		||||
                          NPIdentifier  name)
 | 
			
		||||
{
 | 
			
		||||
  return (name == get_info_id ||
 | 
			
		||||
          name == list_extensions_id ||
 | 
			
		||||
          name == enable_extension_id ||
 | 
			
		||||
          name == install_extension_id ||
 | 
			
		||||
          name == uninstall_extension_id ||
 | 
			
		||||
          name == get_errors_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline gboolean
 | 
			
		||||
uuid_is_valid (const gchar *uuid)
 | 
			
		||||
{
 | 
			
		||||
  gsize i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; uuid[i]; i ++)
 | 
			
		||||
    {
 | 
			
		||||
      gchar c = uuid[i];
 | 
			
		||||
      if (c < 32 || c >= 127)
 | 
			
		||||
        return FALSE;
 | 
			
		||||
 | 
			
		||||
      switch (c)
 | 
			
		||||
        {
 | 
			
		||||
        case '&':
 | 
			
		||||
        case '<':
 | 
			
		||||
        case '>':
 | 
			
		||||
        case '/':
 | 
			
		||||
        case '\\':
 | 
			
		||||
          return FALSE;
 | 
			
		||||
        default:
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
jsonify_variant (GVariant  *variant,
 | 
			
		||||
                 NPVariant *result)
 | 
			
		||||
{
 | 
			
		||||
  gboolean ret;
 | 
			
		||||
  GVariant *real_value;
 | 
			
		||||
  JsonNode *root;
 | 
			
		||||
  JsonGenerator *generator;
 | 
			
		||||
  gsize json_length;
 | 
			
		||||
  gchar *json;
 | 
			
		||||
  gchar *buffer;
 | 
			
		||||
 | 
			
		||||
  ret = TRUE;
 | 
			
		||||
 | 
			
		||||
  /* DBus methods can return multiple values,
 | 
			
		||||
   * but we're only interested in the first. */
 | 
			
		||||
  g_variant_get (variant, "(@*)", &real_value);
 | 
			
		||||
 | 
			
		||||
  root = json_gvariant_serialize (real_value);
 | 
			
		||||
 | 
			
		||||
  generator = json_generator_new ();
 | 
			
		||||
  json_generator_set_root (generator, root);
 | 
			
		||||
  json = json_generator_to_data (generator, &json_length);
 | 
			
		||||
 | 
			
		||||
  buffer = funcs.memalloc (json_length + 1);
 | 
			
		||||
  if (!buffer)
 | 
			
		||||
    {
 | 
			
		||||
      ret = FALSE;
 | 
			
		||||
      goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  strcpy (buffer, json);
 | 
			
		||||
 | 
			
		||||
  STRINGN_TO_NPVARIANT (buffer, json_length, *result);
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
  g_variant_unref (variant);
 | 
			
		||||
  g_variant_unref (real_value);
 | 
			
		||||
  json_node_free (root);
 | 
			
		||||
  g_free (json);
 | 
			
		||||
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
plugin_list_extensions (PluginObject  *obj,
 | 
			
		||||
                        NPVariant     *result)
 | 
			
		||||
{
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
  GVariant *res;
 | 
			
		||||
 | 
			
		||||
  res = g_dbus_proxy_call_sync (obj->proxy,
 | 
			
		||||
                                "ListExtensions",
 | 
			
		||||
                                NULL, /* parameters */
 | 
			
		||||
                                G_DBUS_CALL_FLAGS_NONE,
 | 
			
		||||
                                -1, /* timeout */
 | 
			
		||||
                                NULL, /* cancellable */
 | 
			
		||||
                                &error);
 | 
			
		||||
 | 
			
		||||
  if (!res)
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Failed to retrieve extension list: %s", error->message);
 | 
			
		||||
      g_error_free (error);
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return jsonify_variant (res, result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
plugin_enable_extension (PluginObject *obj,
 | 
			
		||||
                         NPString      uuid,
 | 
			
		||||
                         gboolean      enabled)
 | 
			
		||||
{
 | 
			
		||||
  const gchar *uuid_str = uuid.UTF8Characters;
 | 
			
		||||
  if (!uuid_is_valid (uuid_str))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  g_dbus_proxy_call (obj->proxy,
 | 
			
		||||
                     (enabled ? "EnableExtension" : "DisableExtension"),
 | 
			
		||||
                     g_variant_new ("(s)", uuid_str),
 | 
			
		||||
                     G_DBUS_CALL_FLAGS_NONE,
 | 
			
		||||
                     -1, /* timeout */
 | 
			
		||||
                     NULL, /* cancellable */
 | 
			
		||||
                     NULL, /* callback */
 | 
			
		||||
                     NULL /* user_data */);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
plugin_install_extension (PluginObject *obj,
 | 
			
		||||
                          NPString      uuid,
 | 
			
		||||
                          NPString      version_tag)
 | 
			
		||||
{
 | 
			
		||||
  const gchar *uuid_str = uuid.UTF8Characters;
 | 
			
		||||
  if (!uuid_is_valid (uuid_str))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  g_dbus_proxy_call (obj->proxy,
 | 
			
		||||
                     "InstallRemoteExtension",
 | 
			
		||||
                     g_variant_new ("(ss)",
 | 
			
		||||
                                    uuid_str,
 | 
			
		||||
                                    version_tag.UTF8Characters),
 | 
			
		||||
                     G_DBUS_CALL_FLAGS_NONE,
 | 
			
		||||
                     -1, /* timeout */
 | 
			
		||||
                     NULL, /* cancellable */
 | 
			
		||||
                     NULL, /* callback */
 | 
			
		||||
                     NULL /* user_data */);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
plugin_uninstall_extension (PluginObject *obj,
 | 
			
		||||
                            NPString      uuid,
 | 
			
		||||
                            NPVariant    *result)
 | 
			
		||||
{
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
  GVariant *res;
 | 
			
		||||
  const gchar *uuid_str;
 | 
			
		||||
 | 
			
		||||
  uuid_str = uuid.UTF8Characters;
 | 
			
		||||
  if (!uuid_is_valid (uuid_str))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  res = g_dbus_proxy_call_sync (obj->proxy,
 | 
			
		||||
                                "UninstallExtension",
 | 
			
		||||
                                g_variant_new ("(s)",
 | 
			
		||||
                                               uuid_str),
 | 
			
		||||
                                G_DBUS_CALL_FLAGS_NONE,
 | 
			
		||||
                                -1, /* timeout */
 | 
			
		||||
                                NULL, /* cancellable */
 | 
			
		||||
                                &error);
 | 
			
		||||
 | 
			
		||||
  if (!res)
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Failed to uninstall extension: %s", error->message);
 | 
			
		||||
      g_error_free (error);
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return jsonify_variant (res, result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
plugin_get_info (PluginObject *obj,
 | 
			
		||||
                 NPString      uuid,
 | 
			
		||||
                 NPVariant    *result)
 | 
			
		||||
{
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
  GVariant *res;
 | 
			
		||||
  const gchar *uuid_str;
 | 
			
		||||
 | 
			
		||||
  uuid_str = uuid.UTF8Characters;
 | 
			
		||||
  if (!uuid_is_valid (uuid_str))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  res = g_dbus_proxy_call_sync (obj->proxy,
 | 
			
		||||
                                "GetExtensionInfo",
 | 
			
		||||
                                g_variant_new ("(s)", uuid_str),
 | 
			
		||||
                                G_DBUS_CALL_FLAGS_NONE,
 | 
			
		||||
                                -1, /* timeout */
 | 
			
		||||
                                NULL, /* cancellable */
 | 
			
		||||
                                &error);
 | 
			
		||||
 | 
			
		||||
  if (!res)
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Failed to retrieve extension metadata: %s", error->message);
 | 
			
		||||
      g_error_free (error);
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return jsonify_variant (res, result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
plugin_get_errors (PluginObject *obj,
 | 
			
		||||
                   NPString      uuid,
 | 
			
		||||
                   NPVariant    *result)
 | 
			
		||||
{
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
  GVariant *res;
 | 
			
		||||
  const gchar *uuid_str;
 | 
			
		||||
 | 
			
		||||
  uuid_str = uuid.UTF8Characters;
 | 
			
		||||
  if (!uuid_is_valid (uuid_str))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  res = g_dbus_proxy_call_sync (obj->proxy,
 | 
			
		||||
                                "GetExtensionErrors",
 | 
			
		||||
                                g_variant_new ("(s)", uuid_str),
 | 
			
		||||
                                G_DBUS_CALL_FLAGS_NONE,
 | 
			
		||||
                                -1, /* timeout */
 | 
			
		||||
                                NULL, /* cancellable */
 | 
			
		||||
                                &error);
 | 
			
		||||
 | 
			
		||||
  if (!res)
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Failed to retrieve errors: %s", error->message);
 | 
			
		||||
      g_error_free (error);
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return jsonify_variant (res, result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
plugin_get_api_version (PluginObject  *obj,
 | 
			
		||||
                        NPVariant     *result)
 | 
			
		||||
{
 | 
			
		||||
  INT32_TO_NPVARIANT (PLUGIN_API_VERSION, *result);
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
plugin_get_shell_version (PluginObject  *obj,
 | 
			
		||||
                          NPVariant     *result)
 | 
			
		||||
{
 | 
			
		||||
  GVariant *res;
 | 
			
		||||
  const gchar *version;
 | 
			
		||||
  gsize length;
 | 
			
		||||
  gchar *buffer;
 | 
			
		||||
  gboolean ret;
 | 
			
		||||
 | 
			
		||||
  ret = TRUE;
 | 
			
		||||
 | 
			
		||||
  res = g_dbus_proxy_get_cached_property (obj->proxy,
 | 
			
		||||
                                          "ShellVersion");
 | 
			
		||||
 | 
			
		||||
  if (res == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Failed to grab shell version.");
 | 
			
		||||
      version = "-1";
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      g_variant_get (res, "&s", &version);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  length = strlen (version);
 | 
			
		||||
  buffer = funcs.memalloc (length + 1);
 | 
			
		||||
  if (!buffer)
 | 
			
		||||
    {
 | 
			
		||||
      ret = FALSE;
 | 
			
		||||
      goto out;
 | 
			
		||||
    }
 | 
			
		||||
  strcpy (buffer, version);
 | 
			
		||||
 | 
			
		||||
  STRINGN_TO_NPVARIANT (buffer, length, *result);
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
  g_variant_unref (res);
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
plugin_object_invoke (NPObject        *npobj,
 | 
			
		||||
                      NPIdentifier     name,
 | 
			
		||||
                      const NPVariant *args,
 | 
			
		||||
                      uint32_t         argc,
 | 
			
		||||
                      NPVariant       *result)
 | 
			
		||||
{
 | 
			
		||||
  PluginObject *obj;
 | 
			
		||||
 | 
			
		||||
  g_debug ("invoking plugin object method");
 | 
			
		||||
 | 
			
		||||
  obj = (PluginObject*) npobj;
 | 
			
		||||
 | 
			
		||||
  VOID_TO_NPVARIANT (*result);
 | 
			
		||||
 | 
			
		||||
  if (!plugin_object_has_method (npobj, name))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  if (name == list_extensions_id)
 | 
			
		||||
    return plugin_list_extensions (obj, result);
 | 
			
		||||
  else if (name == get_info_id)
 | 
			
		||||
    {
 | 
			
		||||
      if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
 | 
			
		||||
 | 
			
		||||
      return plugin_get_info (obj, NPVARIANT_TO_STRING(args[0]), result);
 | 
			
		||||
    }
 | 
			
		||||
  else if (name == enable_extension_id)
 | 
			
		||||
    {
 | 
			
		||||
      if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
 | 
			
		||||
      if (!NPVARIANT_IS_BOOLEAN(args[1])) return FALSE;
 | 
			
		||||
 | 
			
		||||
      return plugin_enable_extension (obj,
 | 
			
		||||
                                      NPVARIANT_TO_STRING(args[0]),
 | 
			
		||||
                                      NPVARIANT_TO_BOOLEAN(args[1]));
 | 
			
		||||
    }
 | 
			
		||||
  else if (name == install_extension_id)
 | 
			
		||||
    {
 | 
			
		||||
      if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
 | 
			
		||||
      if (!NPVARIANT_IS_STRING(args[1])) return FALSE;
 | 
			
		||||
 | 
			
		||||
      return plugin_install_extension (obj,
 | 
			
		||||
                                       NPVARIANT_TO_STRING(args[0]),
 | 
			
		||||
                                       NPVARIANT_TO_STRING(args[1]));
 | 
			
		||||
    }
 | 
			
		||||
  else if (name == uninstall_extension_id)
 | 
			
		||||
    {
 | 
			
		||||
      if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
 | 
			
		||||
 | 
			
		||||
      return plugin_uninstall_extension (obj,
 | 
			
		||||
                                         NPVARIANT_TO_STRING(args[0]),
 | 
			
		||||
                                         result);
 | 
			
		||||
    }
 | 
			
		||||
  else if (name == get_errors_id)
 | 
			
		||||
    {
 | 
			
		||||
      if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
 | 
			
		||||
 | 
			
		||||
      return plugin_get_errors (obj,
 | 
			
		||||
                                NPVARIANT_TO_STRING(args[0]),
 | 
			
		||||
                                result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
plugin_object_has_property (NPObject     *npobj,
 | 
			
		||||
                            NPIdentifier  name)
 | 
			
		||||
{
 | 
			
		||||
  return (name == onextension_changed_id ||
 | 
			
		||||
          name == api_version_id ||
 | 
			
		||||
          name == shell_version_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
plugin_object_get_property (NPObject     *npobj,
 | 
			
		||||
                            NPIdentifier  name,
 | 
			
		||||
                            NPVariant    *result)
 | 
			
		||||
{
 | 
			
		||||
  PluginObject *obj;
 | 
			
		||||
 | 
			
		||||
  if (!plugin_object_has_property (npobj, name))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  obj = (PluginObject*) npobj;
 | 
			
		||||
  if (name == api_version_id)
 | 
			
		||||
    return plugin_get_api_version (obj, result);
 | 
			
		||||
  else if (name == shell_version_id)
 | 
			
		||||
    return plugin_get_shell_version (obj, result);
 | 
			
		||||
  else if (name == onextension_changed_id)
 | 
			
		||||
    {
 | 
			
		||||
      if (obj->listener)
 | 
			
		||||
        OBJECT_TO_NPVARIANT (obj->listener, *result);
 | 
			
		||||
      else
 | 
			
		||||
        NULL_TO_NPVARIANT (*result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
plugin_object_set_property (NPObject        *npobj,
 | 
			
		||||
                            NPIdentifier     name,
 | 
			
		||||
                            const NPVariant *value)
 | 
			
		||||
{
 | 
			
		||||
  PluginObject *obj;
 | 
			
		||||
 | 
			
		||||
  if (!plugin_object_has_property (npobj, name))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  if (name == onextension_changed_id)
 | 
			
		||||
    {
 | 
			
		||||
      obj = (PluginObject*) npobj;
 | 
			
		||||
      if (obj->listener)
 | 
			
		||||
        funcs.releaseobject (obj->listener);
 | 
			
		||||
 | 
			
		||||
      obj->listener = NULL;
 | 
			
		||||
      if (NPVARIANT_IS_OBJECT (*value))
 | 
			
		||||
        {
 | 
			
		||||
          obj->listener = NPVARIANT_TO_OBJECT (*value);
 | 
			
		||||
          funcs.retainobject (obj->listener);
 | 
			
		||||
          return TRUE;
 | 
			
		||||
        }
 | 
			
		||||
      else if (NPVARIANT_IS_NULL (*value))
 | 
			
		||||
        return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static NPClass plugin_class = {
 | 
			
		||||
  NP_CLASS_STRUCT_VERSION,
 | 
			
		||||
  plugin_object_allocate,
 | 
			
		||||
  plugin_object_deallocate,
 | 
			
		||||
  NULL, /* invalidate */
 | 
			
		||||
  plugin_object_has_method,
 | 
			
		||||
  plugin_object_invoke,
 | 
			
		||||
  NULL, /* invoke default */
 | 
			
		||||
  plugin_object_has_property,
 | 
			
		||||
  plugin_object_get_property,
 | 
			
		||||
  plugin_object_set_property,
 | 
			
		||||
  NULL, /* remove property */
 | 
			
		||||
  NULL, /* enumerate */
 | 
			
		||||
  NULL, /* construct */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
init_methods_and_properties (void)
 | 
			
		||||
{
 | 
			
		||||
  /* this is the JS public API; it is manipulated through NPIdentifiers for speed */
 | 
			
		||||
  api_version_id = funcs.getstringidentifier ("apiVersion");
 | 
			
		||||
  shell_version_id = funcs.getstringidentifier ("shellVersion");
 | 
			
		||||
 | 
			
		||||
  get_info_id = funcs.getstringidentifier ("getExtensionInfo");
 | 
			
		||||
  list_extensions_id = funcs.getstringidentifier ("listExtensions");
 | 
			
		||||
  enable_extension_id = funcs.getstringidentifier ("setExtensionEnabled");
 | 
			
		||||
  install_extension_id = funcs.getstringidentifier ("installExtension");
 | 
			
		||||
  uninstall_extension_id = funcs.getstringidentifier ("uninstallExtension");
 | 
			
		||||
  get_errors_id = funcs.getstringidentifier ("getExtensionErrors");
 | 
			
		||||
 | 
			
		||||
  onextension_changed_id = funcs.getstringidentifier ("onchange");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NPError
 | 
			
		||||
NPP_GetValue(NPP          instance,
 | 
			
		||||
	     NPPVariable  variable,
 | 
			
		||||
	     void        *value)
 | 
			
		||||
{
 | 
			
		||||
  g_debug ("NPP_GetValue called");
 | 
			
		||||
 | 
			
		||||
  switch (variable) {
 | 
			
		||||
  case NPPVpluginScriptableNPObject:
 | 
			
		||||
    g_debug ("creating scriptable object");
 | 
			
		||||
    init_methods_and_properties ();
 | 
			
		||||
 | 
			
		||||
    *(NPObject**)value = funcs.createobject (instance, &plugin_class);
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
  case NPPVpluginNeedsXEmbed:
 | 
			
		||||
    *(bool *)value = TRUE;
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
  default:
 | 
			
		||||
    ;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return NPERR_NO_ERROR;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										893
									
								
								browser-plugin/npapi/npapi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,893 @@
 | 
			
		||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
			
		||||
/* ***** BEGIN LICENSE BLOCK *****
 | 
			
		||||
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 | 
			
		||||
 *
 | 
			
		||||
 * The contents of this file are subject to the Mozilla Public License Version
 | 
			
		||||
 * 1.1 (the "License"); you may not use this file except in compliance with
 | 
			
		||||
 * the License. You may obtain a copy of the License at
 | 
			
		||||
 * http://www.mozilla.org/MPL/
 | 
			
		||||
 *
 | 
			
		||||
 * Software distributed under the License is distributed on an "AS IS" basis,
 | 
			
		||||
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 | 
			
		||||
 * for the specific language governing rights and limitations under the
 | 
			
		||||
 * License.
 | 
			
		||||
 *
 | 
			
		||||
 * The Original Code is mozilla.org code.
 | 
			
		||||
 *
 | 
			
		||||
 * The Initial Developer of the Original Code is
 | 
			
		||||
 * Netscape Communications Corporation.
 | 
			
		||||
 * Portions created by the Initial Developer are Copyright (C) 1998
 | 
			
		||||
 * the Initial Developer. All Rights Reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Contributor(s):
 | 
			
		||||
 *
 | 
			
		||||
 * Alternatively, the contents of this file may be used under the terms of
 | 
			
		||||
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 | 
			
		||||
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 | 
			
		||||
 * in which case the provisions of the GPL or the LGPL are applicable instead
 | 
			
		||||
 * of those above. If you wish to allow use of your version of this file only
 | 
			
		||||
 * under the terms of either the GPL or the LGPL, and not to allow others to
 | 
			
		||||
 * use your version of this file under the terms of the MPL, indicate your
 | 
			
		||||
 * decision by deleting the provisions above and replace them with the notice
 | 
			
		||||
 * and other provisions required by the GPL or the LGPL. If you do not delete
 | 
			
		||||
 * the provisions above, a recipient may use your version of this file under
 | 
			
		||||
 * the terms of any one of the MPL, the GPL or the LGPL.
 | 
			
		||||
 *
 | 
			
		||||
 * ***** END LICENSE BLOCK ***** */
 | 
			
		||||
 | 
			
		||||
#ifndef npapi_h_
 | 
			
		||||
#define npapi_h_
 | 
			
		||||
 | 
			
		||||
#if defined(__OS2__)
 | 
			
		||||
#pragma pack(1)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "nptypes.h"
 | 
			
		||||
 | 
			
		||||
#if defined(__OS2__) || defined(OS2)
 | 
			
		||||
#ifndef XP_OS2
 | 
			
		||||
#define XP_OS2 1
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32) && !defined(__SYMBIAN32__)
 | 
			
		||||
#include <windef.h>
 | 
			
		||||
#ifndef XP_WIN
 | 
			
		||||
#define XP_WIN 1
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__SYMBIAN32__)
 | 
			
		||||
#ifndef XP_SYMBIAN
 | 
			
		||||
#define XP_SYMBIAN 1
 | 
			
		||||
#undef XP_WIN
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__APPLE_CC__) && !defined(XP_UNIX)
 | 
			
		||||
#ifndef XP_MACOSX
 | 
			
		||||
#define XP_MACOSX 1
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX) && defined(__LP64__)
 | 
			
		||||
#define NP_NO_QUICKDRAW
 | 
			
		||||
#define NP_NO_CARBON
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
#include <ApplicationServices/ApplicationServices.h>
 | 
			
		||||
#include <OpenGL/OpenGL.h>
 | 
			
		||||
#ifndef NP_NO_CARBON
 | 
			
		||||
#include <Carbon/Carbon.h>
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(XP_UNIX)
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#if defined(MOZ_X11)
 | 
			
		||||
#include <X11/Xlib.h>
 | 
			
		||||
#include <X11/Xutil.h>
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(XP_SYMBIAN)
 | 
			
		||||
#include <QEvent>
 | 
			
		||||
#include <QRegion>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
/*                        Plugin Version Constants                      */
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
#define NP_VERSION_MAJOR 0
 | 
			
		||||
#define NP_VERSION_MINOR 27
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* The OS/2 version of Netscape uses RC_DATA to define the
 | 
			
		||||
   mime types, file extensions, etc that are required.
 | 
			
		||||
   Use a vertical bar to separate types, end types with \0.
 | 
			
		||||
   FileVersion and ProductVersion are 32bit ints, all other
 | 
			
		||||
   entries are strings that MUST be terminated with a \0.
 | 
			
		||||
 | 
			
		||||
AN EXAMPLE:
 | 
			
		||||
 | 
			
		||||
RCDATA NP_INFO_ProductVersion { 1,0,0,1,}
 | 
			
		||||
 | 
			
		||||
RCDATA NP_INFO_MIMEType    { "video/x-video|",
 | 
			
		||||
                             "video/x-flick\0" }
 | 
			
		||||
RCDATA NP_INFO_FileExtents { "avi|",
 | 
			
		||||
                             "flc\0" }
 | 
			
		||||
RCDATA NP_INFO_FileOpenName{ "MMOS2 video player(*.avi)|",
 | 
			
		||||
                             "MMOS2 Flc/Fli player(*.flc)\0" }
 | 
			
		||||
 | 
			
		||||
RCDATA NP_INFO_FileVersion       { 1,0,0,1 }
 | 
			
		||||
RCDATA NP_INFO_CompanyName       { "Netscape Communications\0" }
 | 
			
		||||
RCDATA NP_INFO_FileDescription   { "NPAVI32 Extension DLL\0"
 | 
			
		||||
RCDATA NP_INFO_InternalName      { "NPAVI32\0" )
 | 
			
		||||
RCDATA NP_INFO_LegalCopyright    { "Copyright Netscape Communications \251 1996\0"
 | 
			
		||||
RCDATA NP_INFO_OriginalFilename  { "NVAPI32.DLL" }
 | 
			
		||||
RCDATA NP_INFO_ProductName       { "NPAVI32 Dynamic Link Library\0" }
 | 
			
		||||
*/
 | 
			
		||||
/* RC_DATA types for version info - required */
 | 
			
		||||
#define NP_INFO_ProductVersion      1
 | 
			
		||||
#define NP_INFO_MIMEType            2
 | 
			
		||||
#define NP_INFO_FileOpenName        3
 | 
			
		||||
#define NP_INFO_FileExtents         4
 | 
			
		||||
/* RC_DATA types for version info - used if found */
 | 
			
		||||
#define NP_INFO_FileDescription     5
 | 
			
		||||
#define NP_INFO_ProductName         6
 | 
			
		||||
/* RC_DATA types for version info - optional */
 | 
			
		||||
#define NP_INFO_CompanyName         7
 | 
			
		||||
#define NP_INFO_FileVersion         8
 | 
			
		||||
#define NP_INFO_InternalName        9
 | 
			
		||||
#define NP_INFO_LegalCopyright      10
 | 
			
		||||
#define NP_INFO_OriginalFilename    11
 | 
			
		||||
 | 
			
		||||
#ifndef RC_INVOKED
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
/*                       Definition of Basic Types                      */
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
typedef unsigned char NPBool;
 | 
			
		||||
typedef int16_t       NPError;
 | 
			
		||||
typedef int16_t       NPReason;
 | 
			
		||||
typedef char*         NPMIMEType;
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
/*                       Structures and definitions                     */
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
#if !defined(__LP64__)
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
#pragma options align=mac68k
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* __LP64__ */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  NPP is a plug-in's opaque instance handle
 | 
			
		||||
 */
 | 
			
		||||
typedef struct _NPP
 | 
			
		||||
{
 | 
			
		||||
  void* pdata;      /* plug-in private data */
 | 
			
		||||
  void* ndata;      /* netscape private data */
 | 
			
		||||
} NPP_t;
 | 
			
		||||
 | 
			
		||||
typedef NPP_t*  NPP;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPStream
 | 
			
		||||
{
 | 
			
		||||
  void*    pdata; /* plug-in private data */
 | 
			
		||||
  void*    ndata; /* netscape private data */
 | 
			
		||||
  const    char* url;
 | 
			
		||||
  uint32_t end;
 | 
			
		||||
  uint32_t lastmodified;
 | 
			
		||||
  void*    notifyData;
 | 
			
		||||
  const    char* headers; /* Response headers from host.
 | 
			
		||||
                           * Exists only for >= NPVERS_HAS_RESPONSE_HEADERS.
 | 
			
		||||
                           * Used for HTTP only; NULL for non-HTTP.
 | 
			
		||||
                           * Available from NPP_NewStream onwards.
 | 
			
		||||
                           * Plugin should copy this data before storing it.
 | 
			
		||||
                           * Includes HTTP status line and all headers,
 | 
			
		||||
                           * preferably verbatim as received from server,
 | 
			
		||||
                           * headers formatted as in HTTP ("Header: Value"),
 | 
			
		||||
                           * and newlines (\n, NOT \r\n) separating lines.
 | 
			
		||||
                           * Terminated by \n\0 (NOT \n\n\0). */
 | 
			
		||||
} NPStream;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPByteRange
 | 
			
		||||
{
 | 
			
		||||
  int32_t  offset; /* negative offset means from the end */
 | 
			
		||||
  uint32_t length;
 | 
			
		||||
  struct _NPByteRange* next;
 | 
			
		||||
} NPByteRange;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPSavedData
 | 
			
		||||
{
 | 
			
		||||
  int32_t len;
 | 
			
		||||
  void*   buf;
 | 
			
		||||
} NPSavedData;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPRect
 | 
			
		||||
{
 | 
			
		||||
  uint16_t top;
 | 
			
		||||
  uint16_t left;
 | 
			
		||||
  uint16_t bottom;
 | 
			
		||||
  uint16_t right;
 | 
			
		||||
} NPRect;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPSize
 | 
			
		||||
{
 | 
			
		||||
  int32_t width;
 | 
			
		||||
  int32_t height;
 | 
			
		||||
} NPSize;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
  NPFocusNext = 0,
 | 
			
		||||
  NPFocusPrevious = 1
 | 
			
		||||
} NPFocusDirection;
 | 
			
		||||
 | 
			
		||||
/* Return values for NPP_HandleEvent */
 | 
			
		||||
#define kNPEventNotHandled 0
 | 
			
		||||
#define kNPEventHandled 1
 | 
			
		||||
/* Exact meaning must be spec'd in event model. */
 | 
			
		||||
#define kNPEventStartIME 2
 | 
			
		||||
 | 
			
		||||
#if defined(XP_UNIX)
 | 
			
		||||
/*
 | 
			
		||||
 * Unix specific structures and definitions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Callback Structures.
 | 
			
		||||
 *
 | 
			
		||||
 * These are used to pass additional platform specific information.
 | 
			
		||||
 */
 | 
			
		||||
enum {
 | 
			
		||||
  NP_SETWINDOW = 1,
 | 
			
		||||
  NP_PRINT
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  int32_t type;
 | 
			
		||||
} NPAnyCallbackStruct;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  int32_t      type;
 | 
			
		||||
#if defined(MOZ_X11)
 | 
			
		||||
  Display*     display;
 | 
			
		||||
  Visual*      visual;
 | 
			
		||||
  Colormap     colormap;
 | 
			
		||||
  unsigned int depth;
 | 
			
		||||
#endif
 | 
			
		||||
} NPSetWindowCallbackStruct;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  int32_t type;
 | 
			
		||||
  FILE* fp;
 | 
			
		||||
} NPPrintCallbackStruct;
 | 
			
		||||
 | 
			
		||||
#endif /* XP_UNIX */
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
typedef enum {
 | 
			
		||||
#ifndef NP_NO_QUICKDRAW
 | 
			
		||||
  NPDrawingModelQuickDraw = 0,
 | 
			
		||||
#endif
 | 
			
		||||
  NPDrawingModelCoreGraphics = 1,
 | 
			
		||||
  NPDrawingModelOpenGL = 2,
 | 
			
		||||
  NPDrawingModelCoreAnimation = 3,
 | 
			
		||||
  NPDrawingModelInvalidatingCoreAnimation = 4
 | 
			
		||||
} NPDrawingModel;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
#ifndef NP_NO_CARBON
 | 
			
		||||
  NPEventModelCarbon = 0,
 | 
			
		||||
#endif
 | 
			
		||||
  NPEventModelCocoa = 1
 | 
			
		||||
} NPEventModel;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *   The following masks are applied on certain platforms to NPNV and
 | 
			
		||||
 *   NPPV selectors that pass around pointers to COM interfaces. Newer
 | 
			
		||||
 *   compilers on some platforms may generate vtables that are not
 | 
			
		||||
 *   compatible with older compilers. To prevent older plugins from
 | 
			
		||||
 *   not understanding a new browser's ABI, these masks change the
 | 
			
		||||
 *   values of those selectors on those platforms. To remain backwards
 | 
			
		||||
 *   compatible with different versions of the browser, plugins can
 | 
			
		||||
 *   use these masks to dynamically determine and use the correct C++
 | 
			
		||||
 *   ABI that the browser is expecting. This does not apply to Windows
 | 
			
		||||
 *   as Microsoft's COM ABI will likely not change.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define NP_ABI_GCC3_MASK  0x10000000
 | 
			
		||||
/*
 | 
			
		||||
 *   gcc 3.x generated vtables on UNIX and OSX are incompatible with
 | 
			
		||||
 *   previous compilers.
 | 
			
		||||
 */
 | 
			
		||||
#if (defined(XP_UNIX) && defined(__GNUC__) && (__GNUC__ >= 3))
 | 
			
		||||
#define _NP_ABI_MIXIN_FOR_GCC3 NP_ABI_GCC3_MASK
 | 
			
		||||
#else
 | 
			
		||||
#define _NP_ABI_MIXIN_FOR_GCC3 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
#define NP_ABI_MACHO_MASK 0x01000000
 | 
			
		||||
#define _NP_ABI_MIXIN_FOR_MACHO NP_ABI_MACHO_MASK
 | 
			
		||||
#else
 | 
			
		||||
#define _NP_ABI_MIXIN_FOR_MACHO 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define NP_ABI_MASK (_NP_ABI_MIXIN_FOR_GCC3 | _NP_ABI_MIXIN_FOR_MACHO)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * List of variable names for which NPP_GetValue shall be implemented
 | 
			
		||||
 */
 | 
			
		||||
typedef enum {
 | 
			
		||||
  NPPVpluginNameString = 1,
 | 
			
		||||
  NPPVpluginDescriptionString,
 | 
			
		||||
  NPPVpluginWindowBool,
 | 
			
		||||
  NPPVpluginTransparentBool,
 | 
			
		||||
  NPPVjavaClass,
 | 
			
		||||
  NPPVpluginWindowSize,
 | 
			
		||||
  NPPVpluginTimerInterval,
 | 
			
		||||
  NPPVpluginScriptableInstance = (10 | NP_ABI_MASK),
 | 
			
		||||
  NPPVpluginScriptableIID = 11,
 | 
			
		||||
  NPPVjavascriptPushCallerBool = 12,
 | 
			
		||||
  NPPVpluginKeepLibraryInMemory = 13,
 | 
			
		||||
  NPPVpluginNeedsXEmbed         = 14,
 | 
			
		||||
 | 
			
		||||
  /* Get the NPObject for scripting the plugin. Introduced in NPAPI minor version 14.
 | 
			
		||||
   */
 | 
			
		||||
  NPPVpluginScriptableNPObject  = 15,
 | 
			
		||||
 | 
			
		||||
  /* Get the plugin value (as \0-terminated UTF-8 string data) for
 | 
			
		||||
   * form submission if the plugin is part of a form. Use
 | 
			
		||||
   * NPN_MemAlloc() to allocate memory for the string data. Introduced
 | 
			
		||||
   * in NPAPI minor version 15.
 | 
			
		||||
   */
 | 
			
		||||
  NPPVformValue = 16,
 | 
			
		||||
 | 
			
		||||
  NPPVpluginUrlRequestsDisplayedBool = 17,
 | 
			
		||||
 | 
			
		||||
  /* Checks if the plugin is interested in receiving the http body of
 | 
			
		||||
   * all http requests (including failed ones, http status != 200).
 | 
			
		||||
   */
 | 
			
		||||
  NPPVpluginWantsAllNetworkStreams = 18,
 | 
			
		||||
 | 
			
		||||
  /* Browsers can retrieve a native ATK accessibility plug ID via this variable. */
 | 
			
		||||
  NPPVpluginNativeAccessibleAtkPlugId = 19,
 | 
			
		||||
 | 
			
		||||
  /* Checks to see if the plug-in would like the browser to load the "src" attribute. */
 | 
			
		||||
  NPPVpluginCancelSrcStream = 20,
 | 
			
		||||
 | 
			
		||||
  NPPVsupportsAdvancedKeyHandling = 21,
 | 
			
		||||
 | 
			
		||||
  NPPVpluginUsesDOMForCursorBool = 22
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
  /* Used for negotiating drawing models */
 | 
			
		||||
  , NPPVpluginDrawingModel = 1000
 | 
			
		||||
  /* Used for negotiating event models */
 | 
			
		||||
  , NPPVpluginEventModel = 1001
 | 
			
		||||
  /* In the NPDrawingModelCoreAnimation drawing model, the browser asks the plug-in for a Core Animation layer. */
 | 
			
		||||
  , NPPVpluginCoreAnimationLayer = 1003
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
 | 
			
		||||
  , NPPVpluginWindowlessLocalBool = 2002
 | 
			
		||||
#endif
 | 
			
		||||
} NPPVariable;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * List of variable names for which NPN_GetValue should be implemented.
 | 
			
		||||
 */
 | 
			
		||||
typedef enum {
 | 
			
		||||
  NPNVxDisplay = 1,
 | 
			
		||||
  NPNVxtAppContext,
 | 
			
		||||
  NPNVnetscapeWindow,
 | 
			
		||||
  NPNVjavascriptEnabledBool,
 | 
			
		||||
  NPNVasdEnabledBool,
 | 
			
		||||
  NPNVisOfflineBool,
 | 
			
		||||
 | 
			
		||||
  NPNVserviceManager = (10 | NP_ABI_MASK),
 | 
			
		||||
  NPNVDOMElement     = (11 | NP_ABI_MASK),
 | 
			
		||||
  NPNVDOMWindow      = (12 | NP_ABI_MASK),
 | 
			
		||||
  NPNVToolkit        = (13 | NP_ABI_MASK),
 | 
			
		||||
  NPNVSupportsXEmbedBool = 14,
 | 
			
		||||
 | 
			
		||||
  /* Get the NPObject wrapper for the browser window. */
 | 
			
		||||
  NPNVWindowNPObject = 15,
 | 
			
		||||
 | 
			
		||||
  /* Get the NPObject wrapper for the plugins DOM element. */
 | 
			
		||||
  NPNVPluginElementNPObject = 16,
 | 
			
		||||
 | 
			
		||||
  NPNVSupportsWindowless = 17,
 | 
			
		||||
 | 
			
		||||
  NPNVprivateModeBool = 18,
 | 
			
		||||
 | 
			
		||||
  NPNVsupportsAdvancedKeyHandling = 21
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
  /* Used for negotiating drawing models */
 | 
			
		||||
  , NPNVpluginDrawingModel = 1000
 | 
			
		||||
#ifndef NP_NO_QUICKDRAW
 | 
			
		||||
  , NPNVsupportsQuickDrawBool = 2000
 | 
			
		||||
#endif
 | 
			
		||||
  , NPNVsupportsCoreGraphicsBool = 2001
 | 
			
		||||
  , NPNVsupportsOpenGLBool = 2002
 | 
			
		||||
  , NPNVsupportsCoreAnimationBool = 2003
 | 
			
		||||
  , NPNVsupportsInvalidatingCoreAnimationBool = 2004
 | 
			
		||||
#ifndef NP_NO_CARBON
 | 
			
		||||
  , NPNVsupportsCarbonBool = 3000 /* TRUE if the browser supports the Carbon event model */
 | 
			
		||||
#endif
 | 
			
		||||
  , NPNVsupportsCocoaBool = 3001 /* TRUE if the browser supports the Cocoa event model */
 | 
			
		||||
  , NPNVsupportsUpdatedCocoaTextInputBool = 3002 /* TRUE if the browser supports the updated
 | 
			
		||||
                                                    Cocoa text input specification. */
 | 
			
		||||
  , NPNVsupportsCompositingCoreAnimationPluginsBool = 74656 /* TRUE if the browser supports
 | 
			
		||||
                                                               CA model compositing */
 | 
			
		||||
#endif
 | 
			
		||||
#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
 | 
			
		||||
  , NPNVSupportsWindowlessLocal = 2002
 | 
			
		||||
#endif
 | 
			
		||||
} NPNVariable;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
  NPNURLVCookie = 501,
 | 
			
		||||
  NPNURLVProxy
 | 
			
		||||
} NPNURLVariable;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The type of Toolkit the widgets use
 | 
			
		||||
 */
 | 
			
		||||
typedef enum {
 | 
			
		||||
  NPNVGtk12 = 1,
 | 
			
		||||
  NPNVGtk2
 | 
			
		||||
} NPNToolkitType;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The type of a NPWindow - it specifies the type of the data structure
 | 
			
		||||
 * returned in the window field.
 | 
			
		||||
 */
 | 
			
		||||
typedef enum {
 | 
			
		||||
  NPWindowTypeWindow = 1,
 | 
			
		||||
  NPWindowTypeDrawable
 | 
			
		||||
} NPWindowType;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPWindow
 | 
			
		||||
{
 | 
			
		||||
  void* window;  /* Platform specific window handle */
 | 
			
		||||
                 /* OS/2: x - Position of bottom left corner */
 | 
			
		||||
                 /* OS/2: y - relative to visible netscape window */
 | 
			
		||||
  int32_t  x;      /* Position of top left corner relative */
 | 
			
		||||
  int32_t  y;      /* to a netscape page. */
 | 
			
		||||
  uint32_t width;  /* Maximum window size */
 | 
			
		||||
  uint32_t height;
 | 
			
		||||
  NPRect   clipRect; /* Clipping rectangle in port coordinates */
 | 
			
		||||
#if (defined(XP_UNIX) || defined(XP_SYMBIAN)) && !defined(XP_MACOSX)
 | 
			
		||||
  void * ws_info; /* Platform-dependent additional data */
 | 
			
		||||
#endif /* XP_UNIX */
 | 
			
		||||
  NPWindowType type; /* Is this a window or a drawable? */
 | 
			
		||||
} NPWindow;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPImageExpose
 | 
			
		||||
{
 | 
			
		||||
  char*    data;       /* image pointer */
 | 
			
		||||
  int32_t  stride;     /* Stride of data image pointer */
 | 
			
		||||
  int32_t  depth;      /* Depth of image pointer */
 | 
			
		||||
  int32_t  x;          /* Expose x */
 | 
			
		||||
  int32_t  y;          /* Expose y */
 | 
			
		||||
  uint32_t width;      /* Expose width */
 | 
			
		||||
  uint32_t height;     /* Expose height */
 | 
			
		||||
  NPSize   dataSize;   /* Data buffer size */
 | 
			
		||||
  float    translateX; /* translate X matrix value */
 | 
			
		||||
  float    translateY; /* translate Y matrix value */
 | 
			
		||||
  float    scaleX;     /* scale X matrix value */
 | 
			
		||||
  float    scaleY;     /* scale Y matrix value */
 | 
			
		||||
} NPImageExpose;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPFullPrint
 | 
			
		||||
{
 | 
			
		||||
  NPBool pluginPrinted;/* Set TRUE if plugin handled fullscreen printing */
 | 
			
		||||
  NPBool printOne;     /* TRUE if plugin should print one copy to default
 | 
			
		||||
                          printer */
 | 
			
		||||
  void* platformPrint; /* Platform-specific printing info */
 | 
			
		||||
} NPFullPrint;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPEmbedPrint
 | 
			
		||||
{
 | 
			
		||||
  NPWindow window;
 | 
			
		||||
  void* platformPrint; /* Platform-specific printing info */
 | 
			
		||||
} NPEmbedPrint;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPPrint
 | 
			
		||||
{
 | 
			
		||||
  uint16_t mode;               /* NP_FULL or NP_EMBED */
 | 
			
		||||
  union
 | 
			
		||||
  {
 | 
			
		||||
    NPFullPrint fullPrint;   /* if mode is NP_FULL */
 | 
			
		||||
    NPEmbedPrint embedPrint; /* if mode is NP_EMBED */
 | 
			
		||||
  } print;
 | 
			
		||||
} NPPrint;
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
#ifndef NP_NO_CARBON
 | 
			
		||||
typedef EventRecord NPEvent;
 | 
			
		||||
#endif
 | 
			
		||||
#elif defined(XP_SYMBIAN)
 | 
			
		||||
typedef QEvent NPEvent;
 | 
			
		||||
#elif defined(XP_WIN)
 | 
			
		||||
typedef struct _NPEvent
 | 
			
		||||
{
 | 
			
		||||
  uint16_t event;
 | 
			
		||||
  uintptr_t wParam;
 | 
			
		||||
  uintptr_t lParam;
 | 
			
		||||
} NPEvent;
 | 
			
		||||
#elif defined(XP_OS2)
 | 
			
		||||
typedef struct _NPEvent
 | 
			
		||||
{
 | 
			
		||||
  uint32_t event;
 | 
			
		||||
  uint32_t wParam;
 | 
			
		||||
  uint32_t lParam;
 | 
			
		||||
} NPEvent;
 | 
			
		||||
#elif defined(XP_UNIX) && defined(MOZ_X11)
 | 
			
		||||
typedef XEvent NPEvent;
 | 
			
		||||
#else
 | 
			
		||||
typedef void*  NPEvent;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
typedef void* NPRegion;
 | 
			
		||||
#ifndef NP_NO_QUICKDRAW
 | 
			
		||||
typedef RgnHandle NPQDRegion;
 | 
			
		||||
#endif
 | 
			
		||||
typedef CGPathRef NPCGRegion;
 | 
			
		||||
#elif defined(XP_WIN)
 | 
			
		||||
typedef HRGN NPRegion;
 | 
			
		||||
#elif defined(XP_UNIX) && defined(MOZ_X11)
 | 
			
		||||
typedef Region NPRegion;
 | 
			
		||||
#elif defined(XP_SYMBIAN)
 | 
			
		||||
typedef QRegion* NPRegion;
 | 
			
		||||
#else
 | 
			
		||||
typedef void *NPRegion;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct _NPNSString NPNSString;
 | 
			
		||||
typedef struct _NPNSWindow NPNSWindow;
 | 
			
		||||
typedef struct _NPNSMenu   NPNSMenu;
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
typedef NPNSMenu NPMenu;
 | 
			
		||||
#else
 | 
			
		||||
typedef void *NPMenu;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
  NPCoordinateSpacePlugin = 1,
 | 
			
		||||
  NPCoordinateSpaceWindow,
 | 
			
		||||
  NPCoordinateSpaceFlippedWindow,
 | 
			
		||||
  NPCoordinateSpaceScreen,
 | 
			
		||||
  NPCoordinateSpaceFlippedScreen
 | 
			
		||||
} NPCoordinateSpace;
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
 | 
			
		||||
#ifndef NP_NO_QUICKDRAW
 | 
			
		||||
typedef struct NP_Port
 | 
			
		||||
{
 | 
			
		||||
  CGrafPtr port;
 | 
			
		||||
  int32_t portx; /* position inside the topmost window */
 | 
			
		||||
  int32_t porty;
 | 
			
		||||
} NP_Port;
 | 
			
		||||
#endif /* NP_NO_QUICKDRAW */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * NP_CGContext is the type of the NPWindow's 'window' when the plugin specifies NPDrawingModelCoreGraphics
 | 
			
		||||
 * as its drawing model.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
typedef struct NP_CGContext
 | 
			
		||||
{
 | 
			
		||||
  CGContextRef context;
 | 
			
		||||
  void *window; /* A WindowRef under the Carbon event model. */
 | 
			
		||||
} NP_CGContext;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * NP_GLContext is the type of the NPWindow's 'window' when the plugin specifies NPDrawingModelOpenGL as its
 | 
			
		||||
 * drawing model.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
typedef struct NP_GLContext
 | 
			
		||||
{
 | 
			
		||||
  CGLContextObj context;
 | 
			
		||||
#ifdef NP_NO_CARBON
 | 
			
		||||
  NPNSWindow *window;
 | 
			
		||||
#else
 | 
			
		||||
  void *window; /* Can be either an NSWindow or a WindowRef depending on the event model */
 | 
			
		||||
#endif
 | 
			
		||||
} NP_GLContext;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
  NPCocoaEventDrawRect = 1,
 | 
			
		||||
  NPCocoaEventMouseDown,
 | 
			
		||||
  NPCocoaEventMouseUp,
 | 
			
		||||
  NPCocoaEventMouseMoved,
 | 
			
		||||
  NPCocoaEventMouseEntered,
 | 
			
		||||
  NPCocoaEventMouseExited,
 | 
			
		||||
  NPCocoaEventMouseDragged,
 | 
			
		||||
  NPCocoaEventKeyDown,
 | 
			
		||||
  NPCocoaEventKeyUp,
 | 
			
		||||
  NPCocoaEventFlagsChanged,
 | 
			
		||||
  NPCocoaEventFocusChanged,
 | 
			
		||||
  NPCocoaEventWindowFocusChanged,
 | 
			
		||||
  NPCocoaEventScrollWheel,
 | 
			
		||||
  NPCocoaEventTextInput
 | 
			
		||||
} NPCocoaEventType;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPCocoaEvent {
 | 
			
		||||
  NPCocoaEventType type;
 | 
			
		||||
  uint32_t version;
 | 
			
		||||
  union {
 | 
			
		||||
    struct {
 | 
			
		||||
      uint32_t modifierFlags;
 | 
			
		||||
      double   pluginX;
 | 
			
		||||
      double   pluginY;
 | 
			
		||||
      int32_t  buttonNumber;
 | 
			
		||||
      int32_t  clickCount;
 | 
			
		||||
      double   deltaX;
 | 
			
		||||
      double   deltaY;
 | 
			
		||||
      double   deltaZ;
 | 
			
		||||
    } mouse;
 | 
			
		||||
    struct {
 | 
			
		||||
      uint32_t    modifierFlags;
 | 
			
		||||
      NPNSString *characters;
 | 
			
		||||
      NPNSString *charactersIgnoringModifiers;
 | 
			
		||||
      NPBool      isARepeat;
 | 
			
		||||
      uint16_t    keyCode;
 | 
			
		||||
    } key;
 | 
			
		||||
    struct {
 | 
			
		||||
      CGContextRef context;
 | 
			
		||||
      double x;
 | 
			
		||||
      double y;
 | 
			
		||||
      double width;
 | 
			
		||||
      double height;
 | 
			
		||||
    } draw;
 | 
			
		||||
    struct {
 | 
			
		||||
      NPBool hasFocus;
 | 
			
		||||
    } focus;
 | 
			
		||||
    struct {
 | 
			
		||||
      NPNSString *text;
 | 
			
		||||
    } text;
 | 
			
		||||
  } data;
 | 
			
		||||
} NPCocoaEvent;
 | 
			
		||||
 | 
			
		||||
#ifndef NP_NO_CARBON
 | 
			
		||||
/* Non-standard event types that can be passed to HandleEvent */
 | 
			
		||||
enum NPEventType {
 | 
			
		||||
  NPEventType_GetFocusEvent = (osEvt + 16),
 | 
			
		||||
  NPEventType_LoseFocusEvent,
 | 
			
		||||
  NPEventType_AdjustCursorEvent,
 | 
			
		||||
  NPEventType_MenuCommandEvent,
 | 
			
		||||
  NPEventType_ClippingChangedEvent,
 | 
			
		||||
  NPEventType_ScrollingBeginsEvent = 1000,
 | 
			
		||||
  NPEventType_ScrollingEndsEvent
 | 
			
		||||
};
 | 
			
		||||
#endif /* NP_NO_CARBON */
 | 
			
		||||
 | 
			
		||||
#endif /* XP_MACOSX */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Values for mode passed to NPP_New:
 | 
			
		||||
 */
 | 
			
		||||
#define NP_EMBED 1
 | 
			
		||||
#define NP_FULL  2
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Values for stream type passed to NPP_NewStream:
 | 
			
		||||
 */
 | 
			
		||||
#define NP_NORMAL     1
 | 
			
		||||
#define NP_SEEK       2
 | 
			
		||||
#define NP_ASFILE     3
 | 
			
		||||
#define NP_ASFILEONLY 4
 | 
			
		||||
 | 
			
		||||
#define NP_MAXREADY (((unsigned)(~0)<<1)>>1)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Flags for NPP_ClearSiteData.
 | 
			
		||||
 */
 | 
			
		||||
#define NP_CLEAR_ALL   0
 | 
			
		||||
#define NP_CLEAR_CACHE (1 << 0)
 | 
			
		||||
 | 
			
		||||
#if !defined(__LP64__)
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
#pragma options align=reset
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* __LP64__ */
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
/*       Error and Reason Code definitions                              */
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Values of type NPError:
 | 
			
		||||
 */
 | 
			
		||||
#define NPERR_BASE                         0
 | 
			
		||||
#define NPERR_NO_ERROR                    (NPERR_BASE + 0)
 | 
			
		||||
#define NPERR_GENERIC_ERROR               (NPERR_BASE + 1)
 | 
			
		||||
#define NPERR_INVALID_INSTANCE_ERROR      (NPERR_BASE + 2)
 | 
			
		||||
#define NPERR_INVALID_FUNCTABLE_ERROR     (NPERR_BASE + 3)
 | 
			
		||||
#define NPERR_MODULE_LOAD_FAILED_ERROR    (NPERR_BASE + 4)
 | 
			
		||||
#define NPERR_OUT_OF_MEMORY_ERROR         (NPERR_BASE + 5)
 | 
			
		||||
#define NPERR_INVALID_PLUGIN_ERROR        (NPERR_BASE + 6)
 | 
			
		||||
#define NPERR_INVALID_PLUGIN_DIR_ERROR    (NPERR_BASE + 7)
 | 
			
		||||
#define NPERR_INCOMPATIBLE_VERSION_ERROR  (NPERR_BASE + 8)
 | 
			
		||||
#define NPERR_INVALID_PARAM               (NPERR_BASE + 9)
 | 
			
		||||
#define NPERR_INVALID_URL                 (NPERR_BASE + 10)
 | 
			
		||||
#define NPERR_FILE_NOT_FOUND              (NPERR_BASE + 11)
 | 
			
		||||
#define NPERR_NO_DATA                     (NPERR_BASE + 12)
 | 
			
		||||
#define NPERR_STREAM_NOT_SEEKABLE         (NPERR_BASE + 13)
 | 
			
		||||
#define NPERR_TIME_RANGE_NOT_SUPPORTED    (NPERR_BASE + 14)
 | 
			
		||||
#define NPERR_MALFORMED_SITE              (NPERR_BASE + 15)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Values of type NPReason:
 | 
			
		||||
 */
 | 
			
		||||
#define NPRES_BASE          0
 | 
			
		||||
#define NPRES_DONE         (NPRES_BASE + 0)
 | 
			
		||||
#define NPRES_NETWORK_ERR  (NPRES_BASE + 1)
 | 
			
		||||
#define NPRES_USER_BREAK   (NPRES_BASE + 2)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Don't use these obsolete error codes any more.
 | 
			
		||||
 */
 | 
			
		||||
#define NP_NOERR  NP_NOERR_is_obsolete_use_NPERR_NO_ERROR
 | 
			
		||||
#define NP_EINVAL NP_EINVAL_is_obsolete_use_NPERR_GENERIC_ERROR
 | 
			
		||||
#define NP_EABORT NP_EABORT_is_obsolete_use_NPRES_USER_BREAK
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Version feature information
 | 
			
		||||
 */
 | 
			
		||||
#define NPVERS_HAS_STREAMOUTPUT             8
 | 
			
		||||
#define NPVERS_HAS_NOTIFICATION             9
 | 
			
		||||
#define NPVERS_HAS_LIVECONNECT              9
 | 
			
		||||
#define NPVERS_68K_HAS_LIVECONNECT          11
 | 
			
		||||
#define NPVERS_HAS_WINDOWLESS               11
 | 
			
		||||
#define NPVERS_HAS_XPCONNECT_SCRIPTING      13
 | 
			
		||||
#define NPVERS_HAS_NPRUNTIME_SCRIPTING      14
 | 
			
		||||
#define NPVERS_HAS_FORM_VALUES              15
 | 
			
		||||
#define NPVERS_HAS_POPUPS_ENABLED_STATE     16
 | 
			
		||||
#define NPVERS_HAS_RESPONSE_HEADERS         17
 | 
			
		||||
#define NPVERS_HAS_NPOBJECT_ENUM            18
 | 
			
		||||
#define NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL 19
 | 
			
		||||
#define NPVERS_HAS_ALL_NETWORK_STREAMS      20
 | 
			
		||||
#define NPVERS_HAS_URL_AND_AUTH_INFO        21
 | 
			
		||||
#define NPVERS_HAS_PRIVATE_MODE             22
 | 
			
		||||
#define NPVERS_MACOSX_HAS_COCOA_EVENTS      23
 | 
			
		||||
#define NPVERS_HAS_ADVANCED_KEY_HANDLING    25
 | 
			
		||||
#define NPVERS_HAS_URL_REDIRECT_HANDLING    26
 | 
			
		||||
#define NPVERS_HAS_CLEAR_SITE_DATA          27
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
/*                        Function Prototypes                           */
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
#if defined(__OS2__)
 | 
			
		||||
#define NP_LOADDS _System
 | 
			
		||||
#else
 | 
			
		||||
#define NP_LOADDS
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* NPP_* functions are provided by the plugin and called by the navigator. */
 | 
			
		||||
 | 
			
		||||
#if defined(XP_UNIX)
 | 
			
		||||
const char* NPP_GetMIMEDescription(void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
NPError NP_LOADDS NPP_New(NPMIMEType pluginType, NPP instance,
 | 
			
		||||
                          uint16_t mode, int16_t argc, char* argn[],
 | 
			
		||||
                          char* argv[], NPSavedData* saved);
 | 
			
		||||
NPError NP_LOADDS NPP_Destroy(NPP instance, NPSavedData** save);
 | 
			
		||||
NPError NP_LOADDS NPP_SetWindow(NPP instance, NPWindow* window);
 | 
			
		||||
NPError NP_LOADDS NPP_NewStream(NPP instance, NPMIMEType type,
 | 
			
		||||
                                NPStream* stream, NPBool seekable,
 | 
			
		||||
                                uint16_t* stype);
 | 
			
		||||
NPError NP_LOADDS NPP_DestroyStream(NPP instance, NPStream* stream,
 | 
			
		||||
                                    NPReason reason);
 | 
			
		||||
int32_t NP_LOADDS NPP_WriteReady(NPP instance, NPStream* stream);
 | 
			
		||||
int32_t NP_LOADDS NPP_Write(NPP instance, NPStream* stream, int32_t offset,
 | 
			
		||||
                            int32_t len, void* buffer);
 | 
			
		||||
void    NP_LOADDS NPP_StreamAsFile(NPP instance, NPStream* stream,
 | 
			
		||||
                                   const char* fname);
 | 
			
		||||
void    NP_LOADDS NPP_Print(NPP instance, NPPrint* platformPrint);
 | 
			
		||||
int16_t NP_LOADDS NPP_HandleEvent(NPP instance, void* event);
 | 
			
		||||
void    NP_LOADDS NPP_URLNotify(NPP instance, const char* url,
 | 
			
		||||
                                NPReason reason, void* notifyData);
 | 
			
		||||
NPError NP_LOADDS NPP_GetValue(NPP instance, NPPVariable variable, void *value);
 | 
			
		||||
NPError NP_LOADDS NPP_SetValue(NPP instance, NPNVariable variable, void *value);
 | 
			
		||||
NPBool  NP_LOADDS NPP_GotFocus(NPP instance, NPFocusDirection direction);
 | 
			
		||||
void    NP_LOADDS NPP_LostFocus(NPP instance);
 | 
			
		||||
void    NP_LOADDS NPP_URLRedirectNotify(NPP instance, const char* url, int32_t status, void* notifyData);
 | 
			
		||||
NPError NP_LOADDS NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge);
 | 
			
		||||
char**  NP_LOADDS NPP_GetSitesWithData(void);
 | 
			
		||||
 | 
			
		||||
/* NPN_* functions are provided by the navigator and called by the plugin. */
 | 
			
		||||
void        NP_LOADDS NPN_Version(int* plugin_major, int* plugin_minor,
 | 
			
		||||
                                  int* netscape_major, int* netscape_minor);
 | 
			
		||||
NPError     NP_LOADDS NPN_GetURLNotify(NPP instance, const char* url,
 | 
			
		||||
                                       const char* target, void* notifyData);
 | 
			
		||||
NPError     NP_LOADDS NPN_GetURL(NPP instance, const char* url,
 | 
			
		||||
                                 const char* target);
 | 
			
		||||
NPError     NP_LOADDS NPN_PostURLNotify(NPP instance, const char* url,
 | 
			
		||||
                                        const char* target, uint32_t len,
 | 
			
		||||
                                        const char* buf, NPBool file,
 | 
			
		||||
                                        void* notifyData);
 | 
			
		||||
NPError     NP_LOADDS NPN_PostURL(NPP instance, const char* url,
 | 
			
		||||
                                  const char* target, uint32_t len,
 | 
			
		||||
                                  const char* buf, NPBool file);
 | 
			
		||||
NPError     NP_LOADDS NPN_RequestRead(NPStream* stream, NPByteRange* rangeList);
 | 
			
		||||
NPError     NP_LOADDS NPN_NewStream(NPP instance, NPMIMEType type,
 | 
			
		||||
                                    const char* target, NPStream** stream);
 | 
			
		||||
int32_t     NP_LOADDS NPN_Write(NPP instance, NPStream* stream, int32_t len,
 | 
			
		||||
                                void* buffer);
 | 
			
		||||
NPError     NP_LOADDS NPN_DestroyStream(NPP instance, NPStream* stream,
 | 
			
		||||
                                        NPReason reason);
 | 
			
		||||
void        NP_LOADDS NPN_Status(NPP instance, const char* message);
 | 
			
		||||
const char* NP_LOADDS NPN_UserAgent(NPP instance);
 | 
			
		||||
void*       NP_LOADDS NPN_MemAlloc(uint32_t size);
 | 
			
		||||
void        NP_LOADDS NPN_MemFree(void* ptr);
 | 
			
		||||
uint32_t    NP_LOADDS NPN_MemFlush(uint32_t size);
 | 
			
		||||
void        NP_LOADDS NPN_ReloadPlugins(NPBool reloadPages);
 | 
			
		||||
NPError     NP_LOADDS NPN_GetValue(NPP instance, NPNVariable variable,
 | 
			
		||||
                                   void *value);
 | 
			
		||||
NPError     NP_LOADDS NPN_SetValue(NPP instance, NPPVariable variable,
 | 
			
		||||
                                   void *value);
 | 
			
		||||
void        NP_LOADDS NPN_InvalidateRect(NPP instance, NPRect *invalidRect);
 | 
			
		||||
void        NP_LOADDS NPN_InvalidateRegion(NPP instance,
 | 
			
		||||
                                           NPRegion invalidRegion);
 | 
			
		||||
void        NP_LOADDS NPN_ForceRedraw(NPP instance);
 | 
			
		||||
void        NP_LOADDS NPN_PushPopupsEnabledState(NPP instance, NPBool enabled);
 | 
			
		||||
void        NP_LOADDS NPN_PopPopupsEnabledState(NPP instance);
 | 
			
		||||
void        NP_LOADDS NPN_PluginThreadAsyncCall(NPP instance,
 | 
			
		||||
                                                void (*func) (void *),
 | 
			
		||||
                                                void *userData);
 | 
			
		||||
NPError     NP_LOADDS NPN_GetValueForURL(NPP instance, NPNURLVariable variable,
 | 
			
		||||
                                         const char *url, char **value,
 | 
			
		||||
                                         uint32_t *len);
 | 
			
		||||
NPError     NP_LOADDS NPN_SetValueForURL(NPP instance, NPNURLVariable variable,
 | 
			
		||||
                                         const char *url, const char *value,
 | 
			
		||||
                                         uint32_t len);
 | 
			
		||||
NPError     NP_LOADDS NPN_GetAuthenticationInfo(NPP instance,
 | 
			
		||||
                                                const char *protocol,
 | 
			
		||||
                                                const char *host, int32_t port,
 | 
			
		||||
                                                const char *scheme,
 | 
			
		||||
                                                const char *realm,
 | 
			
		||||
                                                char **username, uint32_t *ulen,
 | 
			
		||||
                                                char **password,
 | 
			
		||||
                                                uint32_t *plen);
 | 
			
		||||
uint32_t    NP_LOADDS NPN_ScheduleTimer(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID));
 | 
			
		||||
void        NP_LOADDS NPN_UnscheduleTimer(NPP instance, uint32_t timerID);
 | 
			
		||||
NPError     NP_LOADDS NPN_PopUpContextMenu(NPP instance, NPMenu* menu);
 | 
			
		||||
NPBool      NP_LOADDS NPN_ConvertPoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
 | 
			
		||||
NPBool      NP_LOADDS NPN_HandleEvent(NPP instance, void *event, NPBool handled);
 | 
			
		||||
NPBool      NP_LOADDS NPN_UnfocusInstance(NPP instance, NPFocusDirection direction);
 | 
			
		||||
void        NP_LOADDS NPN_URLRedirectResponse(NPP instance, void* notifyData, NPBool allow);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}  /* end extern "C" */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* RC_INVOKED */
 | 
			
		||||
#if defined(__OS2__)
 | 
			
		||||
#pragma pack()
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* npapi_h_ */
 | 
			
		||||
							
								
								
									
										322
									
								
								browser-plugin/npapi/npfunctions.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,322 @@
 | 
			
		||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 | 
			
		||||
/* ***** BEGIN LICENSE BLOCK *****
 | 
			
		||||
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 | 
			
		||||
 *
 | 
			
		||||
 * The contents of this file are subject to the Mozilla Public License Version
 | 
			
		||||
 * 1.1 (the "License"); you may not use this file except in compliance with
 | 
			
		||||
 * the License. You may obtain a copy of the License at
 | 
			
		||||
 * http://www.mozilla.org/MPL/
 | 
			
		||||
 *
 | 
			
		||||
 * Software distributed under the License is distributed on an "AS IS" basis,
 | 
			
		||||
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 | 
			
		||||
 * for the specific language governing rights and limitations under the
 | 
			
		||||
 * License.
 | 
			
		||||
 *
 | 
			
		||||
 * The Original Code is mozilla.org code.
 | 
			
		||||
 *
 | 
			
		||||
 * The Initial Developer of the Original Code is
 | 
			
		||||
 * Netscape Communications Corporation.
 | 
			
		||||
 * Portions created by the Initial Developer are Copyright (C) 1998
 | 
			
		||||
 * the Initial Developer. All Rights Reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Contributor(s):
 | 
			
		||||
 *
 | 
			
		||||
 * Alternatively, the contents of this file may be used under the terms of
 | 
			
		||||
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 | 
			
		||||
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 | 
			
		||||
 * in which case the provisions of the GPL or the LGPL are applicable instead
 | 
			
		||||
 * of those above. If you wish to allow use of your version of this file only
 | 
			
		||||
 * under the terms of either the GPL or the LGPL, and not to allow others to
 | 
			
		||||
 * use your version of this file under the terms of the MPL, indicate your
 | 
			
		||||
 * decision by deleting the provisions above and replace them with the notice
 | 
			
		||||
 * and other provisions required by the GPL or the LGPL. If you do not delete
 | 
			
		||||
 * the provisions above, a recipient may use your version of this file under
 | 
			
		||||
 * the terms of any one of the MPL, the GPL or the LGPL.
 | 
			
		||||
 *
 | 
			
		||||
 * ***** END LICENSE BLOCK ***** */
 | 
			
		||||
 | 
			
		||||
#ifndef npfunctions_h_
 | 
			
		||||
#define npfunctions_h_
 | 
			
		||||
 | 
			
		||||
#ifdef __OS2__
 | 
			
		||||
#pragma pack(1)
 | 
			
		||||
#define NP_LOADDS _System
 | 
			
		||||
#else
 | 
			
		||||
#define NP_LOADDS
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "npapi.h"
 | 
			
		||||
#include "npruntime.h"
 | 
			
		||||
 | 
			
		||||
typedef NPError      (* NP_LOADDS NPP_NewProcPtr)(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved);
 | 
			
		||||
typedef NPError      (* NP_LOADDS NPP_DestroyProcPtr)(NPP instance, NPSavedData** save);
 | 
			
		||||
typedef NPError      (* NP_LOADDS NPP_SetWindowProcPtr)(NPP instance, NPWindow* window);
 | 
			
		||||
typedef NPError      (* NP_LOADDS NPP_NewStreamProcPtr)(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype);
 | 
			
		||||
typedef NPError      (* NP_LOADDS NPP_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason);
 | 
			
		||||
typedef int32_t      (* NP_LOADDS NPP_WriteReadyProcPtr)(NPP instance, NPStream* stream);
 | 
			
		||||
typedef int32_t      (* NP_LOADDS NPP_WriteProcPtr)(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer);
 | 
			
		||||
typedef void         (* NP_LOADDS NPP_StreamAsFileProcPtr)(NPP instance, NPStream* stream, const char* fname);
 | 
			
		||||
typedef void         (* NP_LOADDS NPP_PrintProcPtr)(NPP instance, NPPrint* platformPrint);
 | 
			
		||||
typedef int16_t      (* NP_LOADDS NPP_HandleEventProcPtr)(NPP instance, void* event);
 | 
			
		||||
typedef void         (* NP_LOADDS NPP_URLNotifyProcPtr)(NPP instance, const char* url, NPReason reason, void* notifyData);
 | 
			
		||||
/* Any NPObjects returned to the browser via NPP_GetValue should be retained
 | 
			
		||||
   by the plugin on the way out. The browser is responsible for releasing. */
 | 
			
		||||
typedef NPError      (* NP_LOADDS NPP_GetValueProcPtr)(NPP instance, NPPVariable variable, void *ret_value);
 | 
			
		||||
typedef NPError      (* NP_LOADDS NPP_SetValueProcPtr)(NPP instance, NPNVariable variable, void *value);
 | 
			
		||||
typedef NPBool       (* NP_LOADDS NPP_GotFocusPtr)(NPP instance, NPFocusDirection direction);
 | 
			
		||||
typedef void         (* NP_LOADDS NPP_LostFocusPtr)(NPP instance);
 | 
			
		||||
typedef void         (* NP_LOADDS NPP_URLRedirectNotifyPtr)(NPP instance, const char* url, int32_t status, void* notifyData);
 | 
			
		||||
typedef NPError      (* NP_LOADDS NPP_ClearSiteDataPtr)(const char* site, uint64_t flags, uint64_t maxAge);
 | 
			
		||||
typedef char**       (* NP_LOADDS NPP_GetSitesWithDataPtr)(void);
 | 
			
		||||
 | 
			
		||||
typedef NPError      (*NPN_GetValueProcPtr)(NPP instance, NPNVariable variable, void *ret_value);
 | 
			
		||||
typedef NPError      (*NPN_SetValueProcPtr)(NPP instance, NPPVariable variable, void *value);
 | 
			
		||||
typedef NPError      (*NPN_GetURLNotifyProcPtr)(NPP instance, const char* url, const char* window, void* notifyData);
 | 
			
		||||
typedef NPError      (*NPN_PostURLNotifyProcPtr)(NPP instance, const char* url, const char* window, uint32_t len, const char* buf, NPBool file, void* notifyData);
 | 
			
		||||
typedef NPError      (*NPN_GetURLProcPtr)(NPP instance, const char* url, const char* window);
 | 
			
		||||
typedef NPError      (*NPN_PostURLProcPtr)(NPP instance, const char* url, const char* window, uint32_t len, const char* buf, NPBool file);
 | 
			
		||||
typedef NPError      (*NPN_RequestReadProcPtr)(NPStream* stream, NPByteRange* rangeList);
 | 
			
		||||
typedef NPError      (*NPN_NewStreamProcPtr)(NPP instance, NPMIMEType type, const char* window, NPStream** stream);
 | 
			
		||||
typedef int32_t      (*NPN_WriteProcPtr)(NPP instance, NPStream* stream, int32_t len, void* buffer);
 | 
			
		||||
typedef NPError      (*NPN_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason);
 | 
			
		||||
typedef void         (*NPN_StatusProcPtr)(NPP instance, const char* message);
 | 
			
		||||
/* Browser manages the lifetime of the buffer returned by NPN_UserAgent, don't
 | 
			
		||||
   depend on it sticking around and don't free it. */
 | 
			
		||||
typedef const char*  (*NPN_UserAgentProcPtr)(NPP instance);
 | 
			
		||||
typedef void*        (*NPN_MemAllocProcPtr)(uint32_t size);
 | 
			
		||||
typedef void         (*NPN_MemFreeProcPtr)(void* ptr);
 | 
			
		||||
typedef uint32_t     (*NPN_MemFlushProcPtr)(uint32_t size);
 | 
			
		||||
typedef void         (*NPN_ReloadPluginsProcPtr)(NPBool reloadPages);
 | 
			
		||||
typedef void*        (*NPN_GetJavaEnvProcPtr)(void);
 | 
			
		||||
typedef void*        (*NPN_GetJavaPeerProcPtr)(NPP instance);
 | 
			
		||||
typedef void         (*NPN_InvalidateRectProcPtr)(NPP instance, NPRect *rect);
 | 
			
		||||
typedef void         (*NPN_InvalidateRegionProcPtr)(NPP instance, NPRegion region);
 | 
			
		||||
typedef void         (*NPN_ForceRedrawProcPtr)(NPP instance);
 | 
			
		||||
typedef NPIdentifier (*NPN_GetStringIdentifierProcPtr)(const NPUTF8* name);
 | 
			
		||||
typedef void         (*NPN_GetStringIdentifiersProcPtr)(const NPUTF8** names, int32_t nameCount, NPIdentifier* identifiers);
 | 
			
		||||
typedef NPIdentifier (*NPN_GetIntIdentifierProcPtr)(int32_t intid);
 | 
			
		||||
typedef bool         (*NPN_IdentifierIsStringProcPtr)(NPIdentifier identifier);
 | 
			
		||||
typedef NPUTF8*      (*NPN_UTF8FromIdentifierProcPtr)(NPIdentifier identifier);
 | 
			
		||||
typedef int32_t      (*NPN_IntFromIdentifierProcPtr)(NPIdentifier identifier);
 | 
			
		||||
typedef NPObject*    (*NPN_CreateObjectProcPtr)(NPP npp, NPClass *aClass);
 | 
			
		||||
typedef NPObject*    (*NPN_RetainObjectProcPtr)(NPObject *obj);
 | 
			
		||||
typedef void         (*NPN_ReleaseObjectProcPtr)(NPObject *obj);
 | 
			
		||||
typedef bool         (*NPN_InvokeProcPtr)(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result);
 | 
			
		||||
typedef bool         (*NPN_InvokeDefaultProcPtr)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result);
 | 
			
		||||
typedef bool         (*NPN_EvaluateProcPtr)(NPP npp, NPObject *obj, NPString *script, NPVariant *result);
 | 
			
		||||
typedef bool         (*NPN_GetPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result);
 | 
			
		||||
typedef bool         (*NPN_SetPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value);
 | 
			
		||||
typedef bool         (*NPN_RemovePropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName);
 | 
			
		||||
typedef bool         (*NPN_HasPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName);
 | 
			
		||||
typedef bool         (*NPN_HasMethodProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName);
 | 
			
		||||
typedef void         (*NPN_ReleaseVariantValueProcPtr)(NPVariant *variant);
 | 
			
		||||
typedef void         (*NPN_SetExceptionProcPtr)(NPObject *obj, const NPUTF8 *message);
 | 
			
		||||
typedef void         (*NPN_PushPopupsEnabledStateProcPtr)(NPP npp, NPBool enabled);
 | 
			
		||||
typedef void         (*NPN_PopPopupsEnabledStateProcPtr)(NPP npp);
 | 
			
		||||
typedef bool         (*NPN_EnumerateProcPtr)(NPP npp, NPObject *obj, NPIdentifier **identifier, uint32_t *count);
 | 
			
		||||
typedef void         (*NPN_PluginThreadAsyncCallProcPtr)(NPP instance, void (*func)(void *), void *userData);
 | 
			
		||||
typedef bool         (*NPN_ConstructProcPtr)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result);
 | 
			
		||||
typedef NPError      (*NPN_GetValueForURLPtr)(NPP npp, NPNURLVariable variable, const char *url, char **value, uint32_t *len);
 | 
			
		||||
typedef NPError      (*NPN_SetValueForURLPtr)(NPP npp, NPNURLVariable variable, const char *url, const char *value, uint32_t len);
 | 
			
		||||
typedef NPError      (*NPN_GetAuthenticationInfoPtr)(NPP npp, const char *protocol, const char *host, int32_t port, const char *scheme, const char *realm, char **username, uint32_t *ulen, char **password, uint32_t *plen);
 | 
			
		||||
typedef uint32_t     (*NPN_ScheduleTimerPtr)(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID));
 | 
			
		||||
typedef void         (*NPN_UnscheduleTimerPtr)(NPP instance, uint32_t timerID);
 | 
			
		||||
typedef NPError      (*NPN_PopUpContextMenuPtr)(NPP instance, NPMenu* menu);
 | 
			
		||||
typedef NPBool       (*NPN_ConvertPointPtr)(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
 | 
			
		||||
typedef NPBool       (*NPN_HandleEventPtr)(NPP instance, void *event, NPBool handled);
 | 
			
		||||
typedef NPBool       (*NPN_UnfocusInstancePtr)(NPP instance, NPFocusDirection direction);
 | 
			
		||||
typedef void         (*NPN_URLRedirectResponsePtr)(NPP instance, void* notifyData, NPBool allow);
 | 
			
		||||
 | 
			
		||||
typedef struct _NPPluginFuncs {
 | 
			
		||||
  uint16_t size;
 | 
			
		||||
  uint16_t version;
 | 
			
		||||
  NPP_NewProcPtr newp;
 | 
			
		||||
  NPP_DestroyProcPtr destroy;
 | 
			
		||||
  NPP_SetWindowProcPtr setwindow;
 | 
			
		||||
  NPP_NewStreamProcPtr newstream;
 | 
			
		||||
  NPP_DestroyStreamProcPtr destroystream;
 | 
			
		||||
  NPP_StreamAsFileProcPtr asfile;
 | 
			
		||||
  NPP_WriteReadyProcPtr writeready;
 | 
			
		||||
  NPP_WriteProcPtr write;
 | 
			
		||||
  NPP_PrintProcPtr print;
 | 
			
		||||
  NPP_HandleEventProcPtr event;
 | 
			
		||||
  NPP_URLNotifyProcPtr urlnotify;
 | 
			
		||||
  void* javaClass;
 | 
			
		||||
  NPP_GetValueProcPtr getvalue;
 | 
			
		||||
  NPP_SetValueProcPtr setvalue;
 | 
			
		||||
  NPP_GotFocusPtr gotfocus;
 | 
			
		||||
  NPP_LostFocusPtr lostfocus;
 | 
			
		||||
  NPP_URLRedirectNotifyPtr urlredirectnotify;
 | 
			
		||||
  NPP_ClearSiteDataPtr clearsitedata;
 | 
			
		||||
  NPP_GetSitesWithDataPtr getsiteswithdata;
 | 
			
		||||
} NPPluginFuncs;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPNetscapeFuncs {
 | 
			
		||||
  uint16_t size;
 | 
			
		||||
  uint16_t version;
 | 
			
		||||
  NPN_GetURLProcPtr geturl;
 | 
			
		||||
  NPN_PostURLProcPtr posturl;
 | 
			
		||||
  NPN_RequestReadProcPtr requestread;
 | 
			
		||||
  NPN_NewStreamProcPtr newstream;
 | 
			
		||||
  NPN_WriteProcPtr write;
 | 
			
		||||
  NPN_DestroyStreamProcPtr destroystream;
 | 
			
		||||
  NPN_StatusProcPtr status;
 | 
			
		||||
  NPN_UserAgentProcPtr uagent;
 | 
			
		||||
  NPN_MemAllocProcPtr memalloc;
 | 
			
		||||
  NPN_MemFreeProcPtr memfree;
 | 
			
		||||
  NPN_MemFlushProcPtr memflush;
 | 
			
		||||
  NPN_ReloadPluginsProcPtr reloadplugins;
 | 
			
		||||
  NPN_GetJavaEnvProcPtr getJavaEnv;
 | 
			
		||||
  NPN_GetJavaPeerProcPtr getJavaPeer;
 | 
			
		||||
  NPN_GetURLNotifyProcPtr geturlnotify;
 | 
			
		||||
  NPN_PostURLNotifyProcPtr posturlnotify;
 | 
			
		||||
  NPN_GetValueProcPtr getvalue;
 | 
			
		||||
  NPN_SetValueProcPtr setvalue;
 | 
			
		||||
  NPN_InvalidateRectProcPtr invalidaterect;
 | 
			
		||||
  NPN_InvalidateRegionProcPtr invalidateregion;
 | 
			
		||||
  NPN_ForceRedrawProcPtr forceredraw;
 | 
			
		||||
  NPN_GetStringIdentifierProcPtr getstringidentifier;
 | 
			
		||||
  NPN_GetStringIdentifiersProcPtr getstringidentifiers;
 | 
			
		||||
  NPN_GetIntIdentifierProcPtr getintidentifier;
 | 
			
		||||
  NPN_IdentifierIsStringProcPtr identifierisstring;
 | 
			
		||||
  NPN_UTF8FromIdentifierProcPtr utf8fromidentifier;
 | 
			
		||||
  NPN_IntFromIdentifierProcPtr intfromidentifier;
 | 
			
		||||
  NPN_CreateObjectProcPtr createobject;
 | 
			
		||||
  NPN_RetainObjectProcPtr retainobject;
 | 
			
		||||
  NPN_ReleaseObjectProcPtr releaseobject;
 | 
			
		||||
  NPN_InvokeProcPtr invoke;
 | 
			
		||||
  NPN_InvokeDefaultProcPtr invokeDefault;
 | 
			
		||||
  NPN_EvaluateProcPtr evaluate;
 | 
			
		||||
  NPN_GetPropertyProcPtr getproperty;
 | 
			
		||||
  NPN_SetPropertyProcPtr setproperty;
 | 
			
		||||
  NPN_RemovePropertyProcPtr removeproperty;
 | 
			
		||||
  NPN_HasPropertyProcPtr hasproperty;
 | 
			
		||||
  NPN_HasMethodProcPtr hasmethod;
 | 
			
		||||
  NPN_ReleaseVariantValueProcPtr releasevariantvalue;
 | 
			
		||||
  NPN_SetExceptionProcPtr setexception;
 | 
			
		||||
  NPN_PushPopupsEnabledStateProcPtr pushpopupsenabledstate;
 | 
			
		||||
  NPN_PopPopupsEnabledStateProcPtr poppopupsenabledstate;
 | 
			
		||||
  NPN_EnumerateProcPtr enumerate;
 | 
			
		||||
  NPN_PluginThreadAsyncCallProcPtr pluginthreadasynccall;
 | 
			
		||||
  NPN_ConstructProcPtr construct;
 | 
			
		||||
  NPN_GetValueForURLPtr getvalueforurl;
 | 
			
		||||
  NPN_SetValueForURLPtr setvalueforurl;
 | 
			
		||||
  NPN_GetAuthenticationInfoPtr getauthenticationinfo;
 | 
			
		||||
  NPN_ScheduleTimerPtr scheduletimer;
 | 
			
		||||
  NPN_UnscheduleTimerPtr unscheduletimer;
 | 
			
		||||
  NPN_PopUpContextMenuPtr popupcontextmenu;
 | 
			
		||||
  NPN_ConvertPointPtr convertpoint;
 | 
			
		||||
  NPN_HandleEventPtr handleevent;
 | 
			
		||||
  NPN_UnfocusInstancePtr unfocusinstance;
 | 
			
		||||
  NPN_URLRedirectResponsePtr urlredirectresponse;
 | 
			
		||||
} NPNetscapeFuncs;
 | 
			
		||||
 | 
			
		||||
#ifdef XP_MACOSX
 | 
			
		||||
/*
 | 
			
		||||
 * Mac OS X version(s) of NP_GetMIMEDescription(const char *)
 | 
			
		||||
 * These can be called to retreive MIME information from the plugin dynamically
 | 
			
		||||
 *
 | 
			
		||||
 * Note: For compatibility with Quicktime, BPSupportedMIMEtypes is another way
 | 
			
		||||
 *       to get mime info from the plugin only on OSX and may not be supported
 | 
			
		||||
 *       in furture version -- use NP_GetMIMEDescription instead
 | 
			
		||||
 */
 | 
			
		||||
enum
 | 
			
		||||
{
 | 
			
		||||
 kBPSupportedMIMETypesStructVers_1    = 1
 | 
			
		||||
};
 | 
			
		||||
typedef struct _BPSupportedMIMETypes
 | 
			
		||||
{
 | 
			
		||||
 SInt32    structVersion;      /* struct version */
 | 
			
		||||
 Handle    typeStrings;        /* STR# formated handle, allocated by plug-in */
 | 
			
		||||
 Handle    infoStrings;        /* STR# formated handle, allocated by plug-in */
 | 
			
		||||
} BPSupportedMIMETypes;
 | 
			
		||||
OSErr BP_GetSupportedMIMETypes(BPSupportedMIMETypes *mimeInfo, UInt32 flags);
 | 
			
		||||
#define NP_GETMIMEDESCRIPTION_NAME "NP_GetMIMEDescription"
 | 
			
		||||
typedef const char* (*NP_GetMIMEDescriptionProcPtr)(void);
 | 
			
		||||
typedef OSErr (*BP_GetSupportedMIMETypesProcPtr)(BPSupportedMIMETypes*, UInt32);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32)
 | 
			
		||||
#define OSCALL WINAPI
 | 
			
		||||
#else
 | 
			
		||||
#if defined(__OS2__)
 | 
			
		||||
#define OSCALL _System
 | 
			
		||||
#else
 | 
			
		||||
#define OSCALL
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(XP_UNIX)
 | 
			
		||||
/* GCC 3.3 and later support the visibility attribute. */
 | 
			
		||||
#if defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))
 | 
			
		||||
#define NP_VISIBILITY_DEFAULT __attribute__((visibility("default")))
 | 
			
		||||
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
 | 
			
		||||
#define NP_VISIBILITY_DEFAULT __global
 | 
			
		||||
#else
 | 
			
		||||
#define NP_VISIBILITY_DEFAULT
 | 
			
		||||
#endif
 | 
			
		||||
#define NP_EXPORT(__type) NP_VISIBILITY_DEFAULT __type
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32) || defined (__OS2__)
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
/* plugin meta member functions */
 | 
			
		||||
#if defined(__OS2__)
 | 
			
		||||
typedef struct _NPPluginData {   /* Alternate OS2 Plugin interface */
 | 
			
		||||
  char *pMimeTypes;
 | 
			
		||||
  char *pFileExtents;
 | 
			
		||||
  char *pFileOpenTemplate;
 | 
			
		||||
  char *pProductName;
 | 
			
		||||
  char *pProductDescription;
 | 
			
		||||
  unsigned long dwProductVersionMS;
 | 
			
		||||
  unsigned long dwProductVersionLS;
 | 
			
		||||
} NPPluginData;
 | 
			
		||||
typedef NPError     (*NP_GetPluginDataFunc)(NPPluginData*);
 | 
			
		||||
NPError OSCALL      NP_GetPluginData(NPPluginData * pPluginData);
 | 
			
		||||
#endif
 | 
			
		||||
typedef NPError     (*NP_GetEntryPointsFunc)(NPPluginFuncs*);
 | 
			
		||||
NPError OSCALL      NP_GetEntryPoints(NPPluginFuncs* pFuncs);
 | 
			
		||||
typedef NPError     (*NP_InitializeFunc)(NPNetscapeFuncs*);
 | 
			
		||||
NPError OSCALL      NP_Initialize(NPNetscapeFuncs* bFuncs);
 | 
			
		||||
typedef NPError     (*NP_ShutdownFunc)(void);
 | 
			
		||||
NPError OSCALL      NP_Shutdown(void);
 | 
			
		||||
typedef const char* (*NP_GetMIMEDescriptionFunc)(void);
 | 
			
		||||
const char*         NP_GetMIMEDescription(void);
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__OS2__)
 | 
			
		||||
#pragma pack()
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef XP_UNIX
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
typedef char*          (*NP_GetPluginVersionFunc)(void);
 | 
			
		||||
NP_EXPORT(char*)       NP_GetPluginVersion(void);
 | 
			
		||||
typedef const char*    (*NP_GetMIMEDescriptionFunc)(void);
 | 
			
		||||
NP_EXPORT(const char*) NP_GetMIMEDescription(void);
 | 
			
		||||
#ifdef XP_MACOSX
 | 
			
		||||
typedef NPError        (*NP_InitializeFunc)(NPNetscapeFuncs*);
 | 
			
		||||
NP_EXPORT(NPError)     NP_Initialize(NPNetscapeFuncs* bFuncs);
 | 
			
		||||
typedef NPError        (*NP_GetEntryPointsFunc)(NPPluginFuncs*);
 | 
			
		||||
NP_EXPORT(NPError)     NP_GetEntryPoints(NPPluginFuncs* pFuncs);
 | 
			
		||||
#else
 | 
			
		||||
typedef NPError        (*NP_InitializeFunc)(NPNetscapeFuncs*, NPPluginFuncs*);
 | 
			
		||||
NP_EXPORT(NPError)     NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs);
 | 
			
		||||
#endif
 | 
			
		||||
typedef NPError        (*NP_ShutdownFunc)(void);
 | 
			
		||||
NP_EXPORT(NPError)     NP_Shutdown(void);
 | 
			
		||||
typedef NPError        (*NP_GetValueFunc)(void *, NPPVariable, void *);
 | 
			
		||||
NP_EXPORT(NPError)     NP_GetValue(void *future, NPPVariable aVariable, void *aValue);
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* npfunctions_h_ */
 | 
			
		||||
							
								
								
									
										393
									
								
								browser-plugin/npapi/npruntime.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,393 @@
 | 
			
		||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2004, Apple Computer, Inc. and The Mozilla Foundation.
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions are
 | 
			
		||||
 * met:
 | 
			
		||||
 *
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 * notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 * notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 * documentation and/or other materials provided with the distribution.
 | 
			
		||||
 * 3. Neither the names of Apple Computer, Inc. ("Apple") or The Mozilla
 | 
			
		||||
 * Foundation ("Mozilla") nor the names of their contributors may be used
 | 
			
		||||
 * to endorse or promote products derived from this software without
 | 
			
		||||
 * specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY APPLE, MOZILLA AND THEIR CONTRIBUTORS "AS
 | 
			
		||||
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 | 
			
		||||
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 | 
			
		||||
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE, MOZILLA OR
 | 
			
		||||
 * THEIR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 | 
			
		||||
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
			
		||||
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 | 
			
		||||
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
			
		||||
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#ifndef _NP_RUNTIME_H_
 | 
			
		||||
#define _NP_RUNTIME_H_
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "nptypes.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    This API is used to facilitate binding code written in C to script
 | 
			
		||||
    objects.  The API in this header does not assume the presence of a
 | 
			
		||||
    user agent.  That is, it can be used to bind C code to scripting
 | 
			
		||||
    environments outside of the context of a user agent.
 | 
			
		||||
 | 
			
		||||
    However, the normal use of the this API is in the context of a
 | 
			
		||||
    scripting environment running in a browser or other user agent.
 | 
			
		||||
    In particular it is used to support the extended Netscape
 | 
			
		||||
    script-ability API for plugins (NP-SAP).  NP-SAP is an extension
 | 
			
		||||
    of the Netscape plugin API.  As such we have adopted the use of
 | 
			
		||||
    the "NP" prefix for this API.
 | 
			
		||||
 | 
			
		||||
    The following NP{N|P}Variables were added to the Netscape plugin
 | 
			
		||||
    API (in npapi.h):
 | 
			
		||||
 | 
			
		||||
    NPNVWindowNPObject
 | 
			
		||||
    NPNVPluginElementNPObject
 | 
			
		||||
    NPPVpluginScriptableNPObject
 | 
			
		||||
 | 
			
		||||
    These variables are exposed through NPN_GetValue() and
 | 
			
		||||
    NPP_GetValue() (respectively) and are used to establish the
 | 
			
		||||
    initial binding between the user agent and native code.  The DOM
 | 
			
		||||
    objects in the user agent can be examined and manipulated using
 | 
			
		||||
    the NPN_ functions that operate on NPObjects described in this
 | 
			
		||||
    header.
 | 
			
		||||
 | 
			
		||||
    To the extent possible the assumptions about the scripting
 | 
			
		||||
    language used by the scripting environment have been minimized.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#define NP_BEGIN_MACRO  do {
 | 
			
		||||
#define NP_END_MACRO    } while (0)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    Objects (non-primitive data) passed between 'C' and script is
 | 
			
		||||
    always wrapped in an NPObject.  The 'interface' of an NPObject is
 | 
			
		||||
    described by an NPClass.
 | 
			
		||||
*/
 | 
			
		||||
typedef struct NPObject NPObject;
 | 
			
		||||
typedef struct NPClass NPClass;
 | 
			
		||||
 | 
			
		||||
typedef char NPUTF8;
 | 
			
		||||
typedef struct _NPString {
 | 
			
		||||
    const NPUTF8 *UTF8Characters;
 | 
			
		||||
    uint32_t UTF8Length;
 | 
			
		||||
} NPString;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    NPVariantType_Void,
 | 
			
		||||
    NPVariantType_Null,
 | 
			
		||||
    NPVariantType_Bool,
 | 
			
		||||
    NPVariantType_Int32,
 | 
			
		||||
    NPVariantType_Double,
 | 
			
		||||
    NPVariantType_String,
 | 
			
		||||
    NPVariantType_Object
 | 
			
		||||
} NPVariantType;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPVariant {
 | 
			
		||||
    NPVariantType type;
 | 
			
		||||
    union {
 | 
			
		||||
        bool boolValue;
 | 
			
		||||
        int32_t intValue;
 | 
			
		||||
        double doubleValue;
 | 
			
		||||
        NPString stringValue;
 | 
			
		||||
        NPObject *objectValue;
 | 
			
		||||
    } value;
 | 
			
		||||
} NPVariant;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    NPN_ReleaseVariantValue is called on all 'out' parameters
 | 
			
		||||
    references.  Specifically it is to be called on variants that own
 | 
			
		||||
    their value, as is the case with all non-const NPVariant*
 | 
			
		||||
    arguments after a successful call to any methods (except this one)
 | 
			
		||||
    in this API.
 | 
			
		||||
 | 
			
		||||
    After calling NPN_ReleaseVariantValue, the type of the variant
 | 
			
		||||
    will be NPVariantType_Void.
 | 
			
		||||
*/
 | 
			
		||||
void NPN_ReleaseVariantValue(NPVariant *variant);
 | 
			
		||||
 | 
			
		||||
#define NPVARIANT_IS_VOID(_v)    ((_v).type == NPVariantType_Void)
 | 
			
		||||
#define NPVARIANT_IS_NULL(_v)    ((_v).type == NPVariantType_Null)
 | 
			
		||||
#define NPVARIANT_IS_BOOLEAN(_v) ((_v).type == NPVariantType_Bool)
 | 
			
		||||
#define NPVARIANT_IS_INT32(_v)   ((_v).type == NPVariantType_Int32)
 | 
			
		||||
#define NPVARIANT_IS_DOUBLE(_v)  ((_v).type == NPVariantType_Double)
 | 
			
		||||
#define NPVARIANT_IS_STRING(_v)  ((_v).type == NPVariantType_String)
 | 
			
		||||
#define NPVARIANT_IS_OBJECT(_v)  ((_v).type == NPVariantType_Object)
 | 
			
		||||
 | 
			
		||||
#define NPVARIANT_TO_BOOLEAN(_v) ((_v).value.boolValue)
 | 
			
		||||
#define NPVARIANT_TO_INT32(_v)   ((_v).value.intValue)
 | 
			
		||||
#define NPVARIANT_TO_DOUBLE(_v)  ((_v).value.doubleValue)
 | 
			
		||||
#define NPVARIANT_TO_STRING(_v)  ((_v).value.stringValue)
 | 
			
		||||
#define NPVARIANT_TO_OBJECT(_v)  ((_v).value.objectValue)
 | 
			
		||||
 | 
			
		||||
#define VOID_TO_NPVARIANT(_v)                                                 \
 | 
			
		||||
NP_BEGIN_MACRO                                                                \
 | 
			
		||||
    (_v).type = NPVariantType_Void;                                           \
 | 
			
		||||
    (_v).value.objectValue = NULL;                                            \
 | 
			
		||||
NP_END_MACRO
 | 
			
		||||
 | 
			
		||||
#define NULL_TO_NPVARIANT(_v)                                                 \
 | 
			
		||||
NP_BEGIN_MACRO                                                                \
 | 
			
		||||
    (_v).type = NPVariantType_Null;                                           \
 | 
			
		||||
    (_v).value.objectValue = NULL;                                            \
 | 
			
		||||
NP_END_MACRO
 | 
			
		||||
 | 
			
		||||
#define BOOLEAN_TO_NPVARIANT(_val, _v)                                        \
 | 
			
		||||
NP_BEGIN_MACRO                                                                \
 | 
			
		||||
    (_v).type = NPVariantType_Bool;                                           \
 | 
			
		||||
    (_v).value.boolValue = !!(_val);                                          \
 | 
			
		||||
NP_END_MACRO
 | 
			
		||||
 | 
			
		||||
#define INT32_TO_NPVARIANT(_val, _v)                                          \
 | 
			
		||||
NP_BEGIN_MACRO                                                                \
 | 
			
		||||
    (_v).type = NPVariantType_Int32;                                          \
 | 
			
		||||
    (_v).value.intValue = _val;                                               \
 | 
			
		||||
NP_END_MACRO
 | 
			
		||||
 | 
			
		||||
#define DOUBLE_TO_NPVARIANT(_val, _v)                                         \
 | 
			
		||||
NP_BEGIN_MACRO                                                                \
 | 
			
		||||
    (_v).type = NPVariantType_Double;                                         \
 | 
			
		||||
    (_v).value.doubleValue = _val;                                            \
 | 
			
		||||
NP_END_MACRO
 | 
			
		||||
 | 
			
		||||
#define STRINGZ_TO_NPVARIANT(_val, _v)                                        \
 | 
			
		||||
NP_BEGIN_MACRO                                                                \
 | 
			
		||||
    (_v).type = NPVariantType_String;                                         \
 | 
			
		||||
    NPString str = { _val, (uint32_t)(strlen(_val)) };                        \
 | 
			
		||||
    (_v).value.stringValue = str;                                             \
 | 
			
		||||
NP_END_MACRO
 | 
			
		||||
 | 
			
		||||
#define STRINGN_TO_NPVARIANT(_val, _len, _v)                                  \
 | 
			
		||||
NP_BEGIN_MACRO                                                                \
 | 
			
		||||
    (_v).type = NPVariantType_String;                                         \
 | 
			
		||||
    NPString str = { _val, (uint32_t)(_len) };                                \
 | 
			
		||||
    (_v).value.stringValue = str;                                             \
 | 
			
		||||
NP_END_MACRO
 | 
			
		||||
 | 
			
		||||
#define OBJECT_TO_NPVARIANT(_val, _v)                                         \
 | 
			
		||||
NP_BEGIN_MACRO                                                                \
 | 
			
		||||
    (_v).type = NPVariantType_Object;                                         \
 | 
			
		||||
    (_v).value.objectValue = _val;                                            \
 | 
			
		||||
NP_END_MACRO
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
  Type mappings (JavaScript types have been used for illustration
 | 
			
		||||
    purposes):
 | 
			
		||||
 | 
			
		||||
  JavaScript       to             C (NPVariant with type:)
 | 
			
		||||
  undefined                       NPVariantType_Void
 | 
			
		||||
  null                            NPVariantType_Null
 | 
			
		||||
  Boolean                         NPVariantType_Bool
 | 
			
		||||
  Number                          NPVariantType_Double or NPVariantType_Int32
 | 
			
		||||
  String                          NPVariantType_String
 | 
			
		||||
  Object                          NPVariantType_Object
 | 
			
		||||
 | 
			
		||||
  C (NPVariant with type:)   to   JavaScript
 | 
			
		||||
  NPVariantType_Void              undefined
 | 
			
		||||
  NPVariantType_Null              null
 | 
			
		||||
  NPVariantType_Bool              Boolean
 | 
			
		||||
  NPVariantType_Int32             Number
 | 
			
		||||
  NPVariantType_Double            Number
 | 
			
		||||
  NPVariantType_String            String
 | 
			
		||||
  NPVariantType_Object            Object
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
typedef void *NPIdentifier;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    NPObjects have methods and properties.  Methods and properties are
 | 
			
		||||
    identified with NPIdentifiers.  These identifiers may be reflected
 | 
			
		||||
    in script.  NPIdentifiers can be either strings or integers, IOW,
 | 
			
		||||
    methods and properties can be identified by either strings or
 | 
			
		||||
    integers (i.e. foo["bar"] vs foo[1]). NPIdentifiers can be
 | 
			
		||||
    compared using ==.  In case of any errors, the requested
 | 
			
		||||
    NPIdentifier(s) will be NULL. NPIdentifier lifetime is controlled
 | 
			
		||||
    by the browser. Plugins do not need to worry about memory management
 | 
			
		||||
    with regards to NPIdentifiers.
 | 
			
		||||
*/
 | 
			
		||||
NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name);
 | 
			
		||||
void NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount,
 | 
			
		||||
                              NPIdentifier *identifiers);
 | 
			
		||||
NPIdentifier NPN_GetIntIdentifier(int32_t intid);
 | 
			
		||||
bool NPN_IdentifierIsString(NPIdentifier identifier);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    The NPUTF8 returned from NPN_UTF8FromIdentifier SHOULD be freed.
 | 
			
		||||
*/
 | 
			
		||||
NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    Get the integer represented by identifier. If identifier is not an
 | 
			
		||||
    integer identifier, the behaviour is undefined.
 | 
			
		||||
*/
 | 
			
		||||
int32_t NPN_IntFromIdentifier(NPIdentifier identifier);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    NPObject behavior is implemented using the following set of
 | 
			
		||||
    callback functions.
 | 
			
		||||
 | 
			
		||||
    The NPVariant *result argument of these functions (where
 | 
			
		||||
    applicable) should be released using NPN_ReleaseVariantValue().
 | 
			
		||||
*/
 | 
			
		||||
typedef NPObject *(*NPAllocateFunctionPtr)(NPP npp, NPClass *aClass);
 | 
			
		||||
typedef void (*NPDeallocateFunctionPtr)(NPObject *npobj);
 | 
			
		||||
typedef void (*NPInvalidateFunctionPtr)(NPObject *npobj);
 | 
			
		||||
typedef bool (*NPHasMethodFunctionPtr)(NPObject *npobj, NPIdentifier name);
 | 
			
		||||
typedef bool (*NPInvokeFunctionPtr)(NPObject *npobj, NPIdentifier name,
 | 
			
		||||
                                    const NPVariant *args, uint32_t argCount,
 | 
			
		||||
                                    NPVariant *result);
 | 
			
		||||
typedef bool (*NPInvokeDefaultFunctionPtr)(NPObject *npobj,
 | 
			
		||||
                                           const NPVariant *args,
 | 
			
		||||
                                           uint32_t argCount,
 | 
			
		||||
                                           NPVariant *result);
 | 
			
		||||
typedef bool (*NPHasPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name);
 | 
			
		||||
typedef bool (*NPGetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name,
 | 
			
		||||
                                         NPVariant *result);
 | 
			
		||||
typedef bool (*NPSetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name,
 | 
			
		||||
                                         const NPVariant *value);
 | 
			
		||||
typedef bool (*NPRemovePropertyFunctionPtr)(NPObject *npobj,
 | 
			
		||||
                                            NPIdentifier name);
 | 
			
		||||
typedef bool (*NPEnumerationFunctionPtr)(NPObject *npobj, NPIdentifier **value,
 | 
			
		||||
                                         uint32_t *count);
 | 
			
		||||
typedef bool (*NPConstructFunctionPtr)(NPObject *npobj,
 | 
			
		||||
                                       const NPVariant *args,
 | 
			
		||||
                                       uint32_t argCount,
 | 
			
		||||
                                       NPVariant *result);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    NPObjects returned by create, retain, invoke, and getProperty pass
 | 
			
		||||
    a reference count to the caller.  That is, the callee adds a
 | 
			
		||||
    reference count which passes to the caller.  It is the caller's
 | 
			
		||||
    responsibility to release the returned object.
 | 
			
		||||
 | 
			
		||||
    NPInvokeFunctionPtr function may return 0 to indicate a void
 | 
			
		||||
    result.
 | 
			
		||||
 | 
			
		||||
    NPInvalidateFunctionPtr is called by the scripting environment
 | 
			
		||||
    when the native code is shutdown.  Any attempt to message a
 | 
			
		||||
    NPObject instance after the invalidate callback has been
 | 
			
		||||
    called will result in undefined behavior, even if the native code
 | 
			
		||||
    is still retaining those NPObject instances.  (The runtime
 | 
			
		||||
    will typically return immediately, with 0 or NULL, from an attempt
 | 
			
		||||
    to dispatch to a NPObject, but this behavior should not be
 | 
			
		||||
    depended upon.)
 | 
			
		||||
 | 
			
		||||
    The NPEnumerationFunctionPtr function may pass an array of
 | 
			
		||||
    NPIdentifiers back to the caller. The callee allocs the memory of
 | 
			
		||||
    the array using NPN_MemAlloc(), and it's the caller's responsibility
 | 
			
		||||
    to release it using NPN_MemFree().
 | 
			
		||||
*/
 | 
			
		||||
struct NPClass
 | 
			
		||||
{
 | 
			
		||||
    uint32_t structVersion;
 | 
			
		||||
    NPAllocateFunctionPtr allocate;
 | 
			
		||||
    NPDeallocateFunctionPtr deallocate;
 | 
			
		||||
    NPInvalidateFunctionPtr invalidate;
 | 
			
		||||
    NPHasMethodFunctionPtr hasMethod;
 | 
			
		||||
    NPInvokeFunctionPtr invoke;
 | 
			
		||||
    NPInvokeDefaultFunctionPtr invokeDefault;
 | 
			
		||||
    NPHasPropertyFunctionPtr hasProperty;
 | 
			
		||||
    NPGetPropertyFunctionPtr getProperty;
 | 
			
		||||
    NPSetPropertyFunctionPtr setProperty;
 | 
			
		||||
    NPRemovePropertyFunctionPtr removeProperty;
 | 
			
		||||
    NPEnumerationFunctionPtr enumerate;
 | 
			
		||||
    NPConstructFunctionPtr construct;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define NP_CLASS_STRUCT_VERSION      3
 | 
			
		||||
 | 
			
		||||
#define NP_CLASS_STRUCT_VERSION_ENUM 2
 | 
			
		||||
#define NP_CLASS_STRUCT_VERSION_CTOR 3
 | 
			
		||||
 | 
			
		||||
#define NP_CLASS_STRUCT_VERSION_HAS_ENUM(npclass)   \
 | 
			
		||||
        ((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_ENUM)
 | 
			
		||||
 | 
			
		||||
#define NP_CLASS_STRUCT_VERSION_HAS_CTOR(npclass)   \
 | 
			
		||||
        ((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR)
 | 
			
		||||
 | 
			
		||||
struct NPObject {
 | 
			
		||||
    NPClass *_class;
 | 
			
		||||
    uint32_t referenceCount;
 | 
			
		||||
    /*
 | 
			
		||||
     * Additional space may be allocated here by types of NPObjects
 | 
			
		||||
     */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    If the class has an allocate function, NPN_CreateObject invokes
 | 
			
		||||
    that function, otherwise a NPObject is allocated and
 | 
			
		||||
    returned. This method will initialize the referenceCount member of
 | 
			
		||||
    the NPObject to 1.
 | 
			
		||||
*/
 | 
			
		||||
NPObject *NPN_CreateObject(NPP npp, NPClass *aClass);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    Increment the NPObject's reference count.
 | 
			
		||||
*/
 | 
			
		||||
NPObject *NPN_RetainObject(NPObject *npobj);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    Decremented the NPObject's reference count.  If the reference
 | 
			
		||||
    count goes to zero, the class's destroy function is invoke if
 | 
			
		||||
    specified, otherwise the object is freed directly.
 | 
			
		||||
*/
 | 
			
		||||
void NPN_ReleaseObject(NPObject *npobj);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    Functions to access script objects represented by NPObject.
 | 
			
		||||
 | 
			
		||||
    Calls to script objects are synchronous.  If a function returns a
 | 
			
		||||
    value, it will be supplied via the result NPVariant
 | 
			
		||||
    argument. Successful calls will return true, false will be
 | 
			
		||||
    returned in case of an error.
 | 
			
		||||
 | 
			
		||||
    Calls made from plugin code to script must be made from the thread
 | 
			
		||||
    on which the plugin was initialized.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName,
 | 
			
		||||
                const NPVariant *args, uint32_t argCount, NPVariant *result);
 | 
			
		||||
bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args,
 | 
			
		||||
                       uint32_t argCount, NPVariant *result);
 | 
			
		||||
bool NPN_Evaluate(NPP npp, NPObject *npobj, NPString *script,
 | 
			
		||||
                  NPVariant *result);
 | 
			
		||||
bool NPN_GetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName,
 | 
			
		||||
                     NPVariant *result);
 | 
			
		||||
bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName,
 | 
			
		||||
                     const NPVariant *value);
 | 
			
		||||
bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);
 | 
			
		||||
bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);
 | 
			
		||||
bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName);
 | 
			
		||||
bool NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier,
 | 
			
		||||
                   uint32_t *count);
 | 
			
		||||
bool NPN_Construct(NPP npp, NPObject *npobj, const NPVariant *args,
 | 
			
		||||
                   uint32_t argCount, NPVariant *result);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    NPN_SetException may be called to trigger a script exception upon
 | 
			
		||||
    return from entry points into NPObjects.  Typical usage:
 | 
			
		||||
 | 
			
		||||
    NPN_SetException (npobj, message);
 | 
			
		||||
*/
 | 
			
		||||
void NPN_SetException(NPObject *npobj, const NPUTF8 *message);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										121
									
								
								browser-plugin/npapi/nptypes.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,121 @@
 | 
			
		||||
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
			
		||||
/* ***** BEGIN LICENSE BLOCK *****
 | 
			
		||||
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 | 
			
		||||
 *
 | 
			
		||||
 * The contents of this file are subject to the Mozilla Public License Version
 | 
			
		||||
 * 1.1 (the "License"); you may not use this file except in compliance with
 | 
			
		||||
 * the License. You may obtain a copy of the License at
 | 
			
		||||
 * http://www.mozilla.org/MPL/
 | 
			
		||||
 *
 | 
			
		||||
 * Software distributed under the License is distributed on an "AS IS" basis,
 | 
			
		||||
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 | 
			
		||||
 * for the specific language governing rights and limitations under the
 | 
			
		||||
 * License.
 | 
			
		||||
 *
 | 
			
		||||
 * The Original Code is mozilla.org code.
 | 
			
		||||
 *
 | 
			
		||||
 * The Initial Developer of the Original Code is
 | 
			
		||||
 * mozilla.org.
 | 
			
		||||
 * Portions created by the Initial Developer are Copyright (C) 2004
 | 
			
		||||
 * the Initial Developer. All Rights Reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Contributor(s):
 | 
			
		||||
 *   Johnny Stenback <jst@mozilla.org> (Original author)
 | 
			
		||||
 *
 | 
			
		||||
 * Alternatively, the contents of this file may be used under the terms of
 | 
			
		||||
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 | 
			
		||||
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 | 
			
		||||
 * in which case the provisions of the GPL or the LGPL are applicable instead
 | 
			
		||||
 * of those above. If you wish to allow use of your version of this file only
 | 
			
		||||
 * under the terms of either the GPL or the LGPL, and not to allow others to
 | 
			
		||||
 * use your version of this file under the terms of the MPL, indicate your
 | 
			
		||||
 * decision by deleting the provisions above and replace them with the notice
 | 
			
		||||
 * and other provisions required by the GPL or the LGPL. If you do not delete
 | 
			
		||||
 * the provisions above, a recipient may use your version of this file under
 | 
			
		||||
 * the terms of any one of the MPL, the GPL or the LGPL.
 | 
			
		||||
 *
 | 
			
		||||
 * ***** END LICENSE BLOCK ***** */
 | 
			
		||||
 | 
			
		||||
#ifndef nptypes_h_
 | 
			
		||||
#define nptypes_h_
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Header file for ensuring that C99 types ([u]int32_t, [u]int64_t and bool) and
 | 
			
		||||
 * true/false macros are available.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if defined(WIN32) || defined(OS2)
 | 
			
		||||
  /*
 | 
			
		||||
   * Win32 and OS/2 don't know C99, so define [u]int_16/32/64 here. The bool
 | 
			
		||||
   * is predefined tho, both in C and C++.
 | 
			
		||||
   */
 | 
			
		||||
  typedef short int16_t;
 | 
			
		||||
  typedef unsigned short uint16_t;
 | 
			
		||||
  typedef int int32_t;
 | 
			
		||||
  typedef unsigned int uint32_t;
 | 
			
		||||
  typedef long long int64_t;
 | 
			
		||||
  typedef unsigned long long uint64_t;
 | 
			
		||||
#elif defined(_AIX) || defined(__sun) || defined(__osf__) || defined(IRIX) || defined(HPUX)
 | 
			
		||||
  /*
 | 
			
		||||
   * AIX and SunOS ship a inttypes.h header that defines [u]int32_t,
 | 
			
		||||
   * but not bool for C.
 | 
			
		||||
   */
 | 
			
		||||
  #include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
  #ifndef __cplusplus
 | 
			
		||||
    typedef int bool;
 | 
			
		||||
    #define true   1
 | 
			
		||||
    #define false  0
 | 
			
		||||
  #endif
 | 
			
		||||
#elif defined(bsdi) || defined(FREEBSD) || defined(OPENBSD)
 | 
			
		||||
  /*
 | 
			
		||||
   * BSD/OS, FreeBSD, and OpenBSD ship sys/types.h that define int32_t and
 | 
			
		||||
   * u_int32_t.
 | 
			
		||||
   */
 | 
			
		||||
  #include <sys/types.h>
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * BSD/OS ships no header that defines uint32_t, nor bool (for C)
 | 
			
		||||
   */
 | 
			
		||||
  #if defined(bsdi)
 | 
			
		||||
  typedef u_int32_t uint32_t;
 | 
			
		||||
  typedef u_int64_t uint64_t;
 | 
			
		||||
 | 
			
		||||
  #if !defined(__cplusplus)
 | 
			
		||||
    typedef int bool;
 | 
			
		||||
    #define true   1
 | 
			
		||||
    #define false  0
 | 
			
		||||
  #endif
 | 
			
		||||
  #else
 | 
			
		||||
  /*
 | 
			
		||||
   * FreeBSD and OpenBSD define uint32_t and bool.
 | 
			
		||||
   */
 | 
			
		||||
    #include <inttypes.h>
 | 
			
		||||
    #include <stdbool.h>
 | 
			
		||||
  #endif
 | 
			
		||||
#elif defined(BEOS)
 | 
			
		||||
  #include <inttypes.h>
 | 
			
		||||
#else
 | 
			
		||||
  /*
 | 
			
		||||
   * For those that ship a standard C99 stdint.h header file, include
 | 
			
		||||
   * it. Can't do the same for stdbool.h tho, since some systems ship
 | 
			
		||||
   * with a stdbool.h file that doesn't compile!
 | 
			
		||||
   */
 | 
			
		||||
  #include <stdint.h>
 | 
			
		||||
 | 
			
		||||
  #ifndef __cplusplus
 | 
			
		||||
    #if !defined(__GNUC__) || (__GNUC__ > 2 || __GNUC_MINOR__ > 95)
 | 
			
		||||
      #include <stdbool.h>
 | 
			
		||||
    #else
 | 
			
		||||
      /*
 | 
			
		||||
       * GCC 2.91 can't deal with a typedef for bool, but a #define
 | 
			
		||||
       * works.
 | 
			
		||||
       */
 | 
			
		||||
      #define bool int
 | 
			
		||||
      #define true   1
 | 
			
		||||
      #define false  0
 | 
			
		||||
    #endif
 | 
			
		||||
  #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* nptypes_h_ */
 | 
			
		||||
							
								
								
									
										179
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						@@ -1,5 +1,5 @@
 | 
			
		||||
AC_PREREQ(2.63)
 | 
			
		||||
AC_INIT([gnome-shell],[2.91.90],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
 | 
			
		||||
AC_INIT([gnome-shell],[3.3.2],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
 | 
			
		||||
 | 
			
		||||
AC_CONFIG_HEADERS([config.h])
 | 
			
		||||
AC_CONFIG_SRCDIR([src/shell-global.c])
 | 
			
		||||
@@ -9,8 +9,8 @@ AC_CONFIG_AUX_DIR([config])
 | 
			
		||||
AC_SUBST([PACKAGE_NAME], ["$PACKAGE_NAME"])
 | 
			
		||||
AC_SUBST([PACKAGE_VERSION], ["$PACKAGE_VERSION"])
 | 
			
		||||
 | 
			
		||||
AM_INIT_AUTOMAKE([1.10 dist-bzip2 no-dist-gzip foreign])
 | 
			
		||||
AM_MAINTAINER_MODE
 | 
			
		||||
AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar foreign])
 | 
			
		||||
AM_MAINTAINER_MODE([enable])
 | 
			
		||||
 | 
			
		||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
 | 
			
		||||
 | 
			
		||||
@@ -23,19 +23,19 @@ AM_PROG_CC_C_O
 | 
			
		||||
LT_PREREQ([2.2.6])
 | 
			
		||||
LT_INIT([disable-static])
 | 
			
		||||
 | 
			
		||||
# i18n
 | 
			
		||||
IT_PROG_INTLTOOL([0.40])
 | 
			
		||||
 | 
			
		||||
AM_GNU_GETTEXT([external])
 | 
			
		||||
AM_GNU_GETTEXT_VERSION([0.17])
 | 
			
		||||
 | 
			
		||||
GETTEXT_PACKAGE=gnome-shell
 | 
			
		||||
AC_SUBST(GETTEXT_PACKAGE)
 | 
			
		||||
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",
 | 
			
		||||
                   [The prefix for our gettext translation domains.])
 | 
			
		||||
IT_PROG_INTLTOOL(0.26)
 | 
			
		||||
AM_GLIB_GNU_GETTEXT
 | 
			
		||||
 | 
			
		||||
PKG_PROG_PKG_CONFIG([0.22])
 | 
			
		||||
 | 
			
		||||
# GConf stuff
 | 
			
		||||
AC_PATH_PROG(GCONFTOOL, gconftool-2, no)
 | 
			
		||||
AM_GCONF_SOURCE_2
 | 
			
		||||
 | 
			
		||||
GLIB_GSETTINGS
 | 
			
		||||
 | 
			
		||||
# Get a value to substitute into gnome-shell.in
 | 
			
		||||
@@ -52,68 +52,81 @@ AC_MSG_CHECKING([for GStreamer (needed for recording functionality)])
 | 
			
		||||
if $PKG_CONFIG --exists gstreamer-0.10 '>=' $GSTREAMER_MIN_VERSION ; then
 | 
			
		||||
   AC_MSG_RESULT(yes)
 | 
			
		||||
   build_recorder=true
 | 
			
		||||
   recorder_modules="gstreamer-0.10 gstreamer-base-0.10 xfixes"
 | 
			
		||||
   PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0)
 | 
			
		||||
   recorder_modules="gstreamer-0.10 gstreamer-base-0.10 x11"
 | 
			
		||||
   PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0 xfixes)
 | 
			
		||||
else
 | 
			
		||||
   AC_MSG_RESULT(no)
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
 | 
			
		||||
 | 
			
		||||
CLUTTER_MIN_VERSION=1.5.15
 | 
			
		||||
CLUTTER_MIN_VERSION=1.7.5
 | 
			
		||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
 | 
			
		||||
GJS_MIN_VERSION=0.7.11
 | 
			
		||||
MUTTER_MIN_VERSION=2.91.90
 | 
			
		||||
GJS_MIN_VERSION=1.29.18
 | 
			
		||||
MUTTER_MIN_VERSION=3.3.2
 | 
			
		||||
FOLKS_MIN_VERSION=0.5.2
 | 
			
		||||
GTK_MIN_VERSION=3.0.0
 | 
			
		||||
GIO_MIN_VERSION=2.25.9
 | 
			
		||||
LIBECAL_REQUIRED=1.6.0
 | 
			
		||||
LIBEDATASERVER_REQUIRED=1.2.0
 | 
			
		||||
LIBEDATASERVERUI2_REQUIRED=1.2.0
 | 
			
		||||
LIBEDATASERVERUI3_REQUIRED=2.91.6
 | 
			
		||||
TELEPATHY_GLIB_MIN_VERSION=0.13.12
 | 
			
		||||
GIO_MIN_VERSION=2.31.0
 | 
			
		||||
LIBECAL_MIN_VERSION=2.32.0
 | 
			
		||||
LIBEDATASERVER_MIN_VERSION=1.2.0
 | 
			
		||||
LIBEDATASERVERUI_MIN_VERSION=2.91.6
 | 
			
		||||
TELEPATHY_GLIB_MIN_VERSION=0.15.5
 | 
			
		||||
TELEPATHY_LOGGER_MIN_VERSION=0.2.4
 | 
			
		||||
POLKIT_MIN_VERSION=0.100
 | 
			
		||||
STARTUP_NOTIFICATION_MIN_VERSION=0.11
 | 
			
		||||
 | 
			
		||||
# Collect more than 20 libraries for a prize!
 | 
			
		||||
PKG_CHECK_MODULES(MUTTER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION
 | 
			
		||||
                                 gio-unix-2.0 dbus-glib-1 libxml-2.0
 | 
			
		||||
                                 gtk+-3.0 >= $GTK_MIN_VERSION
 | 
			
		||||
                                 mutter-plugins >= $MUTTER_MIN_VERSION
 | 
			
		||||
                                 gjs-internals-1.0 >= $GJS_MIN_VERSION
 | 
			
		||||
				 libgnome-menu $recorder_modules gconf-2.0
 | 
			
		||||
                                 gdk-x11-3.0
 | 
			
		||||
				 clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
 | 
			
		||||
				 clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
 | 
			
		||||
                                 libstartup-notification-1.0
 | 
			
		||||
                                 gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION
 | 
			
		||||
				 libcanberra
 | 
			
		||||
                                 telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
 | 
			
		||||
                                 polkit-agent-1 >= $POLKIT_MIN_VERSION)
 | 
			
		||||
PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
 | 
			
		||||
			       libxml-2.0
 | 
			
		||||
                               gtk+-3.0 >= $GTK_MIN_VERSION
 | 
			
		||||
                               folks >= $FOLKS_MIN_VERSION
 | 
			
		||||
                               libmutter >= $MUTTER_MIN_VERSION
 | 
			
		||||
                               gjs-internals-1.0 >= $GJS_MIN_VERSION
 | 
			
		||||
			       libgnome-menu-3.0 $recorder_modules
 | 
			
		||||
                               gdk-x11-3.0 libsoup-2.4
 | 
			
		||||
			       clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
 | 
			
		||||
			       clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
 | 
			
		||||
                               libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION
 | 
			
		||||
                               gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION
 | 
			
		||||
			       libcanberra
 | 
			
		||||
                               telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
 | 
			
		||||
                               telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION
 | 
			
		||||
                               polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes
 | 
			
		||||
                               libnm-glib libnm-util gnome-keyring-1)
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(SHELL_HOTPLUG_SNIFFER, gio-2.0 gdk-pixbuf-2.0)
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(BROWSER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION json-glib-1.0 >= 0.13.2)
 | 
			
		||||
 | 
			
		||||
GJS_VERSION=`$PKG_CONFIG --modversion gjs-internals-1.0`
 | 
			
		||||
AC_DEFINE_UNQUOTED([GJS_VERSION], ["$GJS_VERSION"], [The version of GJS we're linking to])
 | 
			
		||||
AC_SUBST([GJS_VERSION], ["$GJS_VERSION"])
 | 
			
		||||
 | 
			
		||||
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
 | 
			
		||||
JHBUILD_TYPELIBDIR="$INTROSPECTION_TYPELIBDIR"
 | 
			
		||||
AC_SUBST(JHBUILD_TYPELIBDIR)
 | 
			
		||||
 | 
			
		||||
saved_CFLAGS=$CFLAGS
 | 
			
		||||
saved_LIBS=$LIBS
 | 
			
		||||
CFLAGS=$MUTTER_PLUGIN_CFLAGS
 | 
			
		||||
LIBS=$MUTTER_PLUGIN_LIBS
 | 
			
		||||
# sn_startup_sequence_get_application_id, we can replace with a version check later
 | 
			
		||||
AC_CHECK_FUNCS(JS_NewGlobalObject sn_startup_sequence_get_application_id)
 | 
			
		||||
CFLAGS=$GNOME_SHELL_CFLAGS
 | 
			
		||||
LIBS=$GNOME_SHELL_LIBS
 | 
			
		||||
AC_CHECK_FUNCS(JS_NewGlobalObject XFixesCreatePointerBarrier)
 | 
			
		||||
CFLAGS=$saved_CFLAGS
 | 
			
		||||
LIBS=$saved_LIBS
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 gnome-desktop-3.0 >= 2.90.0)
 | 
			
		||||
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-3.0)
 | 
			
		||||
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.2 gnome-desktop-3.0 >= 2.90.0 x11)
 | 
			
		||||
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
 | 
			
		||||
PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
 | 
			
		||||
PKG_CHECK_MODULES(JS_TEST, clutter-x11-1.0 gjs-1.0 gobject-introspection-1.0 gtk+-3.0)
 | 
			
		||||
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 0.1.7)
 | 
			
		||||
 | 
			
		||||
AC_MSG_CHECKING([for bluetooth support])
 | 
			
		||||
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 2.90.0],
 | 
			
		||||
        [BLUETOOTH_DIR=`$PKG_CONFIG --variable=libdir gnome-bluetooth-1.0`/gnome-bluetooth
 | 
			
		||||
	 BLUETOOTH_LIBS="-L'$BLUETOOTH_DIR' -lgnome-bluetooth-applet"
 | 
			
		||||
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0],
 | 
			
		||||
        [BLUETOOTH_DIR=`$PKG_CONFIG --variable=applet_libdir gnome-bluetooth-1.0`
 | 
			
		||||
	 BLUETOOTH_LIBS=`$PKG_CONFIG --variable=applet_libs gnome-bluetooth-1.0`
 | 
			
		||||
	 AC_SUBST([BLUETOOTH_LIBS],["$BLUETOOTH_LIBS"])
 | 
			
		||||
	 AC_SUBST([BLUETOOTH_DIR],["$BLUETOOTH_DIR"])
 | 
			
		||||
	 AC_DEFINE_UNQUOTED([BLUETOOTH_DIR],["$BLUETOOTH_DIR"],[Path to installed GnomeBluetooth typelib and library])
 | 
			
		||||
	 AC_DEFINE([HAVE_BLUETOOTH],[1],[Define if you have libgnome-bluetooth-applet])
 | 
			
		||||
	 AC_SUBST([HAVE_BLUETOOTH],[1])
 | 
			
		||||
@@ -122,23 +135,14 @@ PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 2.90.0],
 | 
			
		||||
	 AC_SUBST([HAVE_BLUETOOTH],[0])
 | 
			
		||||
	 AC_MSG_RESULT([no])])
 | 
			
		||||
 | 
			
		||||
# Default to libedataserverui-3.0, but allow falling back to 1.2
 | 
			
		||||
PKG_CHECK_EXISTS(libedataserverui-3.0,
 | 
			
		||||
                 [EDS_API=3.0
 | 
			
		||||
                  LIBEDATASERVERUI_REQUIRED=$LIBEDATASERVERUI3_REQUIRED],
 | 
			
		||||
                 [EDS_API=1.2
 | 
			
		||||
                  LIBEDATASERVERUI_REQUIRED=$LIBEDATASERVERUI2_REQUIRED])
 | 
			
		||||
PKG_CHECK_MODULES(LIBECAL, libecal-1.2 >= $LIBECAL_REQUIRED libedataserver-1.2 >= $LIBEDATASERVER_REQUIRED libedataserverui-$EDS_API >= $LIBEDATASERVERUI_REQUIRED)
 | 
			
		||||
AC_SUBST(LIBECAL_CFLAGS)
 | 
			
		||||
AC_SUBST(LIBECAL_LIBS)
 | 
			
		||||
PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION libedataserverui-3.0 >= $LIBEDATASERVERUI_MIN_VERSION gio-2.0)
 | 
			
		||||
AC_SUBST(CALENDAR_SERVER_CFLAGS)
 | 
			
		||||
AC_SUBST(CALENDAR_SERVER_LIBS)
 | 
			
		||||
 | 
			
		||||
MUTTER_BIN_DIR=`$PKG_CONFIG --variable=exec_prefix mutter-plugins`/bin
 | 
			
		||||
# FIXME: metacity-plugins.pc should point directly to its .gir file
 | 
			
		||||
MUTTER_LIB_DIR=`$PKG_CONFIG --variable=libdir mutter-plugins`
 | 
			
		||||
MUTTER_PLUGIN_DIR=`$PKG_CONFIG --variable=plugindir mutter-plugins`
 | 
			
		||||
AC_SUBST(MUTTER_BIN_DIR)
 | 
			
		||||
AC_SUBST(MUTTER_LIB_DIR)
 | 
			
		||||
AC_SUBST(MUTTER_PLUGIN_DIR)
 | 
			
		||||
MUTTER_GIR_DIR=`$PKG_CONFIG --variable=girdir libmutter`
 | 
			
		||||
MUTTER_TYPELIB_DIR=`$PKG_CONFIG --variable=typelibdir libmutter`
 | 
			
		||||
AC_SUBST(MUTTER_GIR_DIR)
 | 
			
		||||
AC_SUBST(MUTTER_TYPELIB_DIR)
 | 
			
		||||
 | 
			
		||||
GJS_CONSOLE=`$PKG_CONFIG --variable=gjs_console gjs-1.0`
 | 
			
		||||
AC_SUBST(GJS_CONSOLE)
 | 
			
		||||
@@ -147,6 +151,17 @@ AC_CHECK_FUNCS(fdwalk)
 | 
			
		||||
AC_CHECK_FUNCS(mallinfo)
 | 
			
		||||
AC_CHECK_HEADERS([sys/resource.h])
 | 
			
		||||
 | 
			
		||||
# _NL_TIME_FIRST_WEEKDAY is an enum and not a define
 | 
			
		||||
AC_MSG_CHECKING([for _NL_TIME_FIRST_WEEKDAY])
 | 
			
		||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <langinfo.h>]],
 | 
			
		||||
                                   [[nl_langinfo(_NL_TIME_FIRST_WEEKDAY);]])],
 | 
			
		||||
               [langinfo_ok=yes], [langinfo_ok=no])
 | 
			
		||||
AC_MSG_RESULT($langinfo_ok)
 | 
			
		||||
if test "$langinfo_ok" = "yes"; then
 | 
			
		||||
  AC_DEFINE([HAVE__NL_TIME_FIRST_WEEKDAY], [1],
 | 
			
		||||
            [Define if _NL_TIME_FIRST_WEEKDAY is available])
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Sets GLIB_GENMARSHAL and GLIB_MKENUMS
 | 
			
		||||
AM_PATH_GLIB_2_0()
 | 
			
		||||
G_IR_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0`
 | 
			
		||||
@@ -160,11 +175,13 @@ AC_SUBST(GIRDIR)
 | 
			
		||||
TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)"
 | 
			
		||||
AC_SUBST(TYPELIBDIR)
 | 
			
		||||
 | 
			
		||||
GTK_DOC_CHECK([1.15], [--flavour no-tmpl])
 | 
			
		||||
 | 
			
		||||
# Stay command-line compatible with the gnome-common configure option. Here
 | 
			
		||||
# minimum/yes/maximum are the same, however.
 | 
			
		||||
AC_ARG_ENABLE(compile_warnings,
 | 
			
		||||
  AS_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@],[Turn on compiler warnings]),,
 | 
			
		||||
  enable_compile_warnings=error)
 | 
			
		||||
  enable_compile_warnings=maximum)
 | 
			
		||||
 | 
			
		||||
changequote(,)dnl
 | 
			
		||||
if test "$enable_compile_warnings" != no ; then
 | 
			
		||||
@@ -187,15 +204,51 @@ if test "$enable_compile_warnings" != no ; then
 | 
			
		||||
fi
 | 
			
		||||
changequote([,])dnl
 | 
			
		||||
 | 
			
		||||
AC_PATH_PROG(mutter, [mutter])
 | 
			
		||||
AC_SUBST(mutter)
 | 
			
		||||
AC_ARG_ENABLE(jhbuild-wrapper-script,
 | 
			
		||||
  AS_HELP_STRING([--jhbuild-wrapper-script=yes],[Make "gnome-shell" script work for jhbuild]),,enable_jhbuild_wrapper_script=no)
 | 
			
		||||
AM_CONDITIONAL(USE_JHBUILD_WRAPPER_SCRIPT, test "x$enable_jhbuild_wrapper_script" = xyes)
 | 
			
		||||
 | 
			
		||||
AC_MSG_CHECKING([location of system Certificate Authority list])
 | 
			
		||||
AC_ARG_WITH(ca-certificates,
 | 
			
		||||
            [AC_HELP_STRING([--with-ca-certificates=@<:@path@:>@],
 | 
			
		||||
                            [path to system Certificate Authority list])])
 | 
			
		||||
 | 
			
		||||
if test "$with_ca_certificates" = "no"; then
 | 
			
		||||
    AC_MSG_RESULT([disabled])
 | 
			
		||||
else
 | 
			
		||||
    if test -z "$with_ca_certificates"; then
 | 
			
		||||
        for f in /etc/pki/tls/certs/ca-bundle.crt \
 | 
			
		||||
                 /etc/ssl/certs/ca-certificates.crt; do
 | 
			
		||||
             if test -f "$f"; then
 | 
			
		||||
                with_ca_certificates="$f"
 | 
			
		||||
             fi
 | 
			
		||||
        done
 | 
			
		||||
        if test -z "$with_ca_certificates"; then
 | 
			
		||||
            AC_MSG_ERROR([could not find. Use --with-ca-certificates=path to set, or --without-ca-certificates to disable])
 | 
			
		||||
        fi
 | 
			
		||||
   fi
 | 
			
		||||
 | 
			
		||||
   AC_MSG_RESULT($with_ca_certificates)
 | 
			
		||||
   AC_DEFINE_UNQUOTED(SHELL_SYSTEM_CA_FILE, ["$with_ca_certificates"], [The system TLS CA list])
 | 
			
		||||
fi
 | 
			
		||||
AC_SUBST(SHELL_SYSTEM_CA_FILE,["$with_ca_certificates"])
 | 
			
		||||
 | 
			
		||||
BROWSER_PLUGIN_DIR="${BROWSER_PLUGIN_DIR:-"\${libdir}/mozilla/plugins"}"
 | 
			
		||||
AC_ARG_VAR([BROWSER_PLUGIN_DIR],[Where to install the plugin to])
 | 
			
		||||
 | 
			
		||||
AC_CONFIG_FILES([
 | 
			
		||||
  Makefile
 | 
			
		||||
  data/Makefile
 | 
			
		||||
  docs/Makefile
 | 
			
		||||
  docs/reference/Makefile
 | 
			
		||||
  docs/reference/shell/Makefile
 | 
			
		||||
  docs/reference/shell/shell-docs.sgml
 | 
			
		||||
  docs/reference/st/Makefile
 | 
			
		||||
  docs/reference/st/st-docs.sgml
 | 
			
		||||
  js/Makefile
 | 
			
		||||
  js/misc/config.js
 | 
			
		||||
  src/Makefile
 | 
			
		||||
  browser-plugin/Makefile
 | 
			
		||||
  tests/Makefile
 | 
			
		||||
  po/Makefile.in
 | 
			
		||||
  man/Makefile
 | 
			
		||||
 
 | 
			
		||||
@@ -24,29 +24,22 @@ dist_theme_DATA =				\
 | 
			
		||||
	theme/calendar-today.svg		\
 | 
			
		||||
	theme/close-window.svg			\
 | 
			
		||||
	theme/close.svg				\
 | 
			
		||||
	theme/corner-ripple.png			\
 | 
			
		||||
	theme/corner-ripple-ltr.png		\
 | 
			
		||||
	theme/corner-ripple-rtl.png		\
 | 
			
		||||
	theme/dash-placeholder.svg		\
 | 
			
		||||
	theme/filter-selected.svg		\
 | 
			
		||||
	theme/filter-selected-ltr.svg		\
 | 
			
		||||
	theme/filter-selected-rtl.svg		\
 | 
			
		||||
	theme/gdm.css				\
 | 
			
		||||
	theme/gnome-shell.css			\
 | 
			
		||||
	theme/mosaic-view-active.svg		\
 | 
			
		||||
	theme/mosaic-view.svg			\
 | 
			
		||||
	theme/move-window-on-new.svg		\
 | 
			
		||||
	theme/panel-border.svg			\
 | 
			
		||||
	theme/panel-button-border.svg		\
 | 
			
		||||
	theme/panel-button-highlight-narrow.svg	\
 | 
			
		||||
	theme/panel-button-highlight-wide.svg	\
 | 
			
		||||
	theme/process-working.png		\
 | 
			
		||||
	theme/process-working.svg		\
 | 
			
		||||
	theme/running-indicator.svg		\
 | 
			
		||||
	theme/scroll-button-down-hover.png	\
 | 
			
		||||
	theme/scroll-button-down.png		\
 | 
			
		||||
	theme/scroll-button-up-hover.png	\
 | 
			
		||||
	theme/scroll-button-up.png		\
 | 
			
		||||
	theme/scroll-hhandle.svg		\
 | 
			
		||||
	theme/scroll-vhandle.svg		\
 | 
			
		||||
	theme/section-more.svg			\
 | 
			
		||||
	theme/section-more-open.svg		\
 | 
			
		||||
	theme/separator-white.png		\
 | 
			
		||||
	theme/single-view-active.svg		\
 | 
			
		||||
	theme/single-view.svg			\
 | 
			
		||||
	theme/source-button-border.svg		\
 | 
			
		||||
	theme/toggle-off-us.svg			\
 | 
			
		||||
	theme/toggle-off-intl.svg		\
 | 
			
		||||
	theme/toggle-on-us.svg			\
 | 
			
		||||
@@ -67,28 +60,14 @@ gschemas.compiled: $(gsettings_SCHEMAS:.xml=.valid)
 | 
			
		||||
all-local: gschemas.compiled
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# GConf schemas: provide defaults for keys from Metacity we are overriding
 | 
			
		||||
gconfschemadir  = @GCONF_SCHEMA_FILE_DIR@
 | 
			
		||||
gconfschema_DATA = gnome-shell.schemas
 | 
			
		||||
 | 
			
		||||
menudir = $(sysconfdir)/xdg/menus
 | 
			
		||||
 | 
			
		||||
menu_DATA = \
 | 
			
		||||
	gs-applications.menu
 | 
			
		||||
 | 
			
		||||
shadersdir = $(pkgdatadir)/shaders
 | 
			
		||||
shaders_DATA = \
 | 
			
		||||
	shaders/dim-window.glsl
 | 
			
		||||
 | 
			
		||||
install-data-local:
 | 
			
		||||
	GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(srcdir)/$(gconfschema_DATA)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
EXTRA_DIST =						\
 | 
			
		||||
	gnome-shell.desktop.in.in			\
 | 
			
		||||
	$(menu_DATA)					\
 | 
			
		||||
	$(gconfschema_DATA)				\
 | 
			
		||||
	$(shaders_DATA)					\
 | 
			
		||||
	org.gnome.shell.gschema.xml.in
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,3 +13,4 @@ NoDisplay=true
 | 
			
		||||
X-GNOME-Autostart-Phase=WindowManager
 | 
			
		||||
X-GNOME-Provides=panel;windowmanager;
 | 
			
		||||
X-GNOME-Autostart-Notify=true
 | 
			
		||||
X-GNOME-AutoRestart=true
 | 
			
		||||
 
 | 
			
		||||
@@ -1,85 +0,0 @@
 | 
			
		||||
<gconfschemafile>
 | 
			
		||||
    <schemalist>
 | 
			
		||||
 | 
			
		||||
      <!-- Metacity overrides -->
 | 
			
		||||
      <schema>
 | 
			
		||||
        <key>/schemas/desktop/gnome/shell/windows/attach_modal_dialogs</key>
 | 
			
		||||
        <applyto>/desktop/gnome/shell/windows/attach_modal_dialogs</applyto>
 | 
			
		||||
        <owner>gnome-shell</owner>
 | 
			
		||||
        <type>bool</type>
 | 
			
		||||
        <default>true</default>
 | 
			
		||||
        <locale name="C">
 | 
			
		||||
          <short>Attach modal dialog to the parent window</short>
 | 
			
		||||
          <long>
 | 
			
		||||
             This key overrides /apps/mutter/general/attach_modal_dialogs when
 | 
			
		||||
             running GNOME Shell.
 | 
			
		||||
          </long>
 | 
			
		||||
        </locale>
 | 
			
		||||
      </schema>
 | 
			
		||||
 | 
			
		||||
      <schema>
 | 
			
		||||
        <key>/schemas/desktop/gnome/shell/windows/button_layout</key>
 | 
			
		||||
        <applyto>/desktop/gnome/shell/windows/button_layout</applyto>
 | 
			
		||||
        <owner>gnome-shell</owner>
 | 
			
		||||
        <type>string</type>
 | 
			
		||||
        <default>:close</default>
 | 
			
		||||
        <locale name="C">
 | 
			
		||||
           <short>Arrangement of buttons on the titlebar</short>
 | 
			
		||||
           <long>
 | 
			
		||||
             Arrangement of buttons on the titlebar. The
 | 
			
		||||
             value should be a string, such as
 | 
			
		||||
             "menu:minimize,maximize,spacer,close"; the colon separates the
 | 
			
		||||
             left corner of the window from the right corner, and
 | 
			
		||||
             the button names are comma-separated. Duplicate buttons
 | 
			
		||||
             are not allowed. Unknown button names are silently ignored
 | 
			
		||||
             so that buttons can be added in future gnome-shell versions
 | 
			
		||||
             without breaking older versions.
 | 
			
		||||
             A special spacer tag can be used to insert some space between
 | 
			
		||||
             two adjacent buttons.
 | 
			
		||||
 | 
			
		||||
             This key overrides /apps/metacity/general/button_layout when
 | 
			
		||||
             running GNOME Shell.
 | 
			
		||||
           </long>
 | 
			
		||||
        </locale>
 | 
			
		||||
      </schema>
 | 
			
		||||
 | 
			
		||||
      <schema>
 | 
			
		||||
        <key>/schemas/desktop/gnome/shell/windows/edge_tiling</key>
 | 
			
		||||
        <applyto>/desktop/gnome/shell/windows/edge_tiling</applyto>
 | 
			
		||||
        <owner>gnome-shell</owner>
 | 
			
		||||
        <type>bool</type>
 | 
			
		||||
        <default>true</default>
 | 
			
		||||
        <locale name="C">
 | 
			
		||||
          <short>enable edge tiling when dropping windows on screen edges</short>
 | 
			
		||||
          <long>
 | 
			
		||||
             If enabled, dropping windows on vertical screen edges maximizes them
 | 
			
		||||
             vertically and resizes them horizontally to cover half of the
 | 
			
		||||
             available area. Dropping windows on the top screen edge maximizes them
 | 
			
		||||
             completely.
 | 
			
		||||
 | 
			
		||||
             This key overrides /apps/metacity/general/edge_tiling when
 | 
			
		||||
             running GNOME Shell.
 | 
			
		||||
          </long>
 | 
			
		||||
        </locale>
 | 
			
		||||
      </schema>
 | 
			
		||||
 | 
			
		||||
      <schema>
 | 
			
		||||
        <key>/schemas/desktop/gnome/shell/windows/theme</key>
 | 
			
		||||
        <applyto>/desktop/gnome/shell/windows/theme</applyto>
 | 
			
		||||
        <owner>gnome-shell</owner>
 | 
			
		||||
        <type>string</type>
 | 
			
		||||
        <default>Adwaita</default>
 | 
			
		||||
        <locale name="C">
 | 
			
		||||
          <short>Current theme</short>
 | 
			
		||||
          <long>
 | 
			
		||||
            The theme determines the appearance of window borders,
 | 
			
		||||
            titlebar, and so forth.
 | 
			
		||||
 | 
			
		||||
            This key overrides /apps/metacity/general/theme when
 | 
			
		||||
            running GNOME Shell.
 | 
			
		||||
          </long>
 | 
			
		||||
        </locale>
 | 
			
		||||
      </schema>
 | 
			
		||||
 | 
			
		||||
  </schemalist>
 | 
			
		||||
</gconfschemafile>
 | 
			
		||||
@@ -1,85 +0,0 @@
 | 
			
		||||
<Menu>
 | 
			
		||||
	<DefaultLayout>
 | 
			
		||||
		<Menuname>Accessories</Menuname>
 | 
			
		||||
		<Menuname>Games</Menuname>
 | 
			
		||||
		<Menuname>Graphics</Menuname>
 | 
			
		||||
		<Menuname>Internet</Menuname>
 | 
			
		||||
		<Menuname>Multimedia</Menuname>
 | 
			
		||||
		<Menuname>Office</Menuname>
 | 
			
		||||
		<Menuname>Other</Menuname>
 | 
			
		||||
	</DefaultLayout>
 | 
			
		||||
 | 
			
		||||
	<Name>Applications</Name>
 | 
			
		||||
	<AppDir>/usr/local/share/applications</AppDir>
 | 
			
		||||
	<DefaultAppDirs/>
 | 
			
		||||
 | 
			
		||||
	<Menu>
 | 
			
		||||
		<Name>Accessories</Name>
 | 
			
		||||
		<Include>
 | 
			
		||||
			<And>
 | 
			
		||||
				<Category>Utility</Category>
 | 
			
		||||
				<Not>
 | 
			
		||||
					<Category>System</Category>
 | 
			
		||||
				</Not>
 | 
			
		||||
			</And>
 | 
			
		||||
		</Include>
 | 
			
		||||
	</Menu>
 | 
			
		||||
 | 
			
		||||
	<Menu>
 | 
			
		||||
		<Name>Games</Name>
 | 
			
		||||
		<Include>
 | 
			
		||||
			<And>
 | 
			
		||||
				<Category>Game</Category>
 | 
			
		||||
			</And>
 | 
			
		||||
		</Include>
 | 
			
		||||
	</Menu>
 | 
			
		||||
 | 
			
		||||
	<Menu>
 | 
			
		||||
		<Name>Graphics</Name>
 | 
			
		||||
		<Include>
 | 
			
		||||
			<And>
 | 
			
		||||
				<Category>Graphics</Category>
 | 
			
		||||
			</And>
 | 
			
		||||
		</Include>
 | 
			
		||||
	</Menu>
 | 
			
		||||
 | 
			
		||||
	<Menu>
 | 
			
		||||
		<Name>Internet</Name>
 | 
			
		||||
		<Include>
 | 
			
		||||
			<And>
 | 
			
		||||
				<Category>Network</Category>
 | 
			
		||||
				<Not><Category>Settings</Category></Not>
 | 
			
		||||
			</And>
 | 
			
		||||
		</Include>
 | 
			
		||||
	</Menu>
 | 
			
		||||
 | 
			
		||||
	<Menu>
 | 
			
		||||
		<Name>Multimedia</Name>
 | 
			
		||||
		<Include>
 | 
			
		||||
			<And>
 | 
			
		||||
				<Category>AudioVideo</Category>
 | 
			
		||||
				<Not><Category>Settings</Category></Not>
 | 
			
		||||
			</And>
 | 
			
		||||
		</Include>
 | 
			
		||||
	</Menu>
 | 
			
		||||
 | 
			
		||||
	<Menu>
 | 
			
		||||
		<Name>Office</Name>
 | 
			
		||||
		<Include>
 | 
			
		||||
			<And>
 | 
			
		||||
				<Category>Office</Category>
 | 
			
		||||
			</And>
 | 
			
		||||
		</Include>
 | 
			
		||||
	</Menu>
 | 
			
		||||
 | 
			
		||||
	<Menu>
 | 
			
		||||
		<Name>Other</Name>
 | 
			
		||||
		<OnlyUnallocated/>
 | 
			
		||||
		<Include>
 | 
			
		||||
			<And>
 | 
			
		||||
				<Not><Category>Settings</Category></Not>
 | 
			
		||||
				<Not><Category>Screensaver</Category></Not>
 | 
			
		||||
			</And>
 | 
			
		||||
		</Include>
 | 
			
		||||
	</Menu>
 | 
			
		||||
</Menu>
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<schemalist>
 | 
			
		||||
  <schema id="org.gnome.shell" path="/apps/gnome-shell/"
 | 
			
		||||
  <schema id="org.gnome.shell" path="/org/gnome/shell/"
 | 
			
		||||
          gettext-domain="@GETTEXT_PACKAGE@">
 | 
			
		||||
    <key name="development-tools" type="b">
 | 
			
		||||
      <default>true</default>
 | 
			
		||||
@@ -11,12 +11,14 @@
 | 
			
		||||
        using the Alt-F2 dialog.
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="disabled-extensions" type="as">
 | 
			
		||||
    <key name="enabled-extensions" type="as">
 | 
			
		||||
      <default>[]</default>
 | 
			
		||||
      <_summary>Uuids of extensions to disable</_summary>
 | 
			
		||||
      <_summary>Uuids of extensions to enable</_summary>
 | 
			
		||||
      <_description>
 | 
			
		||||
        GNOME Shell extensions have a uuid property;
 | 
			
		||||
        this key lists extensions which should not be loaded.
 | 
			
		||||
        GNOME Shell extensions have a uuid property; this key lists extensions
 | 
			
		||||
        which should be loaded. Any extension that wants to be loaded needs
 | 
			
		||||
        to be in this list. You can also manipulate this list with the
 | 
			
		||||
        EnableExtension and DisableExtension DBus methods on org.gnome.Shell.
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="enable-app-monitoring" type="b">
 | 
			
		||||
@@ -30,7 +32,7 @@
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="favorite-apps" type="as">
 | 
			
		||||
      <default>[ 'mozilla-firefox.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'openoffice.org-writer.desktop', 'nautilus.desktop' ]</default>
 | 
			
		||||
      <default>[ 'epiphany.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'libreoffice-writer.desktop', 'nautilus.desktop', 'gnome-documents.desktop' ]</default>
 | 
			
		||||
      <_summary>List of desktop file IDs for favorite applications</_summary>
 | 
			
		||||
      <_description>
 | 
			
		||||
        The applications corresponding to these identifiers
 | 
			
		||||
@@ -49,12 +51,21 @@
 | 
			
		||||
      <default>[]</default>
 | 
			
		||||
      <_summary>History for the looking glass dialog</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="saved-im-presence" type="i">
 | 
			
		||||
      <default>1</default>
 | 
			
		||||
      <_summary></_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="saved-session-presence" type="i">
 | 
			
		||||
      <default>0</default>
 | 
			
		||||
      <_summary></_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <child name="clock" schema="org.gnome.shell.clock"/>
 | 
			
		||||
    <child name="calendar" schema="org.gnome.shell.calendar"/>
 | 
			
		||||
    <child name="recorder" schema="org.gnome.shell.recorder"/>
 | 
			
		||||
    <child name="keyboard" schema="org.gnome.shell.keyboard"/>
 | 
			
		||||
  </schema>
 | 
			
		||||
 | 
			
		||||
  <schema id="org.gnome.shell.calendar" path="/apps/gnome-shell/calendar/"
 | 
			
		||||
  <schema id="org.gnome.shell.calendar" path="/org/gnome/shell/calendar/"
 | 
			
		||||
          gettext-domain="@GETTEXT_PACKAGE@">
 | 
			
		||||
    <key name="show-weekdate" type="b">
 | 
			
		||||
      <default>false</default>
 | 
			
		||||
@@ -65,7 +76,18 @@
 | 
			
		||||
      </key>
 | 
			
		||||
  </schema>
 | 
			
		||||
 | 
			
		||||
  <schema id="org.gnome.shell.clock" path="/apps/gnome-shell/clock/"
 | 
			
		||||
  <schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/"
 | 
			
		||||
          gettext-domain="@GETTEXT_PACKAGE@">
 | 
			
		||||
    <key name="keyboard-type" type="s">
 | 
			
		||||
      <default>'touch'</default>
 | 
			
		||||
      <_summary>Which keyboard to use</_summary>
 | 
			
		||||
      <_description>
 | 
			
		||||
        The type of keyboard to use.
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
  </schema>
 | 
			
		||||
 | 
			
		||||
  <schema id="org.gnome.shell.clock" path="/org/gnome/shell/clock/"
 | 
			
		||||
          gettext-domain="@GETTEXT_PACKAGE@">
 | 
			
		||||
    <key name="show-seconds" type="b">
 | 
			
		||||
      <default>false</default>
 | 
			
		||||
@@ -83,7 +105,7 @@
 | 
			
		||||
    </key>
 | 
			
		||||
  </schema>
 | 
			
		||||
 | 
			
		||||
  <schema id="org.gnome.shell.recorder" path="/apps/gnome-shell/recorder/"
 | 
			
		||||
  <schema id="org.gnome.shell.recorder" path="/org/gnome/shell/recorder/"
 | 
			
		||||
          gettext-domain="@GETTEXT_PACKAGE@">
 | 
			
		||||
    <key name="framerate" type="i">
 | 
			
		||||
      <default>15</default>
 | 
			
		||||
@@ -120,4 +142,40 @@
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
  </schema>
 | 
			
		||||
 | 
			
		||||
  <schema id="org.gnome.shell.overrides" path="/org/gnome/shell/overrides/">
 | 
			
		||||
    <key name="attach-modal-dialogs" type="b">
 | 
			
		||||
      <default>true</default>
 | 
			
		||||
      <summary>Attach modal dialog to the parent window</summary>
 | 
			
		||||
      <description>
 | 
			
		||||
        This key overrides the key in org.gnome.mutter when running
 | 
			
		||||
        GNOME Shell.
 | 
			
		||||
      </description>
 | 
			
		||||
    </key>
 | 
			
		||||
 | 
			
		||||
    <key name="button-layout" type="s">
 | 
			
		||||
      <default>":close"</default>
 | 
			
		||||
      <summary>Arrangement of buttons on the titlebar</summary>
 | 
			
		||||
      <description>
 | 
			
		||||
        This key overrides the key in org.gnome.desktop.wm.preferences when
 | 
			
		||||
        running GNOME Shell.
 | 
			
		||||
      </description>
 | 
			
		||||
    </key>
 | 
			
		||||
 | 
			
		||||
    <key name="edge-tiling" type="b">
 | 
			
		||||
      <default>true</default>
 | 
			
		||||
      <summary>Enable edge tiling when dropping windows on screen edges</summary>
 | 
			
		||||
      <description>
 | 
			
		||||
        This key overrides the key in org.gnome.mutter when running GNOME Shell.
 | 
			
		||||
      </description>
 | 
			
		||||
    </key>
 | 
			
		||||
 | 
			
		||||
    <key name="workspaces-only-on-primary" type="b">
 | 
			
		||||
      <default>true</default>
 | 
			
		||||
      <summary>Workspaces only on primary monitor</summary>
 | 
			
		||||
      <description>
 | 
			
		||||
        This key overrides the key in org.gnome.mutter when running GNOME Shell.
 | 
			
		||||
      </description>
 | 
			
		||||
    </key>
 | 
			
		||||
  </schema>
 | 
			
		||||
</schemalist>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
#version 110
 | 
			
		||||
uniform sampler2D sampler0;
 | 
			
		||||
uniform sampler2D tex;
 | 
			
		||||
uniform float fraction;
 | 
			
		||||
uniform float height;
 | 
			
		||||
const float c = -0.2;
 | 
			
		||||
@@ -12,15 +12,16 @@ mat4 contrast = mat4 (1.0 + c, 0.0, 0.0, 0.0,
 | 
			
		||||
vec4 off = vec4(0.633, 0.633, 0.633, 0);
 | 
			
		||||
void main()
 | 
			
		||||
{
 | 
			
		||||
  vec4 color = texture2D(sampler0, gl_TexCoord[0].st);
 | 
			
		||||
  float y = height * gl_TexCoord[0][1];
 | 
			
		||||
  vec4 color = texture2D(tex, cogl_tex_coord_in[0].xy);
 | 
			
		||||
  float y = height * cogl_tex_coord_in[0].y;
 | 
			
		||||
 | 
			
		||||
  // To reduce contrast, blend with a mid gray
 | 
			
		||||
  gl_FragColor = color * contrast - off * c;
 | 
			
		||||
  cogl_color_out = color * contrast - off * c * color.a;
 | 
			
		||||
 | 
			
		||||
  // We only fully dim at a distance of BORDER_MAX_HEIGHT from the edge and
 | 
			
		||||
  // We only fully dim at a distance of BORDER_MAX_HEIGHT from the top and
 | 
			
		||||
  // when the fraction is 1.0. For other locations and fractions we linearly
 | 
			
		||||
  // interpolate back to the original undimmed color.
 | 
			
		||||
  gl_FragColor = color + (gl_FragColor - color) * min(y / border_max_height, 1.0);
 | 
			
		||||
  gl_FragColor = color + (gl_FragColor - color) * fraction;
 | 
			
		||||
  // interpolate back to the original undimmed color, so the top of the window
 | 
			
		||||
  // is at full color.
 | 
			
		||||
  cogl_color_out = color + (cogl_color_out - color) * max(min(y / border_max_height, 1.0), 0.0);
 | 
			
		||||
  cogl_color_out = color + (cogl_color_out - color) * fraction;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,24 +1,26 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  -->
 | 
			
		||||
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:xlink="http://www.w3.org/1999/xlink"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   version="1.0"
 | 
			
		||||
   id="Foreground"
 | 
			
		||||
   x="0px"
 | 
			
		||||
   y="0px"
 | 
			
		||||
   width="22"
 | 
			
		||||
   height="22"
 | 
			
		||||
   viewBox="0 0 16 16"
 | 
			
		||||
   width="32"
 | 
			
		||||
   height="32"
 | 
			
		||||
   viewBox="0 0 23.272727 23.272727"
 | 
			
		||||
   enable-background="new 0 0 16 16"
 | 
			
		||||
   xml:space="preserve"
 | 
			
		||||
   sodipodi:version="0.32"
 | 
			
		||||
   inkscape:version="0.46"
 | 
			
		||||
   inkscape:version="0.48+devel r10081 custom"
 | 
			
		||||
   sodipodi:docname="close-window.svg"
 | 
			
		||||
   inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
 | 
			
		||||
   id="metadata2399"><rdf:RDF><cc:Work
 | 
			
		||||
@@ -37,11 +39,49 @@
 | 
			
		||||
     inkscape:vp_y="0 : 1000 : 0"
 | 
			
		||||
     inkscape:vp_z="16 : 8 : 1"
 | 
			
		||||
     inkscape:persp3d-origin="8 : 5.3333333 : 1"
 | 
			
		||||
     id="perspective2401" /></defs><sodipodi:namedview
 | 
			
		||||
   inkscape:window-height="999"
 | 
			
		||||
   inkscape:window-width="1680"
 | 
			
		||||
     id="perspective2401" /><filter
 | 
			
		||||
     color-interpolation-filters="sRGB"
 | 
			
		||||
     inkscape:collect="always"
 | 
			
		||||
     id="filter16494-4"
 | 
			
		||||
     x="-0.20989846"
 | 
			
		||||
     width="1.4197969"
 | 
			
		||||
     y="-0.20903821"
 | 
			
		||||
     height="1.4180764"><feGaussianBlur
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       stdDeviation="1.3282637"
 | 
			
		||||
       id="feGaussianBlur16496-8" /></filter><radialGradient
 | 
			
		||||
     inkscape:collect="always"
 | 
			
		||||
     xlink:href="#linearGradient16498-6"
 | 
			
		||||
     id="radialGradient16504-1"
 | 
			
		||||
     cx="7.6582627"
 | 
			
		||||
     cy="5.8191104"
 | 
			
		||||
     fx="7.6582627"
 | 
			
		||||
     fy="5.8191104"
 | 
			
		||||
     r="8.6928644"
 | 
			
		||||
     gradientTransform="matrix(1.0474339,0,0,1.0517402,-0.3632615,-0.42032492)"
 | 
			
		||||
     gradientUnits="userSpaceOnUse" /><linearGradient
 | 
			
		||||
     inkscape:collect="always"
 | 
			
		||||
     id="linearGradient16498-6"><stop
 | 
			
		||||
       style="stop-color:#7b7b7b;stop-opacity:1"
 | 
			
		||||
       offset="0"
 | 
			
		||||
       id="stop16500-8" /><stop
 | 
			
		||||
       style="stop-color:#101010;stop-opacity:1"
 | 
			
		||||
       offset="1"
 | 
			
		||||
       id="stop16502-0" /></linearGradient><filter
 | 
			
		||||
     color-interpolation-filters="sRGB"
 | 
			
		||||
     inkscape:collect="always"
 | 
			
		||||
     id="filter16524-9"
 | 
			
		||||
     x="-0.212979"
 | 
			
		||||
     width="1.425958"
 | 
			
		||||
     y="-0.21305652"
 | 
			
		||||
     height="1.426113"><feGaussianBlur
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       stdDeviation="0.71020915"
 | 
			
		||||
       id="feGaussianBlur16526-0" /></filter></defs><sodipodi:namedview
 | 
			
		||||
   inkscape:window-height="1114"
 | 
			
		||||
   inkscape:window-width="1463"
 | 
			
		||||
   inkscape:pageshadow="2"
 | 
			
		||||
   inkscape:pageopacity="1"
 | 
			
		||||
   inkscape:pageopacity="0"
 | 
			
		||||
   guidetolerance="10.0"
 | 
			
		||||
   gridtolerance="10.0"
 | 
			
		||||
   objecttolerance="10.0"
 | 
			
		||||
@@ -50,27 +90,63 @@
 | 
			
		||||
   pagecolor="#000000"
 | 
			
		||||
   id="base"
 | 
			
		||||
   showgrid="false"
 | 
			
		||||
   inkscape:zoom="25.648691"
 | 
			
		||||
   inkscape:cx="8.8097603"
 | 
			
		||||
   inkscape:cy="9.0472789"
 | 
			
		||||
   inkscape:zoom="1"
 | 
			
		||||
   inkscape:cx="10.720189"
 | 
			
		||||
   inkscape:cy="13.739577"
 | 
			
		||||
   inkscape:window-x="0"
 | 
			
		||||
   inkscape:window-y="26"
 | 
			
		||||
   inkscape:current-layer="Foreground"
 | 
			
		||||
   showguides="true"
 | 
			
		||||
   inkscape:guide-bbox="true" />
 | 
			
		||||
   inkscape:guide-bbox="true"
 | 
			
		||||
   borderlayer="true"
 | 
			
		||||
   inkscape:showpageshadow="false"
 | 
			
		||||
   inkscape:window-maximized="0"><inkscape:grid
 | 
			
		||||
     type="xygrid"
 | 
			
		||||
     id="grid11246"
 | 
			
		||||
     empspacing="5"
 | 
			
		||||
     visible="true"
 | 
			
		||||
     enabled="true"
 | 
			
		||||
     snapvisiblegridlinesonly="true" /></sodipodi:namedview>
 | 
			
		||||
 | 
			
		||||
<g
 | 
			
		||||
   id="g3175"><path
 | 
			
		||||
     sodipodi:nodetypes="csssc"
 | 
			
		||||
     style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.59217799;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
     id="path2394"
 | 
			
		||||
     d="M 0.83987936,8.0425327 C 0.83987936,4.0805265 4.0712155,0.86823453 8.0567103,0.86823453 C 12.042205,0.86823453 15.273542,4.0805265 15.273542,8.0425327 C 15.273542,12.004539 12.042205,15.216831 8.0567103,15.216831 C 4.0712155,15.216831 0.83987936,12.004539 0.83987936,8.0425327 z"
 | 
			
		||||
     clip-rule="evenodd" /><g
 | 
			
		||||
     id="g3172"><path
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.67127273;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
       d="M 5.4242673,5.3313047 L 10.515414,10.421272 L 10.714004,10.646491"
 | 
			
		||||
       id="path3152" /></g></g><path
 | 
			
		||||
   style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.67127273;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
   d="M 5.4402527,10.650392 L 10.688082,5.3573033"
 | 
			
		||||
   id="path3154"
 | 
			
		||||
   sodipodi:nodetypes="cc" /></svg>
 | 
			
		||||
   style="display:inline"
 | 
			
		||||
   id="g16402-8"
 | 
			
		||||
   transform="translate(4.7533483,2.8238929)"><g
 | 
			
		||||
     id="g3175-4"><path
 | 
			
		||||
       sodipodi:type="inkscape:offset"
 | 
			
		||||
       inkscape:radius="0"
 | 
			
		||||
       inkscape:original="M 7.65625 0.125 C 3.2589349 0.125 -0.3125 3.7070002 -0.3125 8.125 C -0.3125 12.543001 3.2589349 16.125 7.65625 16.125 C 12.053566 16.125 15.625 12.543001 15.625 8.125 C 15.625 3.7070002 12.053566 0.125 7.65625 0.125 z "
 | 
			
		||||
       xlink:href="#path2394-32"
 | 
			
		||||
       style="opacity:0.52994014;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.18181825;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter16494-4);enable-background:accumulate"
 | 
			
		||||
       id="path16480-5"
 | 
			
		||||
       inkscape:href="#path2394-32"
 | 
			
		||||
       d="m 7.65625,0.125 c -4.3973151,0 -7.96875,3.5820002 -7.96875,8 0,4.418001 3.5714349,8 7.96875,8 4.397316,0 7.96875,-3.581999 7.96875,-8 0,-4.4179998 -3.571434,-8 -7.96875,-8 z"
 | 
			
		||||
       transform="translate(0,1.028519)" /><path
 | 
			
		||||
       clip-rule="evenodd"
 | 
			
		||||
       d="m -0.30428257,8.1237596 c 0,-4.4179998 3.56522987,-7.9999996 7.96254497,-7.9999996 4.3973156,0 7.9625456,3.5819998 7.9625456,7.9999996 0,4.4180014 -3.56523,8.0000004 -7.9625456,8.0000004 -4.3973151,0 -7.96254497,-3.581999 -7.96254497,-8.0000004 z"
 | 
			
		||||
       id="path2394-32"
 | 
			
		||||
       style="color:#000000;fill:url(#radialGradient16504-1);fill-opacity:1;fill-rule:nonzero;stroke:#eeeeec;stroke-width:1.4545455;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
       sodipodi:nodetypes="csssc"
 | 
			
		||||
       inkscape:connector-curvature="0" /><g
 | 
			
		||||
       id="g3172-6" /></g><g
 | 
			
		||||
     transform="matrix(0.72727273,0,0,0.72727273,2.368236,2.1803254)"
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:1;display:inline"
 | 
			
		||||
     id="g27275-6-6"
 | 
			
		||||
     inkscape:label="window-close"><g
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;display:inline"
 | 
			
		||||
       id="g27277-1-1"
 | 
			
		||||
       transform="translate(-41,-760)"><path
 | 
			
		||||
         sodipodi:type="inkscape:offset"
 | 
			
		||||
         inkscape:radius="0"
 | 
			
		||||
         inkscape:original="M 44.21875 764.1875 L 44.21875 765.1875 C 44.19684 765.46825 44.289258 765.74287 44.5 765.9375 L 46.78125 768.21875 L 44.5 770.46875 C 44.31181 770.65692 44.218747 770.92221 44.21875 771.1875 L 44.21875 772.1875 L 45.21875 772.1875 C 45.48404 772.1875 45.749336 772.09444 45.9375 771.90625 L 48.21875 769.625 L 50.5 771.90625 C 50.688164 772.0944 50.953449 772.18749 51.21875 772.1875 L 52.21875 772.1875 L 52.21875 771.1875 C 52.218742 770.9222 52.125688 770.65692 51.9375 770.46875 L 49.6875 768.21875 L 51.96875 765.9375 C 52.18441 765.73815 52.21875 765.47397 52.21875 765.1875 L 52.21875 764.1875 L 51.21875 764.1875 C 50.977922 764.1945 50.796875 764.2695 50.53125 764.5 L 48.21875 766.78125 L 45.9375 764.5 C 45.75987 764.31608 45.504951 764.1987 45.25 764.1875 C 45.23954 764.18704 45.22912 764.18738 45.21875 764.1875 L 44.21875 764.1875 z "
 | 
			
		||||
         xlink:href="#path27279-0-5"
 | 
			
		||||
         style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#bebebe;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.78124988;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter16524-9);enable-background:new;font-family:Andale Mono;-inkscape-font-specification:Andale Mono"
 | 
			
		||||
         id="path16506-5"
 | 
			
		||||
         inkscape:href="#path27279-0-5"
 | 
			
		||||
         d="m 44.21875,764.1875 0,1 c -0.02191,0.28075 0.07051,0.55537 0.28125,0.75 l 2.28125,2.28125 -2.28125,2.25 c -0.18819,0.18817 -0.281253,0.45346 -0.28125,0.71875 l 0,1 1,0 c 0.26529,0 0.530586,-0.0931 0.71875,-0.28125 L 48.21875,769.625 50.5,771.90625 c 0.188164,0.18815 0.453449,0.28124 0.71875,0.28125 l 1,0 0,-1 c -8e-6,-0.2653 -0.09306,-0.53058 -0.28125,-0.71875 l -2.25,-2.25 2.28125,-2.28125 c 0.21566,-0.19935 0.25,-0.46353 0.25,-0.75 l 0,-1 -1,0 c -0.240828,0.007 -0.421875,0.082 -0.6875,0.3125 l -2.3125,2.28125 L 45.9375,764.5 c -0.17763,-0.18392 -0.432549,-0.3013 -0.6875,-0.3125 -0.01046,-4.6e-4 -0.02088,-1.2e-4 -0.03125,0 l -1,0 z"
 | 
			
		||||
         transform="translate(0,1.3535534)" /><path
 | 
			
		||||
         sodipodi:nodetypes="ccsccccccccccccccccccccccc"
 | 
			
		||||
         style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#bebebe;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.78124988;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new;font-family:Andale Mono;-inkscape-font-specification:Andale Mono"
 | 
			
		||||
         id="path27279-0-5"
 | 
			
		||||
         inkscape:connector-curvature="0"
 | 
			
		||||
         d="m 44.226475,764.17222 1,0 c 0.01037,-1.2e-4 0.02079,-4.6e-4 0.03125,0 0.254951,0.0112 0.50987,0.12858 0.6875,0.3125 l 2.28125,2.28125 2.3125,-2.28125 c 0.265625,-0.2305 0.446672,-0.3055 0.6875,-0.3125 l 1,0 0,1 c 0,0.28647 -0.03434,0.55065 -0.25,0.75 l -2.28125,2.28125 2.25,2.25 c 0.188188,0.18817 0.281242,0.45345 0.28125,0.71875 l 0,1 -1,0 c -0.265301,-1e-5 -0.530586,-0.0931 -0.71875,-0.28125 l -2.28125,-2.28125 -2.28125,2.28125 c -0.188164,0.18819 -0.45346,0.28125 -0.71875,0.28125 l -1,0 0,-1 c -3e-6,-0.26529 0.09306,-0.53058 0.28125,-0.71875 l 2.28125,-2.25 -2.28125,-2.28125 c -0.210742,-0.19463 -0.30316,-0.46925 -0.28125,-0.75 l 0,-1 z" /></g></g></g></svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 9.4 KiB  | 
| 
		 Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								data/theme/corner-ripple-rtl.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.3 KiB  | 
| 
		 Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB  | 
@@ -9,23 +9,23 @@
 | 
			
		||||
   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="24"
 | 
			
		||||
   height="16"
 | 
			
		||||
   id="svg6446"
 | 
			
		||||
   width="10"
 | 
			
		||||
   height="20"
 | 
			
		||||
   id="svg10003"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.47pre4 r22446"
 | 
			
		||||
   sodipodi:docname="single-view-active.svg">
 | 
			
		||||
   inkscape:version="0.48.1 r9760"
 | 
			
		||||
   sodipodi:docname="filter-selected-ltr.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs6448">
 | 
			
		||||
     id="defs10005">
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       sodipodi:type="inkscape:persp3d"
 | 
			
		||||
       inkscape:vp_x="0 : 16 : 1"
 | 
			
		||||
       inkscape:vp_x="0 : 32 : 1"
 | 
			
		||||
       inkscape:vp_y="0 : 1000 : 0"
 | 
			
		||||
       inkscape:vp_z="32 : 16 : 1"
 | 
			
		||||
       inkscape:persp3d-origin="16 : 10.666667 : 1"
 | 
			
		||||
       id="perspective6454" />
 | 
			
		||||
       inkscape:vp_z="64 : 32 : 1"
 | 
			
		||||
       inkscape:persp3d-origin="32 : 21.333333 : 1"
 | 
			
		||||
       id="perspective10011" />
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       id="perspective6441"
 | 
			
		||||
       id="perspective9998"
 | 
			
		||||
       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
 | 
			
		||||
       inkscape:vp_z="1 : 0.5 : 1"
 | 
			
		||||
       inkscape:vp_y="0 : 1000 : 0"
 | 
			
		||||
@@ -37,29 +37,29 @@
 | 
			
		||||
     pagecolor="#ffffff"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="0.0"
 | 
			
		||||
     inkscape:pageopacity="0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="11.197802"
 | 
			
		||||
     inkscape:cx="0.014720032"
 | 
			
		||||
     inkscape:cy="16"
 | 
			
		||||
     inkscape:zoom="5.5"
 | 
			
		||||
     inkscape:cx="32.363636"
 | 
			
		||||
     inkscape:cy="10.181818"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="true"
 | 
			
		||||
     inkscape:grid-bbox="true"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:window-width="1680"
 | 
			
		||||
     inkscape:window-height="997"
 | 
			
		||||
     inkscape:grid-bbox="true"
 | 
			
		||||
     inkscape:window-width="1440"
 | 
			
		||||
     inkscape:window-height="839"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="26"
 | 
			
		||||
     inkscape:window-maximized="1" />
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata6451">
 | 
			
		||||
     id="metadata10008">
 | 
			
		||||
    <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></dc:title>
 | 
			
		||||
      </cc:Work>
 | 
			
		||||
    </rdf:RDF>
 | 
			
		||||
  </metadata>
 | 
			
		||||
@@ -67,15 +67,15 @@
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     inkscape:label="Layer 1"
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     transform="translate(0,-17)">
 | 
			
		||||
    <rect
 | 
			
		||||
       ry="0.5"
 | 
			
		||||
       rx="0.49999979"
 | 
			
		||||
       y="17.483809"
 | 
			
		||||
       x="0.53483802"
 | 
			
		||||
       height="15"
 | 
			
		||||
       width="23"
 | 
			
		||||
       id="rect5304"
 | 
			
		||||
       style="fill:#cccccc;fill-opacity:1;stroke:#cccccc;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
 | 
			
		||||
     transform="translate(0,-44)">
 | 
			
		||||
    <path
 | 
			
		||||
       inkscape:export-ydpi="90"
 | 
			
		||||
       inkscape:export-xdpi="90"
 | 
			
		||||
       inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/app-picker.png"
 | 
			
		||||
       sodipodi:nodetypes="cccc"
 | 
			
		||||
       inkscape:connector-curvature="0"
 | 
			
		||||
       id="rect34320"
 | 
			
		||||
       d="m 10.369085,54.181804 -10.55634072,10.55636 -1e-5,-21.11269 z"
 | 
			
		||||
       style="opacity:0.21000001;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.99999988;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.7 KiB  | 
							
								
								
									
										180
									
								
								data/theme/gdm.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,180 @@
 | 
			
		||||
/* Copyright 2011, Red Hat, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms and conditions of the GNU Lesser General Public License,
 | 
			
		||||
 * version 2.1, as published by the Free Software Foundation.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope it will be useful, but WITHOUT ANY
 | 
			
		||||
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 | 
			
		||||
 * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 | 
			
		||||
 * more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Login Dialog */
 | 
			
		||||
 | 
			
		||||
.login-dialog-title {
 | 
			
		||||
    font-size: 14pt;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    color: #666666;
 | 
			
		||||
    padding-bottom: 2em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog {
 | 
			
		||||
    border-radius: 16px;
 | 
			
		||||
    min-height: 150px;
 | 
			
		||||
    max-height: 700px;
 | 
			
		||||
    min-width: 350px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-prompt-fingerprint-message {
 | 
			
		||||
    font-size: 10.5pt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-user-list-view {
 | 
			
		||||
    -st-vfade-offset: 1em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-user-list {
 | 
			
		||||
    spacing: 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-user-list-item {
 | 
			
		||||
    color: #666666;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-user-list-item:ltr {
 | 
			
		||||
    padding-right: 1em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-user-list-item:rtl {
 | 
			
		||||
    padding-left: 1em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-user-list-item .login-dialog-user-list-item-name {
 | 
			
		||||
    font-size: 20pt;
 | 
			
		||||
    padding-left: 1em;
 | 
			
		||||
    color: #666666;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-user-list-item:hover .login-dialog-user-list-item-name {
 | 
			
		||||
    color: white;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-user-list-item:focus .login-dialog-user-list-item-name {
 | 
			
		||||
    color: white;
 | 
			
		||||
    text-shadow: black 0px 2px 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-user-list-item-vertical-layout {
 | 
			
		||||
    spacing: 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-user-list-item .login-dialog-user-list-item-focus-bin {
 | 
			
		||||
    background-color: rgba(0,0,0,0.0);
 | 
			
		||||
    height: 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-user-list-item:focus .login-dialog-user-list-item-focus-bin {
 | 
			
		||||
    background-color: #666666;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-user-list-item-icon {
 | 
			
		||||
    border: 2px solid #8b8b8b;
 | 
			
		||||
    border-radius: 8px;
 | 
			
		||||
    width: 64px;
 | 
			
		||||
    height: 64px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-not-listed-button {
 | 
			
		||||
    padding-top: 2em;
 | 
			
		||||
}
 | 
			
		||||
.login-dialog-not-listed-label {
 | 
			
		||||
    font-size: 14pt;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    color: #666666;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-not-listed-button:hover .login-dialog-not-listed-label {
 | 
			
		||||
    color: white;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-prompt-layout {
 | 
			
		||||
    padding-bottom: 32px;
 | 
			
		||||
}
 | 
			
		||||
.login-dialog-prompt-label {
 | 
			
		||||
    color: white;
 | 
			
		||||
    font-size: 20pt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-prompt-entry {
 | 
			
		||||
    padding: 4px;
 | 
			
		||||
    border-radius: 4px;
 | 
			
		||||
    border: 2px solid #5656cc;
 | 
			
		||||
    color: black;
 | 
			
		||||
    background-color: white;
 | 
			
		||||
    caret-color: black;
 | 
			
		||||
    caret-size: 1px;
 | 
			
		||||
    width: 15em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-prompt-entry .capslock-warning {
 | 
			
		||||
    icon-size: 16px;
 | 
			
		||||
    warning-color: #999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-prompt-entry:insensitive {
 | 
			
		||||
    color: rgba(0,0,0,0.7);
 | 
			
		||||
    border: 2px solid #565656;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list {
 | 
			
		||||
    color: #ffffff;
 | 
			
		||||
    font-size: 10.5pt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-button {
 | 
			
		||||
    padding: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-button:focus {
 | 
			
		||||
    background-color: #4c4c4c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-button:active {
 | 
			
		||||
    background-color: #4c4c4c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-button:hover {
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-scroll-view {
 | 
			
		||||
    background-gradient-start: rgba(80,80,80,0.3);
 | 
			
		||||
    background-gradient-end: rgba(80,80,80,0.7);
 | 
			
		||||
    background-gradient-direction: vertical;
 | 
			
		||||
    box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9);
 | 
			
		||||
    border-radius: 8px;
 | 
			
		||||
    border: 1px solid rgba(80,80,80,1.0);
 | 
			
		||||
    padding: .5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-item:focus {
 | 
			
		||||
    background-color: #666666;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-triangle {
 | 
			
		||||
    padding-right: .5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-item-box {
 | 
			
		||||
    spacing: .25em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-item-dot {
 | 
			
		||||
    width: .75em;
 | 
			
		||||
    height: .75em;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,113 +0,0 @@
 | 
			
		||||
<?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="24"
 | 
			
		||||
   height="16"
 | 
			
		||||
   id="svg6503"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.47pre4 r22446"
 | 
			
		||||
   sodipodi:docname="mosaic-view-active.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs6505">
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       sodipodi:type="inkscape:persp3d"
 | 
			
		||||
       inkscape:vp_x="0 : 16 : 1"
 | 
			
		||||
       inkscape:vp_y="0 : 1000 : 0"
 | 
			
		||||
       inkscape:vp_z="32 : 16 : 1"
 | 
			
		||||
       inkscape:persp3d-origin="16 : 10.666667 : 1"
 | 
			
		||||
       id="perspective6511" />
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       id="perspective6494"
 | 
			
		||||
       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" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#ffffff"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="0.0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="11.197802"
 | 
			
		||||
     inkscape:cx="-15.97056"
 | 
			
		||||
     inkscape:cy="16"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="true"
 | 
			
		||||
     inkscape:grid-bbox="true"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:window-width="1680"
 | 
			
		||||
     inkscape:window-height="997"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="26"
 | 
			
		||||
     inkscape:window-maximized="1" />
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata6508">
 | 
			
		||||
    <rdf:RDF>
 | 
			
		||||
      <cc:Work
 | 
			
		||||
         rdf:about="">
 | 
			
		||||
        <dc:format>image/svg+xml</dc:format>
 | 
			
		||||
        <dc:type
 | 
			
		||||
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
 | 
			
		||||
        <dc:title />
 | 
			
		||||
      </cc:Work>
 | 
			
		||||
    </rdf:RDF>
 | 
			
		||||
  </metadata>
 | 
			
		||||
  <g
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     inkscape:label="Layer 1"
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     transform="translate(0,-16)">
 | 
			
		||||
    <g
 | 
			
		||||
       style="display:inline;fill:#cbcbcb;fill-opacity:1"
 | 
			
		||||
       transform="translate(-449.85476,-685.85869)"
 | 
			
		||||
       id="g5306">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none"
 | 
			
		||||
         id="rect5308"
 | 
			
		||||
         width="11"
 | 
			
		||||
         height="7"
 | 
			
		||||
         x="450.5"
 | 
			
		||||
         y="710.5"
 | 
			
		||||
         rx="0.99999958"
 | 
			
		||||
         ry="1" />
 | 
			
		||||
      <rect
 | 
			
		||||
         style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline"
 | 
			
		||||
         id="rect5310"
 | 
			
		||||
         width="11"
 | 
			
		||||
         height="7"
 | 
			
		||||
         x="462.5"
 | 
			
		||||
         y="702.5"
 | 
			
		||||
         rx="0.99999958"
 | 
			
		||||
         ry="1" />
 | 
			
		||||
      <rect
 | 
			
		||||
         style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999976000000002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline"
 | 
			
		||||
         id="rect5312"
 | 
			
		||||
         width="11"
 | 
			
		||||
         height="7"
 | 
			
		||||
         x="450.5"
 | 
			
		||||
         y="702.5"
 | 
			
		||||
         rx="0.99999958"
 | 
			
		||||
         ry="1" />
 | 
			
		||||
      <rect
 | 
			
		||||
         style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline"
 | 
			
		||||
         id="rect5314"
 | 
			
		||||
         width="11"
 | 
			
		||||
         height="7"
 | 
			
		||||
         x="462.5"
 | 
			
		||||
         y="710.5"
 | 
			
		||||
         rx="0.99999958"
 | 
			
		||||
         ry="1" />
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 3.7 KiB  | 
@@ -1,113 +0,0 @@
 | 
			
		||||
<?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="24"
 | 
			
		||||
   height="16"
 | 
			
		||||
   id="svg6503"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.47pre4 r22446"
 | 
			
		||||
   sodipodi:docname="New document 19">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs6505">
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       sodipodi:type="inkscape:persp3d"
 | 
			
		||||
       inkscape:vp_x="0 : 16 : 1"
 | 
			
		||||
       inkscape:vp_y="0 : 1000 : 0"
 | 
			
		||||
       inkscape:vp_z="32 : 16 : 1"
 | 
			
		||||
       inkscape:persp3d-origin="16 : 10.666667 : 1"
 | 
			
		||||
       id="perspective6511" />
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       id="perspective6494"
 | 
			
		||||
       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" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#ffffff"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="0.0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="11.197802"
 | 
			
		||||
     inkscape:cx="16"
 | 
			
		||||
     inkscape:cy="16"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="true"
 | 
			
		||||
     inkscape:grid-bbox="true"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:window-width="1680"
 | 
			
		||||
     inkscape:window-height="997"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="26"
 | 
			
		||||
     inkscape:window-maximized="1" />
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata6508">
 | 
			
		||||
    <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
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     inkscape:label="Layer 1"
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     transform="translate(0,-16)">
 | 
			
		||||
    <g
 | 
			
		||||
       style="display:inline"
 | 
			
		||||
       transform="translate(-449.85476,-685.85869)"
 | 
			
		||||
       id="g5306">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none"
 | 
			
		||||
         id="rect5308"
 | 
			
		||||
         width="11"
 | 
			
		||||
         height="7"
 | 
			
		||||
         x="450.5"
 | 
			
		||||
         y="710.5"
 | 
			
		||||
         rx="0.99999958"
 | 
			
		||||
         ry="1" />
 | 
			
		||||
      <rect
 | 
			
		||||
         style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline"
 | 
			
		||||
         id="rect5310"
 | 
			
		||||
         width="11"
 | 
			
		||||
         height="7"
 | 
			
		||||
         x="462.5"
 | 
			
		||||
         y="702.5"
 | 
			
		||||
         rx="0.99999958"
 | 
			
		||||
         ry="1" />
 | 
			
		||||
      <rect
 | 
			
		||||
         style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline"
 | 
			
		||||
         id="rect5312"
 | 
			
		||||
         width="11"
 | 
			
		||||
         height="7"
 | 
			
		||||
         x="450.5"
 | 
			
		||||
         y="702.5"
 | 
			
		||||
         rx="0.99999958"
 | 
			
		||||
         ry="1" />
 | 
			
		||||
      <rect
 | 
			
		||||
         style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline"
 | 
			
		||||
         id="rect5314"
 | 
			
		||||
         width="11"
 | 
			
		||||
         height="7"
 | 
			
		||||
         x="462.5"
 | 
			
		||||
         y="710.5"
 | 
			
		||||
         rx="0.99999958"
 | 
			
		||||
         ry="1" />
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 3.6 KiB  | 
@@ -1,89 +0,0 @@
 | 
			
		||||
<?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="98"
 | 
			
		||||
   height="98"
 | 
			
		||||
   id="svg6375"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.47 r22583"
 | 
			
		||||
   sodipodi:docname="add-workspace.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs6377">
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       sodipodi:type="inkscape:persp3d"
 | 
			
		||||
       inkscape:vp_x="0 : 16 : 1"
 | 
			
		||||
       inkscape:vp_y="0 : 1000 : 0"
 | 
			
		||||
       inkscape:vp_z="32 : 16 : 1"
 | 
			
		||||
       inkscape:persp3d-origin="16 : 10.666667 : 1"
 | 
			
		||||
       id="perspective6383" />
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       id="perspective6366"
 | 
			
		||||
       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" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#ffffff"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="0.0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="3.9590209"
 | 
			
		||||
     inkscape:cx="56.650687"
 | 
			
		||||
     inkscape:cy="20.635343"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="true"
 | 
			
		||||
     inkscape:grid-bbox="true"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:window-width="1680"
 | 
			
		||||
     inkscape:window-height="997"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="26"
 | 
			
		||||
     inkscape:window-maximized="1" />
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata6380">
 | 
			
		||||
    <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
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     inkscape:label="Layer 1"
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     transform="translate(0,66)">
 | 
			
		||||
    <g
 | 
			
		||||
       id="g2824"
 | 
			
		||||
       transform="matrix(11.568551,0,0,11.698271,-78.828159,-304.81518)">
 | 
			
		||||
      <path
 | 
			
		||||
         style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
 | 
			
		||||
         d="m 11.07363,21.36834 0,6.43903"
 | 
			
		||||
         id="path5322" />
 | 
			
		||||
      <path
 | 
			
		||||
         style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
 | 
			
		||||
         d="m 14.29314,24.58786 -6.43902,0"
 | 
			
		||||
         id="path5324" />
 | 
			
		||||
    </g>
 | 
			
		||||
    <path
 | 
			
		||||
       style="fill:#000000;fill-opacity:0.98823529"
 | 
			
		||||
       d="m 48.239516,97.908047 c -0.41677,-0.05102 -1.269253,-0.222408 -1.894408,-0.380859 -4.088493,-1.036262 -7.520781,-4.753234 -8.330163,-9.021094 -0.154947,-0.817026 -0.257819,-6.68112 -0.257819,-14.696556 l 0,-13.337088 -13.829177,-0.08909 C 10.802042,60.298796 10.026884,60.268266 8.6851548,59.783022 3.6288503,57.954375 0.62673331,53.828648 0.62673331,48.708554 c 0,-5.625522 4.25936019,-10.425065 9.97721469,-11.242548 0.987903,-0.141242 7.368912,-0.254994 14.460646,-0.257791 l 12.692532,-0.005 0,-13.586668 c 0,-14.6441583 0.03287,-15.0698926 1.364686,-17.6753047 2.185477,-4.2754229 6.938193,-6.75739913 11.687647,-6.10355607 3.382776,0.46569661 6.737962,2.72496967 8.414081,5.66577137 1.480816,2.5981315 1.519067,3.0522448 1.519067,18.0333334 l 0,13.666424 12.692533,0.005 c 7.091733,0.0028 13.472742,0.116549 14.460646,0.257791 6.395303,0.914337 10.804785,6.623716 9.941157,12.871766 -0.698243,5.051565 -4.792685,9.104635 -9.941157,9.840713 -0.987904,0.141242 -7.368913,0.254995 -14.460646,0.257791 l -12.692533,0.005 0,13.801945 c 0,13.031417 -0.02798,13.895893 -0.501177,15.484801 -1.526902,5.127058 -6.919246,8.802262 -12.001914,8.18002 z"
 | 
			
		||||
       id="path2828"
 | 
			
		||||
       transform="translate(0,-66)" />
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 4.0 KiB  | 
							
								
								
									
										33
									
								
								data/theme/panel-border.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,33 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
 | 
			
		||||
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   width="3"
 | 
			
		||||
   height="10"
 | 
			
		||||
   id="svg2"
 | 
			
		||||
   version="1.1">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs4" />
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata7">
 | 
			
		||||
  </metadata>
 | 
			
		||||
  <g
 | 
			
		||||
     id="layer1">
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#000000;fill-opacity:1;stroke-width:0.43599999000000000;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
       id="rect3779"
 | 
			
		||||
       width="3"
 | 
			
		||||
       height="10"
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="0" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#536272;fill-opacity:1;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
       id="rect3796"
 | 
			
		||||
       width="3"
 | 
			
		||||
       height="1"
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="9" />
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 787 B  | 
| 
		 Before Width: | Height: | Size: 4.0 KiB  | 
							
								
								
									
										261
									
								
								data/theme/process-working.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,261 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
 | 
			
		||||
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:xlink="http://www.w3.org/1999/xlink"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   id="svg5369"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.48+devel r10053 custom"
 | 
			
		||||
   width="96"
 | 
			
		||||
   height="48"
 | 
			
		||||
   sodipodi:docname="process-working.svg"
 | 
			
		||||
   style="display:inline">
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata5375">
 | 
			
		||||
    <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>
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs5373" />
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     pagecolor="#808080"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1"
 | 
			
		||||
     objecttolerance="10"
 | 
			
		||||
     gridtolerance="10"
 | 
			
		||||
     guidetolerance="10"
 | 
			
		||||
     inkscape:pageopacity="0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:window-width="1975"
 | 
			
		||||
     inkscape:window-height="1098"
 | 
			
		||||
     id="namedview5371"
 | 
			
		||||
     showgrid="true"
 | 
			
		||||
     borderlayer="true"
 | 
			
		||||
     inkscape:showpageshadow="false"
 | 
			
		||||
     inkscape:zoom="16"
 | 
			
		||||
     inkscape:cx="53.997662"
 | 
			
		||||
     inkscape:cy="22.367695"
 | 
			
		||||
     inkscape:window-x="1600"
 | 
			
		||||
     inkscape:window-y="33"
 | 
			
		||||
     inkscape:window-maximized="0"
 | 
			
		||||
     inkscape:current-layer="layer2">
 | 
			
		||||
    <inkscape:grid
 | 
			
		||||
       type="xygrid"
 | 
			
		||||
       id="grid11933"
 | 
			
		||||
       empspacing="5"
 | 
			
		||||
       visible="true"
 | 
			
		||||
       enabled="true"
 | 
			
		||||
       snapvisiblegridlinesonly="true" />
 | 
			
		||||
  </sodipodi:namedview>
 | 
			
		||||
  <g
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     inkscape:label="tiles"
 | 
			
		||||
     style="display:none">
 | 
			
		||||
    <rect
 | 
			
		||||
       style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
       id="rect12451"
 | 
			
		||||
       width="24"
 | 
			
		||||
       height="24"
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="0" />
 | 
			
		||||
    <rect
 | 
			
		||||
       y="24"
 | 
			
		||||
       x="0"
 | 
			
		||||
       height="24"
 | 
			
		||||
       width="24"
 | 
			
		||||
       id="rect12453"
 | 
			
		||||
       style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
 | 
			
		||||
    <rect
 | 
			
		||||
       y="0"
 | 
			
		||||
       x="24"
 | 
			
		||||
       height="24"
 | 
			
		||||
       width="24"
 | 
			
		||||
       id="rect12455"
 | 
			
		||||
       style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
       id="rect12457"
 | 
			
		||||
       width="24"
 | 
			
		||||
       height="24"
 | 
			
		||||
       x="24"
 | 
			
		||||
       y="24" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
       id="rect12459"
 | 
			
		||||
       width="24"
 | 
			
		||||
       height="24"
 | 
			
		||||
       x="48"
 | 
			
		||||
       y="0" />
 | 
			
		||||
    <rect
 | 
			
		||||
       y="24"
 | 
			
		||||
       x="48"
 | 
			
		||||
       height="24"
 | 
			
		||||
       width="24"
 | 
			
		||||
       id="rect12461"
 | 
			
		||||
       style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
 | 
			
		||||
    <rect
 | 
			
		||||
       y="0"
 | 
			
		||||
       x="72"
 | 
			
		||||
       height="24"
 | 
			
		||||
       width="24"
 | 
			
		||||
       id="rect12463"
 | 
			
		||||
       style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
       id="rect12465"
 | 
			
		||||
       width="24"
 | 
			
		||||
       height="24"
 | 
			
		||||
       x="72"
 | 
			
		||||
       y="24" />
 | 
			
		||||
  </g>
 | 
			
		||||
  <g
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     id="layer2"
 | 
			
		||||
     inkscape:label="spinner">
 | 
			
		||||
    <g
 | 
			
		||||
       transform="matrix(0.28240106,0,0,0.28240106,146.92015,-382.52444)"
 | 
			
		||||
       id="g10450-5"
 | 
			
		||||
       style="display:inline">
 | 
			
		||||
      <path
 | 
			
		||||
         inkscape:connector-curvature="0"
 | 
			
		||||
         style="opacity:0.6;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
         d="m -477.76072,1373.3569 0,9.4717"
 | 
			
		||||
         id="path18768"
 | 
			
		||||
         sodipodi:nodetypes="cc"
 | 
			
		||||
         inkscape:transform-center-y="-4.6808838" />
 | 
			
		||||
      <path
 | 
			
		||||
         inkscape:connector-curvature="0"
 | 
			
		||||
         inkscape:transform-center-y="-3.3099227"
 | 
			
		||||
         sodipodi:nodetypes="cc"
 | 
			
		||||
         id="path18770"
 | 
			
		||||
         d="m -461.0171,1380.2922 -7.23427,7.3824"
 | 
			
		||||
         style="opacity:0.7;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
         inkscape:transform-center-x="-3.3098966" />
 | 
			
		||||
      <path
 | 
			
		||||
         inkscape:connector-curvature="0"
 | 
			
		||||
         inkscape:transform-center-x="-4.6808962"
 | 
			
		||||
         style="opacity:0.8;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
         d="m -454.08163,1397.0359 -9.47165,0"
 | 
			
		||||
         id="path18772"
 | 
			
		||||
         sodipodi:nodetypes="cc"
 | 
			
		||||
         inkscape:transform-center-y="-2.6596956e-05" />
 | 
			
		||||
      <path
 | 
			
		||||
         inkscape:connector-curvature="0"
 | 
			
		||||
         sodipodi:nodetypes="cc"
 | 
			
		||||
         id="path18774"
 | 
			
		||||
         d="m -461.01709,1413.7796 -6.93831,-7.0864"
 | 
			
		||||
         style="opacity:0.9;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
         inkscape:transform-center-x="-3.3098966"
 | 
			
		||||
         inkscape:transform-center-y="3.3098652" />
 | 
			
		||||
      <path
 | 
			
		||||
         inkscape:connector-curvature="0"
 | 
			
		||||
         inkscape:transform-center-y="4.6808757"
 | 
			
		||||
         style="color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
         d="m -477.76074,1420.715 9e-5,-9.4716"
 | 
			
		||||
         id="path18776"
 | 
			
		||||
         sodipodi:nodetypes="cc" />
 | 
			
		||||
      <path
 | 
			
		||||
         inkscape:connector-curvature="0"
 | 
			
		||||
         sodipodi:nodetypes="cc"
 | 
			
		||||
         id="path18778"
 | 
			
		||||
         d="m -494.50442,1413.7796 6.79048,-6.9384"
 | 
			
		||||
         style="opacity:0.3;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
         inkscape:transform-center-y="3.3098769"
 | 
			
		||||
         inkscape:transform-center-x="3.3098883" />
 | 
			
		||||
      <path
 | 
			
		||||
         inkscape:connector-curvature="0"
 | 
			
		||||
         inkscape:transform-center-x="4.6808941"
 | 
			
		||||
         style="opacity:0.4;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
         d="m -501.43987,1397.0359 9.47174,0"
 | 
			
		||||
         id="path18780"
 | 
			
		||||
         sodipodi:nodetypes="cc"
 | 
			
		||||
         inkscape:transform-center-y="-2.6596956e-05" />
 | 
			
		||||
      <path
 | 
			
		||||
         inkscape:connector-curvature="0"
 | 
			
		||||
         sodipodi:nodetypes="cc"
 | 
			
		||||
         id="path18782"
 | 
			
		||||
         d="m -494.5044,1380.2922 6.64243,6.9384"
 | 
			
		||||
         style="opacity:0.5;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
         inkscape:transform-center-x="3.3098902"
 | 
			
		||||
         inkscape:transform-center-y="-3.3099302" />
 | 
			
		||||
    </g>
 | 
			
		||||
    <use
 | 
			
		||||
       style="display:inline"
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="0"
 | 
			
		||||
       xlink:href="#g10450-5"
 | 
			
		||||
       id="use4981"
 | 
			
		||||
       transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,36,-4.9705636)"
 | 
			
		||||
       width="400"
 | 
			
		||||
       height="400" />
 | 
			
		||||
    <use
 | 
			
		||||
       style="display:inline"
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="0"
 | 
			
		||||
       xlink:href="#use4981"
 | 
			
		||||
       id="use4983"
 | 
			
		||||
       transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,43.032478,-21.909695)"
 | 
			
		||||
       width="400"
 | 
			
		||||
       height="400" />
 | 
			
		||||
    <use
 | 
			
		||||
       style="display:inline"
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="0"
 | 
			
		||||
       xlink:href="#use4983"
 | 
			
		||||
       id="use4985"
 | 
			
		||||
       transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,50.081986,-38.904617)"
 | 
			
		||||
       width="400"
 | 
			
		||||
       height="400" />
 | 
			
		||||
    <use
 | 
			
		||||
       style="display:inline"
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="0"
 | 
			
		||||
       xlink:href="#use4985"
 | 
			
		||||
       id="use4987"
 | 
			
		||||
       transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,-38.919996,-31.872139)"
 | 
			
		||||
       width="400"
 | 
			
		||||
       height="400" />
 | 
			
		||||
    <use
 | 
			
		||||
       style="display:inline"
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="0"
 | 
			
		||||
       xlink:href="#use4987"
 | 
			
		||||
       id="use4989"
 | 
			
		||||
       transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,52.986628,2.0890543)"
 | 
			
		||||
       width="400"
 | 
			
		||||
       height="400" />
 | 
			
		||||
    <use
 | 
			
		||||
       style="display:inline"
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="0"
 | 
			
		||||
       xlink:href="#use4989"
 | 
			
		||||
       id="use4991"
 | 
			
		||||
       transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,60.013026,-14.912936)"
 | 
			
		||||
       width="400"
 | 
			
		||||
       height="400" />
 | 
			
		||||
    <use
 | 
			
		||||
       style="display:inline"
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="0"
 | 
			
		||||
       xlink:href="#use4991"
 | 
			
		||||
       id="use4993"
 | 
			
		||||
       transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,67.022396,-31.859127)"
 | 
			
		||||
       width="400"
 | 
			
		||||
       height="400" />
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 9.8 KiB  | 
@@ -2,24 +2,62 @@
 | 
			
		||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
 | 
			
		||||
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:xlink="http://www.w3.org/1999/xlink"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   width="119.97824"
 | 
			
		||||
   height="119.97824"
 | 
			
		||||
   id="svg7355"
 | 
			
		||||
   version="1.1">
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.48.1 r9760"
 | 
			
		||||
   sodipodi:docname="running-indicator.svg">
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata4175">
 | 
			
		||||
    <rdf:RDF>
 | 
			
		||||
      <cc:Work
 | 
			
		||||
         rdf:about="">
 | 
			
		||||
        <dc:format>image/svg+xml</dc:format>
 | 
			
		||||
        <dc:type
 | 
			
		||||
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
 | 
			
		||||
      </cc:Work>
 | 
			
		||||
    </rdf:RDF>
 | 
			
		||||
  </metadata>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     pagecolor="#2c1cff"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1"
 | 
			
		||||
     objecttolerance="10"
 | 
			
		||||
     gridtolerance="10"
 | 
			
		||||
     guidetolerance="10"
 | 
			
		||||
     inkscape:pageopacity="1"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:window-width="1920"
 | 
			
		||||
     inkscape:window-height="1141"
 | 
			
		||||
     id="namedview4173"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:zoom="8.1348081"
 | 
			
		||||
     inkscape:cx="81.120662"
 | 
			
		||||
     inkscape:cy="58.117986"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="26"
 | 
			
		||||
     inkscape:window-maximized="1"
 | 
			
		||||
     inkscape:current-layer="g30864" />
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs7357">
 | 
			
		||||
    <radialGradient
 | 
			
		||||
       xlink:href="#linearGradient36429"
 | 
			
		||||
       id="radialGradient7461"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       gradientTransform="matrix(1.0525552,0,0,1.0525552,-2.5162753,-9.0000838)"
 | 
			
		||||
       cx="47.878681"
 | 
			
		||||
       cy="171.25"
 | 
			
		||||
       fx="47.878681"
 | 
			
		||||
       fy="171.25"
 | 
			
		||||
       gradientTransform="matrix(1.011539,0,0,0.57582113,-0.39262194,71.83807)"
 | 
			
		||||
       cx="47.428951"
 | 
			
		||||
       cy="167.16817"
 | 
			
		||||
       fx="47.428951"
 | 
			
		||||
       fy="167.16817"
 | 
			
		||||
       r="37" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       id="linearGradient36429">
 | 
			
		||||
@@ -59,7 +97,7 @@
 | 
			
		||||
       fx="49.067139"
 | 
			
		||||
       cy="242.50381"
 | 
			
		||||
       cx="49.067139"
 | 
			
		||||
       gradientTransform="matrix(1.1891549,0,0,0.55513246,-9.281289,36.12653)"
 | 
			
		||||
       gradientTransform="matrix(1.1891549,0,0,0.15252127,-9.281289,132.52772)"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       id="radialGradient7488"
 | 
			
		||||
       xlink:href="#linearGradient36471" />
 | 
			
		||||
@@ -72,19 +110,21 @@
 | 
			
		||||
       id="g30864"
 | 
			
		||||
       transform="translate(255.223,70.118091)">
 | 
			
		||||
      <rect
 | 
			
		||||
         ry="3.5996203"
 | 
			
		||||
         rx="3.5996203"
 | 
			
		||||
         y="98"
 | 
			
		||||
         x="11"
 | 
			
		||||
         height="74"
 | 
			
		||||
         width="74"
 | 
			
		||||
         ry="3.4593496"
 | 
			
		||||
         rx="3.4593496"
 | 
			
		||||
         y="99.596962"
 | 
			
		||||
         x="12.596948"
 | 
			
		||||
         height="71.116341"
 | 
			
		||||
         width="71.116341"
 | 
			
		||||
         id="rect14000"
 | 
			
		||||
         style="opacity:0.371875;fill:url(#radialGradient7461);fill-opacity:1;stroke:none" />
 | 
			
		||||
         style="opacity:0.37187500000000001;fill:url(#radialGradient7461);fill-opacity:1;stroke:none" />
 | 
			
		||||
      <path
 | 
			
		||||
         id="rect34520"
 | 
			
		||||
         d="m 84.506708,167.95508 c 6e-6,1.96759 -1.584022,3.55162 -3.551629,3.55163 l -65.910146,0 c -1.967608,-1e-5 -3.551648,-1.58402 -3.551643,-3.55164"
 | 
			
		||||
         style="opacity:0.2;fill:none;stroke:url(#radialGradient7488);stroke-width:1;stroke-opacity:1"
 | 
			
		||||
         inkscape:connector-curvature="0" />
 | 
			
		||||
         d="m 83.273151,166.72152 c 0,1.96759 -1.584022,3.55163 -3.551629,3.55163 l -63.443032,0 c -1.967608,0 -3.551648,-1.58402 -3.551643,-3.55164 0,-5.85318 0,-5.85318 0,0"
 | 
			
		||||
         style="opacity:0.35;fill:none;stroke:url(#radialGradient7488);stroke-width:1;stroke-opacity:1"
 | 
			
		||||
         connector-curvature="0"
 | 
			
		||||
         inkscape:connector-curvature="0"
 | 
			
		||||
         sodipodi:nodetypes="ccscc" />
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
 
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 3.9 KiB  | 
| 
		 Before Width: | Height: | Size: 225 B  | 
| 
		 Before Width: | Height: | Size: 225 B  | 
| 
		 Before Width: | Height: | Size: 211 B  | 
| 
		 Before Width: | Height: | Size: 211 B  | 
@@ -1,87 +0,0 @@
 | 
			
		||||
<?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="5.8600588"
 | 
			
		||||
   height="9"
 | 
			
		||||
   id="svg3647"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.47 r22583"
 | 
			
		||||
   sodipodi:docname="section-more.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs3649">
 | 
			
		||||
    <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="perspective3655" />
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       id="perspective3603"
 | 
			
		||||
       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" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#ffffff"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="0.0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="82.777778"
 | 
			
		||||
     inkscape:cx="2.9300294"
 | 
			
		||||
     inkscape:cy="5.466443"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:window-width="1680"
 | 
			
		||||
     inkscape:window-height="997"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="26"
 | 
			
		||||
     inkscape:window-maximized="1" />
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata3652">
 | 
			
		||||
    <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(-262.78425,-490.71933)">
 | 
			
		||||
    <path
 | 
			
		||||
       transform="matrix(0,-0.98149546,0.71467449,0,25.404986,578.15569)"
 | 
			
		||||
       d="M 88.830127,340 80.169873,340 84.5,332.5 88.830127,340 z"
 | 
			
		||||
       inkscape:randomized="0"
 | 
			
		||||
       inkscape:rounded="0"
 | 
			
		||||
       inkscape:flatsided="true"
 | 
			
		||||
       sodipodi:arg2="1.5707963"
 | 
			
		||||
       sodipodi:arg1="0.52359878"
 | 
			
		||||
       sodipodi:r2="2.5"
 | 
			
		||||
       sodipodi:r1="5"
 | 
			
		||||
       sodipodi:cy="337.5"
 | 
			
		||||
       sodipodi:cx="84.5"
 | 
			
		||||
       sodipodi:sides="3"
 | 
			
		||||
       id="path5497-5"
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.59699643;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
 | 
			
		||||
       sodipodi:type="star" />
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 2.8 KiB  | 
@@ -1,87 +0,0 @@
 | 
			
		||||
<?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="5.8600588"
 | 
			
		||||
   height="9"
 | 
			
		||||
   id="svg3647"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.46+devel"
 | 
			
		||||
   sodipodi:docname="New document 6">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs3649">
 | 
			
		||||
    <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="perspective3655" />
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       id="perspective3603"
 | 
			
		||||
       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" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#ffffff"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="0.0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="0.35"
 | 
			
		||||
     inkscape:cx="112.21575"
 | 
			
		||||
     inkscape:cy="-32.642856"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:window-width="609"
 | 
			
		||||
     inkscape:window-height="501"
 | 
			
		||||
     inkscape:window-x="164"
 | 
			
		||||
     inkscape:window-y="26"
 | 
			
		||||
     inkscape:window-maximized="0" />
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata3652">
 | 
			
		||||
    <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(-262.78425,-490.71933)">
 | 
			
		||||
    <path
 | 
			
		||||
       transform="matrix(0,0.98149546,-0.71467449,0,506.02358,412.28296)"
 | 
			
		||||
       d="M 88.830127,340 80.169873,340 84.5,332.5 88.830127,340 z"
 | 
			
		||||
       inkscape:randomized="0"
 | 
			
		||||
       inkscape:rounded="0"
 | 
			
		||||
       inkscape:flatsided="true"
 | 
			
		||||
       sodipodi:arg2="1.5707963"
 | 
			
		||||
       sodipodi:arg1="0.52359878"
 | 
			
		||||
       sodipodi:r2="2.5"
 | 
			
		||||
       sodipodi:r1="5"
 | 
			
		||||
       sodipodi:cy="337.5"
 | 
			
		||||
       sodipodi:cx="84.5"
 | 
			
		||||
       sodipodi:sides="3"
 | 
			
		||||
       id="path5497-5"
 | 
			
		||||
       style="fill:#5f5f5f;fill-opacity:1;stroke:#5f5f5f;stroke-width:0.59699643;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
 | 
			
		||||
       sodipodi:type="star" />
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 2.8 KiB  | 
| 
		 Before Width: | Height: | Size: 531 B  | 
@@ -1,81 +0,0 @@
 | 
			
		||||
<?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="24"
 | 
			
		||||
   height="16"
 | 
			
		||||
   id="svg6446"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.47pre4 r22446"
 | 
			
		||||
   sodipodi:docname="single-view.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs6448">
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       sodipodi:type="inkscape:persp3d"
 | 
			
		||||
       inkscape:vp_x="0 : 16 : 1"
 | 
			
		||||
       inkscape:vp_y="0 : 1000 : 0"
 | 
			
		||||
       inkscape:vp_z="32 : 16 : 1"
 | 
			
		||||
       inkscape:persp3d-origin="16 : 10.666667 : 1"
 | 
			
		||||
       id="perspective6454" />
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       id="perspective6441"
 | 
			
		||||
       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" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#ffffff"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="0.0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="11.197802"
 | 
			
		||||
     inkscape:cx="0.014720032"
 | 
			
		||||
     inkscape:cy="16"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="true"
 | 
			
		||||
     inkscape:grid-bbox="true"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:window-width="1680"
 | 
			
		||||
     inkscape:window-height="997"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="26"
 | 
			
		||||
     inkscape:window-maximized="1" />
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata6451">
 | 
			
		||||
    <rdf:RDF>
 | 
			
		||||
      <cc:Work
 | 
			
		||||
         rdf:about="">
 | 
			
		||||
        <dc:format>image/svg+xml</dc:format>
 | 
			
		||||
        <dc:type
 | 
			
		||||
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
 | 
			
		||||
        <dc:title />
 | 
			
		||||
      </cc:Work>
 | 
			
		||||
    </rdf:RDF>
 | 
			
		||||
  </metadata>
 | 
			
		||||
  <g
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     inkscape:label="Layer 1"
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     transform="translate(0,-17)">
 | 
			
		||||
    <rect
 | 
			
		||||
       ry="0.5"
 | 
			
		||||
       rx="0.49999979"
 | 
			
		||||
       y="17.483809"
 | 
			
		||||
       x="0.53483802"
 | 
			
		||||
       height="15"
 | 
			
		||||
       width="23"
 | 
			
		||||
       id="rect5304"
 | 
			
		||||
       style="fill:#626262;fill-opacity:1;stroke:#cccccc;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 2.4 KiB  | 
							
								
								
									
										74
									
								
								data/theme/source-button-border.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,74 @@
 | 
			
		||||
<?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="21"
 | 
			
		||||
   height="10"
 | 
			
		||||
   id="svg2"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.48.0 r9654"
 | 
			
		||||
   sodipodi:docname="source-button-border.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs4" />
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#000000"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="44.8"
 | 
			
		||||
     inkscape:cx="8.704132"
 | 
			
		||||
     inkscape:cy="5.7029946"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="true"
 | 
			
		||||
     showguides="true"
 | 
			
		||||
     inkscape:guide-bbox="true"
 | 
			
		||||
     inkscape:window-width="1600"
 | 
			
		||||
     inkscape:window-height="1145"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="26"
 | 
			
		||||
     inkscape:window-maximized="1"
 | 
			
		||||
     guidetolerance="10000"
 | 
			
		||||
     objecttolerance="10000">
 | 
			
		||||
    <inkscape:grid
 | 
			
		||||
       type="xygrid"
 | 
			
		||||
       id="grid3792"
 | 
			
		||||
       empspacing="10"
 | 
			
		||||
       visible="true"
 | 
			
		||||
       enabled="true"
 | 
			
		||||
       snapvisiblegridlinesonly="true" />
 | 
			
		||||
  </sodipodi:namedview>
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata7">
 | 
			
		||||
    <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">
 | 
			
		||||
    <rect
 | 
			
		||||
       style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
       id="rect3796"
 | 
			
		||||
       width="19"
 | 
			
		||||
       height="2"
 | 
			
		||||
       x="1"
 | 
			
		||||
       y="8" />
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 2.0 KiB  | 
@@ -13,8 +13,8 @@
 | 
			
		||||
   height="22"
 | 
			
		||||
   id="svg3199"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.47 r22583"
 | 
			
		||||
   sodipodi:docname="New document 11">
 | 
			
		||||
   inkscape:version="0.48.1 r9760"
 | 
			
		||||
   sodipodi:docname="toggle-on-intl.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs3201">
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
@@ -39,14 +39,14 @@
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="0.0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="0.35"
 | 
			
		||||
     inkscape:cx="32.500004"
 | 
			
		||||
     inkscape:cy="10.999997"
 | 
			
		||||
     inkscape:zoom="1"
 | 
			
		||||
     inkscape:cx="49.147112"
 | 
			
		||||
     inkscape:cy="17.532036"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:window-width="609"
 | 
			
		||||
     inkscape:window-height="501"
 | 
			
		||||
     inkscape:window-width="1412"
 | 
			
		||||
     inkscape:window-height="1067"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="26"
 | 
			
		||||
     inkscape:window-maximized="0" />
 | 
			
		||||
@@ -58,7 +58,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>
 | 
			
		||||
@@ -72,7 +72,7 @@
 | 
			
		||||
       transform="translate(-453.5,448.36218)"
 | 
			
		||||
       id="g16453">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="color:#000000;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994;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:#4a90d9;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994000000003;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"
 | 
			
		||||
         id="rect16256-9-4"
 | 
			
		||||
         width="63.000004"
 | 
			
		||||
         height="19"
 | 
			
		||||
 
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB  | 
@@ -13,8 +13,8 @@
 | 
			
		||||
   height="22"
 | 
			
		||||
   id="svg2857"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.47 r22583"
 | 
			
		||||
   sodipodi:docname="New document 2">
 | 
			
		||||
   inkscape:version="0.48.1 r9760"
 | 
			
		||||
   sodipodi:docname="toggle-on-us.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs2859">
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
@@ -40,16 +40,18 @@
 | 
			
		||||
     inkscape:pageopacity="0.0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="1"
 | 
			
		||||
     inkscape:cx="-69.642856"
 | 
			
		||||
     inkscape:cy="42.428569"
 | 
			
		||||
     inkscape:cx="19.689855"
 | 
			
		||||
     inkscape:cy="2.0517979"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:window-width="609"
 | 
			
		||||
     inkscape:window-height="501"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="26"
 | 
			
		||||
     inkscape:window-maximized="0" />
 | 
			
		||||
     inkscape:window-width="941"
 | 
			
		||||
     inkscape:window-height="751"
 | 
			
		||||
     inkscape:window-x="2577"
 | 
			
		||||
     inkscape:window-y="206"
 | 
			
		||||
     inkscape:window-maximized="0"
 | 
			
		||||
     borderlayer="true"
 | 
			
		||||
     inkscape:showpageshadow="false" />
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata2862">
 | 
			
		||||
    <rdf:RDF>
 | 
			
		||||
@@ -58,7 +60,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>
 | 
			
		||||
@@ -72,7 +74,7 @@
 | 
			
		||||
       transform="translate(-351.35714,708.36218)"
 | 
			
		||||
       id="g16453">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="color:#000000;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994;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:#4a90d9;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994000000003;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"
 | 
			
		||||
         id="rect16256-9-4"
 | 
			
		||||
         width="63.000004"
 | 
			
		||||
         height="19"
 | 
			
		||||
 
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.8 KiB  | 
							
								
								
									
										1
									
								
								docs/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
SUBDIRS = reference
 | 
			
		||||
							
								
								
									
										1
									
								
								docs/reference/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
SUBDIRS = shell st
 | 
			
		||||
							
								
								
									
										105
									
								
								docs/reference/shell/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,105 @@
 | 
			
		||||
## Process this file with automake to produce Makefile.in
 | 
			
		||||
 | 
			
		||||
# We require automake 1.6 at least.
 | 
			
		||||
AUTOMAKE_OPTIONS = 1.6
 | 
			
		||||
 | 
			
		||||
# This is a blank Makefile.am for using gtk-doc.
 | 
			
		||||
# Copy this to your project's API docs directory and modify the variables to
 | 
			
		||||
# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
 | 
			
		||||
# of using the various options.
 | 
			
		||||
 | 
			
		||||
# The name of the module, e.g. 'glib'.
 | 
			
		||||
DOC_MODULE=shell
 | 
			
		||||
 | 
			
		||||
# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
 | 
			
		||||
#DOC_MODULE_VERSION=2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# The top-level SGML file. You can change this if you want to.
 | 
			
		||||
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
 | 
			
		||||
 | 
			
		||||
# Directories containing the source code, relative to $(srcdir).
 | 
			
		||||
# gtk-doc will search all .c and .h files beneath these paths
 | 
			
		||||
# for inline comments documenting functions and macros.
 | 
			
		||||
# e.g. DOC_SOURCE_DIR=../../../gtk ../../../gdk
 | 
			
		||||
DOC_SOURCE_DIR=../../../src
 | 
			
		||||
 | 
			
		||||
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
 | 
			
		||||
SCANGOBJ_OPTIONS=
 | 
			
		||||
 | 
			
		||||
# Extra options to supply to gtkdoc-scan.
 | 
			
		||||
# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
 | 
			
		||||
SCAN_OPTIONS=--rebuild-types
 | 
			
		||||
 | 
			
		||||
# Extra options to supply to gtkdoc-mkdb.
 | 
			
		||||
# e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
 | 
			
		||||
MKDB_OPTIONS=--xml-mode --output-format=xml
 | 
			
		||||
 | 
			
		||||
# Extra options to supply to gtkdoc-mktmpl
 | 
			
		||||
# e.g. MKTMPL_OPTIONS=--only-section-tmpl
 | 
			
		||||
MKTMPL_OPTIONS=
 | 
			
		||||
 | 
			
		||||
# Extra options to supply to gtkdoc-mkhtml
 | 
			
		||||
MKHTML_OPTIONS=
 | 
			
		||||
 | 
			
		||||
# Extra options to supply to gtkdoc-fixref. Not normally needed.
 | 
			
		||||
# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
 | 
			
		||||
FIXXREF_OPTIONS=
 | 
			
		||||
 | 
			
		||||
# Used for dependencies. The docs will be rebuilt if any of these change.
 | 
			
		||||
# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
 | 
			
		||||
# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
 | 
			
		||||
HFILE_GLOB=$(top_srcdir)/src/*.h
 | 
			
		||||
CFILE_GLOB=$(top_srcdir)/src/*.c
 | 
			
		||||
 | 
			
		||||
# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
 | 
			
		||||
# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
 | 
			
		||||
EXTRA_HFILES=
 | 
			
		||||
 | 
			
		||||
# Header files or dirs to ignore when scanning. Use base file/dir names
 | 
			
		||||
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
 | 
			
		||||
IGNORE_HFILES=calendar-server gvc hotplug-sniffer st tray
 | 
			
		||||
 | 
			
		||||
# Images to copy into HTML directory.
 | 
			
		||||
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
 | 
			
		||||
HTML_IMAGES=
 | 
			
		||||
 | 
			
		||||
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
 | 
			
		||||
# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
 | 
			
		||||
content_files=
 | 
			
		||||
 | 
			
		||||
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
 | 
			
		||||
# These files must be listed here *and* in content_files
 | 
			
		||||
# e.g. expand_content_files=running.sgml
 | 
			
		||||
expand_content_files=
 | 
			
		||||
 | 
			
		||||
# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
 | 
			
		||||
# Only needed if you are using gtkdoc-scangobj to dynamically query widget
 | 
			
		||||
# signals and properties.
 | 
			
		||||
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
 | 
			
		||||
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
 | 
			
		||||
GTKDOC_CFLAGS=$(GNOME_SHELL_CFLAGS)
 | 
			
		||||
GTKDOC_LIBS=$(GNOME_SHELL_LIBS) $(top_builddir)/src/libgnome-shell.la
 | 
			
		||||
 | 
			
		||||
# This includes the standard gtk-doc make rules, copied by gtkdocize.
 | 
			
		||||
include $(top_srcdir)/gtk-doc.make
 | 
			
		||||
 | 
			
		||||
# Other files to distribute
 | 
			
		||||
# e.g. EXTRA_DIST += version.xml.in
 | 
			
		||||
EXTRA_DIST +=
 | 
			
		||||
 | 
			
		||||
# Files not to distribute
 | 
			
		||||
# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
 | 
			
		||||
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
 | 
			
		||||
DISTCLEANFILES = $(DOC_MODULES).types
 | 
			
		||||
 | 
			
		||||
# Comment this out if you want 'make check' to test you doc status
 | 
			
		||||
# and run some sanity checks
 | 
			
		||||
if ENABLE_GTK_DOC
 | 
			
		||||
TESTS_ENVIRONMENT = cd $(srcdir) && \
 | 
			
		||||
  DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \
 | 
			
		||||
  SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir)
 | 
			
		||||
#TESTS = $(GTKDOC_CHECK)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
-include $(top_srcdir)/git.mk
 | 
			
		||||
							
								
								
									
										73
									
								
								docs/reference/shell/shell-docs.sgml.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,73 @@
 | 
			
		||||
<?xml version="1.0"?>
 | 
			
		||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
 | 
			
		||||
               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
 | 
			
		||||
[
 | 
			
		||||
  <!ENTITY % local.common.attrib "xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2003/XInclude'">
 | 
			
		||||
]>
 | 
			
		||||
<book id="index">
 | 
			
		||||
  <bookinfo>
 | 
			
		||||
    <title>Shell Reference Manual</title>
 | 
			
		||||
    <releaseinfo>
 | 
			
		||||
      for Shell @VERSION@.
 | 
			
		||||
      <!--The latest version of this documentation can be found on-line at
 | 
			
		||||
      <ulink role="online-location" url="http://[SERVER]/shell/index.html">http://[SERVER]/shell/</ulink>.-->
 | 
			
		||||
    </releaseinfo>
 | 
			
		||||
  </bookinfo>
 | 
			
		||||
 | 
			
		||||
  <chapter>
 | 
			
		||||
    <title>Actors</title>
 | 
			
		||||
    <xi:include href="xml/shell-generic-container.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-slicer.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-stack.xml"/>
 | 
			
		||||
  </chapter>
 | 
			
		||||
  <chapter>
 | 
			
		||||
    <title>Application tracking</title>
 | 
			
		||||
    <xi:include href="xml/shell-app.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-app-usage.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-window-tracker.xml"/>
 | 
			
		||||
  </chapter>
 | 
			
		||||
  <chapter>
 | 
			
		||||
    <title>Search</title>
 | 
			
		||||
    <xi:include href="xml/shell-app-system.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-contact-system.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-doc-system.xml"/>
 | 
			
		||||
  </chapter>
 | 
			
		||||
  <chapter>
 | 
			
		||||
    <title>Tray Icons</title>
 | 
			
		||||
    <xi:include href="xml/shell-embedded-window.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-gtk-embed.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-tray-icon.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-tray-manager.xml"/>
 | 
			
		||||
  </chapter>
 | 
			
		||||
  <chapter>
 | 
			
		||||
    <title>Recorder</title>
 | 
			
		||||
    <xi:include href="xml/shell-recorder.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-recorder-src.xml"/>
 | 
			
		||||
  </chapter>
 | 
			
		||||
  <chapter>
 | 
			
		||||
    <title>Integration helpers and utilities</title>
 | 
			
		||||
    <xi:include href="xml/shell-global.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-wm.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-xfixes-cursor.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-util.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-mount-operation.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-mobile-providers.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-network-agent.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-polkit-authentication-agent.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-tp-client.xml"/>
 | 
			
		||||
  </chapter>
 | 
			
		||||
  <chapter id="object-tree">
 | 
			
		||||
    <title>Object Hierarchy</title>
 | 
			
		||||
     <xi:include href="xml/tree_index.sgml"/>
 | 
			
		||||
  </chapter>
 | 
			
		||||
  <index id="api-index-full">
 | 
			
		||||
    <title>API Index</title>
 | 
			
		||||
    <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
 | 
			
		||||
  </index>
 | 
			
		||||
  <index id="deprecated-api-index" role="deprecated">
 | 
			
		||||
    <title>Index of deprecated API</title>
 | 
			
		||||
    <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
 | 
			
		||||
  </index>
 | 
			
		||||
 | 
			
		||||
  <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
 | 
			
		||||
</book>
 | 
			
		||||
							
								
								
									
										105
									
								
								docs/reference/st/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,105 @@
 | 
			
		||||
## Process this file with automake to produce Makefile.in
 | 
			
		||||
 | 
			
		||||
# We require automake 1.6 at least.
 | 
			
		||||
AUTOMAKE_OPTIONS = 1.6
 | 
			
		||||
 | 
			
		||||
# This is a blank Makefile.am for using gtk-doc.
 | 
			
		||||
# Copy this to your project's API docs directory and modify the variables to
 | 
			
		||||
# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
 | 
			
		||||
# of using the various options.
 | 
			
		||||
 | 
			
		||||
# The name of the module, e.g. 'glib'.
 | 
			
		||||
DOC_MODULE=st
 | 
			
		||||
 | 
			
		||||
# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
 | 
			
		||||
#DOC_MODULE_VERSION=2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# The top-level SGML file. You can change this if you want to.
 | 
			
		||||
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
 | 
			
		||||
 | 
			
		||||
# Directories containing the source code, relative to $(srcdir).
 | 
			
		||||
# gtk-doc will search all .c and .h files beneath these paths
 | 
			
		||||
# for inline comments documenting functions and macros.
 | 
			
		||||
# e.g. DOC_SOURCE_DIR=../../../gtk ../../../gdk
 | 
			
		||||
DOC_SOURCE_DIR=../../../src/st
 | 
			
		||||
 | 
			
		||||
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
 | 
			
		||||
SCANGOBJ_OPTIONS=
 | 
			
		||||
 | 
			
		||||
# Extra options to supply to gtkdoc-scan.
 | 
			
		||||
# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
 | 
			
		||||
SCAN_OPTIONS=--rebuild-types --rebuild-sections
 | 
			
		||||
 | 
			
		||||
# Extra options to supply to gtkdoc-mkdb.
 | 
			
		||||
# e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
 | 
			
		||||
MKDB_OPTIONS=--xml-mode --output-format=xml
 | 
			
		||||
 | 
			
		||||
# Extra options to supply to gtkdoc-mktmpl
 | 
			
		||||
# e.g. MKTMPL_OPTIONS=--only-section-tmpl
 | 
			
		||||
MKTMPL_OPTIONS=
 | 
			
		||||
 | 
			
		||||
# Extra options to supply to gtkdoc-mkhtml
 | 
			
		||||
MKHTML_OPTIONS=
 | 
			
		||||
 | 
			
		||||
# Extra options to supply to gtkdoc-fixref. Not normally needed.
 | 
			
		||||
# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
 | 
			
		||||
FIXXREF_OPTIONS=
 | 
			
		||||
 | 
			
		||||
# Used for dependencies. The docs will be rebuilt if any of these change.
 | 
			
		||||
# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
 | 
			
		||||
# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
 | 
			
		||||
HFILE_GLOB=$(top_srcdir)/src/st/*.h
 | 
			
		||||
CFILE_GLOB=$(top_srcdir)/src/st/*.c
 | 
			
		||||
 | 
			
		||||
# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
 | 
			
		||||
# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
 | 
			
		||||
EXTRA_HFILES=
 | 
			
		||||
 | 
			
		||||
# Header files or dirs to ignore when scanning. Use base file/dir names
 | 
			
		||||
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
 | 
			
		||||
IGNORE_HFILES=st-private.h st-theme-node-private.h
 | 
			
		||||
 | 
			
		||||
# Images to copy into HTML directory.
 | 
			
		||||
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
 | 
			
		||||
HTML_IMAGES=
 | 
			
		||||
 | 
			
		||||
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
 | 
			
		||||
# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
 | 
			
		||||
content_files=
 | 
			
		||||
 | 
			
		||||
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
 | 
			
		||||
# These files must be listed here *and* in content_files
 | 
			
		||||
# e.g. expand_content_files=running.sgml
 | 
			
		||||
expand_content_files=
 | 
			
		||||
 | 
			
		||||
# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
 | 
			
		||||
# Only needed if you are using gtkdoc-scangobj to dynamically query widget
 | 
			
		||||
# signals and properties.
 | 
			
		||||
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
 | 
			
		||||
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
 | 
			
		||||
GTKDOC_CFLAGS=
 | 
			
		||||
GTKDOC_LIBS=$(top_builddir)/src/libst-1.0.la
 | 
			
		||||
 | 
			
		||||
# This includes the standard gtk-doc make rules, copied by gtkdocize.
 | 
			
		||||
include $(top_srcdir)/gtk-doc.make
 | 
			
		||||
 | 
			
		||||
# Other files to distribute
 | 
			
		||||
# e.g. EXTRA_DIST += version.xml.in
 | 
			
		||||
EXTRA_DIST +=
 | 
			
		||||
 | 
			
		||||
# Files not to distribute
 | 
			
		||||
# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
 | 
			
		||||
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
 | 
			
		||||
DISTCLEANFILES = $(DOC_MODULE).types $(DOC_MODULE)-sections.txt
 | 
			
		||||
 | 
			
		||||
# Comment this out if you want 'make check' to test you doc status
 | 
			
		||||
# and run some sanity checks
 | 
			
		||||
if ENABLE_GTK_DOC
 | 
			
		||||
TESTS_ENVIRONMENT = cd $(srcdir) && \
 | 
			
		||||
  DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \
 | 
			
		||||
  SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir)
 | 
			
		||||
#TESTS = $(GTKDOC_CHECK)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
-include $(top_srcdir)/git.mk
 | 
			
		||||
							
								
								
									
										68
									
								
								docs/reference/st/st-docs.sgml.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,68 @@
 | 
			
		||||
<?xml version="1.0"?>
 | 
			
		||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
 | 
			
		||||
               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
 | 
			
		||||
[
 | 
			
		||||
  <!ENTITY % local.common.attrib "xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2003/XInclude'">
 | 
			
		||||
]>
 | 
			
		||||
<book id="index">
 | 
			
		||||
  <bookinfo>
 | 
			
		||||
    <title>St Reference Manual</title>
 | 
			
		||||
    <releaseinfo>
 | 
			
		||||
      for St @VERSION@.
 | 
			
		||||
      <!--The latest version of this documentation can be found on-line at
 | 
			
		||||
      <ulink role="online-location" url="http://[SERVER]/st/index.html">http://[SERVER]/st/</ulink>.-->
 | 
			
		||||
    </releaseinfo>
 | 
			
		||||
  </bookinfo>
 | 
			
		||||
 | 
			
		||||
  <part>
 | 
			
		||||
    <title>API reference</title>
 | 
			
		||||
    <chapter id="base">
 | 
			
		||||
      <title>Abstract classes and Interfaces</title>
 | 
			
		||||
      <xi:include href="xml/st-widget.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-widget-accessible.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-container.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-scrollable.xml"/>
 | 
			
		||||
    </chapter>
 | 
			
		||||
    <chapter id="widgets">
 | 
			
		||||
      <title>Widgets</title>
 | 
			
		||||
      <xi:include href="xml/st-button.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-drawing-area.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-entry.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-icon.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-label.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-tooltip.xml"/>
 | 
			
		||||
    </chapter>
 | 
			
		||||
    <chapter id="containers">
 | 
			
		||||
      <title>Containers</title>
 | 
			
		||||
      <xi:include href="xml/st-bin.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-box-layout.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-group.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-overflow-box.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-scroll-view.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-table.xml"/>
 | 
			
		||||
    </chapter>
 | 
			
		||||
 | 
			
		||||
    <chapter id="styling">
 | 
			
		||||
      <title>Styling</title>
 | 
			
		||||
      <xi:include href="xml/st-theme.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-theme-context.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-theme-node.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-theme-node-transition.xml"/>
 | 
			
		||||
      <xi:include href="xml/st-texture-cache.xml"/>
 | 
			
		||||
    </chapter>
 | 
			
		||||
  </part>
 | 
			
		||||
  <chapter id="object-tree">
 | 
			
		||||
    <title>Object Hierarchy</title>
 | 
			
		||||
     <xi:include href="xml/tree_index.sgml"/>
 | 
			
		||||
  </chapter>
 | 
			
		||||
  <index id="api-index-full">
 | 
			
		||||
    <title>API Index</title>
 | 
			
		||||
    <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
 | 
			
		||||
  </index>
 | 
			
		||||
  <index id="deprecated-api-index" role="deprecated">
 | 
			
		||||
    <title>Index of deprecated API</title>
 | 
			
		||||
    <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
 | 
			
		||||
  </index>
 | 
			
		||||
 | 
			
		||||
  <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
 | 
			
		||||
</book>
 | 
			
		||||
@@ -6,6 +6,22 @@
 | 
			
		||||
 | 
			
		||||
  <name xml:lang="en">GNOME Shell</name>
 | 
			
		||||
  <shortdesc xml:lang="en">Next generation GNOME desktop shell</shortdesc>
 | 
			
		||||
  <description>GNOME Shell provides core user interface functions for the GNOME 3
 | 
			
		||||
desktop, like switching to windows and launching applications.
 | 
			
		||||
GNOME Shell takes advantage of the capabilities of modern graphics
 | 
			
		||||
hardware and introduces innovative user interface concepts to
 | 
			
		||||
provide a visually attractive and easy to use experience.
 | 
			
		||||
 | 
			
		||||
Tarball releases are provided largely for distributions to build
 | 
			
		||||
packages. If you are interested in building GNOME Shell from source,
 | 
			
		||||
we would recommend building from version control using the build
 | 
			
		||||
script described at:
 | 
			
		||||
 | 
			
		||||
 http://live.gnome.org/GnomeShell
 | 
			
		||||
 | 
			
		||||
Not only will that give you the very latest version of this rapidly
 | 
			
		||||
changing project, it will be much easier than get GNOME Shell and
 | 
			
		||||
its dependencies to build from tarballs.</description>
 | 
			
		||||
  <!--
 | 
			
		||||
  <homepage rdf:resource="http://live.gnome.org/GnomeShell" />
 | 
			
		||||
  -->
 | 
			
		||||
 
 | 
			
		||||
@@ -2,21 +2,31 @@
 | 
			
		||||
jsdir = $(pkgdatadir)/js
 | 
			
		||||
 | 
			
		||||
nobase_dist_js_DATA = 	\
 | 
			
		||||
	gdm/batch.js		\
 | 
			
		||||
	gdm/consoleKit.js	\
 | 
			
		||||
	gdm/fingerprint.js	\
 | 
			
		||||
	gdm/loginDialog.js	\
 | 
			
		||||
	gdm/powerMenu.js	\
 | 
			
		||||
	misc/config.js		\
 | 
			
		||||
	misc/docInfo.js		\
 | 
			
		||||
	misc/fileUtils.js	\
 | 
			
		||||
	misc/format.js		\
 | 
			
		||||
	misc/gnomeSession.js	\
 | 
			
		||||
	misc/history.js		\
 | 
			
		||||
	misc/jsParse.js		\
 | 
			
		||||
	misc/modemManager.js	\
 | 
			
		||||
	misc/params.js		\
 | 
			
		||||
	misc/screenSaver.js     \
 | 
			
		||||
	misc/util.js		\
 | 
			
		||||
	perf/core.js		\
 | 
			
		||||
	ui/altTab.js		\
 | 
			
		||||
	ui/appDisplay.js	\
 | 
			
		||||
	ui/appFavorites.js	\
 | 
			
		||||
	ui/automountManager.js  \
 | 
			
		||||
	ui/autorunManager.js    \
 | 
			
		||||
	ui/boxpointer.js	\
 | 
			
		||||
	ui/calendar.js		\
 | 
			
		||||
	ui/chrome.js		\
 | 
			
		||||
	ui/contactDisplay.js \
 | 
			
		||||
	ui/ctrlAltTab.js	\
 | 
			
		||||
	ui/dash.js		\
 | 
			
		||||
	ui/dateMenu.js		\
 | 
			
		||||
@@ -26,6 +36,8 @@ nobase_dist_js_DATA = 	\
 | 
			
		||||
	ui/environment.js	\
 | 
			
		||||
	ui/extensionSystem.js	\
 | 
			
		||||
	ui/iconGrid.js		\
 | 
			
		||||
	ui/keyboard.js		\
 | 
			
		||||
	ui/layout.js		\
 | 
			
		||||
	ui/lightbox.js		\
 | 
			
		||||
	ui/link.js		\
 | 
			
		||||
	ui/lookingGlass.js	\
 | 
			
		||||
@@ -34,6 +46,9 @@ nobase_dist_js_DATA = 	\
 | 
			
		||||
	ui/main.js		\
 | 
			
		||||
	ui/messageTray.js	\
 | 
			
		||||
	ui/modalDialog.js	\
 | 
			
		||||
	ui/networkAgent.js	\
 | 
			
		||||
	ui/shellEntry.js	\
 | 
			
		||||
	ui/shellMountOperation.js \
 | 
			
		||||
	ui/notificationDaemon.js \
 | 
			
		||||
	ui/overview.js		\
 | 
			
		||||
	ui/panel.js		\
 | 
			
		||||
@@ -47,14 +62,15 @@ nobase_dist_js_DATA = 	\
 | 
			
		||||
	ui/searchDisplay.js	\
 | 
			
		||||
	ui/shellDBus.js		\
 | 
			
		||||
	ui/statusIconDispatcher.js	\
 | 
			
		||||
	ui/statusMenu.js	\
 | 
			
		||||
	ui/status/accessibility.js	\
 | 
			
		||||
	ui/status/keyboard.js	\
 | 
			
		||||
	ui/status/network.js	\
 | 
			
		||||
	ui/status/power.js	\
 | 
			
		||||
	ui/status/volume.js	\
 | 
			
		||||
	ui/status/bluetooth.js	\
 | 
			
		||||
	ui/telepathyClient.js	\
 | 
			
		||||
	ui/tweener.js		\
 | 
			
		||||
	ui/userMenu.js		\
 | 
			
		||||
	ui/viewSelector.js	\
 | 
			
		||||
	ui/windowAttentionHandler.js	\
 | 
			
		||||
	ui/windowManager.js	\
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										203
									
								
								js/gdm/batch.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,203 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2011 Red Hat, Inc
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 | 
			
		||||
 * 02111-1307, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const Task = new Lang.Class({
 | 
			
		||||
    Name: 'Task',
 | 
			
		||||
 | 
			
		||||
    _init: function(scope, handler) {
 | 
			
		||||
        if (scope)
 | 
			
		||||
            this.scope = scope;
 | 
			
		||||
        else
 | 
			
		||||
            this.scope = this;
 | 
			
		||||
 | 
			
		||||
        this.handler = handler;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    run: function() {
 | 
			
		||||
        if (this.handler)
 | 
			
		||||
            return this.handler.call(this.scope);
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(Task.prototype);
 | 
			
		||||
 | 
			
		||||
const Hold = new Lang.Class({
 | 
			
		||||
    Name: 'Hold',
 | 
			
		||||
    Extends: Task,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.parent(this, function () {
 | 
			
		||||
            return this;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._acquisitions = 1;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    acquire: function() {
 | 
			
		||||
        if (this._acquisitions <= 0)
 | 
			
		||||
            throw new Error("Cannot acquire hold after it's been released");
 | 
			
		||||
        this._acquisitions++;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    acquireUntilAfter: function(hold) {
 | 
			
		||||
        if (!hold.isAcquired())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.acquire();
 | 
			
		||||
        let signalId = hold.connect('release', Lang.bind(this, function() {
 | 
			
		||||
                                        hold.disconnect(signalId);
 | 
			
		||||
                                        this.release();
 | 
			
		||||
                                    }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    release: function() {
 | 
			
		||||
        this._acquisitions--;
 | 
			
		||||
 | 
			
		||||
        if (this._acquisitions == 0)
 | 
			
		||||
            this.emit('release');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    isAcquired: function() {
 | 
			
		||||
        return this._acquisitions > 0;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(Hold.prototype);
 | 
			
		||||
 | 
			
		||||
const Batch = new Lang.Class({
 | 
			
		||||
    Name: 'Batch',
 | 
			
		||||
    Extends: Task,
 | 
			
		||||
 | 
			
		||||
    _init: function(scope, tasks) {
 | 
			
		||||
        this.parent();
 | 
			
		||||
 | 
			
		||||
        this.tasks = [];
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < tasks.length; i++) {
 | 
			
		||||
            let task;
 | 
			
		||||
 | 
			
		||||
            if (tasks[i] instanceof Task) {
 | 
			
		||||
                task = tasks[i];
 | 
			
		||||
            } else if (typeof tasks[i] == 'function') {
 | 
			
		||||
                task = new Task(scope, tasks[i]);
 | 
			
		||||
            } else {
 | 
			
		||||
                throw new Error('Batch tasks must be functions or Task, Hold or Batch objects');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.tasks.push(task);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    process: function() {
 | 
			
		||||
        throw new Error('Not implemented');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    runTask: function() {
 | 
			
		||||
        if (!(this._currentTaskIndex in this.tasks)) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this.tasks[this._currentTaskIndex].run();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _finish: function() {
 | 
			
		||||
        this.hold.release();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    nextTask: function() {
 | 
			
		||||
        this._currentTaskIndex++;
 | 
			
		||||
 | 
			
		||||
        // if the entire batch of tasks is finished, release
 | 
			
		||||
        // the hold and notify anyone waiting on the batch
 | 
			
		||||
        if (this._currentTaskIndex >= this.tasks.length) {
 | 
			
		||||
            this._finish();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.process();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _start: function() {
 | 
			
		||||
        // acquire a hold to get released when the entire
 | 
			
		||||
        // batch of tasks is finished
 | 
			
		||||
        this.hold = new Hold();
 | 
			
		||||
        this._currentTaskIndex = 0;
 | 
			
		||||
        this.process();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    run: function() {
 | 
			
		||||
        this._start();
 | 
			
		||||
 | 
			
		||||
        // hold may be destroyed at this point
 | 
			
		||||
        // if we're already done running
 | 
			
		||||
        return this.hold;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    cancel: function() {
 | 
			
		||||
        this.tasks = this.tasks.splice(0, this._currentTaskIndex + 1);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(Batch.prototype);
 | 
			
		||||
 | 
			
		||||
const ConcurrentBatch = new Lang.Class({
 | 
			
		||||
    Name: 'ConcurrentBatch',
 | 
			
		||||
    Extends: Batch,
 | 
			
		||||
 | 
			
		||||
    process: function() {
 | 
			
		||||
       let hold = this.runTask();
 | 
			
		||||
 | 
			
		||||
       if (hold) {
 | 
			
		||||
           this.hold.acquireUntilAfter(hold);
 | 
			
		||||
       }
 | 
			
		||||
 | 
			
		||||
       // Regardless of the state of the just run task,
 | 
			
		||||
       // fire off the next one, so all the tasks can run
 | 
			
		||||
       // concurrently.
 | 
			
		||||
       this.nextTask();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ConcurrentBatch.prototype);
 | 
			
		||||
 | 
			
		||||
const ConsecutiveBatch = new Lang.Class({
 | 
			
		||||
    Name: 'ConsecutiveBatch',
 | 
			
		||||
    Extends: Batch,
 | 
			
		||||
 | 
			
		||||
    process: function() {
 | 
			
		||||
       let hold = this.runTask();
 | 
			
		||||
 | 
			
		||||
       if (hold && hold.isAcquired()) {
 | 
			
		||||
           // This task is inhibiting the batch. Wait on it
 | 
			
		||||
           // before processing the next one.
 | 
			
		||||
           let signalId = hold.connect('release',
 | 
			
		||||
                                       Lang.bind(this, function() {
 | 
			
		||||
                                           hold.disconnect(signalId);
 | 
			
		||||
                                           this.nextTask();
 | 
			
		||||
                                       }));
 | 
			
		||||
           return;
 | 
			
		||||
       } else {
 | 
			
		||||
           // This task finished, process the next one
 | 
			
		||||
           this.nextTask();
 | 
			
		||||
       }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ConsecutiveBatch.prototype);
 | 
			
		||||
							
								
								
									
										22
									
								
								js/gdm/consoleKit.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,22 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
 | 
			
		||||
const ConsoleKitManagerIface = <interface name='org.freedesktop.ConsoleKit.Manager'>
 | 
			
		||||
<method name='CanRestart'>
 | 
			
		||||
    <arg type='b' direction='out'/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name='CanStop'>
 | 
			
		||||
    <arg type='b' direction='out'/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name='Restart' />
 | 
			
		||||
<method name='Stop' />
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const ConsoleKitProxy = Gio.DBusProxy.makeProxyWrapper(ConsoleKitManagerIface);
 | 
			
		||||
 | 
			
		||||
function ConsoleKitManager() {
 | 
			
		||||
    return new ConsoleKitProxy(Gio.DBus.system,
 | 
			
		||||
                               'org.freedesktop.ConsoleKit',
 | 
			
		||||
                               '/org/freedesktop/ConsoleKit/Manager');
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										20
									
								
								js/gdm/fingerprint.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,20 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const FprintManagerIface = <interface name='net.reactivated.Fprint.Manager'>
 | 
			
		||||
<method name='GetDefaultDevice'>
 | 
			
		||||
    <arg type='o' direction='out' />
 | 
			
		||||
</method>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const FprintManagerProxy = Gio.DBusProxy.makeProxyWrapper(FprintManagerIface);
 | 
			
		||||
 | 
			
		||||
function FprintManager() {
 | 
			
		||||
    return new FprintManagerProxy(Gio.DBus.system,
 | 
			
		||||
                           'net.reactivated.Fprint',
 | 
			
		||||
                           '/net/reactivated/Fprint/Manager');
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										1387
									
								
								js/gdm/loginDialog.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										143
									
								
								js/gdm/powerMenu.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,143 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2011 Red Hat, Inc
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 | 
			
		||||
 * 02111-1307, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const UPowerGlib = imports.gi.UPowerGlib;
 | 
			
		||||
 | 
			
		||||
const ConsoleKit = imports.gdm.consoleKit;
 | 
			
		||||
const PanelMenu = imports.ui.panelMenu;
 | 
			
		||||
const PopupMenu = imports.ui.popupMenu;
 | 
			
		||||
 | 
			
		||||
const PowerMenuButton = new Lang.Class({
 | 
			
		||||
    Name: 'PowerMenuButton',
 | 
			
		||||
    Extends: PanelMenu.SystemStatusButton,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.parent('system-shutdown', null);
 | 
			
		||||
        this._consoleKitManager = new ConsoleKit.ConsoleKitManager();
 | 
			
		||||
        this._upClient = new UPowerGlib.Client();
 | 
			
		||||
 | 
			
		||||
        this._createSubMenu();
 | 
			
		||||
 | 
			
		||||
        this._upClient.connect('notify::can-suspend',
 | 
			
		||||
                               Lang.bind(this, this._updateHaveSuspend));
 | 
			
		||||
        this._updateHaveSuspend();
 | 
			
		||||
 | 
			
		||||
        // ConsoleKit doesn't send notifications when shutdown/reboot
 | 
			
		||||
        // are disabled, so we update the menu item each time the menu opens
 | 
			
		||||
        this.menu.connect('open-state-changed', Lang.bind(this,
 | 
			
		||||
            function(menu, open) {
 | 
			
		||||
                if (open) {
 | 
			
		||||
                    this._updateHaveShutdown();
 | 
			
		||||
                    this._updateHaveRestart();
 | 
			
		||||
                }
 | 
			
		||||
            }));
 | 
			
		||||
        this._updateHaveShutdown();
 | 
			
		||||
        this._updateHaveRestart();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateVisibility: function() {
 | 
			
		||||
        if (!this._haveSuspend && !this._haveShutdown && !this._haveRestart)
 | 
			
		||||
            this.actor.hide();
 | 
			
		||||
        else
 | 
			
		||||
            this.actor.show();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateHaveShutdown: function() {
 | 
			
		||||
        this._consoleKitManager.CanStopRemote(Lang.bind(this,
 | 
			
		||||
            function(result, error) {
 | 
			
		||||
                if (!error)
 | 
			
		||||
                    this._haveShutdown = result;
 | 
			
		||||
                else
 | 
			
		||||
                    this._haveShutdown = false;
 | 
			
		||||
 | 
			
		||||
                if (this._haveShutdown) {
 | 
			
		||||
                    this._powerOffItem.actor.show();
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._powerOffItem.actor.hide();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this._updateVisibility();
 | 
			
		||||
            }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateHaveRestart: function() {
 | 
			
		||||
        this._consoleKitManager.CanRestartRemote(Lang.bind(this,
 | 
			
		||||
            function(result, error) {
 | 
			
		||||
                if (!error)
 | 
			
		||||
                    this._haveRestart = result;
 | 
			
		||||
                else
 | 
			
		||||
                    this._haveRestart = false;
 | 
			
		||||
 | 
			
		||||
                if (this._haveRestart) {
 | 
			
		||||
                    this._restartItem.actor.show();
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._restartItem.actor.hide();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this._updateVisibility();
 | 
			
		||||
            }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateHaveSuspend: function() {
 | 
			
		||||
        this._haveSuspend = this._upClient.get_can_suspend();
 | 
			
		||||
 | 
			
		||||
        if (this._haveSuspend)
 | 
			
		||||
            this._suspendItem.actor.show();
 | 
			
		||||
        else
 | 
			
		||||
            this._suspendItem.actor.hide();
 | 
			
		||||
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createSubMenu: function() {
 | 
			
		||||
        let item;
 | 
			
		||||
 | 
			
		||||
        item = new PopupMenu.PopupMenuItem(_("Suspend"));
 | 
			
		||||
        item.connect('activate', Lang.bind(this, this._onActivateSuspend));
 | 
			
		||||
        this.menu.addMenuItem(item);
 | 
			
		||||
        this._suspendItem = item;
 | 
			
		||||
 | 
			
		||||
        item = new PopupMenu.PopupMenuItem(_("Restart"));
 | 
			
		||||
        item.connect('activate', Lang.bind(this, this._onActivateRestart));
 | 
			
		||||
        this.menu.addMenuItem(item);
 | 
			
		||||
        this._restartItem = item;
 | 
			
		||||
 | 
			
		||||
        item = new PopupMenu.PopupMenuItem(_("Power Off"));
 | 
			
		||||
        item.connect('activate', Lang.bind(this, this._onActivatePowerOff));
 | 
			
		||||
        this.menu.addMenuItem(item);
 | 
			
		||||
        this._powerOffItem = item;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onActivateSuspend: function() {
 | 
			
		||||
        if (this._haveSuspend)
 | 
			
		||||
            this._upClient.suspend_sync(null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onActivateRestart: function() {
 | 
			
		||||
        if (this._haveRestart)
 | 
			
		||||
            this._consoleKitManager.RestartRemote();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onActivatePowerOff: function() {
 | 
			
		||||
        if (this._haveShutdown)
 | 
			
		||||
            this._consoleKitManager.StopRemote();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
/* mode: js2; indent-tabs-mode: nil; tab-size: 4 */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
/* The name of this package (not localized) */
 | 
			
		||||
const PACKAGE_NAME = '@PACKAGE_NAME@';
 | 
			
		||||
/* The version of this package */
 | 
			
		||||
@@ -7,4 +8,5 @@ const PACKAGE_VERSION = '@PACKAGE_VERSION@';
 | 
			
		||||
const GJS_VERSION = '@GJS_VERSION@';
 | 
			
		||||
/* 1 if gnome-bluetooth is available, 0 otherwise */
 | 
			
		||||
const HAVE_BLUETOOTH = @HAVE_BLUETOOTH@;
 | 
			
		||||
 | 
			
		||||
/* The system TLS CA list */
 | 
			
		||||
const SHELL_SYSTEM_CA_FILE = '@SHELL_SYSTEM_CA_FILE@';
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
@@ -8,11 +8,9 @@ const Search = imports.ui.search;
 | 
			
		||||
 | 
			
		||||
const THUMBNAIL_ICON_MARGIN = 2;
 | 
			
		||||
 | 
			
		||||
function DocInfo(recentInfo) {
 | 
			
		||||
    this._init(recentInfo);
 | 
			
		||||
}
 | 
			
		||||
const DocInfo = new Lang.Class({
 | 
			
		||||
    Name: 'DocInfo',
 | 
			
		||||
 | 
			
		||||
DocInfo.prototype = {
 | 
			
		||||
    _init : function(recentInfo) {
 | 
			
		||||
        this.recentInfo = recentInfo;
 | 
			
		||||
        // We actually used get_modified() instead of get_visited()
 | 
			
		||||
@@ -49,7 +47,7 @@ DocInfo.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
        return mtype;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var docManagerInstance = null;
 | 
			
		||||
 | 
			
		||||
@@ -62,11 +60,9 @@ function getDocManager() {
 | 
			
		||||
/**
 | 
			
		||||
 * DocManager wraps the DocSystem, primarily to expose DocInfo objects.
 | 
			
		||||
 */
 | 
			
		||||
function DocManager() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const DocManager = new Lang.Class({
 | 
			
		||||
    Name: 'DocManager',
 | 
			
		||||
 | 
			
		||||
DocManager.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._docSystem = Shell.DocSystem.get_default();
 | 
			
		||||
        this._infosByTimestamp = [];
 | 
			
		||||
@@ -135,6 +131,6 @@ DocManager.prototype = {
 | 
			
		||||
                return this._infosByUri[url];
 | 
			
		||||
            })), terms);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(DocManager.prototype);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
 | 
			
		||||
@@ -20,3 +22,25 @@ function listDirAsync(file, callback) {
 | 
			
		||||
        enumerator.next_files_async(100, GLib.PRIORITY_LOW, null, onNextFileComplete);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function deleteGFile(file) {
 | 
			
		||||
    // Work around 'delete' being a keyword in JS.
 | 
			
		||||
    return file['delete'](null);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function recursivelyDeleteDir(dir) {
 | 
			
		||||
    let children = dir.enumerate_children('standard::name,standard::type',
 | 
			
		||||
                                          Gio.FileQueryInfoFlags.NONE, null);
 | 
			
		||||
 | 
			
		||||
    let info, child;
 | 
			
		||||
    while ((info = children.next_file(null)) != null) {
 | 
			
		||||
        let type = info.get_file_type();
 | 
			
		||||
        let child = dir.get_child(info.get_name());
 | 
			
		||||
        if (type == Gio.FileType.REGULAR)
 | 
			
		||||
            deleteGFile(child);
 | 
			
		||||
        else if (type == Gio.TypeType.DIRECTORY)
 | 
			
		||||
            recursivelyDeleteDir(child);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    deleteGFile(dir);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This function is intended to extend the String object and provide
 | 
			
		||||
 
 | 
			
		||||
@@ -1,19 +1,18 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const DBus = imports.dbus;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const PresenceIface = {
 | 
			
		||||
    name: 'org.gnome.SessionManager.Presence',
 | 
			
		||||
    methods: [{ name: 'SetStatus',
 | 
			
		||||
                inSignature: 'u' }],
 | 
			
		||||
    properties: [{ name: 'status',
 | 
			
		||||
                   signature: 'u',
 | 
			
		||||
                   access: 'readwrite' }],
 | 
			
		||||
    signals: [{ name: 'StatusChanged',
 | 
			
		||||
                inSignature: 'u' }]
 | 
			
		||||
};
 | 
			
		||||
const PresenceIface = <interface name="org.gnome.SessionManager.Presence">
 | 
			
		||||
<method name="SetStatus">
 | 
			
		||||
    <arg type="u" direction="in"/>
 | 
			
		||||
</method>
 | 
			
		||||
<property name="status" type="u" access="readwrite"/>
 | 
			
		||||
<signal name="StatusChanged">
 | 
			
		||||
    <arg type="u" direction="out"/>
 | 
			
		||||
</signal>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const PresenceStatus = {
 | 
			
		||||
    AVAILABLE: 0,
 | 
			
		||||
@@ -22,82 +21,41 @@ const PresenceStatus = {
 | 
			
		||||
    IDLE: 3
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function Presence() {
 | 
			
		||||
    this._init();
 | 
			
		||||
var PresenceProxy = Gio.DBusProxy.makeProxyWrapper(PresenceIface);
 | 
			
		||||
function Presence(initCallback, cancellable) {
 | 
			
		||||
    return new PresenceProxy(Gio.DBus.session, 'org.gnome.SessionManager',
 | 
			
		||||
                             '/org/gnome/SessionManager/Presence', initCallback, cancellable);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Presence.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        DBus.session.proxifyObject(this, 'org.gnome.SessionManager', '/org/gnome/SessionManager/Presence', this);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getStatus: function(callback) {
 | 
			
		||||
        this.GetRemote('status', Lang.bind(this,
 | 
			
		||||
            function(status, ex) {
 | 
			
		||||
                if (!ex)
 | 
			
		||||
                    callback(this, status);
 | 
			
		||||
            }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setStatus: function(status) {
 | 
			
		||||
        this.SetStatusRemote(status);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
DBus.proxifyPrototype(Presence.prototype, PresenceIface);
 | 
			
		||||
 | 
			
		||||
// Note inhibitors are immutable objects, so they don't
 | 
			
		||||
// change at runtime (changes always come in the form
 | 
			
		||||
// of new inhibitors)
 | 
			
		||||
const InhibitorIface = {
 | 
			
		||||
    name: 'org.gnome.SessionManager.Inhibitor',
 | 
			
		||||
    properties: [{ name: 'app_id',
 | 
			
		||||
                   signature: 's',
 | 
			
		||||
                   access: 'readonly' },
 | 
			
		||||
                 { name: 'client_id',
 | 
			
		||||
                   signature: 's',
 | 
			
		||||
                   access: 'readonly' },
 | 
			
		||||
                 { name: 'reason',
 | 
			
		||||
                   signature: 's',
 | 
			
		||||
                   access: 'readonly' },
 | 
			
		||||
                 { name: 'flags',
 | 
			
		||||
                   signature: 'u',
 | 
			
		||||
                   access: 'readonly' },
 | 
			
		||||
                 { name: 'toplevel_xid',
 | 
			
		||||
                   signature: 'u',
 | 
			
		||||
                   access: 'readonly' },
 | 
			
		||||
                 { name: 'cookie',
 | 
			
		||||
                   signature: 'u',
 | 
			
		||||
                   access: 'readonly' }],
 | 
			
		||||
};
 | 
			
		||||
const InhibitorIface = <interface name="org.gnome.SessionManager.Inhibitor">
 | 
			
		||||
<property name="app_id" type="s" access="read" />
 | 
			
		||||
<property name="client_id" type="s" access="read" />
 | 
			
		||||
<property name="reason" type="s" access="read" />
 | 
			
		||||
<property name="flags" type="u" access="read" />
 | 
			
		||||
<property name="toplevel_xid" type="u" access="read" />
 | 
			
		||||
<property name="cookie" type="u" access="read" />
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
function Inhibitor(objectPath) {
 | 
			
		||||
    this._init(objectPath);
 | 
			
		||||
var InhibitorProxy = Gio.DBusProxy.makeProxyWrapper(InhibitorIface);
 | 
			
		||||
function Inhibitor(objectPath, initCallback, cancellable) {
 | 
			
		||||
    return new InhibitorProxy(Gio.DBus.session, 'org.gnome.SessionManager', objectPath, initCallback, cancellable);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Inhibitor.prototype = {
 | 
			
		||||
    _init: function(objectPath) {
 | 
			
		||||
        DBus.session.proxifyObject(this,
 | 
			
		||||
                                   "org.gnome.SessionManager",
 | 
			
		||||
                                   objectPath);
 | 
			
		||||
        this.isLoaded = false;
 | 
			
		||||
        this._loadingPropertiesCount = InhibitorIface.properties.length;
 | 
			
		||||
        for (let i = 0; i < InhibitorIface.properties.length; i++) {
 | 
			
		||||
            let propertyName = InhibitorIface.properties[i].name;
 | 
			
		||||
            this.GetRemote(propertyName, Lang.bind(this,
 | 
			
		||||
                function(value, exception) {
 | 
			
		||||
                    if (exception)
 | 
			
		||||
                        return;
 | 
			
		||||
// Not the full interface, only the methods we use
 | 
			
		||||
const SessionManagerIface = <interface name="org.gnome.SessionManager">
 | 
			
		||||
<method name="Logout">
 | 
			
		||||
    <arg type="u" direction="in" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="Shutdown" />
 | 
			
		||||
<method name="CanShutdown">
 | 
			
		||||
    <arg type="b" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
                    this[propertyName] = value;
 | 
			
		||||
                    this._loadingPropertiesCount--;
 | 
			
		||||
 | 
			
		||||
                    if (this._loadingPropertiesCount == 0) {
 | 
			
		||||
                        this.isLoaded = true;
 | 
			
		||||
                        this.emit("is-loaded");
 | 
			
		||||
                    }
 | 
			
		||||
                }));
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
DBus.proxifyPrototype(Inhibitor.prototype, InhibitorIface);
 | 
			
		||||
Signals.addSignalMethods(Inhibitor.prototype);
 | 
			
		||||
var SessionManagerProxy = Gio.DBusProxy.makeProxyWrapper(SessionManagerIface);
 | 
			
		||||
function SessionManager(initCallback, cancellable) {
 | 
			
		||||
    return new SessionManagerProxy(Gio.DBus.session, 'org.gnome.SessionManager', '/org/gnome/SessionManager', initCallback, cancellable);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +1,39 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
 | 
			
		||||
const DEFAULT_LIMIT = 512;
 | 
			
		||||
 | 
			
		||||
function HistoryManager(settings_key) {
 | 
			
		||||
    this._init(settings_key);
 | 
			
		||||
}
 | 
			
		||||
const HistoryManager = new Lang.Class({
 | 
			
		||||
    Name: 'HistoryManager',
 | 
			
		||||
 | 
			
		||||
HistoryManager.prototype = {
 | 
			
		||||
    _init: function(settings_key, limit) {
 | 
			
		||||
        this._limit = limit || DEFAULT_LIMIT;
 | 
			
		||||
        this._key = settings_key;
 | 
			
		||||
        this._history = global.settings.get_strv(settings_key);
 | 
			
		||||
        this._historyIndex = -1;
 | 
			
		||||
    _init: function(params) {
 | 
			
		||||
        params = Params.parse(params, { gsettingsKey: null,
 | 
			
		||||
                                        limit: DEFAULT_LIMIT,
 | 
			
		||||
                                        entry: null });
 | 
			
		||||
 | 
			
		||||
        global.settings.connect('changed::' + settings_key,
 | 
			
		||||
                                Lang.bind(this, this._historyChanged));
 | 
			
		||||
        this._key = params.gsettingsKey;
 | 
			
		||||
        this._limit = params.limit;
 | 
			
		||||
 | 
			
		||||
        this._historyIndex = 0;
 | 
			
		||||
        if (this._key) {
 | 
			
		||||
            this._history = global.settings.get_strv(this._key);
 | 
			
		||||
            global.settings.connect('changed::' + this._key,
 | 
			
		||||
                                    Lang.bind(this, this._historyChanged));
 | 
			
		||||
 | 
			
		||||
        } else {
 | 
			
		||||
            this._history = [];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._entry = params.entry;
 | 
			
		||||
 | 
			
		||||
        if (this._entry) {
 | 
			
		||||
            this._entry.connect('key-press-event', 
 | 
			
		||||
                                Lang.bind(this, this._onEntryKeyPress));
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _historyChanged: function() {
 | 
			
		||||
@@ -26,18 +42,32 @@ HistoryManager.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    prevItem: function(text) {
 | 
			
		||||
        this._setHistory(this._historyIndex--, text);
 | 
			
		||||
        if (this._historyIndex <= 0)
 | 
			
		||||
            return text;
 | 
			
		||||
 | 
			
		||||
        if (text)
 | 
			
		||||
            this._history[this._historyIndex] = text;
 | 
			
		||||
        this._historyIndex--;
 | 
			
		||||
        return this._indexChanged();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    nextItem: function(text) {
 | 
			
		||||
        this._setHistory(this._historyIndex++, text);
 | 
			
		||||
        if (this._historyIndex >= this._history.length)
 | 
			
		||||
            return text;
 | 
			
		||||
 | 
			
		||||
        if (text)
 | 
			
		||||
            this._history[this._historyIndex] = text;
 | 
			
		||||
        this._historyIndex++;
 | 
			
		||||
        return this._indexChanged();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    lastItem: function() {
 | 
			
		||||
        this._historyIndex = this._history.length;
 | 
			
		||||
        return this._indexChanged();
 | 
			
		||||
        if (this._historyIndex != this._history.length) {
 | 
			
		||||
            this._historyIndex = this._history.length;
 | 
			
		||||
            this._indexChanged();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this._historyIndex[this._history.length];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addItem: function(input) {
 | 
			
		||||
@@ -46,27 +76,38 @@ HistoryManager.prototype = {
 | 
			
		||||
 | 
			
		||||
            this._history.push(input);
 | 
			
		||||
            this._save();
 | 
			
		||||
        }   
 | 
			
		||||
        }
 | 
			
		||||
        this._historyIndex = this._history.length;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onEntryKeyPress: function(entry, event) {
 | 
			
		||||
        let symbol = event.get_key_symbol();
 | 
			
		||||
        if (symbol == Clutter.KEY_Up) {
 | 
			
		||||
            this.prevItem(entry.get_text());
 | 
			
		||||
            return true;
 | 
			
		||||
        } else if (symbol == Clutter.KEY_Down) {
 | 
			
		||||
            this.nextItem(entry.get_text());
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _indexChanged: function() {
 | 
			
		||||
        let current = this._history[this._historyIndex] || '';
 | 
			
		||||
        this.emit('changed', current);
 | 
			
		||||
 | 
			
		||||
        if (this._entry)
 | 
			
		||||
            this._entry.set_text(current);
 | 
			
		||||
 | 
			
		||||
        return current;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setHistory: function(index, text) {
 | 
			
		||||
        this._historyIndex = Math.max(this._historyIndex, 0);
 | 
			
		||||
        this._historyIndex = Math.min(this._historyIndex, this._history.length);
 | 
			
		||||
 | 
			
		||||
        if (text)
 | 
			
		||||
            this._history[index] = text;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _save: function() {
 | 
			
		||||
        if (this._history.length > this._limit)
 | 
			
		||||
            this._history.splice(0, this._history.length - this._key);
 | 
			
		||||
        global.settings.set_strv(this._key, this._history);
 | 
			
		||||
            this._history.splice(0, this._history.length - this._limit);
 | 
			
		||||
 | 
			
		||||
        if (this._key)
 | 
			
		||||
            global.settings.set_strv(this._key, this._history);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(HistoryManager.prototype);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										246
									
								
								js/misc/jsParse.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,246 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
 | 
			
		||||
// Returns a list of potential completions for text. Completions either
 | 
			
		||||
// follow a dot (e.g. foo.ba -> bar) or they are picked from globalCompletionList (e.g. fo -> foo)
 | 
			
		||||
// commandHeader is prefixed on any expression before it is eval'ed.  It will most likely
 | 
			
		||||
// consist of global constants that might not carry over from the calling environment.
 | 
			
		||||
//
 | 
			
		||||
// This function is likely the one you want to call from external modules
 | 
			
		||||
function getCompletions(text, commandHeader, globalCompletionList) {
 | 
			
		||||
    let methods = [];
 | 
			
		||||
    let expr, base;
 | 
			
		||||
    let attrHead = '';
 | 
			
		||||
    if (globalCompletionList == null) {
 | 
			
		||||
        globalCompletionList = [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let offset = getExpressionOffset(text, text.length - 1);
 | 
			
		||||
    if (offset >= 0) {
 | 
			
		||||
        text = text.slice(offset);
 | 
			
		||||
 | 
			
		||||
        // Look for expressions like "Main.panel.foo" and match Main.panel and foo
 | 
			
		||||
        let matches = text.match(/(.*)\.(.*)/);
 | 
			
		||||
        if (matches) {
 | 
			
		||||
            [expr, base, attrHead] = matches;
 | 
			
		||||
 | 
			
		||||
            methods = getPropertyNamesFromExpression(base, commandHeader).filter(function(attr) {
 | 
			
		||||
                return attr.slice(0, attrHead.length) == attrHead;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Look for the empty expression or partially entered words
 | 
			
		||||
        // not proceeded by a dot and match them against global constants
 | 
			
		||||
        matches = text.match(/^(\w*)$/);
 | 
			
		||||
        if (text == '' || matches) {
 | 
			
		||||
            [expr, attrHead] = matches;
 | 
			
		||||
            methods = globalCompletionList.filter(function(attr) {
 | 
			
		||||
                return attr.slice(0, attrHead.length) == attrHead;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return [methods, attrHead];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// A few functions for parsing strings of javascript code.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
// Identify characters that delimit an expression.  That is,
 | 
			
		||||
// if we encounter anything that isn't a letter, '.', ')', or ']',
 | 
			
		||||
// we should stop parsing.
 | 
			
		||||
function isStopChar(c) {
 | 
			
		||||
    return !c.match(/[\w\.\)\]]/);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Given the ending position of a quoted string, find where it starts
 | 
			
		||||
function findMatchingQuote(expr, offset) {
 | 
			
		||||
    let quoteChar = expr.charAt(offset);
 | 
			
		||||
    for (let i = offset - 1; i >= 0; --i) {
 | 
			
		||||
        if (expr.charAt(i) == quoteChar && expr.charAt(i-1) != '\\'){
 | 
			
		||||
            return i;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Given the ending position of a regex, find where it starts
 | 
			
		||||
function findMatchingSlash(expr, offset) {
 | 
			
		||||
    for (let i = offset - 1; i >= 0; --i) {
 | 
			
		||||
        if (expr.charAt(i) == '/' && expr.charAt(i-1) != '\\'){
 | 
			
		||||
            return i;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// If expr.charAt(offset) is ')' or ']',
 | 
			
		||||
// return the position of the corresponding '(' or '[' bracket.
 | 
			
		||||
// This function does not check for syntactic correctness.  e.g.,
 | 
			
		||||
// findMatchingBrace("[(])", 3) returns 1.
 | 
			
		||||
function findMatchingBrace(expr, offset) {
 | 
			
		||||
    let closeBrace = expr.charAt(offset);
 | 
			
		||||
    let openBrace = ({')': '(', ']': '['})[closeBrace];
 | 
			
		||||
 | 
			
		||||
    function findTheBrace(expr, offset) {
 | 
			
		||||
        if (offset < 0) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (expr.charAt(offset) == openBrace) {
 | 
			
		||||
            return offset;
 | 
			
		||||
        }
 | 
			
		||||
        if (expr.charAt(offset).match(/['"]/)) {
 | 
			
		||||
            return findTheBrace(expr, findMatchingQuote(expr, offset) - 1);
 | 
			
		||||
        }
 | 
			
		||||
        if (expr.charAt(offset) == '/') {
 | 
			
		||||
            return findTheBrace(expr, findMatchingSlash(expr, offset) - 1);
 | 
			
		||||
        }
 | 
			
		||||
        if (expr.charAt(offset) == closeBrace) {
 | 
			
		||||
            return findTheBrace(expr, findTheBrace(expr, offset - 1) - 1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return findTheBrace(expr, offset - 1);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return findTheBrace(expr, offset - 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Walk expr backwards from offset looking for the beginning of an
 | 
			
		||||
// expression suitable for passing to eval.
 | 
			
		||||
// There is no guarantee of correct javascript syntax between the return
 | 
			
		||||
// value and offset.  This function is meant to take a string like
 | 
			
		||||
// "foo(Obj.We.Are.Completing" and allow you to extract "Obj.We.Are.Completing"
 | 
			
		||||
function getExpressionOffset(expr, offset) {
 | 
			
		||||
    while (offset >= 0) {
 | 
			
		||||
        let currChar = expr.charAt(offset);
 | 
			
		||||
 | 
			
		||||
        if (isStopChar(currChar)){
 | 
			
		||||
            return offset + 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (currChar.match(/[\)\]]/)) {
 | 
			
		||||
            offset = findMatchingBrace(expr, offset);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        --offset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return offset + 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Things with non-word characters or that start with a number
 | 
			
		||||
// are not accessible via .foo notation and so aren't returned
 | 
			
		||||
function isValidPropertyName(w) {
 | 
			
		||||
    return !(w.match(/\W/) || w.match(/^\d/));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// To get all properties (enumerable and not), we need to walk
 | 
			
		||||
// the prototype chain ourselves
 | 
			
		||||
function getAllProps(obj) {
 | 
			
		||||
    if (obj === null || obj === undefined) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    return Object.getOwnPropertyNames(obj).concat( getAllProps(Object.getPrototypeOf(obj)) );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Given a string _expr_, returns all methods
 | 
			
		||||
// that can be accessed via '.' notation.
 | 
			
		||||
// e.g., expr="({ foo: null, bar: null, 4: null })" will
 | 
			
		||||
// return ["foo", "bar", ...] but the list will not include "4",
 | 
			
		||||
// since methods accessed with '.' notation must star with a letter or _.
 | 
			
		||||
function getPropertyNamesFromExpression(expr, commandHeader) {
 | 
			
		||||
    if (commandHeader == null) {
 | 
			
		||||
        commandHeader = '';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let obj = {};
 | 
			
		||||
    if (!isUnsafeExpression(expr)) {
 | 
			
		||||
        try {
 | 
			
		||||
                obj = eval(commandHeader + expr);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let propsUnique = {};
 | 
			
		||||
    if (typeof obj === 'object'){
 | 
			
		||||
        let allProps = getAllProps(obj);
 | 
			
		||||
        // Get only things we are allowed to complete following a '.'
 | 
			
		||||
        allProps = allProps.filter( isValidPropertyName );
 | 
			
		||||
 | 
			
		||||
        // Make sure propsUnique contains one key for every
 | 
			
		||||
        // property so we end up with a unique list of properties
 | 
			
		||||
        allProps.map(function(p){ propsUnique[p] = null; });
 | 
			
		||||
    }
 | 
			
		||||
    return Object.keys(propsUnique).sort();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Given a list of words, returns the longest prefix they all have in common
 | 
			
		||||
function getCommonPrefix(words) {
 | 
			
		||||
    let word = words[0];
 | 
			
		||||
    for (let i = 0; i < word.length; i++) {
 | 
			
		||||
        for (let w = 1; w < words.length; w++) {
 | 
			
		||||
            if (words[w].charAt(i) != word.charAt(i))
 | 
			
		||||
                return word.slice(0, i);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return word;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns true if there is reason to think that eval(str)
 | 
			
		||||
// will modify the global scope
 | 
			
		||||
function isUnsafeExpression(str) {
 | 
			
		||||
    // Remove any blocks that are quoted or are in a regex
 | 
			
		||||
    function removeLiterals(str) {
 | 
			
		||||
        if (str.length == 0) {
 | 
			
		||||
            return '';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let currChar = str.charAt(str.length - 1);
 | 
			
		||||
        if (currChar == '"' || currChar == '\'') {
 | 
			
		||||
            return removeLiterals(str.slice(0, findMatchingQuote(str, str.length - 1)));
 | 
			
		||||
        } else if (currChar == '/') {
 | 
			
		||||
            return removeLiterals(str.slice(0, findMatchingSlash(str, str.length - 1)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return removeLiterals(str.slice(0, str.length - 1)) + currChar;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check for any sort of assignment
 | 
			
		||||
    // The strategy used is dumb: remove any quotes
 | 
			
		||||
    // or regexs and comparison operators and see if there is an '=' character.
 | 
			
		||||
    // If there is, it might be an unsafe assignment.
 | 
			
		||||
 | 
			
		||||
    let prunedStr = removeLiterals(str);
 | 
			
		||||
    prunedStr = prunedStr.replace(/[=!]==/g, '');    //replace === and !== with nothing
 | 
			
		||||
    prunedStr = prunedStr.replace(/[=<>!]=/g, '');    //replace ==, <=, >=, != with nothing
 | 
			
		||||
 | 
			
		||||
    if (prunedStr.match(/=/)) {
 | 
			
		||||
        return true;
 | 
			
		||||
    } else if (prunedStr.match(/;/)) {
 | 
			
		||||
        // If we contain a semicolon not inside of a quote/regex, assume we're unsafe as well
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a list of global keywords derived from str
 | 
			
		||||
function getDeclaredConstants(str) {
 | 
			
		||||
    let ret = [];
 | 
			
		||||
    str.split(';').forEach(function(s) {
 | 
			
		||||
        let base, keyword;
 | 
			
		||||
        let match = s.match(/const\s+(\w+)\s*=/);
 | 
			
		||||
        if (match) {
 | 
			
		||||
            [base, keyword] = match;
 | 
			
		||||
            ret.push(keyword);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										231
									
								
								js/misc/modemManager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,231 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
// The following are not the complete interfaces, just the methods we need
 | 
			
		||||
// (or may need in the future)
 | 
			
		||||
 | 
			
		||||
const ModemGsmNetworkInterface = <interface name="org.freedesktop.ModemManager.Modem.Gsm.Network">
 | 
			
		||||
<method name="GetRegistrationInfo">
 | 
			
		||||
    <arg type="u" direction="out" />
 | 
			
		||||
    <arg type="s" direction="out" />
 | 
			
		||||
    <arg type="s" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="GetSignalQuality">
 | 
			
		||||
    <arg type="u" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<property name="AccessTechnology" type="u" access="read" />
 | 
			
		||||
<signal name="SignalQuality">
 | 
			
		||||
    <arg type="u" direction="out" />
 | 
			
		||||
</signal>
 | 
			
		||||
<signal name="RegistrationInfo">
 | 
			
		||||
    <arg type="u" direction="out" />
 | 
			
		||||
    <arg type="s" direction="out" />
 | 
			
		||||
    <arg type="s" direction="out" />
 | 
			
		||||
</signal>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const ModemGsmNetworkProxy = Gio.DBusProxy.makeProxyWrapper(ModemGsmNetworkInterface);
 | 
			
		||||
 | 
			
		||||
const ModemCdmaInterface = <interface name="org.freedesktop.ModemManager.Modem.Cdma">
 | 
			
		||||
<method name="GetSignalQuality">
 | 
			
		||||
    <arg type="u" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="GetServingSystem">
 | 
			
		||||
    <arg type="u" direction="out" />
 | 
			
		||||
    <arg type="s" direction="out" />
 | 
			
		||||
    <arg type="u" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<signal name="SignalQuality">
 | 
			
		||||
    <arg type="u" direction="out" />
 | 
			
		||||
</signal>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const ModemCdmaProxy = Gio.DBusProxy.makeProxyWrapper(ModemCdmaInterface);
 | 
			
		||||
 | 
			
		||||
let _providersTable;
 | 
			
		||||
function _getProvidersTable() {
 | 
			
		||||
    if (_providersTable)
 | 
			
		||||
        return _providersTable;
 | 
			
		||||
    let [providers, countryCodes] = Shell.mobile_providers_parse();
 | 
			
		||||
    return _providersTable = providers;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ModemGsm = new Lang.Class({
 | 
			
		||||
    Name: 'ModemGsm',
 | 
			
		||||
 | 
			
		||||
    _init: function(path) {
 | 
			
		||||
        this._proxy = new ModemGsmNetworkProxy(Gio.DBus.system, 'org.freedesktop.ModemManager', path);
 | 
			
		||||
 | 
			
		||||
        this.signal_quality = 0;
 | 
			
		||||
        this.operator_name = null;
 | 
			
		||||
 | 
			
		||||
        // Code is duplicated because the function have different signatures
 | 
			
		||||
        this._proxy.connectSignal('SignalQuality', Lang.bind(this, function(proxy, sender, [quality]) {
 | 
			
		||||
            this.signal_quality = quality;
 | 
			
		||||
            this.emit('notify::signal-quality');
 | 
			
		||||
        }));
 | 
			
		||||
        this._proxy.connectSignal('RegistrationInfo', Lang.bind(this, function(proxy, sender, [status, code, name]) {
 | 
			
		||||
            this.operator_name = this._findOperatorName(name, code);
 | 
			
		||||
            this.emit('notify::operator-name');
 | 
			
		||||
        }));
 | 
			
		||||
        this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function(result, err) {
 | 
			
		||||
            if (err) {
 | 
			
		||||
                log(err);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let [status, code, name] = result;
 | 
			
		||||
            this.operator_name = this._findOperatorName(name, code);
 | 
			
		||||
            this.emit('notify::operator-name');
 | 
			
		||||
        }));
 | 
			
		||||
        this._proxy.GetSignalQualityRemote(Lang.bind(this, function(result, err) {
 | 
			
		||||
            if (err) {
 | 
			
		||||
                // it will return an error if the device is not connected
 | 
			
		||||
                this.signal_quality = 0;
 | 
			
		||||
            } else {
 | 
			
		||||
                let [quality] = result;
 | 
			
		||||
                this.signal_quality = quality;
 | 
			
		||||
            }
 | 
			
		||||
            this.emit('notify::signal-quality');
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _findOperatorName: function(name, opCode) {
 | 
			
		||||
        if (name.length != 0 && (name.length > 6 || name.length < 5)) {
 | 
			
		||||
            // this looks like a valid name, i.e. not an MCCMNC (that some
 | 
			
		||||
            // devices return when not yet connected
 | 
			
		||||
            return name;
 | 
			
		||||
        }
 | 
			
		||||
        if (isNaN(parseInt(name))) {
 | 
			
		||||
            // name is definitely not a MCCMNC, so it may be a name
 | 
			
		||||
            // after all; return that
 | 
			
		||||
            return name;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let needle;
 | 
			
		||||
        if (name.length == 0 && opCode)
 | 
			
		||||
            needle = opCode;
 | 
			
		||||
        else if (name.length == 6 || name.length == 5)
 | 
			
		||||
            needle = name;
 | 
			
		||||
        else // nothing to search
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
        return this._findProviderForMCCMNC(needle);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _findProviderForMCCMNC: function(needle) {
 | 
			
		||||
        let table = _getProvidersTable();
 | 
			
		||||
        let needlemcc = needle.substring(0, 3);
 | 
			
		||||
        let needlemnc = needle.substring(3, needle.length);
 | 
			
		||||
 | 
			
		||||
        let name2, name3;
 | 
			
		||||
        for (let iter in table) {
 | 
			
		||||
            let providers = table[iter];
 | 
			
		||||
 | 
			
		||||
            // Search through each country's providers
 | 
			
		||||
            for (let i = 0; i < providers.length; i++) {
 | 
			
		||||
                let provider = providers[i];
 | 
			
		||||
 | 
			
		||||
                // Search through MCC/MNC list
 | 
			
		||||
                let list = provider.get_gsm_mcc_mnc();
 | 
			
		||||
                for (let j = 0; j < list.length; j++) {
 | 
			
		||||
                    let mccmnc = list[j];
 | 
			
		||||
 | 
			
		||||
                    // Match both 2-digit and 3-digit MNC; prefer a
 | 
			
		||||
                    // 3-digit match if found, otherwise a 2-digit one.
 | 
			
		||||
                    if (mccmnc.mcc != needlemcc)
 | 
			
		||||
                        continue;  // MCC was wrong
 | 
			
		||||
 | 
			
		||||
                    if (!name3 && needle.length == 6 && needlemnc == mccmnc.mnc)
 | 
			
		||||
                        name3 = provider.name;
 | 
			
		||||
 | 
			
		||||
                    if (!name2 && needlemnc.substring(0, 2) == mccmnc.mnc.substring(0, 2))
 | 
			
		||||
                        name2 = provider.name;
 | 
			
		||||
 | 
			
		||||
                    if (name2 && name3)
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return name3 || name2 || null;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ModemGsm.prototype);
 | 
			
		||||
 | 
			
		||||
const ModemCdma = new Lang.Class({
 | 
			
		||||
    Name: 'ModemCdma',
 | 
			
		||||
 | 
			
		||||
    _init: function(path) {
 | 
			
		||||
        this._proxy = new ModemCdmaProxy(Gio.DBus.system, 'org.freedesktop.ModemManager', path);
 | 
			
		||||
 | 
			
		||||
        this.signal_quality = 0;
 | 
			
		||||
        this.operator_name = null;
 | 
			
		||||
        this._proxy.connect('SignalQuality', Lang.bind(this, function(proxy, sender, params) {
 | 
			
		||||
            this.signal_quality = params[0];
 | 
			
		||||
            this.emit('notify::signal-quality');
 | 
			
		||||
 | 
			
		||||
            // receiving this signal means the device got activated
 | 
			
		||||
            // and we can finally call GetServingSystem
 | 
			
		||||
            if (this.operator_name == null)
 | 
			
		||||
                this._refreshServingSystem();
 | 
			
		||||
        }));
 | 
			
		||||
        this._proxy.GetSignalQualityRemote(Lang.bind(this, function(result, err) {
 | 
			
		||||
            if (err) {
 | 
			
		||||
                // it will return an error if the device is not connected
 | 
			
		||||
                this.signal_quality = 0;
 | 
			
		||||
            } else {
 | 
			
		||||
                let [quality] = result;
 | 
			
		||||
                this.signal_quality = quality;
 | 
			
		||||
            }
 | 
			
		||||
            this.emit('notify::signal-quality');
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _refreshServingSystem: function() {
 | 
			
		||||
        this._proxy.GetServingSystemRemote(Lang.bind(this, function(result, err) {
 | 
			
		||||
            if (err) {
 | 
			
		||||
                // it will return an error if the device is not connected
 | 
			
		||||
                this.operator_name = null;
 | 
			
		||||
            } else {
 | 
			
		||||
                let [bandClass, band, id] = result;
 | 
			
		||||
                if (name.length > 0)
 | 
			
		||||
                    this.operator_name = this._findProviderForSid(id);
 | 
			
		||||
                else
 | 
			
		||||
                    this.operator_name = null;
 | 
			
		||||
            }
 | 
			
		||||
            this.emit('notify::operator-name');
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _findProviderForSid: function(sid) {
 | 
			
		||||
        if (sid == 0)
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
        let table = _getProvidersTable();
 | 
			
		||||
 | 
			
		||||
        // Search through each country
 | 
			
		||||
        for (let iter in table) {
 | 
			
		||||
            let providers = table[iter];
 | 
			
		||||
 | 
			
		||||
            // Search through each country's providers
 | 
			
		||||
            for (let i = 0; i < providers.length; i++) {
 | 
			
		||||
                let provider = providers[i];
 | 
			
		||||
                let cdma_sid = provider.get_cdma_sid();
 | 
			
		||||
 | 
			
		||||
                // Search through CDMA SID list
 | 
			
		||||
                for (let j = 0; j < cdma_sid.length; j++) {
 | 
			
		||||
                    if (cdma_sid[j] == sid)
 | 
			
		||||
                        return provider.name;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ModemCdma.prototype);
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
// parse:
 | 
			
		||||
// @params: caller-provided parameter object, or %null
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										48
									
								
								js/misc/screenSaver.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,48 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
 | 
			
		||||
const ScreenSaverIface = <interface name="org.gnome.ScreenSaver">
 | 
			
		||||
<method name="GetActive">
 | 
			
		||||
    <arg type="b" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="Lock" />
 | 
			
		||||
<method name="SetActive">
 | 
			
		||||
    <arg type="b" direction="in" />
 | 
			
		||||
</method>
 | 
			
		||||
<signal name="ActiveChanged">
 | 
			
		||||
    <arg type="b" direction="out" />
 | 
			
		||||
</signal>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const ScreenSaverInfo = Gio.DBusInterfaceInfo.new_for_xml(ScreenSaverIface);
 | 
			
		||||
 | 
			
		||||
function ScreenSaverProxy() {
 | 
			
		||||
    var self = new Gio.DBusProxy({ g_connection: Gio.DBus.session,
 | 
			
		||||
				   g_interface_name: ScreenSaverInfo.name,
 | 
			
		||||
				   g_interface_info: ScreenSaverInfo,
 | 
			
		||||
				   g_name: 'org.gnome.ScreenSaver',
 | 
			
		||||
				   g_object_path: '/org/gnome/ScreenSaver',
 | 
			
		||||
                                   g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
 | 
			
		||||
                                             Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
 | 
			
		||||
    self.init(null);
 | 
			
		||||
    self.screenSaverActive = false;
 | 
			
		||||
 | 
			
		||||
    self.connectSignal('ActiveChanged', function(proxy, senderName, [isActive]) {
 | 
			
		||||
        self.screenSaverActive = isActive;
 | 
			
		||||
    });
 | 
			
		||||
    self.connect('notify::g-name-owner', function() {
 | 
			
		||||
        if (self.g_name_owner) {
 | 
			
		||||
            self.GetActiveRemote(function(result, excp) {
 | 
			
		||||
                if (result) {
 | 
			
		||||
                    let [isActive] = result;
 | 
			
		||||
                    self.screenSaverActive = isActive;
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        } else
 | 
			
		||||
            self.screenSaverActive = false;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return self;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										168
									
								
								js/misc/util.js
									
									
									
									
									
								
							
							
						
						@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Gdk = imports.gi.Gdk;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
@@ -6,13 +6,33 @@ const GLib = imports.gi.GLib;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
// http://daringfireball.net/2010/07/improved_regex_for_matching_urls
 | 
			
		||||
const _balancedParens = '\\((?:[^\\s()<>]+|(?:\\(?:[^\\s()<>]+\\)))*\\)';
 | 
			
		||||
const _leadingJunk = '[\\s`(\\[{\'\\"<\u00AB\u201C\u2018]';
 | 
			
		||||
const _notTrailingJunk = '[^\\s`!()\\[\\]{};:\'\\".,<>?\u00AB\u00BB\u201C\u201D\u2018\u2019]';
 | 
			
		||||
 | 
			
		||||
/* http://daringfireball.net/2010/07/improved_regex_for_matching_urls */
 | 
			
		||||
const _urlRegexp = new RegExp('\\b(([a-z][\\w-]+:(/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)([^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:\'\\".,<>?«»“”‘’]))', 'gi');
 | 
			
		||||
const _urlRegexp = new RegExp(
 | 
			
		||||
    '(^|' + _leadingJunk + ')' +
 | 
			
		||||
    '(' +
 | 
			
		||||
        '(?:' +
 | 
			
		||||
            '[a-z][\\w-]+://' +                   // scheme://
 | 
			
		||||
            '|' +
 | 
			
		||||
            'www\\d{0,3}[.]' +                    // www.
 | 
			
		||||
            '|' +
 | 
			
		||||
            '[a-z0-9.\\-]+[.][a-z]{2,4}/' +       // foo.xx/
 | 
			
		||||
        ')' +
 | 
			
		||||
        '(?:' +                                   // one or more:
 | 
			
		||||
            '[^\\s()<>]+' +                       // run of non-space non-()
 | 
			
		||||
            '|' +                                 // or
 | 
			
		||||
            _balancedParens +                     // balanced parens
 | 
			
		||||
        ')+' +
 | 
			
		||||
        '(?:' +                                   // end with:
 | 
			
		||||
            _balancedParens +                     // balanced parens
 | 
			
		||||
            '|' +                                 // or
 | 
			
		||||
            _notTrailingJunk +                    // last non-junk char
 | 
			
		||||
        ')' +
 | 
			
		||||
    ')', 'gi');
 | 
			
		||||
 | 
			
		||||
// findUrls:
 | 
			
		||||
// @str: string to find URLs in
 | 
			
		||||
@@ -25,7 +45,7 @@ const _urlRegexp = new RegExp('\\b(([a-z][\\w-]+:(/{1,3}|[a-z0-9%])|www\\d{0,3}[
 | 
			
		||||
function findUrls(str) {
 | 
			
		||||
    let res = [], match;
 | 
			
		||||
    while ((match = _urlRegexp.exec(str)))
 | 
			
		||||
        res.push({ url: match[0], pos: match.index });
 | 
			
		||||
        res.push({ url: match[2], pos: match.index + match[1].length });
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -49,27 +69,13 @@ function spawn(argv) {
 | 
			
		||||
// occur when trying to parse or start the program.
 | 
			
		||||
function spawnCommandLine(command_line) {
 | 
			
		||||
    try {
 | 
			
		||||
        let [success, argc, argv] = GLib.shell_parse_argv(command_line);
 | 
			
		||||
        let [success, argv] = GLib.shell_parse_argv(command_line);
 | 
			
		||||
        trySpawn(argv);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
        _handleSpawnError(command_line, err);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// spawnDesktop:
 | 
			
		||||
// @id: a desktop file ID
 | 
			
		||||
//
 | 
			
		||||
// Spawns the desktop file identified by @id using startup notification,
 | 
			
		||||
// etc, handling any errors that occur when trying to find or start
 | 
			
		||||
// the program.
 | 
			
		||||
function spawnDesktop(id) {
 | 
			
		||||
    try {
 | 
			
		||||
        trySpawnDesktop(id);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
        _handleSpawnError(id, err);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// trySpawn:
 | 
			
		||||
// @argv: an argv array
 | 
			
		||||
//
 | 
			
		||||
@@ -103,10 +109,10 @@ function trySpawn(argv)
 | 
			
		||||
// Runs @command_line in the background. If launching @command_line
 | 
			
		||||
// fails, this will throw an error.
 | 
			
		||||
function trySpawnCommandLine(command_line) {
 | 
			
		||||
    let success, argc, argv;
 | 
			
		||||
    let success, argv;
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        [success, argc, argv] = GLib.shell_parse_argv(command_line);
 | 
			
		||||
        [success, argv] = GLib.shell_parse_argv(command_line);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
        // Replace "Error invoking GLib.shell_parse_argv: " with
 | 
			
		||||
        // something nicer
 | 
			
		||||
@@ -117,41 +123,9 @@ function trySpawnCommandLine(command_line) {
 | 
			
		||||
    trySpawn(argv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// trySpawnDesktop:
 | 
			
		||||
// @id: a desktop file ID
 | 
			
		||||
//
 | 
			
		||||
// Spawns the desktop file identified by @id using startup notification.
 | 
			
		||||
// On error, throws an exception.
 | 
			
		||||
function trySpawnDesktop(id) {
 | 
			
		||||
    let app;
 | 
			
		||||
 | 
			
		||||
    // shell_app_system_load_from_desktop_file() will end up returning
 | 
			
		||||
    // a stupid error message if the desktop file doesn't exist, but
 | 
			
		||||
    // that's the only case it returns an error for, so we just
 | 
			
		||||
    // substitute our own error in instead
 | 
			
		||||
    try {
 | 
			
		||||
        app = Shell.AppSystem.get_default().load_from_desktop_file(id + '.desktop');
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
        throw new Error(_("No such application"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        app.launch();
 | 
			
		||||
    } catch(err) {
 | 
			
		||||
        // see trySpawn
 | 
			
		||||
        err.message = err.message.replace(/.*\((.+)\)/, '$1');
 | 
			
		||||
        throw err;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _handleSpawnError(command, err) {
 | 
			
		||||
    let title = _("Execution of '%s' failed:").format(command);
 | 
			
		||||
 | 
			
		||||
    let source = new MessageTray.SystemNotificationSource();
 | 
			
		||||
    Main.messageTray.add(source);
 | 
			
		||||
    let notification = new MessageTray.Notification(source, title, err.message);
 | 
			
		||||
    notification.setTransient(true);
 | 
			
		||||
    source.notify(notification);
 | 
			
		||||
    Main.notifyError(title, err.message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// killall:
 | 
			
		||||
@@ -178,3 +152,83 @@ function killall(processName) {
 | 
			
		||||
        logError(e, 'Failed to kill ' + processName);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This was ported from network-manager-applet
 | 
			
		||||
// Copyright 2007 - 2011 Red Hat, Inc.
 | 
			
		||||
// Author: Dan Williams <dcbw@redhat.com>
 | 
			
		||||
 | 
			
		||||
const _IGNORED_WORDS = [
 | 
			
		||||
        'Semiconductor',
 | 
			
		||||
        'Components',
 | 
			
		||||
        'Corporation',
 | 
			
		||||
        'Communications',
 | 
			
		||||
        'Company',
 | 
			
		||||
        'Corp.',
 | 
			
		||||
        'Corp',
 | 
			
		||||
        'Co.',
 | 
			
		||||
        'Inc.',
 | 
			
		||||
        'Inc',
 | 
			
		||||
        'Incorporated',
 | 
			
		||||
        'Ltd.',
 | 
			
		||||
        'Limited.',
 | 
			
		||||
        'Intel',
 | 
			
		||||
        'chipset',
 | 
			
		||||
        'adapter',
 | 
			
		||||
        '[hex]',
 | 
			
		||||
        'NDIS',
 | 
			
		||||
        'Module'
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const _IGNORED_PHRASES = [
 | 
			
		||||
        'Multiprotocol MAC/baseband processor',
 | 
			
		||||
        'Wireless LAN Controller',
 | 
			
		||||
        'Wireless LAN Adapter',
 | 
			
		||||
        'Wireless Adapter',
 | 
			
		||||
        'Network Connection',
 | 
			
		||||
        'Wireless Cardbus Adapter',
 | 
			
		||||
        'Wireless CardBus Adapter',
 | 
			
		||||
        '54 Mbps Wireless PC Card',
 | 
			
		||||
        'Wireless PC Card',
 | 
			
		||||
        'Wireless PC',
 | 
			
		||||
        'PC Card with XJACK(r) Antenna',
 | 
			
		||||
        'Wireless cardbus',
 | 
			
		||||
        'Wireless LAN PC Card',
 | 
			
		||||
        'Technology Group Ltd.',
 | 
			
		||||
        'Communication S.p.A.',
 | 
			
		||||
        'Business Mobile Networks BV',
 | 
			
		||||
        'Mobile Broadband Minicard Composite Device',
 | 
			
		||||
        'Mobile Communications AB',
 | 
			
		||||
        '(PC-Suite Mode)'
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
function fixupPCIDescription(desc) {
 | 
			
		||||
    desc = desc.replace(/[_,]/, ' ');
 | 
			
		||||
 | 
			
		||||
    /* Attempt to shorten ID by ignoring certain phrases */
 | 
			
		||||
    for (let i = 0; i < _IGNORED_PHRASES.length; i++) {
 | 
			
		||||
        let item = _IGNORED_PHRASES[i];
 | 
			
		||||
        let pos = desc.indexOf(item);
 | 
			
		||||
        if (pos != -1) {
 | 
			
		||||
            let before = desc.substring(0, pos);
 | 
			
		||||
            let after = desc.substring(pos + item.length, desc.length);
 | 
			
		||||
            desc = before + after;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Attmept to shorten ID by ignoring certain individual words */
 | 
			
		||||
    let words = desc.split(' ');
 | 
			
		||||
    let out = [ ];
 | 
			
		||||
    for (let i = 0; i < words.length; i++) {
 | 
			
		||||
        let item = words[i];
 | 
			
		||||
 | 
			
		||||
        // skip empty items (that come out from consecutive spaces)
 | 
			
		||||
        if (item.length == 0)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        if (_IGNORED_WORDS.indexOf(item) == -1) {
 | 
			
		||||
            out.push(item);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return out.join(' ');
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Scripting = imports.ui.scripting;
 | 
			
		||||
@@ -21,26 +21,77 @@ let METRICS = {
 | 
			
		||||
    overviewFpsSubsequent:
 | 
			
		||||
    { description: "Frames rate when going to the overview, second time",
 | 
			
		||||
      units: "frames / s" },
 | 
			
		||||
    overviewFps5Windows:
 | 
			
		||||
    { description: "Frames rate when going to the overview, 5 windows open",
 | 
			
		||||
      units: "frames / s" },
 | 
			
		||||
    overviewFps10Windows:
 | 
			
		||||
    { description: "Frames rate when going to the overview, 10 windows open",
 | 
			
		||||
      units: "frames / s" },
 | 
			
		||||
    overviewFps5Maximized:
 | 
			
		||||
    { description: "Frames rate when going to the overview, 5 maximized windows open",
 | 
			
		||||
      units: "frames / s" },
 | 
			
		||||
    overviewFps10Maximized:
 | 
			
		||||
    { description: "Frames rate when going to the overview, 10 maximized windows open",
 | 
			
		||||
      units: "frames / s" },
 | 
			
		||||
    overviewFps5Alpha:
 | 
			
		||||
    { description: "Frames rate when going to the overview, 5 alpha-transparent windows open",
 | 
			
		||||
      units: "frames / s" },
 | 
			
		||||
    overviewFps10Alpha:
 | 
			
		||||
    { description: "Frames rate when going to the overview, 10 alpha-transparent windows open",
 | 
			
		||||
      units: "frames / s" },
 | 
			
		||||
    usedAfterOverview:
 | 
			
		||||
    { description: "Malloc'ed bytes after the overview is shown once",
 | 
			
		||||
      units: "B" },
 | 
			
		||||
    leakedAfterOverview:
 | 
			
		||||
    { description: "Additional malloc'ed bytes the second time the overview is shown",
 | 
			
		||||
      units: "B" }
 | 
			
		||||
      units: "B" },
 | 
			
		||||
    applicationsShowTimeFirst:
 | 
			
		||||
    { description: "Time to switch to applications view, first time",
 | 
			
		||||
      units: "us" },
 | 
			
		||||
    applicationsShowTimeSubsequent:
 | 
			
		||||
    { description: "Time to switch to applications view, second time",
 | 
			
		||||
      units: "us"}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let WINDOW_CONFIGS = [
 | 
			
		||||
    { width: 640, height: 480, alpha: false, maximized: false, count: 1,  metric: 'overviewFpsSubsequent' },
 | 
			
		||||
    { width: 640, height: 480, alpha: false, maximized: false, count: 5,  metric: 'overviewFps5Windows'  },
 | 
			
		||||
    { width: 640, height: 480, alpha: false, maximized: false, count: 10, metric: 'overviewFps10Windows'  },
 | 
			
		||||
    { width: 640, height: 480, alpha: false, maximized: true,  count: 5,  metric: 'overviewFps5Maximized' },
 | 
			
		||||
    { width: 640, height: 480, alpha: false, maximized: true,  count: 10, metric: 'overviewFps10Maximized' },
 | 
			
		||||
    { width: 640, height: 480, alpha: true,  maximized: false, count: 5,  metric: 'overviewFps5Alpha' },
 | 
			
		||||
    { width: 640, height: 480, alpha: true,  maximized: false, count: 10, metric: 'overviewFps10Alpha' }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
function run() {
 | 
			
		||||
    Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
 | 
			
		||||
    Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing");
 | 
			
		||||
    Scripting.defineScriptEvent("afterShowHide", "After a show/hide cycle for the overview");
 | 
			
		||||
    Scripting.defineScriptEvent("applicationsShowStart", "Starting to switch to applications view");
 | 
			
		||||
    Scripting.defineScriptEvent("applicationsShowDone", "Done switching to applications view");
 | 
			
		||||
 | 
			
		||||
    Main.overview.connect('shown', function() {
 | 
			
		||||
                              Scripting.scriptEvent('overviewShowDone');
 | 
			
		||||
                          });
 | 
			
		||||
 | 
			
		||||
    yield Scripting.sleep(1000);
 | 
			
		||||
    yield Scripting.waitLeisure();
 | 
			
		||||
    for (let i = 0; i < 2; i++) {
 | 
			
		||||
 | 
			
		||||
    for (let i = 0; i < 2 * WINDOW_CONFIGS.length; i++) {
 | 
			
		||||
        // We go to the overview twice for each configuration; the first time
 | 
			
		||||
        // to calculate the mipmaps for the windows, the second time to get
 | 
			
		||||
        // a clean set of numbers.
 | 
			
		||||
        if ((i % 2) == 0) {
 | 
			
		||||
            let config = WINDOW_CONFIGS[i / 2];
 | 
			
		||||
            yield Scripting.destroyTestWindows();
 | 
			
		||||
 | 
			
		||||
            for (let k = 0; k < config.count; k++)
 | 
			
		||||
                yield Scripting.createTestWindow(config.width, config.height, config.alpha, config.maximized);
 | 
			
		||||
 | 
			
		||||
            yield Scripting.waitTestWindows();
 | 
			
		||||
            yield Scripting.sleep(1000);
 | 
			
		||||
            yield Scripting.waitLeisure();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Scripting.scriptEvent('overviewShowStart');
 | 
			
		||||
        Main.overview.show();
 | 
			
		||||
 | 
			
		||||
@@ -53,6 +104,21 @@ function run() {
 | 
			
		||||
        Scripting.collectStatistics();
 | 
			
		||||
        Scripting.scriptEvent('afterShowHide');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    yield Scripting.destroyTestWindows();
 | 
			
		||||
    yield Scripting.sleep(1000);
 | 
			
		||||
 | 
			
		||||
    Main.overview.show();
 | 
			
		||||
    yield Scripting.waitLeisure();
 | 
			
		||||
 | 
			
		||||
    for (let i = 0; i < 2; i++) {
 | 
			
		||||
        Scripting.scriptEvent('applicationsShowStart');
 | 
			
		||||
        Main.overview._viewSelector.switchTab('applications');
 | 
			
		||||
        yield Scripting.waitLeisure();
 | 
			
		||||
        Scripting.scriptEvent('applicationsShowDone');
 | 
			
		||||
        Main.overview._viewSelector.switchTab('windows');
 | 
			
		||||
        yield Scripting.waitLeisure();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let showingOverview = false;
 | 
			
		||||
@@ -64,6 +130,8 @@ let mallocUsedSize = 0;
 | 
			
		||||
let overviewShowCount = 0;
 | 
			
		||||
let firstOverviewUsedSize;
 | 
			
		||||
let haveSwapComplete = false;
 | 
			
		||||
let applicationsShowStart;
 | 
			
		||||
let applicationsShowCount = 0;
 | 
			
		||||
 | 
			
		||||
function script_overviewShowStart(time) {
 | 
			
		||||
    showingOverview = true;
 | 
			
		||||
@@ -79,6 +147,18 @@ function script_overviewShowDone(time) {
 | 
			
		||||
    finishedShowingOverview = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function script_applicationsShowStart(time) {
 | 
			
		||||
    applicationsShowStart = time;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function script_applicationsShowDone(time) {
 | 
			
		||||
    applicationsShowCount++;
 | 
			
		||||
    if (applicationsShowCount == 1)
 | 
			
		||||
        METRICS.applicationsShowTimeFirst.value = time - applicationsShowStart;
 | 
			
		||||
    else
 | 
			
		||||
        METRICS.applicationsShowTimeSubsequent.value = time - applicationsShowStart;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function script_afterShowHide(time) {
 | 
			
		||||
    if (overviewShowCount == 1) {
 | 
			
		||||
        METRICS.usedAfterOverview.value = mallocUsedSize;
 | 
			
		||||
@@ -113,9 +193,15 @@ function _frameDone(time) {
 | 
			
		||||
        if (overviewShowCount == 1) {
 | 
			
		||||
            METRICS.overviewLatencyFirst.value = overviewLatency;
 | 
			
		||||
            METRICS.overviewFpsFirst.value = fps;
 | 
			
		||||
        } else {
 | 
			
		||||
        } else if (overviewShowCount == 2) {
 | 
			
		||||
            METRICS.overviewLatencySubsequent.value = overviewLatency;
 | 
			
		||||
            METRICS.overviewFpsSubsequent.value = fps;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Other than overviewFpsFirst, we collect FPS metrics the second
 | 
			
		||||
        // we show each window configuration. overviewShowCount is 1,2,3...
 | 
			
		||||
        if (overviewShowCount % 2 == 0) {
 | 
			
		||||
            let config = WINDOW_CONFIGS[(overviewShowCount / 2) - 1];
 | 
			
		||||
            METRICS[config.metric].value = fps;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										290
									
								
								js/ui/altTab.js
									
									
									
									
									
								
							
							
						
						@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gdk = imports.gi.Gdk;
 | 
			
		||||
@@ -14,7 +14,8 @@ const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
const POPUP_APPICON_SIZE = 96;
 | 
			
		||||
const POPUP_SCROLL_TIME = 0.10; // seconds
 | 
			
		||||
const POPUP_FADE_TIME = 0.1; // seconds
 | 
			
		||||
const POPUP_DELAY_TIMEOUT = 150; // milliseconds
 | 
			
		||||
const POPUP_FADE_OUT_TIME = 0.1; // seconds
 | 
			
		||||
 | 
			
		||||
const APP_ICON_HOVER_TIMEOUT = 200; // milliseconds
 | 
			
		||||
 | 
			
		||||
@@ -30,11 +31,21 @@ function mod(a, b) {
 | 
			
		||||
    return (a + b) % b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function AltTabPopup() {
 | 
			
		||||
    this._init();
 | 
			
		||||
function primaryModifier(mask) {
 | 
			
		||||
    if (mask == 0)
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
    let primary = 1;
 | 
			
		||||
    while (mask > 1) {
 | 
			
		||||
        mask >>= 1;
 | 
			
		||||
        primary <<= 1;
 | 
			
		||||
    }
 | 
			
		||||
    return primary;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AltTabPopup.prototype = {
 | 
			
		||||
const AltTabPopup = new Lang.Class({
 | 
			
		||||
    Name: 'AltTabPopup',
 | 
			
		||||
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        this.actor = new Shell.GenericContainer({ name: 'altTabPopup',
 | 
			
		||||
                                                  reactive: true,
 | 
			
		||||
@@ -47,11 +58,13 @@ AltTabPopup.prototype = {
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 | 
			
		||||
 | 
			
		||||
        this._haveModal = false;
 | 
			
		||||
        this._modifierMask = 0;
 | 
			
		||||
 | 
			
		||||
        this._currentApp = 0;
 | 
			
		||||
        this._currentWindow = -1;
 | 
			
		||||
        this._thumbnailTimeoutId = 0;
 | 
			
		||||
        this._motionTimeoutId = 0;
 | 
			
		||||
        this._initialDelayTimeoutId = 0;
 | 
			
		||||
 | 
			
		||||
        this.thumbnailsVisible = false;
 | 
			
		||||
 | 
			
		||||
@@ -74,7 +87,7 @@ AltTabPopup.prototype = {
 | 
			
		||||
 | 
			
		||||
    _allocate: function (actor, box, flags) {
 | 
			
		||||
        let childBox = new Clutter.ActorBox();
 | 
			
		||||
        let primary = global.get_primary_monitor();
 | 
			
		||||
        let primary = Main.layoutManager.primaryMonitor;
 | 
			
		||||
 | 
			
		||||
        let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
 | 
			
		||||
        let rightPadding = this.actor.get_theme_node().get_padding(St.Side.RIGHT);
 | 
			
		||||
@@ -87,7 +100,7 @@ AltTabPopup.prototype = {
 | 
			
		||||
        let [childMinHeight, childNaturalHeight] = this._appSwitcher.actor.get_preferred_height(primary.width - hPadding);
 | 
			
		||||
        let [childMinWidth, childNaturalWidth] = this._appSwitcher.actor.get_preferred_width(childNaturalHeight);
 | 
			
		||||
        childBox.x1 = Math.max(primary.x + leftPadding, primary.x + Math.floor((primary.width - childNaturalWidth) / 2));
 | 
			
		||||
        childBox.x2 = Math.min(childBox.x1 + primary.width - hPadding, childBox.x1 + childNaturalWidth);
 | 
			
		||||
        childBox.x2 = Math.min(primary.x + primary.width - rightPadding, childBox.x1 + childNaturalWidth);
 | 
			
		||||
        childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
 | 
			
		||||
        childBox.y2 = childBox.y1 + childNaturalHeight;
 | 
			
		||||
        this._appSwitcher.actor.allocate(childBox, flags);
 | 
			
		||||
@@ -97,8 +110,6 @@ AltTabPopup.prototype = {
 | 
			
		||||
        // those calculations
 | 
			
		||||
        if (this._thumbnails) {
 | 
			
		||||
            let icon = this._appIcons[this._currentApp].actor;
 | 
			
		||||
            // Force a stage relayout to make sure we get the correct position
 | 
			
		||||
            global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, 0, 0);
 | 
			
		||||
            let [posX, posY] = icon.get_transformed_position();
 | 
			
		||||
            let thumbnailCenter = posX + icon.width / 2;
 | 
			
		||||
            let [childMinWidth, childNaturalWidth] = this._thumbnails.actor.get_preferred_width(-1);
 | 
			
		||||
@@ -121,16 +132,50 @@ AltTabPopup.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show : function(backward, switch_group) {
 | 
			
		||||
    _getAppLists: function() {
 | 
			
		||||
        let tracker = Shell.WindowTracker.get_default();
 | 
			
		||||
        let apps = tracker.get_running_apps ('');
 | 
			
		||||
        let appSys = Shell.AppSystem.get_default();
 | 
			
		||||
        let allApps = appSys.get_running ();
 | 
			
		||||
 | 
			
		||||
        if (!apps.length)
 | 
			
		||||
        let screen = global.screen;
 | 
			
		||||
        let display = screen.get_display();
 | 
			
		||||
        let windows = display.get_tab_list(Meta.TabList.NORMAL, screen,
 | 
			
		||||
                                           screen.get_active_workspace());
 | 
			
		||||
 | 
			
		||||
        // windows is only the windows on the current workspace. For
 | 
			
		||||
        // each one, if it corresponds to an app we know, move that
 | 
			
		||||
        // app from allApps to apps.
 | 
			
		||||
        let apps = [];
 | 
			
		||||
        for (let i = 0; i < windows.length && allApps.length != 0; i++) {
 | 
			
		||||
            let app = tracker.get_window_app(windows[i]);
 | 
			
		||||
            let index = allApps.indexOf(app);
 | 
			
		||||
            if (index != -1) {
 | 
			
		||||
                apps.push(app);
 | 
			
		||||
                allApps.splice(index, 1);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Now @apps is a list of apps on the current workspace, in
 | 
			
		||||
        // standard Alt+Tab order (MRU except for minimized windows),
 | 
			
		||||
        // and allApps is a list of apps that only appear on other
 | 
			
		||||
        // workspaces, sorted by user_time, which is good enough.
 | 
			
		||||
        return [apps, allApps];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show : function(backward, binding, mask) {
 | 
			
		||||
        let [localApps, otherApps] = this._getAppLists();
 | 
			
		||||
 | 
			
		||||
        if (localApps.length == 0 && otherApps.length == 0)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (!Main.pushModal(this.actor))
 | 
			
		||||
            return false;
 | 
			
		||||
        if (!Main.pushModal(this.actor)) {
 | 
			
		||||
            // Probably someone else has a pointer grab, try again with keyboard only
 | 
			
		||||
            if (!Main.pushModal(this.actor, global.get_current_time(), Meta.ModalOptions.POINTER_ALREADY_GRABBED)) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        this._haveModal = true;
 | 
			
		||||
        this._modifierMask = primaryModifier(mask);
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
 | 
			
		||||
        this.actor.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
 | 
			
		||||
@@ -138,15 +183,21 @@ AltTabPopup.prototype = {
 | 
			
		||||
        this.actor.connect('button-press-event', Lang.bind(this, this._clickedOutside));
 | 
			
		||||
        this.actor.connect('scroll-event', Lang.bind(this, this._onScroll));
 | 
			
		||||
 | 
			
		||||
        this._appSwitcher = new AppSwitcher(apps, this);
 | 
			
		||||
        this._appSwitcher = new AppSwitcher(localApps, otherApps, this);
 | 
			
		||||
        this.actor.add_actor(this._appSwitcher.actor);
 | 
			
		||||
        this._appSwitcher.connect('item-activated', Lang.bind(this, this._appActivated));
 | 
			
		||||
        this._appSwitcher.connect('item-entered', Lang.bind(this, this._appEntered));
 | 
			
		||||
 | 
			
		||||
        this._appIcons = this._appSwitcher.icons;
 | 
			
		||||
 | 
			
		||||
        // Need to force an allocation so we can figure out whether we
 | 
			
		||||
        // need to scroll when selecting
 | 
			
		||||
        this.actor.opacity = 0;
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
        this.actor.get_allocation_box();
 | 
			
		||||
 | 
			
		||||
        // Make the initial selection
 | 
			
		||||
        if (switch_group) {
 | 
			
		||||
        if (binding == 'switch-group') {
 | 
			
		||||
            if (backward) {
 | 
			
		||||
                this._select(0, this._appIcons[0].cachedWindows.length - 1);
 | 
			
		||||
            } else {
 | 
			
		||||
@@ -155,30 +206,16 @@ AltTabPopup.prototype = {
 | 
			
		||||
                else
 | 
			
		||||
                    this._select(0, 0);
 | 
			
		||||
            }
 | 
			
		||||
        } else if (binding == 'switch-group-backward') {
 | 
			
		||||
            this._select(0, this._appIcons[0].cachedWindows.length - 1);
 | 
			
		||||
        } else if (binding == 'switch-windows-backward') {
 | 
			
		||||
            this._select(this._appIcons.length - 1);
 | 
			
		||||
        } else if (this._appIcons.length == 1) {
 | 
			
		||||
            if (!backward && this._appIcons[0].cachedWindows.length > 1) {
 | 
			
		||||
                // For compatibility with the multi-app case below
 | 
			
		||||
                this._select(0, 1, true);
 | 
			
		||||
            } else
 | 
			
		||||
                this._select(0);
 | 
			
		||||
            this._select(0);
 | 
			
		||||
        } else if (backward) {
 | 
			
		||||
            this._select(this._appIcons.length - 1);
 | 
			
		||||
        } else {
 | 
			
		||||
            let firstWindows = this._appIcons[0].cachedWindows;
 | 
			
		||||
            if (firstWindows.length > 1) {
 | 
			
		||||
                let curAppNextWindow = firstWindows[1];
 | 
			
		||||
                let nextAppWindow = this._appIcons[1].cachedWindows[0];
 | 
			
		||||
 | 
			
		||||
                // If the next window of the current app is more-recently-used
 | 
			
		||||
                // than the first window of the next app, then select it.
 | 
			
		||||
                if (curAppNextWindow.get_workspace() == global.screen.get_active_workspace() &&
 | 
			
		||||
                    curAppNextWindow.get_user_time() > nextAppWindow.get_user_time())
 | 
			
		||||
                    this._select(0, 1, true);
 | 
			
		||||
                else
 | 
			
		||||
                    this._select(1);
 | 
			
		||||
            } else {
 | 
			
		||||
                this._select(1);
 | 
			
		||||
            }
 | 
			
		||||
            this._select(1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // There's a race condition; if the user released Alt before
 | 
			
		||||
@@ -187,18 +224,18 @@ AltTabPopup.prototype = {
 | 
			
		||||
        // details.) So we check now. (Have to do this after updating
 | 
			
		||||
        // selection.)
 | 
			
		||||
        let [x, y, mods] = global.get_pointer();
 | 
			
		||||
        if (!(mods & Gdk.ModifierType.MOD1_MASK)) {
 | 
			
		||||
        if (!(mods & this._modifierMask)) {
 | 
			
		||||
            this._finish();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.actor.opacity = 0;
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
        Tweener.addTween(this.actor,
 | 
			
		||||
                         { opacity: 255,
 | 
			
		||||
                           time: POPUP_FADE_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad'
 | 
			
		||||
                         });
 | 
			
		||||
        // We delay showing the popup so that fast Alt+Tab users aren't
 | 
			
		||||
        // disturbed by the popup briefly flashing.
 | 
			
		||||
        this._initialDelayTimeoutId = Mainloop.timeout_add(POPUP_DELAY_TIMEOUT,
 | 
			
		||||
                                                           Lang.bind(this, function () {
 | 
			
		||||
                                                               this.actor.opacity = 255;
 | 
			
		||||
                                                               this._initialDelayTimeoutId = 0;
 | 
			
		||||
                                                           }));
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
@@ -229,37 +266,29 @@ AltTabPopup.prototype = {
 | 
			
		||||
        let keysym = event.get_key_symbol();
 | 
			
		||||
        let event_state = Shell.get_event_state(event);
 | 
			
		||||
        let backwards = event_state & Clutter.ModifierType.SHIFT_MASK;
 | 
			
		||||
        let action = global.screen.get_display().get_keybinding_action(event.get_key_code(), event_state);
 | 
			
		||||
        let action = global.display.get_keybinding_action(event.get_key_code(), event_state);
 | 
			
		||||
 | 
			
		||||
        this._disableHover();
 | 
			
		||||
 | 
			
		||||
        if (action == Meta.KeyBindingAction.SWITCH_GROUP)
 | 
			
		||||
            this._select(this._currentApp, backwards ? this._previousWindow() : this._nextWindow());
 | 
			
		||||
        else if (keysym == Clutter.Escape)
 | 
			
		||||
        if (keysym == Clutter.Escape) {
 | 
			
		||||
            this.destroy();
 | 
			
		||||
        else if (this._thumbnailsFocused) {
 | 
			
		||||
            if (action == Meta.KeyBindingAction.SWITCH_WINDOWS)
 | 
			
		||||
                if (backwards) {
 | 
			
		||||
                    if (this._currentWindow == 0 || this._currentWindow == -1)
 | 
			
		||||
                        this._select(this._previousApp());
 | 
			
		||||
                    else
 | 
			
		||||
                        this._select(this._currentApp, this._previousWindow());
 | 
			
		||||
                } else {
 | 
			
		||||
                    if (this._currentWindow == this._appIcons[this._currentApp].cachedWindows.length - 1)
 | 
			
		||||
                        this._select(this._nextApp());
 | 
			
		||||
                    else
 | 
			
		||||
                        this._select(this._currentApp, this._nextWindow());
 | 
			
		||||
                }
 | 
			
		||||
            else if (keysym == Clutter.Left)
 | 
			
		||||
        } else if (action == Meta.KeyBindingAction.SWITCH_GROUP) {
 | 
			
		||||
            this._select(this._currentApp, backwards ? this._previousWindow() : this._nextWindow());
 | 
			
		||||
        } else if (action == Meta.KeyBindingAction.SWITCH_GROUP_BACKWARD) {
 | 
			
		||||
            this._select(this._currentApp, this._previousWindow());
 | 
			
		||||
        } else if (action == Meta.KeyBindingAction.SWITCH_WINDOWS) {
 | 
			
		||||
            this._select(backwards ? this._previousApp() : this._nextApp());
 | 
			
		||||
        } else if (action == Meta.KeyBindingAction.SWITCH_WINDOWS_BACKWARD) {
 | 
			
		||||
            this._select(this._previousApp());
 | 
			
		||||
        } else if (this._thumbnailsFocused) {
 | 
			
		||||
            if (keysym == Clutter.Left)
 | 
			
		||||
                this._select(this._currentApp, this._previousWindow());
 | 
			
		||||
            else if (keysym == Clutter.Right)
 | 
			
		||||
                this._select(this._currentApp, this._nextWindow());
 | 
			
		||||
            else if (keysym == Clutter.Up)
 | 
			
		||||
                this._select(this._currentApp, null, true);
 | 
			
		||||
        } else {
 | 
			
		||||
            if (action == Meta.KeyBindingAction.SWITCH_WINDOWS)
 | 
			
		||||
                this._select(backwards ? this._previousApp() : this._nextApp());
 | 
			
		||||
            else if (keysym == Clutter.Left)
 | 
			
		||||
            if (keysym == Clutter.Left)
 | 
			
		||||
                this._select(this._previousApp());
 | 
			
		||||
            else if (keysym == Clutter.Right)
 | 
			
		||||
                this._select(this._nextApp());
 | 
			
		||||
@@ -272,7 +301,7 @@ AltTabPopup.prototype = {
 | 
			
		||||
 | 
			
		||||
    _keyReleaseEvent : function(actor, event) {
 | 
			
		||||
        let [x, y, mods] = global.get_pointer();
 | 
			
		||||
        let state = mods & Clutter.ModifierType.MOD1_MASK;
 | 
			
		||||
        let state = mods & this._modifierMask;
 | 
			
		||||
 | 
			
		||||
        if (state == 0)
 | 
			
		||||
            this._finish();
 | 
			
		||||
@@ -376,11 +405,19 @@ AltTabPopup.prototype = {
 | 
			
		||||
        this.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _popModal: function() {
 | 
			
		||||
        if (this._haveModal) {
 | 
			
		||||
            Main.popModal(this.actor);
 | 
			
		||||
            this._haveModal = false;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy : function() {
 | 
			
		||||
        this._popModal();
 | 
			
		||||
        if (this.actor.visible) {
 | 
			
		||||
            Tweener.addTween(this.actor,
 | 
			
		||||
                             { opacity: 0,
 | 
			
		||||
                               time: POPUP_FADE_TIME,
 | 
			
		||||
                               time: POPUP_FADE_OUT_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad',
 | 
			
		||||
                               onComplete: Lang.bind(this,
 | 
			
		||||
                                   function() {
 | 
			
		||||
@@ -392,8 +429,7 @@ AltTabPopup.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDestroy : function() {
 | 
			
		||||
        if (this._haveModal)
 | 
			
		||||
            Main.popModal(this.actor);
 | 
			
		||||
        this._popModal();
 | 
			
		||||
 | 
			
		||||
        if (this._thumbnails)
 | 
			
		||||
            this._destroyThumbnails();
 | 
			
		||||
@@ -402,6 +438,8 @@ AltTabPopup.prototype = {
 | 
			
		||||
            Mainloop.source_remove(this._motionTimeoutId);
 | 
			
		||||
        if (this._thumbnailTimeoutId != 0)
 | 
			
		||||
            Mainloop.source_remove(this._thumbnailTimeoutId);
 | 
			
		||||
        if (this._initialDelayTimeoutId != 0)
 | 
			
		||||
            Mainloop.source_remove(this._initialDelayTimeoutId);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -488,6 +526,10 @@ AltTabPopup.prototype = {
 | 
			
		||||
 | 
			
		||||
        this.actor.add_actor(this._thumbnails.actor);
 | 
			
		||||
 | 
			
		||||
        // Need to force an allocation so we can figure out whether we
 | 
			
		||||
        // need to scroll when selecting
 | 
			
		||||
        this._thumbnails.actor.get_allocation_box();
 | 
			
		||||
 | 
			
		||||
        this._thumbnails.actor.opacity = 0;
 | 
			
		||||
        Tweener.addTween(this._thumbnails.actor,
 | 
			
		||||
                         { opacity: 255,
 | 
			
		||||
@@ -496,13 +538,11 @@ AltTabPopup.prototype = {
 | 
			
		||||
                           onComplete: Lang.bind(this, function () { this.thumbnailsVisible = true; })
 | 
			
		||||
                         });
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function SwitcherList(squareItems) {
 | 
			
		||||
    this._init(squareItems);
 | 
			
		||||
}
 | 
			
		||||
const SwitcherList = new Lang.Class({
 | 
			
		||||
    Name: 'SwitcherList',
 | 
			
		||||
 | 
			
		||||
SwitcherList.prototype = {
 | 
			
		||||
    _init : function(squareItems) {
 | 
			
		||||
        this.actor = new Shell.GenericContainer({ style_class: 'switcher-list' });
 | 
			
		||||
        this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
 | 
			
		||||
@@ -594,7 +634,7 @@ SwitcherList.prototype = {
 | 
			
		||||
        this._rightArrow.opacity = this._rightGradient.opacity;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addItem : function(item) {
 | 
			
		||||
    addItem : function(item, label) {
 | 
			
		||||
        let bbox = new St.Button({ style_class: 'item-box',
 | 
			
		||||
                                   reactive: true });
 | 
			
		||||
 | 
			
		||||
@@ -605,6 +645,8 @@ SwitcherList.prototype = {
 | 
			
		||||
        bbox.connect('clicked', Lang.bind(this, function() { this._onItemClicked(n); }));
 | 
			
		||||
        bbox.connect('enter-event', Lang.bind(this, function() { this._onItemEnter(n); }));
 | 
			
		||||
 | 
			
		||||
        bbox.label_actor = label;
 | 
			
		||||
 | 
			
		||||
        this._items.push(bbox);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -637,11 +679,10 @@ SwitcherList.prototype = {
 | 
			
		||||
                this._items[this._highlighted].add_style_pseudo_class('selected');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let monitor = global.get_primary_monitor();
 | 
			
		||||
        let itemSize = this._items[index].allocation.x2 - this._items[index].allocation.x1;
 | 
			
		||||
        let [posX, posY] = this._items[index].get_transformed_position();
 | 
			
		||||
        posX += this.actor.x;
 | 
			
		||||
        if (posX + itemSize > monitor.width + monitor.x)
 | 
			
		||||
        let [absItemX, absItemY] = this._items[index].get_transformed_position();
 | 
			
		||||
        let [result, posX, posY] = this.actor.transform_stage_point(absItemX, 0);
 | 
			
		||||
        let [containerWidth, containerHeight] = this.actor.get_transformed_size();
 | 
			
		||||
        if (posX + this._items[index].get_width() > containerWidth)
 | 
			
		||||
            this._scrollToRight();
 | 
			
		||||
        else if (posX < 0)
 | 
			
		||||
            this._scrollToLeft();
 | 
			
		||||
@@ -665,7 +706,7 @@ SwitcherList.prototype = {
 | 
			
		||||
 | 
			
		||||
    _scrollToRight : function() {
 | 
			
		||||
        this._scrollableLeft = true;
 | 
			
		||||
        let monitor = global.get_primary_monitor();
 | 
			
		||||
        let monitor = Main.layoutManager.primaryMonitor;
 | 
			
		||||
        let padding = this.actor.get_theme_node().get_horizontal_padding();
 | 
			
		||||
        let parentPadding = this.actor.get_parent().get_theme_node().get_horizontal_padding();
 | 
			
		||||
        let x = this._items[this._highlighted].allocation.x2 - monitor.width + padding + parentPadding;
 | 
			
		||||
@@ -762,7 +803,7 @@ SwitcherList.prototype = {
 | 
			
		||||
        let children = this._list.get_children();
 | 
			
		||||
        let childBox = new Clutter.ActorBox();
 | 
			
		||||
 | 
			
		||||
        let primary = global.get_primary_monitor();
 | 
			
		||||
        let primary = Main.layoutManager.primaryMonitor;
 | 
			
		||||
        let parentRightPadding = this.actor.get_parent().get_theme_node().get_padding(St.Side.RIGHT);
 | 
			
		||||
        if (this.actor.allocation.x2 == primary.x + primary.width - parentRightPadding) {
 | 
			
		||||
            if (this._squareItems)
 | 
			
		||||
@@ -806,21 +847,19 @@ SwitcherList.prototype = {
 | 
			
		||||
        // Clip the area for scrolling
 | 
			
		||||
        this._clipBin.set_clip(0, -topPadding, (this.actor.allocation.x2 - this.actor.allocation.x1) - leftPadding - rightPadding, this.actor.height + bottomPadding);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(SwitcherList.prototype);
 | 
			
		||||
 | 
			
		||||
function AppIcon(app) {
 | 
			
		||||
    this._init(app);
 | 
			
		||||
}
 | 
			
		||||
const AppIcon = new Lang.Class({
 | 
			
		||||
    Name: 'AppIcon',
 | 
			
		||||
 | 
			
		||||
AppIcon.prototype = {
 | 
			
		||||
    _init: function(app) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        this.actor = new St.BoxLayout({ style_class: 'alt-tab-app',
 | 
			
		||||
                                         vertical: true });
 | 
			
		||||
        this.icon = null;
 | 
			
		||||
        this._iconBin = new St.Bin();
 | 
			
		||||
        this._iconBin = new St.Bin({ x_fill: true, y_fill: true });
 | 
			
		||||
 | 
			
		||||
        this.actor.add(this._iconBin, { x_fill: false, y_fill: false } );
 | 
			
		||||
        this.label = new St.Label({ text: this.app.get_name() });
 | 
			
		||||
@@ -832,35 +871,31 @@ AppIcon.prototype = {
 | 
			
		||||
        this._iconBin.set_size(size, size);
 | 
			
		||||
        this._iconBin.child = this.icon;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function AppSwitcher(apps, altTabPopup) {
 | 
			
		||||
    this._init(apps, altTabPopup);
 | 
			
		||||
}
 | 
			
		||||
const AppSwitcher = new Lang.Class({
 | 
			
		||||
    Name: 'AppSwitcher',
 | 
			
		||||
    Extends: SwitcherList,
 | 
			
		||||
 | 
			
		||||
AppSwitcher.prototype = {
 | 
			
		||||
    __proto__ : SwitcherList.prototype,
 | 
			
		||||
    _init : function(localApps, otherApps, altTabPopup) {
 | 
			
		||||
        this.parent(true);
 | 
			
		||||
 | 
			
		||||
    _init : function(apps, altTabPopup) {
 | 
			
		||||
        SwitcherList.prototype._init.call(this, true);
 | 
			
		||||
 | 
			
		||||
        // Construct the AppIcons, sort by time, add to the popup
 | 
			
		||||
        // Construct the AppIcons, add to the popup
 | 
			
		||||
        let activeWorkspace = global.screen.get_active_workspace();
 | 
			
		||||
        let workspaceIcons = [];
 | 
			
		||||
        let otherIcons = [];
 | 
			
		||||
        for (let i = 0; i < apps.length; i++) {
 | 
			
		||||
            let appIcon = new AppIcon(apps[i]);
 | 
			
		||||
        for (let i = 0; i < localApps.length; i++) {
 | 
			
		||||
            let appIcon = new AppIcon(localApps[i]);
 | 
			
		||||
            // Cache the window list now; we don't handle dynamic changes here,
 | 
			
		||||
            // and we don't want to be continually retrieving it
 | 
			
		||||
            appIcon.cachedWindows = appIcon.app.get_windows();
 | 
			
		||||
            if (this._hasWindowsOnWorkspace(appIcon, activeWorkspace))
 | 
			
		||||
              workspaceIcons.push(appIcon);
 | 
			
		||||
            else
 | 
			
		||||
              otherIcons.push(appIcon);
 | 
			
		||||
            workspaceIcons.push(appIcon);
 | 
			
		||||
        }
 | 
			
		||||
        for (let i = 0; i < otherApps.length; i++) {
 | 
			
		||||
            let appIcon = new AppIcon(otherApps[i]);
 | 
			
		||||
            appIcon.cachedWindows = appIcon.app.get_windows();
 | 
			
		||||
            otherIcons.push(appIcon);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        workspaceIcons.sort(Lang.bind(this, this._sortAppIcon));
 | 
			
		||||
        otherIcons.sort(Lang.bind(this, this._sortAppIcon));
 | 
			
		||||
 | 
			
		||||
        this.icons = [];
 | 
			
		||||
        this._arrows = [];
 | 
			
		||||
@@ -892,7 +927,7 @@ AppSwitcher.prototype = {
 | 
			
		||||
           totalSpacing += this._separator.width + this._list.spacing;
 | 
			
		||||
 | 
			
		||||
        // We just assume the whole screen here due to weirdness happing with the passed width
 | 
			
		||||
        let primary = global.get_primary_monitor();
 | 
			
		||||
        let primary = Main.layoutManager.primaryMonitor;
 | 
			
		||||
        let parentPadding = this.actor.get_parent().get_theme_node().get_horizontal_padding();
 | 
			
		||||
        let availWidth = primary.width - parentPadding - this.actor.get_theme_node().get_horizontal_padding();
 | 
			
		||||
        let height = 0;
 | 
			
		||||
@@ -922,7 +957,7 @@ AppSwitcher.prototype = {
 | 
			
		||||
 | 
			
		||||
    _allocate: function (actor, box, flags) {
 | 
			
		||||
        // Allocate the main list items
 | 
			
		||||
        SwitcherList.prototype._allocate.call(this, actor, box, flags);
 | 
			
		||||
        this.parent(actor, box, flags);
 | 
			
		||||
 | 
			
		||||
        let arrowHeight = Math.floor(this.actor.get_theme_node().get_padding(St.Side.BOTTOM) / 3);
 | 
			
		||||
        let arrowWidth = arrowHeight * 2;
 | 
			
		||||
@@ -977,7 +1012,7 @@ AppSwitcher.prototype = {
 | 
			
		||||
                this._arrows[this._curApp].remove_style_pseudo_class('highlighted');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SwitcherList.prototype.highlight.call(this, n, justOutline);
 | 
			
		||||
        this.parent(n, justOutline);
 | 
			
		||||
        this._curApp = n;
 | 
			
		||||
 | 
			
		||||
        if (this._curApp != -1) {
 | 
			
		||||
@@ -990,7 +1025,7 @@ AppSwitcher.prototype = {
 | 
			
		||||
 | 
			
		||||
    _addIcon : function(appIcon) {
 | 
			
		||||
        this.icons.push(appIcon);
 | 
			
		||||
        this.addItem(appIcon.actor);
 | 
			
		||||
        this.addItem(appIcon.actor, appIcon.label);
 | 
			
		||||
 | 
			
		||||
        let n = this._arrows.length;
 | 
			
		||||
        let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' });
 | 
			
		||||
@@ -1000,31 +1035,15 @@ AppSwitcher.prototype = {
 | 
			
		||||
 | 
			
		||||
        if (appIcon.cachedWindows.length == 1)
 | 
			
		||||
            arrow.hide();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _hasWindowsOnWorkspace: function(appIcon, workspace) {
 | 
			
		||||
        let windows = appIcon.cachedWindows;
 | 
			
		||||
        for (let i = 0; i < windows.length; i++) {
 | 
			
		||||
            if (windows[i].get_workspace() == workspace)
 | 
			
		||||
                return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _sortAppIcon : function(appIcon1, appIcon2) {
 | 
			
		||||
        return appIcon1.app.compare(appIcon2.app);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function ThumbnailList(windows) {
 | 
			
		||||
    this._init(windows);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ThumbnailList.prototype = {
 | 
			
		||||
    __proto__ : SwitcherList.prototype,
 | 
			
		||||
const ThumbnailList = new Lang.Class({
 | 
			
		||||
    Name: 'ThumbnailList',
 | 
			
		||||
    Extends: SwitcherList,
 | 
			
		||||
 | 
			
		||||
    _init : function(windows) {
 | 
			
		||||
        SwitcherList.prototype._init.call(this);
 | 
			
		||||
        this.parent(false);
 | 
			
		||||
 | 
			
		||||
        let activeWorkspace = global.screen.get_active_workspace();
 | 
			
		||||
 | 
			
		||||
@@ -1060,9 +1079,12 @@ ThumbnailList.prototype = {
 | 
			
		||||
                this._labels.push(bin);
 | 
			
		||||
                bin.add_actor(name);
 | 
			
		||||
                box.add_actor(bin);
 | 
			
		||||
 | 
			
		||||
                this.addItem(box, name);
 | 
			
		||||
            } else {
 | 
			
		||||
                this.addItem(box, null);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.addItem(box);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -1099,7 +1121,7 @@ ThumbnailList.prototype = {
 | 
			
		||||
        // Make sure we only do this once
 | 
			
		||||
        this._thumbnailBins = new Array();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function _drawArrow(area, side) {
 | 
			
		||||
    let themeNode = area.get_theme_node();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,15 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
const GMenu = imports.gi.GMenu;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
 | 
			
		||||
const AppFavorites = imports.ui.appFavorites;
 | 
			
		||||
const DND = imports.ui.dnd;
 | 
			
		||||
@@ -21,18 +22,19 @@ const Tweener = imports.ui.tweener;
 | 
			
		||||
const Workspace = imports.ui.workspace;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
 | 
			
		||||
const MAX_APPLICATION_WORK_MILLIS = 75;
 | 
			
		||||
const MENU_POPUP_TIMEOUT = 600;
 | 
			
		||||
const SCROLL_TIME = 0.1;
 | 
			
		||||
 | 
			
		||||
function AlphabeticalView() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const AlphabeticalView = new Lang.Class({
 | 
			
		||||
    Name: 'AlphabeticalView',
 | 
			
		||||
 | 
			
		||||
AlphabeticalView.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._grid = new IconGrid.IconGrid({ xAlign: St.Align.START });
 | 
			
		||||
        this._appSystem = Shell.AppSystem.get_default();
 | 
			
		||||
 | 
			
		||||
        this._filterApp = null;
 | 
			
		||||
        this._pendingAppLaterId = 0;
 | 
			
		||||
        this._appIcons = {}; // desktop file id
 | 
			
		||||
 | 
			
		||||
        let box = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        box.add(this._grid.actor, { y_align: St.Align.START, expand: true });
 | 
			
		||||
@@ -40,7 +42,7 @@ AlphabeticalView.prototype = {
 | 
			
		||||
        this.actor = new St.ScrollView({ x_fill: true,
 | 
			
		||||
                                         y_fill: false,
 | 
			
		||||
                                         y_align: St.Align.START,
 | 
			
		||||
                                         vfade: true });
 | 
			
		||||
                                         style_class: 'vfade' });
 | 
			
		||||
        this.actor.add_actor(box);
 | 
			
		||||
        this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
 | 
			
		||||
        this.actor.connect('notify::mapped', Lang.bind(this,
 | 
			
		||||
@@ -59,48 +61,78 @@ AlphabeticalView.prototype = {
 | 
			
		||||
 | 
			
		||||
    _removeAll: function() {
 | 
			
		||||
        this._grid.removeAll();
 | 
			
		||||
        this._apps = [];
 | 
			
		||||
        this._appIcons = {};
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _addApp: function(appInfo) {
 | 
			
		||||
        let appIcon = new AppWellIcon(this._appSystem.get_app(appInfo.get_id()));
 | 
			
		||||
    _addApp: function(app) {
 | 
			
		||||
        var id = app.get_id();
 | 
			
		||||
        let appIcon = new AppWellIcon(app);
 | 
			
		||||
 | 
			
		||||
        this._grid.addItem(appIcon.actor);
 | 
			
		||||
        appIcon.actor.connect('key-focus-in', Lang.bind(this, this._ensureIconVisible));
 | 
			
		||||
 | 
			
		||||
        appIcon._appInfo = appInfo;
 | 
			
		||||
        if (this._filterApp && !this._filterApp(appInfo))
 | 
			
		||||
            appIcon.actor.hide();
 | 
			
		||||
 | 
			
		||||
        this._apps.push(appIcon);
 | 
			
		||||
        this._appIcons[id] = appIcon;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setFilter: function(filter) {
 | 
			
		||||
        this._filterApp = filter;
 | 
			
		||||
        for (let i = 0; i < this._apps.length; i++)
 | 
			
		||||
            this._apps[i].actor.visible = filter(this._apps[i]._appInfo);
 | 
			
		||||
    _ensureIconVisible: function(icon) {
 | 
			
		||||
        let adjustment = this.actor.vscroll.adjustment;
 | 
			
		||||
        let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
 | 
			
		||||
 | 
			
		||||
        let offset = 0;
 | 
			
		||||
        let vfade = this.actor.get_effect("vfade");
 | 
			
		||||
        if (vfade)
 | 
			
		||||
            offset = vfade.fade_offset;
 | 
			
		||||
 | 
			
		||||
        // If this gets called as part of a right-click, the actor
 | 
			
		||||
        // will be needs_allocation, and so "icon.y" would return 0
 | 
			
		||||
        let box = icon.get_allocation_box();
 | 
			
		||||
 | 
			
		||||
        if (box.y1 < value + offset)
 | 
			
		||||
            value = Math.max(0, box.y1 - offset);
 | 
			
		||||
        else if (box.y2 > value + pageSize - offset)
 | 
			
		||||
            value = Math.min(upper, box.y2 + offset - pageSize);
 | 
			
		||||
        else
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Tweener.addTween(adjustment,
 | 
			
		||||
                         { value: value,
 | 
			
		||||
                           time: SCROLL_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad' });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    refresh: function(apps) {
 | 
			
		||||
        let ids = [];
 | 
			
		||||
        for (let i in apps)
 | 
			
		||||
            ids.push(i);
 | 
			
		||||
        ids.sort(function(a, b) {
 | 
			
		||||
            return apps[a].get_name().localeCompare(apps[b].get_name());
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._removeAll();
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < ids.length; i++) {
 | 
			
		||||
            this._addApp(apps[ids[i]]);
 | 
			
		||||
    setVisibleApps: function(apps) {
 | 
			
		||||
        if (apps == null) { // null implies "all"
 | 
			
		||||
            for (var id in this._appIcons) {
 | 
			
		||||
                var icon = this._appIcons[id];
 | 
			
		||||
                icon.actor.visible = true;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            // Set everything to not-visible, then set to visible what we should see
 | 
			
		||||
            for (var id in this._appIcons) {
 | 
			
		||||
                var icon = this._appIcons[id];
 | 
			
		||||
                icon.actor.visible = false;
 | 
			
		||||
            }
 | 
			
		||||
            for (var i = 0; i < apps.length; i++) {
 | 
			
		||||
                var app = apps[i];
 | 
			
		||||
                var id = app.get_id();
 | 
			
		||||
                var icon = this._appIcons[id];
 | 
			
		||||
                icon.actor.visible = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setAppList: function(apps) {
 | 
			
		||||
        this._removeAll();
 | 
			
		||||
        for (var i = 0; i < apps.length; i++) {
 | 
			
		||||
            var app = apps[i];
 | 
			
		||||
            this._addApp(app);
 | 
			
		||||
         }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function ViewByCategories() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const ViewByCategories = new Lang.Class({
 | 
			
		||||
    Name: 'ViewByCategories',
 | 
			
		||||
 | 
			
		||||
ViewByCategories.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._appSystem = Shell.AppSystem.get_default();
 | 
			
		||||
        this.actor = new St.BoxLayout({ style_class: 'all-app' });
 | 
			
		||||
@@ -108,89 +140,151 @@ ViewByCategories.prototype = {
 | 
			
		||||
 | 
			
		||||
        this._view = new AlphabeticalView();
 | 
			
		||||
 | 
			
		||||
        this._filters = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        // categories can be -1 (the All view) or 0...n-1, where n
 | 
			
		||||
        // is the number of sections
 | 
			
		||||
        // -2 is a flag to indicate that nothing is selected
 | 
			
		||||
        // (used only before the actor is mapped the first time)
 | 
			
		||||
        this._currentCategory = -2;
 | 
			
		||||
        this._categories = [];
 | 
			
		||||
        this._apps = null;
 | 
			
		||||
 | 
			
		||||
        this._categoryBox = new St.BoxLayout({ vertical: true, reactive: true });
 | 
			
		||||
        this._categoryScroll = new St.ScrollView({ x_fill: false,
 | 
			
		||||
                                                   y_fill: false,
 | 
			
		||||
                                                   style_class: 'vfade' });
 | 
			
		||||
        this._categoryScroll.add_actor(this._categoryBox);
 | 
			
		||||
        this.actor.add(this._view.actor, { expand: true, x_fill: true, y_fill: true });
 | 
			
		||||
        this.actor.add(this._filters, { expand: false, y_fill: false, y_align: St.Align.START });
 | 
			
		||||
        this.actor.add(this._categoryScroll, { expand: false, y_fill: false, y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        // Always select the "All" filter when switching to the app view
 | 
			
		||||
        this.actor.connect('notify::mapped', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
                if (this.actor.mapped && this._allFilter)
 | 
			
		||||
                if (this.actor.mapped && this._allCategoryButton)
 | 
			
		||||
                    this._selectCategory(-1);
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        this._sections = [];
 | 
			
		||||
        // We need a dummy actor to catch the keyboard focus if the
 | 
			
		||||
        // user Ctrl-Alt-Tabs here before the deferred work creates
 | 
			
		||||
        // our real contents
 | 
			
		||||
        this._focusDummy = new St.Bin({ can_focus: true });
 | 
			
		||||
        this.actor.add(this._focusDummy);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _selectCategory: function(num) {
 | 
			
		||||
        if (num != -1)
 | 
			
		||||
            this._allFilter.remove_style_pseudo_class('selected');
 | 
			
		||||
        else
 | 
			
		||||
            this._allFilter.add_style_pseudo_class('selected');
 | 
			
		||||
        if (this._currentCategory == num) // nothing to do
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._view.setFilter(Lang.bind(this, function(app) {
 | 
			
		||||
            if (num == -1)
 | 
			
		||||
                return true;
 | 
			
		||||
            return this._sections[num].name == app.get_section();
 | 
			
		||||
        }));
 | 
			
		||||
        this._currentCategory = num;
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._sections.length; i++) {
 | 
			
		||||
        if (num != -1) {
 | 
			
		||||
            var category = this._categories[num];
 | 
			
		||||
            this._allCategoryButton.remove_style_pseudo_class('selected');
 | 
			
		||||
            this._view.setVisibleApps(category.apps);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._allCategoryButton.add_style_pseudo_class('selected');
 | 
			
		||||
            this._view.setVisibleApps(null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (var i = 0; i < this._categories.length; i++) {
 | 
			
		||||
            if (i == num)
 | 
			
		||||
                this._sections[i].filterActor.add_style_pseudo_class('selected');
 | 
			
		||||
                this._categories[i].button.add_style_pseudo_class('selected');
 | 
			
		||||
            else
 | 
			
		||||
                this._sections[i].filterActor.remove_style_pseudo_class('selected');
 | 
			
		||||
                this._categories[i].button.remove_style_pseudo_class('selected');
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _addFilter: function(name, num) {
 | 
			
		||||
        let button = new St.Button({ label: name,
 | 
			
		||||
    // Recursively load a GMenuTreeDirectory; we could put this in ShellAppSystem too
 | 
			
		||||
    _loadCategory: function(dir, appList) {
 | 
			
		||||
        var iter = dir.iter();
 | 
			
		||||
        var nextType;
 | 
			
		||||
        while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
 | 
			
		||||
            if (nextType == GMenu.TreeItemType.ENTRY) {
 | 
			
		||||
                var entry = iter.get_entry();
 | 
			
		||||
                var app = this._appSystem.lookup_app_by_tree_entry(entry);
 | 
			
		||||
                if (!entry.get_app_info().get_nodisplay())
 | 
			
		||||
                    appList.push(app);
 | 
			
		||||
            } else if (nextType == GMenu.TreeItemType.DIRECTORY) {
 | 
			
		||||
                if (!dir.get_is_nodisplay())
 | 
			
		||||
                    this._loadCategory(iter.get_directory(), appList);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _addCategory: function(name, index, dir, allApps) {
 | 
			
		||||
        let button = new St.Button({ label: GLib.markup_escape_text (name, -1),
 | 
			
		||||
                                     style_class: 'app-filter',
 | 
			
		||||
                                     x_align: St.Align.START });
 | 
			
		||||
        this._filters.add(button, { expand: true, x_fill: true, y_fill: false });
 | 
			
		||||
                                     x_align: St.Align.START,
 | 
			
		||||
                                     can_focus: true });
 | 
			
		||||
        button.connect('clicked', Lang.bind(this, function() {
 | 
			
		||||
            this._selectCategory(num);
 | 
			
		||||
            this._selectCategory(index);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        if (num != -1)
 | 
			
		||||
            this._sections[num] = { filterActor: button,
 | 
			
		||||
                                    name: name };
 | 
			
		||||
        else
 | 
			
		||||
            this._allFilter = button;
 | 
			
		||||
        var apps;
 | 
			
		||||
        if (dir == null) {
 | 
			
		||||
            apps = allApps;
 | 
			
		||||
            this._allCategoryButton = button;
 | 
			
		||||
        } else {
 | 
			
		||||
            apps = [];
 | 
			
		||||
            this._loadCategory(dir, apps);
 | 
			
		||||
            this._categories.push({ apps: apps,
 | 
			
		||||
                                    name: name,
 | 
			
		||||
                                    button: button });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._categoryBox.add(button, { expand: true, x_fill: true, y_fill: false });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _removeAll: function() {
 | 
			
		||||
        this._sections = [];
 | 
			
		||||
        this._filters.destroy_children();
 | 
			
		||||
        this._categories = [];
 | 
			
		||||
        this._categoryBox.destroy_children();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    refresh: function(apps) {
 | 
			
		||||
    refresh: function() {
 | 
			
		||||
        this._removeAll();
 | 
			
		||||
 | 
			
		||||
        let sections = this._appSystem.get_sections();
 | 
			
		||||
        this._apps = apps;
 | 
			
		||||
        this._view.refresh(apps);
 | 
			
		||||
        var allApps = Shell.AppSystem.get_default().get_all();
 | 
			
		||||
        allApps.sort(function(a, b) {
 | 
			
		||||
            return a.compare_by_name(b);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        /* Translators: Filter to display all applications */
 | 
			
		||||
        this._addFilter(_("All"), -1);
 | 
			
		||||
        this._addCategory(_("All"), -1, null, allApps);
 | 
			
		||||
 | 
			
		||||
        if (!sections)
 | 
			
		||||
            return;
 | 
			
		||||
        var tree = this._appSystem.get_tree();
 | 
			
		||||
        var root = tree.get_root_directory();
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < sections.length; i++)
 | 
			
		||||
            this._addFilter(sections[i], i);
 | 
			
		||||
        var iter = root.iter();
 | 
			
		||||
        var nextType;
 | 
			
		||||
        var i = 0;
 | 
			
		||||
        while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
 | 
			
		||||
            if (nextType == GMenu.TreeItemType.DIRECTORY) {
 | 
			
		||||
                var dir = iter.get_directory();
 | 
			
		||||
                if (dir.get_is_nodisplay())
 | 
			
		||||
                    continue;
 | 
			
		||||
                this._addCategory(dir.get_name(), i, dir);
 | 
			
		||||
                i++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._view.setAppList(allApps);
 | 
			
		||||
        this._selectCategory(-1);
 | 
			
		||||
 | 
			
		||||
        if (this._focusDummy) {
 | 
			
		||||
            let focused = this._focusDummy.has_key_focus();
 | 
			
		||||
            this._focusDummy.destroy();
 | 
			
		||||
            this._focusDummy = null;
 | 
			
		||||
            if (focused)
 | 
			
		||||
                this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* This class represents a display containing a collection of application items.
 | 
			
		||||
 * The applications are sorted based on their name.
 | 
			
		||||
 */
 | 
			
		||||
function AllAppDisplay() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const AllAppDisplay = new Lang.Class({
 | 
			
		||||
    Name: 'AllAppDisplay',
 | 
			
		||||
 | 
			
		||||
AllAppDisplay.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._appSystem = Shell.AppSystem.get_default();
 | 
			
		||||
        this._appSystem.connect('installed-changed', Lang.bind(this, function() {
 | 
			
		||||
@@ -204,140 +298,138 @@ AllAppDisplay.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _redisplay: function() {
 | 
			
		||||
        let apps = this._appSystem.get_flattened_apps().filter(function(app) {
 | 
			
		||||
            return !app.get_is_nodisplay();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._appView.refresh(apps);
 | 
			
		||||
        this._appView.refresh();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function BaseAppSearchProvider() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const AppSearchProvider = new Lang.Class({
 | 
			
		||||
    Name: 'AppSearchProvider',
 | 
			
		||||
    Extends: Search.SearchProvider,
 | 
			
		||||
 | 
			
		||||
BaseAppSearchProvider.prototype = {
 | 
			
		||||
    __proto__: Search.SearchProvider.prototype,
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.parent(_("APPLICATIONS"));
 | 
			
		||||
 | 
			
		||||
    _init: function(name) {
 | 
			
		||||
        Search.SearchProvider.prototype._init.call(this, name);
 | 
			
		||||
        this._appSys = Shell.AppSystem.get_default();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getResultMeta: function(resultId) {
 | 
			
		||||
        let app = this._appSys.get_app(resultId);
 | 
			
		||||
        if (!app)
 | 
			
		||||
            return null;
 | 
			
		||||
        return { 'id': resultId,
 | 
			
		||||
    getResultMeta: function(app) {
 | 
			
		||||
        return { 'id': app,
 | 
			
		||||
                 'name': app.get_name(),
 | 
			
		||||
                 'icon': app.create_icon_texture(Search.RESULT_ICON_SIZE)};
 | 
			
		||||
                 'createIcon': function(size) {
 | 
			
		||||
                                   return app.create_icon_texture(size);
 | 
			
		||||
                               }
 | 
			
		||||
               };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activateResult: function(id, params) {
 | 
			
		||||
        params = Params.parse(params, { workspace: null,
 | 
			
		||||
                                        timestamp: null });
 | 
			
		||||
    getInitialResultSet: function(terms) {
 | 
			
		||||
        return this._appSys.initial_search(terms);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
        let app = this._appSys.get_app(id);
 | 
			
		||||
        app.activate(params.workspace ? params.workspace.index() : -1);
 | 
			
		||||
    getSubsearchResultSet: function(previousResults, terms) {
 | 
			
		||||
        return this._appSys.subsearch(previousResults, terms);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activateResult: function(app, params) {
 | 
			
		||||
        params = Params.parse(params, { workspace: -1,
 | 
			
		||||
                                        timestamp: 0 });
 | 
			
		||||
 | 
			
		||||
        let event = Clutter.get_current_event();
 | 
			
		||||
        let modifiers = event ? Shell.get_event_state(event) : 0;
 | 
			
		||||
        let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK;
 | 
			
		||||
 | 
			
		||||
        if (openNewWindow)
 | 
			
		||||
            app.open_new_window(params.workspace);
 | 
			
		||||
        else
 | 
			
		||||
            app.activate_full(params.workspace, params.timestamp);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    dragActivateResult: function(id, params) {
 | 
			
		||||
        params = Params.parse(params, { workspace: null,
 | 
			
		||||
                                        timestamp: null });
 | 
			
		||||
        params = Params.parse(params, { workspace: -1,
 | 
			
		||||
                                        timestamp: 0 });
 | 
			
		||||
 | 
			
		||||
        let app = this._appSys.get_app(id);
 | 
			
		||||
        app.open_new_window(params.workspace ? params.workspace.get_index() : -1);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function AppSearchProvider() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AppSearchProvider.prototype = {
 | 
			
		||||
    __proto__: BaseAppSearchProvider.prototype,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
         BaseAppSearchProvider.prototype._init.call(this, _("APPLICATIONS"));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getInitialResultSet: function(terms) {
 | 
			
		||||
        return this._appSys.initial_search(false, terms);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getSubsearchResultSet: function(previousResults, terms) {
 | 
			
		||||
        return this._appSys.subsearch(false, previousResults, terms);
 | 
			
		||||
        let app = this._appSys.lookup_app(id);
 | 
			
		||||
        app.open_new_window(workspace);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createResultActor: function (resultMeta, terms) {
 | 
			
		||||
        let app = this._appSys.get_app(resultMeta['id']);
 | 
			
		||||
        let app = resultMeta['id'];
 | 
			
		||||
        let icon = new AppWellIcon(app);
 | 
			
		||||
        return icon.actor;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    expandSearch: function(terms) {
 | 
			
		||||
        log('TODO expand search');
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function PrefsSearchProvider() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PrefsSearchProvider.prototype = {
 | 
			
		||||
    __proto__: BaseAppSearchProvider.prototype,
 | 
			
		||||
const SettingsSearchProvider = new Lang.Class({
 | 
			
		||||
    Name: 'SettingsSearchProvider',
 | 
			
		||||
    Extends: Search.SearchProvider,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        BaseAppSearchProvider.prototype._init.call(this, _("PREFERENCES"));
 | 
			
		||||
        this.parent(_("SETTINGS"));
 | 
			
		||||
 | 
			
		||||
        this._appSys = Shell.AppSystem.get_default();
 | 
			
		||||
        this._gnomecc = this._appSys.lookup_app('gnome-control-center.desktop');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getResultMeta: function(pref) {
 | 
			
		||||
        return { 'id': pref,
 | 
			
		||||
                 'name': pref.get_name(),
 | 
			
		||||
                 'createIcon': function(size) {
 | 
			
		||||
                                   return pref.create_icon_texture(size);
 | 
			
		||||
                               }
 | 
			
		||||
               };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getInitialResultSet: function(terms) {
 | 
			
		||||
        return this._appSys.initial_search(true, terms);
 | 
			
		||||
        return this._appSys.search_settings(terms);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getSubsearchResultSet: function(previousResults, terms) {
 | 
			
		||||
        return this._appSys.subsearch(true, previousResults, terms);
 | 
			
		||||
        return this._appSys.search_settings(terms);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    expandSearch: function(terms) {
 | 
			
		||||
        let controlCenter = this._appSys.load_from_desktop_file('gnomecc.desktop');
 | 
			
		||||
        controlCenter.launch();
 | 
			
		||||
        Main.overview.hide();
 | 
			
		||||
    activateResult: function(pref, params) {
 | 
			
		||||
        params = Params.parse(params, { workspace: -1,
 | 
			
		||||
                                        timestamp: 0 });
 | 
			
		||||
 | 
			
		||||
        pref.activate_full(params.workspace, params.timestamp);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    dragActivateResult: function(pref, params) {
 | 
			
		||||
        this.activateResult(pref, params);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createResultActor: function (resultMeta, terms) {
 | 
			
		||||
        let app = resultMeta['id'];
 | 
			
		||||
        let icon = new AppWellIcon(app);
 | 
			
		||||
        return icon.actor;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function AppIcon(app, params) {
 | 
			
		||||
    this._init(app, params);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AppIcon.prototype = {
 | 
			
		||||
    __proto__:  IconGrid.BaseIcon.prototype,
 | 
			
		||||
const AppIcon = new Lang.Class({
 | 
			
		||||
    Name: 'AppIcon',
 | 
			
		||||
    Extends: IconGrid.BaseIcon,
 | 
			
		||||
 | 
			
		||||
    _init : function(app, params) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        let label = this.app.get_name();
 | 
			
		||||
 | 
			
		||||
        IconGrid.BaseIcon.prototype._init.call(this,
 | 
			
		||||
                                               label,
 | 
			
		||||
                                               params);
 | 
			
		||||
        this.parent(label, params);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createIcon: function(iconSize) {
 | 
			
		||||
        return this.app.create_icon_texture(iconSize);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function AppWellIcon(app, iconParams) {
 | 
			
		||||
    this._init(app, iconParams);
 | 
			
		||||
}
 | 
			
		||||
const AppWellIcon = new Lang.Class({
 | 
			
		||||
    Name: 'AppWellIcon',
 | 
			
		||||
 | 
			
		||||
AppWellIcon.prototype = {
 | 
			
		||||
    _init : function(app, iconParams) {
 | 
			
		||||
    _init : function(app, iconParams, onActivateOverride) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        this.actor = new St.Button({ style_class: 'app-well-app',
 | 
			
		||||
                                     reactive: true,
 | 
			
		||||
                                     button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO,
 | 
			
		||||
                                     can_focus: true,
 | 
			
		||||
                                     x_fill: true,
 | 
			
		||||
                                     y_fill: true });
 | 
			
		||||
        this.actor._delegate = this;
 | 
			
		||||
@@ -345,8 +437,13 @@ AppWellIcon.prototype = {
 | 
			
		||||
        this.icon = new AppIcon(app, iconParams);
 | 
			
		||||
        this.actor.set_child(this.icon.actor);
 | 
			
		||||
 | 
			
		||||
        this.actor.label_actor = this.icon.label;
 | 
			
		||||
 | 
			
		||||
        // A function callback to override the default "app.activate()"; used by preferences
 | 
			
		||||
        this._onActivateOverride = onActivateOverride;
 | 
			
		||||
        this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
 | 
			
		||||
        this.actor.connect('clicked', Lang.bind(this, this._onClicked));
 | 
			
		||||
        this.actor.connect('popup-menu', Lang.bind(this, this._onKeyboardPopupMenu));
 | 
			
		||||
 | 
			
		||||
        this._menu = null;
 | 
			
		||||
        this._menuManager = new PopupMenu.PopupMenuManager(this);
 | 
			
		||||
@@ -357,6 +454,10 @@ AppWellIcon.prototype = {
 | 
			
		||||
                this._removeMenuTimeout();
 | 
			
		||||
                Main.overview.beginItemDrag(this);
 | 
			
		||||
            }));
 | 
			
		||||
        this._draggable.connect('drag-cancelled', Lang.bind(this,
 | 
			
		||||
            function () {
 | 
			
		||||
                Main.overview.cancelledItemDrag(this);
 | 
			
		||||
            }));
 | 
			
		||||
        this._draggable.connect('drag-end', Lang.bind(this,
 | 
			
		||||
            function () {
 | 
			
		||||
               Main.overview.endItemDrag(this);
 | 
			
		||||
@@ -423,6 +524,11 @@ AppWellIcon.prototype = {
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeyboardPopupMenu: function() {
 | 
			
		||||
        this.popupMenu();
 | 
			
		||||
        this._menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getId: function() {
 | 
			
		||||
        return this.app.get_id();
 | 
			
		||||
    },
 | 
			
		||||
@@ -436,14 +542,17 @@ AppWellIcon.prototype = {
 | 
			
		||||
            this._menu.connect('activate-window', Lang.bind(this, function (menu, window) {
 | 
			
		||||
                this.activateWindow(window);
 | 
			
		||||
            }));
 | 
			
		||||
            this._menu.connect('popup', Lang.bind(this, function (menu, isPoppedUp) {
 | 
			
		||||
            this._menu.connect('open-state-changed', Lang.bind(this, function (menu, isPoppedUp) {
 | 
			
		||||
                if (!isPoppedUp)
 | 
			
		||||
                    this._onMenuPoppedDown();
 | 
			
		||||
            }));
 | 
			
		||||
            Main.overview.connect('hiding', Lang.bind(this, function () { this._menu.close(); }));
 | 
			
		||||
 | 
			
		||||
            this._menuManager.addMenu(this._menu);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.actor.set_hover(true);
 | 
			
		||||
        this.actor.show_tooltip();
 | 
			
		||||
        this._menu.popup();
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
@@ -465,24 +574,28 @@ AppWellIcon.prototype = {
 | 
			
		||||
        this.emit('launching');
 | 
			
		||||
        let modifiers = Shell.get_event_state(event);
 | 
			
		||||
 | 
			
		||||
        if (modifiers & Clutter.ModifierType.CONTROL_MASK
 | 
			
		||||
            && this.app.state == Shell.AppState.RUNNING) {
 | 
			
		||||
            this.app.open_new_window(-1);
 | 
			
		||||
        if (this._onActivateOverride) {
 | 
			
		||||
            this._onActivateOverride(event);
 | 
			
		||||
        } else {
 | 
			
		||||
            this.app.activate(-1);
 | 
			
		||||
            if (modifiers & Clutter.ModifierType.CONTROL_MASK
 | 
			
		||||
                && this.app.state == Shell.AppState.RUNNING) {
 | 
			
		||||
                this.app.open_new_window(-1);
 | 
			
		||||
            } else {
 | 
			
		||||
                this.app.activate();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Main.overview.hide();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    shellWorkspaceLaunch : function(params) {
 | 
			
		||||
        params = Params.parse(params, { workspace: null,
 | 
			
		||||
                                        timestamp: null });
 | 
			
		||||
        params = Params.parse(params, { workspace: -1,
 | 
			
		||||
                                        timestamp: 0 });
 | 
			
		||||
 | 
			
		||||
        this.app.open_new_window(params.workspace ? params.workspace.index() : -1);
 | 
			
		||||
        this.app.open_new_window(params.workspace);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getDragActor: function() {
 | 
			
		||||
        return this.app.create_icon_texture(Main.overview.dash.iconSize);
 | 
			
		||||
        return this.app.create_icon_texture(Main.overview.dashIconSize);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Returns the original actor that should align with the actor
 | 
			
		||||
@@ -490,27 +603,26 @@ AppWellIcon.prototype = {
 | 
			
		||||
    getDragActorSource: function() {
 | 
			
		||||
        return this.icon.icon;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(AppWellIcon.prototype);
 | 
			
		||||
 | 
			
		||||
function AppIconMenu(source) {
 | 
			
		||||
    this._init(source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AppIconMenu.prototype = {
 | 
			
		||||
    __proto__: PopupMenu.PopupMenu.prototype,
 | 
			
		||||
const AppIconMenu = new Lang.Class({
 | 
			
		||||
    Name: 'AppIconMenu',
 | 
			
		||||
    Extends: PopupMenu.PopupMenu,
 | 
			
		||||
 | 
			
		||||
    _init: function(source) {
 | 
			
		||||
        let side = St.Side.LEFT;
 | 
			
		||||
        if (St.Widget.get_default_direction() == St.TextDirection.RTL)
 | 
			
		||||
            side = St.Side.RIGHT;
 | 
			
		||||
 | 
			
		||||
        PopupMenu.PopupMenu.prototype._init.call(this, source.actor, 0.5, side, 0);
 | 
			
		||||
        this.parent(source.actor, 0.5, side);
 | 
			
		||||
 | 
			
		||||
        // We want to keep the item hovered while the menu is up
 | 
			
		||||
        this.blockSourceEvents = true;
 | 
			
		||||
 | 
			
		||||
        this._source = source;
 | 
			
		||||
 | 
			
		||||
        this.connect('activate', Lang.bind(this, this._onActivate));
 | 
			
		||||
        this.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
 | 
			
		||||
 | 
			
		||||
        this.actor.add_style_class_name('app-well-menu');
 | 
			
		||||
 | 
			
		||||
@@ -543,18 +655,18 @@ AppIconMenu.prototype = {
 | 
			
		||||
            item._window = windows[i];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (windows.length > 0)
 | 
			
		||||
        if (!this._source.app.is_window_backed()) {
 | 
			
		||||
            if (windows.length > 0)
 | 
			
		||||
                this._appendSeparator();
 | 
			
		||||
 | 
			
		||||
            let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id());
 | 
			
		||||
 | 
			
		||||
            this._newWindowMenuItem = this._appendMenuItem(_("New Window"));
 | 
			
		||||
            this._appendSeparator();
 | 
			
		||||
 | 
			
		||||
        let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id());
 | 
			
		||||
 | 
			
		||||
        this._newWindowMenuItem = windows.length > 0 ? this._appendMenuItem(_("New Window")) : null;
 | 
			
		||||
 | 
			
		||||
        if (windows.length > 0)
 | 
			
		||||
            this._appendSeparator();
 | 
			
		||||
        this._toggleFavoriteMenuItem = this._appendMenuItem(isFavorite ? _("Remove from Favorites")
 | 
			
		||||
                                                                    : _("Add to Favorites"));
 | 
			
		||||
 | 
			
		||||
            this._toggleFavoriteMenuItem = this._appendMenuItem(isFavorite ? _("Remove from Favorites")
 | 
			
		||||
                                                                : _("Add to Favorites"));
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _appendSeparator: function () {
 | 
			
		||||
@@ -574,14 +686,6 @@ AppIconMenu.prototype = {
 | 
			
		||||
        this.open();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onOpenStateChanged: function (menu, open) {
 | 
			
		||||
        if (open) {
 | 
			
		||||
            this.emit('popup', true);
 | 
			
		||||
        } else {
 | 
			
		||||
            this.emit('popup', false);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onActivate: function (actor, child) {
 | 
			
		||||
        if (child._window) {
 | 
			
		||||
            let metaWindow = child._window;
 | 
			
		||||
@@ -599,5 +703,5 @@ AppIconMenu.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
        this.close();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(AppIconMenu.prototype);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,14 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
 | 
			
		||||
function AppFavorites() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const AppFavorites = new Lang.Class({
 | 
			
		||||
    Name: 'AppFavorites',
 | 
			
		||||
 | 
			
		||||
AppFavorites.prototype = {
 | 
			
		||||
    FAVORITE_APPS_KEY: 'favorite-apps',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
@@ -30,7 +26,7 @@ AppFavorites.prototype = {
 | 
			
		||||
        let ids = global.settings.get_strv(this.FAVORITE_APPS_KEY);
 | 
			
		||||
        let appSys = Shell.AppSystem.get_default();
 | 
			
		||||
        let apps = ids.map(function (id) {
 | 
			
		||||
                return appSys.get_app(id);
 | 
			
		||||
                return appSys.lookup_app(id);
 | 
			
		||||
            }).filter(function (app) {
 | 
			
		||||
                return app != null;
 | 
			
		||||
            });
 | 
			
		||||
@@ -67,7 +63,7 @@ AppFavorites.prototype = {
 | 
			
		||||
        if (appId in this._favorites)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        let app = Shell.AppSystem.get_default().get_app(appId);
 | 
			
		||||
        let app = Shell.AppSystem.get_default().lookup_app(appId);
 | 
			
		||||
 | 
			
		||||
        if (!app)
 | 
			
		||||
            return false;
 | 
			
		||||
@@ -86,9 +82,9 @@ AppFavorites.prototype = {
 | 
			
		||||
        if (!this._addFavorite(appId, pos))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let app = Shell.AppSystem.get_default().get_app(appId);
 | 
			
		||||
        let app = Shell.AppSystem.get_default().lookup_app(appId);
 | 
			
		||||
 | 
			
		||||
        Main.overview.shellInfo.setMessage(_("%s has been added to your favorites.").format(app.get_name()), Lang.bind(this, function () {
 | 
			
		||||
        Main.overview.setMessage(_("%s has been added to your favorites.").format(app.get_name()), Lang.bind(this, function () {
 | 
			
		||||
            this._removeFavorite(appId);
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
@@ -119,12 +115,12 @@ AppFavorites.prototype = {
 | 
			
		||||
        if (!this._removeFavorite(appId))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Main.overview.shellInfo.setMessage(_("%s has been removed from your favorites.").format(app.get_name()),
 | 
			
		||||
                                         Lang.bind(this, function () {
 | 
			
		||||
        Main.overview.setMessage(_("%s has been removed from your favorites.").format(app.get_name()),
 | 
			
		||||
                                 Lang.bind(this, function () {
 | 
			
		||||
            this._addFavorite(appId, pos);
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(AppFavorites.prototype);
 | 
			
		||||
 | 
			
		||||
var appFavoritesInstance = null;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										269
									
								
								js/ui/automountManager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,269 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const ShellMountOperation = imports.ui.shellMountOperation;
 | 
			
		||||
const ScreenSaver = imports.misc.screenSaver;
 | 
			
		||||
 | 
			
		||||
// GSettings keys
 | 
			
		||||
const SETTINGS_SCHEMA = 'org.gnome.desktop.media-handling';
 | 
			
		||||
const SETTING_ENABLE_AUTOMOUNT = 'automount';
 | 
			
		||||
 | 
			
		||||
const AUTORUN_EXPIRE_TIMEOUT_SECS = 10;
 | 
			
		||||
 | 
			
		||||
const ConsoleKitSessionIface = <interface name="org.freedesktop.ConsoleKit.Session">
 | 
			
		||||
<method name="IsActive">
 | 
			
		||||
    <arg type="b" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<signal name="ActiveChanged">
 | 
			
		||||
    <arg type="b" direction="out" />
 | 
			
		||||
</signal>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const ConsoleKitSessionProxy = Gio.DBusProxy.makeProxyWrapper(ConsoleKitSessionIface);
 | 
			
		||||
 | 
			
		||||
const ConsoleKitManagerIface = <interface name="org.freedesktop.ConsoleKit.Manager">
 | 
			
		||||
<method name="GetCurrentSession">
 | 
			
		||||
    <arg type="o" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const ConsoleKitManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(ConsoleKitManagerIface);
 | 
			
		||||
 | 
			
		||||
function ConsoleKitManager() {
 | 
			
		||||
    var self = new Gio.DBusProxy({ g_connection: Gio.DBus.system,
 | 
			
		||||
				   g_interface_name: ConsoleKitManagerInfo.name,
 | 
			
		||||
				   g_interface_info: ConsoleKitManagerInfo,
 | 
			
		||||
				   g_name: 'org.freedesktop.ConsoleKit',
 | 
			
		||||
				   g_object_path: '/org/freedesktop/ConsoleKit/Manager',
 | 
			
		||||
                                   g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
 | 
			
		||||
                                             Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
 | 
			
		||||
 | 
			
		||||
    self.connect('notify::g-name-owner', function() {
 | 
			
		||||
        if (self.g_name_owner) {
 | 
			
		||||
            self.GetCurrentSessionRemote(function([session]) {
 | 
			
		||||
                self._ckSession = new ConsoleKitSessionProxy(Gio.DBus.system, 'org.freedesktop.ConsoleKit', session);
 | 
			
		||||
 | 
			
		||||
                self._ckSession.connectSignal('ActiveChanged', function(object, senderName, [isActive]) {
 | 
			
		||||
                    self.sessionActive = isActive;
 | 
			
		||||
                });
 | 
			
		||||
                self._ckSession.IsActiveRemote(function([isActive]) {
 | 
			
		||||
                    self.sessionActive = isActive;
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            self.sessionActive = true;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    self.init(null);
 | 
			
		||||
    return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const AutomountManager = new Lang.Class({
 | 
			
		||||
    Name: 'AutomountManager',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
 | 
			
		||||
        this._volumeQueue = [];
 | 
			
		||||
 | 
			
		||||
        this.ckListener = new ConsoleKitManager();
 | 
			
		||||
 | 
			
		||||
        this._ssProxy = new ScreenSaver.ScreenSaverProxy();
 | 
			
		||||
        this._ssProxy.connectSignal('ActiveChanged',
 | 
			
		||||
                                    Lang.bind(this, this._screenSaverActiveChanged));
 | 
			
		||||
 | 
			
		||||
        this._volumeMonitor = Gio.VolumeMonitor.get();
 | 
			
		||||
 | 
			
		||||
        this._volumeMonitor.connect('volume-added',
 | 
			
		||||
                                    Lang.bind(this,
 | 
			
		||||
                                              this._onVolumeAdded));
 | 
			
		||||
        this._volumeMonitor.connect('volume-removed',
 | 
			
		||||
                                    Lang.bind(this,
 | 
			
		||||
                                              this._onVolumeRemoved));
 | 
			
		||||
        this._volumeMonitor.connect('drive-connected',
 | 
			
		||||
                                    Lang.bind(this,
 | 
			
		||||
                                              this._onDriveConnected));
 | 
			
		||||
        this._volumeMonitor.connect('drive-disconnected',
 | 
			
		||||
                                    Lang.bind(this,
 | 
			
		||||
                                              this._onDriveDisconnected));
 | 
			
		||||
        this._volumeMonitor.connect('drive-eject-button',
 | 
			
		||||
                                    Lang.bind(this,
 | 
			
		||||
                                              this._onDriveEjectButton));
 | 
			
		||||
 | 
			
		||||
        Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _screenSaverActiveChanged: function(object, senderName, [isActive]) {
 | 
			
		||||
        if (!isActive) {
 | 
			
		||||
            this._volumeQueue.forEach(Lang.bind(this, function(volume) {
 | 
			
		||||
                this._checkAndMountVolume(volume);
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // clear the queue anyway
 | 
			
		||||
        this._volumeQueue = [];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _startupMountAll: function() {
 | 
			
		||||
        let volumes = this._volumeMonitor.get_volumes();
 | 
			
		||||
        volumes.forEach(Lang.bind(this, function(volume) {
 | 
			
		||||
            this._checkAndMountVolume(volume, { checkSession: false,
 | 
			
		||||
                                                useMountOp: false });
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDriveConnected: function() {
 | 
			
		||||
        // if we're not in the current ConsoleKit session,
 | 
			
		||||
        // or screensaver is active, don't play sounds
 | 
			
		||||
        if (!this.ckListener.sessionActive)
 | 
			
		||||
            return;        
 | 
			
		||||
 | 
			
		||||
        if (this._ssProxy.screenSaverActive)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        global.play_theme_sound(0, 'device-added-media');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDriveDisconnected: function() {
 | 
			
		||||
        // if we're not in the current ConsoleKit session,
 | 
			
		||||
        // or screensaver is active, don't play sounds
 | 
			
		||||
        if (!this.ckListener.sessionActive)
 | 
			
		||||
            return;        
 | 
			
		||||
 | 
			
		||||
        if (this._ssProxy.screenSaverActive)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        global.play_theme_sound(0, 'device-removed-media');        
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDriveEjectButton: function(monitor, drive) {
 | 
			
		||||
        // TODO: this code path is not tested, as the GVfs volume monitor
 | 
			
		||||
        // doesn't emit this signal just yet.
 | 
			
		||||
        if (!this.ckListener.sessionActive)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // we force stop/eject in this case, so we don't have to pass a
 | 
			
		||||
        // mount operation object
 | 
			
		||||
        if (drive.can_stop()) {
 | 
			
		||||
            drive.stop
 | 
			
		||||
                (Gio.MountUnmountFlags.FORCE, null, null,
 | 
			
		||||
                 Lang.bind(this, function(drive, res) {
 | 
			
		||||
                     try {
 | 
			
		||||
                         drive.stop_finish(res);
 | 
			
		||||
                     } catch (e) {
 | 
			
		||||
                         log("Unable to stop the drive after drive-eject-button " + e.toString());
 | 
			
		||||
                     }
 | 
			
		||||
                 }));
 | 
			
		||||
        } else if (drive.can_eject()) {
 | 
			
		||||
            drive.eject_with_operation 
 | 
			
		||||
                (Gio.MountUnmountFlags.FORCE, null, null,
 | 
			
		||||
                 Lang.bind(this, function(drive, res) {
 | 
			
		||||
                     try {
 | 
			
		||||
                         drive.eject_with_operation_finish(res);
 | 
			
		||||
                     } catch (e) {
 | 
			
		||||
                         log("Unable to eject the drive after drive-eject-button " + e.toString());
 | 
			
		||||
                     }
 | 
			
		||||
                 }));
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onVolumeAdded: function(monitor, volume) {
 | 
			
		||||
        this._checkAndMountVolume(volume);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _checkAndMountVolume: function(volume, params) {
 | 
			
		||||
        params = Params.parse(params, { checkSession: true,
 | 
			
		||||
                                        useMountOp: true });
 | 
			
		||||
 | 
			
		||||
        if (params.checkSession) {
 | 
			
		||||
            // if we're not in the current ConsoleKit session,
 | 
			
		||||
            // don't attempt automount
 | 
			
		||||
            if (!this.ckListener.sessionActive)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            if (this._ssProxy.screenSaverActive) {
 | 
			
		||||
                if (this._volumeQueue.indexOf(volume) == -1)
 | 
			
		||||
                    this._volumeQueue.push(volume);
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Volume is already mounted, don't bother.
 | 
			
		||||
        if (volume.get_mount())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (!this._settings.get_boolean(SETTING_ENABLE_AUTOMOUNT) ||
 | 
			
		||||
            !volume.should_automount() ||
 | 
			
		||||
            !volume.can_mount()) {
 | 
			
		||||
            // allow the autorun to run anyway; this can happen if the
 | 
			
		||||
            // mount gets added programmatically later, even if 
 | 
			
		||||
            // should_automount() or can_mount() are false, like for
 | 
			
		||||
            // blank optical media.
 | 
			
		||||
            this._allowAutorun(volume);
 | 
			
		||||
            this._allowAutorunExpire(volume);
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (params.useMountOp) {
 | 
			
		||||
            let operation = new ShellMountOperation.ShellMountOperation(volume);
 | 
			
		||||
            this._mountVolume(volume, operation.mountOp);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._mountVolume(volume, null);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _mountVolume: function(volume, operation) {
 | 
			
		||||
        this._allowAutorun(volume);
 | 
			
		||||
        volume.mount(0, operation, null,
 | 
			
		||||
                     Lang.bind(this, this._onVolumeMounted));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onVolumeMounted: function(volume, res) {
 | 
			
		||||
        this._allowAutorunExpire(volume);
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            volume.mount_finish(res);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            let string = e.toString();
 | 
			
		||||
 | 
			
		||||
            // FIXME: needs proper error code handling instead of this
 | 
			
		||||
            // See https://bugzilla.gnome.org/show_bug.cgi?id=591480
 | 
			
		||||
            if (string.indexOf('No key available with this passphrase') != -1)
 | 
			
		||||
                this._reaskPassword(volume);
 | 
			
		||||
            else
 | 
			
		||||
                log('Unable to mount volume ' + volume.get_name() + ': ' + string);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onVolumeRemoved: function(monitor, volume) {
 | 
			
		||||
        this._volumeQueue = 
 | 
			
		||||
            this._volumeQueue.filter(function(element) {
 | 
			
		||||
                return (element != volume);
 | 
			
		||||
            });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _reaskPassword: function(volume) {
 | 
			
		||||
        let operation = new ShellMountOperation.ShellMountOperation(volume, { reaskPassword: true });
 | 
			
		||||
        this._mountVolume(volume, operation.mountOp);        
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _allowAutorun: function(volume) {
 | 
			
		||||
        volume.allowAutorun = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _allowAutorunExpire: function(volume) {
 | 
			
		||||
        Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, function() {
 | 
			
		||||
            volume.allowAutorun = false;
 | 
			
		||||
            return false;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										603
									
								
								js/ui/autorunManager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,603 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
const ShellMountOperation = imports.ui.shellMountOperation;
 | 
			
		||||
 | 
			
		||||
// GSettings keys
 | 
			
		||||
const SETTINGS_SCHEMA = 'org.gnome.desktop.media-handling';
 | 
			
		||||
const SETTING_DISABLE_AUTORUN = 'autorun-never';
 | 
			
		||||
const SETTING_START_APP = 'autorun-x-content-start-app';
 | 
			
		||||
const SETTING_IGNORE = 'autorun-x-content-ignore';
 | 
			
		||||
const SETTING_OPEN_FOLDER = 'autorun-x-content-open-folder';
 | 
			
		||||
 | 
			
		||||
const AutorunSetting = {
 | 
			
		||||
    RUN: 0,
 | 
			
		||||
    IGNORE: 1,
 | 
			
		||||
    FILES: 2,
 | 
			
		||||
    ASK: 3
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// misc utils
 | 
			
		||||
function ignoreAutorunForMount(mount) {
 | 
			
		||||
    let root = mount.get_root();
 | 
			
		||||
    let volume = mount.get_volume();
 | 
			
		||||
 | 
			
		||||
    if ((root.is_native() && !isMountRootHidden(root)) ||
 | 
			
		||||
        (volume && volume.allowAutorun && volume.should_automount()))
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isMountRootHidden(root) {
 | 
			
		||||
    let path = root.get_path();
 | 
			
		||||
 | 
			
		||||
    // skip any mounts in hidden directory hierarchies
 | 
			
		||||
    return (path.indexOf('/.') != -1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function startAppForMount(app, mount) {
 | 
			
		||||
    let files = [];
 | 
			
		||||
    let root = mount.get_root();
 | 
			
		||||
    let retval = false;
 | 
			
		||||
 | 
			
		||||
    files.push(root);
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        retval = app.launch(files, 
 | 
			
		||||
                            global.create_app_launch_context())
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        log('Unable to launch the application ' + app.get_name()
 | 
			
		||||
            + ': ' + e.toString());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return retval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************/
 | 
			
		||||
 | 
			
		||||
const HotplugSnifferIface = <interface name="org.gnome.Shell.HotplugSniffer">
 | 
			
		||||
<method name="SniffURI">
 | 
			
		||||
    <arg type="s" direction="in" />
 | 
			
		||||
    <arg type="as" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const HotplugSnifferProxy = Gio.DBusProxy.makeProxyWrapper(HotplugSnifferIface);
 | 
			
		||||
function HotplugSniffer() {
 | 
			
		||||
    return new HotplugSnifferProxy(Gio.DBus.session,
 | 
			
		||||
                                   'org.gnome.Shell.HotplugSniffer',
 | 
			
		||||
                                   '/org/gnome/Shell/HotplugSniffer');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ContentTypeDiscoverer = new Lang.Class({
 | 
			
		||||
    Name: 'ContentTypeDiscoverer',
 | 
			
		||||
 | 
			
		||||
    _init: function(callback) {
 | 
			
		||||
        this._callback = callback;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    guessContentTypes: function(mount) {
 | 
			
		||||
        // guess mount's content types using GIO
 | 
			
		||||
        mount.guess_content_type(false, null,
 | 
			
		||||
                                 Lang.bind(this,
 | 
			
		||||
                                           this._onContentTypeGuessed));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onContentTypeGuessed: function(mount, res) {
 | 
			
		||||
        let contentTypes = [];
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            contentTypes = mount.guess_content_type_finish(res);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            log('Unable to guess content types on added mount ' + mount.get_name()
 | 
			
		||||
                + ': ' + e.toString());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (contentTypes.length) {
 | 
			
		||||
            this._emitCallback(mount, contentTypes);
 | 
			
		||||
        } else {
 | 
			
		||||
            let root = mount.get_root();
 | 
			
		||||
 | 
			
		||||
            let hotplugSniffer = new HotplugSniffer();
 | 
			
		||||
            hotplugSniffer.SniffURIRemote(root.get_uri(),
 | 
			
		||||
                 Lang.bind(this, function([contentTypes]) {
 | 
			
		||||
                     this._emitCallback(mount, contentTypes);
 | 
			
		||||
                 }));
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _emitCallback: function(mount, contentTypes) {
 | 
			
		||||
        if (!contentTypes)
 | 
			
		||||
            contentTypes = [];
 | 
			
		||||
 | 
			
		||||
        // we're not interested in win32 software content types here
 | 
			
		||||
        contentTypes = contentTypes.filter(function(type) {
 | 
			
		||||
            return (type != 'x-content/win32-software');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let apps = [];
 | 
			
		||||
        contentTypes.forEach(function(type) {
 | 
			
		||||
            let app = Gio.app_info_get_default_for_type(type, false);
 | 
			
		||||
 | 
			
		||||
            if (app)
 | 
			
		||||
                apps.push(app);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (apps.length == 0)
 | 
			
		||||
            apps.push(Gio.app_info_get_default_for_type('inode/directory', false));
 | 
			
		||||
 | 
			
		||||
        this._callback(mount, apps, contentTypes);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AutorunManager = new Lang.Class({
 | 
			
		||||
    Name: 'AutorunManager',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._volumeMonitor = Gio.VolumeMonitor.get();
 | 
			
		||||
 | 
			
		||||
        this._volumeMonitor.connect('mount-added',
 | 
			
		||||
                                    Lang.bind(this,
 | 
			
		||||
                                              this._onMountAdded));
 | 
			
		||||
        this._volumeMonitor.connect('mount-removed',
 | 
			
		||||
                                    Lang.bind(this,
 | 
			
		||||
                                              this._onMountRemoved));
 | 
			
		||||
 | 
			
		||||
        this._transDispatcher = new AutorunTransientDispatcher();
 | 
			
		||||
        this._createResidentSource();
 | 
			
		||||
 | 
			
		||||
        let mounts = this._volumeMonitor.get_mounts();
 | 
			
		||||
 | 
			
		||||
        mounts.forEach(Lang.bind(this, function (mount) {
 | 
			
		||||
            let discoverer = new ContentTypeDiscoverer(Lang.bind (this, 
 | 
			
		||||
                function (mount, apps) {
 | 
			
		||||
                    this._residentSource.addMount(mount, apps);
 | 
			
		||||
                }));
 | 
			
		||||
 | 
			
		||||
            discoverer.guessContentTypes(mount);
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createResidentSource: function() {
 | 
			
		||||
        this._residentSource = new AutorunResidentSource();
 | 
			
		||||
        this._residentSource.connect('destroy',
 | 
			
		||||
                                     Lang.bind(this,
 | 
			
		||||
                                               this._createResidentSource));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onMountAdded: function(monitor, mount) {
 | 
			
		||||
        // don't do anything if our session is not the currently
 | 
			
		||||
        // active one
 | 
			
		||||
        if (!Main.automountManager.ckListener.sessionActive)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let discoverer = new ContentTypeDiscoverer(Lang.bind (this,
 | 
			
		||||
            function (mount, apps, contentTypes) {
 | 
			
		||||
                this._transDispatcher.addMount(mount, apps, contentTypes);
 | 
			
		||||
                this._residentSource.addMount(mount, apps);
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        discoverer.guessContentTypes(mount);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onMountRemoved: function(monitor, mount) {
 | 
			
		||||
        this._transDispatcher.removeMount(mount);
 | 
			
		||||
        this._residentSource.removeMount(mount);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    ejectMount: function(mount) {
 | 
			
		||||
        let mountOp = new ShellMountOperation.ShellMountOperation(mount);
 | 
			
		||||
 | 
			
		||||
        // first, see if we have a drive
 | 
			
		||||
        let drive = mount.get_drive();
 | 
			
		||||
        let volume = mount.get_volume();
 | 
			
		||||
 | 
			
		||||
        if (drive &&
 | 
			
		||||
            drive.get_start_stop_type() == Gio.DriveStartStopType.SHUTDOWN &&
 | 
			
		||||
            drive.can_stop()) {
 | 
			
		||||
            drive.stop(0, mountOp.mountOp, null,
 | 
			
		||||
                       Lang.bind(this, this._onStop));
 | 
			
		||||
        } else {
 | 
			
		||||
            if (mount.can_eject()) {
 | 
			
		||||
                mount.eject_with_operation(0, mountOp.mountOp, null,
 | 
			
		||||
                                           Lang.bind(this, this._onEject));
 | 
			
		||||
            } else if (volume && volume.can_eject()) {
 | 
			
		||||
                volume.eject_with_operation(0, mountOp.mountOp, null,
 | 
			
		||||
                                            Lang.bind(this, this._onEject));
 | 
			
		||||
            } else if (drive && drive.can_eject()) {
 | 
			
		||||
                drive.eject_with_operation(0, mountOp.mountOp, null,
 | 
			
		||||
                                           Lang.bind(this, this._onEject));
 | 
			
		||||
            } else if (mount.can_unmount()) {
 | 
			
		||||
                mount.unmount_with_operation(0, mountOp.mountOp, null,
 | 
			
		||||
                                             Lang.bind(this, this._onUnmount));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onUnmount: function(mount, res) {
 | 
			
		||||
        try {
 | 
			
		||||
            mount.unmount_with_operation_finish(res);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            // FIXME: we need to ignore G_IO_ERROR_FAILED_HANDLED errors here
 | 
			
		||||
            // but we can't access the error code from JS.
 | 
			
		||||
            // See https://bugzilla.gnome.org/show_bug.cgi?id=591480
 | 
			
		||||
            log('Unable to eject the mount ' + mount.get_name() 
 | 
			
		||||
                + ': ' + e.toString());
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onEject: function(source, res) {
 | 
			
		||||
        try {
 | 
			
		||||
            source.eject_with_operation_finish(res);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            // FIXME: we need to ignore G_IO_ERROR_FAILED_HANDLED errors here
 | 
			
		||||
            // but we can't access the error code from JS.
 | 
			
		||||
            // See https://bugzilla.gnome.org/show_bug.cgi?id=591480
 | 
			
		||||
            log('Unable to eject the drive ' + source.get_name() 
 | 
			
		||||
                + ': ' + e.toString());
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onStop: function(drive, res) {
 | 
			
		||||
        try {
 | 
			
		||||
            drive.stop_finish(res);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            // FIXME: we need to ignore G_IO_ERROR_FAILED_HANDLED errors here
 | 
			
		||||
            // but we can't access the error code from JS.
 | 
			
		||||
            // See https://bugzilla.gnome.org/show_bug.cgi?id=591480
 | 
			
		||||
            log('Unable to stop the drive ' + drive.get_name() 
 | 
			
		||||
                + ': ' + e.toString());
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AutorunResidentSource = new Lang.Class({
 | 
			
		||||
    Name: 'AutorunResidentSource',
 | 
			
		||||
    Extends: MessageTray.Source,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.parent(_("Removable Devices"));
 | 
			
		||||
 | 
			
		||||
        this._mounts = [];
 | 
			
		||||
 | 
			
		||||
        this._notification = new AutorunResidentNotification(this);
 | 
			
		||||
        this._setSummaryIcon(this.createNotificationIcon());
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addMount: function(mount, apps) {
 | 
			
		||||
        if (ignoreAutorunForMount(mount))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let filtered = this._mounts.filter(function (element) {
 | 
			
		||||
            return (element.mount == mount);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (filtered.length != 0)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let element = { mount: mount, apps: apps };
 | 
			
		||||
        this._mounts.push(element);
 | 
			
		||||
        this._redisplay();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    removeMount: function(mount) {
 | 
			
		||||
        this._mounts =
 | 
			
		||||
            this._mounts.filter(function (element) {
 | 
			
		||||
                return (element.mount != mount);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        this._redisplay();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _redisplay: function() {
 | 
			
		||||
        if (this._mounts.length == 0) {
 | 
			
		||||
            this._notification.destroy();
 | 
			
		||||
            this.destroy();
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._notification.updateForMounts(this._mounts);
 | 
			
		||||
 | 
			
		||||
        // add ourselves as a source, and push the notification
 | 
			
		||||
        if (!Main.messageTray.contains(this)) {
 | 
			
		||||
            Main.messageTray.add(this);
 | 
			
		||||
            this.pushNotification(this._notification);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createNotificationIcon: function() {
 | 
			
		||||
        return new St.Icon ({ icon_name: 'media-removable',
 | 
			
		||||
                              icon_type: St.IconType.FULLCOLOR,
 | 
			
		||||
                              icon_size: this.ICON_SIZE });
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AutorunResidentNotification = new Lang.Class({
 | 
			
		||||
    Name: 'AutorunResidentNotification',
 | 
			
		||||
    Extends: MessageTray.Notification,
 | 
			
		||||
 | 
			
		||||
    _init: function(source) {
 | 
			
		||||
        this.parent(source, source.title, null, { customContent: true });
 | 
			
		||||
 | 
			
		||||
        // set the notification as resident
 | 
			
		||||
        this.setResident(true);
 | 
			
		||||
 | 
			
		||||
        this._layout = new St.BoxLayout ({ style_class: 'hotplug-resident-box',
 | 
			
		||||
                                           vertical: true });
 | 
			
		||||
 | 
			
		||||
        this.addActor(this._layout,
 | 
			
		||||
                      { x_expand: true,
 | 
			
		||||
                        x_fill: true });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    updateForMounts: function(mounts) {
 | 
			
		||||
        // remove all the layout content
 | 
			
		||||
        this._layout.destroy_children();
 | 
			
		||||
 | 
			
		||||
        for (let idx = 0; idx < mounts.length; idx++) {
 | 
			
		||||
            let element = mounts[idx];
 | 
			
		||||
 | 
			
		||||
            let actor = this._itemForMount(element.mount, element.apps);
 | 
			
		||||
            this._layout.add(actor, { x_fill: true,
 | 
			
		||||
                                      expand: true });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _itemForMount: function(mount, apps) {
 | 
			
		||||
        let item = new St.BoxLayout();
 | 
			
		||||
 | 
			
		||||
        // prepare the mount button content
 | 
			
		||||
        let mountLayout = new St.BoxLayout();
 | 
			
		||||
 | 
			
		||||
        let mountIcon = new St.Icon({ gicon: mount.get_icon(),
 | 
			
		||||
                                      style_class: 'hotplug-resident-mount-icon' });
 | 
			
		||||
        mountLayout.add_actor(mountIcon);
 | 
			
		||||
 | 
			
		||||
        let labelBin = new St.Bin({ y_align: St.Align.MIDDLE });
 | 
			
		||||
        let mountLabel =
 | 
			
		||||
            new St.Label({ text: mount.get_name(),
 | 
			
		||||
                           style_class: 'hotplug-resident-mount-label',
 | 
			
		||||
                           track_hover: true,
 | 
			
		||||
                           reactive: true });
 | 
			
		||||
        labelBin.add_actor(mountLabel);
 | 
			
		||||
        mountLayout.add_actor(labelBin);
 | 
			
		||||
 | 
			
		||||
        let mountButton = new St.Button({ child: mountLayout,
 | 
			
		||||
                                          x_align: St.Align.START,
 | 
			
		||||
                                          x_fill: true,
 | 
			
		||||
                                          style_class: 'hotplug-resident-mount',
 | 
			
		||||
                                          button_mask: St.ButtonMask.ONE });
 | 
			
		||||
        item.add(mountButton, { x_align: St.Align.START,
 | 
			
		||||
                                expand: true });
 | 
			
		||||
 | 
			
		||||
        let ejectIcon = 
 | 
			
		||||
            new St.Icon({ icon_name: 'media-eject',
 | 
			
		||||
                          style_class: 'hotplug-resident-eject-icon' });
 | 
			
		||||
 | 
			
		||||
        let ejectButton =
 | 
			
		||||
            new St.Button({ style_class: 'hotplug-resident-eject-button',
 | 
			
		||||
                            button_mask: St.ButtonMask.ONE,
 | 
			
		||||
                            child: ejectIcon });
 | 
			
		||||
        item.add(ejectButton, { x_align: St.Align.END });
 | 
			
		||||
 | 
			
		||||
        // now connect signals
 | 
			
		||||
        mountButton.connect('clicked', Lang.bind(this, function(actor, event) {
 | 
			
		||||
            startAppForMount(apps[0], mount);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        ejectButton.connect('clicked', Lang.bind(this, function() {
 | 
			
		||||
            Main.autorunManager.ejectMount(mount);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return item;
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AutorunTransientDispatcher = new Lang.Class({
 | 
			
		||||
    Name: 'AutorunTransientDispatcher',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._sources = [];
 | 
			
		||||
        this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getAutorunSettingForType: function(contentType) {
 | 
			
		||||
        let runApp = this._settings.get_strv(SETTING_START_APP);
 | 
			
		||||
        if (runApp.indexOf(contentType) != -1)
 | 
			
		||||
            return AutorunSetting.RUN;
 | 
			
		||||
 | 
			
		||||
        let ignore = this._settings.get_strv(SETTING_IGNORE);
 | 
			
		||||
        if (ignore.indexOf(contentType) != -1)
 | 
			
		||||
            return AutorunSetting.IGNORE;
 | 
			
		||||
 | 
			
		||||
        let openFiles = this._settings.get_strv(SETTING_OPEN_FOLDER);
 | 
			
		||||
        if (openFiles.indexOf(contentType) != -1)
 | 
			
		||||
            return AutorunSetting.FILES;
 | 
			
		||||
 | 
			
		||||
        return AutorunSetting.ASK;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getSourceForMount: function(mount) {
 | 
			
		||||
        let filtered =
 | 
			
		||||
            this._sources.filter(function (source) {
 | 
			
		||||
                return (source.mount == mount);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        // we always make sure not to add two sources for the same
 | 
			
		||||
        // mount in addMount(), so it's safe to assume filtered.length
 | 
			
		||||
        // is always either 1 or 0.
 | 
			
		||||
        if (filtered.length == 1)
 | 
			
		||||
            return filtered[0];
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _addSource: function(mount, apps) {
 | 
			
		||||
        // if we already have a source showing for this 
 | 
			
		||||
        // mount, return
 | 
			
		||||
        if (this._getSourceForMount(mount))
 | 
			
		||||
            return;
 | 
			
		||||
     
 | 
			
		||||
        // add a new source
 | 
			
		||||
        this._sources.push(new AutorunTransientSource(mount, apps));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addMount: function(mount, apps, contentTypes) {
 | 
			
		||||
        // if autorun is disabled globally, return
 | 
			
		||||
        if (this._settings.get_boolean(SETTING_DISABLE_AUTORUN))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // if the mount doesn't want to be autorun, return
 | 
			
		||||
        if (ignoreAutorunForMount(mount))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let setting = this._getAutorunSettingForType(contentTypes[0]);
 | 
			
		||||
 | 
			
		||||
        // check at the settings for the first content type
 | 
			
		||||
        // to see whether we should ask
 | 
			
		||||
        if (setting == AutorunSetting.IGNORE)
 | 
			
		||||
            return; // return right away
 | 
			
		||||
 | 
			
		||||
        let success = false;
 | 
			
		||||
        let app = null;
 | 
			
		||||
 | 
			
		||||
        if (setting == AutorunSetting.RUN) {
 | 
			
		||||
            app = Gio.app_info_get_default_for_type(contentTypes[0], false);
 | 
			
		||||
        } else if (setting == AutorunSetting.FILES) {
 | 
			
		||||
            app = Gio.app_info_get_default_for_type('inode/directory', false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (app)
 | 
			
		||||
            success = startAppForMount(app, mount);
 | 
			
		||||
 | 
			
		||||
        // we fallback here also in case the settings did not specify 'ask',
 | 
			
		||||
        // but we failed launching the default app or the default file manager
 | 
			
		||||
        if (!success)
 | 
			
		||||
            this._addSource(mount, apps);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    removeMount: function(mount) {
 | 
			
		||||
        let source = this._getSourceForMount(mount);
 | 
			
		||||
        
 | 
			
		||||
        // if we aren't tracking this mount, don't do anything
 | 
			
		||||
        if (!source)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // destroy the notification source
 | 
			
		||||
        source.destroy();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AutorunTransientSource = new Lang.Class({
 | 
			
		||||
    Name: 'AutorunTransientSource',
 | 
			
		||||
    Extends: MessageTray.Source,
 | 
			
		||||
 | 
			
		||||
    _init: function(mount, apps) {
 | 
			
		||||
        this.parent(mount.get_name());
 | 
			
		||||
 | 
			
		||||
        this.mount = mount;
 | 
			
		||||
        this.apps = apps;
 | 
			
		||||
 | 
			
		||||
        this._notification = new AutorunTransientNotification(this);
 | 
			
		||||
        this._setSummaryIcon(this.createNotificationIcon());
 | 
			
		||||
 | 
			
		||||
        // add ourselves as a source, and popup the notification
 | 
			
		||||
        Main.messageTray.add(this);
 | 
			
		||||
        this.notify(this._notification);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createNotificationIcon: function() {
 | 
			
		||||
        return new St.Icon({ gicon: this.mount.get_icon(),
 | 
			
		||||
                             icon_size: this.ICON_SIZE });
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AutorunTransientNotification = new Lang.Class({
 | 
			
		||||
    Name: 'AutorunTransientNotification',
 | 
			
		||||
    Extends: MessageTray.Notification,
 | 
			
		||||
 | 
			
		||||
    _init: function(source) {
 | 
			
		||||
        this.parent(source, source.title, null, { customContent: true });
 | 
			
		||||
 | 
			
		||||
        this._box = new St.BoxLayout({ style_class: 'hotplug-transient-box',
 | 
			
		||||
                                       vertical: true });
 | 
			
		||||
        this.addActor(this._box);
 | 
			
		||||
 | 
			
		||||
        this._mount = source.mount;
 | 
			
		||||
 | 
			
		||||
        source.apps.forEach(Lang.bind(this, function (app) {
 | 
			
		||||
            let actor = this._buttonForApp(app);
 | 
			
		||||
 | 
			
		||||
            if (actor)
 | 
			
		||||
                this._box.add(actor, { x_fill: true,
 | 
			
		||||
                                       x_align: St.Align.START });
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        this._box.add(this._buttonForEject(), { x_fill: true,
 | 
			
		||||
                                                x_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        // set the notification to transient and urgent, so that it
 | 
			
		||||
        // expands out
 | 
			
		||||
        this.setTransient(true);
 | 
			
		||||
        this.setUrgency(MessageTray.Urgency.CRITICAL);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _buttonForApp: function(app) {
 | 
			
		||||
        let box = new St.BoxLayout();
 | 
			
		||||
        let icon = new St.Icon({ gicon: app.get_icon(),
 | 
			
		||||
                                 style_class: 'hotplug-notification-item-icon' });
 | 
			
		||||
        box.add(icon);
 | 
			
		||||
 | 
			
		||||
        let label = new St.Bin({ y_align: St.Align.MIDDLE,
 | 
			
		||||
                                 child: new St.Label
 | 
			
		||||
                                 ({ text: _("Open with %s").format(app.get_display_name()) })
 | 
			
		||||
                               });
 | 
			
		||||
        box.add(label);
 | 
			
		||||
 | 
			
		||||
        let button = new St.Button({ child: box,
 | 
			
		||||
                                     x_fill: true,
 | 
			
		||||
                                     x_align: St.Align.START,
 | 
			
		||||
                                     button_mask: St.ButtonMask.ONE,
 | 
			
		||||
                                     style_class: 'hotplug-notification-item' });
 | 
			
		||||
 | 
			
		||||
        button.connect('clicked', Lang.bind(this, function() {
 | 
			
		||||
            startAppForMount(app, this._mount);
 | 
			
		||||
            this.destroy();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return button;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _buttonForEject: function() {
 | 
			
		||||
        let box = new St.BoxLayout();
 | 
			
		||||
        let icon = new St.Icon({ icon_name: 'media-eject',
 | 
			
		||||
                                 style_class: 'hotplug-notification-item-icon' });
 | 
			
		||||
        box.add(icon);
 | 
			
		||||
 | 
			
		||||
        let label = new St.Bin({ y_align: St.Align.MIDDLE,
 | 
			
		||||
                                 child: new St.Label
 | 
			
		||||
                                 ({ text: _("Eject") })
 | 
			
		||||
                               });
 | 
			
		||||
        box.add(label);
 | 
			
		||||
 | 
			
		||||
        let button = new St.Button({ child: box,
 | 
			
		||||
                                     x_fill: true,
 | 
			
		||||
                                     x_align: St.Align.START,
 | 
			
		||||
                                     button_mask: St.ButtonMask.ONE,
 | 
			
		||||
                                     style_class: 'hotplug-notification-item' });
 | 
			
		||||
 | 
			
		||||
        button.connect('clicked', Lang.bind(this, function() {
 | 
			
		||||
            Main.autorunManager.ejectMount(this._mount);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return button;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -1,10 +1,12 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
const POPUP_ANIMATION_TIME = 0.15;
 | 
			
		||||
@@ -19,11 +21,9 @@ const POPUP_ANIMATION_TIME = 0.15;
 | 
			
		||||
 * placed.  The arrow position may be controlled via setArrowOrigin().
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
function BoxPointer(side, binProperties) {
 | 
			
		||||
    this._init(side, binProperties);
 | 
			
		||||
}
 | 
			
		||||
const BoxPointer = new Lang.Class({
 | 
			
		||||
    Name: 'BoxPointer',
 | 
			
		||||
 | 
			
		||||
BoxPointer.prototype = {
 | 
			
		||||
    _init: function(arrowSide, binProperties) {
 | 
			
		||||
        this._arrowSide = arrowSide;
 | 
			
		||||
        this._arrowOrigin = 0;
 | 
			
		||||
@@ -40,80 +40,81 @@ BoxPointer.prototype = {
 | 
			
		||||
        this._border.connect('repaint', Lang.bind(this, this._drawBorder));
 | 
			
		||||
        this._container.add_actor(this._border);
 | 
			
		||||
        this.bin.raise(this._border);
 | 
			
		||||
        this._xOffset = 0;
 | 
			
		||||
        this._yOffset = 0;
 | 
			
		||||
        this._xPosition = 0;
 | 
			
		||||
        this._yPosition = 0;
 | 
			
		||||
        this._sourceAlignment = 0.5;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show: function(animate, onComplete) {
 | 
			
		||||
        let x = this.actor.x;
 | 
			
		||||
        let y = this.actor.y;
 | 
			
		||||
        let themeNode = this.actor.get_theme_node();
 | 
			
		||||
        let rise = themeNode.get_length('-arrow-rise');
 | 
			
		||||
 | 
			
		||||
        this.actor.opacity = 0;
 | 
			
		||||
        this.opacity = 0;
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
 | 
			
		||||
        if (animate) {
 | 
			
		||||
            switch (this._arrowSide) {
 | 
			
		||||
                case St.Side.TOP:
 | 
			
		||||
                    this.actor.y -= rise;
 | 
			
		||||
                    this.yOffset = -rise;
 | 
			
		||||
                    break;
 | 
			
		||||
                case St.Side.BOTTOM:
 | 
			
		||||
                    this.actor.y += rise;
 | 
			
		||||
                    this.yOffset = rise;
 | 
			
		||||
                    break;
 | 
			
		||||
                case St.Side.LEFT:
 | 
			
		||||
                    this.actor.x -= rise;
 | 
			
		||||
                    this.xOffset = -rise;
 | 
			
		||||
                    break;
 | 
			
		||||
                case St.Side.RIGHT:
 | 
			
		||||
                    this.actor.x += rise;
 | 
			
		||||
                    this.xOffset = rise;
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Tweener.addTween(this.actor, { opacity: 255,
 | 
			
		||||
                                       x: x,
 | 
			
		||||
                                       y: y,
 | 
			
		||||
                                       transition: "linear",
 | 
			
		||||
                                       onComplete: onComplete,
 | 
			
		||||
                                       time: POPUP_ANIMATION_TIME });
 | 
			
		||||
        Tweener.addTween(this, { opacity: 255,
 | 
			
		||||
                                 xOffset: 0,
 | 
			
		||||
                                 yOffset: 0,
 | 
			
		||||
                                 transition: 'linear',
 | 
			
		||||
                                 onComplete: onComplete,
 | 
			
		||||
                                 time: POPUP_ANIMATION_TIME });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hide: function(animate, onComplete) {
 | 
			
		||||
        let x = this.actor.x;
 | 
			
		||||
        let y = this.actor.y;
 | 
			
		||||
        let originalX = this.actor.x;
 | 
			
		||||
        let originalY = this.actor.y;
 | 
			
		||||
        let xOffset = 0;
 | 
			
		||||
        let yOffset = 0;
 | 
			
		||||
        let themeNode = this.actor.get_theme_node();
 | 
			
		||||
        let rise = themeNode.get_length('-arrow-rise');
 | 
			
		||||
 | 
			
		||||
        if (animate) {
 | 
			
		||||
            switch (this._arrowSide) {
 | 
			
		||||
                case St.Side.TOP:
 | 
			
		||||
                    y += rise;
 | 
			
		||||
                    yOffset = rise;
 | 
			
		||||
                    break;
 | 
			
		||||
                case St.Side.BOTTOM:
 | 
			
		||||
                    y -= rise;
 | 
			
		||||
                    yOffset = -rise;
 | 
			
		||||
                    break;
 | 
			
		||||
                case St.Side.LEFT:
 | 
			
		||||
                    x += rise;
 | 
			
		||||
                    xOffset = rise;
 | 
			
		||||
                    break;
 | 
			
		||||
                case St.Side.RIGHT:
 | 
			
		||||
                    x -= rise;
 | 
			
		||||
                    xOffset = -rise;
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Tweener.addTween(this.actor, { opacity: 0,
 | 
			
		||||
                                       x: x,
 | 
			
		||||
                                       y: y,
 | 
			
		||||
                                       transition: "linear",
 | 
			
		||||
                                       time: POPUP_ANIMATION_TIME,
 | 
			
		||||
                                       onComplete: Lang.bind(this, function () {
 | 
			
		||||
                                           this.actor.hide();
 | 
			
		||||
                                           this.actor.x = originalX;
 | 
			
		||||
                                           this.actor.y = originalY;
 | 
			
		||||
                                           if (onComplete)
 | 
			
		||||
                                               onComplete();
 | 
			
		||||
                                       })
 | 
			
		||||
                                     });
 | 
			
		||||
        Tweener.addTween(this, { opacity: 0,
 | 
			
		||||
                                 xOffset: xOffset,
 | 
			
		||||
                                 yOffset: yOffset,
 | 
			
		||||
                                 transition: 'linear',
 | 
			
		||||
                                 time: POPUP_ANIMATION_TIME,
 | 
			
		||||
                                 onComplete: Lang.bind(this, function () {
 | 
			
		||||
                                     this.actor.hide();
 | 
			
		||||
                                     this.xOffset = 0;
 | 
			
		||||
                                     this.yOffset = 0;
 | 
			
		||||
                                     if (onComplete)
 | 
			
		||||
                                         onComplete();
 | 
			
		||||
                                 })
 | 
			
		||||
                               });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _adjustAllocationForArrow: function(isWidth, alloc) {
 | 
			
		||||
@@ -176,6 +177,9 @@ BoxPointer.prototype = {
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
        this.bin.allocate(childBox, flags);
 | 
			
		||||
 | 
			
		||||
        if (this._sourceActor && this._sourceActor.mapped)
 | 
			
		||||
            this._reposition(this._sourceActor, this._arrowAlignment);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _drawBorder: function(area) {
 | 
			
		||||
@@ -301,24 +305,43 @@ BoxPointer.prototype = {
 | 
			
		||||
        cr.stroke();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setPosition: function(sourceActor, gap, alignment) {
 | 
			
		||||
    setPosition: function(sourceActor, alignment) {
 | 
			
		||||
        // We need to show it now to force an allocation,
 | 
			
		||||
        // so that we can query the correct size.
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
 | 
			
		||||
        this._sourceActor = sourceActor;
 | 
			
		||||
        this._arrowAlignment = alignment;
 | 
			
		||||
 | 
			
		||||
        this._reposition(sourceActor, alignment);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setSourceAlignment: function(alignment) {
 | 
			
		||||
        this._sourceAlignment = alignment;
 | 
			
		||||
 | 
			
		||||
        if (!this._sourceActor)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // We need to show it now to force an allocation,
 | 
			
		||||
        // so that we can query the correct size.
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
 | 
			
		||||
        this._reposition(this._sourceActor, this._arrowAlignment);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _reposition: function(sourceActor, alignment) {
 | 
			
		||||
        // Position correctly relative to the sourceActor
 | 
			
		||||
        let sourceNode = sourceActor.get_theme_node();
 | 
			
		||||
        let sourceContentBox = sourceNode.get_content_box(sourceActor.get_allocation_box());
 | 
			
		||||
        let [sourceX, sourceY] = sourceActor.get_transformed_position();
 | 
			
		||||
        let [sourceWidth, sourceHeight] = sourceActor.get_transformed_size();
 | 
			
		||||
        let sourceCenterX = sourceX + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) / 2;
 | 
			
		||||
        let sourceCenterY = sourceY + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) / 2;
 | 
			
		||||
        let sourceAllocation = Shell.util_get_transformed_allocation(sourceActor);
 | 
			
		||||
        let sourceCenterX = sourceAllocation.x1 + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * this._sourceAlignment;
 | 
			
		||||
        let sourceCenterY = sourceAllocation.y1 + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) * this._sourceAlignment;
 | 
			
		||||
        let [minWidth, minHeight, natWidth, natHeight] = this.actor.get_preferred_size();
 | 
			
		||||
 | 
			
		||||
        // We also want to keep it onscreen, and separated from the
 | 
			
		||||
        // edge by the same distance as the main part of the box is
 | 
			
		||||
        // separated from its sourceActor
 | 
			
		||||
        let primary = global.get_primary_monitor();
 | 
			
		||||
        let monitor = Main.layoutManager.findMonitorForActor(sourceActor);
 | 
			
		||||
        let themeNode = this.actor.get_theme_node();
 | 
			
		||||
        let borderWidth = themeNode.get_length('-arrow-border-width');
 | 
			
		||||
        let arrowBase = themeNode.get_length('-arrow-base');
 | 
			
		||||
@@ -326,20 +349,23 @@ BoxPointer.prototype = {
 | 
			
		||||
        let margin = (4 * borderRadius + borderWidth + arrowBase);
 | 
			
		||||
        let halfMargin = margin / 2;
 | 
			
		||||
 | 
			
		||||
        let themeNode = this.actor.get_theme_node();
 | 
			
		||||
        let gap = themeNode.get_length('-boxpointer-gap');
 | 
			
		||||
 | 
			
		||||
        let resX, resY;
 | 
			
		||||
 | 
			
		||||
        switch (this._arrowSide) {
 | 
			
		||||
        case St.Side.TOP:
 | 
			
		||||
            resY = sourceY + sourceHeight + gap;
 | 
			
		||||
            resY = sourceAllocation.y2 + gap;
 | 
			
		||||
            break;
 | 
			
		||||
        case St.Side.BOTTOM:
 | 
			
		||||
            resY = sourceY - natHeight - gap;
 | 
			
		||||
            resY = sourceAllocation.y1 - natHeight - gap;
 | 
			
		||||
            break;
 | 
			
		||||
        case St.Side.LEFT:
 | 
			
		||||
            resX = sourceX + sourceWidth + gap;
 | 
			
		||||
            resX = sourceAllocation.x2 + gap;
 | 
			
		||||
            break;
 | 
			
		||||
        case St.Side.RIGHT:
 | 
			
		||||
            resX = sourceX - natWidth - gap;
 | 
			
		||||
            resX = sourceAllocation.x1 - natWidth - gap;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -350,8 +376,8 @@ BoxPointer.prototype = {
 | 
			
		||||
        case St.Side.BOTTOM:
 | 
			
		||||
            resX = sourceCenterX - (halfMargin + (natWidth - margin) * alignment);
 | 
			
		||||
 | 
			
		||||
            resX = Math.max(resX, primary.x + 10);
 | 
			
		||||
            resX = Math.min(resX, primary.x + primary.width - (10 + natWidth));
 | 
			
		||||
            resX = Math.max(resX, monitor.x + 10);
 | 
			
		||||
            resX = Math.min(resX, monitor.x + monitor.width - (10 + natWidth));
 | 
			
		||||
            this.setArrowOrigin(sourceCenterX - resX);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
@@ -359,8 +385,8 @@ BoxPointer.prototype = {
 | 
			
		||||
        case St.Side.RIGHT:
 | 
			
		||||
            resY = sourceCenterY - (halfMargin + (natHeight - margin) * alignment);
 | 
			
		||||
 | 
			
		||||
            resY = Math.max(resY, primary.y + 10);
 | 
			
		||||
            resY = Math.min(resY, primary.y + primary.height - (10 + natHeight));
 | 
			
		||||
            resY = Math.max(resY, monitor.y + 10);
 | 
			
		||||
            resY = Math.min(resY, monitor.y + monitor.height - (10 + natHeight));
 | 
			
		||||
 | 
			
		||||
            this.setArrowOrigin(sourceCenterY - resY);
 | 
			
		||||
            break;
 | 
			
		||||
@@ -373,9 +399,9 @@ BoxPointer.prototype = {
 | 
			
		||||
            parent = parent.get_parent();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Actually set the position
 | 
			
		||||
        this.actor.x = Math.floor(x);
 | 
			
		||||
        this.actor.y = Math.floor(y);
 | 
			
		||||
        this._xPosition = Math.floor(x);
 | 
			
		||||
        this._yPosition = Math.floor(y);
 | 
			
		||||
        this._shiftActor();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // @origin: Coordinate specifying middle of the arrow, along
 | 
			
		||||
@@ -386,5 +412,42 @@ BoxPointer.prototype = {
 | 
			
		||||
            this._arrowOrigin = origin;
 | 
			
		||||
            this._border.queue_repaint();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _shiftActor : function() {
 | 
			
		||||
        // Since the position of the BoxPointer depends on the allocated size
 | 
			
		||||
        // of the BoxPointer and the position of the source actor, trying
 | 
			
		||||
        // to position the BoxPoiner via the x/y properties will result in
 | 
			
		||||
        // allocation loops and warnings. Instead we do the positioning via
 | 
			
		||||
        // the anchor point, which is independent of allocation, and leave
 | 
			
		||||
        // x == y == 0.
 | 
			
		||||
        this.actor.set_anchor_point(-(this._xPosition + this._xOffset),
 | 
			
		||||
                                    -(this._yPosition + this._yOffset));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    set xOffset(offset) {
 | 
			
		||||
        this._xOffset = offset;
 | 
			
		||||
        this._shiftActor();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get xOffset() {
 | 
			
		||||
        return this._xOffset;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    set yOffset(offset) {
 | 
			
		||||
        this._yOffset = offset;
 | 
			
		||||
        this._shiftActor();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get yOffset() {
 | 
			
		||||
        return this._yOffset;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    set opacity(opacity) {
 | 
			
		||||
        this.actor.opacity = opacity;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get opacity() {
 | 
			
		||||
        return this.actor.opacity;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
@@ -7,9 +7,6 @@ const St = imports.gi.St;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Pango = imports.gi.Pango;
 | 
			
		||||
const Gettext_gtk30 = imports.gettext.domain('gtk30');
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
const C_ = Gettext.pgettext;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
 | 
			
		||||
@@ -158,27 +155,24 @@ function _getEventDayAbbreviation(dayNumber) {
 | 
			
		||||
 | 
			
		||||
// Abstraction for an appointment/event in a calendar
 | 
			
		||||
 | 
			
		||||
function CalendarEvent(date, summary, allDay) {
 | 
			
		||||
    this._init(date, summary, allDay);
 | 
			
		||||
}
 | 
			
		||||
const CalendarEvent = new Lang.Class({
 | 
			
		||||
    Name: 'CalendarEvent',
 | 
			
		||||
 | 
			
		||||
CalendarEvent.prototype = {
 | 
			
		||||
    _init: function(date, summary, allDay) {
 | 
			
		||||
    _init: function(date, end, summary, allDay) {
 | 
			
		||||
        this.date = date;
 | 
			
		||||
        this.end = end;
 | 
			
		||||
        this.summary = summary;
 | 
			
		||||
        this.allDay = allDay;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Interface for appointments/events - e.g. the contents of a calendar
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
// First, an implementation with no events
 | 
			
		||||
function EmptyEventSource() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const EmptyEventSource = new Lang.Class({
 | 
			
		||||
    Name: 'EmptyEventSource',
 | 
			
		||||
 | 
			
		||||
EmptyEventSource.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -193,142 +187,142 @@ EmptyEventSource.prototype = {
 | 
			
		||||
    hasEvents: function(day) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(EmptyEventSource.prototype);
 | 
			
		||||
 | 
			
		||||
// Second, wrap native Evolution event source
 | 
			
		||||
function EvolutionEventSource() {
 | 
			
		||||
    this._init();
 | 
			
		||||
const CalendarServerIface = <interface name="org.gnome.Shell.CalendarServer">
 | 
			
		||||
<method name="GetEvents">
 | 
			
		||||
    <arg type="x" direction="in" />
 | 
			
		||||
    <arg type="x" direction="in" />
 | 
			
		||||
    <arg type="b" direction="in" />
 | 
			
		||||
    <arg type="a(sssbxxa{sv})" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<signal name="Changed" />
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const CalendarServerInfo  = Gio.DBusInterfaceInfo.new_for_xml(CalendarServerIface);
 | 
			
		||||
 | 
			
		||||
function CalendarServer() {
 | 
			
		||||
    var self = new Gio.DBusProxy({ g_connection: Gio.DBus.session,
 | 
			
		||||
				   g_interface_name: CalendarServerInfo.name,
 | 
			
		||||
				   g_interface_info: CalendarServerInfo,
 | 
			
		||||
				   g_name: 'org.gnome.Shell.CalendarServer',
 | 
			
		||||
				   g_object_path: '/org/gnome/Shell/CalendarServer',
 | 
			
		||||
                                   g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
 | 
			
		||||
                                             Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
 | 
			
		||||
 | 
			
		||||
    self.init(null);
 | 
			
		||||
    return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
EvolutionEventSource.prototype = {
 | 
			
		||||
function _datesEqual(a, b) {
 | 
			
		||||
    if (a < b)
 | 
			
		||||
        return false;
 | 
			
		||||
    else if (a > b)
 | 
			
		||||
        return false;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _dateIntervalsOverlap(a0, a1, b0, b1)
 | 
			
		||||
{
 | 
			
		||||
    if (a1 <= b0)
 | 
			
		||||
        return false;
 | 
			
		||||
    else if (b1 <= a0)
 | 
			
		||||
        return false;
 | 
			
		||||
    else
 | 
			
		||||
        return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// an implementation that reads data from a session bus service
 | 
			
		||||
const DBusEventSource = new Lang.Class({
 | 
			
		||||
    Name: 'DBusEventSource',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._native = new Shell.EvolutionEventSource();
 | 
			
		||||
        this._native.connect('changed', Lang.bind(this, function() {
 | 
			
		||||
            this.emit('changed');
 | 
			
		||||
        this._resetCache();
 | 
			
		||||
 | 
			
		||||
        this._dbusProxy = new CalendarServer();
 | 
			
		||||
        this._dbusProxy.connectSignal('Changed', Lang.bind(this, this._onChanged));
 | 
			
		||||
 | 
			
		||||
        this._dbusProxy.connect('notify::g-name-owner', Lang.bind(this, function() {
 | 
			
		||||
            if (this._dbusProxy.g_name_owner)
 | 
			
		||||
                this._onNameAppeared();
 | 
			
		||||
            else
 | 
			
		||||
                this._onNameVanished();
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    requestRange: function(begin, end) {
 | 
			
		||||
        this._native.request_range(begin.getTime(), end.getTime());
 | 
			
		||||
    _resetCache: function() {
 | 
			
		||||
        this._events = [];
 | 
			
		||||
        this._lastRequestBegin = null;
 | 
			
		||||
        this._lastRequestEnd = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getEvents: function(begin, end) {
 | 
			
		||||
        let result = [];
 | 
			
		||||
        let nativeEvents = this._native.get_events(begin.getTime(), end.getTime());
 | 
			
		||||
        for (let n = 0; n < nativeEvents.length; n++) {
 | 
			
		||||
            let nativeEvent = nativeEvents[n];
 | 
			
		||||
            result.push(new CalendarEvent(new Date(nativeEvent.msec_begin), nativeEvent.summary, nativeEvent.all_day));
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    _onNameAppeared: function(owner) {
 | 
			
		||||
        this._resetCache();
 | 
			
		||||
        this._loadEvents(true);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hasEvents: function(day) {
 | 
			
		||||
        let dayBegin = _getBeginningOfDay(day);
 | 
			
		||||
        let dayEnd = _getEndOfDay(day);
 | 
			
		||||
 | 
			
		||||
        let events = this.getEvents(dayBegin, dayEnd);
 | 
			
		||||
 | 
			
		||||
        if (events.length == 0)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
Signals.addSignalMethods(EvolutionEventSource.prototype);
 | 
			
		||||
 | 
			
		||||
// Finally, an implementation with fake events
 | 
			
		||||
function FakeEventSource() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FakeEventSource.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
 | 
			
		||||
        this._fakeEvents = [];
 | 
			
		||||
 | 
			
		||||
        // Generate fake events
 | 
			
		||||
        //
 | 
			
		||||
        let midnightToday = _getBeginningOfDay(new Date());
 | 
			
		||||
        let summary = '';
 | 
			
		||||
 | 
			
		||||
        // '10-oclock pow-wow' is an event occuring IN THE PAST every four days at 10am
 | 
			
		||||
        for (let n = 0; n < 10; n++) {
 | 
			
		||||
            let t = new Date(midnightToday.getTime() - n * 4 * 86400 * 1000);
 | 
			
		||||
            t.setHours(10);
 | 
			
		||||
            summary = '10-oclock pow-wow (n=' + n + ')';
 | 
			
		||||
            this._fakeEvents.push(new CalendarEvent(t, summary, false));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // '11-oclock thing' is an event occuring every three days at 11am
 | 
			
		||||
        for (let n = 0; n < 10; n++) {
 | 
			
		||||
            let t = new Date(midnightToday.getTime() + n * 3 * 86400 * 1000);
 | 
			
		||||
            t.setHours(11);
 | 
			
		||||
            summary = '11-oclock thing (n=' + n + ')';
 | 
			
		||||
            this._fakeEvents.push(new CalendarEvent(t, summary, false));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 'Weekly Meeting' is an event occuring every seven days at 1:45pm (two days displaced)
 | 
			
		||||
        for (let n = 0; n < 5; n++) {
 | 
			
		||||
            let t = new Date(midnightToday.getTime() + (n * 7 + 2) * 86400 * 1000);
 | 
			
		||||
            t.setHours(13);
 | 
			
		||||
            t.setMinutes(45);
 | 
			
		||||
            summary = 'Weekly Meeting (n=' + n + ')';
 | 
			
		||||
            this._fakeEvents.push(new CalendarEvent(t, summary, false));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 'Fun All Day' is an all-day event occuring every fortnight (three days displayed)
 | 
			
		||||
        for (let n = 0; n < 10; n++) {
 | 
			
		||||
            let t = new Date(midnightToday.getTime() + (n * 14 + 3) * 86400 * 1000);
 | 
			
		||||
            summary = 'Fun All Day (n=' + n + ')';
 | 
			
		||||
            this._fakeEvents.push(new CalendarEvent(t, summary, true));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 'Get Married' is an event that actually reflects reality (Dec 4, 2010) :-)
 | 
			
		||||
        this._fakeEvents.push(new CalendarEvent(new Date(2010, 11, 4, 16, 0), 'Get Married', false));
 | 
			
		||||
 | 
			
		||||
        // ditto for 'NE Patriots vs NY Jets'
 | 
			
		||||
        this._fakeEvents.push(new CalendarEvent(new Date(2010, 11, 6, 20, 30), 'NE Patriots vs NY Jets', false));
 | 
			
		||||
 | 
			
		||||
        // An event for tomorrow @6:30pm that is added/removed every five
 | 
			
		||||
        // seconds (to check that the ::changed signal works)
 | 
			
		||||
        let transientEventDate = new Date(midnightToday.getTime() + 86400 * 1000);
 | 
			
		||||
        transientEventDate.setHours(18);
 | 
			
		||||
        transientEventDate.setMinutes(30);
 | 
			
		||||
        transientEventDate.setSeconds(0);
 | 
			
		||||
        Mainloop.timeout_add(5000, Lang.bind(this, this._updateTransientEvent));
 | 
			
		||||
        this._includeTransientEvent = false;
 | 
			
		||||
        this._transientEvent = new CalendarEvent(transientEventDate, 'A Transient Event', false);
 | 
			
		||||
        this._transientEventCounter = 1;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateTransientEvent: function() {
 | 
			
		||||
        this._includeTransientEvent = !this._includeTransientEvent;
 | 
			
		||||
        this._transientEventCounter = this._transientEventCounter + 1;
 | 
			
		||||
        this._transientEvent.summary = 'A Transient Event (' + this._transientEventCounter + ')';
 | 
			
		||||
    _onNameVanished: function(oldOwner) {
 | 
			
		||||
        this._resetCache();
 | 
			
		||||
        this.emit('changed');
 | 
			
		||||
        Mainloop.timeout_add(5000, Lang.bind(this, this._updateTransientEvent));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    requestRange: function(begin, end) {
 | 
			
		||||
    _onChanged: function() {
 | 
			
		||||
        this._loadEvents(false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onEventsReceived: function([appointments]) {
 | 
			
		||||
        let newEvents = [];
 | 
			
		||||
        if (appointments != null) {
 | 
			
		||||
            for (let n = 0; n < appointments.length; n++) {
 | 
			
		||||
                let a = appointments[n];
 | 
			
		||||
                let date = new Date(a[4] * 1000);
 | 
			
		||||
                let end = new Date(a[5] * 1000);
 | 
			
		||||
                let summary = a[1];
 | 
			
		||||
                let allDay = a[3];
 | 
			
		||||
                let event = new CalendarEvent(date, end, summary, allDay);
 | 
			
		||||
                newEvents.push(event);
 | 
			
		||||
            }
 | 
			
		||||
            newEvents.sort(function(event1, event2) {
 | 
			
		||||
                return event1.date.getTime() - event2.date.getTime();
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._events = newEvents;
 | 
			
		||||
        this.emit('changed');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _loadEvents: function(forceReload) {
 | 
			
		||||
        if (this._curRequestBegin && this._curRequestEnd){
 | 
			
		||||
            let callFlags = Gio.DBusCallFlags.NO_AUTO_START;
 | 
			
		||||
            if (forceReload)
 | 
			
		||||
                callFlags = Gio.DBusCallFlags.NONE;
 | 
			
		||||
            this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
 | 
			
		||||
                                            this._curRequestEnd.getTime() / 1000,
 | 
			
		||||
                                            forceReload,
 | 
			
		||||
                                            Lang.bind(this, this._onEventsReceived),
 | 
			
		||||
                                            callFlags);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    requestRange: function(begin, end, forceReload) {
 | 
			
		||||
        if (forceReload || !(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) {
 | 
			
		||||
            this._lastRequestBegin = begin;
 | 
			
		||||
            this._lastRequestEnd = end;
 | 
			
		||||
            this._curRequestBegin = begin;
 | 
			
		||||
            this._curRequestEnd = end;
 | 
			
		||||
            this._loadEvents(forceReload);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getEvents: function(begin, end) {
 | 
			
		||||
        let result = [];
 | 
			
		||||
        //log('begin:' + begin);
 | 
			
		||||
        //log('end:  ' + end);
 | 
			
		||||
        for(let n = 0; n < this._fakeEvents.length; n++) {
 | 
			
		||||
            let event = this._fakeEvents[n];
 | 
			
		||||
            if (event.date >= begin && event.date <= end) {
 | 
			
		||||
        for(let n = 0; n < this._events.length; n++) {
 | 
			
		||||
            let event = this._events[n];
 | 
			
		||||
            if (_dateIntervalsOverlap (event.date, event.end, begin, end)) {
 | 
			
		||||
                result.push(event);
 | 
			
		||||
            }
 | 
			
		||||
            //log('when:' + event.date + ' summary:' + event.summary);
 | 
			
		||||
        }
 | 
			
		||||
        if (this._includeTransientEvent && this._transientEvent.date >= begin && this._transientEvent.date <= end)
 | 
			
		||||
            result.push(this._transientEvent);
 | 
			
		||||
        result.sort(function(event1, event2) {
 | 
			
		||||
            return event1.date.getTime() - event2.date.getTime();
 | 
			
		||||
        });
 | 
			
		||||
        return result;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -343,27 +337,26 @@ FakeEventSource.prototype = {
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
Signals.addSignalMethods(FakeEventSource.prototype);
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(DBusEventSource.prototype);
 | 
			
		||||
 | 
			
		||||
// Calendar:
 | 
			
		||||
// @eventSource: is an object implementing the EventSource API, e.g. the
 | 
			
		||||
// requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
 | 
			
		||||
function Calendar(eventSource) {
 | 
			
		||||
    this._init(eventSource);
 | 
			
		||||
}
 | 
			
		||||
const Calendar = new Lang.Class({
 | 
			
		||||
    Name: 'Calendar',
 | 
			
		||||
 | 
			
		||||
Calendar.prototype = {
 | 
			
		||||
    _init: function(eventSource) {
 | 
			
		||||
        this._eventSource = eventSource;
 | 
			
		||||
        if (eventSource) {
 | 
			
		||||
            this._eventSource = eventSource;
 | 
			
		||||
 | 
			
		||||
        this._eventSource.connect('changed', Lang.bind(this, this._update));
 | 
			
		||||
            this._eventSource.connect('changed', Lang.bind(this,
 | 
			
		||||
                                                           function() {
 | 
			
		||||
                                                               this._update(false);
 | 
			
		||||
                                                           }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // FIXME: This is actually the fallback method for GTK+ for the week start;
 | 
			
		||||
        // GTK+ by preference uses nl_langinfo (NL_TIME_FIRST_WEEKDAY). We probably
 | 
			
		||||
        // should add a C function so we can do the full handling.
 | 
			
		||||
        this._weekStart = NaN;
 | 
			
		||||
        this._weekStart = Shell.util_get_week_start();
 | 
			
		||||
        this._weekdate = NaN;
 | 
			
		||||
        this._digitWidth = NaN;
 | 
			
		||||
        this._settings = new Gio.Settings({ schema: 'org.gnome.shell.calendar' });
 | 
			
		||||
@@ -371,16 +364,6 @@ Calendar.prototype = {
 | 
			
		||||
        this._settings.connect('changed::' + SHOW_WEEKDATE_KEY, Lang.bind(this, this._onSettingsChange));
 | 
			
		||||
        this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY);
 | 
			
		||||
 | 
			
		||||
        let weekStartString = Gettext_gtk30.gettext('calendar:week_start:0');
 | 
			
		||||
        if (weekStartString.indexOf('calendar:week_start:') == 0) {
 | 
			
		||||
            this._weekStart = parseInt(weekStartString.substring(20));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isNaN(this._weekStart) || this._weekStart < 0 || this._weekStart > 6) {
 | 
			
		||||
            log('Translation of "calendar:week_start:0" in GTK+ is not correct');
 | 
			
		||||
            this._weekStart = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Find the ordering for month/year in the calendar heading
 | 
			
		||||
        this._headerFormatWithoutYear = '%B';
 | 
			
		||||
        switch (Gettext_gtk30.gettext('calendar:MY')) {
 | 
			
		||||
@@ -407,15 +390,17 @@ Calendar.prototype = {
 | 
			
		||||
                           Lang.bind(this, this._onScroll));
 | 
			
		||||
 | 
			
		||||
        this._buildHeader ();
 | 
			
		||||
        this._update();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Sets the calendar to show a specific date
 | 
			
		||||
    setDate: function(date) {
 | 
			
		||||
    setDate: function(date, forceReload) {
 | 
			
		||||
        if (!_sameDay(date, this._selectedDate)) {
 | 
			
		||||
            this._selectedDate = date;
 | 
			
		||||
            this._update();
 | 
			
		||||
            this._update(forceReload);
 | 
			
		||||
            this.emit('selected-date-changed', new Date(this._selectedDate));
 | 
			
		||||
        } else {
 | 
			
		||||
            if (forceReload)
 | 
			
		||||
                this._update(forceReload);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -510,7 +495,7 @@ Calendar.prototype = {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.setDate(newDate);
 | 
			
		||||
        this.setDate(newDate, false);
 | 
			
		||||
   },
 | 
			
		||||
 | 
			
		||||
   _onNextMonthButtonClicked: function() {
 | 
			
		||||
@@ -532,16 +517,16 @@ Calendar.prototype = {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.setDate(newDate);
 | 
			
		||||
       this.setDate(newDate, false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onSettingsChange: function() {
 | 
			
		||||
        this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY);
 | 
			
		||||
        this._buildHeader();
 | 
			
		||||
        this._update();
 | 
			
		||||
        this._update(false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _update: function() {
 | 
			
		||||
    _update: function(forceReload) {
 | 
			
		||||
        let now = new Date();
 | 
			
		||||
 | 
			
		||||
        if (_sameYear(this._selectedDate, now))
 | 
			
		||||
@@ -567,13 +552,16 @@ Calendar.prototype = {
 | 
			
		||||
        while (true) {
 | 
			
		||||
            let button = new St.Button({ label: iter.getDate().toString() });
 | 
			
		||||
 | 
			
		||||
            if (!this._eventSource)
 | 
			
		||||
                button.reactive = false;
 | 
			
		||||
 | 
			
		||||
            let iterStr = iter.toUTCString();
 | 
			
		||||
            button.connect('clicked', Lang.bind(this, function() {
 | 
			
		||||
                let newlySelectedDate = new Date(iterStr);
 | 
			
		||||
                this.setDate(newlySelectedDate);
 | 
			
		||||
                this.setDate(newlySelectedDate, false);
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            let hasEvents = this._eventSource.hasEvents(iter);
 | 
			
		||||
            let hasEvents = this._eventSource && this._eventSource.hasEvents(iter);
 | 
			
		||||
            let styleClass = 'calendar-day-base calendar-day';
 | 
			
		||||
            if (_isWorkDay(iter))
 | 
			
		||||
                styleClass += ' calendar-work-day'
 | 
			
		||||
@@ -620,17 +608,16 @@ Calendar.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
        // Signal to the event source that we are interested in events
 | 
			
		||||
        // only from this date range
 | 
			
		||||
        this._eventSource.requestRange(beginDate, iter);
 | 
			
		||||
        if (this._eventSource)
 | 
			
		||||
            this._eventSource.requestRange(beginDate, iter, forceReload);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(Calendar.prototype);
 | 
			
		||||
 | 
			
		||||
function EventsList(eventSource) {
 | 
			
		||||
    this._init(eventSource);
 | 
			
		||||
}
 | 
			
		||||
const EventsList = new Lang.Class({
 | 
			
		||||
    Name: 'EventsList',
 | 
			
		||||
 | 
			
		||||
EventsList.prototype = {
 | 
			
		||||
    _init: function(eventSource) {
 | 
			
		||||
        this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'});
 | 
			
		||||
        this._date = new Date();
 | 
			
		||||
@@ -638,17 +625,7 @@ EventsList.prototype = {
 | 
			
		||||
        this._eventSource.connect('changed', Lang.bind(this, this._update));
 | 
			
		||||
        this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
 | 
			
		||||
        this._desktopSettings.connect('changed', Lang.bind(this, this._update));
 | 
			
		||||
        let weekStartString = Gettext_gtk30.gettext('calendar:week_start:0');
 | 
			
		||||
        if (weekStartString.indexOf('calendar:week_start:') == 0) {
 | 
			
		||||
            this._weekStart = parseInt(weekStartString.substring(20));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isNaN(this._weekStart) ||
 | 
			
		||||
                  this._weekStart < 0 ||
 | 
			
		||||
                  this._weekStart > 6) {
 | 
			
		||||
            log('Translation of "calendar:week_start:0" in GTK+ is not correct');
 | 
			
		||||
            this._weekStart = 0;
 | 
			
		||||
        }
 | 
			
		||||
        this._weekStart = Shell.util_get_week_start();
 | 
			
		||||
 | 
			
		||||
        this._update();
 | 
			
		||||
    },
 | 
			
		||||
@@ -667,6 +644,9 @@ EventsList.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _addPeriod: function(header, begin, end, includeDayName, showNothingScheduled) {
 | 
			
		||||
        if (!this._eventSource)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let events = this._eventSource.getEvents(begin, end);
 | 
			
		||||
 | 
			
		||||
        let clockFormat = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);;
 | 
			
		||||
@@ -698,7 +678,7 @@ EventsList.prototype = {
 | 
			
		||||
        if (events.length == 0 && showNothingScheduled) {
 | 
			
		||||
            let now = new Date();
 | 
			
		||||
            /* Translators: Text to show if there are no events */
 | 
			
		||||
            let nothingEvent = new CalendarEvent(now, _("Nothing Scheduled"), true);
 | 
			
		||||
            let nothingEvent = new CalendarEvent(now, now, _("Nothing Scheduled"), true);
 | 
			
		||||
            let timeString = _formatEventTime(nothingEvent, clockFormat);
 | 
			
		||||
            this._addEvent(dayNameBox, timeBox, eventTitleBox, false, "", timeString, nothingEvent.summary);
 | 
			
		||||
        }
 | 
			
		||||
@@ -768,4 +748,4 @@ EventsList.prototype = {
 | 
			
		||||
            this._showOtherDay(this._date);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										364
									
								
								js/ui/chrome.js
									
									
									
									
									
								
							
							
						
						@@ -1,364 +0,0 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
 | 
			
		||||
// This manages the shell "chrome"; the UI that's visible in the
 | 
			
		||||
// normal mode (ie, outside the Overview), that surrounds the main
 | 
			
		||||
// workspace content.
 | 
			
		||||
 | 
			
		||||
const Visibility = {
 | 
			
		||||
    FULL:       1,
 | 
			
		||||
    FULLSCREEN: 2,
 | 
			
		||||
    OVERVIEW:   3
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const defaultParams = {
 | 
			
		||||
    visibleInOverview: false,
 | 
			
		||||
    visibleInFullscreen: false,
 | 
			
		||||
    affectsStruts: true,
 | 
			
		||||
    affectsInputRegion: true
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function Chrome() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Chrome.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        // The group itself has zero size so it doesn't interfere with DND
 | 
			
		||||
        this.actor = new Shell.GenericContainer({ width: 0, height: 0 });
 | 
			
		||||
        Main.uiGroup.add_actor(this.actor);
 | 
			
		||||
        this.actor.connect('allocate', Lang.bind(this, this._allocated));
 | 
			
		||||
 | 
			
		||||
        this._inFullscreen = false;
 | 
			
		||||
        this._inOverview = false;
 | 
			
		||||
        this.visibility = Visibility.FULL;
 | 
			
		||||
 | 
			
		||||
        this._trackedActors = [];
 | 
			
		||||
 | 
			
		||||
        global.screen.connect('restacked',
 | 
			
		||||
                              Lang.bind(this, this._windowsRestacked));
 | 
			
		||||
 | 
			
		||||
        // Need to update struts on new workspaces when they are added
 | 
			
		||||
        global.screen.connect('notify::n-workspaces',
 | 
			
		||||
                              Lang.bind(this, this._queueUpdateRegions));
 | 
			
		||||
 | 
			
		||||
        Main.overview.connect('showing',
 | 
			
		||||
                             Lang.bind(this, this._overviewShowing));
 | 
			
		||||
        Main.overview.connect('hidden',
 | 
			
		||||
                             Lang.bind(this, this._overviewHidden));
 | 
			
		||||
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _allocated: function(actor, box, flags) {
 | 
			
		||||
        let children = this.actor.get_children();
 | 
			
		||||
        for (let i = 0; i < children.length; i++)
 | 
			
		||||
            children[i].allocate_preferred_size(flags);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // addActor:
 | 
			
		||||
    // @actor: an actor to add to the chrome layer
 | 
			
		||||
    // @params: (optional) additional params
 | 
			
		||||
    //
 | 
			
		||||
    // Adds @actor to the chrome layer and extends the input region
 | 
			
		||||
    // and window manager struts to include it. (Window manager struts
 | 
			
		||||
    // will only be affected if @actor is touching a screen edge.)
 | 
			
		||||
    // Changes in @actor's size and position will automatically result
 | 
			
		||||
    // in appropriate changes to the input region and struts. Changes
 | 
			
		||||
    // in its visibility will affect the input region, but NOT the
 | 
			
		||||
    // struts.
 | 
			
		||||
    //
 | 
			
		||||
    // If %visibleInOverview is %true in @params, @actor will remain
 | 
			
		||||
    // visible when the overview is brought up. Otherwise it will
 | 
			
		||||
    // automatically be hidden. Likewise, if %visibleInFullscreen is
 | 
			
		||||
    // %true, the actor will be visible even when a fullscreen window
 | 
			
		||||
    // should be covering it.
 | 
			
		||||
    //
 | 
			
		||||
    // If %affectsStruts or %affectsInputRegion is %false, the actor
 | 
			
		||||
    // will not have the indicated effect.
 | 
			
		||||
    addActor: function(actor, params) {
 | 
			
		||||
        this.actor.add_actor(actor);
 | 
			
		||||
        this._trackActor(actor, params);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // trackActor:
 | 
			
		||||
    // @actor: a descendant of the chrome to begin tracking
 | 
			
		||||
    // @params: parameters describing how to track @actor
 | 
			
		||||
    //
 | 
			
		||||
    // Tells the chrome to track @actor, which must be a descendant
 | 
			
		||||
    // of an actor added via addActor(). This can be used to extend the
 | 
			
		||||
    // struts or input region to cover specific children.
 | 
			
		||||
    //
 | 
			
		||||
    // @params can have any of the same values as in addActor(), though
 | 
			
		||||
    // some possibilities don't make sense (eg, trying to have a
 | 
			
		||||
    // %visibleInOverview child of a non-%visibleInOverview parent).
 | 
			
		||||
    // By default, @actor has the same params as its chrome ancestor.
 | 
			
		||||
    trackActor: function(actor, params) {
 | 
			
		||||
        let ancestor = actor.get_parent();
 | 
			
		||||
        let index = this._findActor(ancestor);
 | 
			
		||||
        while (ancestor && index == -1) {
 | 
			
		||||
            ancestor = ancestor.get_parent();
 | 
			
		||||
            index = this._findActor(ancestor);
 | 
			
		||||
        }
 | 
			
		||||
        if (!ancestor)
 | 
			
		||||
            throw new Error('actor is not a descendent of the chrome layer');
 | 
			
		||||
 | 
			
		||||
        let ancestorData = this._trackedActors[index];
 | 
			
		||||
        if (!params)
 | 
			
		||||
            params = {};
 | 
			
		||||
        // We can't use Params.parse here because we want to drop
 | 
			
		||||
        // the extra values like ancestorData.actor
 | 
			
		||||
        for (let prop in defaultParams) {
 | 
			
		||||
            if (!params[prop])
 | 
			
		||||
                params[prop] = ancestorData[prop];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._trackActor(actor, params);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // untrackActor:
 | 
			
		||||
    // @actor: an actor previously tracked via trackActor()
 | 
			
		||||
    //
 | 
			
		||||
    // Undoes the effect of trackActor()
 | 
			
		||||
    untrackActor: function(actor) {
 | 
			
		||||
        this._untrackActor(actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // removeActor:
 | 
			
		||||
    // @actor: a child of the chrome layer
 | 
			
		||||
    //
 | 
			
		||||
    // Removes @actor from the chrome layer
 | 
			
		||||
    removeActor: function(actor) {
 | 
			
		||||
        this.actor.remove_actor(actor);
 | 
			
		||||
        this._untrackActor(actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _findActor: function(actor) {
 | 
			
		||||
        for (let i = 0; i < this._trackedActors.length; i++) {
 | 
			
		||||
            let actorData = this._trackedActors[i];
 | 
			
		||||
            if (actorData.actor == actor)
 | 
			
		||||
                return i;
 | 
			
		||||
        }
 | 
			
		||||
        return -1;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _trackActor: function(actor, params) {
 | 
			
		||||
        if (this._findActor(actor) != -1)
 | 
			
		||||
            throw new Error('trying to re-track existing chrome actor');
 | 
			
		||||
 | 
			
		||||
        let actorData = Params.parse(params, defaultParams);
 | 
			
		||||
        actorData.actor = actor;
 | 
			
		||||
        actorData.visibleId = actor.connect('notify::visible',
 | 
			
		||||
                                            Lang.bind(this, this._queueUpdateRegions));
 | 
			
		||||
        actorData.allocationId = actor.connect('notify::allocation',
 | 
			
		||||
                                               Lang.bind(this, this._queueUpdateRegions));
 | 
			
		||||
        actorData.parentSetId = actor.connect('parent-set',
 | 
			
		||||
                                              Lang.bind(this, this._actorReparented));
 | 
			
		||||
        // Note that destroying actor will unset its parent, so we don't
 | 
			
		||||
        // need to connect to 'destroy' too.
 | 
			
		||||
 | 
			
		||||
        this._trackedActors.push(actorData);
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _untrackActor: function(actor) {
 | 
			
		||||
        let i = this._findActor(actor);
 | 
			
		||||
 | 
			
		||||
        if (i == -1)
 | 
			
		||||
            return;
 | 
			
		||||
        let actorData = this._trackedActors[i];
 | 
			
		||||
 | 
			
		||||
        this._trackedActors.splice(i, 1);
 | 
			
		||||
        actor.disconnect(actorData.visibleId);
 | 
			
		||||
        actor.disconnect(actorData.allocationId);
 | 
			
		||||
        actor.disconnect(actorData.parentSetId);
 | 
			
		||||
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _actorReparented: function(actor, oldParent) {
 | 
			
		||||
        if (!this.actor.contains(actor))
 | 
			
		||||
            this._untrackActor(actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateVisibility: function() {
 | 
			
		||||
        for (let i = 0; i < this._trackedActors.length; i++) {
 | 
			
		||||
            let actorData = this._trackedActors[i];
 | 
			
		||||
            if (this._inOverview && !actorData.visibleInOverview)
 | 
			
		||||
                this.actor.set_skip_paint(actorData.actor, true);
 | 
			
		||||
            else if (!this._inOverview && this._inFullscreen && !actorData.visibleInFullscreen)
 | 
			
		||||
                this.actor.set_skip_paint(actorData.actor, true);
 | 
			
		||||
            else
 | 
			
		||||
                this.actor.set_skip_paint(actorData.actor, false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let newVisibility;
 | 
			
		||||
        if (this._inOverview)
 | 
			
		||||
            newVisibility = Visibility.OVERVIEW;
 | 
			
		||||
        else if (this._inFullscreen)
 | 
			
		||||
            newVisibility = Visibility.FULLSCREEN;
 | 
			
		||||
        else
 | 
			
		||||
            newVisibility = Visibility.FULL;
 | 
			
		||||
 | 
			
		||||
        if (newVisibility != this.visibility) {
 | 
			
		||||
            this.visibility = newVisibility;
 | 
			
		||||
            this.emit('visibility-changed', this.visibility);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _overviewShowing: function() {
 | 
			
		||||
        this._inOverview = true;
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _overviewHidden: function() {
 | 
			
		||||
        this._inOverview = false;
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _queueUpdateRegions: function() {
 | 
			
		||||
        if (!this._updateRegionIdle)
 | 
			
		||||
            this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this._updateRegions),
 | 
			
		||||
                                                       Meta.PRIORITY_BEFORE_REDRAW);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _windowsRestacked: function() {
 | 
			
		||||
        let windows = Main.getWindowActorsForWorkspace(global.screen.get_active_workspace_index());
 | 
			
		||||
        let primary = global.get_primary_monitor();
 | 
			
		||||
 | 
			
		||||
        // The chrome layer should be visible unless there is a window
 | 
			
		||||
        // with layer FULLSCREEN, or a window with layer
 | 
			
		||||
        // OVERRIDE_REDIRECT that covers the whole screen.
 | 
			
		||||
        // ('override_redirect' is not actually a layer above all
 | 
			
		||||
        // other windows, but this seems to be how mutter treats it
 | 
			
		||||
        // currently...) If we wanted to be extra clever, we could
 | 
			
		||||
        // figure out when an OVERRIDE_REDIRECT window was trying to
 | 
			
		||||
        // partially overlap us, and then adjust the input region and
 | 
			
		||||
        // our clip region accordingly...
 | 
			
		||||
 | 
			
		||||
        // @windows is sorted bottom to top.
 | 
			
		||||
 | 
			
		||||
        let wasInFullscreen = this._inFullscreen;
 | 
			
		||||
        this._inFullscreen = false;
 | 
			
		||||
        for (let i = windows.length - 1; i > -1; i--) {
 | 
			
		||||
            let layer = windows[i].get_meta_window().get_layer();
 | 
			
		||||
 | 
			
		||||
            // There are 3 cases we check here for:
 | 
			
		||||
            // 1.) Monitor sized window
 | 
			
		||||
            // 2.) Window with a position somewhere on the primary screen having the _NET_WM_FULLSCREEN flag set
 | 
			
		||||
            // 3.) Window that is partly off screen (tries to hide its decorations) which might have negative coords
 | 
			
		||||
            // We check for 1.) and 2.) by checking if the upper right corner is on the primary monitor, but avoid the case
 | 
			
		||||
            // where it overlaps with the secondary screen (like window.x + window.width == primary.x + primary.width)
 | 
			
		||||
            // For 3.) we just ignore negative values as they don't really make sense
 | 
			
		||||
 | 
			
		||||
            if (layer == Meta.StackLayer.FULLSCREEN) {
 | 
			
		||||
                if (Math.max(windows[i].x, 0) >= primary.x && Math.max(windows[i].x, 0) < primary.x + primary.width &&
 | 
			
		||||
                    Math.max(windows[i].y, 0) >= primary.y && Math.max(windows[i].y, 0) < primary.y + primary.height) {
 | 
			
		||||
                        this._inFullscreen = true;
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (layer == Meta.StackLayer.OVERRIDE_REDIRECT) {
 | 
			
		||||
                if (windows[i].x <= primary.x &&
 | 
			
		||||
                    windows[i].x + windows[i].width >= primary.x + primary.width &&
 | 
			
		||||
                    windows[i].y <= primary.y &&
 | 
			
		||||
                    windows[i].y + windows[i].height >= primary.y + primary.height) {
 | 
			
		||||
                    this._inFullscreen = true;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            } else
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._inFullscreen != wasInFullscreen) {
 | 
			
		||||
            this._updateVisibility();
 | 
			
		||||
            this._queueUpdateRegions();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateRegions: function() {
 | 
			
		||||
        let rects = [], struts = [], i;
 | 
			
		||||
 | 
			
		||||
        delete this._updateRegionIdle;
 | 
			
		||||
 | 
			
		||||
        for (i = 0; i < this._trackedActors.length; i++) {
 | 
			
		||||
            let actorData = this._trackedActors[i];
 | 
			
		||||
            if (!actorData.affectsInputRegion && !actorData.affectsStruts)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            let [x, y] = actorData.actor.get_transformed_position();
 | 
			
		||||
            let [w, h] = actorData.actor.get_transformed_size();
 | 
			
		||||
            x = Math.round(x);
 | 
			
		||||
            y = Math.round(y);
 | 
			
		||||
            w = Math.round(w);
 | 
			
		||||
            h = Math.round(h);
 | 
			
		||||
            let rect = new Meta.Rectangle({ x: x, y: y, width: w, height: h});
 | 
			
		||||
 | 
			
		||||
            if (actorData.affectsInputRegion &&
 | 
			
		||||
                actorData.actor.get_paint_visibility() &&
 | 
			
		||||
                !this.actor.get_skip_paint(actorData.actor))
 | 
			
		||||
                rects.push(rect);
 | 
			
		||||
 | 
			
		||||
            if (!actorData.affectsStruts)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            // Metacity wants to know what side of the screen the
 | 
			
		||||
            // strut is considered to be attached to. If the actor is
 | 
			
		||||
            // only touching one edge, or is touching the entire
 | 
			
		||||
            // width/height of one edge, then it's obvious which side
 | 
			
		||||
            // to call it. If it's in a corner, we pick a side
 | 
			
		||||
            // arbitrarily. If it doesn't touch any edges, or it spans
 | 
			
		||||
            // the width/height across the middle of the screen, then
 | 
			
		||||
            // we don't create a strut for it at all.
 | 
			
		||||
            let side;
 | 
			
		||||
            if (w >= global.screen_width) {
 | 
			
		||||
                if (y <= 0)
 | 
			
		||||
                    side = Meta.Side.TOP;
 | 
			
		||||
                else if (y + h >= global.screen_height)
 | 
			
		||||
                    side = Meta.Side.BOTTOM;
 | 
			
		||||
                else
 | 
			
		||||
                    continue;
 | 
			
		||||
            } else if (h >= global.screen_height) {
 | 
			
		||||
                if (x <= 0)
 | 
			
		||||
                    side = Meta.Side.LEFT;
 | 
			
		||||
                else if (x + w >= global.screen_width)
 | 
			
		||||
                    side = Meta.Side.RIGHT;
 | 
			
		||||
                else
 | 
			
		||||
                    continue;
 | 
			
		||||
            } else if (x <= 0)
 | 
			
		||||
                side = Meta.Side.LEFT;
 | 
			
		||||
            else if (y <= 0)
 | 
			
		||||
                side = Meta.Side.TOP;
 | 
			
		||||
            else if (x + w >= global.screen_width)
 | 
			
		||||
                side = Meta.Side.RIGHT;
 | 
			
		||||
            else if (y + h >= global.screen_height)
 | 
			
		||||
                side = Meta.Side.BOTTOM;
 | 
			
		||||
            else
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            let strut = new Meta.Strut({ rect: rect, side: side });
 | 
			
		||||
            struts.push(strut);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        global.set_stage_input_region(rects);
 | 
			
		||||
 | 
			
		||||
        let screen = global.screen;
 | 
			
		||||
        for (let w = 0; w < screen.n_workspaces; w++) {
 | 
			
		||||
            let workspace = screen.get_workspace_by_index(w);
 | 
			
		||||
            workspace.set_builtin_struts(struts);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
Signals.addSignalMethods(Chrome.prototype);
 | 
			
		||||
							
								
								
									
										180
									
								
								js/ui/contactDisplay.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,180 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Folks = imports.gi.Folks
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const Util = imports.misc.util;
 | 
			
		||||
const IconGrid = imports.ui.iconGrid;
 | 
			
		||||
const Search = imports.ui.search;
 | 
			
		||||
const SearchDisplay = imports.ui.searchDisplay;
 | 
			
		||||
 | 
			
		||||
const MAX_SEARCH_RESULTS_ROWS = 1;
 | 
			
		||||
const ICON_SIZE = 81;
 | 
			
		||||
 | 
			
		||||
function launchContact(id) {
 | 
			
		||||
    Util.spawn(['gnome-contacts', '-i', id]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* This class represents a shown contact search result in the overview */
 | 
			
		||||
const Contact = new Lang.Class({
 | 
			
		||||
    Name: 'Contact',
 | 
			
		||||
 | 
			
		||||
    _init: function(id) {
 | 
			
		||||
        this._contactSys = Shell.ContactSystem.get_default();
 | 
			
		||||
        this.individual = this._contactSys.get_individual(id);
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.Bin({ style_class: 'contact',
 | 
			
		||||
                                  reactive: true,
 | 
			
		||||
                                  track_hover: true });
 | 
			
		||||
 | 
			
		||||
        let content = new St.BoxLayout( { style_class: 'contact-content',
 | 
			
		||||
                                          vertical: false });
 | 
			
		||||
        this.actor.set_child(content);
 | 
			
		||||
 | 
			
		||||
        let icon = new St.Icon({ icon_type: St.IconType.FULLCOLOR,
 | 
			
		||||
                                 icon_size: ICON_SIZE,
 | 
			
		||||
                                 style_class: 'contact-icon' });
 | 
			
		||||
        if (this.individual.avatar != null)
 | 
			
		||||
            icon.gicon = this.individual.avatar;
 | 
			
		||||
        else
 | 
			
		||||
            icon.icon_name = 'avatar-default';
 | 
			
		||||
 | 
			
		||||
        content.add(icon, { x_fill: true,
 | 
			
		||||
                            y_fill: false,
 | 
			
		||||
                            x_align: St.Align.START,
 | 
			
		||||
                            y_align: St.Align.MIDDLE });
 | 
			
		||||
 | 
			
		||||
        let details = new St.BoxLayout({ style_class: 'contact-details',
 | 
			
		||||
                                         vertical: true });
 | 
			
		||||
        content.add(details, { x_fill: true,
 | 
			
		||||
                               y_fill: false,
 | 
			
		||||
                               x_align: St.Align.START,
 | 
			
		||||
                               y_align: St.Align.MIDDLE });
 | 
			
		||||
 | 
			
		||||
        let email = this._contactSys.get_email_for_display(this.individual);
 | 
			
		||||
        let aliasText = this.individual.alias     ||
 | 
			
		||||
                        this.individual.full_name ||
 | 
			
		||||
                        this.individual.nickname  ||
 | 
			
		||||
                        email                     ||
 | 
			
		||||
                        _("Unknown");
 | 
			
		||||
        let aliasLabel = new St.Label({ text: aliasText,
 | 
			
		||||
                                        style_class: 'contact-details-alias' });
 | 
			
		||||
        details.add(aliasLabel, { x_fill: true,
 | 
			
		||||
                                  y_fill: false,
 | 
			
		||||
                                  x_align: St.Align.START,
 | 
			
		||||
                                  y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        let presence = this._createPresence(this.individual.presence_type);
 | 
			
		||||
        details.add(presence, { x_fill: false,
 | 
			
		||||
                                y_fill: true,
 | 
			
		||||
                                x_align: St.Align.START,
 | 
			
		||||
                                y_align: St.Align.END });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createPresence: function(presence) {
 | 
			
		||||
        let text;
 | 
			
		||||
        let iconName;
 | 
			
		||||
 | 
			
		||||
        switch(presence) {
 | 
			
		||||
          case Folks.PresenceType.AVAILABLE:
 | 
			
		||||
            text = _("Available");
 | 
			
		||||
            iconName = 'user-available';
 | 
			
		||||
            break;
 | 
			
		||||
          case Folks.PresenceType.AWAY:
 | 
			
		||||
          case Folks.PresenceType.EXTENDED_AWAY:
 | 
			
		||||
            text = _("Away");
 | 
			
		||||
            iconName = 'user-away';
 | 
			
		||||
            break;
 | 
			
		||||
          case Folks.PresenceType.BUSY:
 | 
			
		||||
            text = _("Busy");
 | 
			
		||||
            iconName = 'user-busy';
 | 
			
		||||
            break;
 | 
			
		||||
          default:
 | 
			
		||||
            text = _("Offline");
 | 
			
		||||
            iconName = 'user-offline';
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
        let icon = new St.Icon({ icon_name: iconName,
 | 
			
		||||
                                 icon_type: St.IconType.FULLCOLOR,
 | 
			
		||||
                                 icon_size: 16,
 | 
			
		||||
                                 style_class: 'contact-details-status-icon' });
 | 
			
		||||
        let label = new St.Label({ text: text });
 | 
			
		||||
 | 
			
		||||
        let box = new St.BoxLayout({ vertical: false,
 | 
			
		||||
                                     style_class: 'contact-details-status' });
 | 
			
		||||
        box.add(icon, { x_fill: true,
 | 
			
		||||
                        y_fill: false,
 | 
			
		||||
                        x_align: St.Align.START,
 | 
			
		||||
                        y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        box.add(label, { x_fill: true,
 | 
			
		||||
                         y_fill: false,
 | 
			
		||||
                         x_align: St.Align.END,
 | 
			
		||||
                         y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        return box;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createIcon: function(size) {
 | 
			
		||||
        let tc = St.TextureCache.get_default();
 | 
			
		||||
        let icon = this.individual.avatar;
 | 
			
		||||
 | 
			
		||||
        if (icon != null) {
 | 
			
		||||
            return tc.load_gicon(null, icon, size);
 | 
			
		||||
        } else {
 | 
			
		||||
            return tc.load_icon_name(null, 'avatar-default', St.IconType.FULLCOLOR, size);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Searches for and returns contacts */
 | 
			
		||||
const ContactSearchProvider = new Lang.Class({
 | 
			
		||||
    Name: 'ContactSearchProvider',
 | 
			
		||||
    Extends: Search.SearchProvider,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.parent(_("CONTACTS"));
 | 
			
		||||
        this._contactSys = Shell.ContactSystem.get_default();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getResultMeta: function(id) {
 | 
			
		||||
        let contact = new Contact(id);
 | 
			
		||||
        return { 'id': id,
 | 
			
		||||
                 'name': contact.alias,
 | 
			
		||||
                 'createIcon': function(size) {
 | 
			
		||||
                         return contact.createIcon(size);
 | 
			
		||||
                 }
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getInitialResultSet: function(terms) {
 | 
			
		||||
        return this._contactSys.initial_search(terms);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getSubsearchResultSet: function(previousResults, terms) {
 | 
			
		||||
        return this._contactSys.subsearch(previousResults, terms);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createResultActor: function(resultMeta, terms) {
 | 
			
		||||
        let contact = new Contact(resultMeta.id);
 | 
			
		||||
        return contact.actor;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createResultContainerActor: function() {
 | 
			
		||||
        let grid = new IconGrid.IconGrid({ rowLimit: MAX_SEARCH_RESULTS_ROWS,
 | 
			
		||||
                                             xAlign: St.Align.START });
 | 
			
		||||
        grid.actor.style_class = 'contact-grid';
 | 
			
		||||
 | 
			
		||||
        let actor = new SearchDisplay.GridSearchResults(this, grid);
 | 
			
		||||
        return actor;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activateResult: function(id, params) {
 | 
			
		||||
        launchContact(id);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gdk = imports.gi.Gdk;
 | 
			
		||||
@@ -10,27 +10,36 @@ const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const AltTab = imports.ui.altTab;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
const POPUP_APPICON_SIZE = 96;
 | 
			
		||||
const POPUP_FADE_TIME = 0.1; // seconds
 | 
			
		||||
 | 
			
		||||
function CtrlAltTabManager() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const SortGroup = {
 | 
			
		||||
    TOP:    0,
 | 
			
		||||
    MIDDLE: 1,
 | 
			
		||||
    BOTTOM: 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const CtrlAltTabManager = new Lang.Class({
 | 
			
		||||
    Name: 'CtrlAltTabManager',
 | 
			
		||||
 | 
			
		||||
CtrlAltTabManager.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._items = [];
 | 
			
		||||
        this._focusManager = St.FocusManager.get_for_stage(global.stage);
 | 
			
		||||
        Main.wm.setKeybindingHandler('switch_panels', Lang.bind(this,
 | 
			
		||||
            function (shellwm, binding, window, backwards) {
 | 
			
		||||
                this.popup(backwards);
 | 
			
		||||
            }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addGroup: function(root, name, icon) {
 | 
			
		||||
        this._items.push({ root: root, name: name, iconName: icon });
 | 
			
		||||
    addGroup: function(root, name, icon, params) {
 | 
			
		||||
        let item = Params.parse(params, { sortGroup: SortGroup.MIDDLE,
 | 
			
		||||
                                          proxy: root,
 | 
			
		||||
                                          focusCallback: null });
 | 
			
		||||
 | 
			
		||||
        item.root = root;
 | 
			
		||||
        item.name = name;
 | 
			
		||||
        item.iconName = icon;
 | 
			
		||||
 | 
			
		||||
        this._items.push(item);
 | 
			
		||||
        root.connect('destroy', Lang.bind(this, function() { this.removeGroup(root); }));
 | 
			
		||||
        this._focusManager.add_group(root);
 | 
			
		||||
    },
 | 
			
		||||
@@ -45,71 +54,146 @@ CtrlAltTabManager.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    focusGroup: function(root) {
 | 
			
		||||
    focusGroup: function(item) {
 | 
			
		||||
        if (global.stage_input_mode == Shell.StageInputMode.NONREACTIVE ||
 | 
			
		||||
            global.stage_input_mode == Shell.StageInputMode.NORMAL)
 | 
			
		||||
            global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
 | 
			
		||||
        root.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
 | 
			
		||||
 | 
			
		||||
        if (item.window)
 | 
			
		||||
            Main.activateWindow(item.window);
 | 
			
		||||
        else if (item.focusCallback)
 | 
			
		||||
            item.focusCallback();
 | 
			
		||||
        else
 | 
			
		||||
            item.root.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    popup: function(backwards) {
 | 
			
		||||
    // Sort the items into a consistent order; panel first, tray last,
 | 
			
		||||
    // and everything else in between, sorted by X coordinate, so that
 | 
			
		||||
    // they will have the same left-to-right ordering in the
 | 
			
		||||
    // Ctrl-Alt-Tab dialog as they do onscreen.
 | 
			
		||||
    _sortItems: function(a, b) {
 | 
			
		||||
        if (a.sortGroup != b.sortGroup)
 | 
			
		||||
            return a.sortGroup - b.sortGroup;
 | 
			
		||||
 | 
			
		||||
        let y;
 | 
			
		||||
        if (a.x == undefined) {
 | 
			
		||||
            if (a.window)
 | 
			
		||||
                a.x = a.window.get_compositor_private().x;
 | 
			
		||||
            else
 | 
			
		||||
                [a.x, y] = a.proxy.get_transformed_position();
 | 
			
		||||
        }
 | 
			
		||||
        if (b.x == undefined) {
 | 
			
		||||
            if (b.window)
 | 
			
		||||
                b.x = b.window.get_compositor_private().x;
 | 
			
		||||
            else
 | 
			
		||||
                [b.x, y] = b.proxy.get_transformed_position();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return a.x - b.x;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    popup: function(backwards, mask) {
 | 
			
		||||
        // Start with the set of focus groups that are currently mapped
 | 
			
		||||
        let items = this._items.filter(function (item) { return item.root.mapped; });
 | 
			
		||||
        let items = this._items.filter(function (item) { return item.proxy.mapped; });
 | 
			
		||||
 | 
			
		||||
        // And add the windows metacity would show in its Ctrl-Alt-Tab list
 | 
			
		||||
        let screen = global.screen;
 | 
			
		||||
        let display = screen.get_display();
 | 
			
		||||
        let windows = display.get_tab_list(Meta.TabList.DOCKS, screen, screen.get_active_workspace ());
 | 
			
		||||
        let windowTracker = Shell.WindowTracker.get_default();
 | 
			
		||||
        let textureCache = St.TextureCache.get_default();
 | 
			
		||||
        for (let i = 0; i < windows.length; i++) {
 | 
			
		||||
            let icon;
 | 
			
		||||
            let app = windowTracker.get_window_app(windows[i]);
 | 
			
		||||
            if (app)
 | 
			
		||||
                icon = app.create_icon_texture(POPUP_APPICON_SIZE);
 | 
			
		||||
            else
 | 
			
		||||
                icon = textureCache.bind_pixbuf_property(windows[i], 'icon');
 | 
			
		||||
            items.push({ window: windows[i],
 | 
			
		||||
                         name: windows[i].title,
 | 
			
		||||
                         iconActor: icon });
 | 
			
		||||
        if (!Main.overview.visible) {
 | 
			
		||||
            let screen = global.screen;
 | 
			
		||||
            let display = screen.get_display();
 | 
			
		||||
            let windows = display.get_tab_list(Meta.TabList.DOCKS, screen, screen.get_active_workspace ());
 | 
			
		||||
            let windowTracker = Shell.WindowTracker.get_default();
 | 
			
		||||
            let textureCache = St.TextureCache.get_default();
 | 
			
		||||
            for (let i = 0; i < windows.length; i++) {
 | 
			
		||||
                let icon;
 | 
			
		||||
                let app = windowTracker.get_window_app(windows[i]);
 | 
			
		||||
                if (app)
 | 
			
		||||
                    icon = app.create_icon_texture(POPUP_APPICON_SIZE);
 | 
			
		||||
                else
 | 
			
		||||
                    icon = textureCache.bind_pixbuf_property(windows[i], 'icon');
 | 
			
		||||
                items.push({ window: windows[i],
 | 
			
		||||
                             name: windows[i].title,
 | 
			
		||||
                             iconActor: icon,
 | 
			
		||||
                             sortGroup: SortGroup.MIDDLE });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!items.length)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        new CtrlAltTabPopup().show(items, backwards);
 | 
			
		||||
        items.sort(Lang.bind(this, this._sortItems));
 | 
			
		||||
 | 
			
		||||
        if (!this._popup) {
 | 
			
		||||
            this._popup = new CtrlAltTabPopup();
 | 
			
		||||
            this._popup.show(items, backwards, mask);
 | 
			
		||||
 | 
			
		||||
            this._popup.actor.connect('destroy',
 | 
			
		||||
                                      Lang.bind(this, function() {
 | 
			
		||||
                                          this._popup = null;
 | 
			
		||||
                                      }));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function mod(a, b) {
 | 
			
		||||
    return (a + b) % b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function CtrlAltTabPopup() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const CtrlAltTabPopup = new Lang.Class({
 | 
			
		||||
    Name: 'CtrlAltTabPopup',
 | 
			
		||||
 | 
			
		||||
CtrlAltTabPopup.prototype = {
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        let primary = global.get_primary_monitor();
 | 
			
		||||
        this.actor = new St.BoxLayout({ name: 'ctrlAltTabPopup',
 | 
			
		||||
                                        reactive: true,
 | 
			
		||||
                                        x: primary.x + primary.width / 2,
 | 
			
		||||
                                        y: primary.y + primary.height / 2,
 | 
			
		||||
                                        anchor_gravity: Clutter.Gravity.CENTER });
 | 
			
		||||
        this.actor = new Shell.GenericContainer({ name: 'ctrlAltTabPopup',
 | 
			
		||||
                                                  reactive: true });
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
 | 
			
		||||
        this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
 | 
			
		||||
        this.actor.connect('allocate', Lang.bind(this, this._allocate));
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 | 
			
		||||
 | 
			
		||||
        this._haveModal = false;
 | 
			
		||||
        this._modifierMask = 0;
 | 
			
		||||
        this._selection = 0;
 | 
			
		||||
 | 
			
		||||
        Main.uiGroup.add_actor(this.actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show : function(items, startBackwards) {
 | 
			
		||||
    _getPreferredWidth: function (actor, forHeight, alloc) {
 | 
			
		||||
        let primary = Main.layoutManager.primaryMonitor;
 | 
			
		||||
 | 
			
		||||
        alloc.min_size = primary.width;
 | 
			
		||||
        alloc.natural_size = primary.width;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getPreferredHeight: function (actor, forWidth, alloc) {
 | 
			
		||||
        let primary = Main.layoutManager.primaryMonitor;
 | 
			
		||||
 | 
			
		||||
        alloc.min_size = primary.height;
 | 
			
		||||
        alloc.natural_size = primary.height;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _allocate: function (actor, box, flags) {
 | 
			
		||||
        let childBox = new Clutter.ActorBox();
 | 
			
		||||
        let primary = Main.layoutManager.primaryMonitor;
 | 
			
		||||
 | 
			
		||||
        let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
 | 
			
		||||
        let vPadding = this.actor.get_theme_node().get_vertical_padding();
 | 
			
		||||
        let hPadding = this.actor.get_theme_node().get_horizontal_padding();
 | 
			
		||||
 | 
			
		||||
        let [childMinHeight, childNaturalHeight] = this._switcher.actor.get_preferred_height(primary.width - hPadding);
 | 
			
		||||
        let [childMinWidth, childNaturalWidth] = this._switcher.actor.get_preferred_width(childNaturalHeight);
 | 
			
		||||
        childBox.x1 = Math.max(primary.x + leftPadding, primary.x + Math.floor((primary.width - childNaturalWidth) / 2));
 | 
			
		||||
        childBox.x2 = Math.min(primary.x + primary.width - hPadding, childBox.x1 + childNaturalWidth);
 | 
			
		||||
        childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
 | 
			
		||||
        childBox.y2 = childBox.y1 + childNaturalHeight;
 | 
			
		||||
        this._switcher.actor.allocate(childBox, flags);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show : function(items, startBackwards, mask) {
 | 
			
		||||
        if (!Main.pushModal(this.actor))
 | 
			
		||||
            return false;
 | 
			
		||||
        this._haveModal = true;
 | 
			
		||||
        this._modifierMask = AltTab.primaryModifier(mask);
 | 
			
		||||
 | 
			
		||||
        this._keyPressEventId = this.actor.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
 | 
			
		||||
        this._keyReleaseEventId = this.actor.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
 | 
			
		||||
@@ -123,7 +207,7 @@ CtrlAltTabPopup.prototype = {
 | 
			
		||||
        this._select(this._selection);
 | 
			
		||||
 | 
			
		||||
        let [x, y, mods] = global.get_pointer();
 | 
			
		||||
        if (!(mods & Gdk.ModifierType.MOD1_MASK)) {
 | 
			
		||||
        if (!(mods & this._modifierMask)) {
 | 
			
		||||
            this._finish();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
@@ -169,7 +253,7 @@ CtrlAltTabPopup.prototype = {
 | 
			
		||||
 | 
			
		||||
    _keyReleaseEvent : function(actor, event) {
 | 
			
		||||
        let [x, y, mods] = global.get_pointer();
 | 
			
		||||
        let state = mods & Clutter.ModifierType.MOD1_MASK;
 | 
			
		||||
        let state = mods & this._modifierMask;
 | 
			
		||||
 | 
			
		||||
        if (state == 0)
 | 
			
		||||
            this._finish();
 | 
			
		||||
@@ -180,11 +264,7 @@ CtrlAltTabPopup.prototype = {
 | 
			
		||||
    _finish : function() {
 | 
			
		||||
        this.destroy();
 | 
			
		||||
 | 
			
		||||
        let item = this._items[this._selection];
 | 
			
		||||
        if (item.root)
 | 
			
		||||
            Main.ctrlAltTabManager.focusGroup(item.root);
 | 
			
		||||
        else
 | 
			
		||||
            Main.activateWindow(item.window);
 | 
			
		||||
        Main.ctrlAltTabManager.focusGroup(this._items[this._selection]);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _popModal: function() {
 | 
			
		||||
@@ -208,6 +288,7 @@ CtrlAltTabPopup.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDestroy : function() {
 | 
			
		||||
        this._popModal();
 | 
			
		||||
        if (this._keyPressEventId)
 | 
			
		||||
            this.actor.disconnect(this._keyPressEventId);
 | 
			
		||||
        if (this._keyReleaseEventId)
 | 
			
		||||
@@ -218,17 +299,14 @@ CtrlAltTabPopup.prototype = {
 | 
			
		||||
        this._selection = num;
 | 
			
		||||
        this._switcher.highlight(num);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function CtrlAltTabSwitcher(items) {
 | 
			
		||||
    this._init(items);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CtrlAltTabSwitcher.prototype = {
 | 
			
		||||
    __proto__ : AltTab.SwitcherList.prototype,
 | 
			
		||||
const CtrlAltTabSwitcher = new Lang.Class({
 | 
			
		||||
    Name: 'CtrlAltTabSwitcher',
 | 
			
		||||
    Extends: AltTab.SwitcherList,
 | 
			
		||||
 | 
			
		||||
    _init : function(items) {
 | 
			
		||||
        AltTab.SwitcherList.prototype._init.call(this, true);
 | 
			
		||||
        this.parent(true);
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < items.length; i++)
 | 
			
		||||
            this._addIcon(items[i]);
 | 
			
		||||
@@ -249,6 +327,6 @@ CtrlAltTabSwitcher.prototype = {
 | 
			
		||||
        let text = new St.Label({ text: item.name });
 | 
			
		||||
        box.add(text, { x_fill: false });
 | 
			
		||||
 | 
			
		||||
        this.addItem(box);
 | 
			
		||||
        this.addItem(box, text);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										211
									
								
								js/ui/dash.js
									
									
									
									
									
								
							
							
						
						@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
@@ -6,8 +6,6 @@ const Lang = imports.lang;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
 | 
			
		||||
const AppDisplay = imports.ui.appDisplay;
 | 
			
		||||
const AppFavorites = imports.ui.appFavorites;
 | 
			
		||||
@@ -21,11 +19,9 @@ const DASH_ANIMATION_TIME = 0.2;
 | 
			
		||||
 | 
			
		||||
// A container like StBin, but taking the child's scale into account
 | 
			
		||||
// when requesting a size
 | 
			
		||||
function DashItemContainer() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const DashItemContainer = new Lang.Class({
 | 
			
		||||
    Name: 'DashItemContainer',
 | 
			
		||||
 | 
			
		||||
DashItemContainer.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.actor = new Shell.GenericContainer({ style_class: 'dash-item-container' });
 | 
			
		||||
        this.actor.connect('get-preferred-width',
 | 
			
		||||
@@ -39,6 +35,7 @@ DashItemContainer.prototype = {
 | 
			
		||||
        this.child = null;
 | 
			
		||||
        this._childScale = 1;
 | 
			
		||||
        this._childOpacity = 255;
 | 
			
		||||
        this.animatingOut = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _allocate: function(actor, box, flags) {
 | 
			
		||||
@@ -117,6 +114,7 @@ DashItemContainer.prototype = {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.animatingOut = true;
 | 
			
		||||
        this.childScale = 1.0;
 | 
			
		||||
        Tweener.addTween(this,
 | 
			
		||||
                         { childScale: 0.0,
 | 
			
		||||
@@ -157,17 +155,14 @@ DashItemContainer.prototype = {
 | 
			
		||||
    get childOpacity() {
 | 
			
		||||
        return this._childOpacity;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function RemoveFavoriteIcon() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RemoveFavoriteIcon.prototype = {
 | 
			
		||||
    __proto__: DashItemContainer.prototype,
 | 
			
		||||
const RemoveFavoriteIcon = new Lang.Class({
 | 
			
		||||
    Name: 'RemoveFavoriteIcon',
 | 
			
		||||
    Extends: DashItemContainer,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        DashItemContainer.prototype._init.call(this);
 | 
			
		||||
        this.parent();
 | 
			
		||||
 | 
			
		||||
        this._iconBin = new St.Bin({ style_class: 'remove-favorite' });
 | 
			
		||||
        this._iconActor = null;
 | 
			
		||||
@@ -179,12 +174,6 @@ RemoveFavoriteIcon.prototype = {
 | 
			
		||||
        this._iconBin._delegate = this;
 | 
			
		||||
 | 
			
		||||
        this.setChild(this._iconBin);
 | 
			
		||||
        this.hiding = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    animateOutAndDestroy: function() {
 | 
			
		||||
        DashItemContainer.prototype.animateOutAndDestroy.call(this);
 | 
			
		||||
        this.hiding = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createIcon: function(size) {
 | 
			
		||||
@@ -209,7 +198,7 @@ RemoveFavoriteIcon.prototype = {
 | 
			
		||||
        let app = null;
 | 
			
		||||
        if (source instanceof AppDisplay.AppWellIcon) {
 | 
			
		||||
            let appSystem = Shell.AppSystem.get_default();
 | 
			
		||||
            app = appSystem.get_app(source.getId());
 | 
			
		||||
            app = appSystem.lookup_app(source.getId());
 | 
			
		||||
        } else if (source.metaWindow) {
 | 
			
		||||
            let tracker = Shell.WindowTracker.get_default();
 | 
			
		||||
            app = tracker.get_window_app(source.metaWindow);
 | 
			
		||||
@@ -225,28 +214,21 @@ RemoveFavoriteIcon.prototype = {
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function DragPlaceholderItem() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DragPlaceholderItem.prototype = {
 | 
			
		||||
    __proto__: DashItemContainer.prototype,
 | 
			
		||||
const DragPlaceholderItem = new Lang.Class({
 | 
			
		||||
    Name: 'DragPlaceholderItem',
 | 
			
		||||
    Extends: DashItemContainer,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        DashItemContainer.prototype._init.call(this);
 | 
			
		||||
        this.setChild(new St.Bin({ style_class: 'dash-placeholder' }));
 | 
			
		||||
        this.parent();
 | 
			
		||||
        this.setChild(new St.Bin({ style_class: 'placeholder' }));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const Dash = new Lang.Class({
 | 
			
		||||
    Name: 'Dash',
 | 
			
		||||
 | 
			
		||||
function Dash() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Dash.prototype = {
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        this._maxHeight = -1;
 | 
			
		||||
        this.iconSize = 64;
 | 
			
		||||
@@ -262,11 +244,6 @@ Dash.prototype = {
 | 
			
		||||
                                       clip_to_allocation: true });
 | 
			
		||||
        this._box._delegate = this;
 | 
			
		||||
 | 
			
		||||
        // This will eventually be automatic, see
 | 
			
		||||
        // https://bugzilla.gnome.org/show_bug.cgi?id=584662
 | 
			
		||||
        if (St.Widget.get_default_direction () == St.TextDirection.RTL)
 | 
			
		||||
            this._box.add_style_pseudo_class('rtl');
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.Bin({ y_align: St.Align.START, child: this._box });
 | 
			
		||||
        this.actor.connect('notify::height', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
@@ -282,45 +259,59 @@ Dash.prototype = {
 | 
			
		||||
 | 
			
		||||
        this._appSystem.connect('installed-changed', Lang.bind(this, this._queueRedisplay));
 | 
			
		||||
        AppFavorites.getAppFavorites().connect('changed', Lang.bind(this, this._queueRedisplay));
 | 
			
		||||
        this._tracker.connect('app-state-changed', Lang.bind(this, this._queueRedisplay));
 | 
			
		||||
        this._appSystem.connect('app-state-changed', Lang.bind(this, this._queueRedisplay));
 | 
			
		||||
 | 
			
		||||
        Main.overview.connect('item-drag-begin',
 | 
			
		||||
                              Lang.bind(this, this._onDragBegin));
 | 
			
		||||
        Main.overview.connect('item-drag-end',
 | 
			
		||||
                              Lang.bind(this, this._onDragEnd));
 | 
			
		||||
        Main.overview.connect('item-drag-cancelled',
 | 
			
		||||
                              Lang.bind(this, this._onDragCancelled));
 | 
			
		||||
        Main.overview.connect('window-drag-begin',
 | 
			
		||||
                              Lang.bind(this, this._onDragBegin));
 | 
			
		||||
        Main.overview.connect('window-drag-cancelled',
 | 
			
		||||
                              Lang.bind(this, this._onDragCancelled));
 | 
			
		||||
        Main.overview.connect('window-drag-end',
 | 
			
		||||
                              Lang.bind(this, this._onDragEnd));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDragBegin: function() {
 | 
			
		||||
        this._dragCancelled = false;
 | 
			
		||||
        this._dragMonitor = {
 | 
			
		||||
            dragMotion: Lang.bind(this, this._onDragMotion)
 | 
			
		||||
        };
 | 
			
		||||
        DND.addDragMonitor(this._dragMonitor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDragCancelled: function() {
 | 
			
		||||
        this._dragCancelled = true;
 | 
			
		||||
        this._endDrag();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDragEnd: function() {
 | 
			
		||||
        if (this._dragCancelled)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._endDrag();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _endDrag: function() {
 | 
			
		||||
        this._clearDragPlaceholder();
 | 
			
		||||
        if (this._favRemoveTarget) {
 | 
			
		||||
            this._favRemoveTarget.actor.hide();
 | 
			
		||||
            this._adjustIconSize();
 | 
			
		||||
            this._favRemoveTarget.actor.show();
 | 
			
		||||
 | 
			
		||||
            this._favRemoveTarget.animateOutAndDestroy();
 | 
			
		||||
            this._favRemoveTarget.actor.connect('destroy', Lang.bind(this,
 | 
			
		||||
                function() {
 | 
			
		||||
                    this._favRemoveTarget = null;
 | 
			
		||||
                }));
 | 
			
		||||
            this._adjustIconSize();
 | 
			
		||||
        }
 | 
			
		||||
        DND.removeMonitor(this._dragMonitor);
 | 
			
		||||
        DND.removeDragMonitor(this._dragMonitor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDragMotion: function(dragEvent) {
 | 
			
		||||
        let app = null;
 | 
			
		||||
        if (dragEvent.source instanceof AppDisplay.AppWellIcon)
 | 
			
		||||
            app = this._appSystem.get_app(dragEvent.source.getId());
 | 
			
		||||
            app = this._appSystem.lookup_app(dragEvent.source.getId());
 | 
			
		||||
        else if (dragEvent.source.metaWindow)
 | 
			
		||||
            app = this._tracker.get_window_app(dragEvent.source.metaWindow);
 | 
			
		||||
        else
 | 
			
		||||
@@ -332,7 +323,10 @@ Dash.prototype = {
 | 
			
		||||
 | 
			
		||||
        let srcIsFavorite = (id in favorites);
 | 
			
		||||
 | 
			
		||||
        if (srcIsFavorite && this._favRemoveTarget == null) {
 | 
			
		||||
        if (srcIsFavorite &&
 | 
			
		||||
            dragEvent.source.actor &&
 | 
			
		||||
            this.actor.contains (dragEvent.source.actor) &&
 | 
			
		||||
            this._favRemoveTarget == null) {
 | 
			
		||||
                this._favRemoveTarget = new RemoveFavoriteIcon();
 | 
			
		||||
                this._favRemoveTarget.icon.setIconSize(this.iconSize);
 | 
			
		||||
                this._box.add(this._favRemoveTarget.actor);
 | 
			
		||||
@@ -377,6 +371,8 @@ Dash.prototype = {
 | 
			
		||||
                                   Lang.bind(this, function() {
 | 
			
		||||
                                       display.actor.opacity = 255;
 | 
			
		||||
                                   }));
 | 
			
		||||
        display.actor.set_tooltip_text(app.get_name());
 | 
			
		||||
 | 
			
		||||
        let item = new DashItemContainer();
 | 
			
		||||
        item.setChild(display.actor);
 | 
			
		||||
 | 
			
		||||
@@ -386,8 +382,18 @@ Dash.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _adjustIconSize: function() {
 | 
			
		||||
        let children = this._box.get_children();
 | 
			
		||||
        if (children.length == 0) {
 | 
			
		||||
        // For the icon size, we only consider children which are "proper"
 | 
			
		||||
        // icons (i.e. ignoring drag placeholders) and which are not
 | 
			
		||||
        // animating out (which means they will be destroyed at the end of
 | 
			
		||||
        // the animation)
 | 
			
		||||
        let iconChildren = this._box.get_children().filter(function(actor) {
 | 
			
		||||
            return actor._delegate.child &&
 | 
			
		||||
                   actor._delegate.child._delegate &&
 | 
			
		||||
                   actor._delegate.child._delegate.icon &&
 | 
			
		||||
                   !actor._delegate.animatingOut;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (iconChildren.length == 0) {
 | 
			
		||||
            this._box.add_style_pseudo_class('empty');
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -397,23 +403,45 @@ Dash.prototype = {
 | 
			
		||||
        if (this._maxHeight == -1)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let iconChildren = children.filter(function(actor) {
 | 
			
		||||
            return actor.visible &&
 | 
			
		||||
                   actor._delegate.child &&
 | 
			
		||||
                   actor._delegate.child._delegate &&
 | 
			
		||||
                   actor._delegate.child._delegate.icon;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Compute the amount of extra space (or missing space) we have
 | 
			
		||||
        // per icon with the current icon size
 | 
			
		||||
        let [minHeight, natHeight] = this.actor.get_preferred_height(-1);
 | 
			
		||||
        let diff = (this._maxHeight - natHeight) / iconChildren.length;
 | 
			
		||||
        let themeNode = this.actor.get_theme_node();
 | 
			
		||||
        let maxAllocation = new Clutter.ActorBox({ x1: 0, y1: 0,
 | 
			
		||||
                                                   x2: 42 /* whatever */,
 | 
			
		||||
                                                   y2: this._maxHeight });
 | 
			
		||||
        let maxContent = themeNode.get_content_box(maxAllocation);
 | 
			
		||||
        let availHeight = maxContent.y2 - maxContent.y1;
 | 
			
		||||
        let spacing = themeNode.get_length('spacing');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        let firstIcon = iconChildren[0]._delegate.child._delegate.icon;
 | 
			
		||||
 | 
			
		||||
        let minHeight, natHeight;
 | 
			
		||||
 | 
			
		||||
        // Enforce the current icon size during the size request if
 | 
			
		||||
        // the icon is animating
 | 
			
		||||
        if (firstIcon._animating) {
 | 
			
		||||
            let [currentWidth, currentHeight] = firstIcon.icon.get_size();
 | 
			
		||||
 | 
			
		||||
            firstIcon.icon.set_size(this.iconSize, this.iconSize);
 | 
			
		||||
            [minHeight, natHeight] = iconChildren[0].get_preferred_height(-1);
 | 
			
		||||
 | 
			
		||||
            firstIcon.icon.set_size(currentWidth, currentHeight);
 | 
			
		||||
        } else {
 | 
			
		||||
            [minHeight, natHeight] = iconChildren[0].get_preferred_height(-1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Subtract icon padding and box spacing from the available height
 | 
			
		||||
        availHeight -= iconChildren.length * (natHeight - this.iconSize) +
 | 
			
		||||
                       (iconChildren.length - 1) * spacing;
 | 
			
		||||
 | 
			
		||||
        let availSize = availHeight / iconChildren.length;
 | 
			
		||||
 | 
			
		||||
        let iconSizes = [ 16, 22, 24, 32, 48, 64 ];
 | 
			
		||||
 | 
			
		||||
        let newIconSize = 16;
 | 
			
		||||
        for (let i = 0; i < iconSizes.length; i++) {
 | 
			
		||||
            if (iconSizes[i] < this.iconSize + diff)
 | 
			
		||||
            if (iconSizes[i] < availSize)
 | 
			
		||||
                newIconSize = iconSizes[i];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -422,6 +450,7 @@ Dash.prototype = {
 | 
			
		||||
 | 
			
		||||
        let oldIconSize = this.iconSize;
 | 
			
		||||
        this.iconSize = newIconSize;
 | 
			
		||||
        this.emit('icon-size-changed');
 | 
			
		||||
 | 
			
		||||
        let scale = oldIconSize / newIconSize;
 | 
			
		||||
        for (let i = 0; i < iconChildren.length; i++) {
 | 
			
		||||
@@ -443,11 +472,15 @@ Dash.prototype = {
 | 
			
		||||
            icon.icon.set_size(icon.icon.width * scale,
 | 
			
		||||
                               icon.icon.height * scale);
 | 
			
		||||
 | 
			
		||||
            icon._animating = true;
 | 
			
		||||
            Tweener.addTween(icon.icon,
 | 
			
		||||
                             { width: targetWidth,
 | 
			
		||||
                               height: targetHeight,
 | 
			
		||||
                               time: DASH_ANIMATION_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad'
 | 
			
		||||
                               transition: 'easeOutQuad',
 | 
			
		||||
                               onComplete: function() {
 | 
			
		||||
                                   icon._animating = false;
 | 
			
		||||
                               }
 | 
			
		||||
                             });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
@@ -455,10 +488,7 @@ Dash.prototype = {
 | 
			
		||||
    _redisplay: function () {
 | 
			
		||||
        let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
 | 
			
		||||
 | 
			
		||||
        /* hardcode here pending some design about how exactly desktop contexts behave */
 | 
			
		||||
        let contextId = '';
 | 
			
		||||
 | 
			
		||||
        let running = this._tracker.get_running_apps(contextId);
 | 
			
		||||
        let running = this._appSystem.get_running();
 | 
			
		||||
 | 
			
		||||
        let children = this._box.get_children().filter(function(actor) {
 | 
			
		||||
                return actor._delegate.child &&
 | 
			
		||||
@@ -553,29 +583,7 @@ Dash.prototype = {
 | 
			
		||||
            this._box.insert_actor(addedItems[i].item.actor,
 | 
			
		||||
                                   addedItems[i].pos);
 | 
			
		||||
 | 
			
		||||
        // Hide removed actors to not take them into account
 | 
			
		||||
        // when adjusting the icon size ...
 | 
			
		||||
        for (let i = 0; i < removedActors.length; i++)
 | 
			
		||||
            removedActors[i].hide();
 | 
			
		||||
 | 
			
		||||
        // ... and do the same for the remove target if necessary
 | 
			
		||||
        if (this._favRemoveTarget && this._favRemoveTarget.hiding)
 | 
			
		||||
            this._favRemoveTarget.actor.hide();
 | 
			
		||||
 | 
			
		||||
        this._adjustIconSize();
 | 
			
		||||
 | 
			
		||||
        if (this._favRemoveTarget && this._favRemoveTarget.hiding)
 | 
			
		||||
            this._favRemoveTarget.actor.show();
 | 
			
		||||
 | 
			
		||||
        // Skip animations on first run when adding the initial set
 | 
			
		||||
        // of items, to avoid all items zooming in at once
 | 
			
		||||
        if (!this._shownInitially) {
 | 
			
		||||
            this._shownInitially = true;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < removedActors.length; i++) {
 | 
			
		||||
            removedActors[i].show();
 | 
			
		||||
            let item = removedActors[i]._delegate;
 | 
			
		||||
 | 
			
		||||
            // Don't animate item removal when the overview is hidden
 | 
			
		||||
@@ -585,6 +593,15 @@ Dash.prototype = {
 | 
			
		||||
                item.actor.destroy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._adjustIconSize();
 | 
			
		||||
 | 
			
		||||
        // Skip animations on first run when adding the initial set
 | 
			
		||||
        // of items, to avoid all items zooming in at once
 | 
			
		||||
        if (!this._shownInitially) {
 | 
			
		||||
            this._shownInitially = true;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Don't animate item addition when the overview is hidden
 | 
			
		||||
        if (!Main.overview.visible)
 | 
			
		||||
            return;
 | 
			
		||||
@@ -604,12 +621,12 @@ Dash.prototype = {
 | 
			
		||||
    handleDragOver : function(source, actor, x, y, time) {
 | 
			
		||||
        let app = null;
 | 
			
		||||
        if (source instanceof AppDisplay.AppWellIcon)
 | 
			
		||||
            app = this._appSystem.get_app(source.getId());
 | 
			
		||||
            app = this._appSystem.lookup_app(source.getId());
 | 
			
		||||
        else if (source.metaWindow)
 | 
			
		||||
            app = this._tracker.get_window_app(source.metaWindow);
 | 
			
		||||
 | 
			
		||||
        // Don't allow favoriting of transient apps
 | 
			
		||||
        if (app == null || app.is_transient())
 | 
			
		||||
        if (app == null || app.is_window_backed())
 | 
			
		||||
            return DND.DragMotionResult.NO_DROP;
 | 
			
		||||
 | 
			
		||||
        let favorites = AppFavorites.getAppFavorites().getFavorites();
 | 
			
		||||
@@ -671,6 +688,8 @@ Dash.prototype = {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this._dragPlaceholder = new DragPlaceholderItem();
 | 
			
		||||
            this._dragPlaceholder.child.set_width (this.iconSize);
 | 
			
		||||
            this._dragPlaceholder.child.set_height (this.iconSize / 2);
 | 
			
		||||
            this._box.insert_actor(this._dragPlaceholder.actor,
 | 
			
		||||
                                   this._dragPlaceholderPos);
 | 
			
		||||
            if (fadeIn)
 | 
			
		||||
@@ -689,13 +708,13 @@ Dash.prototype = {
 | 
			
		||||
    acceptDrop : function(source, actor, x, y, time) {
 | 
			
		||||
        let app = null;
 | 
			
		||||
        if (source instanceof AppDisplay.AppWellIcon) {
 | 
			
		||||
            app = this._appSystem.get_app(source.getId());
 | 
			
		||||
            app = this._appSystem.lookup_app(source.getId());
 | 
			
		||||
        } else if (source.metaWindow) {
 | 
			
		||||
            app = this._tracker.get_window_app(source.metaWindow);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Don't allow favoriting of transient apps
 | 
			
		||||
        if (app == null || app.is_transient()) {
 | 
			
		||||
        if (app == null || app.is_window_backed()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -731,6 +750,6 @@ Dash.prototype = {
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(Dash.prototype);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
@@ -8,14 +8,14 @@ const Cairo = imports.cairo;
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const Util = imports.misc.util;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const PanelMenu = imports.ui.panelMenu;
 | 
			
		||||
const PopupMenu = imports.ui.popupMenu;
 | 
			
		||||
const Calendar = imports.ui.calendar;
 | 
			
		||||
const UPowerGlib = imports.gi.UPowerGlib;
 | 
			
		||||
 | 
			
		||||
// in org.gnome.desktop.interface
 | 
			
		||||
const CLOCK_FORMAT_KEY        = 'clock-format';
 | 
			
		||||
@@ -40,31 +40,26 @@ function _onVertSepRepaint (area)
 | 
			
		||||
    cr.stroke();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function DateMenuButton() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const DateMenuButton = new Lang.Class({
 | 
			
		||||
    Name: 'DateMenuButton',
 | 
			
		||||
    Extends: PanelMenu.Button,
 | 
			
		||||
 | 
			
		||||
DateMenuButton.prototype = {
 | 
			
		||||
    __proto__: PanelMenu.Button.prototype,
 | 
			
		||||
    _init: function(params) {
 | 
			
		||||
        params = Params.parse(params, { showEvents: true });
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        let item;
 | 
			
		||||
        let hbox;
 | 
			
		||||
        let vbox;
 | 
			
		||||
 | 
			
		||||
        //this._eventSource = new Calendar.EmptyEventSource();
 | 
			
		||||
        //this._eventSource = new Calendar.FakeEventSource();
 | 
			
		||||
        this._eventSource = new Calendar.EvolutionEventSource();
 | 
			
		||||
 | 
			
		||||
        let menuAlignment = 0.25;
 | 
			
		||||
        if (St.Widget.get_default_direction() == St.TextDirection.RTL)
 | 
			
		||||
            menuAlignment = 1.0 - menuAlignment;
 | 
			
		||||
        PanelMenu.Button.prototype._init.call(this, menuAlignment);
 | 
			
		||||
        this.parent(menuAlignment);
 | 
			
		||||
 | 
			
		||||
        this._clock = new St.Label();
 | 
			
		||||
        this.actor.set_child(this._clock);
 | 
			
		||||
        this.actor.add_actor(this._clock);
 | 
			
		||||
 | 
			
		||||
        hbox = new St.BoxLayout({name: 'calendarArea'});
 | 
			
		||||
        hbox = new St.BoxLayout({name: 'calendarArea' });
 | 
			
		||||
        this.menu.addActor(hbox);
 | 
			
		||||
 | 
			
		||||
        // Fill up the first column
 | 
			
		||||
@@ -77,47 +72,77 @@ DateMenuButton.prototype = {
 | 
			
		||||
        this._date.style_class = 'datemenu-date-label';
 | 
			
		||||
        vbox.add(this._date);
 | 
			
		||||
 | 
			
		||||
        this._eventList = new Calendar.EventsList(this._eventSource);
 | 
			
		||||
        if (params.showEvents) {
 | 
			
		||||
            this._eventSource = new Calendar.DBusEventSource();
 | 
			
		||||
            this._eventList = new Calendar.EventsList(this._eventSource);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._eventSource = null;
 | 
			
		||||
            this._eventList = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Calendar
 | 
			
		||||
        this._calendar = new Calendar.Calendar(this._eventSource);
 | 
			
		||||
 | 
			
		||||
        this._calendar.connect('selected-date-changed',
 | 
			
		||||
                               Lang.bind(this, function(calendar, date) {
 | 
			
		||||
                                  // we know this._eventList is defined here, because selected-data-changed
 | 
			
		||||
                                  // only gets emitted when the user clicks a date in the calendar,
 | 
			
		||||
                                  // and the calender makes those dates unclickable when instantiated with
 | 
			
		||||
                                  // a null event source
 | 
			
		||||
                                   this._eventList.setDate(date);
 | 
			
		||||
                               }));
 | 
			
		||||
        vbox.add(this._calendar.actor);
 | 
			
		||||
 | 
			
		||||
        item = new PopupMenu.PopupSeparatorMenuItem();
 | 
			
		||||
        item.setColumnWidths(1);
 | 
			
		||||
        vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
 | 
			
		||||
        item = new PopupMenu.PopupMenuItem(_("Date and Time Settings"));
 | 
			
		||||
        item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
 | 
			
		||||
        vbox.add(item.actor);
 | 
			
		||||
        item = this.menu.addSettingsAction(_("Date and Time Settings"), 'gnome-datetime-panel.desktop');
 | 
			
		||||
        if (item) {
 | 
			
		||||
            let separator = new PopupMenu.PopupSeparatorMenuItem();
 | 
			
		||||
            separator.setColumnWidths(1);
 | 
			
		||||
            vbox.add(separator.actor, {y_align: St.Align.END, expand: true, y_fill: false});
 | 
			
		||||
 | 
			
		||||
        // Add vertical separator
 | 
			
		||||
            item.actor.can_focus = false;
 | 
			
		||||
            item.actor.reparent(vbox);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        item = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
 | 
			
		||||
                                    pseudo_class: 'highlighted' });
 | 
			
		||||
        item.connect('repaint', Lang.bind(this, _onVertSepRepaint));
 | 
			
		||||
        hbox.add(item);
 | 
			
		||||
        if (params.showEvents) {
 | 
			
		||||
            // Add vertical separator
 | 
			
		||||
 | 
			
		||||
        // Fill up the second column
 | 
			
		||||
            item = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
 | 
			
		||||
                                        pseudo_class: 'highlighted' });
 | 
			
		||||
            item.connect('repaint', Lang.bind(this, _onVertSepRepaint));
 | 
			
		||||
            hbox.add(item);
 | 
			
		||||
 | 
			
		||||
        vbox = new St.BoxLayout({vertical: true});
 | 
			
		||||
        hbox.add(vbox);
 | 
			
		||||
            // Fill up the second column
 | 
			
		||||
            vbox = new St.BoxLayout({name:     'calendarEventsArea',
 | 
			
		||||
                                     vertical: true});
 | 
			
		||||
            hbox.add(vbox, { expand: true });
 | 
			
		||||
 | 
			
		||||
        // Event list
 | 
			
		||||
        vbox.add(this._eventList.actor);
 | 
			
		||||
            // Event list
 | 
			
		||||
            vbox.add(this._eventList.actor, { expand: true });
 | 
			
		||||
 | 
			
		||||
        item = new PopupMenu.PopupMenuItem(_("Open Calendar"));
 | 
			
		||||
        item.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
 | 
			
		||||
        vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
 | 
			
		||||
            item = new PopupMenu.PopupMenuItem(_("Open Calendar"));
 | 
			
		||||
            item.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
 | 
			
		||||
            item.actor.can_focus = false;
 | 
			
		||||
            vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Whenever the menu is opened, select today
 | 
			
		||||
        this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
 | 
			
		||||
            if (isOpen) {
 | 
			
		||||
                let now = new Date();
 | 
			
		||||
                this._calendar.setDate(now);
 | 
			
		||||
                /* Passing true to setDate() forces events to be reloaded. We
 | 
			
		||||
                 * want this behavior, because
 | 
			
		||||
                 *
 | 
			
		||||
                 *   o It will cause activation of the calendar server which is
 | 
			
		||||
                 *     useful if it has crashed
 | 
			
		||||
                 *
 | 
			
		||||
                 *   o It will cause the calendar server to reload events which
 | 
			
		||||
                 *     is useful if dynamic updates are not supported or not
 | 
			
		||||
                 *     properly working
 | 
			
		||||
                 *
 | 
			
		||||
                 * Since this only happens when the menu is opened, the cost
 | 
			
		||||
                 * isn't very big.
 | 
			
		||||
                 */
 | 
			
		||||
                this._calendar.setDate(now, true);
 | 
			
		||||
                // No need to update this._eventList as ::selected-date-changed
 | 
			
		||||
                // signal will fire
 | 
			
		||||
            }
 | 
			
		||||
@@ -131,6 +156,10 @@ DateMenuButton.prototype = {
 | 
			
		||||
        this._desktopSettings.connect('changed', Lang.bind(this, this._updateClockAndDate));
 | 
			
		||||
        this._clockSettings.connect('changed', Lang.bind(this, this._updateClockAndDate));
 | 
			
		||||
 | 
			
		||||
        // https://bugzilla.gnome.org/show_bug.cgi?id=655129
 | 
			
		||||
        this._upClient = new UPowerGlib.Client();
 | 
			
		||||
        this._upClient.connect('notify-resume', Lang.bind(this, this._updateClockAndDate));
 | 
			
		||||
 | 
			
		||||
        // Start the clock
 | 
			
		||||
        this._updateClockAndDate();
 | 
			
		||||
    },
 | 
			
		||||
@@ -146,12 +175,12 @@ DateMenuButton.prototype = {
 | 
			
		||||
        switch (format) {
 | 
			
		||||
            case '24h':
 | 
			
		||||
                if (showDate)
 | 
			
		||||
	            /* Translators: This is the time format with date used
 | 
			
		||||
                    /* Translators: This is the time format with date used
 | 
			
		||||
                       in 24-hour mode. */
 | 
			
		||||
                    clockFormat = showSeconds ? _("%a %b %e, %R:%S")
 | 
			
		||||
                                              : _("%a %b %e, %R");
 | 
			
		||||
                else
 | 
			
		||||
	            /* Translators: This is the time format without date used
 | 
			
		||||
                    /* Translators: This is the time format without date used
 | 
			
		||||
                       in 24-hour mode. */
 | 
			
		||||
                    clockFormat = showSeconds ? _("%a %R:%S")
 | 
			
		||||
                                              : _("%a %R");
 | 
			
		||||
@@ -159,12 +188,12 @@ DateMenuButton.prototype = {
 | 
			
		||||
            case '12h':
 | 
			
		||||
            default:
 | 
			
		||||
                if (showDate)
 | 
			
		||||
	            /* Translators: This is a time format with date used
 | 
			
		||||
                    /* Translators: This is a time format with date used
 | 
			
		||||
                       for AM/PM. */
 | 
			
		||||
                    clockFormat = showSeconds ? _("%a %b %e, %l:%M:%S %p")
 | 
			
		||||
                                              : _("%a %b %e, %l:%M %p");
 | 
			
		||||
                else
 | 
			
		||||
	            /* Translators: This is a time format without date used
 | 
			
		||||
                    /* Translators: This is a time format without date used
 | 
			
		||||
                       for AM/PM. */
 | 
			
		||||
                    clockFormat = showSeconds ? _("%a %l:%M:%S %p")
 | 
			
		||||
                                              : _("%a %l:%M %p");
 | 
			
		||||
@@ -172,21 +201,6 @@ DateMenuButton.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let displayDate = new Date();
 | 
			
		||||
        let msecRemaining;
 | 
			
		||||
        if (showSeconds) {
 | 
			
		||||
            msecRemaining = 1000 - displayDate.getMilliseconds();
 | 
			
		||||
            if (msecRemaining < 50) {
 | 
			
		||||
                displayDate.setSeconds(displayDate.getSeconds() + 1);
 | 
			
		||||
                msecRemaining += 1000;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            msecRemaining = 60000 - (1000 * displayDate.getSeconds() +
 | 
			
		||||
                                     displayDate.getMilliseconds());
 | 
			
		||||
            if (msecRemaining < 500) {
 | 
			
		||||
                displayDate.setMinutes(displayDate.getMinutes() + 1);
 | 
			
		||||
                msecRemaining += 60000;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._clock.set_text(displayDate.toLocaleFormat(clockFormat));
 | 
			
		||||
 | 
			
		||||
@@ -196,19 +210,30 @@ DateMenuButton.prototype = {
 | 
			
		||||
        dateFormat = _("%A %B %e, %Y");
 | 
			
		||||
        this._date.set_text(displayDate.toLocaleFormat(dateFormat));
 | 
			
		||||
 | 
			
		||||
        Mainloop.timeout_add(msecRemaining, Lang.bind(this, this._updateClockAndDate));
 | 
			
		||||
        Mainloop.timeout_add_seconds(1, Lang.bind(this, this._updateClockAndDate));
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onPreferencesActivate: function() {
 | 
			
		||||
        this.menu.close();
 | 
			
		||||
        Util.spawnDesktop('gnome-datetime-panel');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onOpenCalendarActivate: function() {
 | 
			
		||||
        this.menu.close();
 | 
			
		||||
        // TODO: pass '-c calendar' (to force the calendar at startup)
 | 
			
		||||
        // TODO: pass the selected day
 | 
			
		||||
        Util.spawnDesktop('evolution');
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
        let calendarSettings = new Gio.Settings({ schema: 'org.gnome.desktop.default-applications.office.calendar' });
 | 
			
		||||
        let tool = calendarSettings.get_string('exec');
 | 
			
		||||
        if (tool.length == 0 || tool == 'evolution') {
 | 
			
		||||
            // TODO: pass the selected day
 | 
			
		||||
            Util.spawn(['evolution', '-c', 'calendar']);
 | 
			
		||||
        } else {
 | 
			
		||||
            let needTerm = calendarSettings.get_boolean('needs-term');
 | 
			
		||||
            if (needTerm) {
 | 
			
		||||
                let terminalSettings = new Gio.Settings({ schema: 'org.gnome.desktop.default-applications.terminal' });
 | 
			
		||||
                let term = terminalSettings.get_string('exec');
 | 
			
		||||
                let arg = terminalSettings.get_string('exec-arg');
 | 
			
		||||
                if (arg != '')
 | 
			
		||||
                    Util.spawn([term, arg, tool]);
 | 
			
		||||
                else
 | 
			
		||||
                    Util.spawn([term, tool]);
 | 
			
		||||
            } else {
 | 
			
		||||
                Util.spawnCommandLine(tool)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										73
									
								
								js/ui/dnd.js
									
									
									
									
									
								
							
							
						
						@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
@@ -61,7 +61,7 @@ function addDragMonitor(monitor) {
 | 
			
		||||
    dragMonitors.push(monitor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function removeMonitor(monitor) {
 | 
			
		||||
function removeDragMonitor(monitor) {
 | 
			
		||||
    for (let i = 0; i < dragMonitors.length; i++)
 | 
			
		||||
        if (dragMonitors[i] == monitor) {
 | 
			
		||||
            dragMonitors.splice(i, 1);
 | 
			
		||||
@@ -69,11 +69,9 @@ function removeMonitor(monitor) {
 | 
			
		||||
        }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _Draggable(actor, params) {
 | 
			
		||||
    this._init(actor, params);
 | 
			
		||||
}
 | 
			
		||||
const _Draggable = new Lang.Class({
 | 
			
		||||
    Name: 'Draggable',
 | 
			
		||||
 | 
			
		||||
_Draggable.prototype = {
 | 
			
		||||
    _init : function(actor, params) {
 | 
			
		||||
        params = Params.parse(params, { manualMode: false,
 | 
			
		||||
                                        restoreOnSuccess: false,
 | 
			
		||||
@@ -87,6 +85,10 @@ _Draggable.prototype = {
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, function() {
 | 
			
		||||
            this._actorDestroyed = true;
 | 
			
		||||
            // If the drag actor is destroyed and we were going to fix
 | 
			
		||||
            // up its hover state, fix up the parent hover state instead
 | 
			
		||||
            if (this.actor == this._firstLeaveActor)
 | 
			
		||||
                this._firstLeaveActor = this._dragOrigParent;
 | 
			
		||||
            if (this._dragInProgress)
 | 
			
		||||
                this._cancelDrag(global.get_current_time());
 | 
			
		||||
            this.disconnectAll();
 | 
			
		||||
@@ -101,6 +103,12 @@ _Draggable.prototype = {
 | 
			
		||||
        this._dragInProgress = false; // The drag has been started, and has not been dropped or cancelled yet.
 | 
			
		||||
        this._animationInProgress = false; // The drag is over and the item is in the process of animating to its original position (snapping back or reverting).
 | 
			
		||||
 | 
			
		||||
        // During the drag, we eat enter/leave events so that actors don't prelight or show
 | 
			
		||||
        // tooltips. But we remember the actors that we first left/last entered so we can
 | 
			
		||||
        // fix up the hover state after the drag ends.
 | 
			
		||||
        this._firstLeaveActor = null;
 | 
			
		||||
        this._lastEnterActor = null;
 | 
			
		||||
 | 
			
		||||
        this._eventsGrabbed = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -144,6 +152,8 @@ _Draggable.prototype = {
 | 
			
		||||
 | 
			
		||||
    _ungrabActor: function() {
 | 
			
		||||
        Clutter.ungrab_pointer();
 | 
			
		||||
        if (!this._onEventId)
 | 
			
		||||
            return;
 | 
			
		||||
        this.actor.disconnect(this._onEventId);
 | 
			
		||||
        this._onEventId = null;
 | 
			
		||||
    },
 | 
			
		||||
@@ -198,6 +208,11 @@ _Draggable.prototype = {
 | 
			
		||||
                this._cancelDrag(event.get_time());
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (event.type() == Clutter.EventType.LEAVE) {
 | 
			
		||||
            if (this._firstLeaveActor == null)
 | 
			
		||||
                this._firstLeaveActor = event.get_source();
 | 
			
		||||
        } else if (event.type() == Clutter.EventType.ENTER) {
 | 
			
		||||
            this._lastEnterActor = event.get_source();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
@@ -267,13 +282,13 @@ _Draggable.prototype = {
 | 
			
		||||
            this._dragOffsetY = actorStageY - this._dragStartY;
 | 
			
		||||
 | 
			
		||||
            // Set the actor's scale such that it will keep the same
 | 
			
		||||
            // transformed size when it's reparented to the stage
 | 
			
		||||
            // transformed size when it's reparented to the uiGroup
 | 
			
		||||
            let [scaledWidth, scaledHeight] = this.actor.get_transformed_size();
 | 
			
		||||
            this.actor.set_scale(scaledWidth / this.actor.width,
 | 
			
		||||
                                 scaledHeight / this.actor.height);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._dragActor.reparent(this.actor.get_stage());
 | 
			
		||||
        this._dragActor.reparent(Main.uiGroup);
 | 
			
		||||
        this._dragActor.raise_top();
 | 
			
		||||
        Shell.util_set_hidden_from_pick(this._dragActor, true);
 | 
			
		||||
 | 
			
		||||
@@ -425,7 +440,7 @@ _Draggable.prototype = {
 | 
			
		||||
                        return true;
 | 
			
		||||
                    // If it accepted the drop without taking the actor,
 | 
			
		||||
                    // handle it ourselves.
 | 
			
		||||
                    if (this._dragActor.get_parent() == this._dragActor.get_stage()) {
 | 
			
		||||
                    if (this._dragActor.get_parent() == Main.uiGroup) {
 | 
			
		||||
                        if (this._restoreOnSuccess) {
 | 
			
		||||
                            this._restoreDragActor(event.get_time());
 | 
			
		||||
                            return true;
 | 
			
		||||
@@ -463,7 +478,9 @@ _Draggable.prototype = {
 | 
			
		||||
            let [parentX, parentY] = this._dragOrigParent.get_transformed_position();
 | 
			
		||||
            let [parentWidth, parentHeight] = this._dragOrigParent.get_size();
 | 
			
		||||
            let [parentScaledWidth, parentScaledHeight] = this._dragOrigParent.get_transformed_size();
 | 
			
		||||
            let parentScale = parentScaledWidth / parentWidth;
 | 
			
		||||
            let parentScale = 1.0;
 | 
			
		||||
            if (parentWidth != 0)
 | 
			
		||||
                parentScale = parentScaledWidth / parentWidth;
 | 
			
		||||
 | 
			
		||||
            x = parentX + parentScale * this._dragOrigX;
 | 
			
		||||
            y = parentY + parentScale * this._dragOrigY;
 | 
			
		||||
@@ -479,14 +496,18 @@ _Draggable.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _cancelDrag: function(eventTime) {
 | 
			
		||||
        this.emit('drag-cancelled', eventTime);
 | 
			
		||||
        this._dragInProgress = false;
 | 
			
		||||
        let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation();
 | 
			
		||||
 | 
			
		||||
        if (this._actorDestroyed) {
 | 
			
		||||
            global.unset_cursor();
 | 
			
		||||
            if (!this._buttonDown)
 | 
			
		||||
                this._ungrabEvents();
 | 
			
		||||
                this._dragComplete();
 | 
			
		||||
            this.emit('drag-end', eventTime, false);
 | 
			
		||||
            if (!this._dragOrigParent)
 | 
			
		||||
                this._dragActor.destroy();
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -542,14 +563,38 @@ _Draggable.prototype = {
 | 
			
		||||
            this._dragComplete();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Actor is an actor we have entered or left during the drag; call
 | 
			
		||||
    // st_widget_sync_hover on all StWidget ancestors
 | 
			
		||||
    _syncHover: function(actor) {
 | 
			
		||||
        while (actor) {
 | 
			
		||||
            let parent = actor.get_parent();
 | 
			
		||||
            if (actor instanceof St.Widget)
 | 
			
		||||
                actor.sync_hover();
 | 
			
		||||
 | 
			
		||||
            actor = parent;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _dragComplete: function() {
 | 
			
		||||
        Shell.util_set_hidden_from_pick(this._dragActor, false);
 | 
			
		||||
        if (!this._actorDestroyed)
 | 
			
		||||
            Shell.util_set_hidden_from_pick(this._dragActor, false);
 | 
			
		||||
 | 
			
		||||
        this._ungrabEvents();
 | 
			
		||||
 | 
			
		||||
        if (this._firstLeaveActor) {
 | 
			
		||||
            this._syncHover(this._firstLeaveActor);
 | 
			
		||||
            this._firstLeaveActor = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._lastEnterActor) {
 | 
			
		||||
            this._syncHover(this._lastEnterActor);
 | 
			
		||||
            this._lastEnterActor = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._dragActor = undefined;
 | 
			
		||||
        currentDraggable = null;
 | 
			
		||||
        this._ungrabEvents();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(_Draggable.prototype);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,22 +1,16 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const DocInfo = imports.misc.docInfo;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const Search = imports.ui.search;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function DocSearchProvider() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DocSearchProvider.prototype = {
 | 
			
		||||
    __proto__: Search.SearchProvider.prototype,
 | 
			
		||||
const DocSearchProvider = new Lang.Class({
 | 
			
		||||
    Name: 'DocSearchProvider',
 | 
			
		||||
    Extends: Search.SearchProvider,
 | 
			
		||||
 | 
			
		||||
    _init: function(name) {
 | 
			
		||||
        Search.SearchProvider.prototype._init.call(this, _("RECENT ITEMS"));
 | 
			
		||||
        this.parent(_("RECENT ITEMS"));
 | 
			
		||||
        this._docManager = DocInfo.getDocManager();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -26,15 +20,18 @@ DocSearchProvider.prototype = {
 | 
			
		||||
            return null;
 | 
			
		||||
        return { 'id': resultId,
 | 
			
		||||
                 'name': docInfo.name,
 | 
			
		||||
                 'icon': docInfo.createIcon(Search.RESULT_ICON_SIZE)};
 | 
			
		||||
                 'createIcon': function(size) {
 | 
			
		||||
                                   return docInfo.createIcon(size);
 | 
			
		||||
                               }
 | 
			
		||||
               };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activateResult: function(id, params) {
 | 
			
		||||
        params = Params.parse(params, { workspace: null,
 | 
			
		||||
                                        timestamp: null });
 | 
			
		||||
        params = Params.parse(params, { workspace: -1,
 | 
			
		||||
                                        timestamp: 0 });
 | 
			
		||||
 | 
			
		||||
        let docInfo = this._docManager.lookupByUri(id);
 | 
			
		||||
        docInfo.launch(params.workspace ? params.workspace.index() : -1);
 | 
			
		||||
        docInfo.launch(params.workspace);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getInitialResultSet: function(terms) {
 | 
			
		||||
@@ -43,9 +40,5 @@ DocSearchProvider.prototype = {
 | 
			
		||||
 | 
			
		||||
    getSubsearchResultSet: function(previousResults, terms) {
 | 
			
		||||
        return this._docManager.subsearch(previousResults, terms);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    expandSearch: function(terms) {
 | 
			
		||||
        log('TODO expand docs search');
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 *
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2010 Red Hat, Inc
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
@@ -18,22 +18,19 @@
 | 
			
		||||
 * 02111-1307, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
const DBus = imports.dbus;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
 | 
			
		||||
const AccountsService = imports.gi.AccountsService;
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gdm = imports.gi.Gdm;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
const Pango = imports.gi.Pango;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
 | 
			
		||||
const GnomeSession = imports.misc.gnomeSession
 | 
			
		||||
const GnomeSession = imports.misc.gnomeSession;
 | 
			
		||||
const Lightbox = imports.ui.lightbox;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
@@ -46,46 +43,68 @@ const _DIALOG_ICON_SIZE = 32;
 | 
			
		||||
 | 
			
		||||
const GSM_SESSION_MANAGER_LOGOUT_FORCE = 2;
 | 
			
		||||
 | 
			
		||||
const EndSessionDialogIface = {
 | 
			
		||||
    name: 'org.gnome.SessionManager.EndSessionDialog',
 | 
			
		||||
    methods: [{ name: 'Open',
 | 
			
		||||
                inSignature: 'uuuao',
 | 
			
		||||
                outSignature: ''
 | 
			
		||||
              }
 | 
			
		||||
             ],
 | 
			
		||||
    signals: [{ name: 'Canceled',
 | 
			
		||||
                outSignature: '',
 | 
			
		||||
              }],
 | 
			
		||||
    properties: []
 | 
			
		||||
};
 | 
			
		||||
const EndSessionDialogIface = <interface name="org.gnome.SessionManager.EndSessionDialog">
 | 
			
		||||
<method name="Open">
 | 
			
		||||
    <arg type="u" direction="in" />
 | 
			
		||||
    <arg type="u" direction="in" />
 | 
			
		||||
    <arg type="u" direction="in" />
 | 
			
		||||
    <arg type="ao" direction="in" />
 | 
			
		||||
</method>
 | 
			
		||||
<signal name="ConfirmedLogout" />
 | 
			
		||||
<signal name="ConfirmedReboot" />
 | 
			
		||||
<signal name="ConfirmedShutdown" />
 | 
			
		||||
<signal name="Canceled" />
 | 
			
		||||
<signal name="Closed" />
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const logoutDialogContent = {
 | 
			
		||||
    subjectWithUser: _("Log Out %s"),
 | 
			
		||||
    subject: _("Log Out"),
 | 
			
		||||
    subjectWithUser: C_("title", "Log Out %s"),
 | 
			
		||||
    subject: C_("title", "Log Out"),
 | 
			
		||||
    inhibitedDescription: _("Click Log Out to quit these applications and log out of the system."),
 | 
			
		||||
    uninhibitedDescriptionWithUser: _("%s will be logged out automatically in %d seconds."),
 | 
			
		||||
    uninhibitedDescription: _("You will be logged out automatically in %d seconds."),
 | 
			
		||||
    uninhibitedDescriptionWithUser: function(user, seconds) {
 | 
			
		||||
        return ngettext("%s will be logged out automatically in %d second.",
 | 
			
		||||
                        "%s will be logged out automatically in %d seconds.",
 | 
			
		||||
                        seconds).format(user, seconds);
 | 
			
		||||
    },
 | 
			
		||||
    uninhibitedDescription: function(seconds) {
 | 
			
		||||
        return ngettext("You will be logged out automatically in %d second.",
 | 
			
		||||
                        "You will be logged out automatically in %d seconds.",
 | 
			
		||||
                        seconds).format(seconds);
 | 
			
		||||
    },
 | 
			
		||||
    endDescription: _("Logging out of the system."),
 | 
			
		||||
    confirmButtonText: _("Log Out"),
 | 
			
		||||
    confirmButtons: [{ signal: 'ConfirmedLogout',
 | 
			
		||||
                       label:  C_("button", "Log Out") }],
 | 
			
		||||
    iconStyleClass: 'end-session-dialog-logout-icon'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const shutdownDialogContent = {
 | 
			
		||||
    subject: _("Shut Down"),
 | 
			
		||||
    inhibitedDescription: _("Click Shut Down to quit these applications and shut down the system."),
 | 
			
		||||
    uninhibitedDescription: _("The system will shut down automatically in %d seconds."),
 | 
			
		||||
    endDescription: _("Shutting down the system."),
 | 
			
		||||
    confirmButtonText: _("Shut Down"),
 | 
			
		||||
    subject: C_("title", "Power Off"),
 | 
			
		||||
    inhibitedDescription: _("Click Power Off to quit these applications and power off the system."),
 | 
			
		||||
    uninhibitedDescription: function(seconds) {
 | 
			
		||||
        return ngettext("The system will power off automatically in %d second.",
 | 
			
		||||
                        "The system will power off automatically in %d seconds.",
 | 
			
		||||
                        seconds).format(seconds);
 | 
			
		||||
    },
 | 
			
		||||
    endDescription: _("Powering off the system."),
 | 
			
		||||
    confirmButtons: [{ signal: 'ConfirmedReboot',
 | 
			
		||||
                       label:  C_("button", "Restart") },
 | 
			
		||||
                     { signal: 'ConfirmedShutdown',
 | 
			
		||||
                       label:  C_("button", "Power Off") }],
 | 
			
		||||
    iconName: 'system-shutdown',
 | 
			
		||||
    iconStyleClass: 'end-session-dialog-shutdown-icon'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const restartDialogContent = {
 | 
			
		||||
    subject: _("Restart"),
 | 
			
		||||
    subject: C_("title", "Restart"),
 | 
			
		||||
    inhibitedDescription: _("Click Restart to quit these applications and restart the system."),
 | 
			
		||||
    uninhibitedDescription: _("The system will restart automatically in %d seconds."),
 | 
			
		||||
    uninhibitedDescription: function(seconds) {
 | 
			
		||||
        return ngettext("The system will restart automatically in %d second.",
 | 
			
		||||
                        "The system will restart automatically in %d seconds.",
 | 
			
		||||
                        seconds).format(seconds);
 | 
			
		||||
    },
 | 
			
		||||
    endDescription: _("Restarting the system."),
 | 
			
		||||
    confirmButtonText: _("Restart"),
 | 
			
		||||
    confirmButtons: [{ signal: 'ConfirmedReboot',
 | 
			
		||||
                       label:  C_("button", "Restart") }],
 | 
			
		||||
    iconName: 'system-shutdown',
 | 
			
		||||
    iconStyleClass: 'end-session-dialog-shutdown-icon'
 | 
			
		||||
};
 | 
			
		||||
@@ -111,7 +130,7 @@ function findAppFromInhibitor(inhibitor) {
 | 
			
		||||
    let app = null;
 | 
			
		||||
    for (let i = 0; i < candidateDesktopFiles.length; i++) {
 | 
			
		||||
        try {
 | 
			
		||||
            app = appSystem.get_app(candidateDesktopFiles[i]);
 | 
			
		||||
            app = appSystem.lookup_app(candidateDesktopFiles[i]);
 | 
			
		||||
 | 
			
		||||
            if (app)
 | 
			
		||||
                break;
 | 
			
		||||
@@ -123,11 +142,9 @@ function findAppFromInhibitor(inhibitor) {
 | 
			
		||||
    return app;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ListItem(app, reason) {
 | 
			
		||||
    this._init(app, reason);
 | 
			
		||||
}
 | 
			
		||||
const ListItem = new Lang.Class({
 | 
			
		||||
    Name: 'ListItem',
 | 
			
		||||
 | 
			
		||||
ListItem.prototype = {
 | 
			
		||||
    _init: function(app, reason) {
 | 
			
		||||
        this._app = app;
 | 
			
		||||
        this._reason = reason;
 | 
			
		||||
@@ -171,9 +188,9 @@ ListItem.prototype = {
 | 
			
		||||
 | 
			
		||||
    _onClicked: function() {
 | 
			
		||||
        this.emit('activate');
 | 
			
		||||
        this._app.activate(-1);
 | 
			
		||||
        this._app.activate();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ListItem.prototype);
 | 
			
		||||
 | 
			
		||||
// The logout timer only shows updates every 10 seconds
 | 
			
		||||
@@ -211,31 +228,21 @@ function _setLabelText(label, text) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function EndSessionDialog() {
 | 
			
		||||
    if (_endSessionDialog == null) {
 | 
			
		||||
        this._init();
 | 
			
		||||
        DBus.session.exportObject('/org/gnome/SessionManager/EndSessionDialog',
 | 
			
		||||
                                  this);
 | 
			
		||||
        _endSessionDialog = this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return _endSessionDialog;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function init() {
 | 
			
		||||
    // This always returns the same singleton object
 | 
			
		||||
    // By instantiating it initially, we register the
 | 
			
		||||
    // bus object, etc.
 | 
			
		||||
    let dialog = new EndSessionDialog();
 | 
			
		||||
    _endSessionDialog = new EndSessionDialog();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
EndSessionDialog.prototype = {
 | 
			
		||||
    __proto__: ModalDialog.ModalDialog.prototype,
 | 
			
		||||
const EndSessionDialog = new Lang.Class({
 | 
			
		||||
    Name: 'EndSessionDialog',
 | 
			
		||||
    Extends: ModalDialog.ModalDialog,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        ModalDialog.ModalDialog.prototype._init.call(this);
 | 
			
		||||
        this.parent({ styleClass: 'end-session-dialog' });
 | 
			
		||||
 | 
			
		||||
        this._user = Gdm.UserManager.ref_default().get_user(GLib.get_user_name());
 | 
			
		||||
        this._user = AccountsService.UserManager.get_default().get_user(GLib.get_user_name());
 | 
			
		||||
 | 
			
		||||
        this._secondsLeft = 0;
 | 
			
		||||
        this._totalSecondsToStayOpen = 0;
 | 
			
		||||
@@ -288,12 +295,29 @@ EndSessionDialog.prototype = {
 | 
			
		||||
        this.contentLayout.add(scrollView,
 | 
			
		||||
                               { x_fill: true,
 | 
			
		||||
                                 y_fill: true });
 | 
			
		||||
        scrollView.hide();
 | 
			
		||||
 | 
			
		||||
        this._applicationList = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        scrollView.add_actor(this._applicationList,
 | 
			
		||||
                             { x_fill:  true,
 | 
			
		||||
                               y_fill:  true,
 | 
			
		||||
                               x_align: St.Align.START,
 | 
			
		||||
                               y_align: St.Align.MIDDLE });
 | 
			
		||||
 | 
			
		||||
        this._applicationList.connect('actor-added',
 | 
			
		||||
                                      Lang.bind(this, function() {
 | 
			
		||||
                                          if (this._applicationList.get_children().length == 1)
 | 
			
		||||
                                              scrollView.show();
 | 
			
		||||
                                      }));
 | 
			
		||||
 | 
			
		||||
        this._applicationList.connect('actor-removed',
 | 
			
		||||
                                      Lang.bind(this, function() {
 | 
			
		||||
                                          if (this._applicationList.get_children().length == 0)
 | 
			
		||||
                                              scrollView.hide();
 | 
			
		||||
                                      }));
 | 
			
		||||
 | 
			
		||||
        this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(EndSessionDialogIface, this);
 | 
			
		||||
        this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDestroy: function() {
 | 
			
		||||
@@ -347,8 +371,10 @@ EndSessionDialog.prototype = {
 | 
			
		||||
 | 
			
		||||
        if (this._user.is_loaded && !dialogContent.iconName) {
 | 
			
		||||
            let iconFile = this._user.get_icon_file();
 | 
			
		||||
 | 
			
		||||
            this._setIconFromFile(iconFile, dialogContent.iconStyleClass);
 | 
			
		||||
            if (GLib.file_test(iconFile, GLib.FileTest.EXISTS))
 | 
			
		||||
                this._setIconFromFile(iconFile, dialogContent.iconStyleClass);
 | 
			
		||||
            else
 | 
			
		||||
                this._setIconFromName('avatar-default', dialogContent.iconStyleClass);
 | 
			
		||||
        } else if (dialogContent.iconName) {
 | 
			
		||||
            this._setIconFromName(dialogContent.iconName,
 | 
			
		||||
                                  dialogContent.iconStyleClass);
 | 
			
		||||
@@ -370,14 +396,14 @@ EndSessionDialog.prototype = {
 | 
			
		||||
                        subject = dialogContent.subjectWithUser.format(realName);
 | 
			
		||||
 | 
			
		||||
                    if (dialogContent.uninhibitedDescriptionWithUser)
 | 
			
		||||
                        description = dialogContent.uninhibitedDescriptionWithUser.format(realName, displayTime);
 | 
			
		||||
                        description = dialogContent.uninhibitedDescriptionWithUser(realName, displayTime);
 | 
			
		||||
                    else
 | 
			
		||||
                        description = dialogContent.uninhibitedDescription.format(displayTime);
 | 
			
		||||
                        description = dialogContent.uninhibitedDescription(displayTime);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!description)
 | 
			
		||||
                description = dialogContent.uninhibitedDescription.format(displayTime);
 | 
			
		||||
                description = dialogContent.uninhibitedDescription(displayTime);
 | 
			
		||||
        } else {
 | 
			
		||||
            description = dialogContent.endDescription;
 | 
			
		||||
        }
 | 
			
		||||
@@ -387,39 +413,38 @@ EndSessionDialog.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateButtons: function() {
 | 
			
		||||
        if (this.state != ModalDialog.State.OPENING &&
 | 
			
		||||
            this.state != ModalDialog.State.OPENED)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let dialogContent = DialogContent[this._type];
 | 
			
		||||
        let confirmButtonText = _("Confirm");
 | 
			
		||||
        let buttons = [{ action: Lang.bind(this, this.cancel),
 | 
			
		||||
                         label:  _("Cancel"),
 | 
			
		||||
                         key:    Clutter.Escape }];
 | 
			
		||||
 | 
			
		||||
        if (dialogContent.confirmButtonText)
 | 
			
		||||
            confirmButtonText = dialogContent.confirmButtonText;
 | 
			
		||||
        for (let i = 0; i < dialogContent.confirmButtons.length; i++) {
 | 
			
		||||
            let signal = dialogContent.confirmButtons[i].signal;
 | 
			
		||||
            let label = dialogContent.confirmButtons[i].label;
 | 
			
		||||
            buttons.push({ action: Lang.bind(this, function() {
 | 
			
		||||
                                       this._confirm(signal);
 | 
			
		||||
                                   }),
 | 
			
		||||
                           label: label });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.setButtons([{ label: _("Cancel"),
 | 
			
		||||
                           action: Lang.bind(this, this.cancel),
 | 
			
		||||
                           key:    Clutter.Escape
 | 
			
		||||
                         },
 | 
			
		||||
                         { label:  confirmButtonText,
 | 
			
		||||
                           action: Lang.bind(this, this._confirm)
 | 
			
		||||
                         }]);
 | 
			
		||||
        this.setButtons(buttons);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    close: function() {
 | 
			
		||||
        this.parent();
 | 
			
		||||
        this._dbusImpl.emit_signal('Closed', null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    cancel: function() {
 | 
			
		||||
        this._stopTimer();
 | 
			
		||||
        DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
 | 
			
		||||
                                 'org.gnome.SessionManager.EndSessionDialog',
 | 
			
		||||
                                 'Canceled', '', []);
 | 
			
		||||
        this._dbusImpl.emit_signal('Canceled', null);
 | 
			
		||||
        this.close(global.get_current_time());
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _confirm: function() {
 | 
			
		||||
    _confirm: function(signal) {
 | 
			
		||||
        this._fadeOutDialog();
 | 
			
		||||
        this._stopTimer();
 | 
			
		||||
        DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
 | 
			
		||||
                                 'org.gnome.SessionManager.EndSessionDialog',
 | 
			
		||||
                                 'Confirmed', '', []);
 | 
			
		||||
        this._dbusImpl.emit_signal(signal, null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onOpened: function() {
 | 
			
		||||
@@ -434,7 +459,11 @@ EndSessionDialog.prototype = {
 | 
			
		||||
                           time: this._secondsLeft,
 | 
			
		||||
                           transition: 'linear',
 | 
			
		||||
                           onUpdate: Lang.bind(this, this._updateContent),
 | 
			
		||||
                           onComplete: Lang.bind(this, this._confirm),
 | 
			
		||||
                           onComplete: Lang.bind(this, function() {
 | 
			
		||||
                                           let dialogContent = DialogContent[this._type];
 | 
			
		||||
                                           let button = dialogContent.confirmButtons[dialogContent.confirmButtons.length - 1];
 | 
			
		||||
                                           this._confirm(button.signal);
 | 
			
		||||
                                       }),
 | 
			
		||||
                         });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -467,38 +496,41 @@ EndSessionDialog.prototype = {
 | 
			
		||||
        this._updateContent();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    OpenAsync: function(type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths, callback) {
 | 
			
		||||
    OpenAsync: function(parameters, invocation) {
 | 
			
		||||
        let [type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths] = parameters;
 | 
			
		||||
        this._totalSecondsToStayOpen = totalSecondsToStayOpen;
 | 
			
		||||
        this._inhibitors = [];
 | 
			
		||||
        this._applicationList.destroy_children();
 | 
			
		||||
        this._type = type;
 | 
			
		||||
 | 
			
		||||
        if (!(this._type in DialogContent))
 | 
			
		||||
            throw new DBus.DBusError('org.gnome.Shell.ModalDialog.TypeError',
 | 
			
		||||
                                     "Unknown dialog type requested");
 | 
			
		||||
        if (!(this._type in DialogContent)) {
 | 
			
		||||
            invocation.report_dbus_error('org.gnome.Shell.ModalDialog.TypeError',
 | 
			
		||||
                                         "Unknown dialog type requested");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < inhibitorObjectPaths.length; i++) {
 | 
			
		||||
            let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i]);
 | 
			
		||||
            let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i], Lang.bind(this, function(proxy, error) {
 | 
			
		||||
                this._onInhibitorLoaded(proxy);
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            inhibitor.connect('is-loaded',
 | 
			
		||||
                              Lang.bind(this, function() {
 | 
			
		||||
                                  this._onInhibitorLoaded(inhibitor);
 | 
			
		||||
                              }));
 | 
			
		||||
            this._inhibitors.push(inhibitor);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!this.open(timestamp))
 | 
			
		||||
            throw new DBus.DBusError('org.gnome.Shell.ModalDialog.GrabError',
 | 
			
		||||
                                     "Cannot grab pointer and keyboard");
 | 
			
		||||
 | 
			
		||||
        this._updateButtons();
 | 
			
		||||
 | 
			
		||||
        if (!this.open(timestamp)) {
 | 
			
		||||
            invocation.report_dbus_error('org.gnome.Shell.ModalDialog.GrabError',
 | 
			
		||||
                                         "Cannot grab pointer and keyboard");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._updateContent();
 | 
			
		||||
 | 
			
		||||
        let signalId = this.connect('opened',
 | 
			
		||||
                                    Lang.bind(this, function() {
 | 
			
		||||
                                        callback();
 | 
			
		||||
                                        invocation.return_value(null);
 | 
			
		||||
                                        this.disconnect(signalId);
 | 
			
		||||
                                    }));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
DBus.conformExport(EndSessionDialog.prototype, EndSessionDialogIface);
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,22 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
imports.gi.versions.Clutter = '1.0';
 | 
			
		||||
imports.gi.versions.Gio = '2.0';
 | 
			
		||||
imports.gi.versions.Gdk = '3.0';
 | 
			
		||||
imports.gi.versions.GdkPixbuf = '2.0';
 | 
			
		||||
imports.gi.versions.Gtk = '3.0';
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;;
 | 
			
		||||
const Gettext = imports.gettext;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Gettext_gtk30 = imports.gettext.domain('gtk30');
 | 
			
		||||
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
// We can't import shell JS modules yet, because they may have
 | 
			
		||||
// variable initializations, etc, that depend on init() already having
 | 
			
		||||
// been run.
 | 
			
		||||
 | 
			
		||||
const Format = imports.misc.format;
 | 
			
		||||
 | 
			
		||||
// "monkey patch" in some varargs ClutterContainer methods; we need
 | 
			
		||||
// to do this per-container class since there is no representation
 | 
			
		||||
@@ -17,7 +25,7 @@ function _patchContainerClass(containerClass) {
 | 
			
		||||
    // This one is a straightforward mapping of the C method
 | 
			
		||||
    containerClass.prototype.child_set = function(actor, props) {
 | 
			
		||||
        let meta = this.get_child_meta(actor);
 | 
			
		||||
        for (prop in props)
 | 
			
		||||
        for (let prop in props)
 | 
			
		||||
            meta[prop] = props[prop];
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@@ -31,44 +39,42 @@ function _patchContainerClass(containerClass) {
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Replace @method with something that throws an error instead
 | 
			
		||||
function _blockMethod(method, replacement, reason) {
 | 
			
		||||
    let match = method.match(/^(.+)\.([^.]+)$/);
 | 
			
		||||
    if (!match)
 | 
			
		||||
        throw new Error('Bad method name "' + method + '"');
 | 
			
		||||
    let proto = 'imports.gi.' + match[1] + '.prototype';
 | 
			
		||||
    let property = match[2];
 | 
			
		||||
 | 
			
		||||
    if (!global.set_property_mutable(proto, property, true))
 | 
			
		||||
        throw new Error('Bad method name "' + method + '"');
 | 
			
		||||
 | 
			
		||||
    // eval() is evil in general, but we know it's safe here since
 | 
			
		||||
    // set_property_mutable() would have failed if proto was
 | 
			
		||||
    // malformed.
 | 
			
		||||
    let node = eval(proto);
 | 
			
		||||
 | 
			
		||||
    let msg = 'Do not use "' + method + '".';
 | 
			
		||||
    if (replacement)
 | 
			
		||||
        msg += ' Use "' + replacement + '" instead.';
 | 
			
		||||
    if (reason)
 | 
			
		||||
        msg += ' (' + reason + ')';
 | 
			
		||||
 | 
			
		||||
    node[property] = function() {
 | 
			
		||||
        throw new Error(msg);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    global.set_property_mutable(proto, property, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function init() {
 | 
			
		||||
    Tweener.init();
 | 
			
		||||
    String.prototype.format = Format.format;
 | 
			
		||||
    // Add some bindings to the global JS namespace; (gjs keeps the web
 | 
			
		||||
    // browser convention of having that namespace be called 'window'.)
 | 
			
		||||
    window.global = Shell.Global.get();
 | 
			
		||||
 | 
			
		||||
    window._ = Gettext.gettext;
 | 
			
		||||
    window.C_ = Gettext.pgettext;
 | 
			
		||||
    window.ngettext = Gettext.ngettext;
 | 
			
		||||
 | 
			
		||||
    // Set the default direction for St widgets (this needs to be done before any use of St)
 | 
			
		||||
    if (Gettext_gtk30.gettext('default:LTR') == 'default:RTL') {
 | 
			
		||||
    if (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL) {
 | 
			
		||||
        St.Widget.set_default_direction(St.TextDirection.RTL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Miscellaneous monkeypatching
 | 
			
		||||
    _patchContainerClass(St.BoxLayout);
 | 
			
		||||
    _patchContainerClass(St.Table);
 | 
			
		||||
 | 
			
		||||
    Clutter.Actor.prototype.toString = function() {
 | 
			
		||||
        return St.describe_actor(this);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let origToString = Object.prototype.toString;
 | 
			
		||||
    Object.prototype.toString = function() {
 | 
			
		||||
        let base = origToString.call(this);
 | 
			
		||||
        if ('actor' in this && this.actor instanceof Clutter.Actor)
 | 
			
		||||
            return base.replace(/\]$/, ' delegate for ' + this.actor.toString().substring(1));
 | 
			
		||||
        else
 | 
			
		||||
            return base;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=508783
 | 
			
		||||
    Date.prototype.toLocaleFormat = function(format) {
 | 
			
		||||
        return Shell.util_format_date(format, this.getTime());
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let slowdownEnv = GLib.getenv('GNOME_SHELL_SLOWDOWN_FACTOR');
 | 
			
		||||
    if (slowdownEnv) {
 | 
			
		||||
        let factor = parseFloat(slowdownEnv);
 | 
			
		||||
@@ -76,24 +82,10 @@ function init() {
 | 
			
		||||
            St.set_slow_down_factor(factor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _patchContainerClass(St.BoxLayout);
 | 
			
		||||
    _patchContainerClass(St.Table);
 | 
			
		||||
    // OK, now things are initialized enough that we can import shell JS
 | 
			
		||||
    const Format = imports.misc.format;
 | 
			
		||||
    const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
    Clutter.Actor.prototype.toString = function() {
 | 
			
		||||
        return St.describe_actor(this);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (window.global === undefined) // test environment
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    _blockMethod('Clutter.Event.get_state', 'Shell.get_event_state',
 | 
			
		||||
                 'gjs\'s handling of Clutter.ModifierType is broken. See bug 597292.');
 | 
			
		||||
    _blockMethod('Gdk.Window.get_device_position', 'global.get_pointer',
 | 
			
		||||
                 'gjs\'s handling of Gdk.ModifierType is broken. See bug 597292.');
 | 
			
		||||
 | 
			
		||||
    // Now close the back door to prevent extensions from trying to
 | 
			
		||||
    // abuse it. We can't actually delete it since
 | 
			
		||||
    // Shell.Global.prototype itself is read-only.
 | 
			
		||||
    global.set_property_mutable('imports.gi.Shell.Global.prototype', 'set_property_mutable', true);
 | 
			
		||||
    Shell.Global.prototype.set_property_mutable = undefined;
 | 
			
		||||
    Tweener.init();
 | 
			
		||||
    String.prototype.format = Format.format;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,32 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Soup = imports.gi.Soup;
 | 
			
		||||
 | 
			
		||||
const Config = imports.misc.config;
 | 
			
		||||
const FileUtils = imports.misc.fileUtils;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
 | 
			
		||||
const API_VERSION = 1;
 | 
			
		||||
 | 
			
		||||
const ExtensionState = {
 | 
			
		||||
    ENABLED: 1,
 | 
			
		||||
    DISABLED: 2,
 | 
			
		||||
    ERROR: 3,
 | 
			
		||||
    OUT_OF_DATE: 4
 | 
			
		||||
    OUT_OF_DATE: 4,
 | 
			
		||||
    DOWNLOADING: 5,
 | 
			
		||||
    INITIALIZED: 6,
 | 
			
		||||
 | 
			
		||||
    // Used as an error state for operations on unknown extensions,
 | 
			
		||||
    // should never be in a real extensionMeta object.
 | 
			
		||||
    UNINSTALLED: 99
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const ExtensionType = {
 | 
			
		||||
@@ -18,15 +34,57 @@ const ExtensionType = {
 | 
			
		||||
    PER_USER: 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const REPOSITORY_URL_BASE = 'https://extensions.gnome.org';
 | 
			
		||||
const REPOSITORY_URL_DOWNLOAD = REPOSITORY_URL_BASE + '/download-extension/%s.shell-extension.zip';
 | 
			
		||||
const REPOSITORY_URL_INFO =     REPOSITORY_URL_BASE + '/extension-info/';
 | 
			
		||||
 | 
			
		||||
const _httpSession = new Soup.SessionAsync();
 | 
			
		||||
 | 
			
		||||
// The unfortunate state of gjs, gobject-introspection and libsoup
 | 
			
		||||
// means that I have to do a hack to add a feature.
 | 
			
		||||
// See: https://bugzilla.gnome.org/show_bug.cgi?id=655189 for context.
 | 
			
		||||
 | 
			
		||||
if (Soup.Session.prototype.add_feature != null)
 | 
			
		||||
    Soup.Session.prototype.add_feature.call(_httpSession, new Soup.ProxyResolverDefault());
 | 
			
		||||
 | 
			
		||||
function _getCertFile() {
 | 
			
		||||
    let localCert = GLib.build_filenamev([global.userdatadir, 'extensions.gnome.org.crt']);
 | 
			
		||||
    if (GLib.file_test(localCert, GLib.FileTest.EXISTS))
 | 
			
		||||
        return localCert;
 | 
			
		||||
    else
 | 
			
		||||
        return Config.SHELL_SYSTEM_CA_FILE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_httpSession.ssl_ca_file = _getCertFile();
 | 
			
		||||
 | 
			
		||||
// Maps uuid -> metadata object
 | 
			
		||||
const extensionMeta = {};
 | 
			
		||||
// Maps uuid -> importer object (extension directory tree)
 | 
			
		||||
const extensions = {};
 | 
			
		||||
// Array of uuids
 | 
			
		||||
var disabledExtensions;
 | 
			
		||||
// Maps uuid -> extension state object (returned from init())
 | 
			
		||||
const extensionStateObjs = {};
 | 
			
		||||
// Contains the order that extensions were enabled in.
 | 
			
		||||
const extensionOrder = [];
 | 
			
		||||
 | 
			
		||||
// Arrays of uuids
 | 
			
		||||
var enabledExtensions;
 | 
			
		||||
// GFile for user extensions
 | 
			
		||||
var userExtensionsDir = null;
 | 
			
		||||
 | 
			
		||||
// We don't really have a class to add signals on. So, create
 | 
			
		||||
// a simple dummy object, add the signal methods, and export those
 | 
			
		||||
// publically.
 | 
			
		||||
var _signals = {};
 | 
			
		||||
Signals.addSignalMethods(_signals);
 | 
			
		||||
 | 
			
		||||
const connect = Lang.bind(_signals, _signals.connect);
 | 
			
		||||
const disconnect = Lang.bind(_signals, _signals.disconnect);
 | 
			
		||||
 | 
			
		||||
// UUID => Array of error messages
 | 
			
		||||
var errors = {};
 | 
			
		||||
 | 
			
		||||
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * versionCheck:
 | 
			
		||||
 * @required: an array of versions we're compatible with
 | 
			
		||||
@@ -57,69 +115,261 @@ function versionCheck(required, current) {
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function loadExtension(dir, enabled, type) {
 | 
			
		||||
    let info;
 | 
			
		||||
    let baseErrorString = 'While loading extension from "' + dir.get_parse_name() + '": ';
 | 
			
		||||
function installExtensionFromUUID(uuid, version_tag) {
 | 
			
		||||
    let params = { uuid: uuid,
 | 
			
		||||
                   version_tag: version_tag,
 | 
			
		||||
                   shell_version: Config.PACKAGE_VERSION,
 | 
			
		||||
                   api_version: API_VERSION.toString() };
 | 
			
		||||
 | 
			
		||||
    let metadataFile = dir.get_child('metadata.json');
 | 
			
		||||
    if (!metadataFile.query_exists(null)) {
 | 
			
		||||
        global.logError(baseErrorString + 'Missing metadata.json');
 | 
			
		||||
    let message = Soup.form_request_new_from_hash('GET', REPOSITORY_URL_INFO, params);
 | 
			
		||||
 | 
			
		||||
    _httpSession.queue_message(message,
 | 
			
		||||
                               function(session, message) {
 | 
			
		||||
                                   let info = JSON.parse(message.response_body.data);
 | 
			
		||||
                                   let dialog = new InstallExtensionDialog(uuid, version_tag, info.name);
 | 
			
		||||
                                   dialog.open(global.get_current_time());
 | 
			
		||||
                               });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function uninstallExtensionFromUUID(uuid) {
 | 
			
		||||
    let meta = extensionMeta[uuid];
 | 
			
		||||
    if (!meta)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    // Try to disable it -- if it's ERROR'd, we can't guarantee that,
 | 
			
		||||
    // but it will be removed on next reboot, and hopefully nothing
 | 
			
		||||
    // broke too much.
 | 
			
		||||
    disableExtension(uuid);
 | 
			
		||||
 | 
			
		||||
    // Don't try to uninstall system extensions
 | 
			
		||||
    if (meta.type != ExtensionType.PER_USER)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    meta.state = ExtensionState.UNINSTALLED;
 | 
			
		||||
    _signals.emit('extension-state-changed', meta);
 | 
			
		||||
 | 
			
		||||
    delete extensionMeta[uuid];
 | 
			
		||||
 | 
			
		||||
    // Importers are marked as PERMANENT, so we can't do this.
 | 
			
		||||
    // delete extensions[uuid];
 | 
			
		||||
    extensions[uuid] = undefined;
 | 
			
		||||
 | 
			
		||||
    delete extensionStateObjs[uuid];
 | 
			
		||||
    delete errors[uuid];
 | 
			
		||||
 | 
			
		||||
    FileUtils.recursivelyDeleteDir(Gio.file_new_for_path(meta.path));
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function gotExtensionZipFile(session, message, uuid) {
 | 
			
		||||
    if (message.status_code != Soup.KnownStatusCode.OK) {
 | 
			
		||||
        logExtensionError(uuid, 'downloading extension: ' + message.status_code);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let [success, metadataContents, len, etag] = metadataFile.load_contents(null);
 | 
			
		||||
    // FIXME: use a GFile mkstemp-type method once one exists
 | 
			
		||||
    let fd, tmpzip;
 | 
			
		||||
    try {
 | 
			
		||||
        [fd, tmpzip] = GLib.file_open_tmp('XXXXXX.shell-extension.zip');
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        logExtensionError(uuid, 'tempfile: ' + e.toString());
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let stream = new Gio.UnixOutputStream({ fd: fd });
 | 
			
		||||
    let dir = userExtensionsDir.get_child(uuid);
 | 
			
		||||
    Shell.write_soup_message_to_stream(stream, message);
 | 
			
		||||
    stream.close(null);
 | 
			
		||||
    let [success, pid] = GLib.spawn_async(null,
 | 
			
		||||
                                          ['unzip', '-uod', dir.get_path(), '--', tmpzip],
 | 
			
		||||
                                          null,
 | 
			
		||||
                                          GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
 | 
			
		||||
                                          null);
 | 
			
		||||
 | 
			
		||||
    if (!success) {
 | 
			
		||||
        logExtensionError(uuid, 'extract: could not extract');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function(pid, status) {
 | 
			
		||||
        GLib.spawn_close_pid(pid);
 | 
			
		||||
 | 
			
		||||
        // Add extension to 'enabled-extensions' for the user, always...
 | 
			
		||||
        let enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
 | 
			
		||||
        if (enabledExtensions.indexOf(uuid) == -1) {
 | 
			
		||||
            enabledExtensions.push(uuid);
 | 
			
		||||
            global.settings.set_strv(ENABLED_EXTENSIONS_KEY, enabledExtensions);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        loadExtension(dir, true, ExtensionType.PER_USER);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function disableExtension(uuid) {
 | 
			
		||||
    let meta = extensionMeta[uuid];
 | 
			
		||||
    if (!meta)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (meta.state != ExtensionState.ENABLED)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    let extensionState = extensionStateObjs[uuid];
 | 
			
		||||
 | 
			
		||||
    // "Rebase" the extension order by disabling and then enabling extensions
 | 
			
		||||
    // in order to help prevent conflicts.
 | 
			
		||||
 | 
			
		||||
    // Example:
 | 
			
		||||
    //   order = [A, B, C, D, E]
 | 
			
		||||
    //   user disables C
 | 
			
		||||
    //   this should: disable E, disable D, disable C, enable D, enable E
 | 
			
		||||
 | 
			
		||||
    let orderIdx = extensionOrder.indexOf(uuid);
 | 
			
		||||
    let order = extensionOrder.slice(orderIdx + 1);
 | 
			
		||||
    let orderReversed = order.slice().reverse();
 | 
			
		||||
 | 
			
		||||
    for (let i = 0; i < orderReversed.length; i++) {
 | 
			
		||||
        let uuid = orderReversed[i];
 | 
			
		||||
        try {
 | 
			
		||||
            extensionStateObjs[uuid].disable();
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            logExtensionError(uuid, e.toString());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        extensionState.disable();
 | 
			
		||||
    } catch(e) {
 | 
			
		||||
        logExtensionError(uuid, e.toString());
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (let i = 0; i < order.length; i++) {
 | 
			
		||||
        let uuid = order[i];
 | 
			
		||||
        try {
 | 
			
		||||
            extensionStateObjs[uuid].enable();
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            logExtensionError(uuid, e.toString());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    extensionOrder.splice(orderIdx, 1);
 | 
			
		||||
 | 
			
		||||
    meta.state = ExtensionState.DISABLED;
 | 
			
		||||
    _signals.emit('extension-state-changed', meta);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function enableExtension(uuid) {
 | 
			
		||||
    let meta = extensionMeta[uuid];
 | 
			
		||||
    if (!meta)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (meta.state == ExtensionState.INITIALIZED) {
 | 
			
		||||
        loadExtension(meta.dir, meta.type, true);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (meta.state != ExtensionState.DISABLED)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    let extensionState = extensionStateObjs[uuid];
 | 
			
		||||
 | 
			
		||||
    extensionOrder.push(uuid);
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        extensionState.enable();
 | 
			
		||||
    } catch(e) {
 | 
			
		||||
        logExtensionError(uuid, e.toString());
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    meta.state = ExtensionState.ENABLED;
 | 
			
		||||
    _signals.emit('extension-state-changed', meta);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function logExtensionError(uuid, message, state) {
 | 
			
		||||
    if (!errors[uuid]) errors[uuid] = [];
 | 
			
		||||
    errors[uuid].push(message);
 | 
			
		||||
    global.logError('Extension "%s" had error: %s'.format(uuid, message));
 | 
			
		||||
    state = state || ExtensionState.ERROR;
 | 
			
		||||
    _signals.emit('extension-state-changed', { uuid: uuid,
 | 
			
		||||
                                               error: message,
 | 
			
		||||
                                               state: state });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function loadExtension(dir, type, enabled) {
 | 
			
		||||
    let info;
 | 
			
		||||
    let uuid = dir.get_basename();
 | 
			
		||||
 | 
			
		||||
    let metadataFile = dir.get_child('metadata.json');
 | 
			
		||||
    if (!metadataFile.query_exists(null)) {
 | 
			
		||||
        logExtensionError(uuid, 'Missing metadata.json');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let metadataContents;
 | 
			
		||||
    try {
 | 
			
		||||
        metadataContents = Shell.get_file_contents_utf8_sync(metadataFile.get_path());
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        logExtensionError(uuid, 'Failed to load metadata.json: ' + e);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    let meta;
 | 
			
		||||
    try {
 | 
			
		||||
        meta = JSON.parse(metadataContents);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        global.logError(baseErrorString + 'Failed to parse metadata.json: ' + e);
 | 
			
		||||
        logExtensionError(uuid, 'Failed to parse metadata.json: ' + e);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let requiredProperties = ['uuid', 'name', 'description', 'shell-version'];
 | 
			
		||||
    for (let i = 0; i < requiredProperties.length; i++) {
 | 
			
		||||
        let prop = requiredProperties[i];
 | 
			
		||||
        if (!meta[prop]) {
 | 
			
		||||
            global.logError(baseErrorString + 'missing "' + prop + '" property in metadata.json');
 | 
			
		||||
            logExtensionError(uuid, 'missing "' + prop + '" property in metadata.json');
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (extensions[meta.uuid] != undefined) {
 | 
			
		||||
        global.logError(baseErrorString + "extension already loaded");
 | 
			
		||||
    if (extensions[uuid] != undefined) {
 | 
			
		||||
        logExtensionError(uuid, 'extension already loaded');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Encourage people to add this
 | 
			
		||||
    if (!meta['url']) {
 | 
			
		||||
        global.log(baseErrorString + 'Warning: Missing "url" property in metadata.json');
 | 
			
		||||
        global.log('Warning: Missing "url" property in metadata.json');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let base = dir.get_basename();
 | 
			
		||||
    if (base != meta.uuid) {
 | 
			
		||||
        global.logError(baseErrorString + 'uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + base + '"');
 | 
			
		||||
    if (uuid != meta.uuid) {
 | 
			
		||||
        logExtensionError(uuid, 'uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    extensionMeta[uuid] = meta;
 | 
			
		||||
    meta.type = type;
 | 
			
		||||
    meta.dir = dir;
 | 
			
		||||
    meta.path = dir.get_path();
 | 
			
		||||
    meta.error = '';
 | 
			
		||||
 | 
			
		||||
    // Default to error, we set success as the last step
 | 
			
		||||
    meta.state = ExtensionState.ERROR;
 | 
			
		||||
 | 
			
		||||
    if (!versionCheck(meta['shell-version'], Config.PACKAGE_VERSION) ||
 | 
			
		||||
        (meta['js-version'] && !versionCheck(meta['js-version'], Config.GJS_VERSION))) {
 | 
			
		||||
        global.logError(baseErrorString + 'extension is not compatible with current GNOME Shell and/or GJS version');
 | 
			
		||||
        logExtensionError(uuid, 'extension is not compatible with current GNOME Shell and/or GJS version', ExtensionState.OUT_OF_DATE);
 | 
			
		||||
        meta.state = ExtensionState.OUT_OF_DATE;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    extensionMeta[meta.uuid] = meta;
 | 
			
		||||
    extensionMeta[meta.uuid].type = type;
 | 
			
		||||
    extensionMeta[meta.uuid].path = dir.get_path();
 | 
			
		||||
    if (!enabled) {
 | 
			
		||||
        extensionMeta[meta.uuid].state = ExtensionState.DISABLED;
 | 
			
		||||
        meta.state = ExtensionState.INITIALIZED;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Default to error, we set success as the last step
 | 
			
		||||
    extensionMeta[meta.uuid].state = ExtensionState.ERROR;
 | 
			
		||||
 | 
			
		||||
    let extensionJs = dir.get_child('extension.js');
 | 
			
		||||
    if (!extensionJs.query_exists(null)) {
 | 
			
		||||
        global.logError(baseErrorString + 'Missing extension.js');
 | 
			
		||||
        logExtensionError(uuid, 'Missing extension.js');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    let stylesheetPath = null;
 | 
			
		||||
@@ -130,66 +380,118 @@ function loadExtension(dir, enabled, type) {
 | 
			
		||||
        try {
 | 
			
		||||
            theme.load_stylesheet(stylesheetFile.get_path());
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            global.logError(baseErrorString + 'Stylesheet parse error: ' + e);
 | 
			
		||||
            logExtensionError(uuid, 'Stylesheet parse error: ' + e);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let extensionModule;
 | 
			
		||||
    let extensionState = null;
 | 
			
		||||
    try {
 | 
			
		||||
        global.add_extension_importer('imports.ui.extensionSystem.extensions', meta.uuid, dir.get_path());
 | 
			
		||||
        extensionModule = extensions[meta.uuid].extension;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        if (stylesheetPath != null)
 | 
			
		||||
            theme.unload_stylesheet(stylesheetPath);
 | 
			
		||||
        global.logError(baseErrorString + e);
 | 
			
		||||
        logExtensionError(uuid, e);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (!extensionModule.main) {
 | 
			
		||||
        global.logError(baseErrorString + 'missing \'main\' function');
 | 
			
		||||
 | 
			
		||||
    if (!extensionModule.init) {
 | 
			
		||||
        logExtensionError(uuid, 'missing \'init\' function');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        extensionModule.main(meta);
 | 
			
		||||
        extensionState = extensionModule.init(meta);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        if (stylesheetPath != null)
 | 
			
		||||
            theme.unload_stylesheet(stylesheetPath);
 | 
			
		||||
        global.logError(baseErrorString + 'Failed to evaluate main function:' + e);
 | 
			
		||||
        logExtensionError(uuid, 'Failed to evaluate init function:' + e);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    extensionMeta[meta.uuid].state = ExtensionState.ENABLED;
 | 
			
		||||
 | 
			
		||||
    if (!extensionState)
 | 
			
		||||
        extensionState = extensionModule;
 | 
			
		||||
    extensionStateObjs[uuid] = extensionState;
 | 
			
		||||
 | 
			
		||||
    if (!extensionState.enable) {
 | 
			
		||||
        logExtensionError(uuid, 'missing \'enable\' function');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (!extensionState.disable) {
 | 
			
		||||
        logExtensionError(uuid, 'missing \'disable\' function');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    meta.state = ExtensionState.DISABLED;
 | 
			
		||||
 | 
			
		||||
    enableExtension(uuid);
 | 
			
		||||
 | 
			
		||||
    _signals.emit('extension-loaded', meta.uuid);
 | 
			
		||||
    _signals.emit('extension-state-changed', meta);
 | 
			
		||||
    global.log('Loaded extension ' + meta.uuid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function onEnabledExtensionsChanged() {
 | 
			
		||||
    let newEnabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
 | 
			
		||||
 | 
			
		||||
    // Find and enable all the newly enabled extensions: UUIDs found in the
 | 
			
		||||
    // new setting, but not in the old one.
 | 
			
		||||
    newEnabledExtensions.filter(function(uuid) {
 | 
			
		||||
        return enabledExtensions.indexOf(uuid) == -1;
 | 
			
		||||
    }).forEach(function(uuid) {
 | 
			
		||||
        enableExtension(uuid);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Find and disable all the newly disabled extensions: UUIDs found in the
 | 
			
		||||
    // old setting, but not in the new one.
 | 
			
		||||
    enabledExtensions.filter(function(item) {
 | 
			
		||||
        return newEnabledExtensions.indexOf(item) == -1;
 | 
			
		||||
    }).forEach(function(uuid) {
 | 
			
		||||
        disableExtension(uuid);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    enabledExtensions = newEnabledExtensions;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function init() {
 | 
			
		||||
    let userExtensionsPath = GLib.build_filenamev([global.userdatadir, 'extensions']);
 | 
			
		||||
    userExtensionsDir = Gio.file_new_for_path(userExtensionsPath);
 | 
			
		||||
    try {
 | 
			
		||||
        userExtensionsDir.make_directory_with_parents(null);
 | 
			
		||||
        if (!userExtensionsDir.query_exists(null))
 | 
			
		||||
            userExtensionsDir.make_directory_with_parents(null);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        global.logError('' + e);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    disabledExtensions = global.settings.get_strv('disabled-extensions', -1);
 | 
			
		||||
    global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
 | 
			
		||||
    enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _loadExtensionsIn(dir, type) {
 | 
			
		||||
    let fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
 | 
			
		||||
    let fileEnum;
 | 
			
		||||
    let file, info;
 | 
			
		||||
    try {
 | 
			
		||||
        fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        global.logError('' + e);
 | 
			
		||||
       return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while ((info = fileEnum.next_file(null)) != null) {
 | 
			
		||||
        let fileType = info.get_file_type();
 | 
			
		||||
        if (fileType != Gio.FileType.DIRECTORY)
 | 
			
		||||
            continue;
 | 
			
		||||
        let name = info.get_name();
 | 
			
		||||
        let enabled = disabledExtensions.indexOf(name) < 0;
 | 
			
		||||
        let child = dir.get_child(name);
 | 
			
		||||
        loadExtension(child, enabled, type);
 | 
			
		||||
        let enabled = enabledExtensions.indexOf(name) != -1;
 | 
			
		||||
        loadExtension(child, type, enabled);
 | 
			
		||||
    }
 | 
			
		||||
    fileEnum.close(null);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function loadExtensions() {
 | 
			
		||||
    _loadExtensionsIn(userExtensionsDir, ExtensionType.PER_USER);
 | 
			
		||||
    let systemDataDirs = GLib.get_system_data_dirs();
 | 
			
		||||
    for (let i = 0; i < systemDataDirs.length; i++) {
 | 
			
		||||
        let dirPath = systemDataDirs[i] + '/gnome-shell/extensions';
 | 
			
		||||
@@ -197,4 +499,72 @@ function loadExtensions() {
 | 
			
		||||
        if (dir.query_exists(null))
 | 
			
		||||
            _loadExtensionsIn(dir, ExtensionType.SYSTEM);
 | 
			
		||||
    }
 | 
			
		||||
    _loadExtensionsIn(userExtensionsDir, ExtensionType.PER_USER);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const InstallExtensionDialog = new Lang.Class({
 | 
			
		||||
    Name: 'InstallExtensionDialog',
 | 
			
		||||
    Extends: ModalDialog.ModalDialog,
 | 
			
		||||
 | 
			
		||||
    _init: function(uuid, version_tag, name) {
 | 
			
		||||
        this.parent({ styleClass: 'extension-dialog' });
 | 
			
		||||
 | 
			
		||||
        this._uuid = uuid;
 | 
			
		||||
        this._version_tag = version_tag;
 | 
			
		||||
        this._name = name;
 | 
			
		||||
 | 
			
		||||
        this.setButtons([{ label: _("Cancel"),
 | 
			
		||||
                           action: Lang.bind(this, this._onCancelButtonPressed),
 | 
			
		||||
                           key:    Clutter.Escape
 | 
			
		||||
                         },
 | 
			
		||||
                         { label:  _("Install"),
 | 
			
		||||
                           action: Lang.bind(this, this._onInstallButtonPressed)
 | 
			
		||||
                         }]);
 | 
			
		||||
 | 
			
		||||
        let message = _("Download and install '%s' from extensions.gnome.org?").format(name);
 | 
			
		||||
 | 
			
		||||
        this._descriptionLabel = new St.Label({ text: message });
 | 
			
		||||
 | 
			
		||||
        this.contentLayout.add(this._descriptionLabel,
 | 
			
		||||
                               { y_fill:  true,
 | 
			
		||||
                                 y_align: St.Align.START });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onCancelButtonPressed: function(button, event) {
 | 
			
		||||
        this.close(global.get_current_time());
 | 
			
		||||
 | 
			
		||||
        // Even though the extension is already "uninstalled", send through
 | 
			
		||||
        // a state-changed signal for any users who want to know if the install
 | 
			
		||||
        // went through correctly -- using proper async DBus would block more
 | 
			
		||||
        // traditional clients like the plugin
 | 
			
		||||
        let meta = { uuid: this._uuid,
 | 
			
		||||
                     state: ExtensionState.UNINSTALLED,
 | 
			
		||||
                     error: '' };
 | 
			
		||||
 | 
			
		||||
        _signals.emit('extension-state-changed', meta);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onInstallButtonPressed: function(button, event) {
 | 
			
		||||
        let meta = { uuid: this._uuid,
 | 
			
		||||
                     state: ExtensionState.DOWNLOADING,
 | 
			
		||||
                     error: '' };
 | 
			
		||||
 | 
			
		||||
        extensionMeta[this._uuid] = meta;
 | 
			
		||||
 | 
			
		||||
        _signals.emit('extension-state-changed', meta);
 | 
			
		||||
 | 
			
		||||
        let params = { version_tag: this._version_tag,
 | 
			
		||||
                       shell_version: Config.PACKAGE_VERSION,
 | 
			
		||||
                       api_version: API_VERSION.toString() };
 | 
			
		||||
 | 
			
		||||
        let url = REPOSITORY_URL_DOWNLOAD.format(this._uuid);
 | 
			
		||||
        let message = Soup.form_request_new_from_hash('GET', url, params);
 | 
			
		||||
 | 
			
		||||
        _httpSession.queue_message(message,
 | 
			
		||||
                                   Lang.bind(this, function(session, message) {
 | 
			
		||||
                                       gotExtensionZipFile(session, message, this._uuid);
 | 
			
		||||
                                   }));
 | 
			
		||||
 | 
			
		||||
        this.close(global.get_current_time());
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
@@ -10,11 +10,9 @@ const Params = imports.misc.params;
 | 
			
		||||
const ICON_SIZE = 48;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function BaseIcon(label, createIcon) {
 | 
			
		||||
    this._init(label, createIcon);
 | 
			
		||||
}
 | 
			
		||||
const BaseIcon = new Lang.Class({
 | 
			
		||||
    Name: 'BaseIcon',
 | 
			
		||||
 | 
			
		||||
BaseIcon.prototype = {
 | 
			
		||||
    _init : function(label, params) {
 | 
			
		||||
        params = Params.parse(params, { createIcon: null,
 | 
			
		||||
                                        setSizeManually: false,
 | 
			
		||||
@@ -42,18 +40,17 @@ BaseIcon.prototype = {
 | 
			
		||||
        box.add_actor(this._iconBin);
 | 
			
		||||
 | 
			
		||||
        if (params.showLabel) {
 | 
			
		||||
            this._name = new St.Label({ text: label });
 | 
			
		||||
            box.add_actor(this._name);
 | 
			
		||||
            this.label = new St.Label({ text: label });
 | 
			
		||||
            box.add_actor(this.label);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._name = null;
 | 
			
		||||
            this.label = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (params.createIcon)
 | 
			
		||||
            this.createIcon = params.createIcon;
 | 
			
		||||
        this._setSizeManually = params.setSizeManually;
 | 
			
		||||
 | 
			
		||||
        this.icon = this.createIcon(this.iconSize);
 | 
			
		||||
        this._iconBin.set_child(this.icon);
 | 
			
		||||
        this.icon = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _allocate: function(actor, box, flags) {
 | 
			
		||||
@@ -68,8 +65,8 @@ BaseIcon.prototype = {
 | 
			
		||||
 | 
			
		||||
        let childBox = new Clutter.ActorBox();
 | 
			
		||||
 | 
			
		||||
        if (this._name) {
 | 
			
		||||
            let [labelMinHeight, labelNatHeight] = this._name.get_preferred_height(-1);
 | 
			
		||||
        if (this.label) {
 | 
			
		||||
            let [labelMinHeight, labelNatHeight] = this.label.get_preferred_height(-1);
 | 
			
		||||
            preferredHeight += this._spacing + labelNatHeight;
 | 
			
		||||
 | 
			
		||||
            let labelHeight = availHeight >= preferredHeight ? labelNatHeight
 | 
			
		||||
@@ -80,7 +77,7 @@ BaseIcon.prototype = {
 | 
			
		||||
            childBox.x2 = availWidth;
 | 
			
		||||
            childBox.y1 = iconSize + this._spacing;
 | 
			
		||||
            childBox.y2 = childBox.y1 + labelHeight;
 | 
			
		||||
            this._name.allocate(childBox, flags);
 | 
			
		||||
            this.label.allocate(childBox, flags);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        childBox.x1 = Math.floor((availWidth - iconNatWidth) / 2);
 | 
			
		||||
@@ -99,8 +96,8 @@ BaseIcon.prototype = {
 | 
			
		||||
        alloc.min_size = iconMinHeight;
 | 
			
		||||
        alloc.natural_size = iconNatHeight;
 | 
			
		||||
 | 
			
		||||
        if (this._name) {
 | 
			
		||||
            let [labelMinHeight, labelNatHeight] = this._name.get_preferred_height(forWidth);
 | 
			
		||||
        if (this.label) {
 | 
			
		||||
            let [labelMinHeight, labelNatHeight] = this.label.get_preferred_height(forWidth);
 | 
			
		||||
            alloc.min_size += this._spacing + labelMinHeight;
 | 
			
		||||
            alloc.natural_size += this._spacing + labelNatHeight;
 | 
			
		||||
        }
 | 
			
		||||
@@ -116,16 +113,23 @@ BaseIcon.prototype = {
 | 
			
		||||
        if (!this._setSizeManually)
 | 
			
		||||
            throw new Error('setSizeManually has to be set to use setIconsize');
 | 
			
		||||
 | 
			
		||||
        this._setIconSize(size);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setIconSize: function(size) {
 | 
			
		||||
        if (size == this.iconSize)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.icon.destroy();
 | 
			
		||||
        this._createIconTexture(size);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createIconTexture: function(size) {
 | 
			
		||||
        if (this.icon)
 | 
			
		||||
            this.icon.destroy();
 | 
			
		||||
        this.iconSize = size;
 | 
			
		||||
        this.icon = this.createIcon(this.iconSize);
 | 
			
		||||
 | 
			
		||||
        // The icon returned by createIcon() might actually be smaller than
 | 
			
		||||
        // the requested icon size (for instance StTextureCache does this
 | 
			
		||||
        // for fallback icons), so set the size explicitly.
 | 
			
		||||
        this.icon.set_size(this.iconSize, this.iconSize);
 | 
			
		||||
 | 
			
		||||
        this._iconBin.child = this.icon;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -133,20 +137,21 @@ BaseIcon.prototype = {
 | 
			
		||||
        let node = this.actor.get_theme_node();
 | 
			
		||||
        this._spacing = node.get_length('spacing');
 | 
			
		||||
 | 
			
		||||
        if (this._setSizeManually)
 | 
			
		||||
            return;
 | 
			
		||||
        let size;
 | 
			
		||||
        if (this._setSizeManually) {
 | 
			
		||||
            size = this.iconSize;
 | 
			
		||||
        } else {
 | 
			
		||||
            let [found, len] = node.lookup_length('icon-size', false);
 | 
			
		||||
            size = found ? len : ICON_SIZE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let len = node.get_length('icon-size');
 | 
			
		||||
        if (len > 0)
 | 
			
		||||
            this._setIconSize(len);
 | 
			
		||||
        this._createIconTexture(size);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function IconGrid(params) {
 | 
			
		||||
    this._init(params);
 | 
			
		||||
}
 | 
			
		||||
const IconGrid = new Lang.Class({
 | 
			
		||||
    Name: 'IconGrid',
 | 
			
		||||
 | 
			
		||||
IconGrid.prototype = {
 | 
			
		||||
    _init: function(params) {
 | 
			
		||||
        params = Params.parse(params, { rowLimit: null,
 | 
			
		||||
                                        columnLimit: null,
 | 
			
		||||
@@ -272,8 +277,11 @@ IconGrid.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    childrenInRow: function(rowWidth) {
 | 
			
		||||
        return this._computeLayout(rowWidth)[0];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _computeLayout: function (forWidth) {
 | 
			
		||||
        let children = this._grid.get_children();
 | 
			
		||||
        let nColumns = 0;
 | 
			
		||||
        let usedWidth = 0;
 | 
			
		||||
        while ((this._colLimit == null || nColumns < this._colLimit) &&
 | 
			
		||||
@@ -312,4 +320,4 @@ IconGrid.prototype = {
 | 
			
		||||
    visibleItemsCount: function() {
 | 
			
		||||
        return this._grid.get_children().length - this._grid.get_n_skip_paint();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										563
									
								
								js/ui/keyboard.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,563 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Caribou = imports.gi.Caribou;
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const DBus = imports.dbus;
 | 
			
		||||
const Gdk = imports.gi.Gdk;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const BoxPointer = imports.ui.boxpointer;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
 | 
			
		||||
const KEYBOARD_SCHEMA = 'org.gnome.shell.keyboard';
 | 
			
		||||
const KEYBOARD_TYPE = 'keyboard-type';
 | 
			
		||||
 | 
			
		||||
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
 | 
			
		||||
const SHOW_KEYBOARD = 'screen-keyboard-enabled';
 | 
			
		||||
 | 
			
		||||
// Key constants taken from Antler
 | 
			
		||||
// FIXME: ought to be moved into libcaribou
 | 
			
		||||
const PRETTY_KEYS = {
 | 
			
		||||
    'BackSpace': '\u232b',
 | 
			
		||||
    'space': ' ',
 | 
			
		||||
    'Return': '\u23ce',
 | 
			
		||||
    'Caribou_Prefs': '\u2328',
 | 
			
		||||
    'Caribou_ShiftUp': '\u2b06',
 | 
			
		||||
    'Caribou_ShiftDown': '\u2b07',
 | 
			
		||||
    'Caribou_Emoticons': '\u263a',
 | 
			
		||||
    'Caribou_Symbols': '123',
 | 
			
		||||
    'Caribou_Symbols_More': '{#*',
 | 
			
		||||
    'Caribou_Alpha': 'Abc',
 | 
			
		||||
    'Tab': 'Tab',
 | 
			
		||||
    'Escape': 'Esc',
 | 
			
		||||
    'Control_L': 'Ctrl',
 | 
			
		||||
    'Alt_L': 'Alt'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const CaribouKeyboardIface = <interface name='org.gnome.Caribou.Keyboard'>
 | 
			
		||||
<method name='Show'>
 | 
			
		||||
    <arg type='u' direction='in' />
 | 
			
		||||
</method>
 | 
			
		||||
<method name='Hide'>
 | 
			
		||||
    <arg type='u' direction='in' />
 | 
			
		||||
</method>
 | 
			
		||||
<method name='SetCursorLocation'>
 | 
			
		||||
    <arg type='i' direction='in' />
 | 
			
		||||
    <arg type='i' direction='in' />
 | 
			
		||||
    <arg type='i' direction='in' />
 | 
			
		||||
    <arg type='i' direction='in' />
 | 
			
		||||
</method>
 | 
			
		||||
<method name='SetEntryLocation'>
 | 
			
		||||
    <arg type='i' direction='in' />
 | 
			
		||||
    <arg type='i' direction='in' />
 | 
			
		||||
    <arg type='i' direction='in' />
 | 
			
		||||
    <arg type='i' direction='in' />
 | 
			
		||||
</method>
 | 
			
		||||
<property name='Name' access='read' type='s' />
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const Key = new Lang.Class({
 | 
			
		||||
    Name: 'Key',
 | 
			
		||||
 | 
			
		||||
    _init : function(key) {
 | 
			
		||||
        this._key = key;
 | 
			
		||||
 | 
			
		||||
        this.actor = this._makeKey();
 | 
			
		||||
 | 
			
		||||
        this._extended_keys = this._key.get_extended_keys();
 | 
			
		||||
        this._extended_keyboard = null;
 | 
			
		||||
 | 
			
		||||
        if (this._key.name == 'Control_L' || this._key.name == 'Alt_L')
 | 
			
		||||
            this._key.latch = true;
 | 
			
		||||
 | 
			
		||||
        this._key.connect('key-pressed', Lang.bind(this, function ()
 | 
			
		||||
                                                   { this.actor.checked = true }));
 | 
			
		||||
        this._key.connect('key-released', Lang.bind(this, function ()
 | 
			
		||||
                                                    { this.actor.checked = false; }));
 | 
			
		||||
 | 
			
		||||
        if (this._extended_keys.length > 0) {
 | 
			
		||||
            this._grabbed = false;
 | 
			
		||||
            this._eventCaptureId = 0;
 | 
			
		||||
            this._key.connect('notify::show-subkeys', Lang.bind(this, this._onShowSubkeysChanged));
 | 
			
		||||
            this._boxPointer = new BoxPointer.BoxPointer(St.Side.BOTTOM,
 | 
			
		||||
                                                         { x_fill: true,
 | 
			
		||||
                                                           y_fill: true,
 | 
			
		||||
                                                           x_align: St.Align.START });
 | 
			
		||||
            // Adds style to existing keyboard style to avoid repetition
 | 
			
		||||
            this._boxPointer.actor.add_style_class_name('keyboard-subkeys');
 | 
			
		||||
            this._getExtendedKeys();
 | 
			
		||||
            this.actor._extended_keys = this._extended_keyboard;
 | 
			
		||||
            this._boxPointer.actor.hide();
 | 
			
		||||
            Main.layoutManager.addChrome(this._boxPointer.actor, { visibleInFullscreen: true });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _makeKey: function () {
 | 
			
		||||
        let label = this._key.name;
 | 
			
		||||
 | 
			
		||||
        if (label.length > 1) {
 | 
			
		||||
            let pretty = PRETTY_KEYS[label];
 | 
			
		||||
            if (pretty)
 | 
			
		||||
                label = pretty;
 | 
			
		||||
            else
 | 
			
		||||
                label = this._getUnichar(this._key);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        label = GLib.markup_escape_text(label, -1);
 | 
			
		||||
        let button = new St.Button ({ label: label,
 | 
			
		||||
                                      style_class: 'keyboard-key' });
 | 
			
		||||
 | 
			
		||||
        button.key_width = this._key.width;
 | 
			
		||||
        button.connect('button-press-event', Lang.bind(this, function () { this._key.press(); }));
 | 
			
		||||
        button.connect('button-release-event', Lang.bind(this, function () { this._key.release(); }));
 | 
			
		||||
 | 
			
		||||
        return button;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getUnichar: function(key) {
 | 
			
		||||
        let keyval = key.keyval;
 | 
			
		||||
        let unichar = Gdk.keyval_to_unicode(keyval);
 | 
			
		||||
        if (unichar) {
 | 
			
		||||
            return String.fromCharCode(unichar);
 | 
			
		||||
        } else {
 | 
			
		||||
            return key.name;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getExtendedKeys: function () {
 | 
			
		||||
        this._extended_keyboard = new St.BoxLayout({ style_class: 'keyboard-layout',
 | 
			
		||||
                                                     vertical: false });
 | 
			
		||||
        for (let i = 0; i < this._extended_keys.length; ++i) {
 | 
			
		||||
            let extended_key = this._extended_keys[i];
 | 
			
		||||
            let label = this._getUnichar(extended_key);
 | 
			
		||||
            let key = new St.Button({ label: label, style_class: 'keyboard-key' });
 | 
			
		||||
            key.extended_key = extended_key;
 | 
			
		||||
            key.connect('button-press-event', Lang.bind(this, function () { extended_key.press(); }));
 | 
			
		||||
            key.connect('button-release-event', Lang.bind(this, function () { extended_key.release(); }));
 | 
			
		||||
            this._extended_keyboard.add(key);
 | 
			
		||||
        }
 | 
			
		||||
        this._boxPointer.bin.add_actor(this._extended_keyboard);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onEventCapture: function (actor, event) {
 | 
			
		||||
        let source = event.get_source();
 | 
			
		||||
        let type = event.type();
 | 
			
		||||
 | 
			
		||||
        if ((type == Clutter.EventType.BUTTON_PRESS ||
 | 
			
		||||
             type == Clutter.EventType.BUTTON_RELEASE) &&
 | 
			
		||||
            this._extended_keyboard.contains(source)) {
 | 
			
		||||
            source.extended_key.press();
 | 
			
		||||
            source.extended_key.release();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (type == Clutter.EventType.BUTTON_PRESS) {
 | 
			
		||||
            this._boxPointer.actor.hide();
 | 
			
		||||
            this._ungrab();
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _ungrab: function () {
 | 
			
		||||
        global.stage.disconnect(this._eventCaptureId);
 | 
			
		||||
        this._eventCaptureId = 0;
 | 
			
		||||
        this._grabbed = false;
 | 
			
		||||
        Main.popModal(this.actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onShowSubkeysChanged: function () {
 | 
			
		||||
        if (this._key.show_subkeys) {
 | 
			
		||||
            this.actor.fake_release();
 | 
			
		||||
            this._boxPointer.actor.raise_top();
 | 
			
		||||
            this._boxPointer.setPosition(this.actor, 0.5);
 | 
			
		||||
            this._boxPointer.show(true);
 | 
			
		||||
            this.actor.set_hover(false);
 | 
			
		||||
            if (!this._grabbed) {
 | 
			
		||||
                 Main.pushModal(this.actor);
 | 
			
		||||
                 this._eventCaptureId = global.stage.connect('captured-event', Lang.bind(this, this._onEventCapture));
 | 
			
		||||
                 this._grabbed = true;
 | 
			
		||||
            }
 | 
			
		||||
            this._key.release();
 | 
			
		||||
        } else {
 | 
			
		||||
            if (this._grabbed)
 | 
			
		||||
                this._ungrab();
 | 
			
		||||
            this._boxPointer.hide(true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const Keyboard = new Lang.Class({
 | 
			
		||||
    // HACK: we can't set Name, because it collides with Name dbus property
 | 
			
		||||
    // Name: 'Keyboard',
 | 
			
		||||
 | 
			
		||||
    _init: function () {
 | 
			
		||||
        this._impl = Gio.DBusExportedObject.wrapJSObject(CaribouKeyboardIface, this);
 | 
			
		||||
        this._impl.export(Gio.DBus.session, '/org/gnome/Caribou/Keyboard');
 | 
			
		||||
 | 
			
		||||
        this.actor = null;
 | 
			
		||||
 | 
			
		||||
        this._timestamp = global.get_current_time();
 | 
			
		||||
        Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._redraw));
 | 
			
		||||
 | 
			
		||||
        this._keyboardSettings = new Gio.Settings({ schema: KEYBOARD_SCHEMA });
 | 
			
		||||
        this._keyboardSettings.connect('changed', Lang.bind(this, this._settingsChanged));
 | 
			
		||||
        this._a11yApplicationsSettings = new Gio.Settings({ schema: A11Y_APPLICATIONS_SCHEMA });
 | 
			
		||||
        this._a11yApplicationsSettings.connect('changed', Lang.bind(this, this._settingsChanged));
 | 
			
		||||
        this._settingsChanged();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    init: function () {
 | 
			
		||||
        this._redraw();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _settingsChanged: function (settings, key) {
 | 
			
		||||
        this._enableKeyboard = this._a11yApplicationsSettings.get_boolean(SHOW_KEYBOARD);
 | 
			
		||||
        if (!this._enableKeyboard && !this._keyboard)
 | 
			
		||||
            return;
 | 
			
		||||
        if (this._enableKeyboard && this._keyboard &&
 | 
			
		||||
            this._keyboard.keyboard_type == this._keyboardSettings.get_string(KEYBOARD_TYPE))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (this._keyboard)
 | 
			
		||||
            this._destroyKeyboard();
 | 
			
		||||
 | 
			
		||||
        if (this._enableKeyboard) {
 | 
			
		||||
            // If we've been called because the setting actually just
 | 
			
		||||
            // changed to true (as opposed to being called from
 | 
			
		||||
            // this._init()), then we want to pop up the keyboard.
 | 
			
		||||
            let showKeyboard = (settings != null);
 | 
			
		||||
 | 
			
		||||
            // However, caribou-gtk-module or this._onKeyFocusChanged
 | 
			
		||||
            // will probably immediately tell us to hide it, so we
 | 
			
		||||
            // have to fake things out so we'll ignore that request.
 | 
			
		||||
            if (showKeyboard)
 | 
			
		||||
                this._timestamp = global.display.get_current_time_roundtrip() + 1;
 | 
			
		||||
            this._setupKeyboard(showKeyboard);
 | 
			
		||||
        } else
 | 
			
		||||
            Main.layoutManager.hideKeyboard(true);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _destroyKeyboard: function() {
 | 
			
		||||
        if (this._keyboardNotifyId)
 | 
			
		||||
            this._keyboard.disconnect(this._keyboardNotifyId);
 | 
			
		||||
        if (this._focusNotifyId)
 | 
			
		||||
            global.stage.disconnect(this._focusNotifyId);
 | 
			
		||||
        this._keyboard = null;
 | 
			
		||||
        this.actor.destroy();
 | 
			
		||||
        this.actor = null;
 | 
			
		||||
 | 
			
		||||
        this._destroySource();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setupKeyboard: function(show) {
 | 
			
		||||
        this.actor = new St.BoxLayout({ name: 'keyboard', vertical: true, reactive: true });
 | 
			
		||||
        Main.layoutManager.keyboardBox.add_actor(this.actor);
 | 
			
		||||
        Main.layoutManager.trackChrome(this.actor);
 | 
			
		||||
 | 
			
		||||
        this._keyboard = new Caribou.KeyboardModel({ keyboard_type: this._keyboardSettings.get_string(KEYBOARD_TYPE) });
 | 
			
		||||
        this._groups = {};
 | 
			
		||||
        this._current_page = null;
 | 
			
		||||
 | 
			
		||||
        // Initialize keyboard key measurements
 | 
			
		||||
        this._numOfHorizKeys = 0;
 | 
			
		||||
        this._numOfVertKeys = 0;
 | 
			
		||||
 | 
			
		||||
        this._addKeys();
 | 
			
		||||
 | 
			
		||||
        this._keyboardNotifyId = this._keyboard.connect('notify::active-group', Lang.bind(this, this._onGroupChanged));
 | 
			
		||||
        this._focusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
 | 
			
		||||
 | 
			
		||||
        if (show)
 | 
			
		||||
            this.show();
 | 
			
		||||
        else
 | 
			
		||||
            this._createSource();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeyFocusChanged: function () {
 | 
			
		||||
        let focus = global.stage.key_focus;
 | 
			
		||||
 | 
			
		||||
        // Showing an extended key popup and clicking a key from the extended keys
 | 
			
		||||
        // will grab focus, but ignore that
 | 
			
		||||
        if (focus && (focus._extended_keys || (focus._key && focus._key.extended_key)))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let time = global.get_current_time();
 | 
			
		||||
        if (focus instanceof Clutter.Text)
 | 
			
		||||
            this.Show(time);
 | 
			
		||||
        else
 | 
			
		||||
            this.Hide(time);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _addKeys: function () {
 | 
			
		||||
        let groups = this._keyboard.get_groups();
 | 
			
		||||
        for (let i = 0; i < groups.length; ++i) {
 | 
			
		||||
             let gname = groups[i];
 | 
			
		||||
             let group = this._keyboard.get_group(gname);
 | 
			
		||||
             group.connect('notify::active-level', Lang.bind(this, this._onLevelChanged));
 | 
			
		||||
             let layers = {};
 | 
			
		||||
             let levels = group.get_levels();
 | 
			
		||||
             for (let j = 0; j < levels.length; ++j) {
 | 
			
		||||
                 let lname = levels[j];
 | 
			
		||||
                 let level = group.get_level(lname);
 | 
			
		||||
                 let layout = new St.BoxLayout({ style_class: 'keyboard-layout',
 | 
			
		||||
                                                 vertical: true });
 | 
			
		||||
                 this._loadRows(level, layout);
 | 
			
		||||
                 layers[lname] = layout;
 | 
			
		||||
                 this.actor.add(layout, { x_fill: false });
 | 
			
		||||
 | 
			
		||||
                 layout.hide();
 | 
			
		||||
             }
 | 
			
		||||
             this._groups[gname] = layers;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._setActiveLayer();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getTrayIcon: function () {
 | 
			
		||||
        let trayButton = new St.Button ({ label: _("tray"),
 | 
			
		||||
                                          style_class: 'keyboard-key' });
 | 
			
		||||
        trayButton.key_width = 1;
 | 
			
		||||
        trayButton.connect('button-press-event', Lang.bind(this, function () {
 | 
			
		||||
            Main.messageTray.toggle();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        Main.overview.connect('showing', Lang.bind(this, function () {
 | 
			
		||||
            trayButton.reactive = false;
 | 
			
		||||
            trayButton.add_style_pseudo_class('grayed');
 | 
			
		||||
        }));
 | 
			
		||||
        Main.overview.connect('hiding', Lang.bind(this, function () {
 | 
			
		||||
            trayButton.reactive = true;
 | 
			
		||||
            trayButton.remove_style_pseudo_class('grayed');
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return trayButton;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _addRows : function (keys, layout) {
 | 
			
		||||
        let keyboard_row = new St.BoxLayout();
 | 
			
		||||
        for (let i = 0; i < keys.length; ++i) {
 | 
			
		||||
            let children = keys[i].get_children();
 | 
			
		||||
            let right_box = new St.BoxLayout({ style_class: 'keyboard-row' });
 | 
			
		||||
            let left_box = new St.BoxLayout({ style_class: 'keyboard-row' });
 | 
			
		||||
            for (let j = 0; j < children.length; ++j) {
 | 
			
		||||
                if (this._numOfHorizKeys == 0)
 | 
			
		||||
                    this._numOfHorizKeys = children.length;
 | 
			
		||||
                let key = children[j];
 | 
			
		||||
                let button = new Key(key);
 | 
			
		||||
 | 
			
		||||
                if (key.align == 'right')
 | 
			
		||||
                    right_box.add(button.actor);
 | 
			
		||||
                else
 | 
			
		||||
                    left_box.add(button.actor);
 | 
			
		||||
                if (key.name == 'Caribou_Prefs') {
 | 
			
		||||
                    key.connect('key-released', Lang.bind(this, this.hide));
 | 
			
		||||
 | 
			
		||||
                    // Add new key for hiding message tray
 | 
			
		||||
                    right_box.add(this._getTrayIcon());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            keyboard_row.add(left_box, { expand: true, x_fill: false, x_align: St.Align.START });
 | 
			
		||||
            keyboard_row.add(right_box, { expand: true, x_fill: false, x_align: St.Align.END });
 | 
			
		||||
        }
 | 
			
		||||
        layout.add(keyboard_row);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _loadRows : function (level, layout) {
 | 
			
		||||
        let rows = level.get_rows();
 | 
			
		||||
        for (let i = 0; i < rows.length; ++i) {
 | 
			
		||||
            let row = rows[i];
 | 
			
		||||
            if (this._numOfVertKeys == 0)
 | 
			
		||||
                this._numOfVertKeys = rows.length;
 | 
			
		||||
            this._addRows(row.get_columns(), layout);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _redraw: function () {
 | 
			
		||||
        if (!this._enableKeyboard)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let monitor = Main.layoutManager.bottomMonitor;
 | 
			
		||||
        let maxHeight = monitor.height / 3;
 | 
			
		||||
        this.actor.width = monitor.width;
 | 
			
		||||
 | 
			
		||||
        let layout = this._current_page;
 | 
			
		||||
        let verticalSpacing = layout.get_theme_node().get_length('spacing');
 | 
			
		||||
        let padding = layout.get_theme_node().get_length('padding');
 | 
			
		||||
 | 
			
		||||
        let box = layout.get_children()[0].get_children()[0];
 | 
			
		||||
        let horizontalSpacing = box.get_theme_node().get_length('spacing');
 | 
			
		||||
        let allHorizontalSpacing = (this._numOfHorizKeys - 1) * horizontalSpacing;
 | 
			
		||||
        let keyWidth = Math.floor((this.actor.width - allHorizontalSpacing - 2 * padding) / this._numOfHorizKeys);
 | 
			
		||||
 | 
			
		||||
        let allVerticalSpacing = (this._numOfVertKeys - 1) * verticalSpacing;
 | 
			
		||||
        let keyHeight = Math.floor((maxHeight - allVerticalSpacing - 2 * padding) / this._numOfVertKeys);
 | 
			
		||||
 | 
			
		||||
        let keySize = Math.min(keyWidth, keyHeight);
 | 
			
		||||
        this.actor.height = keySize * this._numOfVertKeys + allVerticalSpacing + 2 * padding;
 | 
			
		||||
 | 
			
		||||
        let rows = this._current_page.get_children();
 | 
			
		||||
        for (let i = 0; i < rows.length; ++i) {
 | 
			
		||||
            let keyboard_row = rows[i];
 | 
			
		||||
            let boxes = keyboard_row.get_children();
 | 
			
		||||
            for (let j = 0; j < boxes.length; ++j) {
 | 
			
		||||
                let keys = boxes[j].get_children();
 | 
			
		||||
                for (let k = 0; k < keys.length; ++k) {
 | 
			
		||||
                    let child = keys[k];
 | 
			
		||||
                    child.width = keySize * child.key_width;
 | 
			
		||||
                    child.height = keySize;
 | 
			
		||||
                    if (child._extended_keys) {
 | 
			
		||||
                        let extended_keys = child._extended_keys.get_children();
 | 
			
		||||
                        for (let n = 0; n < extended_keys.length; ++n) {
 | 
			
		||||
                            let extended_key = extended_keys[n];
 | 
			
		||||
                            extended_key.width = keySize;
 | 
			
		||||
                            extended_key.height = keySize;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onLevelChanged: function () {
 | 
			
		||||
        this._setActiveLayer();
 | 
			
		||||
        this._redraw();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onGroupChanged: function () {
 | 
			
		||||
        this._setActiveLayer();
 | 
			
		||||
        this._redraw();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setActiveLayer: function () {
 | 
			
		||||
        let active_group_name = this._keyboard.active_group;
 | 
			
		||||
        let active_group = this._keyboard.get_group(active_group_name);
 | 
			
		||||
        let active_level = active_group.active_level;
 | 
			
		||||
        let layers = this._groups[active_group_name];
 | 
			
		||||
 | 
			
		||||
        if (this._current_page != null) {
 | 
			
		||||
            this._current_page.hide();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._current_page = layers[active_level];
 | 
			
		||||
        this._current_page.show();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createSource: function () {
 | 
			
		||||
        if (this._source == null) {
 | 
			
		||||
            this._source = new KeyboardSource(this);
 | 
			
		||||
            this._source.setTransient(true);
 | 
			
		||||
            Main.messageTray.add(this._source);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _destroySource: function () {
 | 
			
		||||
        if (this._source) {
 | 
			
		||||
            this._source.destroy();
 | 
			
		||||
            this._source = null;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show: function () {
 | 
			
		||||
        this._redraw();
 | 
			
		||||
 | 
			
		||||
        Main.layoutManager.showKeyboard();
 | 
			
		||||
        this._destroySource();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hide: function () {
 | 
			
		||||
        Main.layoutManager.hideKeyboard();
 | 
			
		||||
        this._createSource();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _moveTemporarily: function () {
 | 
			
		||||
        let currentWindow = global.screen.get_display().focus_window;
 | 
			
		||||
        let rect = currentWindow.get_outer_rect();
 | 
			
		||||
 | 
			
		||||
        let newX = rect.x;
 | 
			
		||||
        let newY = 3 * this.actor.height / 2;
 | 
			
		||||
        currentWindow.move_frame(true, newX, newY);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setLocation: function (x, y) {
 | 
			
		||||
        if (y >= 2 * this.actor.height)
 | 
			
		||||
            this._moveTemporarily();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // D-Bus methods
 | 
			
		||||
    Show: function(timestamp) {
 | 
			
		||||
        if (!this._enableKeyboard)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (timestamp - this._timestamp < 0)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._timestamp = timestamp;
 | 
			
		||||
        this.show();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    Hide: function(timestamp) {
 | 
			
		||||
        if (!this._enableKeyboard)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (timestamp - this._timestamp < 0)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._timestamp = timestamp;
 | 
			
		||||
        this.hide();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    SetCursorLocation: function(x, y, w, h) {
 | 
			
		||||
        if (!this._enableKeyboard)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
//        this._setLocation(x, y);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    SetEntryLocation: function(x, y, w, h) {
 | 
			
		||||
        if (!this._enableKeyboard)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
//        this._setLocation(x, y);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get Name() {
 | 
			
		||||
        return 'gnome-shell';
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const KeyboardSource = new Lang.Class({
 | 
			
		||||
    Name: 'KeyboardSource',
 | 
			
		||||
    Extends: MessageTray.Source,
 | 
			
		||||
 | 
			
		||||
    _init: function(keyboard) {
 | 
			
		||||
        this.parent(_("Keyboard"));
 | 
			
		||||
        this._keyboard = keyboard;
 | 
			
		||||
 | 
			
		||||
        this._setSummaryIcon(this.createNotificationIcon());
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createNotificationIcon: function() {
 | 
			
		||||
        return new St.Icon({ icon_name: 'input-keyboard',
 | 
			
		||||
                             icon_type: St.IconType.SYMBOLIC,
 | 
			
		||||
                             icon_size: this.ICON_SIZE });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handleSummaryClick: function() {
 | 
			
		||||
        let event = Clutter.get_current_event();
 | 
			
		||||
        if (event.type() != Clutter.EventType.BUTTON_RELEASE)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        this.open();
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    open: function() {
 | 
			
		||||
        this._keyboard.show();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										978
									
								
								js/ui/layout.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,978 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const ScreenSaver = imports.misc.screenSaver;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
 | 
			
		||||
const STARTUP_ANIMATION_TIME = 0.2;
 | 
			
		||||
const KEYBOARD_ANIMATION_TIME = 0.5;
 | 
			
		||||
 | 
			
		||||
const LayoutManager = new Lang.Class({
 | 
			
		||||
    Name: 'LayoutManager',
 | 
			
		||||
 | 
			
		||||
    _init: function () {
 | 
			
		||||
        this._rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL);
 | 
			
		||||
        this.monitors = [];
 | 
			
		||||
        this.primaryMonitor = null;
 | 
			
		||||
        this.primaryIndex = -1;
 | 
			
		||||
        this._hotCorners = [];
 | 
			
		||||
        this._leftPanelBarrier = 0;
 | 
			
		||||
        this._rightPanelBarrier = 0;
 | 
			
		||||
        this._trayBarrier = 0;
 | 
			
		||||
 | 
			
		||||
        this._chrome = new Chrome(this);
 | 
			
		||||
 | 
			
		||||
        this.panelBox = new St.BoxLayout({ name: 'panelBox',
 | 
			
		||||
                                           vertical: true });
 | 
			
		||||
        this.addChrome(this.panelBox, { affectsStruts: true });
 | 
			
		||||
        this.panelBox.connect('allocation-changed',
 | 
			
		||||
                              Lang.bind(this, this._updatePanelBarriers));
 | 
			
		||||
 | 
			
		||||
        this.trayBox = new St.BoxLayout({ name: 'trayBox' }); 
 | 
			
		||||
        this.addChrome(this.trayBox, { visibleInFullscreen: true });
 | 
			
		||||
        this.trayBox.connect('allocation-changed',
 | 
			
		||||
                             Lang.bind(this, this._updateTrayBarrier));
 | 
			
		||||
 | 
			
		||||
        this.keyboardBox = new St.BoxLayout({ name: 'keyboardBox',
 | 
			
		||||
                                              reactive: true,
 | 
			
		||||
                                              track_hover: true });
 | 
			
		||||
        this.addChrome(this.keyboardBox, { visibleInFullscreen: true });
 | 
			
		||||
        this._keyboardHeightNotifyId = 0;
 | 
			
		||||
 | 
			
		||||
        global.screen.connect('monitors-changed',
 | 
			
		||||
                              Lang.bind(this, this._monitorsChanged));
 | 
			
		||||
        this._monitorsChanged();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // This is called by Main after everything else is constructed;
 | 
			
		||||
    // Chrome.init() needs access to Main.overview, which didn't exist
 | 
			
		||||
    // yet when the LayoutManager was constructed.
 | 
			
		||||
    init: function() {
 | 
			
		||||
        this._chrome.init();
 | 
			
		||||
 | 
			
		||||
        this._startupAnimation();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateMonitors: function() {
 | 
			
		||||
        let screen = global.screen;
 | 
			
		||||
 | 
			
		||||
        this.monitors = [];
 | 
			
		||||
        let nMonitors = screen.get_n_monitors();
 | 
			
		||||
        for (let i = 0; i < nMonitors; i++)
 | 
			
		||||
            this.monitors.push(screen.get_monitor_geometry(i));
 | 
			
		||||
 | 
			
		||||
        if (nMonitors == 1) {
 | 
			
		||||
            this.primaryIndex = this.bottomIndex = 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            // If there are monitors below the primary, then we need
 | 
			
		||||
            // to split primary from bottom.
 | 
			
		||||
            this.primaryIndex = this.bottomIndex = screen.get_primary_monitor();
 | 
			
		||||
            for (let i = 0; i < this.monitors.length; i++) {
 | 
			
		||||
                let monitor = this.monitors[i];
 | 
			
		||||
                if (this._isAboveOrBelowPrimary(monitor)) {
 | 
			
		||||
                    if (monitor.y > this.monitors[this.bottomIndex].y)
 | 
			
		||||
                        this.bottomIndex = i;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        this.primaryMonitor = this.monitors[this.primaryIndex];
 | 
			
		||||
        this.bottomMonitor = this.monitors[this.bottomIndex];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateHotCorners: function() {
 | 
			
		||||
        // destroy old hot corners
 | 
			
		||||
        for (let i = 0; i < this._hotCorners.length; i++)
 | 
			
		||||
            this._hotCorners[i].destroy();
 | 
			
		||||
        this._hotCorners = [];
 | 
			
		||||
 | 
			
		||||
        // build new hot corners
 | 
			
		||||
        for (let i = 0; i < this.monitors.length; i++) {
 | 
			
		||||
            if (i == this.primaryIndex)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            let monitor = this.monitors[i];
 | 
			
		||||
            let cornerX = this._rtl ? monitor.x + monitor.width : monitor.x;
 | 
			
		||||
            let cornerY = monitor.y;
 | 
			
		||||
 | 
			
		||||
            let haveTopLeftCorner = true;
 | 
			
		||||
 | 
			
		||||
            // Check if we have a top left (right for RTL) corner.
 | 
			
		||||
            // I.e. if there is no monitor directly above or to the left(right)
 | 
			
		||||
            let besideX = this._rtl ? monitor.x + 1 : cornerX - 1;
 | 
			
		||||
            let besideY = cornerY;
 | 
			
		||||
            let aboveX = cornerX;
 | 
			
		||||
            let aboveY = cornerY - 1;
 | 
			
		||||
 | 
			
		||||
            for (let j = 0; j < this.monitors.length; j++) {
 | 
			
		||||
                if (i == j)
 | 
			
		||||
                    continue;
 | 
			
		||||
                let otherMonitor = this.monitors[j];
 | 
			
		||||
                if (besideX >= otherMonitor.x &&
 | 
			
		||||
                    besideX < otherMonitor.x + otherMonitor.width &&
 | 
			
		||||
                    besideY >= otherMonitor.y &&
 | 
			
		||||
                    besideY < otherMonitor.y + otherMonitor.height) {
 | 
			
		||||
                    haveTopLeftCorner = false;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                if (aboveX >= otherMonitor.x &&
 | 
			
		||||
                    aboveX < otherMonitor.x + otherMonitor.width &&
 | 
			
		||||
                    aboveY >= otherMonitor.y &&
 | 
			
		||||
                    aboveY < otherMonitor.y + otherMonitor.height) {
 | 
			
		||||
                    haveTopLeftCorner = false;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!haveTopLeftCorner)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            let corner = new HotCorner();
 | 
			
		||||
            this._hotCorners.push(corner);
 | 
			
		||||
            corner.actor.set_position(cornerX, cornerY);
 | 
			
		||||
            this._chrome.addActor(corner.actor);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateBoxes: function() {
 | 
			
		||||
        this.panelBox.set_position(this.primaryMonitor.x, this.primaryMonitor.y);
 | 
			
		||||
        this.panelBox.set_size(this.primaryMonitor.width, -1);
 | 
			
		||||
 | 
			
		||||
        this.keyboardBox.set_position(this.bottomMonitor.x,
 | 
			
		||||
                                      this.bottomMonitor.y + this.bottomMonitor.height);
 | 
			
		||||
        this.keyboardBox.set_size(this.bottomMonitor.width, -1);
 | 
			
		||||
 | 
			
		||||
        this.trayBox.set_position(this.bottomMonitor.x,
 | 
			
		||||
                                  this.bottomMonitor.y + this.bottomMonitor.height);
 | 
			
		||||
        this.trayBox.set_size(this.bottomMonitor.width, -1);
 | 
			
		||||
 | 
			
		||||
        // Set trayBox's clip to show things above it, but not below
 | 
			
		||||
        // it (so it's not visible behind the keyboard). The exact
 | 
			
		||||
        // height of the clip doesn't matter, as long as it's taller
 | 
			
		||||
        // than any Notification.actor.
 | 
			
		||||
        this.trayBox.set_clip(0, -this.bottomMonitor.height,
 | 
			
		||||
                              this.bottomMonitor.width, this.bottomMonitor.height);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updatePanelBarriers: function() {
 | 
			
		||||
        if (this._leftPanelBarrier)
 | 
			
		||||
            global.destroy_pointer_barrier(this._leftPanelBarrier);
 | 
			
		||||
        if (this._rightPanelBarrier)
 | 
			
		||||
            global.destroy_pointer_barrier(this._rightPanelBarrier);
 | 
			
		||||
 | 
			
		||||
        if (this.panelBox.height) {
 | 
			
		||||
            let primary = this.primaryMonitor;
 | 
			
		||||
            this._leftPanelBarrier =
 | 
			
		||||
                global.create_pointer_barrier(primary.x, primary.y,
 | 
			
		||||
                                              primary.x, primary.y + this.panelBox.height,
 | 
			
		||||
                                              1 /* BarrierPositiveX */);
 | 
			
		||||
            this._rightPanelBarrier =
 | 
			
		||||
                global.create_pointer_barrier(primary.x + primary.width, primary.y,
 | 
			
		||||
                                              primary.x + primary.width, primary.y + this.panelBox.height,
 | 
			
		||||
                                              4 /* BarrierNegativeX */);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._leftPanelBarrier = 0;
 | 
			
		||||
            this._rightPanelBarrier = 0;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateTrayBarrier: function() {
 | 
			
		||||
        let monitor = this.bottomMonitor;
 | 
			
		||||
 | 
			
		||||
        if (this._trayBarrier)
 | 
			
		||||
            global.destroy_pointer_barrier(this._trayBarrier);
 | 
			
		||||
 | 
			
		||||
        if (Main.messageTray) {
 | 
			
		||||
            this._trayBarrier =
 | 
			
		||||
                global.create_pointer_barrier(monitor.x + monitor.width, monitor.y + monitor.height - Main.messageTray.actor.height,
 | 
			
		||||
                                              monitor.x + monitor.width, monitor.y + monitor.height,
 | 
			
		||||
                                              4 /* BarrierNegativeX */);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._trayBarrier = 0;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _monitorsChanged: function() {
 | 
			
		||||
        this._updateMonitors();
 | 
			
		||||
        this._updateBoxes();
 | 
			
		||||
        this._updateHotCorners();
 | 
			
		||||
 | 
			
		||||
        this.emit('monitors-changed');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _isAboveOrBelowPrimary: function(monitor) {
 | 
			
		||||
        let primary = this.monitors[this.primaryIndex];
 | 
			
		||||
        let monitorLeft = monitor.x, monitorRight = monitor.x + monitor.width;
 | 
			
		||||
        let primaryLeft = primary.x, primaryRight = primary.x + primary.width;
 | 
			
		||||
 | 
			
		||||
        if ((monitorLeft >= primaryLeft && monitorLeft < primaryRight) ||
 | 
			
		||||
            (monitorRight > primaryLeft && monitorRight <= primaryRight) ||
 | 
			
		||||
            (primaryLeft >= monitorLeft && primaryLeft < monitorRight) ||
 | 
			
		||||
            (primaryRight > monitorLeft && primaryRight <= monitorRight))
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get focusIndex() {
 | 
			
		||||
        let focusWindow = global.display.focus_window;
 | 
			
		||||
 | 
			
		||||
        if (focusWindow) {
 | 
			
		||||
            let wrect = focusWindow.get_outer_rect();
 | 
			
		||||
            for (let i = 0; i < this.monitors.length; i++) {
 | 
			
		||||
                let monitor = this.monitors[i];
 | 
			
		||||
 | 
			
		||||
                if (monitor.x <= wrect.x && monitor.y <= wrect.y &&
 | 
			
		||||
                    monitor.x + monitor.width > wrect.x &&
 | 
			
		||||
                    monitor.y + monitor.height > wrect.y)
 | 
			
		||||
                    return i;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this.primaryIndex;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get focusMonitor() {
 | 
			
		||||
        return this.monitors[this.focusIndex];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _startupAnimation: function() {
 | 
			
		||||
        // Don't animate the strut
 | 
			
		||||
        this._chrome.freezeUpdateRegions();
 | 
			
		||||
 | 
			
		||||
        this.panelBox.anchor_y = this.panelBox.height;
 | 
			
		||||
        Tweener.addTween(this.panelBox,
 | 
			
		||||
                         { anchor_y: 0,
 | 
			
		||||
                           time: STARTUP_ANIMATION_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: this._startupAnimationComplete,
 | 
			
		||||
                           onCompleteScope: this
 | 
			
		||||
                         });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _startupAnimationComplete: function() {
 | 
			
		||||
        this._chrome.thawUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    showKeyboard: function () {
 | 
			
		||||
        Main.messageTray.hide();
 | 
			
		||||
        this.keyboardBox.raise_top();
 | 
			
		||||
        Tweener.addTween(this.keyboardBox,
 | 
			
		||||
                         { anchor_y: this.keyboardBox.height,
 | 
			
		||||
                           time: KEYBOARD_ANIMATION_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: this._showKeyboardComplete,
 | 
			
		||||
                           onCompleteScope: this
 | 
			
		||||
                         });
 | 
			
		||||
        Tweener.addTween(this.trayBox,
 | 
			
		||||
                         { anchor_y: this.keyboardBox.height,
 | 
			
		||||
                           time: KEYBOARD_ANIMATION_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad'
 | 
			
		||||
                         });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showKeyboardComplete: function() {
 | 
			
		||||
        // Poke Chrome to update the input shape; it doesn't notice
 | 
			
		||||
        // anchor point changes
 | 
			
		||||
        this._chrome.updateRegions();
 | 
			
		||||
 | 
			
		||||
        this._keyboardHeightNotifyId = this.keyboardBox.connect('notify::height', Lang.bind(this, function () {
 | 
			
		||||
            this.keyboardBox.anchor_y = this.keyboardBox.height;
 | 
			
		||||
            this.trayBox.anchor_y = this.keyboardBox.height;
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hideKeyboard: function (immediate) {
 | 
			
		||||
        Main.messageTray.hide();
 | 
			
		||||
        if (this._keyboardHeightNotifyId) {
 | 
			
		||||
            this.keyboardBox.disconnect(this._keyboardHeightNotifyId);
 | 
			
		||||
            this._keyboardHeightNotifyId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        Tweener.addTween(this.keyboardBox,
 | 
			
		||||
                         { anchor_y: 0,
 | 
			
		||||
                           time: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: this._hideKeyboardComplete,
 | 
			
		||||
                           onCompleteScope: this
 | 
			
		||||
                         });
 | 
			
		||||
        Tweener.addTween(this.trayBox,
 | 
			
		||||
                         { anchor_y: 0,
 | 
			
		||||
                           time: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad'
 | 
			
		||||
                         });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _hideKeyboardComplete: function() {
 | 
			
		||||
        this._chrome.updateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // addChrome:
 | 
			
		||||
    // @actor: an actor to add to the chrome
 | 
			
		||||
    // @params: (optional) additional params
 | 
			
		||||
    //
 | 
			
		||||
    // Adds @actor to the chrome, and (unless %affectsInputRegion in
 | 
			
		||||
    // @params is %false) extends the input region to include it.
 | 
			
		||||
    // Changes in @actor's size, position, and visibility will
 | 
			
		||||
    // automatically result in appropriate changes to the input
 | 
			
		||||
    // region.
 | 
			
		||||
    //
 | 
			
		||||
    // If %affectsStruts in @params is %true (and @actor is along a
 | 
			
		||||
    // screen edge), then @actor's size and position will also affect
 | 
			
		||||
    // the window manager struts. Changes to @actor's visibility will
 | 
			
		||||
    // NOT affect whether or not the strut is present, however.
 | 
			
		||||
    //
 | 
			
		||||
    // If %visibleInFullscreen in @params is %true, the actor will be
 | 
			
		||||
    // visible even when a fullscreen window should be covering it.
 | 
			
		||||
    addChrome: function(actor, params) {
 | 
			
		||||
        this._chrome.addActor(actor, params);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // trackChrome:
 | 
			
		||||
    // @actor: a descendant of the chrome to begin tracking
 | 
			
		||||
    // @params: parameters describing how to track @actor
 | 
			
		||||
    //
 | 
			
		||||
    // Tells the chrome to track @actor, which must be a descendant
 | 
			
		||||
    // of an actor added via addChrome(). This can be used to extend the
 | 
			
		||||
    // struts or input region to cover specific children.
 | 
			
		||||
    //
 | 
			
		||||
    // @params can have any of the same values as in addChrome(),
 | 
			
		||||
    // though some possibilities don't make sense (eg, trying to have
 | 
			
		||||
    // a %visibleInFullscreen child of a non-%visibleInFullscreen
 | 
			
		||||
    // parent). By default, @actor has the same params as its chrome
 | 
			
		||||
    // ancestor.
 | 
			
		||||
    trackChrome: function(actor, params) {
 | 
			
		||||
        this._chrome.trackActor(actor, params);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // untrackChrome:
 | 
			
		||||
    // @actor: an actor previously tracked via trackChrome()
 | 
			
		||||
    //
 | 
			
		||||
    // Undoes the effect of trackChrome()
 | 
			
		||||
    untrackChrome: function(actor) {
 | 
			
		||||
        this._chrome.untrackActor(actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // removeChrome:
 | 
			
		||||
    // @actor: a chrome actor
 | 
			
		||||
    //
 | 
			
		||||
    // Removes @actor from the chrome
 | 
			
		||||
    removeChrome: function(actor) {
 | 
			
		||||
        this._chrome.removeActor(actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    findMonitorForActor: function(actor) {
 | 
			
		||||
        return this._chrome.findMonitorForActor(actor);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(LayoutManager.prototype);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// HotCorner:
 | 
			
		||||
//
 | 
			
		||||
// This class manages a "hot corner" that can toggle switching to
 | 
			
		||||
// overview.
 | 
			
		||||
const HotCorner = new Lang.Class({
 | 
			
		||||
    Name: 'HotCorner',
 | 
			
		||||
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        // We use this flag to mark the case where the user has entered the
 | 
			
		||||
        // hot corner and has not left both the hot corner and a surrounding
 | 
			
		||||
        // guard area (the "environs"). This avoids triggering the hot corner
 | 
			
		||||
        // multiple times due to an accidental jitter.
 | 
			
		||||
        this._entered = false;
 | 
			
		||||
 | 
			
		||||
        this.actor = new Clutter.Group({ name: 'hot-corner-environs',
 | 
			
		||||
                                         width: 3,
 | 
			
		||||
                                         height: 3,
 | 
			
		||||
                                         reactive: true });
 | 
			
		||||
 | 
			
		||||
        this._corner = new Clutter.Rectangle({ name: 'hot-corner',
 | 
			
		||||
                                               width: 1,
 | 
			
		||||
                                               height: 1,
 | 
			
		||||
                                               opacity: 0,
 | 
			
		||||
                                               reactive: true });
 | 
			
		||||
        this._corner._delegate = this;
 | 
			
		||||
 | 
			
		||||
        this.actor.add_actor(this._corner);
 | 
			
		||||
 | 
			
		||||
        if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
 | 
			
		||||
            this._corner.set_position(this.actor.width - this._corner.width, 0);
 | 
			
		||||
            this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._corner.set_position(0, 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._activationTime = 0;
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('leave-event',
 | 
			
		||||
                           Lang.bind(this, this._onEnvironsLeft));
 | 
			
		||||
 | 
			
		||||
        // Clicking on the hot corner environs should result in the
 | 
			
		||||
        // same behavior as clicking on the hot corner.
 | 
			
		||||
        this.actor.connect('button-release-event',
 | 
			
		||||
                           Lang.bind(this, this._onCornerClicked));
 | 
			
		||||
 | 
			
		||||
        // In addition to being triggered by the mouse enter event,
 | 
			
		||||
        // the hot corner can be triggered by clicking on it. This is
 | 
			
		||||
        // useful if the user wants to undo the effect of triggering
 | 
			
		||||
        // the hot corner once in the hot corner.
 | 
			
		||||
        this._corner.connect('enter-event',
 | 
			
		||||
                             Lang.bind(this, this._onCornerEntered));
 | 
			
		||||
        this._corner.connect('button-release-event',
 | 
			
		||||
                             Lang.bind(this, this._onCornerClicked));
 | 
			
		||||
        this._corner.connect('leave-event',
 | 
			
		||||
                             Lang.bind(this, this._onCornerLeft));
 | 
			
		||||
 | 
			
		||||
        // Cache the three ripples instead of dynamically creating and destroying them.
 | 
			
		||||
        this._ripple1 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0 });
 | 
			
		||||
        this._ripple2 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0 });
 | 
			
		||||
        this._ripple3 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0 });
 | 
			
		||||
 | 
			
		||||
        Main.uiGroup.add_actor(this._ripple1);
 | 
			
		||||
        Main.uiGroup.add_actor(this._ripple2);
 | 
			
		||||
        Main.uiGroup.add_actor(this._ripple3);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
        this.actor.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _animRipple : function(ripple, delay, time, startScale, startOpacity, finalScale) {
 | 
			
		||||
        // We draw a ripple by using a source image and animating it scaling
 | 
			
		||||
        // outwards and fading away. We want the ripples to move linearly
 | 
			
		||||
        // or it looks unrealistic, but if the opacity of the ripple goes
 | 
			
		||||
        // linearly to zero it fades away too quickly, so we use Tweener's
 | 
			
		||||
        // 'onUpdate' to give a non-linear curve to the fade-away and make
 | 
			
		||||
        // it more visible in the middle section.
 | 
			
		||||
 | 
			
		||||
        ripple._opacity = startOpacity;
 | 
			
		||||
 | 
			
		||||
        if (ripple.get_direction() == St.TextDirection.RTL)
 | 
			
		||||
            ripple.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
 | 
			
		||||
 | 
			
		||||
        ripple.visible = true;
 | 
			
		||||
        ripple.opacity = 255 * Math.sqrt(startOpacity);
 | 
			
		||||
        ripple.scale_x = ripple.scale_y = startScale;
 | 
			
		||||
 | 
			
		||||
        let [x, y] = this._corner.get_transformed_position();
 | 
			
		||||
        ripple.x = x;
 | 
			
		||||
        ripple.y = y;
 | 
			
		||||
 | 
			
		||||
        Tweener.addTween(ripple, { _opacity: 0,
 | 
			
		||||
                                   scale_x: finalScale,
 | 
			
		||||
                                   scale_y: finalScale,
 | 
			
		||||
                                   delay: delay,
 | 
			
		||||
                                   time: time,
 | 
			
		||||
                                   transition: 'linear',
 | 
			
		||||
                                   onUpdate: function() { ripple.opacity = 255 * Math.sqrt(ripple._opacity); },
 | 
			
		||||
                                   onComplete: function() { ripple.visible = false; } });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    rippleAnimation: function() {
 | 
			
		||||
        // Show three concentric ripples expanding outwards; the exact
 | 
			
		||||
        // parameters were found by trial and error, so don't look
 | 
			
		||||
        // for them to make perfect sense mathematically
 | 
			
		||||
 | 
			
		||||
        //                              delay  time  scale opacity => scale
 | 
			
		||||
        this._animRipple(this._ripple1, 0.0,   0.83,  0.25,  1.0,     1.5);
 | 
			
		||||
        this._animRipple(this._ripple2, 0.05,  1.0,   0.0,   0.7,     1.25);
 | 
			
		||||
        this._animRipple(this._ripple3, 0.35,  1.0,   0.0,   0.3,     1);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handleDragOver: function(source, actor, x, y, time) {
 | 
			
		||||
        if (source != Main.xdndHandler)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (!Main.overview.visible && !Main.overview.animationInProgress) {
 | 
			
		||||
            this.rippleAnimation();
 | 
			
		||||
            Main.overview.showTemporarily();
 | 
			
		||||
            Main.overview.beginItemDrag(actor);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onCornerEntered : function() {
 | 
			
		||||
        if (!this._entered) {
 | 
			
		||||
            this._entered = true;
 | 
			
		||||
            if (!Main.overview.animationInProgress) {
 | 
			
		||||
                this._activationTime = Date.now() / 1000;
 | 
			
		||||
 | 
			
		||||
                this.rippleAnimation();
 | 
			
		||||
                Main.overview.toggle();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onCornerClicked : function() {
 | 
			
		||||
        if (this.shouldToggleOverviewOnClick())
 | 
			
		||||
            Main.overview.toggle();
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onCornerLeft : function(actor, event) {
 | 
			
		||||
        if (event.get_related() != this.actor)
 | 
			
		||||
            this._entered = false;
 | 
			
		||||
        // Consume event, otherwise this will confuse onEnvironsLeft
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onEnvironsLeft : function(actor, event) {
 | 
			
		||||
        if (event.get_related() != this._corner)
 | 
			
		||||
            this._entered = false;
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Checks if the Activities button is currently sensitive to
 | 
			
		||||
    // clicks. The first call to this function within the
 | 
			
		||||
    // HOT_CORNER_ACTIVATION_TIMEOUT time of the hot corner being
 | 
			
		||||
    // triggered will return false. This avoids opening and closing
 | 
			
		||||
    // the overview if the user both triggered the hot corner and
 | 
			
		||||
    // clicked the Activities button.
 | 
			
		||||
    shouldToggleOverviewOnClick: function() {
 | 
			
		||||
        if (Main.overview.animationInProgress)
 | 
			
		||||
            return false;
 | 
			
		||||
        if (this._activationTime == 0 || Date.now() / 1000 - this._activationTime > HOT_CORNER_ACTIVATION_TIMEOUT)
 | 
			
		||||
            return true;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// This manages the shell "chrome"; the UI that's visible in the
 | 
			
		||||
// normal mode (ie, outside the Overview), that surrounds the main
 | 
			
		||||
// workspace content.
 | 
			
		||||
 | 
			
		||||
const defaultParams = {
 | 
			
		||||
    visibleInFullscreen: false,
 | 
			
		||||
    affectsStruts: false,
 | 
			
		||||
    affectsInputRegion: true
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const Chrome = new Lang.Class({
 | 
			
		||||
    Name: 'Chrome',
 | 
			
		||||
 | 
			
		||||
    _init: function(layoutManager) {
 | 
			
		||||
        this._layoutManager = layoutManager;
 | 
			
		||||
 | 
			
		||||
        this._monitors = [];
 | 
			
		||||
        this._inOverview = false;
 | 
			
		||||
        this._updateRegionIdle = 0;
 | 
			
		||||
        this._freezeUpdateCount = 0;
 | 
			
		||||
 | 
			
		||||
        this._trackedActors = [];
 | 
			
		||||
 | 
			
		||||
        this._layoutManager.connect('monitors-changed',
 | 
			
		||||
                                    Lang.bind(this, this._relayout));
 | 
			
		||||
        global.screen.connect('restacked',
 | 
			
		||||
                              Lang.bind(this, this._windowsRestacked));
 | 
			
		||||
 | 
			
		||||
        // Need to update struts on new workspaces when they are added
 | 
			
		||||
        global.screen.connect('notify::n-workspaces',
 | 
			
		||||
                              Lang.bind(this, this._queueUpdateRegions));
 | 
			
		||||
 | 
			
		||||
        this._screenSaverActive = false;
 | 
			
		||||
        this._screenSaverProxy = new ScreenSaver.ScreenSaverProxy();
 | 
			
		||||
        this._screenSaverProxy.connectSignal('ActiveChanged', Lang.bind(this, function(proxy, senderName, [isActive]) {
 | 
			
		||||
            this._onScreenSaverActiveChanged(isActive);
 | 
			
		||||
        }));
 | 
			
		||||
        this._screenSaverProxy.GetActiveRemote(Lang.bind(this, function(result, err) {
 | 
			
		||||
            if (!err)
 | 
			
		||||
                this._onScreenSaverActiveChanged(result[0]);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        this._relayout();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    init: function() {
 | 
			
		||||
        Main.overview.connect('showing',
 | 
			
		||||
                             Lang.bind(this, this._overviewShowing));
 | 
			
		||||
        Main.overview.connect('hidden',
 | 
			
		||||
                             Lang.bind(this, this._overviewHidden));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addActor: function(actor, params) {
 | 
			
		||||
        Main.uiGroup.add_actor(actor);
 | 
			
		||||
        this._trackActor(actor, params);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    trackActor: function(actor, params) {
 | 
			
		||||
        let ancestor = actor.get_parent();
 | 
			
		||||
        let index = this._findActor(ancestor);
 | 
			
		||||
        while (ancestor && index == -1) {
 | 
			
		||||
            ancestor = ancestor.get_parent();
 | 
			
		||||
            index = this._findActor(ancestor);
 | 
			
		||||
        }
 | 
			
		||||
        if (!ancestor)
 | 
			
		||||
            throw new Error('actor is not a descendent of a chrome actor');
 | 
			
		||||
 | 
			
		||||
        let ancestorData = this._trackedActors[index];
 | 
			
		||||
        if (!params)
 | 
			
		||||
            params = {};
 | 
			
		||||
        // We can't use Params.parse here because we want to drop
 | 
			
		||||
        // the extra values like ancestorData.actor
 | 
			
		||||
        for (let prop in defaultParams) {
 | 
			
		||||
            if (!params.hasOwnProperty(prop))
 | 
			
		||||
                params[prop] = ancestorData[prop];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._trackActor(actor, params);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    untrackActor: function(actor) {
 | 
			
		||||
        this._untrackActor(actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    removeActor: function(actor) {
 | 
			
		||||
        Main.uiGroup.remove_actor(actor);
 | 
			
		||||
        this._untrackActor(actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _findActor: function(actor) {
 | 
			
		||||
        for (let i = 0; i < this._trackedActors.length; i++) {
 | 
			
		||||
            let actorData = this._trackedActors[i];
 | 
			
		||||
            if (actorData.actor == actor)
 | 
			
		||||
                return i;
 | 
			
		||||
        }
 | 
			
		||||
        return -1;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _trackActor: function(actor, params) {
 | 
			
		||||
        if (this._findActor(actor) != -1)
 | 
			
		||||
            throw new Error('trying to re-track existing chrome actor');
 | 
			
		||||
 | 
			
		||||
        let actorData = Params.parse(params, defaultParams);
 | 
			
		||||
        actorData.actor = actor;
 | 
			
		||||
        actorData.isToplevel = actor.get_parent() == Main.uiGroup;
 | 
			
		||||
        actorData.visibleId = actor.connect('notify::visible',
 | 
			
		||||
                                            Lang.bind(this, this._queueUpdateRegions));
 | 
			
		||||
        actorData.allocationId = actor.connect('notify::allocation',
 | 
			
		||||
                                               Lang.bind(this, this._queueUpdateRegions));
 | 
			
		||||
        actorData.parentSetId = actor.connect('parent-set',
 | 
			
		||||
                                              Lang.bind(this, this._actorReparented));
 | 
			
		||||
        // Note that destroying actor will unset its parent, so we don't
 | 
			
		||||
        // need to connect to 'destroy' too.
 | 
			
		||||
 | 
			
		||||
        this._trackedActors.push(actorData);
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _untrackActor: function(actor) {
 | 
			
		||||
        let i = this._findActor(actor);
 | 
			
		||||
 | 
			
		||||
        if (i == -1)
 | 
			
		||||
            return;
 | 
			
		||||
        let actorData = this._trackedActors[i];
 | 
			
		||||
 | 
			
		||||
        this._trackedActors.splice(i, 1);
 | 
			
		||||
        actor.disconnect(actorData.visibleId);
 | 
			
		||||
        actor.disconnect(actorData.allocationId);
 | 
			
		||||
        actor.disconnect(actorData.parentSetId);
 | 
			
		||||
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _actorReparented: function(actor, oldParent) {
 | 
			
		||||
        let newParent = actor.get_parent();
 | 
			
		||||
        if (!newParent)
 | 
			
		||||
            this._untrackActor(actor);
 | 
			
		||||
        else
 | 
			
		||||
            actorData.isToplevel = (newParent == Main.uiGroup);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateVisibility: function() {
 | 
			
		||||
        for (let i = 0; i < this._trackedActors.length; i++) {
 | 
			
		||||
            let actorData = this._trackedActors[i], visible;
 | 
			
		||||
            if (!actorData.isToplevel)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (this._screenSaverActive)
 | 
			
		||||
                visible = false;
 | 
			
		||||
            else if (this._inOverview)
 | 
			
		||||
                visible = true;
 | 
			
		||||
            else if (!actorData.visibleInFullscreen &&
 | 
			
		||||
                     this.findMonitorForActor(actorData.actor).inFullscreen)
 | 
			
		||||
                visible = false;
 | 
			
		||||
            else
 | 
			
		||||
                visible = true;
 | 
			
		||||
            Main.uiGroup.set_skip_paint(actorData.actor, !visible);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _overviewShowing: function() {
 | 
			
		||||
        this._inOverview = true;
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _overviewHidden: function() {
 | 
			
		||||
        this._inOverview = false;
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _relayout: function() {
 | 
			
		||||
        this._monitors = this._layoutManager.monitors;
 | 
			
		||||
        this._primaryMonitor = this._layoutManager.primaryMonitor;
 | 
			
		||||
 | 
			
		||||
        this._updateFullscreen();
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onScreenSaverActiveChanged: function(screenSaverActive) {
 | 
			
		||||
        this._screenSaverActive = screenSaverActive;
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _findMonitorForRect: function(x, y, w, h) {
 | 
			
		||||
        // First look at what monitor the center of the rectangle is at
 | 
			
		||||
        let cx = x + w/2;
 | 
			
		||||
        let cy = y + h/2;
 | 
			
		||||
        for (let i = 0; i < this._monitors.length; i++) {
 | 
			
		||||
            let monitor = this._monitors[i];
 | 
			
		||||
            if (cx >= monitor.x && cx < monitor.x + monitor.width &&
 | 
			
		||||
                cy >= monitor.y && cy < monitor.y + monitor.height)
 | 
			
		||||
                return monitor;
 | 
			
		||||
        }
 | 
			
		||||
        // If the center is not on a monitor, return the first overlapping monitor
 | 
			
		||||
        for (let i = 0; i < this._monitors.length; i++) {
 | 
			
		||||
            let monitor = this._monitors[i];
 | 
			
		||||
            if (x + w > monitor.x && x < monitor.x + monitor.width &&
 | 
			
		||||
                y + h > monitor.y && y < monitor.y + monitor.height)
 | 
			
		||||
                return monitor;
 | 
			
		||||
        }
 | 
			
		||||
        // otherwise on no monitor
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _findMonitorForWindow: function(window) {
 | 
			
		||||
        return this._findMonitorForRect(window.x, window.y, window.width, window.height);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // This call guarantees that we return some monitor to simplify usage of it
 | 
			
		||||
    // In practice all tracked actors should be visible on some monitor anyway
 | 
			
		||||
    findMonitorForActor: function(actor) {
 | 
			
		||||
        let [x, y] = actor.get_transformed_position();
 | 
			
		||||
        let [w, h] = actor.get_transformed_size();
 | 
			
		||||
        let monitor = this._findMonitorForRect(x, y, w, h);
 | 
			
		||||
        if (monitor)
 | 
			
		||||
            return monitor;
 | 
			
		||||
        return this._primaryMonitor; // Not on any monitor, pretend its on the primary
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _queueUpdateRegions: function() {
 | 
			
		||||
        if (!this._updateRegionIdle && !this._freezeUpdateCount)
 | 
			
		||||
            this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this.updateRegions),
 | 
			
		||||
                                                       Meta.PRIORITY_BEFORE_REDRAW);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    freezeUpdateRegions: function() {
 | 
			
		||||
        if (this._updateRegionIdle)
 | 
			
		||||
            this.updateRegions();
 | 
			
		||||
        this._freezeUpdateCount++;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    thawUpdateRegions: function() {
 | 
			
		||||
        this._freezeUpdateCount--;
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateFullscreen: function() {
 | 
			
		||||
        let windows = Main.getWindowActorsForWorkspace(global.screen.get_active_workspace_index());
 | 
			
		||||
 | 
			
		||||
        // Reset all monitors to not fullscreen
 | 
			
		||||
        for (let i = 0; i < this._monitors.length; i++)
 | 
			
		||||
            this._monitors[i].inFullscreen = false;
 | 
			
		||||
 | 
			
		||||
        // Ordinary chrome should be visible unless there is a window
 | 
			
		||||
        // with layer FULLSCREEN, or a window with layer
 | 
			
		||||
        // OVERRIDE_REDIRECT that covers the whole screen.
 | 
			
		||||
        // ('override_redirect' is not actually a layer above all
 | 
			
		||||
        // other windows, but this seems to be how mutter treats it
 | 
			
		||||
        // currently...) If we wanted to be extra clever, we could
 | 
			
		||||
        // figure out when an OVERRIDE_REDIRECT window was trying to
 | 
			
		||||
        // partially overlap us, and then adjust the input region and
 | 
			
		||||
        // our clip region accordingly...
 | 
			
		||||
 | 
			
		||||
        // @windows is sorted bottom to top.
 | 
			
		||||
 | 
			
		||||
        for (let i = windows.length - 1; i > -1; i--) {
 | 
			
		||||
            let window = windows[i];
 | 
			
		||||
            let layer = window.get_meta_window().get_layer();
 | 
			
		||||
 | 
			
		||||
            // Skip minimized windows
 | 
			
		||||
            if (!window.showing_on_its_workspace())
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (layer == Meta.StackLayer.FULLSCREEN) {
 | 
			
		||||
                let monitor = this._findMonitorForWindow(window);
 | 
			
		||||
                if (monitor)
 | 
			
		||||
                    monitor.inFullscreen = true;
 | 
			
		||||
            }
 | 
			
		||||
            if (layer == Meta.StackLayer.OVERRIDE_REDIRECT) {
 | 
			
		||||
                // Check whether the window is screen sized
 | 
			
		||||
                let isScreenSized =
 | 
			
		||||
                    (window.x == 0 && window.y == 0 &&
 | 
			
		||||
                    window.width == global.screen_width &&
 | 
			
		||||
                    window.height == global.screen_height);
 | 
			
		||||
 | 
			
		||||
                if (isScreenSized) {
 | 
			
		||||
                    for (let i = 0; i < this._monitors.length; i++)
 | 
			
		||||
                        this._monitors[i].inFullscreen = true;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Or whether it is monitor sized
 | 
			
		||||
                let monitor = this._findMonitorForWindow(window);
 | 
			
		||||
                if (monitor &&
 | 
			
		||||
                    window.x <= monitor.x &&
 | 
			
		||||
                    window.x + window.width >= monitor.x + monitor.width &&
 | 
			
		||||
                    window.y <= monitor.y &&
 | 
			
		||||
                    window.y + window.height >= monitor.y + monitor.height)
 | 
			
		||||
                    monitor.inFullscreen = true;
 | 
			
		||||
            } else
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _windowsRestacked: function() {
 | 
			
		||||
        let wasInFullscreen = [];
 | 
			
		||||
        for (let i = 0; i < this._monitors.length; i++)
 | 
			
		||||
            wasInFullscreen[i] = this._monitors[i].inFullscreen;
 | 
			
		||||
 | 
			
		||||
        this._updateFullscreen();
 | 
			
		||||
 | 
			
		||||
        let changed = false;
 | 
			
		||||
        for (let i = 0; i < wasInFullscreen.length; i++) {
 | 
			
		||||
            if (wasInFullscreen[i] != this._monitors[i].inFullscreen) {
 | 
			
		||||
                changed = true;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (changed) {
 | 
			
		||||
            this._updateVisibility();
 | 
			
		||||
            this._queueUpdateRegions();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    updateRegions: function() {
 | 
			
		||||
        let rects = [], struts = [], i;
 | 
			
		||||
 | 
			
		||||
        if (this._updateRegionIdle) {
 | 
			
		||||
            Mainloop.source_remove(this._updateRegionIdle);
 | 
			
		||||
            delete this._updateRegionIdle;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (i = 0; i < this._trackedActors.length; i++) {
 | 
			
		||||
            let actorData = this._trackedActors[i];
 | 
			
		||||
            if (!actorData.affectsInputRegion && !actorData.affectsStruts)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            let [x, y] = actorData.actor.get_transformed_position();
 | 
			
		||||
            let [w, h] = actorData.actor.get_transformed_size();
 | 
			
		||||
            x = Math.round(x);
 | 
			
		||||
            y = Math.round(y);
 | 
			
		||||
            w = Math.round(w);
 | 
			
		||||
            h = Math.round(h);
 | 
			
		||||
            let rect = new Meta.Rectangle({ x: x, y: y, width: w, height: h});
 | 
			
		||||
 | 
			
		||||
            if (actorData.affectsInputRegion &&
 | 
			
		||||
                actorData.actor.get_paint_visibility() &&
 | 
			
		||||
                !Main.uiGroup.get_skip_paint(actorData.actor))
 | 
			
		||||
                rects.push(rect);
 | 
			
		||||
 | 
			
		||||
            if (!actorData.affectsStruts)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            // Limit struts to the size of the screen
 | 
			
		||||
            let x1 = Math.max(x, 0);
 | 
			
		||||
            let x2 = Math.min(x + w, global.screen_width);
 | 
			
		||||
            let y1 = Math.max(y, 0);
 | 
			
		||||
            let y2 = Math.min(y + h, global.screen_height);
 | 
			
		||||
 | 
			
		||||
            // NetWM struts are not really powerful enought to handle
 | 
			
		||||
            // a multi-monitor scenario, they only describe what happens
 | 
			
		||||
            // around the outer sides of the full display region. However
 | 
			
		||||
            // it can describe a partial region along each side, so
 | 
			
		||||
            // we can support having the struts only affect the
 | 
			
		||||
            // primary monitor. This should be enough as we only have
 | 
			
		||||
            // chrome affecting the struts on the primary monitor so
 | 
			
		||||
            // far.
 | 
			
		||||
            //
 | 
			
		||||
            // Metacity wants to know what side of the screen the
 | 
			
		||||
            // strut is considered to be attached to. If the actor is
 | 
			
		||||
            // only touching one edge, or is touching the entire
 | 
			
		||||
            // border of the primary monitor, then it's obvious which
 | 
			
		||||
            // side to call it. If it's in a corner, we pick a side
 | 
			
		||||
            // arbitrarily. If it doesn't touch any edges, or it spans
 | 
			
		||||
            // the width/height across the middle of the screen, then
 | 
			
		||||
            // we don't create a strut for it at all.
 | 
			
		||||
            let side;
 | 
			
		||||
            let primary = this._primaryMonitor;
 | 
			
		||||
            if (x1 <= primary.x && x2 >= primary.x + primary.width) {
 | 
			
		||||
                if (y1 <= primary.y)
 | 
			
		||||
                    side = Meta.Side.TOP;
 | 
			
		||||
                else if (y2 >= primary.y + primary.height)
 | 
			
		||||
                    side = Meta.Side.BOTTOM;
 | 
			
		||||
                else
 | 
			
		||||
                    continue;
 | 
			
		||||
            } else if (y1 <= primary.y && y2 >= primary.y + primary.height) {
 | 
			
		||||
                if (x1 <= 0)
 | 
			
		||||
                    side = Meta.Side.LEFT;
 | 
			
		||||
                else if (x2 >= global.screen_width)
 | 
			
		||||
                    side = Meta.Side.RIGHT;
 | 
			
		||||
                else
 | 
			
		||||
                    continue;
 | 
			
		||||
            } else if (x1 <= 0)
 | 
			
		||||
                side = Meta.Side.LEFT;
 | 
			
		||||
            else if (y1 <= 0)
 | 
			
		||||
                side = Meta.Side.TOP;
 | 
			
		||||
            else if (x2 >= global.screen_width)
 | 
			
		||||
                side = Meta.Side.RIGHT;
 | 
			
		||||
            else if (y2 >= global.screen_height)
 | 
			
		||||
                side = Meta.Side.BOTTOM;
 | 
			
		||||
            else
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            // Ensure that the strut rects goes all the way to the screen edge,
 | 
			
		||||
            // as this really what mutter expects.
 | 
			
		||||
            switch (side) {
 | 
			
		||||
            case Meta.Side.TOP:
 | 
			
		||||
                y1 = 0;
 | 
			
		||||
                break;
 | 
			
		||||
            case Meta.Side.BOTTOM:
 | 
			
		||||
                y2 = global.screen_height;
 | 
			
		||||
                break;
 | 
			
		||||
            case Meta.Side.LEFT:
 | 
			
		||||
                x1 = 0;
 | 
			
		||||
                break;
 | 
			
		||||
            case Meta.Side.RIGHT:
 | 
			
		||||
                x2 = global.screen_width;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let strutRect = new Meta.Rectangle({ x: x1, y: y1, width: x2 - x1, height: y2 - y1});
 | 
			
		||||
            let strut = new Meta.Strut({ rect: strutRect, side: side });
 | 
			
		||||
            struts.push(strut);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        global.set_stage_input_region(rects);
 | 
			
		||||
 | 
			
		||||
        let screen = global.screen;
 | 
			
		||||
        for (let w = 0; w < screen.n_workspaces; w++) {
 | 
			
		||||
            let workspace = screen.get_workspace_by_index(w);
 | 
			
		||||
            workspace.set_builtin_struts(struts);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
@@ -30,11 +30,9 @@ const Tweener = imports.ui.tweener;
 | 
			
		||||
 * @container and will track any changes in its size. You can override
 | 
			
		||||
 * this by passing an explicit width and height in @params.
 | 
			
		||||
 */
 | 
			
		||||
function Lightbox(container, params) {
 | 
			
		||||
    this._init(container, params);
 | 
			
		||||
}
 | 
			
		||||
const Lightbox = new Lang.Class({
 | 
			
		||||
    Name: 'Lightbox',
 | 
			
		||||
 | 
			
		||||
Lightbox.prototype = {
 | 
			
		||||
    _init : function(container, params) {
 | 
			
		||||
        params = Params.parse(params, { inhibitEvents: false,
 | 
			
		||||
                                        width: null,
 | 
			
		||||
@@ -196,4 +194,4 @@ Lightbox.prototype = {
 | 
			
		||||
 | 
			
		||||
        this.highlight(null);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,12 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
function Link(props) {
 | 
			
		||||
    this._init(props);
 | 
			
		||||
}
 | 
			
		||||
const Link = new Lang.Class({
 | 
			
		||||
    Name: 'Link',
 | 
			
		||||
 | 
			
		||||
Link.prototype = {
 | 
			
		||||
    _init : function(props) {
 | 
			
		||||
        let realProps = { reactive: true,
 | 
			
		||||
                          track_hover: true,
 | 
			
		||||
@@ -19,6 +17,5 @@ Link.prototype = {
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.Button(realProps);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(Link.prototype);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,24 +1,25 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Cogl = imports.gi.Cogl;
 | 
			
		||||
const GConf = imports.gi.GConf;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const Pango = imports.gi.Pango;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
 | 
			
		||||
const History = imports.misc.history;
 | 
			
		||||
const ExtensionSystem = imports.ui.extensionSystem;
 | 
			
		||||
const Link = imports.ui.link;
 | 
			
		||||
const ShellEntry = imports.ui.shellEntry;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const JsParse = imports.misc.jsParse;
 | 
			
		||||
 | 
			
		||||
/* Imports...feel free to add here as needed */
 | 
			
		||||
var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
 | 
			
		||||
@@ -27,6 +28,7 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
 | 
			
		||||
                    'const Mainloop = imports.mainloop; ' +
 | 
			
		||||
                    'const Meta = imports.gi.Meta; ' +
 | 
			
		||||
                    'const Shell = imports.gi.Shell; ' +
 | 
			
		||||
                    'const Tp = imports.gi.TelepathyGLib; ' +
 | 
			
		||||
                    'const Main = imports.ui.main; ' +
 | 
			
		||||
                    'const Lang = imports.lang; ' +
 | 
			
		||||
                    'const Tweener = imports.ui.tweener; ' +
 | 
			
		||||
@@ -39,12 +41,88 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
 | 
			
		||||
                    'const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); ';
 | 
			
		||||
 | 
			
		||||
const HISTORY_KEY = 'looking-glass-history';
 | 
			
		||||
// Time between tabs for them to count as a double-tab event
 | 
			
		||||
const AUTO_COMPLETE_DOUBLE_TAB_DELAY = 500;
 | 
			
		||||
const AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION = 0.2;
 | 
			
		||||
const AUTO_COMPLETE_GLOBAL_KEYWORDS = _getAutoCompleteGlobalKeywords();
 | 
			
		||||
 | 
			
		||||
function Notebook() {
 | 
			
		||||
    this._init();
 | 
			
		||||
function _getAutoCompleteGlobalKeywords() {
 | 
			
		||||
    const keywords = ['true', 'false', 'null', 'new'];
 | 
			
		||||
    // Don't add the private properties of window (i.e., ones starting with '_')
 | 
			
		||||
    const windowProperties = Object.getOwnPropertyNames(window).filter(function(a){ return a.charAt(0) != '_' });
 | 
			
		||||
    const headerProperties = JsParse.getDeclaredConstants(commandHeader);
 | 
			
		||||
 | 
			
		||||
    return keywords.concat(windowProperties).concat(headerProperties);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Notebook.prototype = {
 | 
			
		||||
const AutoComplete = new Lang.Class({
 | 
			
		||||
    Name: 'AutoComplete',
 | 
			
		||||
 | 
			
		||||
    _init: function(entry) {
 | 
			
		||||
        this._entry = entry;
 | 
			
		||||
        this._entry.connect('key-press-event', Lang.bind(this, this._entryKeyPressEvent));
 | 
			
		||||
        this._lastTabTime = global.get_current_time();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _processCompletionRequest: function(event) {
 | 
			
		||||
        if (event.completions.length == 0) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // Unique match = go ahead and complete; multiple matches + single tab = complete the common starting string;
 | 
			
		||||
        // multiple matches + double tab = emit a suggest event with all possible options
 | 
			
		||||
        if (event.completions.length == 1) {
 | 
			
		||||
            this.additionalCompletionText(event.completions[0], event.attrHead);
 | 
			
		||||
            this.emit('completion', { completion: event.completions[0], type: 'whole-word' });
 | 
			
		||||
        } else if (event.completions.length > 1 && event.tabType === 'single') {
 | 
			
		||||
            let commonPrefix = JsParse.getCommonPrefix(event.completions);
 | 
			
		||||
 | 
			
		||||
            if (commonPrefix.length > 0) {
 | 
			
		||||
                this.additionalCompletionText(commonPrefix, event.attrHead);
 | 
			
		||||
                this.emit('completion', { completion: commonPrefix, type: 'prefix' });
 | 
			
		||||
                this.emit('suggest', { completions: event.completions});
 | 
			
		||||
            }
 | 
			
		||||
        } else if (event.completions.length > 1 && event.tabType === 'double') {
 | 
			
		||||
            this.emit('suggest', { completions: event.completions});
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _entryKeyPressEvent: function(actor, event) {
 | 
			
		||||
        let cursorPos = this._entry.clutter_text.get_cursor_position();
 | 
			
		||||
        let text = this._entry.get_text();
 | 
			
		||||
        if (cursorPos != -1) {
 | 
			
		||||
            text = text.slice(0, cursorPos);
 | 
			
		||||
        }
 | 
			
		||||
        if (event.get_key_symbol() == Clutter.Tab) {
 | 
			
		||||
            let [completions, attrHead] = JsParse.getCompletions(text, commandHeader, AUTO_COMPLETE_GLOBAL_KEYWORDS);
 | 
			
		||||
            let currTime = global.get_current_time();
 | 
			
		||||
            if ((currTime - this._lastTabTime) < AUTO_COMPLETE_DOUBLE_TAB_DELAY) {
 | 
			
		||||
                this._processCompletionRequest({ tabType: 'double',
 | 
			
		||||
                                                 completions: completions,
 | 
			
		||||
                                                 attrHead: attrHead });
 | 
			
		||||
            } else {
 | 
			
		||||
                this._processCompletionRequest({ tabType: 'single',
 | 
			
		||||
                                                 completions: completions,
 | 
			
		||||
                                                 attrHead: attrHead });
 | 
			
		||||
            }
 | 
			
		||||
            this._lastTabTime = currTime;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Insert characters of text not already included in head at cursor position.  i.e., if text="abc" and head="a",
 | 
			
		||||
    // the string "bc" will be appended to this._entry
 | 
			
		||||
    additionalCompletionText: function(text, head) {
 | 
			
		||||
        let additionalCompletionText = text.slice(head.length);
 | 
			
		||||
        let cursorPos = this._entry.clutter_text.get_cursor_position();
 | 
			
		||||
 | 
			
		||||
        this._entry.clutter_text.insert_text(additionalCompletionText, cursorPos);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(AutoComplete.prototype);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const Notebook = new Lang.Class({
 | 
			
		||||
    Name: 'Notebook',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.actor = new St.BoxLayout({ vertical: true });
 | 
			
		||||
 | 
			
		||||
@@ -99,12 +177,19 @@ Notebook.prototype = {
 | 
			
		||||
    selectIndex: function(index) {
 | 
			
		||||
        if (index == this._selectedIndex)
 | 
			
		||||
            return;
 | 
			
		||||
        this._unselect();
 | 
			
		||||
        if (index < 0) {
 | 
			
		||||
            this._unselect();
 | 
			
		||||
            this.emit('selection', null);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Focus the new tab before unmapping the old one
 | 
			
		||||
        let tabData = this._tabs[index];
 | 
			
		||||
        if (!tabData.scrollView.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false))
 | 
			
		||||
            this.actor.grab_key_focus();
 | 
			
		||||
 | 
			
		||||
        this._unselect();
 | 
			
		||||
 | 
			
		||||
        tabData.labelBox.add_style_pseudo_class('selected');
 | 
			
		||||
        tabData.scrollView.show();
 | 
			
		||||
        this._selectedIndex = index;
 | 
			
		||||
@@ -142,25 +227,40 @@ Notebook.prototype = {
 | 
			
		||||
            return;
 | 
			
		||||
        let vAdjust = tabData.scrollView.vscroll.adjustment;
 | 
			
		||||
        vAdjust.value = vAdjust.upper - vAdjust.page_size;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    nextTab: function() {
 | 
			
		||||
        let nextIndex = this._selectedIndex;
 | 
			
		||||
        if (nextIndex < this._tabs.length - 1) {
 | 
			
		||||
            ++nextIndex;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.selectIndex(nextIndex);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    prevTab: function() {
 | 
			
		||||
        let prevIndex = this._selectedIndex;
 | 
			
		||||
        if (prevIndex > 0) {
 | 
			
		||||
            --prevIndex;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.selectIndex(prevIndex);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(Notebook.prototype);
 | 
			
		||||
 | 
			
		||||
function objectToString(o) {
 | 
			
		||||
    if (typeof(o) == typeof(objectToString)) {
 | 
			
		||||
        // special case this since the default is way, way too verbose
 | 
			
		||||
        return "<js function>";
 | 
			
		||||
        return '<js function>';
 | 
			
		||||
    } else {
 | 
			
		||||
        return "" + o;
 | 
			
		||||
        return '' + o;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ObjLink(o, title) {
 | 
			
		||||
    this._init(o, title);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ObjLink.prototype = {
 | 
			
		||||
    __proto__: Link.Link,
 | 
			
		||||
const ObjLink = new Lang.Class({
 | 
			
		||||
    Name: 'ObjLink',
 | 
			
		||||
    Extends: Link.Link,
 | 
			
		||||
 | 
			
		||||
    _init: function(o, title) {
 | 
			
		||||
        let text;
 | 
			
		||||
@@ -170,7 +270,8 @@ ObjLink.prototype = {
 | 
			
		||||
            text = objectToString(o);
 | 
			
		||||
        text = GLib.markup_escape_text(text, -1);
 | 
			
		||||
        this._obj = o;
 | 
			
		||||
        Link.Link.prototype._init.call(this, { label: text });
 | 
			
		||||
 | 
			
		||||
        this.parent({ label: text });
 | 
			
		||||
        this.actor.get_child().single_line_mode = true;
 | 
			
		||||
        this.actor.connect('clicked', Lang.bind(this, this._onClicked));
 | 
			
		||||
    },
 | 
			
		||||
@@ -178,13 +279,11 @@ ObjLink.prototype = {
 | 
			
		||||
    _onClicked: function (link) {
 | 
			
		||||
        Main.lookingGlass.inspectObject(this._obj, this.actor);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function Result(command, o, index) {
 | 
			
		||||
    this._init(command, o, index);
 | 
			
		||||
}
 | 
			
		||||
const Result = new Lang.Class({
 | 
			
		||||
    Name: 'Result',
 | 
			
		||||
 | 
			
		||||
Result.prototype = {
 | 
			
		||||
    _init : function(command, o, index) {
 | 
			
		||||
        this.index = index;
 | 
			
		||||
        this.o = o;
 | 
			
		||||
@@ -206,19 +305,16 @@ Result.prototype = {
 | 
			
		||||
        padBin.add_actor(line);
 | 
			
		||||
        this.actor.add(padBin);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function WindowList() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const WindowList = new Lang.Class({
 | 
			
		||||
    Name: 'WindowList',
 | 
			
		||||
 | 
			
		||||
WindowList.prototype = {
 | 
			
		||||
    _init : function () {
 | 
			
		||||
        this.actor = new St.BoxLayout({ name: 'Windows', vertical: true, style: 'spacing: 8px' });
 | 
			
		||||
        let display = global.screen.get_display();
 | 
			
		||||
        let tracker = Shell.WindowTracker.get_default();
 | 
			
		||||
        this._updateId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._updateWindowList));
 | 
			
		||||
        display.connect('window-created', Lang.bind(this, this._updateWindowList));
 | 
			
		||||
        global.display.connect('window-created', Lang.bind(this, this._updateWindowList));
 | 
			
		||||
        tracker.connect('tracked-windows-changed', Lang.bind(this, this._updateWindowList));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -241,7 +337,7 @@ WindowList.prototype = {
 | 
			
		||||
            box.add(propsBox);
 | 
			
		||||
            propsBox.add(new St.Label({ text: 'wmclass: ' + metaWindow.get_wm_class() }));
 | 
			
		||||
            let app = tracker.get_window_app(metaWindow);
 | 
			
		||||
            if (app != null && !app.is_transient()) {
 | 
			
		||||
            if (app != null && !app.is_window_backed()) {
 | 
			
		||||
                let icon = app.create_icon_texture(22);
 | 
			
		||||
                let propBox = new St.BoxLayout({ style: 'spacing: 6px; ' });
 | 
			
		||||
                propsBox.add(propBox);
 | 
			
		||||
@@ -254,14 +350,12 @@ WindowList.prototype = {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(WindowList.prototype);
 | 
			
		||||
 | 
			
		||||
function ObjInspector() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const ObjInspector = new Lang.Class({
 | 
			
		||||
    Name: 'ObjInspector',
 | 
			
		||||
 | 
			
		||||
ObjInspector.prototype = {
 | 
			
		||||
    _init : function () {
 | 
			
		||||
        this._obj = null;
 | 
			
		||||
        this._previousObj = null;
 | 
			
		||||
@@ -315,7 +409,7 @@ ObjInspector.prototype = {
 | 
			
		||||
                    link = new St.Label({ text: '<error>' });
 | 
			
		||||
                }
 | 
			
		||||
                let hbox = new St.BoxLayout();
 | 
			
		||||
                let propText = propName + ": " + valueStr;
 | 
			
		||||
                let propText = propName + ': ' + valueStr;
 | 
			
		||||
                hbox.add(new St.Label({ text: propName + ': ' }));
 | 
			
		||||
                hbox.add(link);
 | 
			
		||||
                this._container.add_actor(hbox);
 | 
			
		||||
@@ -336,7 +430,7 @@ ObjInspector.prototype = {
 | 
			
		||||
            this.actor.move_anchor_point(Math.floor(sourceX + sourceWidth / 2),
 | 
			
		||||
                                         Math.floor(sourceY + sourceHeight / 2));
 | 
			
		||||
            Tweener.addTween(this.actor, { scale_x: 1, scale_y: 1,
 | 
			
		||||
                                           transition: "easeOutQuad",
 | 
			
		||||
                                           transition: 'easeOutQuad',
 | 
			
		||||
                                           time: 0.2 });
 | 
			
		||||
        } else {
 | 
			
		||||
            this.actor.set_scale(1, 1);
 | 
			
		||||
@@ -361,7 +455,7 @@ ObjInspector.prototype = {
 | 
			
		||||
    _onBack: function() {
 | 
			
		||||
        this.selectObject(this._previousObj, true);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function addBorderPaintHook(actor) {
 | 
			
		||||
    let signalId = actor.connect_after('paint',
 | 
			
		||||
@@ -387,11 +481,9 @@ function addBorderPaintHook(actor) {
 | 
			
		||||
    return signalId;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function Inspector() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const Inspector = new Lang.Class({
 | 
			
		||||
    Name: 'Inspector',
 | 
			
		||||
 | 
			
		||||
Inspector.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        let container = new Shell.GenericContainer({ width: 0,
 | 
			
		||||
                                                     height: 0 });
 | 
			
		||||
@@ -429,7 +521,7 @@ Inspector.prototype = {
 | 
			
		||||
        if (!this._eventHandler)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let primary = global.get_primary_monitor();
 | 
			
		||||
        let primary = Main.layoutManager.primaryMonitor;
 | 
			
		||||
 | 
			
		||||
        let [minWidth, minHeight, natWidth, natHeight] =
 | 
			
		||||
            this._eventHandler.get_preferred_size();
 | 
			
		||||
@@ -530,15 +622,13 @@ Inspector.prototype = {
 | 
			
		||||
            this._borderPaintId = addBorderPaintHook(this._target);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(Inspector.prototype);
 | 
			
		||||
 | 
			
		||||
function ErrorLog() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const ErrorLog = new Lang.Class({
 | 
			
		||||
    Name: 'ErrorLog',
 | 
			
		||||
 | 
			
		||||
ErrorLog.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.actor = new St.BoxLayout();
 | 
			
		||||
        this.text = new St.Label();
 | 
			
		||||
@@ -573,35 +663,91 @@ ErrorLog.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
        this.text.text = text;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function Extensions() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const Memory = new Lang.Class({
 | 
			
		||||
    Name: 'Memory',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.actor = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        this._glibc_uordblks = new St.Label();
 | 
			
		||||
        this.actor.add(this._glibc_uordblks);
 | 
			
		||||
 | 
			
		||||
        this._js_bytes = new St.Label();
 | 
			
		||||
        this.actor.add(this._js_bytes);
 | 
			
		||||
 | 
			
		||||
        this._gjs_boxed = new St.Label();
 | 
			
		||||
        this.actor.add(this._gjs_boxed);
 | 
			
		||||
 | 
			
		||||
        this._gjs_gobject = new St.Label();
 | 
			
		||||
        this.actor.add(this._gjs_gobject);
 | 
			
		||||
 | 
			
		||||
        this._gjs_function = new St.Label();
 | 
			
		||||
        this.actor.add(this._gjs_function);
 | 
			
		||||
 | 
			
		||||
        this._gjs_closure = new St.Label();
 | 
			
		||||
        this.actor.add(this._gjs_closure);
 | 
			
		||||
 | 
			
		||||
        this._last_gc_seconds_ago = new St.Label();
 | 
			
		||||
        this.actor.add(this._last_gc_seconds_ago);
 | 
			
		||||
 | 
			
		||||
        this._gcbutton = new St.Button({ label: 'Full GC',
 | 
			
		||||
                                         style_class: 'lg-obj-inspector-button' });
 | 
			
		||||
        this._gcbutton.connect('clicked', Lang.bind(this, function () { global.gc(); this._renderText(); }));
 | 
			
		||||
        this.actor.add(this._gcbutton, { x_align: St.Align.START,
 | 
			
		||||
                                         x_fill: false });
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('notify::mapped', Lang.bind(this, this._renderText));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _renderText: function() {
 | 
			
		||||
        if (!this.actor.mapped)
 | 
			
		||||
            return;
 | 
			
		||||
        let memInfo = global.get_memory_info();
 | 
			
		||||
        this._glibc_uordblks.text = 'glibc_uordblks: ' + memInfo.glibc_uordblks;
 | 
			
		||||
        this._js_bytes.text = 'js bytes: ' + memInfo.js_bytes;
 | 
			
		||||
        this._gjs_boxed.text = 'gjs_boxed: ' + memInfo.gjs_boxed;
 | 
			
		||||
        this._gjs_gobject.text = 'gjs_gobject: ' + memInfo.gjs_gobject;
 | 
			
		||||
        this._gjs_function.text = 'gjs_function: ' + memInfo.gjs_function;
 | 
			
		||||
        this._gjs_closure.text = 'gjs_closure: ' + memInfo.gjs_closure;
 | 
			
		||||
        this._last_gc_seconds_ago.text = 'last_gc_seconds_ago: ' + memInfo.last_gc_seconds_ago;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const Extensions = new Lang.Class({
 | 
			
		||||
    Name: 'Extensions',
 | 
			
		||||
 | 
			
		||||
Extensions.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.actor = new St.BoxLayout({ vertical: true,
 | 
			
		||||
                                        name: 'lookingGlassExtensions' });
 | 
			
		||||
        this._noExtensions = new St.Label({ style_class: 'lg-extensions-none',
 | 
			
		||||
                                             text: _("No extensions installed") });
 | 
			
		||||
        this._numExtensions = 0;
 | 
			
		||||
        this._extensionsList = new St.BoxLayout({ vertical: true,
 | 
			
		||||
                                                  style_class: 'lg-extensions-list' });
 | 
			
		||||
        this._extensionsList.add(this._noExtensions);
 | 
			
		||||
        this.actor.add(this._extensionsList);
 | 
			
		||||
        this._loadExtensionList();
 | 
			
		||||
 | 
			
		||||
        for (let uuid in ExtensionSystem.extensionMeta)
 | 
			
		||||
            this._loadExtension(null, uuid);
 | 
			
		||||
 | 
			
		||||
        ExtensionSystem.connect('extension-loaded',
 | 
			
		||||
                                Lang.bind(this, this._loadExtension));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _loadExtensionList: function() {
 | 
			
		||||
        let extensions = ExtensionSystem.extensionMeta;
 | 
			
		||||
        let totalExtensions = 0;
 | 
			
		||||
        for (let uuid in extensions) {
 | 
			
		||||
            let extensionDisplay = this._createExtensionDisplay(extensions[uuid]);
 | 
			
		||||
            this._extensionsList.add(extensionDisplay);
 | 
			
		||||
            totalExtensions++;
 | 
			
		||||
        }
 | 
			
		||||
        if (totalExtensions == 0) {
 | 
			
		||||
            this._extensionsList.add(this._noExtensions);
 | 
			
		||||
        }
 | 
			
		||||
    _loadExtension: function(o, uuid) {
 | 
			
		||||
        let extension = ExtensionSystem.extensionMeta[uuid];
 | 
			
		||||
        // There can be cases where we create dummy extension metadata
 | 
			
		||||
        // that's not really a proper extension. Don't bother with these.
 | 
			
		||||
        if (!extension.name)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let extensionDisplay = this._createExtensionDisplay(extension);
 | 
			
		||||
        if (this._numExtensions == 0)
 | 
			
		||||
            this._extensionsList.remove_actor(this._noExtensions);
 | 
			
		||||
 | 
			
		||||
        this._numExtensions ++;
 | 
			
		||||
        this._extensionsList.add(extensionDisplay);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onViewSource: function (actor) {
 | 
			
		||||
@@ -618,16 +764,47 @@ Extensions.prototype = {
 | 
			
		||||
        Main.lookingGlass.close();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onViewErrors: function (actor) {
 | 
			
		||||
        let meta = actor._extensionMeta;
 | 
			
		||||
        let shouldShow = !actor._isShowing;
 | 
			
		||||
 | 
			
		||||
        if (shouldShow) {
 | 
			
		||||
            let errors = ExtensionSystem.errors[meta.uuid];
 | 
			
		||||
            let errorDisplay = new St.BoxLayout({ vertical: true });
 | 
			
		||||
            if (errors && errors.length) {
 | 
			
		||||
                for (let i = 0; i < errors.length; i ++)
 | 
			
		||||
                    errorDisplay.add(new St.Label({ text: errors[i] }));
 | 
			
		||||
            } else {
 | 
			
		||||
                /* Translators: argument is an extension UUID. */
 | 
			
		||||
                let message = _("%s has not emitted any errors.").format(meta.uuid);
 | 
			
		||||
                errorDisplay.add(new St.Label({ text: message }));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            actor._errorDisplay = errorDisplay;
 | 
			
		||||
            actor._parentBox.add(errorDisplay);
 | 
			
		||||
            actor.label = _("Hide Errors");
 | 
			
		||||
        } else {
 | 
			
		||||
            actor._errorDisplay.destroy();
 | 
			
		||||
            actor._errorDisplay = null;
 | 
			
		||||
            actor.label = _("Show Errors");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        actor._isShowing = shouldShow;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _stateToString: function(extensionState) {
 | 
			
		||||
        switch (extensionState) {
 | 
			
		||||
            case ExtensionSystem.ExtensionState.ENABLED:
 | 
			
		||||
                return _("Enabled");
 | 
			
		||||
            case ExtensionSystem.ExtensionState.DISABLED:
 | 
			
		||||
            case ExtensionSystem.ExtensionState.INITIALIZED:
 | 
			
		||||
                return _("Disabled");
 | 
			
		||||
            case ExtensionSystem.ExtensionState.ERROR:
 | 
			
		||||
                return _("Error");
 | 
			
		||||
            case ExtensionSystem.ExtensionState.OUT_OF_DATE:
 | 
			
		||||
                return _("Out of date");
 | 
			
		||||
            case ExtensionSystem.ExtensionState.DOWNLOADING:
 | 
			
		||||
                return _("Downloading");
 | 
			
		||||
        }
 | 
			
		||||
        return 'Unknown'; // Not translated, shouldn't appear
 | 
			
		||||
    },
 | 
			
		||||
@@ -638,41 +815,42 @@ Extensions.prototype = {
 | 
			
		||||
                                   text: meta.name });
 | 
			
		||||
        box.add(name, { expand: true });
 | 
			
		||||
        let description = new St.Label({ style_class: 'lg-extension-description',
 | 
			
		||||
                                         text: meta.description });
 | 
			
		||||
                                         text: meta.description || 'No description' });
 | 
			
		||||
        box.add(description, { expand: true });
 | 
			
		||||
 | 
			
		||||
        let metaBox = new St.BoxLayout();
 | 
			
		||||
        let metaBox = new St.BoxLayout({ style_class: 'lg-extension-meta' });
 | 
			
		||||
        box.add(metaBox);
 | 
			
		||||
        let stateString = this._stateToString(meta.state);
 | 
			
		||||
        let state = new St.Label({ style_class: 'lg-extension-state',
 | 
			
		||||
                                   text: this._stateToString(meta.state) });
 | 
			
		||||
 | 
			
		||||
        let actionsContainer = new St.Bin({ x_align: St.Align.END });
 | 
			
		||||
        metaBox.add(actionsContainer);
 | 
			
		||||
        let actionsBox = new St.BoxLayout({ style_class: 'lg-extension-actions' });
 | 
			
		||||
        actionsContainer.set_child(actionsBox);
 | 
			
		||||
        metaBox.add(state);
 | 
			
		||||
 | 
			
		||||
        let viewsource = new Link.Link({ label: _("View Source") });
 | 
			
		||||
        viewsource.actor._extensionMeta = meta;
 | 
			
		||||
        viewsource.actor.connect('clicked', Lang.bind(this, this._onViewSource));
 | 
			
		||||
        actionsBox.add(viewsource.actor);
 | 
			
		||||
        metaBox.add(viewsource.actor);
 | 
			
		||||
 | 
			
		||||
        if (meta.url) {
 | 
			
		||||
            let webpage = new Link.Link({ label: _("Web Page") });
 | 
			
		||||
            webpage.actor._extensionMeta = meta;
 | 
			
		||||
            webpage.actor.connect('clicked', Lang.bind(this, this._onWebPage));
 | 
			
		||||
            actionsBox.add(webpage.actor);
 | 
			
		||||
            metaBox.add(webpage.actor);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let viewerrors = new Link.Link({ label: _("Show Errors") });
 | 
			
		||||
        viewerrors.actor._extensionMeta = meta;
 | 
			
		||||
        viewerrors.actor._parentBox = box;
 | 
			
		||||
        viewerrors.actor._isShowing = false;
 | 
			
		||||
        viewerrors.actor.connect('clicked', Lang.bind(this, this._onViewErrors));
 | 
			
		||||
        metaBox.add(viewerrors.actor);
 | 
			
		||||
 | 
			
		||||
        return box;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function LookingGlass() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const LookingGlass = new Lang.Class({
 | 
			
		||||
    Name: 'LookingGlass',
 | 
			
		||||
 | 
			
		||||
LookingGlass.prototype = {
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        this._borderPaintTarget = null;
 | 
			
		||||
        this._borderPaintId = 0;
 | 
			
		||||
@@ -689,7 +867,8 @@ LookingGlass.prototype = {
 | 
			
		||||
        this.actor = new St.BoxLayout({ name: 'LookingGlassDialog',
 | 
			
		||||
                                        style_class: 'lg-dialog',
 | 
			
		||||
                                        vertical: true,
 | 
			
		||||
                                        visible: false });
 | 
			
		||||
                                        visible: false,
 | 
			
		||||
                                        reactive: true });
 | 
			
		||||
        this.actor.connect('key-press-event', Lang.bind(this, this._globalKeyPressEvent));
 | 
			
		||||
 | 
			
		||||
        this._interfaceSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
 | 
			
		||||
@@ -697,7 +876,13 @@ LookingGlass.prototype = {
 | 
			
		||||
                                        Lang.bind(this, this._updateFont));
 | 
			
		||||
        this._updateFont();
 | 
			
		||||
 | 
			
		||||
        Main.uiGroup.add_actor(this.actor);
 | 
			
		||||
        // We want it to appear to slide out from underneath the panel
 | 
			
		||||
        Main.layoutManager.panelBox.add_actor(this.actor);
 | 
			
		||||
        this.actor.lower_bottom();
 | 
			
		||||
        Main.layoutManager.panelBox.connect('allocation-changed',
 | 
			
		||||
                                            Lang.bind(this, this._queueResize));
 | 
			
		||||
        Main.layoutManager.keyboardBox.connect('allocation-changed',
 | 
			
		||||
                                               Lang.bind(this, this._queueResize));
 | 
			
		||||
 | 
			
		||||
        this._objInspector = new ObjInspector();
 | 
			
		||||
        Main.uiGroup.add_actor(this._objInspector.actor);
 | 
			
		||||
@@ -706,6 +891,7 @@ LookingGlass.prototype = {
 | 
			
		||||
        let toolbar = new St.BoxLayout({ name: 'Toolbar' });
 | 
			
		||||
        this.actor.add_actor(toolbar);
 | 
			
		||||
        let inspectIcon = new St.Icon({ icon_name: 'gtk-color-picker',
 | 
			
		||||
                                        icon_type: St.IconType.FULLCOLOR,
 | 
			
		||||
                                        icon_size: 24 });
 | 
			
		||||
        toolbar.add_actor(inspectIcon);
 | 
			
		||||
        inspectIcon.reactive = true;
 | 
			
		||||
@@ -737,19 +923,15 @@ LookingGlass.prototype = {
 | 
			
		||||
        this._resultsArea = new St.BoxLayout({ name: 'ResultsArea', vertical: true });
 | 
			
		||||
        this._evalBox.add(this._resultsArea, { expand: true });
 | 
			
		||||
 | 
			
		||||
        let entryArea = new St.BoxLayout({ name: 'EntryArea' });
 | 
			
		||||
        this._evalBox.add_actor(entryArea);
 | 
			
		||||
        this._entryArea = new St.BoxLayout({ name: 'EntryArea' });
 | 
			
		||||
        this._evalBox.add_actor(this._entryArea);
 | 
			
		||||
 | 
			
		||||
        let label = new St.Label({ text: 'js>>> ' });
 | 
			
		||||
        entryArea.add(label);
 | 
			
		||||
        this._entryArea.add(label);
 | 
			
		||||
 | 
			
		||||
        this._entry = new St.Entry();
 | 
			
		||||
        /* unmapping the edit box will un-focus it, undo that */
 | 
			
		||||
        notebook.connect('selection', Lang.bind(this, function (nb, child) {
 | 
			
		||||
            if (child == this._evalBox)
 | 
			
		||||
                global.stage.set_key_focus(this._entry);
 | 
			
		||||
        }));
 | 
			
		||||
        entryArea.add(this._entry, { expand: true });
 | 
			
		||||
        this._entry = new St.Entry({ can_focus: true });
 | 
			
		||||
        ShellEntry.addContextMenu(this._entry);
 | 
			
		||||
        this._entryArea.add(this._entry, { expand: true });
 | 
			
		||||
 | 
			
		||||
        this._windowList = new WindowList();
 | 
			
		||||
        this._windowList.connect('selected', Lang.bind(this, function(list, window) {
 | 
			
		||||
@@ -761,10 +943,16 @@ LookingGlass.prototype = {
 | 
			
		||||
        this._errorLog = new ErrorLog();
 | 
			
		||||
        notebook.appendPage('Errors', this._errorLog.actor);
 | 
			
		||||
 | 
			
		||||
        this._memory = new Memory();
 | 
			
		||||
        notebook.appendPage('Memory', this._memory.actor);
 | 
			
		||||
 | 
			
		||||
        this._extensions = new Extensions();
 | 
			
		||||
        notebook.appendPage('Extensions', this._extensions.actor);
 | 
			
		||||
 | 
			
		||||
        this._entry.clutter_text.connect('activate', Lang.bind(this, function (o, e) {
 | 
			
		||||
            // Hide any completions we are currently showing
 | 
			
		||||
            this._hideCompletions();
 | 
			
		||||
 | 
			
		||||
            let text = o.get_text();
 | 
			
		||||
            // Ensure we don't get newlines in the command; the history file is
 | 
			
		||||
            // newline-separated.
 | 
			
		||||
@@ -777,23 +965,21 @@ LookingGlass.prototype = {
 | 
			
		||||
            return true;
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        this._history = new History.HistoryManager(HISTORY_KEY);
 | 
			
		||||
        this._history.connect('changed', Lang.bind(this, function(history, text) {
 | 
			
		||||
            this._entry.text = text;
 | 
			
		||||
        this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY, 
 | 
			
		||||
                                                     entry: this._entry.clutter_text });
 | 
			
		||||
 | 
			
		||||
        this._autoComplete = new AutoComplete(this._entry);
 | 
			
		||||
        this._autoComplete.connect('suggest', Lang.bind(this, function(a,e) {
 | 
			
		||||
            this._showCompletions(e.completions);
 | 
			
		||||
        }));
 | 
			
		||||
        // If a completion is completed unambiguously, the currently-displayed completion
 | 
			
		||||
        // suggestions become irrelevant.
 | 
			
		||||
        this._autoComplete.connect('completion', Lang.bind(this, function(a,e) {
 | 
			
		||||
            if (e.type == 'whole-word')
 | 
			
		||||
                this._hideCompletions();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        this._entry.clutter_text.connect('key-press-event', Lang.bind(this, function(o, e) {
 | 
			
		||||
            let symbol = e.get_key_symbol();
 | 
			
		||||
            if (symbol == Clutter.Up) {
 | 
			
		||||
                this._history.prevItem(o.get_text());
 | 
			
		||||
                return true;
 | 
			
		||||
            } else if (symbol == Clutter.Down) {
 | 
			
		||||
                this._history.nextItem(o.get_text());
 | 
			
		||||
                return true;
 | 
			
		||||
            } else {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }));
 | 
			
		||||
        this._resize();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateFont: function() {
 | 
			
		||||
@@ -837,6 +1023,59 @@ LookingGlass.prototype = {
 | 
			
		||||
        this._notebook.scrollToBottom(0);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showCompletions: function(completions) {
 | 
			
		||||
        if (!this._completionActor) {
 | 
			
		||||
            let actor = new St.BoxLayout({ vertical: true });
 | 
			
		||||
 | 
			
		||||
            this._completionText = new St.Label({ name: 'LookingGlassAutoCompletionText', style_class: 'lg-completions-text' });
 | 
			
		||||
            this._completionText.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
 | 
			
		||||
            this._completionText.clutter_text.line_wrap = true;
 | 
			
		||||
            actor.add(this._completionText);
 | 
			
		||||
 | 
			
		||||
            let line = new Clutter.Rectangle();
 | 
			
		||||
            let padBin = new St.Bin({ x_fill: true, y_fill: true });
 | 
			
		||||
            padBin.add_actor(line);
 | 
			
		||||
            actor.add(padBin);
 | 
			
		||||
 | 
			
		||||
            this._completionActor = actor;
 | 
			
		||||
            this._evalBox.insert_before(this._completionActor, this._entryArea);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._completionText.set_text(completions.join(', '));
 | 
			
		||||
 | 
			
		||||
        // Setting the height to -1 allows us to get its actual preferred height rather than
 | 
			
		||||
        // whatever was last given in set_height by Tweener.
 | 
			
		||||
        this._completionActor.set_height(-1);
 | 
			
		||||
        let [minHeight, naturalHeight] = this._completionText.get_preferred_height(this._resultsArea.get_width());
 | 
			
		||||
 | 
			
		||||
        // Don't reanimate if we are already visible
 | 
			
		||||
        if (this._completionActor.visible) {
 | 
			
		||||
            this._completionActor.height = naturalHeight;
 | 
			
		||||
        } else {
 | 
			
		||||
            this._completionActor.show();
 | 
			
		||||
            Tweener.removeTweens(this._completionActor);
 | 
			
		||||
            Tweener.addTween(this._completionActor, { time: AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION / St.get_slow_down_factor(),
 | 
			
		||||
                                                      transition: 'easeOutQuad',
 | 
			
		||||
                                                      height: naturalHeight,
 | 
			
		||||
                                                      opacity: 255
 | 
			
		||||
                                                    });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _hideCompletions: function() {
 | 
			
		||||
        if (this._completionActor) {
 | 
			
		||||
            Tweener.removeTweens(this._completionActor);
 | 
			
		||||
            Tweener.addTween(this._completionActor, { time: AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION / St.get_slow_down_factor(),
 | 
			
		||||
                                                      transition: 'easeOutQuad',
 | 
			
		||||
                                                      height: 0,
 | 
			
		||||
                                                      opacity: 0,
 | 
			
		||||
                                                      onComplete: Lang.bind(this, function () {
 | 
			
		||||
                                                          this._completionActor.hide();
 | 
			
		||||
                                                      })
 | 
			
		||||
                                                    });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _evaluate : function(command) {
 | 
			
		||||
        this._history.addItem(command);
 | 
			
		||||
 | 
			
		||||
@@ -868,13 +1107,18 @@ LookingGlass.prototype = {
 | 
			
		||||
            this.open();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _resizeTo: function(actor) {
 | 
			
		||||
        let primary = global.get_primary_monitor();
 | 
			
		||||
    _queueResize: function() {
 | 
			
		||||
        Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
 | 
			
		||||
                       Lang.bind(this, function () { this._resize(); }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _resize: function() {
 | 
			
		||||
        let primary = Main.layoutManager.primaryMonitor;
 | 
			
		||||
        let myWidth = primary.width * 0.7;
 | 
			
		||||
        let myHeight = primary.height * 0.7;
 | 
			
		||||
        let [srcX, srcY] = actor.get_transformed_position();
 | 
			
		||||
        this.actor.x = srcX + (primary.width - myWidth) / 2;
 | 
			
		||||
        this._hiddenY = srcY + actor.height - myHeight - 4; // -4 to hide the top corners
 | 
			
		||||
        let availableHeight = primary.height - Main.layoutManager.keyboardBox.height;
 | 
			
		||||
        let myHeight = Math.min(primary.height * 0.7, availableHeight * 0.9);
 | 
			
		||||
        this.actor.x = (primary.width - myWidth) / 2;
 | 
			
		||||
        this._hiddenY = this.actor.get_parent().height - myHeight - 4; // -4 to hide the top corners
 | 
			
		||||
        this._targetY = this._hiddenY + myHeight;
 | 
			
		||||
        this.actor.y = this._hiddenY;
 | 
			
		||||
        this.actor.width = myWidth;
 | 
			
		||||
@@ -884,14 +1128,6 @@ LookingGlass.prototype = {
 | 
			
		||||
                                              this._targetY + Math.floor(myHeight * 0.1));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    slaveTo: function(actor) {
 | 
			
		||||
        this._slaveTo = actor;
 | 
			
		||||
        actor.connect('notify::allocation', Lang.bind(this, function () {
 | 
			
		||||
            this._resizeTo(actor);
 | 
			
		||||
        }));
 | 
			
		||||
        this._resizeTo(actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    insertObject: function(obj) {
 | 
			
		||||
        this._pushResult('<insert>', obj);
 | 
			
		||||
    },
 | 
			
		||||
@@ -904,6 +1140,7 @@ LookingGlass.prototype = {
 | 
			
		||||
    // Handle key events which are relevant for all tabs of the LookingGlass
 | 
			
		||||
    _globalKeyPressEvent : function(actor, event) {
 | 
			
		||||
        let symbol = event.get_key_symbol();
 | 
			
		||||
        let modifierState = Shell.get_event_state(event);
 | 
			
		||||
        if (symbol == Clutter.Escape) {
 | 
			
		||||
            if (this._objInspector.actor.visible) {
 | 
			
		||||
                this._objInspector.close();
 | 
			
		||||
@@ -912,6 +1149,14 @@ LookingGlass.prototype = {
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        // Ctrl+PgUp and Ctrl+PgDown switches tabs in the notebook view
 | 
			
		||||
        if (modifierState & Clutter.ModifierType.CONTROL_MASK) {
 | 
			
		||||
            if (symbol == Clutter.KEY_Page_Up) {
 | 
			
		||||
                this._notebook.prevTab();
 | 
			
		||||
            } else if (symbol == Clutter.KEY_Page_Down) {
 | 
			
		||||
                this._notebook.nextTab();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -922,8 +1167,8 @@ LookingGlass.prototype = {
 | 
			
		||||
        if (!Main.pushModal(this._entry))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._notebook.selectIndex(0);
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
        this.actor.lower(Main.chrome.actor);
 | 
			
		||||
        this._open = true;
 | 
			
		||||
        this._history.lastItem();
 | 
			
		||||
 | 
			
		||||
@@ -962,5 +1207,5 @@ LookingGlass.prototype = {
 | 
			
		||||
                                       })
 | 
			
		||||
                                     });
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(LookingGlass.prototype);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const GDesktopEnums = imports.gi.GDesktopEnums;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
@@ -12,22 +13,6 @@ const Main = imports.ui.main;
 | 
			
		||||
const MagnifierDBus = imports.ui.magnifierDBus;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
 | 
			
		||||
// Keep enums in sync with GSettings schemas
 | 
			
		||||
const MouseTrackingMode = {
 | 
			
		||||
    NONE: 0,
 | 
			
		||||
    CENTERED: 1,
 | 
			
		||||
    PROPORTIONAL: 2,
 | 
			
		||||
    PUSH: 3
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const ScreenPosition = {
 | 
			
		||||
    NONE: 0,
 | 
			
		||||
    FULL_SCREEN: 1,
 | 
			
		||||
    TOP_HALF: 2,
 | 
			
		||||
    BOTTOM_HALF: 3,
 | 
			
		||||
    LEFT_HALF: 4,
 | 
			
		||||
    RIGHT_HALF: 5
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const MOUSE_POLL_FREQUENCY = 50;
 | 
			
		||||
const CROSSHAIRS_CLIP_SIZE = [100, 100];
 | 
			
		||||
@@ -51,11 +36,9 @@ const CROSS_HAIRS_CLIP_KEY      = 'cross-hairs-clip';
 | 
			
		||||
 | 
			
		||||
let magDBusService = null;
 | 
			
		||||
 | 
			
		||||
function Magnifier() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const Magnifier = new Lang.Class({
 | 
			
		||||
    Name: 'Magnifier',
 | 
			
		||||
 | 
			
		||||
Magnifier.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        // Magnifier is a manager of ZoomRegions.
 | 
			
		||||
        this._zoomRegions = [];
 | 
			
		||||
@@ -520,7 +503,7 @@ Magnifier.prototype = {
 | 
			
		||||
        if (this._zoomRegions.length) {
 | 
			
		||||
            let position = this._settings.get_enum(SCREEN_POSITION_KEY);
 | 
			
		||||
            this._zoomRegions[0].setScreenPosition(position);
 | 
			
		||||
            if (position != ScreenPosition.FULL_SCREEN)
 | 
			
		||||
            if (position != GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN)
 | 
			
		||||
                this._updateLensMode();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
@@ -558,21 +541,19 @@ Magnifier.prototype = {
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(Magnifier.prototype);
 | 
			
		||||
 | 
			
		||||
function ZoomRegion(magnifier, mouseSourceActor) {
 | 
			
		||||
    this._init(magnifier, mouseSourceActor);
 | 
			
		||||
}
 | 
			
		||||
const ZoomRegion = new Lang.Class({
 | 
			
		||||
    Name: 'ZoomRegion',
 | 
			
		||||
 | 
			
		||||
ZoomRegion.prototype = {
 | 
			
		||||
    _init: function(magnifier, mouseSourceActor) {
 | 
			
		||||
        this._magnifier = magnifier;
 | 
			
		||||
 | 
			
		||||
        this._mouseTrackingMode = MouseTrackingMode.NONE;
 | 
			
		||||
        this._mouseTrackingMode = GDesktopEnums.MagnifierMouseTrackingMode.NONE;
 | 
			
		||||
        this._clampScrollingAtEdges = false;
 | 
			
		||||
        this._lensMode = false;
 | 
			
		||||
        this._screenPosition = ScreenPosition.FULL_SCREEN;
 | 
			
		||||
        this._screenPosition = GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN;
 | 
			
		||||
 | 
			
		||||
        this._magView = null;
 | 
			
		||||
        this._uiGroupClone = null;
 | 
			
		||||
@@ -647,7 +628,8 @@ ZoomRegion.prototype = {
 | 
			
		||||
     * @mode:     One of the enum MouseTrackingMode values.
 | 
			
		||||
     */
 | 
			
		||||
    setMouseTrackingMode: function(mode) {
 | 
			
		||||
        if (mode >= MouseTrackingMode.NONE && mode <= MouseTrackingMode.PUSH)
 | 
			
		||||
        if (mode >= GDesktopEnums.MagnifierMouseTrackingMode.NONE &&
 | 
			
		||||
            mode <= GDesktopEnums.MagnifierMouseTrackingMode.PUSH)
 | 
			
		||||
            this._mouseTrackingMode = mode;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -668,7 +650,7 @@ ZoomRegion.prototype = {
 | 
			
		||||
     */
 | 
			
		||||
    setViewPort: function(viewPort) {
 | 
			
		||||
        this._setViewPort(viewPort);
 | 
			
		||||
        this._screenPosition = ScreenPosition.NONE;
 | 
			
		||||
        this._screenPosition = GDesktopEnums.MagnifierScreenPosition.NONE;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -750,7 +732,7 @@ ZoomRegion.prototype = {
 | 
			
		||||
        viewPort.width = global.screen_width;
 | 
			
		||||
        viewPort.height = global.screen_height/2;
 | 
			
		||||
        this._setViewPort(viewPort);
 | 
			
		||||
        this._screenPosition = ScreenPosition.TOP_HALF;
 | 
			
		||||
        this._screenPosition = GDesktopEnums.MagnifierScreenPosition.TOP_HALF;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -764,7 +746,7 @@ ZoomRegion.prototype = {
 | 
			
		||||
        viewPort.width = global.screen_width;
 | 
			
		||||
        viewPort.height = global.screen_height/2;
 | 
			
		||||
        this._setViewPort(viewPort);
 | 
			
		||||
        this._screenPosition = ScreenPosition.BOTTOM_HALF;
 | 
			
		||||
        this._screenPosition = GDesktopEnums.MagnifierScreenPosition.BOTTOM_HALF;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -778,7 +760,7 @@ ZoomRegion.prototype = {
 | 
			
		||||
        viewPort.width = global.screen_width/2;
 | 
			
		||||
        viewPort.height = global.screen_height;
 | 
			
		||||
        this._setViewPort(viewPort);
 | 
			
		||||
        this._screenPosition = ScreenPosition.LEFT_HALF;
 | 
			
		||||
        this._screenPosition = GDesktopEnums.MagnifierScreenPosition.LEFT_HALF;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -792,7 +774,7 @@ ZoomRegion.prototype = {
 | 
			
		||||
        viewPort.width = global.screen_width/2;
 | 
			
		||||
        viewPort.height = global.screen_height;
 | 
			
		||||
        this._setViewPort(viewPort);
 | 
			
		||||
        this._screenPosition = ScreenPosition.RIGHT_HALF;
 | 
			
		||||
        this._screenPosition = GDesktopEnums.MagnifierScreenPosition.RIGHT_HALF;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -808,7 +790,7 @@ ZoomRegion.prototype = {
 | 
			
		||||
        viewPort.height = global.screen_height;
 | 
			
		||||
        this.setViewPort(viewPort);
 | 
			
		||||
 | 
			
		||||
        this._screenPosition = ScreenPosition.FULL_SCREEN;
 | 
			
		||||
        this._screenPosition = GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -821,19 +803,19 @@ ZoomRegion.prototype = {
 | 
			
		||||
     */
 | 
			
		||||
    setScreenPosition: function(inPosition) {
 | 
			
		||||
        switch (inPosition) {
 | 
			
		||||
            case ScreenPosition.FULL_SCREEN:
 | 
			
		||||
            case GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN:
 | 
			
		||||
                this.setFullScreenMode();
 | 
			
		||||
                break;
 | 
			
		||||
            case ScreenPosition.TOP_HALF:
 | 
			
		||||
            case GDesktopEnums.MagnifierScreenPosition.TOP_HALF:
 | 
			
		||||
                this.setTopHalf();
 | 
			
		||||
                break;
 | 
			
		||||
            case ScreenPosition.BOTTOM_HALF:
 | 
			
		||||
            case GDesktopEnums.MagnifierScreenPosition.BOTTOM_HALF:
 | 
			
		||||
                this.setBottomHalf();
 | 
			
		||||
                break;
 | 
			
		||||
            case ScreenPosition.LEFT_HALF:
 | 
			
		||||
            case GDesktopEnums.MagnifierScreenPosition.LEFT_HALF:
 | 
			
		||||
                this.setLeftHalf();
 | 
			
		||||
                break;
 | 
			
		||||
            case ScreenPosition.RIGHT_HALF:
 | 
			
		||||
            case GDesktopEnums.MagnifierScreenPosition.RIGHT_HALF:
 | 
			
		||||
                this.setRightHalf();
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
@@ -856,7 +838,7 @@ ZoomRegion.prototype = {
 | 
			
		||||
     */
 | 
			
		||||
    scrollToMousePos: function() {
 | 
			
		||||
        this._followingCursor = true;
 | 
			
		||||
        if (this._mouseTrackingMode != MouseTrackingMode.NONE)
 | 
			
		||||
        if (this._mouseTrackingMode != GDesktopEnums.MagnifierMouseTrackingMode.NONE)
 | 
			
		||||
            this._changeROI({ redoCursorTracking: true });
 | 
			
		||||
        else
 | 
			
		||||
            this._updateMousePosition();
 | 
			
		||||
@@ -991,7 +973,7 @@ ZoomRegion.prototype = {
 | 
			
		||||
        this._yMagFactor = params.yMagFactor;
 | 
			
		||||
 | 
			
		||||
        if (params.redoCursorTracking &&
 | 
			
		||||
            this._mouseTrackingMode != MouseTrackingMode.NONE) {
 | 
			
		||||
            this._mouseTrackingMode != GDesktopEnums.MagnifierMouseTrackingMode.NONE) {
 | 
			
		||||
            // This depends on this.xMagFactor/yMagFactor already being updated
 | 
			
		||||
            [params.xCenter, params.yCenter] = this._centerFromMousePosition();
 | 
			
		||||
        }
 | 
			
		||||
@@ -1041,7 +1023,7 @@ ZoomRegion.prototype = {
 | 
			
		||||
    _isFullScreen: function() {
 | 
			
		||||
        // Does the magnified view occupy the whole screen? Note that this
 | 
			
		||||
        // doesn't necessarily imply
 | 
			
		||||
        // this._screenPosition = ScreenPosition.FULL_SCREEN;
 | 
			
		||||
        // this._screenPosition = GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN;
 | 
			
		||||
 | 
			
		||||
        if (this._viewPortX != 0 || this._viewPortY != 0)
 | 
			
		||||
            return false;
 | 
			
		||||
@@ -1058,13 +1040,13 @@ ZoomRegion.prototype = {
 | 
			
		||||
        let xMouse = this._magnifier.xMouse;
 | 
			
		||||
        let yMouse = this._magnifier.yMouse;
 | 
			
		||||
 | 
			
		||||
        if (this._mouseTrackingMode == MouseTrackingMode.PROPORTIONAL) {
 | 
			
		||||
        if (this._mouseTrackingMode == GDesktopEnums.MagnifierMouseTrackingMode.PROPORTIONAL) {
 | 
			
		||||
            return this._centerFromMouseProportional(xMouse, yMouse);
 | 
			
		||||
        }
 | 
			
		||||
        else if (this._mouseTrackingMode == MouseTrackingMode.PUSH) {
 | 
			
		||||
        else if (this._mouseTrackingMode == GDesktopEnums.MagnifierMouseTrackingMode.PUSH) {
 | 
			
		||||
            return this._centerFromMousePush(xMouse, yMouse);
 | 
			
		||||
        }
 | 
			
		||||
        else if (this._mouseTrackingMode == MouseTrackingMode.CENTERED) {
 | 
			
		||||
        else if (this._mouseTrackingMode == GDesktopEnums.MagnifierMouseTrackingMode.CENTERED) {
 | 
			
		||||
            return this._centerFromMouseCentered(xMouse, yMouse);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -1164,13 +1146,11 @@ ZoomRegion.prototype = {
 | 
			
		||||
                                               yMagMouse - groupHeight / 2);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function Crosshairs() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const Crosshairs = new Lang.Class({
 | 
			
		||||
    Name: 'Crosshairs',
 | 
			
		||||
 | 
			
		||||
Crosshairs.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
 | 
			
		||||
        // Set the group containing the crosshairs to three times the desktop
 | 
			
		||||
@@ -1426,4 +1406,4 @@ Crosshairs.prototype = {
 | 
			
		||||
        this._vertTopHair.set_position((groupWidth - thickness) / 2, top);
 | 
			
		||||
        this._vertBottomHair.set_position((groupWidth - thickness) / 2, bottom);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const DBus = imports.dbus;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
 | 
			
		||||
const MAG_SERVICE_NAME = 'org.gnome.Magnifier';
 | 
			
		||||
@@ -10,61 +11,99 @@ const ZOOM_SERVICE_PATH = '/org/gnome/Magnifier/ZoomRegion';
 | 
			
		||||
 | 
			
		||||
// Subset of gnome-mag's Magnifier dbus interface -- to be expanded.  See:
 | 
			
		||||
// http://git.gnome.org/browse/gnome-mag/tree/xml/...Magnifier.xml
 | 
			
		||||
const MagnifierIface = {
 | 
			
		||||
    name: MAG_SERVICE_NAME,
 | 
			
		||||
    methods: [
 | 
			
		||||
                { name: 'setActive', inSignature: 'b', outSignature: '' },
 | 
			
		||||
                { name: 'isActive', inSignature: '', outSignature: 'b' },
 | 
			
		||||
                { name: 'showCursor', inSignature: '', outSignature: '' },
 | 
			
		||||
                { name: 'hideCursor', inSignature: '', outSignature: ''  },
 | 
			
		||||
                { name: 'createZoomRegion', inSignature: 'ddaiai', outSignature: 'o' },
 | 
			
		||||
                { name: 'addZoomRegion', inSignature: 'o', outSignature: 'b' },
 | 
			
		||||
                { name: 'getZoomRegions', inSignature: '', outSignature: 'ao' },
 | 
			
		||||
                { name: 'clearAllZoomRegions', inSignature: '', outSignature: '' },
 | 
			
		||||
                { name: 'fullScreenCapable', inSignature: '', outSignature: 'b' },
 | 
			
		||||
 | 
			
		||||
                { name: 'setCrosswireSize', inSignature: 'i', outSignature: '' },
 | 
			
		||||
                { name: 'getCrosswireSize', inSignature: '', outSignature: 'i' },
 | 
			
		||||
                { name: 'setCrosswireLength', inSignature: 'i', outSignature: '' },
 | 
			
		||||
                { name: 'getCrosswireLength', inSignature: '', outSignature: 'i' },
 | 
			
		||||
                { name: 'setCrosswireClip', inSignature: 'b', outSignature: '' },
 | 
			
		||||
                { name: 'getCrosswireClip', inSignature: '', outSignature: 'b' },
 | 
			
		||||
                { name: 'setCrosswireColor', inSignature: 'u', outSignature: '' },
 | 
			
		||||
                { name: 'getCrosswireColor', inSignature: '', outSignature: 'u' }
 | 
			
		||||
             ],
 | 
			
		||||
    signals: [],
 | 
			
		||||
    properties: []
 | 
			
		||||
};
 | 
			
		||||
const MagnifierIface = <interface name={MAG_SERVICE_NAME}>
 | 
			
		||||
<method name="setActive">
 | 
			
		||||
    <arg type="b" direction="in" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="isActive">
 | 
			
		||||
    <arg type="b" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="showCursor" />
 | 
			
		||||
<method name="hideCursor" />
 | 
			
		||||
<method name="createZoomRegion">
 | 
			
		||||
    <arg type="d" direction="in" />
 | 
			
		||||
    <arg type="d" direction="in" />
 | 
			
		||||
    <arg type="ai" direction="in" />
 | 
			
		||||
    <arg type="ai" direction="in" />
 | 
			
		||||
    <arg type="o" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="addZoomRegion">
 | 
			
		||||
    <arg type="o" direction="in" />
 | 
			
		||||
    <arg type="b" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="getZoomRegions">
 | 
			
		||||
    <arg type="ao" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="clearAllZoomRegions" />
 | 
			
		||||
<method name="fullScreenCapable">
 | 
			
		||||
    <arg type="b" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="setCrosswireSize">
 | 
			
		||||
    <arg type="i" direction="in" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="getCrosswireSize">
 | 
			
		||||
    <arg type="i" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="setCrosswireLength">
 | 
			
		||||
    <arg type="i" direction="in" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="getCrosswireLength">
 | 
			
		||||
    <arg type="i" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="setCrosswireClip">
 | 
			
		||||
    <arg type="b" direction="in" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="getCrosswireClip">
 | 
			
		||||
    <arg type="b" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="setCrosswireColor">
 | 
			
		||||
    <arg type="u" direction="in" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="getCrosswireColor">
 | 
			
		||||
    <arg type="u" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
// Subset of gnome-mag's ZoomRegion dbus interface -- to be expanded.  See:
 | 
			
		||||
// http://git.gnome.org/browse/gnome-mag/tree/xml/...ZoomRegion.xml
 | 
			
		||||
const ZoomRegionIface = {
 | 
			
		||||
    name: ZOOM_SERVICE_NAME,
 | 
			
		||||
    methods: [
 | 
			
		||||
                { name: 'setMagFactor', inSignature: 'dd', outSignature: ''},
 | 
			
		||||
                { name: 'getMagFactor', inSignature: '', outSignature: 'dd' },
 | 
			
		||||
                { name: 'setRoi', inSignature: 'ai', outSignature: '' },
 | 
			
		||||
                { name: 'getRoi', inSignature: '', outSignature: 'ai' },
 | 
			
		||||
                { name: 'shiftContentsTo', inSignature: 'ii', outSignature: 'b' },
 | 
			
		||||
                { name: 'moveResize', inSignature: 'ai', outSignature: '' }
 | 
			
		||||
             ],
 | 
			
		||||
    signals: [],
 | 
			
		||||
    properties: []
 | 
			
		||||
};
 | 
			
		||||
const ZoomRegionIface = <interface name={ZOOM_SERVICE_NAME}>
 | 
			
		||||
<method name="setMagFactor">
 | 
			
		||||
    <arg type="d" direction="in" />
 | 
			
		||||
    <arg type="d" direction="in" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="getMagFactor">
 | 
			
		||||
    <arg type="d" direction="out" />
 | 
			
		||||
    <arg type="d" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="setRoi">
 | 
			
		||||
    <arg type="ai" direction="in" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="getRoi">
 | 
			
		||||
    <arg type="ai" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="shiftContentsTo">
 | 
			
		||||
    <arg type="i" direction="in" />
 | 
			
		||||
    <arg type="i" direction="in" />
 | 
			
		||||
    <arg type="b" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="moveResize">
 | 
			
		||||
    <arg type="ai" direction="in" />
 | 
			
		||||
</method>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
// For making unique ZoomRegion DBus proxy object paths of the form:
 | 
			
		||||
// '/org/gnome/Magnifier/ZoomRegion/zoomer0',
 | 
			
		||||
// '/org/gnome/Magnifier/ZoomRegion/zoomer1', etc.
 | 
			
		||||
let _zoomRegionInstanceCount = 0;
 | 
			
		||||
 | 
			
		||||
function ShellMagnifier() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const ShellMagnifier = new Lang.Class({
 | 
			
		||||
    Name: 'ShellMagnifier',
 | 
			
		||||
 | 
			
		||||
ShellMagnifier.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._zoomers = {};
 | 
			
		||||
        DBus.session.exportObject(MAG_SERVICE_PATH, this);
 | 
			
		||||
 | 
			
		||||
        this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(MagnifierIface, this);
 | 
			
		||||
        this._dbusImpl.export(Gio.DBus.session, MAG_SERVICE_PATH);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -195,10 +234,10 @@ ShellMagnifier.prototype = {
 | 
			
		||||
        Main.magnifier.clearAllZoomRegions();
 | 
			
		||||
        for (let objectPath in this._zoomers) {
 | 
			
		||||
            let proxyAndZoomer = this._zoomers[objectPath];
 | 
			
		||||
            proxyAndZoomer.proxy.destroy();
 | 
			
		||||
            proxyAndZoomer.proxy = null;
 | 
			
		||||
            proxyAndZoomer.zoomRegion = null;
 | 
			
		||||
            delete this._zoomers[objectPath];
 | 
			
		||||
            DBus.session.unexportObject(proxyAndZoomer);
 | 
			
		||||
        }
 | 
			
		||||
        this._zoomers = {};
 | 
			
		||||
    },
 | 
			
		||||
@@ -285,7 +324,7 @@ ShellMagnifier.prototype = {
 | 
			
		||||
        // Drop the leading '#'.
 | 
			
		||||
        return parseInt(colorString.slice(1), 16);
 | 
			
		||||
     }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ShellMagnifierZoomRegion:
 | 
			
		||||
@@ -293,15 +332,14 @@ ShellMagnifier.prototype = {
 | 
			
		||||
 * @zoomerObjectPath:   String that is the path to a DBus ZoomRegion.
 | 
			
		||||
 * @zoomRegion:         The actual zoom region associated with the object path.
 | 
			
		||||
 */
 | 
			
		||||
function ShellMagnifierZoomRegion(zoomerObjectPath, zoomRegion) {
 | 
			
		||||
    this._init(zoomerObjectPath, zoomRegion);
 | 
			
		||||
}
 | 
			
		||||
const ShellMagnifierZoomRegion = new Lang.Class({
 | 
			
		||||
    Name: 'ShellMagnifierZoomRegion',
 | 
			
		||||
 | 
			
		||||
ShellMagnifierZoomRegion.prototype = {
 | 
			
		||||
    _init: function(zoomerObjectPath, zoomRegion) {
 | 
			
		||||
        this._zoomRegion = zoomRegion;
 | 
			
		||||
        DBus.session.proxifyObject(this, ZOOM_SERVICE_NAME, zoomerObjectPath);
 | 
			
		||||
        DBus.session.exportObject(zoomerObjectPath, this);
 | 
			
		||||
 | 
			
		||||
        this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ZoomRegionIface, this);
 | 
			
		||||
        this._dbusImpl.export(Gio.DBus.session, zoomerObjectPath);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -376,8 +414,9 @@ ShellMagnifierZoomRegion.prototype = {
 | 
			
		||||
    moveResize: function(viewPort) {
 | 
			
		||||
        let viewRect = { x: viewPort[0], y: viewPort[1], width: viewPort[2] - viewPort[0], height: viewPort[3] - viewPort[1] };
 | 
			
		||||
        this._zoomRegion.setViewPort(viewRect);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
DBus.conformExport(ShellMagnifier.prototype, MagnifierIface);
 | 
			
		||||
DBus.conformExport(ShellMagnifierZoomRegion.prototype, ZoomRegionIface);
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
        this._dbusImpl.unexport();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										441
									
								
								js/ui/main.js
									
									
									
									
									
								
							
							
						
						@@ -1,37 +1,31 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
 | 
			
		||||
imports.gi.versions.Clutter = '1.0';
 | 
			
		||||
imports.gi.versions.Gio = '2.0';
 | 
			
		||||
imports.gi.versions.Gdk = '3.0';
 | 
			
		||||
imports.gi.versions.GdkPixbuf = '2.0';
 | 
			
		||||
imports.gi.versions.Gtk = '3.0';
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const DBus = imports.dbus;
 | 
			
		||||
const Gdk = imports.gi.Gdk;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const GConf = imports.gi.GConf;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
 | 
			
		||||
const Chrome = imports.ui.chrome;
 | 
			
		||||
const AutomountManager = imports.ui.automountManager;
 | 
			
		||||
const AutorunManager = imports.ui.autorunManager;
 | 
			
		||||
const CtrlAltTab = imports.ui.ctrlAltTab;
 | 
			
		||||
const EndSessionDialog = imports.ui.endSessionDialog;
 | 
			
		||||
const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent;
 | 
			
		||||
const Environment = imports.ui.environment;
 | 
			
		||||
const ExtensionSystem = imports.ui.extensionSystem;
 | 
			
		||||
const Keyboard = imports.ui.keyboard;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
const Overview = imports.ui.overview;
 | 
			
		||||
const Panel = imports.ui.panel;
 | 
			
		||||
const PlaceDisplay = imports.ui.placeDisplay;
 | 
			
		||||
const RunDialog = imports.ui.runDialog;
 | 
			
		||||
const Layout = imports.ui.layout;
 | 
			
		||||
const LookingGlass = imports.ui.lookingGlass;
 | 
			
		||||
const NetworkAgent = imports.ui.networkAgent;
 | 
			
		||||
const NotificationDaemon = imports.ui.notificationDaemon;
 | 
			
		||||
const WindowAttentionHandler = imports.ui.windowAttentionHandler;
 | 
			
		||||
const Scripting = imports.ui.scripting;
 | 
			
		||||
@@ -46,8 +40,10 @@ const Util = imports.misc.util;
 | 
			
		||||
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
 | 
			
		||||
DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
 | 
			
		||||
 | 
			
		||||
let chrome = null;
 | 
			
		||||
let automountManager = null;
 | 
			
		||||
let autorunManager = null;
 | 
			
		||||
let panel = null;
 | 
			
		||||
let hotCorners = [];
 | 
			
		||||
let placesManager = null;
 | 
			
		||||
let overview = null;
 | 
			
		||||
let runDialog = null;
 | 
			
		||||
@@ -66,36 +62,101 @@ let uiGroup = null;
 | 
			
		||||
let magnifier = null;
 | 
			
		||||
let xdndHandler = null;
 | 
			
		||||
let statusIconDispatcher = null;
 | 
			
		||||
let keyboard = null;
 | 
			
		||||
let layoutManager = null;
 | 
			
		||||
let networkAgent = null;
 | 
			
		||||
let _errorLogStack = [];
 | 
			
		||||
let _startDate;
 | 
			
		||||
let _defaultCssStylesheet = null;
 | 
			
		||||
let _cssStylesheet = null;
 | 
			
		||||
let _gdmCssStylesheet = null;
 | 
			
		||||
 | 
			
		||||
let background = null;
 | 
			
		||||
 | 
			
		||||
function start() {
 | 
			
		||||
    // Add a binding for 'global' in the global JS namespace; (gjs
 | 
			
		||||
    // keeps the web browser convention of having that namespace be
 | 
			
		||||
    // called 'window'.)
 | 
			
		||||
    window.global = Shell.Global.get();
 | 
			
		||||
function _createUserSession() {
 | 
			
		||||
    // Load the calendar server. Note that we are careful about
 | 
			
		||||
    // not loading any events until the user presses the clock
 | 
			
		||||
    global.launch_calendar_server();
 | 
			
		||||
 | 
			
		||||
    // Now monkey patch utility functions into the global proxy;
 | 
			
		||||
    placesManager = new PlaceDisplay.PlacesManager();
 | 
			
		||||
    telepathyClient = new TelepathyClient.Client();
 | 
			
		||||
    automountManager = new AutomountManager.AutomountManager();
 | 
			
		||||
    autorunManager = new AutorunManager.AutorunManager();
 | 
			
		||||
    networkAgent = new NetworkAgent.NetworkAgent();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _createGDMSession() {
 | 
			
		||||
    // We do this this here instead of at the top to prevent GDM
 | 
			
		||||
    // related code from getting loaded in normal user sessions
 | 
			
		||||
    const LoginDialog = imports.gdm.loginDialog;
 | 
			
		||||
 | 
			
		||||
    let loginDialog = new LoginDialog.LoginDialog();
 | 
			
		||||
    loginDialog.connect('loaded', function() {
 | 
			
		||||
                            loginDialog.open();
 | 
			
		||||
                        });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _initRecorder() {
 | 
			
		||||
    let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
 | 
			
		||||
 | 
			
		||||
    global.screen.connect('toggle-recording', function() {
 | 
			
		||||
        if (recorder == null) {
 | 
			
		||||
            recorder = new Shell.Recorder({ stage: global.stage });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (recorder.is_recording()) {
 | 
			
		||||
            recorder.pause();
 | 
			
		||||
            Meta.enable_unredirect_for_screen(global.screen);
 | 
			
		||||
        } else {
 | 
			
		||||
            // read the parameters from GSettings always in case they have changed
 | 
			
		||||
            recorder.set_framerate(recorderSettings.get_int('framerate'));
 | 
			
		||||
            recorder.set_filename('shell-%d%u-%c.' + recorderSettings.get_string('file-extension'));
 | 
			
		||||
            let pipeline = recorderSettings.get_string('pipeline');
 | 
			
		||||
 | 
			
		||||
            if (!pipeline.match(/^\s*$/))
 | 
			
		||||
                recorder.set_pipeline(pipeline);
 | 
			
		||||
            else
 | 
			
		||||
                recorder.set_pipeline(null);
 | 
			
		||||
 | 
			
		||||
            Meta.disable_unredirect_for_screen(global.screen);
 | 
			
		||||
            recorder.record();
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _initUserSession() {
 | 
			
		||||
    _initRecorder();
 | 
			
		||||
 | 
			
		||||
    global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT, false, -1, 1);
 | 
			
		||||
 | 
			
		||||
    ExtensionSystem.init();
 | 
			
		||||
    ExtensionSystem.loadExtensions();
 | 
			
		||||
 | 
			
		||||
    Meta.keybindings_set_custom_handler('panel-run-dialog', function() {
 | 
			
		||||
       getRunDialog().open();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    Meta.keybindings_set_custom_handler('panel-main-menu', function () {
 | 
			
		||||
        overview.toggle();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    global.display.connect('overlay-key', Lang.bind(overview, overview.toggle));
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function start() {
 | 
			
		||||
    // Monkey patch utility functions into the global proxy;
 | 
			
		||||
    // This is easier and faster than indirecting down into global
 | 
			
		||||
    // if we want to call back up into JS.
 | 
			
		||||
    global.logError = _logError;
 | 
			
		||||
    global.log = _logDebug;
 | 
			
		||||
 | 
			
		||||
    // Chain up async errors reported from C
 | 
			
		||||
    global.connect('notify-error', function (global, msg, detail) { notifyError(msg, detail); });
 | 
			
		||||
 | 
			
		||||
    Gio.DesktopAppInfo.set_desktop_env('GNOME');
 | 
			
		||||
 | 
			
		||||
    global.grab_dbus_service();
 | 
			
		||||
    shellDBusService = new ShellDBus.GnomeShell();
 | 
			
		||||
    // Force a connection now; dbus.js will do this internally
 | 
			
		||||
    // if we use its name acquisition stuff but we aren't right
 | 
			
		||||
    // now; to do so we'd need to convert from its async calls
 | 
			
		||||
    // back into sync ones.
 | 
			
		||||
    DBus.session.flush();
 | 
			
		||||
 | 
			
		||||
    Environment.init();
 | 
			
		||||
 | 
			
		||||
    // Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
 | 
			
		||||
    // also initialize ShellAppSystem first.  ShellAppSystem
 | 
			
		||||
@@ -115,71 +176,51 @@ function start() {
 | 
			
		||||
    global.stage.no_clear_hint = true;
 | 
			
		||||
 | 
			
		||||
    _defaultCssStylesheet = global.datadir + '/theme/gnome-shell.css';
 | 
			
		||||
    _gdmCssStylesheet = global.datadir + '/theme/gdm.css';
 | 
			
		||||
    loadTheme();
 | 
			
		||||
 | 
			
		||||
    let shellwm = global.window_manager;
 | 
			
		||||
    shellwm.takeover_keybinding('panel_main_menu');
 | 
			
		||||
    shellwm.connect('keybinding::panel_main_menu', function () {
 | 
			
		||||
        overview.toggle();
 | 
			
		||||
    });
 | 
			
		||||
    shellwm.takeover_keybinding('panel_run_dialog');
 | 
			
		||||
    shellwm.connect('keybinding::panel_run_dialog', function () {
 | 
			
		||||
       getRunDialog().open();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Set up stage hierarchy to group all UI actors under one container.
 | 
			
		||||
    uiGroup = new Clutter.Group();
 | 
			
		||||
    uiGroup = new Shell.GenericContainer({ name: 'uiGroup' });
 | 
			
		||||
    uiGroup.connect('allocate',
 | 
			
		||||
                    function (actor, box, flags) {
 | 
			
		||||
                        let children = uiGroup.get_children();
 | 
			
		||||
                        for (let i = 0; i < children.length; i++)
 | 
			
		||||
                            children[i].allocate_preferred_size(flags);
 | 
			
		||||
                    });
 | 
			
		||||
    St.set_ui_root(global.stage, uiGroup);
 | 
			
		||||
    global.window_group.reparent(uiGroup);
 | 
			
		||||
    global.overlay_group.reparent(uiGroup);
 | 
			
		||||
    global.stage.add_actor(uiGroup);
 | 
			
		||||
 | 
			
		||||
    placesManager = new PlaceDisplay.PlacesManager();
 | 
			
		||||
    layoutManager = new Layout.LayoutManager();
 | 
			
		||||
    xdndHandler = new XdndHandler.XdndHandler();
 | 
			
		||||
    overview = new Overview.Overview();
 | 
			
		||||
    chrome = new Chrome.Chrome();
 | 
			
		||||
    ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
 | 
			
		||||
    // This overview object is just a stub for non-user sessions
 | 
			
		||||
    overview = new Overview.Overview({ isDummy: global.session_type != Shell.SessionType.USER });
 | 
			
		||||
    magnifier = new Magnifier.Magnifier();
 | 
			
		||||
    statusIconDispatcher = new StatusIconDispatcher.StatusIconDispatcher();
 | 
			
		||||
    panel = new Panel.Panel();
 | 
			
		||||
    wm = new WindowManager.WindowManager();
 | 
			
		||||
    messageTray = new MessageTray.MessageTray();
 | 
			
		||||
    keyboard = new Keyboard.Keyboard();
 | 
			
		||||
    notificationDaemon = new NotificationDaemon.NotificationDaemon();
 | 
			
		||||
    windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
 | 
			
		||||
    telepathyClient = new TelepathyClient.Client();
 | 
			
		||||
 | 
			
		||||
    if (global.session_type == Shell.SessionType.USER)
 | 
			
		||||
        _createUserSession();
 | 
			
		||||
    else if (global.session_type == Shell.SessionType.GDM)
 | 
			
		||||
        _createGDMSession();
 | 
			
		||||
 | 
			
		||||
    panel.startStatusArea();
 | 
			
		||||
 | 
			
		||||
    layoutManager.init();
 | 
			
		||||
    keyboard.init();
 | 
			
		||||
    overview.init();
 | 
			
		||||
 | 
			
		||||
    if (global.session_type == Shell.SessionType.USER)
 | 
			
		||||
        _initUserSession();
 | 
			
		||||
    statusIconDispatcher.start(messageTray.actor);
 | 
			
		||||
 | 
			
		||||
    ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
 | 
			
		||||
    ctrlAltTabManager.addGroup(panel.actor, _("Panel"), 'gnome-panel');
 | 
			
		||||
 | 
			
		||||
    _startDate = new Date();
 | 
			
		||||
 | 
			
		||||
    let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
 | 
			
		||||
 | 
			
		||||
    global.screen.connect('toggle-recording', function() {
 | 
			
		||||
        if (recorder == null) {
 | 
			
		||||
            recorder = new Shell.Recorder({ stage: global.stage });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (recorder.is_recording()) {
 | 
			
		||||
            recorder.pause();
 | 
			
		||||
        } else {
 | 
			
		||||
            // read the parameters from GSettings always in case they have changed
 | 
			
		||||
            recorder.set_framerate(recorderSettings.get_int('framerate'));
 | 
			
		||||
            recorder.set_filename('shell-%d%u-%c.' + recorderSettings.get_string('file-extension'));
 | 
			
		||||
            let pipeline = recorderSettings.get_string('pipeline');
 | 
			
		||||
 | 
			
		||||
            if (!pipeline.match(/^\s*$/))
 | 
			
		||||
                recorder.set_pipeline(pipeline);
 | 
			
		||||
            else
 | 
			
		||||
                recorder.set_pipeline(null);
 | 
			
		||||
 | 
			
		||||
            recorder.record();
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT, false, -1, 1);
 | 
			
		||||
 | 
			
		||||
    // Provide the bus object for gnome-session to
 | 
			
		||||
    // initiate logouts.
 | 
			
		||||
    EndSessionDialog.init();
 | 
			
		||||
@@ -187,22 +228,10 @@ function start() {
 | 
			
		||||
    // Attempt to become a PolicyKit authentication agent
 | 
			
		||||
    PolkitAuthenticationAgent.init()
 | 
			
		||||
 | 
			
		||||
    global.gdk_screen.connect('monitors-changed', _relayout);
 | 
			
		||||
 | 
			
		||||
    ExtensionSystem.init();
 | 
			
		||||
    ExtensionSystem.loadExtensions();
 | 
			
		||||
 | 
			
		||||
    panel.startStatusArea();
 | 
			
		||||
    panel.startupAnimation();
 | 
			
		||||
 | 
			
		||||
    let display = global.screen.get_display();
 | 
			
		||||
    display.connect('overlay-key', Lang.bind(overview, overview.toggle));
 | 
			
		||||
    _startDate = new Date();
 | 
			
		||||
 | 
			
		||||
    global.stage.connect('captured-event', _globalKeyPressHandler);
 | 
			
		||||
 | 
			
		||||
    // Perform initial relayout here
 | 
			
		||||
    _relayout();
 | 
			
		||||
 | 
			
		||||
    _log('info', 'loaded at ' + _startDate);
 | 
			
		||||
    log('GNOME Shell started at ' + _startDate);
 | 
			
		||||
 | 
			
		||||
@@ -214,18 +243,39 @@ function start() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    global.screen.connect('notify::n-workspaces', _nWorkspacesChanged);
 | 
			
		||||
    Mainloop.idle_add(_nWorkspacesChanged);
 | 
			
		||||
 | 
			
		||||
    global.screen.connect('window-entered-monitor', _windowEnteredMonitor);
 | 
			
		||||
    global.screen.connect('window-left-monitor', _windowLeftMonitor);
 | 
			
		||||
    global.screen.connect('restacked', _windowsRestacked);
 | 
			
		||||
 | 
			
		||||
    _nWorkspacesChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let _workspaces = [];
 | 
			
		||||
let _checkWorkspacesId = 0;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * When the last window closed on a workspace is a dialog or splash
 | 
			
		||||
 * screen, we assume that it might be an initial window shown before
 | 
			
		||||
 * the main window of an application, and give the app a grace period
 | 
			
		||||
 * where it can map another window before we remove the workspace.
 | 
			
		||||
 */
 | 
			
		||||
const LAST_WINDOW_GRACE_TIME = 1000;
 | 
			
		||||
 | 
			
		||||
function _checkWorkspaces() {
 | 
			
		||||
    let i;
 | 
			
		||||
    let emptyWorkspaces = [];
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < _workspaces.length; i++)
 | 
			
		||||
        emptyWorkspaces[i] = true;
 | 
			
		||||
    for (i = 0; i < _workspaces.length; i++) {
 | 
			
		||||
        let lastRemoved = _workspaces[i]._lastRemovedWindow;
 | 
			
		||||
        if (lastRemoved &&
 | 
			
		||||
            (lastRemoved.get_window_type() == Meta.WindowType.SPLASHSCREEN ||
 | 
			
		||||
             lastRemoved.get_window_type() == Meta.WindowType.DIALOG ||
 | 
			
		||||
             lastRemoved.get_window_type() == Meta.WindowType.MODAL_DIALOG))
 | 
			
		||||
                emptyWorkspaces[i] = false;
 | 
			
		||||
        else
 | 
			
		||||
            emptyWorkspaces[i] = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let windows = global.get_window_actors();
 | 
			
		||||
    for (i = 0; i < windows.length; i++) {
 | 
			
		||||
@@ -244,16 +294,68 @@ function _checkWorkspaces() {
 | 
			
		||||
        emptyWorkspaces.push(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let activeWorkspaceIndex = global.screen.get_active_workspace_index();
 | 
			
		||||
    let removingCurrentWorkspace = (emptyWorkspaces[activeWorkspaceIndex] &&
 | 
			
		||||
                                    activeWorkspaceIndex < emptyWorkspaces.length - 1);
 | 
			
		||||
    // Don't enter the overview when removing multiple empty workspaces at startup
 | 
			
		||||
    let showOverview  = (removingCurrentWorkspace &&
 | 
			
		||||
                         !emptyWorkspaces.every(function(x) { return x; }));
 | 
			
		||||
 | 
			
		||||
    if (removingCurrentWorkspace) {
 | 
			
		||||
        // "Merge" the empty workspace we are removing with the one at the end
 | 
			
		||||
        wm.blockAnimations();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Delete other empty workspaces; do it from the end to avoid index changes
 | 
			
		||||
    for (i = emptyWorkspaces.length - 2; i >= 0; i--) {
 | 
			
		||||
        if (emptyWorkspaces[i])
 | 
			
		||||
            global.screen.remove_workspace(_workspaces[i], global.get_current_time());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (removingCurrentWorkspace) {
 | 
			
		||||
        global.screen.get_workspace_by_index(global.screen.n_workspaces - 1).activate(global.get_current_time());
 | 
			
		||||
        wm.unblockAnimations();
 | 
			
		||||
 | 
			
		||||
        if (!overview.visible && showOverview)
 | 
			
		||||
            overview.show();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _checkWorkspacesId = 0;
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _windowRemoved(workspace, window) {
 | 
			
		||||
    workspace._lastRemovedWindow = window;
 | 
			
		||||
    _queueCheckWorkspaces();
 | 
			
		||||
    Mainloop.timeout_add(LAST_WINDOW_GRACE_TIME, function() {
 | 
			
		||||
        if (workspace._lastRemovedWindow == window) {
 | 
			
		||||
            workspace._lastRemovedWindow = null;
 | 
			
		||||
            _queueCheckWorkspaces();
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _windowLeftMonitor(metaScreen, monitorIndex, metaWin) {
 | 
			
		||||
    // If the window left the primary monitor, that
 | 
			
		||||
    // might make that workspace empty
 | 
			
		||||
    if (monitorIndex == layoutManager.primaryIndex)
 | 
			
		||||
        _queueCheckWorkspaces();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _windowEnteredMonitor(metaScreen, monitorIndex, metaWin) {
 | 
			
		||||
    // If the window entered the primary monitor, that
 | 
			
		||||
    // might make that workspace non-empty
 | 
			
		||||
    if (monitorIndex == layoutManager.primaryIndex)
 | 
			
		||||
        _queueCheckWorkspaces();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _windowsRestacked() {
 | 
			
		||||
    // Figure out where the pointer is in case we lost track of
 | 
			
		||||
    // it during a grab. (In particular, if a trayicon popup menu
 | 
			
		||||
    // is dismissed, see if we need to close the message tray.)
 | 
			
		||||
    global.sync_pointer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _queueCheckWorkspaces() {
 | 
			
		||||
    if (_checkWorkspacesId == 0)
 | 
			
		||||
        _checkWorkspacesId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, _checkWorkspaces);
 | 
			
		||||
@@ -277,7 +379,7 @@ function _nWorkspacesChanged() {
 | 
			
		||||
        for (w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
 | 
			
		||||
            let workspace = _workspaces[w];
 | 
			
		||||
            workspace._windowAddedId = workspace.connect('window-added', _queueCheckWorkspaces);
 | 
			
		||||
            workspace._windowRemovedId = workspace.connect('window-removed', _queueCheckWorkspaces);
 | 
			
		||||
            workspace._windowRemovedId = workspace.connect('window-removed', _windowRemoved);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
@@ -337,15 +439,57 @@ function setThemeStylesheet(cssStylesheet)
 | 
			
		||||
 */
 | 
			
		||||
function loadTheme() {
 | 
			
		||||
    let themeContext = St.ThemeContext.get_for_stage (global.stage);
 | 
			
		||||
    let previousTheme = themeContext.get_theme();
 | 
			
		||||
 | 
			
		||||
    let cssStylesheet = _defaultCssStylesheet;
 | 
			
		||||
    if (_cssStylesheet != null)
 | 
			
		||||
        cssStylesheet = _cssStylesheet;
 | 
			
		||||
 | 
			
		||||
    let theme = new St.Theme ({ application_stylesheet: cssStylesheet });
 | 
			
		||||
 | 
			
		||||
    if (global.session_type == Shell.SessionType.GDM)
 | 
			
		||||
        theme.load_stylesheet(_gdmCssStylesheet);
 | 
			
		||||
 | 
			
		||||
    if (previousTheme) {
 | 
			
		||||
        let customStylesheets = previousTheme.get_custom_stylesheets();
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < customStylesheets.length; i++)
 | 
			
		||||
            theme.load_stylesheet(customStylesheets[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    themeContext.set_theme (theme);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * notify:
 | 
			
		||||
 * @msg: A message
 | 
			
		||||
 * @details: Additional information
 | 
			
		||||
 */
 | 
			
		||||
function notify(msg, details) {
 | 
			
		||||
    let source = new MessageTray.SystemNotificationSource();
 | 
			
		||||
    messageTray.add(source);
 | 
			
		||||
    let notification = new MessageTray.Notification(source, msg, details);
 | 
			
		||||
    notification.setTransient(true);
 | 
			
		||||
    source.notify(notification);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * notifyError:
 | 
			
		||||
 * @msg: An error message
 | 
			
		||||
 * @details: Additional information
 | 
			
		||||
 *
 | 
			
		||||
 * See shell_global_notify_problem().
 | 
			
		||||
 */
 | 
			
		||||
function notifyError(msg, details) {
 | 
			
		||||
    // Also print to stderr so it's logged somewhere
 | 
			
		||||
    if (details)
 | 
			
		||||
        log('error: ' + msg + ': ' + details);
 | 
			
		||||
    else
 | 
			
		||||
        log('error: ' + msg);
 | 
			
		||||
 | 
			
		||||
    notify(msg, details);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * _log:
 | 
			
		||||
 * @category: string message type ('info', 'error')
 | 
			
		||||
@@ -387,16 +531,16 @@ function _getAndClearErrorStack() {
 | 
			
		||||
    return errors;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _relayout() {
 | 
			
		||||
    let primary = global.get_primary_monitor();
 | 
			
		||||
    panel.actor.set_position(primary.x, primary.y);
 | 
			
		||||
    panel.actor.set_size(primary.width, Panel.PANEL_HEIGHT);
 | 
			
		||||
    overview.relayout();
 | 
			
		||||
 | 
			
		||||
    // To avoid updating the position and size of the workspaces
 | 
			
		||||
    // in the overview, we just hide the overview. The positions
 | 
			
		||||
    // will be updated when it is next shown.
 | 
			
		||||
    overview.hide();
 | 
			
		||||
function logStackTrace(msg) {
 | 
			
		||||
    try {
 | 
			
		||||
        throw new Error();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        // e.stack must have at least two lines, with the first being
 | 
			
		||||
        // logStackTrace() (which we strip off), and the second being
 | 
			
		||||
        // our caller.
 | 
			
		||||
        let trace = e.stack.substr(e.stack.indexOf('\n') + 1);
 | 
			
		||||
        log(msg ? (msg + '\n' + trace) : trace);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isWindowActorDisplayedOnWorkspace(win, workspaceIndex) {
 | 
			
		||||
@@ -425,23 +569,12 @@ function _globalKeyPressHandler(actor, event) {
 | 
			
		||||
    let keyCode = event.get_key_code();
 | 
			
		||||
    let modifierState = Shell.get_event_state(event);
 | 
			
		||||
 | 
			
		||||
    let display = global.screen.get_display();
 | 
			
		||||
    // This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType
 | 
			
		||||
    let action = display.get_keybinding_action(keyCode, modifierState);
 | 
			
		||||
    let action = global.display.get_keybinding_action(keyCode, modifierState);
 | 
			
		||||
 | 
			
		||||
    // The screenshot action should always be available (even if a
 | 
			
		||||
    // modal dialog is present)
 | 
			
		||||
    if (action == Meta.KeyBindingAction.COMMAND_SCREENSHOT) {
 | 
			
		||||
        let gconf = GConf.Client.get_default();
 | 
			
		||||
        let command = gconf.get_string('/apps/metacity/keybinding_commands/command_screenshot');
 | 
			
		||||
        if (command != null && command != '')
 | 
			
		||||
            Util.spawnCommandLine(command);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Other bindings are only available when the overview is up and
 | 
			
		||||
    // Other bindings are only available to the user session when the overview is up and
 | 
			
		||||
    // no modal dialog is present.
 | 
			
		||||
    if (!overview.visible || modalCount > 1)
 | 
			
		||||
    if (global.session_type == Shell.SessionType.USER && (!overview.visible || modalCount > 1))
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    // This isn't a Meta.KeyBindingAction yet
 | 
			
		||||
@@ -450,6 +583,16 @@ function _globalKeyPressHandler(actor, event) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (action == Meta.KeyBindingAction.SWITCH_PANELS) {
 | 
			
		||||
        ctrlAltTabManager.popup(modifierState & Clutter.ModifierType.SHIFT_MASK,
 | 
			
		||||
                                modifierState);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // None of the other bindings are relevant outside of the user's session
 | 
			
		||||
    if (global.session_type != Shell.SessionType.USER)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    switch (action) {
 | 
			
		||||
        // left/right would effectively act as synonyms for up/down if we enabled them;
 | 
			
		||||
        // but that could be considered confusing; we also disable them in the main view.
 | 
			
		||||
@@ -473,9 +616,6 @@ function _globalKeyPressHandler(actor, event) {
 | 
			
		||||
        case Meta.KeyBindingAction.PANEL_MAIN_MENU:
 | 
			
		||||
            overview.hide();
 | 
			
		||||
            return true;
 | 
			
		||||
        case Meta.KeyBindingAction.SWITCH_PANELS:
 | 
			
		||||
            ctrlAltTabManager.popup(modifierState & Clutter.ModifierType.SHIFT_MASK);
 | 
			
		||||
            return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
@@ -483,10 +623,8 @@ function _globalKeyPressHandler(actor, event) {
 | 
			
		||||
 | 
			
		||||
function _findModal(actor) {
 | 
			
		||||
    for (let i = 0; i < modalActorFocusStack.length; i++) {
 | 
			
		||||
        let [stackActor, stackFocus] = modalActorFocusStack[i];
 | 
			
		||||
        if (stackActor == actor) {
 | 
			
		||||
        if (modalActorFocusStack[i].actor == actor)
 | 
			
		||||
            return i;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
@@ -509,15 +647,17 @@ function _findModal(actor) {
 | 
			
		||||
 * initiated event.  If not provided then the value of
 | 
			
		||||
 * global.get_current_time() is assumed.
 | 
			
		||||
 *
 | 
			
		||||
 * @options: optional Meta.ModalOptions flags to indicate that the
 | 
			
		||||
 *           pointer is alrady grabbed
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: true iff we successfully acquired a grab or already had one
 | 
			
		||||
 */
 | 
			
		||||
function pushModal(actor, timestamp) {
 | 
			
		||||
 | 
			
		||||
function pushModal(actor, timestamp, options) {
 | 
			
		||||
    if (timestamp == undefined)
 | 
			
		||||
        timestamp = global.get_current_time();
 | 
			
		||||
 | 
			
		||||
    if (modalCount == 0) {
 | 
			
		||||
        if (!global.begin_modal(timestamp)) {
 | 
			
		||||
        if (!global.begin_modal(timestamp, options ? options : 0)) {
 | 
			
		||||
            log('pushModal: invocation of begin_modal failed');
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
@@ -526,20 +666,24 @@ function pushModal(actor, timestamp) {
 | 
			
		||||
    global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
 | 
			
		||||
 | 
			
		||||
    modalCount += 1;
 | 
			
		||||
    actor.connect('destroy', function() {
 | 
			
		||||
    let actorDestroyId = actor.connect('destroy', function() {
 | 
			
		||||
        let index = _findModal(actor);
 | 
			
		||||
        if (index >= 0)
 | 
			
		||||
            modalActorFocusStack.splice(index, 1);
 | 
			
		||||
    });
 | 
			
		||||
    let curFocus = global.stage.get_key_focus();
 | 
			
		||||
    let curFocusDestroyId;
 | 
			
		||||
    if (curFocus != null) {
 | 
			
		||||
        curFocus.connect('destroy', function() {
 | 
			
		||||
        curFocusDestroyId = curFocus.connect('destroy', function() {
 | 
			
		||||
            let index = _findModal(actor);
 | 
			
		||||
            if (index >= 0)
 | 
			
		||||
                modalActorFocusStack[index][1] = null;
 | 
			
		||||
                modalActorFocusStack[index].actor = null;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    modalActorFocusStack.push([actor, curFocus]);
 | 
			
		||||
    modalActorFocusStack.push({ actor: actor,
 | 
			
		||||
                                focus: curFocus,
 | 
			
		||||
                                destroyId: actorDestroyId,
 | 
			
		||||
                                focusDestroyId: curFocusDestroyId });
 | 
			
		||||
 | 
			
		||||
    global.stage.set_key_focus(actor);
 | 
			
		||||
    return true;
 | 
			
		||||
@@ -559,28 +703,42 @@ function pushModal(actor, timestamp) {
 | 
			
		||||
 * global.get_current_time() is assumed.
 | 
			
		||||
 */
 | 
			
		||||
function popModal(actor, timestamp) {
 | 
			
		||||
 | 
			
		||||
    if (timestamp == undefined)
 | 
			
		||||
        timestamp = global.get_current_time();
 | 
			
		||||
 | 
			
		||||
    modalCount -= 1;
 | 
			
		||||
    let focusIndex = _findModal(actor);
 | 
			
		||||
    if (focusIndex >= 0) {
 | 
			
		||||
        if (focusIndex == modalActorFocusStack.length - 1) {
 | 
			
		||||
            let [stackActor, stackFocus] = modalActorFocusStack[focusIndex];
 | 
			
		||||
            global.stage.set_key_focus(stackFocus);
 | 
			
		||||
        } else {
 | 
			
		||||
            // Remove from the middle, shift the focus chain up
 | 
			
		||||
            for (let i = focusIndex; i < modalActorFocusStack.length - 1; i++) {
 | 
			
		||||
                modalActorFocusStack[i + 1][1] = modalActorFocusStack[i][1];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        modalActorFocusStack.splice(focusIndex, 1);
 | 
			
		||||
    if (focusIndex < 0) {
 | 
			
		||||
        global.stage.set_key_focus(null);
 | 
			
		||||
        global.end_modal(timestamp);
 | 
			
		||||
        global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
 | 
			
		||||
 | 
			
		||||
        throw new Error('incorrect pop');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    modalCount -= 1;
 | 
			
		||||
 | 
			
		||||
    let record = modalActorFocusStack[focusIndex];
 | 
			
		||||
    record.actor.disconnect(record.destroyId);
 | 
			
		||||
 | 
			
		||||
    if (focusIndex == modalActorFocusStack.length - 1) {
 | 
			
		||||
        if (record.focus)
 | 
			
		||||
            record.focus.disconnect(record.focusDestroyId);
 | 
			
		||||
        global.stage.set_key_focus(record.focus);
 | 
			
		||||
    } else {
 | 
			
		||||
        let t = modalActorFocusStack[modalActorFocusStack.length - 1];
 | 
			
		||||
        if (t.focus)
 | 
			
		||||
            t.focus.disconnect(t.focusDestroyId);
 | 
			
		||||
        // Remove from the middle, shift the focus chain up
 | 
			
		||||
        for (let i = modalActorFocusStack.length - 1; i > focusIndex; i--) {
 | 
			
		||||
            modalActorFocusStack[i].focus = modalActorFocusStack[i - 1].focus;
 | 
			
		||||
            modalActorFocusStack[i].focusDestroyId = modalActorFocusStack[i - 1].focusDestroyId;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    modalActorFocusStack.splice(focusIndex, 1);
 | 
			
		||||
 | 
			
		||||
    if (modalCount > 0)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    global.stage.set_key_focus(null);
 | 
			
		||||
    global.end_modal(timestamp);
 | 
			
		||||
    global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
 | 
			
		||||
}
 | 
			
		||||
@@ -588,7 +746,6 @@ function popModal(actor, timestamp) {
 | 
			
		||||
function createLookingGlass() {
 | 
			
		||||
    if (lookingGlass == null) {
 | 
			
		||||
        lookingGlass = new LookingGlass.LookingGlass();
 | 
			
		||||
        lookingGlass.slaveTo(panel.actor);
 | 
			
		||||
    }
 | 
			
		||||
    return lookingGlass;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1140
									
								
								js/ui/messageTray.js
									
									
									
									
									
								
							
							
						
						@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gdk = imports.gi.Gdk;
 | 
			
		||||
@@ -10,8 +10,6 @@ const Pango = imports.gi.Pango;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
 | 
			
		||||
@@ -20,6 +18,7 @@ const Main = imports.ui.main;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
const OPEN_AND_CLOSE_TIME = 0.1;
 | 
			
		||||
const FADE_IN_BUTTONS_TIME = 0.33;
 | 
			
		||||
const FADE_OUT_DIALOG_TIME = 1.0;
 | 
			
		||||
 | 
			
		||||
const State = {
 | 
			
		||||
@@ -30,42 +29,55 @@ const State = {
 | 
			
		||||
    FADED_OUT: 4
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function ModalDialog() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const ModalDialog = new Lang.Class({
 | 
			
		||||
    Name: 'ModalDialog',
 | 
			
		||||
 | 
			
		||||
ModalDialog.prototype = {
 | 
			
		||||
    _init: function(params) {
 | 
			
		||||
        params = Params.parse(params, { styleClass: null });
 | 
			
		||||
        params = Params.parse(params, { shellReactive: false,
 | 
			
		||||
                                        styleClass: null });
 | 
			
		||||
 | 
			
		||||
        this.state = State.CLOSED;
 | 
			
		||||
        this._hasModal = false;
 | 
			
		||||
        this._shellReactive = params.shellReactive;
 | 
			
		||||
 | 
			
		||||
        this._group = new St.Group({ visible: false,
 | 
			
		||||
                                     x: 0,
 | 
			
		||||
                                     y: 0 });
 | 
			
		||||
        Main.uiGroup.add_actor(this._group);
 | 
			
		||||
        global.focus_manager.add_group(this._group);
 | 
			
		||||
        this._initialKeyFocus = this._group;
 | 
			
		||||
 | 
			
		||||
        let constraint = new Clutter.BindConstraint({ source: global.stage,
 | 
			
		||||
                                                      coordinate: Clutter.BindCoordinate.POSITION | Clutter.BindCoordinate.SIZE });
 | 
			
		||||
        this._group.add_constraint(constraint);
 | 
			
		||||
 | 
			
		||||
        this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy));
 | 
			
		||||
 | 
			
		||||
        this._actionKeys = {};
 | 
			
		||||
        this._group.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
 | 
			
		||||
 | 
			
		||||
        this._lightbox = new Lightbox.Lightbox(this._group,
 | 
			
		||||
                                               { inhibitEvents: true });
 | 
			
		||||
 | 
			
		||||
        this._backgroundBin = new St.Bin();
 | 
			
		||||
 | 
			
		||||
        this._group.add_actor(this._backgroundBin);
 | 
			
		||||
        this._lightbox.highlight(this._backgroundBin);
 | 
			
		||||
 | 
			
		||||
        this._dialogLayout = new St.BoxLayout({ style_class: 'modal-dialog',
 | 
			
		||||
                                                vertical:    true });
 | 
			
		||||
        if (params.styleClass != null) {
 | 
			
		||||
            this._dialogLayout.add_style_class_name(params.styleClass);
 | 
			
		||||
        }
 | 
			
		||||
        this._backgroundBin.child = this._dialogLayout;
 | 
			
		||||
 | 
			
		||||
        if (!this._shellReactive) {
 | 
			
		||||
            this._lightbox = new Lightbox.Lightbox(this._group,
 | 
			
		||||
                                                   { inhibitEvents: true });
 | 
			
		||||
            this._lightbox.highlight(this._backgroundBin);
 | 
			
		||||
 | 
			
		||||
            let stack = new Shell.Stack();
 | 
			
		||||
            this._backgroundBin.child = stack;
 | 
			
		||||
 | 
			
		||||
            this._eventBlocker = new Clutter.Group({ reactive: true });
 | 
			
		||||
            stack.add_actor(this._eventBlocker);
 | 
			
		||||
            stack.add_actor(this._dialogLayout);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._backgroundBin.child = this._dialogLayout;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        this.contentLayout = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        this._dialogLayout.add(this.contentLayout,
 | 
			
		||||
@@ -74,29 +86,38 @@ ModalDialog.prototype = {
 | 
			
		||||
                                 x_align: St.Align.MIDDLE,
 | 
			
		||||
                                 y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        this._buttonLayout = new St.BoxLayout({ opacity:  220,
 | 
			
		||||
                                                vertical: false });
 | 
			
		||||
        this._buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box',
 | 
			
		||||
                                                vertical:    false });
 | 
			
		||||
        this._dialogLayout.add(this._buttonLayout,
 | 
			
		||||
                               { expand:  true,
 | 
			
		||||
                                 x_align: St.Align.MIDDLE,
 | 
			
		||||
                                 y_align: St.Align.END });
 | 
			
		||||
 | 
			
		||||
        global.focus_manager.add_group(this._dialogLayout);
 | 
			
		||||
        this._initialKeyFocus = this._dialogLayout;
 | 
			
		||||
        this._savedKeyFocus = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
        this._group.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setButtons: function(buttons) {
 | 
			
		||||
        let hadChildren = this._buttonLayout.get_children() > 0;
 | 
			
		||||
 | 
			
		||||
        this._buttonLayout.destroy_children();
 | 
			
		||||
        this._actionKeys = {};
 | 
			
		||||
 | 
			
		||||
        let i = 0;
 | 
			
		||||
        for (let index in buttons) {
 | 
			
		||||
            let buttonInfo = buttons[index];
 | 
			
		||||
        for (let i = 0; i < buttons.length; i++) {
 | 
			
		||||
            let buttonInfo = buttons[i];
 | 
			
		||||
            let label = buttonInfo['label'];
 | 
			
		||||
            let action = buttonInfo['action'];
 | 
			
		||||
            let key = buttonInfo['key'];
 | 
			
		||||
 | 
			
		||||
            let button = new St.Button({ style_class: 'modal-dialog-button',
 | 
			
		||||
                                         reactive:    true,
 | 
			
		||||
                                         can_focus:   true,
 | 
			
		||||
                                         label:       label });
 | 
			
		||||
            buttonInfo.button = new St.Button({ style_class: 'modal-dialog-button',
 | 
			
		||||
                                                reactive:    true,
 | 
			
		||||
                                                can_focus:   true,
 | 
			
		||||
                                                label:       label });
 | 
			
		||||
 | 
			
		||||
            let x_alignment;
 | 
			
		||||
            if (buttons.length == 1)
 | 
			
		||||
@@ -108,20 +129,37 @@ ModalDialog.prototype = {
 | 
			
		||||
            else
 | 
			
		||||
                x_alignment = St.Align.MIDDLE;
 | 
			
		||||
 | 
			
		||||
            this._initialKeyFocus = button;
 | 
			
		||||
            this._buttonLayout.add(button,
 | 
			
		||||
            if (this._initialKeyFocus == this._dialogLayout ||
 | 
			
		||||
                this._buttonLayout.contains(this._initialKeyFocus))
 | 
			
		||||
                this._initialKeyFocus = buttonInfo.button;
 | 
			
		||||
            this._buttonLayout.add(buttonInfo.button,
 | 
			
		||||
                                   { expand: true,
 | 
			
		||||
                                     x_fill: false,
 | 
			
		||||
                                     y_fill: false,
 | 
			
		||||
                                     x_align: x_alignment,
 | 
			
		||||
                                     y_align: St.Align.MIDDLE });
 | 
			
		||||
 | 
			
		||||
            button.connect('clicked', action);
 | 
			
		||||
            buttonInfo.button.connect('clicked', action);
 | 
			
		||||
 | 
			
		||||
            if (key)
 | 
			
		||||
                this._actionKeys[key] = action;
 | 
			
		||||
            i++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Fade in buttons if there weren't any before
 | 
			
		||||
        if (!hadChildren && buttons.length > 0) {
 | 
			
		||||
            this._buttonLayout.opacity = 0;
 | 
			
		||||
            Tweener.addTween(this._buttonLayout,
 | 
			
		||||
                             { opacity: 255,
 | 
			
		||||
                               time: FADE_IN_BUTTONS_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad',
 | 
			
		||||
                               onComplete: Lang.bind(this, function() {
 | 
			
		||||
                                   this.emit('buttons-set');
 | 
			
		||||
                               })
 | 
			
		||||
                             });
 | 
			
		||||
        } else {
 | 
			
		||||
            this.emit('buttons-set');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeyPressEvent: function(object, keyPressEvent) {
 | 
			
		||||
@@ -137,7 +175,7 @@ ModalDialog.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _fadeOpen: function() {
 | 
			
		||||
        let monitor = global.get_focus_monitor();
 | 
			
		||||
        let monitor = Main.layoutManager.focusMonitor;
 | 
			
		||||
 | 
			
		||||
        this._backgroundBin.set_position(monitor.x, monitor.y);
 | 
			
		||||
        this._backgroundBin.set_size(monitor.width, monitor.height);
 | 
			
		||||
@@ -145,7 +183,8 @@ ModalDialog.prototype = {
 | 
			
		||||
        this.state = State.OPENING;
 | 
			
		||||
 | 
			
		||||
        this._dialogLayout.opacity = 255;
 | 
			
		||||
        this._lightbox.show();
 | 
			
		||||
        if (this._lightbox)
 | 
			
		||||
            this._lightbox.show();
 | 
			
		||||
        this._group.opacity = 0;
 | 
			
		||||
        this._group.show();
 | 
			
		||||
        Tweener.addTween(this._group,
 | 
			
		||||
@@ -154,22 +193,23 @@ ModalDialog.prototype = {
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: Lang.bind(this,
 | 
			
		||||
                               function() {
 | 
			
		||||
                                   this._initialKeyFocus.grab_key_focus();
 | 
			
		||||
                                   this.state = State.OPENED;
 | 
			
		||||
                                   this.emit('opened');
 | 
			
		||||
                               }),
 | 
			
		||||
                               })
 | 
			
		||||
                         });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setInitialKeyFocus: function(actor) {
 | 
			
		||||
        this._initialKeyFocus = actor;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    open: function(timestamp) {
 | 
			
		||||
        if (this.state == State.OPENED || this.state == State.OPENING)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        if (!Main.pushModal(this._group, timestamp))
 | 
			
		||||
        if (!this.pushModal(timestamp))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        global.stage.set_key_focus(this._group);
 | 
			
		||||
 | 
			
		||||
        this._fadeOpen();
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
@@ -178,14 +218,9 @@ ModalDialog.prototype = {
 | 
			
		||||
        if (this.state == State.CLOSED || this.state == State.CLOSING)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let needsPopModal;
 | 
			
		||||
 | 
			
		||||
        if (this.state == State.OPENED || this.state == State.OPENING)
 | 
			
		||||
            needsPopModal = true;
 | 
			
		||||
        else
 | 
			
		||||
            needsPopModal = false;
 | 
			
		||||
 | 
			
		||||
        this.state = State.CLOSING;
 | 
			
		||||
        this.popModal(timestamp);
 | 
			
		||||
        this._savedKeyFocus = null;
 | 
			
		||||
 | 
			
		||||
        Tweener.addTween(this._group,
 | 
			
		||||
                         { opacity: 0,
 | 
			
		||||
@@ -195,13 +230,48 @@ ModalDialog.prototype = {
 | 
			
		||||
                               function() {
 | 
			
		||||
                                   this.state = State.CLOSED;
 | 
			
		||||
                                   this._group.hide();
 | 
			
		||||
 | 
			
		||||
                                   if (needsPopModal)
 | 
			
		||||
                                       Main.popModal(this._group, timestamp);
 | 
			
		||||
                               })
 | 
			
		||||
                         });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Drop modal status without closing the dialog; this makes the
 | 
			
		||||
    // dialog insensitive as well, so it needs to be followed shortly
 | 
			
		||||
    // by either a close() or a pushModal()
 | 
			
		||||
    popModal: function(timestamp) {
 | 
			
		||||
        if (!this._hasModal)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let focus = global.stage.key_focus;
 | 
			
		||||
        if (focus && this._group.contains(focus))
 | 
			
		||||
            this._savedKeyFocus = focus;
 | 
			
		||||
        else
 | 
			
		||||
            this._savedKeyFocus = null;
 | 
			
		||||
        Main.popModal(this._group, timestamp);
 | 
			
		||||
        global.gdk_screen.get_display().sync();
 | 
			
		||||
        this._hasModal = false;
 | 
			
		||||
 | 
			
		||||
        if (!this._shellReactive)
 | 
			
		||||
            this._eventBlocker.raise_top();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    pushModal: function (timestamp) {
 | 
			
		||||
        if (this._hasModal)
 | 
			
		||||
            return true;
 | 
			
		||||
        if (!Main.pushModal(this._group, timestamp))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        this._hasModal = true;
 | 
			
		||||
        if (this._savedKeyFocus) {
 | 
			
		||||
            this._savedKeyFocus.grab_key_focus();
 | 
			
		||||
            this._savedKeyFocus = null;
 | 
			
		||||
        } else
 | 
			
		||||
            this._initialKeyFocus.grab_key_focus();
 | 
			
		||||
 | 
			
		||||
        if (!this._shellReactive)
 | 
			
		||||
            this._eventBlocker.lower_bottom();
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // This method is like close, but fades the dialog out much slower,
 | 
			
		||||
    // and leaves the lightbox in place. Once in the faded out state,
 | 
			
		||||
    // the dialog can be brought back by an open call, or the lightbox
 | 
			
		||||
@@ -220,6 +290,7 @@ ModalDialog.prototype = {
 | 
			
		||||
        if (this.state == State.FADED_OUT)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.popModal(timestamp);
 | 
			
		||||
        Tweener.addTween(this._dialogLayout,
 | 
			
		||||
                         { opacity: 0,
 | 
			
		||||
                           time:    FADE_OUT_DIALOG_TIME,
 | 
			
		||||
@@ -227,9 +298,8 @@ ModalDialog.prototype = {
 | 
			
		||||
                           onComplete: Lang.bind(this,
 | 
			
		||||
                               function() {
 | 
			
		||||
                                   this.state = State.FADED_OUT;
 | 
			
		||||
                                   Main.popModal(this._group, timestamp);
 | 
			
		||||
                               })
 | 
			
		||||
                         });
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ModalDialog.prototype);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										385
									
								
								js/ui/networkAgent.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,385 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2011 Giovanni Campagna <scampa.giovanni@gmail.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 | 
			
		||||
 * 02111-1307, USA.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const NetworkManager = imports.gi.NetworkManager;
 | 
			
		||||
const NMClient = imports.gi.NMClient;
 | 
			
		||||
const Pango = imports.gi.Pango;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const PopupMenu = imports.ui.popupMenu;
 | 
			
		||||
const ShellEntry = imports.ui.shellEntry;
 | 
			
		||||
 | 
			
		||||
const NetworkSecretDialog = new Lang.Class({
 | 
			
		||||
    Name: 'NetworkSecretDialog',
 | 
			
		||||
    Extends: ModalDialog.ModalDialog,
 | 
			
		||||
 | 
			
		||||
    _init: function(agent, requestId, connection, settingName, hints) {
 | 
			
		||||
        this.parent({ styleClass: 'polkit-dialog' });
 | 
			
		||||
 | 
			
		||||
        this._agent = agent;
 | 
			
		||||
        this._requestId = requestId;
 | 
			
		||||
        this._connection = connection;
 | 
			
		||||
        this._settingName = settingName;
 | 
			
		||||
        this._hints = hints;
 | 
			
		||||
 | 
			
		||||
        this._content = this._getContent();
 | 
			
		||||
 | 
			
		||||
        let mainContentBox = new St.BoxLayout({ style_class: 'polkit-dialog-main-layout',
 | 
			
		||||
                                                vertical: false });
 | 
			
		||||
        this.contentLayout.add(mainContentBox,
 | 
			
		||||
                               { x_fill: true,
 | 
			
		||||
                                 y_fill: true });
 | 
			
		||||
 | 
			
		||||
        let icon = new St.Icon({ icon_name: 'dialog-password-symbolic' });
 | 
			
		||||
        mainContentBox.add(icon,
 | 
			
		||||
                           { x_fill:  true,
 | 
			
		||||
                             y_fill:  false,
 | 
			
		||||
                             x_align: St.Align.END,
 | 
			
		||||
                             y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        let messageBox = new St.BoxLayout({ style_class: 'polkit-dialog-message-layout',
 | 
			
		||||
                                            vertical: true });
 | 
			
		||||
        mainContentBox.add(messageBox,
 | 
			
		||||
                           { y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        let subjectLabel = new St.Label({ style_class: 'polkit-dialog-headline',
 | 
			
		||||
                                            text: this._content.title });
 | 
			
		||||
        messageBox.add(subjectLabel,
 | 
			
		||||
                       { y_fill:  false,
 | 
			
		||||
                         y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        if (this._content.message != null) {
 | 
			
		||||
            let descriptionLabel = new St.Label({ style_class: 'polkit-dialog-description',
 | 
			
		||||
                                                  text: this._content.message,
 | 
			
		||||
                                                  // HACK: for reasons unknown to me, the label
 | 
			
		||||
                                                  // is not asked the correct height for width,
 | 
			
		||||
                                                  // and thus is underallocated
 | 
			
		||||
                                                  // place a fixed height to avoid overflowing
 | 
			
		||||
                                                  style: 'height: 3em'
 | 
			
		||||
                                                });
 | 
			
		||||
            descriptionLabel.clutter_text.line_wrap = true;
 | 
			
		||||
 | 
			
		||||
            messageBox.add(descriptionLabel,
 | 
			
		||||
                           { y_fill:  true,
 | 
			
		||||
                             y_align: St.Align.START,
 | 
			
		||||
                             expand: true });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let secretTable = new St.Table({ style_class: 'network-dialog-secret-table' });
 | 
			
		||||
        let initialFocusSet = false;
 | 
			
		||||
        let pos = 0;
 | 
			
		||||
        for (let i = 0; i < this._content.secrets.length; i++) {
 | 
			
		||||
            let secret = this._content.secrets[i];
 | 
			
		||||
            let label = new St.Label({ style_class: 'polkit-dialog-password-label',
 | 
			
		||||
                                       text: secret.label });
 | 
			
		||||
 | 
			
		||||
            let reactive = secret.key != null;
 | 
			
		||||
 | 
			
		||||
            secret.entry = new St.Entry({ style_class: 'polkit-dialog-password-entry',
 | 
			
		||||
                                          text: secret.value, can_focus: reactive,
 | 
			
		||||
                                          reactive: reactive });
 | 
			
		||||
            ShellEntry.addContextMenu(secret.entry,
 | 
			
		||||
                                      { isPassword: secret.password });
 | 
			
		||||
 | 
			
		||||
            if (secret.validate)
 | 
			
		||||
                secret.valid = secret.validate(secret);
 | 
			
		||||
            else // no special validation, just ensure it's not empty
 | 
			
		||||
                secret.valid = secret.value.length > 0;
 | 
			
		||||
 | 
			
		||||
            if (reactive) {
 | 
			
		||||
                if (!initialFocusSet) {
 | 
			
		||||
                    this.setInitialKeyFocus(secret.entry);
 | 
			
		||||
                    initialFocusSet = true;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                secret.entry.clutter_text.connect('activate', Lang.bind(this, this._onOk));
 | 
			
		||||
                secret.entry.clutter_text.connect('text-changed', Lang.bind(this, function() {
 | 
			
		||||
                    secret.value = secret.entry.get_text();
 | 
			
		||||
                    if (secret.validate)
 | 
			
		||||
                        secret.valid = secret.validate(secret);
 | 
			
		||||
                    else
 | 
			
		||||
                        secret.valid = secret.value.length > 0;
 | 
			
		||||
                    this._updateOkButton();
 | 
			
		||||
                }));
 | 
			
		||||
            } else
 | 
			
		||||
                secret.valid = true;
 | 
			
		||||
 | 
			
		||||
            secretTable.add(label, { row: pos, col: 0, x_expand: false, x_fill: true, x_align: St.Align.START, y_align: St.Align.START });
 | 
			
		||||
            secretTable.add(secret.entry, { row: pos, col: 1, x_expand: true, x_fill: true, y_align: St.Align.END });
 | 
			
		||||
            pos++;
 | 
			
		||||
 | 
			
		||||
            if (secret.password)
 | 
			
		||||
                secret.entry.clutter_text.set_password_char('\u25cf');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        messageBox.add(secretTable);
 | 
			
		||||
 | 
			
		||||
        this._okButton = { label:  _("Connect"),
 | 
			
		||||
                           action: Lang.bind(this, this._onOk),
 | 
			
		||||
                           key:    Clutter.KEY_Return,
 | 
			
		||||
                         };
 | 
			
		||||
 | 
			
		||||
        this.setButtons([{ label: _("Cancel"),
 | 
			
		||||
                           action: Lang.bind(this, this.cancel),
 | 
			
		||||
                           key:    Clutter.KEY_Escape,
 | 
			
		||||
                         },
 | 
			
		||||
                         this._okButton]);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateOkButton: function() {
 | 
			
		||||
        let valid = true;
 | 
			
		||||
        for (let i = 0; i < this._content.secrets.length; i++) {
 | 
			
		||||
            let secret = this._content.secrets[i];
 | 
			
		||||
            valid = valid && secret.valid;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._okButton.button.reactive = valid;
 | 
			
		||||
        this._okButton.button.can_focus = valid;
 | 
			
		||||
        if (valid)
 | 
			
		||||
            this._okButton.button.remove_style_pseudo_class('disabled');
 | 
			
		||||
        else
 | 
			
		||||
            this._okButton.button.add_style_pseudo_class('disabled');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onOk: function() {
 | 
			
		||||
        let valid = true;
 | 
			
		||||
        for (let i = 0; i < this._content.secrets.length; i++) {
 | 
			
		||||
            let secret = this._content.secrets[i];
 | 
			
		||||
            valid = valid && secret.valid;
 | 
			
		||||
            if (secret.key != null)
 | 
			
		||||
                this._agent.set_password(this._requestId, secret.key, secret.value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (valid) {
 | 
			
		||||
            this._agent.respond(this._requestId, false);
 | 
			
		||||
            this.close(global.get_current_time());
 | 
			
		||||
        }
 | 
			
		||||
        // do nothing if not valid
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    cancel: function() {
 | 
			
		||||
        this._agent.respond(this._requestId, true);
 | 
			
		||||
        this.close(global.get_current_time());
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _validateWpaPsk: function(secret) {
 | 
			
		||||
        let value = secret.value;
 | 
			
		||||
        if (value.length == 64) {
 | 
			
		||||
            // must be composed of hexadecimal digits only
 | 
			
		||||
            for (let i = 0; i < 64; i++) {
 | 
			
		||||
                if (!((value[i] >= 'a' && value[i] <= 'f')
 | 
			
		||||
                      || (value[i] >= 'A' && value[i] <= 'F')
 | 
			
		||||
                      || (value[i] >= '0' && value[i] <= '9')))
 | 
			
		||||
                    return false;
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (value.length >= 8 && value.length <= 63);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _validateStaticWep: function(secret) {
 | 
			
		||||
        let value = secret.value;
 | 
			
		||||
        if (secret.wep_key_type == NetworkManager.WepKeyType.KEY) {
 | 
			
		||||
            if (value.length == 10 || value.length == 26) {
 | 
			
		||||
		for (let i = 0; i < value.length; i++) {
 | 
			
		||||
                    if (!((value[i] >= 'a' && value[i] <= 'f')
 | 
			
		||||
                          || (value[i] >= 'A' && value[i] <= 'F')
 | 
			
		||||
                          || (value[i] >= '0' && value[i] <= '9')))
 | 
			
		||||
                        return false;
 | 
			
		||||
		}
 | 
			
		||||
	    } else if (value.length == 5 || value.length == 13) {
 | 
			
		||||
		for (let i = 0; i < value.length; i++) {
 | 
			
		||||
                    if (!((value[i] >= 'a' && value[i] <= 'z')
 | 
			
		||||
                          || (value[i] >= 'A' && value[i] <= 'Z')))
 | 
			
		||||
                        return false;
 | 
			
		||||
                }
 | 
			
		||||
            } else
 | 
			
		||||
                return false;
 | 
			
		||||
	} else if (secret.wep_key_type == NetworkManager.WepKeyType.PASSPHRASE) {
 | 
			
		||||
	    if (value.length < 0 || value.length > 64)
 | 
			
		||||
	        return false;
 | 
			
		||||
	}
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getWirelessSecrets: function(secrets, wirelessSetting) {
 | 
			
		||||
        let wirelessSecuritySetting = this._connection.get_setting_wireless_security();
 | 
			
		||||
        switch (wirelessSecuritySetting.key_mgmt) {
 | 
			
		||||
        // First the easy ones
 | 
			
		||||
        case 'wpa-none':
 | 
			
		||||
        case 'wpa-psk':
 | 
			
		||||
            secrets.push({ label: _("Password: "), key: 'psk',
 | 
			
		||||
                           value: wirelessSecuritySetting.psk || '',
 | 
			
		||||
                           validate: this._validateWpaPsk, password: true });
 | 
			
		||||
            break;
 | 
			
		||||
        case 'none': // static WEP
 | 
			
		||||
            secrets.push({ label: _("Key: "), key: 'wep-key' + wirelessSecuritySetting.wep_tx_keyidx,
 | 
			
		||||
                           value: wirelessSecuritySetting.get_wep_key(wirelessSecuritySetting.wep_tx_keyidx) || '',
 | 
			
		||||
                           wep_key_type: wirelessSecuritySetting.wep_key_type,
 | 
			
		||||
                           validate: this._validateStaticWep, password: true });
 | 
			
		||||
            break;
 | 
			
		||||
        case 'ieee8021x':
 | 
			
		||||
            if (wirelessSecuritySetting.auth_alg == 'leap') // Cisco LEAP
 | 
			
		||||
                secrets.push({ label: _("Password: "), key: 'leap-password',
 | 
			
		||||
                               value: wirelessSecuritySetting.leap_password || '', password: true });
 | 
			
		||||
            else // Dynamic (IEEE 802.1x) WEP
 | 
			
		||||
                this._get8021xSecrets(secrets);
 | 
			
		||||
            break;
 | 
			
		||||
        case 'wpa-eap':
 | 
			
		||||
            this._get8021xSecrets(secrets);
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            log('Invalid wireless key management: ' + wirelessSecuritySetting.key_mgmt);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _get8021xSecrets: function(secrets) {
 | 
			
		||||
        let ieee8021xSetting = this._connection.get_setting_802_1x();
 | 
			
		||||
        let phase2method;
 | 
			
		||||
 | 
			
		||||
        switch (ieee8021xSetting.get_eap_method(0)) {
 | 
			
		||||
        case 'md5':
 | 
			
		||||
        case 'leap':
 | 
			
		||||
        case 'ttls':
 | 
			
		||||
        case 'peap':
 | 
			
		||||
            // TTLS and PEAP are actually much more complicated, but this complication
 | 
			
		||||
            // is not visible here since we only care about phase2 authentication
 | 
			
		||||
            // (and don't even care of which one)
 | 
			
		||||
            secrets.push({ label: _("Username: "), key: null,
 | 
			
		||||
                           value: ieee8021xSetting.identity || '', password: false });
 | 
			
		||||
            secrets.push({ label: _("Password: "), key: 'password',
 | 
			
		||||
                           value: ieee8021xSetting.password || '', password: true });
 | 
			
		||||
            break;
 | 
			
		||||
        case 'tls':
 | 
			
		||||
            secrets.push({ label: _("Identity: "), key: null,
 | 
			
		||||
                           value: ieee8021xSetting.identity || '', password: false });
 | 
			
		||||
            secrets.push({ label: _("Private key password: "), key: 'private-key-password',
 | 
			
		||||
                           value: ieee8021xSetting.private_key_password || '', password: true });
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            log('Invalid EAP/IEEE802.1x method: ' + ieee8021xSetting.get_eap_method(0));
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getPPPoESecrets: function(secrets) {
 | 
			
		||||
        let pppoeSetting = this._connection.get_setting_pppoe();
 | 
			
		||||
        secrets.push({ label: _("Username: "), key: 'username',
 | 
			
		||||
                       value: pppoeSetting.username || '', password: false });
 | 
			
		||||
        secrets.push({ label: _("Service: "), key: 'service',
 | 
			
		||||
                       value: pppoeSetting.service || '', password: false });
 | 
			
		||||
        secrets.push({ label: _("Password: "), key: 'password',
 | 
			
		||||
                       value: pppoeSetting.password || '', password: true });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getMobileSecrets: function(secrets, connectionType) {
 | 
			
		||||
        let setting;
 | 
			
		||||
        if (connectionType == 'bluetooth')
 | 
			
		||||
            setting = this._connection.get_setting_cdma() || this._connection.get_setting_gsm();
 | 
			
		||||
        else
 | 
			
		||||
            setting = this._connection.get_setting_by_name(connectionType);
 | 
			
		||||
        secrets.push({ label: _("Password: "), key: 'password',
 | 
			
		||||
                       value: setting.value || '', password: true });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getContent: function() {
 | 
			
		||||
        let connectionSetting = this._connection.get_setting_connection();
 | 
			
		||||
        let connectionType = connectionSetting.get_connection_type();
 | 
			
		||||
        let wirelessSetting;
 | 
			
		||||
        let ssid;
 | 
			
		||||
 | 
			
		||||
        let content = { };
 | 
			
		||||
        content.secrets = [ ];
 | 
			
		||||
 | 
			
		||||
        switch (connectionType) {
 | 
			
		||||
        case '802-11-wireless':
 | 
			
		||||
            wirelessSetting = this._connection.get_setting_wireless();
 | 
			
		||||
            ssid = NetworkManager.utils_ssid_to_utf8(wirelessSetting.get_ssid());
 | 
			
		||||
            content.title = _("Authentication required by wireless network");
 | 
			
		||||
            content.message = _("Passwords or encryption keys are required to access the wireless network '%s'.").format(ssid);
 | 
			
		||||
            this._getWirelessSecrets(content.secrets, wirelessSetting);
 | 
			
		||||
            break;
 | 
			
		||||
        case '802-3-ethernet':
 | 
			
		||||
            content.title = _("Wired 802.1X authentication");
 | 
			
		||||
            content.message = null;
 | 
			
		||||
            content.secrets.push({ label: _("Network name: "), key: null,
 | 
			
		||||
                                   value: connectionSetting.get_id(), password: false });
 | 
			
		||||
            this._get8021xSecrets(content.secrets);
 | 
			
		||||
            break;
 | 
			
		||||
        case 'pppoe':
 | 
			
		||||
            content.title = _("DSL authentication");
 | 
			
		||||
            content.message = null;
 | 
			
		||||
            this._getPPPoESecrets(content.secrets);
 | 
			
		||||
            break;
 | 
			
		||||
        case 'gsm':
 | 
			
		||||
            if (this._hints.indexOf('pin') != -1) {
 | 
			
		||||
                let gsmSetting = this._connection.get_setting_gsm();
 | 
			
		||||
                content.title = _("PIN code required");
 | 
			
		||||
                content.message = _("PIN code is needed for the mobile broadband device");
 | 
			
		||||
                content.secrets.push({ label: _("PIN: "), key: 'pin',
 | 
			
		||||
                                       value: gsmSetting.pin || '', password: true });
 | 
			
		||||
            }
 | 
			
		||||
            // fall through
 | 
			
		||||
        case 'cdma':
 | 
			
		||||
        case 'bluetooth':
 | 
			
		||||
            content.title = _("Mobile broadband network password");
 | 
			
		||||
            content.message = _("A password is required to connect to '%s'.").format(connectionSetting.get_id());
 | 
			
		||||
            this._getMobileSecrets(content.secrets, connectionType);
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            log('Invalid connection type: ' + connectionType);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return content;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const NetworkAgent = new Lang.Class({
 | 
			
		||||
    Name: 'NetworkAgent',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._native = new Shell.NetworkAgent({ auto_register: true,
 | 
			
		||||
                                                identifier: 'org.gnome.Shell.NetworkAgent' });
 | 
			
		||||
 | 
			
		||||
        this._dialogs = { };
 | 
			
		||||
        this._native.connect('new-request', Lang.bind(this, this._newRequest));
 | 
			
		||||
        this._native.connect('cancel-request', Lang.bind(this, this._cancelRequest));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _newRequest:  function(agent, requestId, connection, settingName, hints) {
 | 
			
		||||
        let dialog = new NetworkSecretDialog(agent, requestId, connection, settingName, hints);
 | 
			
		||||
        dialog.connect('destroy', Lang.bind(this, function() {
 | 
			
		||||
            delete this._dialogs[requestId];
 | 
			
		||||
        }));
 | 
			
		||||
        this._dialogs[requestId] = dialog;
 | 
			
		||||
        dialog.open(global.get_current_time());
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _cancelRequest: function(agent, requestId) {
 | 
			
		||||
        this._dialogs[requestId].close(global.get_current_time());
 | 
			
		||||
        this._dialogs[requestId].destroy();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
@@ -1,13 +1,12 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const DBus = imports.dbus;
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
 | 
			
		||||
const Config = imports.misc.config;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
@@ -17,49 +16,52 @@ const Util = imports.misc.util;
 | 
			
		||||
 | 
			
		||||
let nextNotificationId = 1;
 | 
			
		||||
 | 
			
		||||
// Should really be defined in dbus.js
 | 
			
		||||
const BusIface = {
 | 
			
		||||
    name: 'org.freedesktop.DBus',
 | 
			
		||||
    methods: [{ name: 'GetConnectionUnixProcessID',
 | 
			
		||||
                inSignature: 's',
 | 
			
		||||
                outSignature: 'i' }]
 | 
			
		||||
};
 | 
			
		||||
// Should really be defined in Gio.js
 | 
			
		||||
const BusIface = <interface name="org.freedesktop.DBus">
 | 
			
		||||
<method name="GetConnectionUnixProcessID">
 | 
			
		||||
    <arg type="s" direction="in" />
 | 
			
		||||
    <arg type="u" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const Bus = function () {
 | 
			
		||||
    this._init();
 | 
			
		||||
};
 | 
			
		||||
var BusProxy = Gio.DBusProxy.makeProxyWrapper(BusIface);
 | 
			
		||||
function Bus() {
 | 
			
		||||
    return new BusProxy(Gio.DBus.session, 'org.freedesktop.DBus', '/org/freedesktop/DBus');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Bus.prototype = {
 | 
			
		||||
     _init: function() {
 | 
			
		||||
         DBus.session.proxifyObject(this, 'org.freedesktop.DBus', '/org/freedesktop/DBus');
 | 
			
		||||
     }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
DBus.proxifyPrototype(Bus.prototype, BusIface);
 | 
			
		||||
 | 
			
		||||
const NotificationDaemonIface = {
 | 
			
		||||
    name: 'org.freedesktop.Notifications',
 | 
			
		||||
    methods: [{ name: 'Notify',
 | 
			
		||||
                inSignature: 'susssasa{sv}i',
 | 
			
		||||
                outSignature: 'u'
 | 
			
		||||
              },
 | 
			
		||||
              { name: 'CloseNotification',
 | 
			
		||||
                inSignature: 'u',
 | 
			
		||||
                outSignature: ''
 | 
			
		||||
              },
 | 
			
		||||
              { name: 'GetCapabilities',
 | 
			
		||||
                inSignature: '',
 | 
			
		||||
                outSignature: 'as'
 | 
			
		||||
              },
 | 
			
		||||
              { name: 'GetServerInformation',
 | 
			
		||||
                inSignature: '',
 | 
			
		||||
                outSignature: 'ssss'
 | 
			
		||||
              }],
 | 
			
		||||
    signals: [{ name: 'NotificationClosed',
 | 
			
		||||
                inSignature: 'uu' },
 | 
			
		||||
              { name: 'ActionInvoked',
 | 
			
		||||
                inSignature: 'us' }]
 | 
			
		||||
};
 | 
			
		||||
const NotificationDaemonIface = <interface name="org.freedesktop.Notifications">
 | 
			
		||||
<method name="Notify">
 | 
			
		||||
    <arg type="s" direction="in"/>
 | 
			
		||||
    <arg type="u" direction="in"/>
 | 
			
		||||
    <arg type="s" direction="in"/>
 | 
			
		||||
    <arg type="s" direction="in"/>
 | 
			
		||||
    <arg type="s" direction="in"/>
 | 
			
		||||
    <arg type="as" direction="in"/>
 | 
			
		||||
    <arg type="a{sv}" direction="in"/>
 | 
			
		||||
    <arg type="i" direction="in"/>
 | 
			
		||||
    <arg type="u" direction="out"/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name="CloseNotification">
 | 
			
		||||
    <arg type="u" direction="in"/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name="GetCapabilities">
 | 
			
		||||
    <arg type="as" direction="out"/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name="GetServerInformation">
 | 
			
		||||
    <arg type="s" direction="out"/>
 | 
			
		||||
    <arg type="s" direction="out"/>
 | 
			
		||||
    <arg type="s" direction="out"/>
 | 
			
		||||
    <arg type="s" direction="out"/>
 | 
			
		||||
</method>
 | 
			
		||||
<signal name="NotificationClosed">
 | 
			
		||||
    <arg type="u"/>
 | 
			
		||||
    <arg type="u"/>
 | 
			
		||||
</signal>
 | 
			
		||||
<signal name="ActionInvoked">
 | 
			
		||||
    <arg type="u"/>
 | 
			
		||||
    <arg type="s"/>
 | 
			
		||||
</signal>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const NotificationClosedReason = {
 | 
			
		||||
    EXPIRED: 1,
 | 
			
		||||
@@ -85,23 +87,12 @@ const rewriteRules = {
 | 
			
		||||
    ]
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function NotificationDaemon() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const NotificationDaemon = new Lang.Class({
 | 
			
		||||
    Name: 'NotificationDaemon',
 | 
			
		||||
 | 
			
		||||
NotificationDaemon.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        DBus.session.exportObject('/org/freedesktop/Notifications', this);
 | 
			
		||||
 | 
			
		||||
        this._everAcquiredName = false;
 | 
			
		||||
        DBus.session.acquire_name('org.freedesktop.Notifications',
 | 
			
		||||
                                  // We pass MANY_INSTANCES so that if
 | 
			
		||||
                                  // notification-daemon is running, we'll
 | 
			
		||||
                                  // get queued behind it and then get the
 | 
			
		||||
                                  // name after killing it below
 | 
			
		||||
                                  DBus.MANY_INSTANCES,
 | 
			
		||||
                                  Lang.bind(this, this._acquiredName),
 | 
			
		||||
                                  Lang.bind(this, this._lostName));
 | 
			
		||||
        this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(NotificationDaemonIface, this);
 | 
			
		||||
        this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
 | 
			
		||||
 | 
			
		||||
        this._sources = {};
 | 
			
		||||
        this._senderToPid = {};
 | 
			
		||||
@@ -117,25 +108,17 @@ NotificationDaemon.prototype = {
 | 
			
		||||
            Lang.bind(this, this._onFocusAppChanged));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _acquiredName: function() {
 | 
			
		||||
        this._everAcquiredName = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _lostName: function() {
 | 
			
		||||
        if (this._everAcquiredName)
 | 
			
		||||
            log('Lost name org.freedesktop.Notifications!');
 | 
			
		||||
        else if (GLib.getenv('GNOME_SHELL_NO_REPLACE'))
 | 
			
		||||
            log('Failed to acquire org.freedesktop.Notifications');
 | 
			
		||||
        else {
 | 
			
		||||
            log('Failed to acquire org.freedesktop.Notifications; trying again');
 | 
			
		||||
            Util.killall('notification-daemon');
 | 
			
		||||
            Util.killall('notify-osd');
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _iconForNotificationData: function(icon, hints, size) {
 | 
			
		||||
        let textureCache = St.TextureCache.get_default();
 | 
			
		||||
 | 
			
		||||
        // If an icon is not specified, we use 'image-data' or 'image-path' hint for an icon
 | 
			
		||||
        // and don't show a large image. There are currently many applications that use
 | 
			
		||||
        // notify_notification_set_icon_from_pixbuf() from libnotify, which in turn sets
 | 
			
		||||
        // the 'image-data' hint. These applications don't typically pass in 'app_icon'
 | 
			
		||||
        // argument to Notify() and actually expect the pixbuf to be shown as an icon.
 | 
			
		||||
        // So the logic here does the right thing for this case. If both an icon and either
 | 
			
		||||
        // one of 'image-data' or 'image-path' are specified, we show both an icon and
 | 
			
		||||
        // a large image.
 | 
			
		||||
        if (icon) {
 | 
			
		||||
            if (icon.substr(0, 7) == 'file://')
 | 
			
		||||
                return textureCache.load_uri_async(icon, size, size);
 | 
			
		||||
@@ -149,8 +132,9 @@ NotificationDaemon.prototype = {
 | 
			
		||||
        } else if (hints['image-data']) {
 | 
			
		||||
            let [width, height, rowStride, hasAlpha,
 | 
			
		||||
                 bitsPerSample, nChannels, data] = hints['image-data'];
 | 
			
		||||
            return textureCache.load_from_raw(data, data.length, hasAlpha,
 | 
			
		||||
                                              width, height, rowStride, size);
 | 
			
		||||
            return textureCache.load_from_raw(data, hasAlpha, width, height, rowStride, size);
 | 
			
		||||
        } else if (hints['image-path']) {
 | 
			
		||||
            return textureCache.load_uri_async(GLib.filename_to_uri(hints['image-path'], null), size, size);
 | 
			
		||||
        } else {
 | 
			
		||||
            let stockIcon;
 | 
			
		||||
            switch (hints.urgency) {
 | 
			
		||||
@@ -175,7 +159,7 @@ NotificationDaemon.prototype = {
 | 
			
		||||
    //
 | 
			
		||||
    // Either a pid or ndata.notification is needed to retrieve or
 | 
			
		||||
    // create a source.
 | 
			
		||||
    _getSource: function(title, pid, ndata) {
 | 
			
		||||
    _getSource: function(title, pid, ndata, sender) {
 | 
			
		||||
        if (!pid && !(ndata && ndata.notification))
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
@@ -192,10 +176,13 @@ NotificationDaemon.prototype = {
 | 
			
		||||
        // with a transient one from the same sender, so we
 | 
			
		||||
        // always create a new source object for new transient notifications
 | 
			
		||||
        // and never add it to this._sources .
 | 
			
		||||
        if (!isForTransientNotification && this._sources[pid])
 | 
			
		||||
            return this._sources[pid];
 | 
			
		||||
        if (!isForTransientNotification && this._sources[pid]) {
 | 
			
		||||
            let source = this._sources[pid];
 | 
			
		||||
            source.setTitle(title);
 | 
			
		||||
            return source;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let source = new Source(title, pid);
 | 
			
		||||
        let source = new Source(title, pid, sender);
 | 
			
		||||
        source.setTransient(isForTransientNotification);
 | 
			
		||||
 | 
			
		||||
        if (!isForTransientNotification) {
 | 
			
		||||
@@ -210,13 +197,19 @@ NotificationDaemon.prototype = {
 | 
			
		||||
        return source;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    Notify: function(appName, replacesId, icon, summary, body,
 | 
			
		||||
                     actions, hints, timeout) {
 | 
			
		||||
    NotifyAsync: function(params, invocation) {
 | 
			
		||||
        let [appName, replacesId, icon, summary, body, actions, hints, timeout] = params;
 | 
			
		||||
        let id;
 | 
			
		||||
 | 
			
		||||
        // Filter out notifications from Empathy, since we
 | 
			
		||||
        // handle that information from telepathyClient.js
 | 
			
		||||
        if (appName == 'Empathy') {
 | 
			
		||||
        // Filter out chat, presence, calls and invitation notifications from
 | 
			
		||||
        // Empathy, since we handle that information from telepathyClient.js
 | 
			
		||||
        if (appName == 'Empathy' && (hints['category'] == 'im.received' ||
 | 
			
		||||
              hints['category'] == 'x-empathy.im.room-invitation' ||
 | 
			
		||||
              hints['category'] == 'x-empathy.call.incoming' ||
 | 
			
		||||
              hints['category'] == 'x-empathy.call.incoming"' ||
 | 
			
		||||
              hints['category'] == 'x-empathy.im.subscription-request' ||
 | 
			
		||||
              hints['category'] == 'presence.online' ||
 | 
			
		||||
              hints['category'] == 'presence.offline')) {
 | 
			
		||||
            // Ignore replacesId since we already sent back a
 | 
			
		||||
            // NotificationClosed for that id.
 | 
			
		||||
            id = nextNotificationId++;
 | 
			
		||||
@@ -224,7 +217,7 @@ NotificationDaemon.prototype = {
 | 
			
		||||
                                        function () {
 | 
			
		||||
                                            this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
 | 
			
		||||
                                        }));
 | 
			
		||||
            return id;
 | 
			
		||||
            return invocation.return_value(GLib.Variant.new('(u)', [id]));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let rewrites = rewriteRules[appName];
 | 
			
		||||
@@ -236,16 +229,25 @@ NotificationDaemon.prototype = {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let hint in hints) {
 | 
			
		||||
            // unpack the variants
 | 
			
		||||
            hints[hint] = hints[hint].deep_unpack();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        hints = Params.parse(hints, { urgency: Urgency.NORMAL }, true);
 | 
			
		||||
 | 
			
		||||
        // Be compatible with the various hints for image data
 | 
			
		||||
        // 'image-data' is the latest name of this hint, introduced in 1.2
 | 
			
		||||
        if (!hints['image-data']) {
 | 
			
		||||
        // Be compatible with the various hints for image data and image path
 | 
			
		||||
        // 'image-data' and 'image-path' are the latest name of these hints, introduced in 1.2
 | 
			
		||||
 | 
			
		||||
        if (!hints['image-path'] && hints['image_path'])
 | 
			
		||||
            hints['image-path'] = hints['image_path']; // version 1.1 of the spec
 | 
			
		||||
 | 
			
		||||
        if (!hints['image-data'])
 | 
			
		||||
            if (hints['image_data'])
 | 
			
		||||
                hints['image-data'] = hints['image_data']; // version 1.1 of the spec
 | 
			
		||||
            else if (hints['icon_data'])
 | 
			
		||||
                hints['image-data'] = hints['icon_data']; // previous versions of the spec
 | 
			
		||||
        }
 | 
			
		||||
            else if (hints['icon_data'] && !hints['image-path'])
 | 
			
		||||
                // early versions of the spec; 'icon_data' should only be used if 'image-path' is not available
 | 
			
		||||
                hints['image-data'] = hints['icon_data'];
 | 
			
		||||
 | 
			
		||||
        let ndata = { appName: appName,
 | 
			
		||||
                      icon: icon,
 | 
			
		||||
@@ -263,51 +265,55 @@ NotificationDaemon.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
        this._notifications[id] = ndata;
 | 
			
		||||
 | 
			
		||||
        let sender = DBus.getCurrentMessageContext().sender;
 | 
			
		||||
        let sender = invocation.get_sender();
 | 
			
		||||
        let pid = this._senderToPid[sender];
 | 
			
		||||
 | 
			
		||||
        let source = this._getSource(appName, pid, ndata);
 | 
			
		||||
        let source = this._getSource(appName, pid, ndata, sender);
 | 
			
		||||
 | 
			
		||||
        if (source) {
 | 
			
		||||
            this._notifyForSource(source, ndata);
 | 
			
		||||
            return id;
 | 
			
		||||
            return invocation.return_value(GLib.Variant.new('(u)', [id]));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (replacesId) {
 | 
			
		||||
            // There's already a pending call to GetConnectionUnixProcessID,
 | 
			
		||||
            // which will see the new notification data when it finishes,
 | 
			
		||||
            // so we don't have to do anything.
 | 
			
		||||
            return id;
 | 
			
		||||
            return invocation.return_value(GLib.Variant.new('(u)', [id]));;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._busProxy.GetConnectionUnixProcessIDRemote(sender, Lang.bind(this,
 | 
			
		||||
            function (pid, ex) {
 | 
			
		||||
                // The app may have updated or removed the notification
 | 
			
		||||
                ndata = this._notifications[id];
 | 
			
		||||
                if (!ndata)
 | 
			
		||||
                    return;
 | 
			
		||||
        this._busProxy.GetConnectionUnixProcessIDRemote(sender, Lang.bind(this, function (result, excp) {
 | 
			
		||||
            // The app may have updated or removed the notification
 | 
			
		||||
            ndata = this._notifications[id];
 | 
			
		||||
            if (!ndata)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
                source = this._getSource(appName, pid, ndata);
 | 
			
		||||
            if (excp) {
 | 
			
		||||
                logError(excp, 'Call to GetConnectionUnixProcessID failed');
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
                // We only store sender-pid entries for persistent sources.
 | 
			
		||||
                // Removing the entries once the source is destroyed
 | 
			
		||||
                // would result in the entries associated with transient
 | 
			
		||||
                // sources removed once the notification is shown anyway.
 | 
			
		||||
                // However, keeping these pairs would mean that we would
 | 
			
		||||
                // possibly remove an entry associated with a persistent
 | 
			
		||||
                // source when a transient source for the same sender is
 | 
			
		||||
                // distroyed.
 | 
			
		||||
                if (!source.isTransient) {
 | 
			
		||||
                    this._senderToPid[sender] = pid;
 | 
			
		||||
                    source.connect('destroy', Lang.bind(this,
 | 
			
		||||
                        function() {
 | 
			
		||||
                            delete this._senderToPid[sender];
 | 
			
		||||
                        }));
 | 
			
		||||
                }
 | 
			
		||||
                this._notifyForSource(source, ndata);
 | 
			
		||||
            }));
 | 
			
		||||
            let [pid] = result;
 | 
			
		||||
            source = this._getSource(appName, pid, ndata, sender);
 | 
			
		||||
 | 
			
		||||
        return id;
 | 
			
		||||
            // We only store sender-pid entries for persistent sources.
 | 
			
		||||
            // Removing the entries once the source is destroyed
 | 
			
		||||
            // would result in the entries associated with transient
 | 
			
		||||
            // sources removed once the notification is shown anyway.
 | 
			
		||||
            // However, keeping these pairs would mean that we would
 | 
			
		||||
            // possibly remove an entry associated with a persistent
 | 
			
		||||
            // source when a transient source for the same sender is
 | 
			
		||||
            // distroyed.
 | 
			
		||||
            if (!source.isTransient) {
 | 
			
		||||
                this._senderToPid[sender] = pid;
 | 
			
		||||
                source.connect('destroy', Lang.bind(this, function() {
 | 
			
		||||
                    delete this._senderToPid[sender];
 | 
			
		||||
                }));
 | 
			
		||||
            }
 | 
			
		||||
            this._notifyForSource(source, ndata);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return invocation.return_value(GLib.Variant.new('(u)', [id]));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _notifyForSource: function(source, ndata) {
 | 
			
		||||
@@ -324,7 +330,7 @@ NotificationDaemon.prototype = {
 | 
			
		||||
            ndata.notification = notification;
 | 
			
		||||
            notification.connect('destroy', Lang.bind(this,
 | 
			
		||||
                function(n, reason) {
 | 
			
		||||
                    delete this._notifications[id];
 | 
			
		||||
                    delete this._notifications[ndata.id];
 | 
			
		||||
                    let notificationClosedReason;
 | 
			
		||||
                    switch (reason) {
 | 
			
		||||
                        case MessageTray.NotificationDestroyedReason.EXPIRED:
 | 
			
		||||
@@ -337,11 +343,11 @@ NotificationDaemon.prototype = {
 | 
			
		||||
                            notificationClosedReason = NotificationClosedReason.APP_CLOSED;
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                    this._emitNotificationClosed(id, notificationClosedReason);
 | 
			
		||||
                    this._emitNotificationClosed(ndata.id, notificationClosedReason);
 | 
			
		||||
                }));
 | 
			
		||||
            notification.connect('action-invoked', Lang.bind(this,
 | 
			
		||||
                function(n, actionId) {
 | 
			
		||||
                    this._emitActionInvoked(id, actionId);
 | 
			
		||||
                    this._emitActionInvoked(ndata.id, actionId);
 | 
			
		||||
                }));
 | 
			
		||||
        } else {
 | 
			
		||||
            notification.update(summary, body, { icon: iconActor,
 | 
			
		||||
@@ -349,10 +355,35 @@ NotificationDaemon.prototype = {
 | 
			
		||||
                                                 clear: true });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // We only display a large image if an icon is also specified.
 | 
			
		||||
        if (icon && (hints['image-data'] || hints['image-path'])) {
 | 
			
		||||
            let image = null;
 | 
			
		||||
            if (hints['image-data']) {
 | 
			
		||||
                let [width, height, rowStride, hasAlpha,
 | 
			
		||||
                 bitsPerSample, nChannels, data] = hints['image-data'];
 | 
			
		||||
                image = St.TextureCache.get_default().load_from_raw(data, hasAlpha,
 | 
			
		||||
                                                                    width, height, rowStride, notification.IMAGE_SIZE);
 | 
			
		||||
            } else if (hints['image-path']) {
 | 
			
		||||
                image = St.TextureCache.get_default().load_uri_async(GLib.filename_to_uri(hints['image-path'], null),
 | 
			
		||||
                                                                     notification.IMAGE_SIZE,
 | 
			
		||||
                                                                     notification.IMAGE_SIZE);
 | 
			
		||||
            }
 | 
			
		||||
            notification.setImage(image);
 | 
			
		||||
        } else {
 | 
			
		||||
            notification.unsetImage();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (actions.length) {
 | 
			
		||||
            notification.setUseActionIcons(hints['action-icons'] == true);
 | 
			
		||||
            for (let i = 0; i < actions.length - 1; i += 2)
 | 
			
		||||
                notification.addButton(actions[i], actions[i + 1]);
 | 
			
		||||
            for (let i = 0; i < actions.length - 1; i += 2) {
 | 
			
		||||
                if (actions[i] == 'default')
 | 
			
		||||
                    notification.connect('clicked', Lang.bind(this,
 | 
			
		||||
                        function() {
 | 
			
		||||
                            this._emitActionInvoked(ndata.id, "default");
 | 
			
		||||
                        }));
 | 
			
		||||
                else
 | 
			
		||||
                    notification.addButton(actions[i], actions[i + 1]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        switch (hints.urgency) {
 | 
			
		||||
            case Urgency.LOW:
 | 
			
		||||
@@ -371,7 +402,7 @@ NotificationDaemon.prototype = {
 | 
			
		||||
        notification.setTransient(hints['transient'] == true);
 | 
			
		||||
 | 
			
		||||
        let sourceIconActor = source.useNotificationIcon ? this._iconForNotificationData(icon, hints, source.ICON_SIZE) : null;
 | 
			
		||||
        source.notify(notification, sourceIconActor);
 | 
			
		||||
        source.processNotification(notification, sourceIconActor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    CloseNotification: function(id) {
 | 
			
		||||
@@ -415,29 +446,24 @@ NotificationDaemon.prototype = {
 | 
			
		||||
        for (let id in this._sources) {
 | 
			
		||||
            let source = this._sources[id];
 | 
			
		||||
            if (source.app == tracker.focus_app) {
 | 
			
		||||
                if (source.notification && !source.notification.resident)
 | 
			
		||||
                    source.notification.destroy();
 | 
			
		||||
                source.destroyNonResidentNotifications();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _emitNotificationClosed: function(id, reason) {
 | 
			
		||||
        DBus.session.emit_signal('/org/freedesktop/Notifications',
 | 
			
		||||
                                 'org.freedesktop.Notifications',
 | 
			
		||||
                                 'NotificationClosed', 'uu',
 | 
			
		||||
                                 [id, reason]);
 | 
			
		||||
        this._dbusImpl.emit_signal('NotificationClosed',
 | 
			
		||||
                                   GLib.Variant.new('(uu)', [id, reason]));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _emitActionInvoked: function(id, action) {
 | 
			
		||||
        DBus.session.emit_signal('/org/freedesktop/Notifications',
 | 
			
		||||
                                 'org.freedesktop.Notifications',
 | 
			
		||||
                                 'ActionInvoked', 'us',
 | 
			
		||||
                                 [id, action]);
 | 
			
		||||
        this._dbusImpl.emit_signal('ActionInvoked',
 | 
			
		||||
                                   GLib.Variant.new('(us)', [id, action]));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onTrayIconAdded: function(o, icon) {
 | 
			
		||||
        let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null);
 | 
			
		||||
        let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null, null);
 | 
			
		||||
        source.setTrayIcon(icon);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -446,35 +472,84 @@ NotificationDaemon.prototype = {
 | 
			
		||||
        if (source)
 | 
			
		||||
            source.destroy();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
DBus.conformExport(NotificationDaemon.prototype, NotificationDaemonIface);
 | 
			
		||||
const Source = new Lang.Class({
 | 
			
		||||
    Name: 'NotificationDaemonSource',
 | 
			
		||||
    Extends: MessageTray.Source,
 | 
			
		||||
 | 
			
		||||
function Source(title, pid) {
 | 
			
		||||
    this._init(title, pid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Source.prototype = {
 | 
			
		||||
    __proto__:  MessageTray.Source.prototype,
 | 
			
		||||
 | 
			
		||||
    _init: function(title, pid) {
 | 
			
		||||
        MessageTray.Source.prototype._init.call(this, title);
 | 
			
		||||
    _init: function(title, pid, sender) {
 | 
			
		||||
        this.parent(title);
 | 
			
		||||
 | 
			
		||||
        this._pid = pid;
 | 
			
		||||
        if (sender)
 | 
			
		||||
            this._nameWatcherId = Gio.DBus.session.watch_name(sender,
 | 
			
		||||
                                                              Gio.BusNameWatcherFlags.NONE,
 | 
			
		||||
                                                              null,
 | 
			
		||||
                                                              Lang.bind(this, this._onNameVanished));
 | 
			
		||||
        else
 | 
			
		||||
            this._nameWatcherId = 0;
 | 
			
		||||
 | 
			
		||||
        this._setApp();
 | 
			
		||||
        if (this.app)
 | 
			
		||||
            this.title = this.app.get_name();
 | 
			
		||||
        else
 | 
			
		||||
            this.useNotificationIcon = true;
 | 
			
		||||
        this._isTrayIcon = false;
 | 
			
		||||
        this._trayIcon = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    notify: function(notification, icon) {
 | 
			
		||||
    _onNameVanished: function() {
 | 
			
		||||
        // Destroy the notification source when its sender is removed from DBus.
 | 
			
		||||
        // Only do so if this.app is set to avoid removing "notify-send" sources, senders
 | 
			
		||||
        // of which аre removed from DBus immediately.
 | 
			
		||||
        // Sender being removed from DBus would normally result in a tray icon being removed,
 | 
			
		||||
        // so allow the code path that handles the tray icon being removed to handle that case.
 | 
			
		||||
        if (!this.trayIcon && this.app)
 | 
			
		||||
            this.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    processNotification: function(notification, icon) {
 | 
			
		||||
        if (!this.app)
 | 
			
		||||
            this._setApp();
 | 
			
		||||
        if (!this.app && icon)
 | 
			
		||||
            this._setSummaryIcon(icon);
 | 
			
		||||
        MessageTray.Source.prototype.notify.call(this, notification);
 | 
			
		||||
 | 
			
		||||
        let tracker = Shell.WindowTracker.get_default();
 | 
			
		||||
        if (notification.resident && this.app && tracker.focus_app == this.app)
 | 
			
		||||
            this.pushNotification(notification);
 | 
			
		||||
        else
 | 
			
		||||
            this.notify(notification);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handleSummaryClick: function() {
 | 
			
		||||
        if (!this._trayIcon)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        let event = Clutter.get_current_event();
 | 
			
		||||
        if (event.type() != Clutter.EventType.BUTTON_RELEASE)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        // Left clicks are passed through only where there aren't unacknowledged
 | 
			
		||||
        // notifications, so it possible to open them in summary mode; right
 | 
			
		||||
        // clicks are always forwarded, as the right click menu is not useful for
 | 
			
		||||
        // tray icons
 | 
			
		||||
        if (event.get_button() == 1 &&
 | 
			
		||||
            this.notifications.length > 0)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (Main.overview.visible) {
 | 
			
		||||
            // We can't just connect to Main.overview's 'hidden' signal,
 | 
			
		||||
            // because it's emitted *before* it calls popModal()...
 | 
			
		||||
            let id = global.connect('notify::stage-input-mode', Lang.bind(this,
 | 
			
		||||
                function () {
 | 
			
		||||
                    global.disconnect(id);
 | 
			
		||||
                    this._trayIcon.click(event);
 | 
			
		||||
                }));
 | 
			
		||||
            Main.overview.hide();
 | 
			
		||||
        } else {
 | 
			
		||||
            this._trayIcon.click(event);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setApp: function() {
 | 
			
		||||
@@ -487,7 +562,7 @@ Source.prototype = {
 | 
			
		||||
 | 
			
		||||
        // Only override the icon if we were previously using
 | 
			
		||||
        // notification-based icons (ie, not a trayicon) or if it was unset before
 | 
			
		||||
        if (!this._isTrayIcon) {
 | 
			
		||||
        if (!this._trayIcon) {
 | 
			
		||||
            this.useNotificationIcon = false;
 | 
			
		||||
            this._setSummaryIcon(this.app.create_icon_texture (this.ICON_SIZE));
 | 
			
		||||
        }
 | 
			
		||||
@@ -496,15 +571,16 @@ Source.prototype = {
 | 
			
		||||
    setTrayIcon: function(icon) {
 | 
			
		||||
        this._setSummaryIcon(icon);
 | 
			
		||||
        this.useNotificationIcon = false;
 | 
			
		||||
        this._isTrayIcon = true;
 | 
			
		||||
        this._trayIcon = icon;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _notificationClicked: function(notification) {
 | 
			
		||||
    open: function(notification) {
 | 
			
		||||
        this.destroyNonResidentNotifications();
 | 
			
		||||
        this.openApp();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _notificationRemoved: function() {
 | 
			
		||||
        if (!this._isTrayIcon)
 | 
			
		||||
    _lastNotificationRemoved: function() {
 | 
			
		||||
        if (!this._trayIcon)
 | 
			
		||||
            this.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -517,5 +593,14 @@ Source.prototype = {
 | 
			
		||||
            let mostRecentWindow = windows[0];
 | 
			
		||||
            Main.activateWindow(mostRecentWindow);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
        if (this._nameWatcherId) {
 | 
			
		||||
            Gio.DBus.session.unwatch_name(this._nameWatcherId);
 | 
			
		||||
            this._nameWatcherId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.parent();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
@@ -8,11 +8,10 @@ const Signals = imports.signals;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
const Gdk = imports.gi.Gdk;
 | 
			
		||||
 | 
			
		||||
const AppDisplay = imports.ui.appDisplay;
 | 
			
		||||
const ContactDisplay = imports.ui.contactDisplay;
 | 
			
		||||
const Dash = imports.ui.dash;
 | 
			
		||||
const DND = imports.ui.dnd;
 | 
			
		||||
const DocDisplay = imports.ui.docDisplay;
 | 
			
		||||
@@ -20,10 +19,12 @@ const Lightbox = imports.ui.lightbox;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
const Panel = imports.ui.panel;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const PlaceDisplay = imports.ui.placeDisplay;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const ViewSelector = imports.ui.viewSelector;
 | 
			
		||||
const WorkspacesView = imports.ui.workspacesView;
 | 
			
		||||
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
 | 
			
		||||
 | 
			
		||||
// Time for initial animation going into Overview mode
 | 
			
		||||
const ANIMATION_TIME = 0.25;
 | 
			
		||||
@@ -45,11 +46,9 @@ const SwipeScrollResult = {
 | 
			
		||||
    CLICK: 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function ShellInfo() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const ShellInfo = new Lang.Class({
 | 
			
		||||
    Name: 'ShellInfo',
 | 
			
		||||
 | 
			
		||||
ShellInfo.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._source = null;
 | 
			
		||||
        this._undoCallback = null;
 | 
			
		||||
@@ -74,11 +73,13 @@ ShellInfo.prototype = {
 | 
			
		||||
            Main.messageTray.add(this._source);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let notification = this._source.notification;
 | 
			
		||||
        if (notification == null)
 | 
			
		||||
        let notification = null;
 | 
			
		||||
        if (this._source.notifications.length == 0) {
 | 
			
		||||
            notification = new MessageTray.Notification(this._source, text, null);
 | 
			
		||||
        else
 | 
			
		||||
        } else {
 | 
			
		||||
            notification = this._source.notifications[0];
 | 
			
		||||
            notification.update(text, null, { clear: true });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        notification.setTransient(true);
 | 
			
		||||
 | 
			
		||||
@@ -92,17 +93,31 @@ ShellInfo.prototype = {
 | 
			
		||||
 | 
			
		||||
        this._source.notify(notification);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function Overview() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const Overview = new Lang.Class({
 | 
			
		||||
    Name: 'Overview',
 | 
			
		||||
 | 
			
		||||
Overview.prototype = {
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        // The actual global.background_actor is inside global.window_group,
 | 
			
		||||
        // which is hidden when displaying the overview, so we display a clone.
 | 
			
		||||
        this._background = new Clutter.Clone({ source: global.background_actor });
 | 
			
		||||
    _init : function(params) {
 | 
			
		||||
        params = Params.parse(params, { isDummy: false });
 | 
			
		||||
 | 
			
		||||
        this.isDummy = params.isDummy;
 | 
			
		||||
 | 
			
		||||
        // We only have an overview in user sessions, so
 | 
			
		||||
        // create a dummy overview in other cases
 | 
			
		||||
        if (this.isDummy) {
 | 
			
		||||
            this.animationInProgress = false;
 | 
			
		||||
            this.visible = false;
 | 
			
		||||
            this.workspaces = null;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // The main BackgroundActor is inside global.window_group which is
 | 
			
		||||
        // 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._background = Meta.BackgroundActor.new_for_screen(global.screen);
 | 
			
		||||
        this._background.hide();
 | 
			
		||||
        global.overlay_group.add_actor(this._background);
 | 
			
		||||
 | 
			
		||||
@@ -120,7 +135,7 @@ Overview.prototype = {
 | 
			
		||||
                let spacing = node.get_length('spacing');
 | 
			
		||||
                if (spacing != this._spacing) {
 | 
			
		||||
                    this._spacing = spacing;
 | 
			
		||||
                    this.relayout();
 | 
			
		||||
                    this._relayout();
 | 
			
		||||
                }
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
@@ -174,29 +189,59 @@ Overview.prototype = {
 | 
			
		||||
    // signal handlers and so forth. So we create them after
 | 
			
		||||
    // construction in this init() method.
 | 
			
		||||
    init: function() {
 | 
			
		||||
        this.shellInfo = new ShellInfo();
 | 
			
		||||
        if (this.isDummy)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.viewSelector = new ViewSelector.ViewSelector();
 | 
			
		||||
        this._group.add_actor(this.viewSelector.actor);
 | 
			
		||||
        this._shellInfo = new ShellInfo();
 | 
			
		||||
 | 
			
		||||
        this._viewSelector = new ViewSelector.ViewSelector();
 | 
			
		||||
        this._group.add_actor(this._viewSelector.actor);
 | 
			
		||||
 | 
			
		||||
        this._workspacesDisplay = new WorkspacesView.WorkspacesDisplay();
 | 
			
		||||
        this.viewSelector.addViewTab(_("Windows"), this._workspacesDisplay.actor);
 | 
			
		||||
        this._viewSelector.addViewTab('windows', _("Windows"), this._workspacesDisplay.actor, 'text-x-generic');
 | 
			
		||||
 | 
			
		||||
        let appView = new AppDisplay.AllAppDisplay();
 | 
			
		||||
        this.viewSelector.addViewTab(_("Applications"), appView.actor);
 | 
			
		||||
        this._viewSelector.addViewTab('applications', _("Applications"), appView.actor, 'system-run');
 | 
			
		||||
 | 
			
		||||
        // Default search providers
 | 
			
		||||
        this.viewSelector.addSearchProvider(new AppDisplay.AppSearchProvider());
 | 
			
		||||
        this.viewSelector.addSearchProvider(new AppDisplay.PrefsSearchProvider());
 | 
			
		||||
        this.viewSelector.addSearchProvider(new PlaceDisplay.PlaceSearchProvider());
 | 
			
		||||
        this.viewSelector.addSearchProvider(new DocDisplay.DocSearchProvider());
 | 
			
		||||
        this.addSearchProvider(new AppDisplay.AppSearchProvider());
 | 
			
		||||
        this.addSearchProvider(new AppDisplay.SettingsSearchProvider());
 | 
			
		||||
        this.addSearchProvider(new PlaceDisplay.PlaceSearchProvider());
 | 
			
		||||
        this.addSearchProvider(new DocDisplay.DocSearchProvider());
 | 
			
		||||
        this.addSearchProvider(new ContactDisplay.ContactSearchProvider());
 | 
			
		||||
 | 
			
		||||
        // TODO - recalculate everything when desktop size changes
 | 
			
		||||
        this.dash = new Dash.Dash();
 | 
			
		||||
        this._group.add_actor(this.dash.actor);
 | 
			
		||||
        this.dash.actor.add_constraint(this.viewSelector.constrainY);
 | 
			
		||||
        this.dash.actor.add_constraint(this.viewSelector.constrainHeight);
 | 
			
		||||
        this._dash = new Dash.Dash();
 | 
			
		||||
        this._group.add_actor(this._dash.actor);
 | 
			
		||||
        this._dash.actor.add_constraint(this._viewSelector.constrainY);
 | 
			
		||||
        this._dash.actor.add_constraint(this._viewSelector.constrainHeight);
 | 
			
		||||
        this.dashIconSize = this._dash.iconSize;
 | 
			
		||||
        this._dash.connect('icon-size-changed',
 | 
			
		||||
                           Lang.bind(this, function() {
 | 
			
		||||
                               this.dashIconSize = this._dash.iconSize;
 | 
			
		||||
                           }));
 | 
			
		||||
 | 
			
		||||
        // Translators: this is the name of the dock/favorites area on
 | 
			
		||||
        // the left of the overview
 | 
			
		||||
        Main.ctrlAltTabManager.addGroup(this._dash.actor, _("Dash"), 'user-bookmarks');
 | 
			
		||||
 | 
			
		||||
        Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._relayout));
 | 
			
		||||
        this._relayout();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addSearchProvider: function(provider) {
 | 
			
		||||
        this._viewSelector.addSearchProvider(provider);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    removeSearchProvider: function(provider) {
 | 
			
		||||
        this._viewSelector.removeSearchProvider(provider);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setMessage: function(text, undoCallback, undoLabel) {
 | 
			
		||||
        if (this.isDummy)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._shellInfo.setMessage(text, undoCallback, undoLabel);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDragBegin: function() {
 | 
			
		||||
@@ -213,8 +258,18 @@ Overview.prototype = {
 | 
			
		||||
            global.screen.get_workspace_by_index(this._lastActiveWorkspaceIndex).activate(time);
 | 
			
		||||
            this.hideTemporarily();
 | 
			
		||||
        }
 | 
			
		||||
        this._resetWindowSwitchTimeout();
 | 
			
		||||
        this._lastHoveredWindow = null;
 | 
			
		||||
        DND.removeMonitor(this._dragMonitor);
 | 
			
		||||
        DND.removeDragMonitor(this._dragMonitor);
 | 
			
		||||
        this.endItemDrag();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _resetWindowSwitchTimeout: function() {
 | 
			
		||||
        if (this._windowSwitchTimeoutId != 0) {
 | 
			
		||||
            Mainloop.source_remove(this._windowSwitchTimeoutId);
 | 
			
		||||
            this._windowSwitchTimeoutId = 0;
 | 
			
		||||
            this._needsFakePointerEvent = false;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _fakePointerEvent: function() {
 | 
			
		||||
@@ -229,7 +284,10 @@ Overview.prototype = {
 | 
			
		||||
    _onDragMotion: function(dragEvent) {
 | 
			
		||||
        let targetIsWindow = dragEvent.targetActor &&
 | 
			
		||||
                             dragEvent.targetActor._delegate &&
 | 
			
		||||
                             dragEvent.targetActor._delegate.metaWindow;
 | 
			
		||||
                             dragEvent.targetActor._delegate.metaWindow &&
 | 
			
		||||
                             !(dragEvent.targetActor._delegate instanceof WorkspaceThumbnail.WindowClone);
 | 
			
		||||
 | 
			
		||||
        this._windowSwitchTimestamp = global.get_current_time();
 | 
			
		||||
 | 
			
		||||
        if (targetIsWindow &&
 | 
			
		||||
            dragEvent.targetActor._delegate.metaWindow == this._lastHoveredWindow)
 | 
			
		||||
@@ -237,15 +295,10 @@ Overview.prototype = {
 | 
			
		||||
 | 
			
		||||
        this._lastHoveredWindow = null;
 | 
			
		||||
 | 
			
		||||
        if (this._windowSwitchTimeoutId != 0) {
 | 
			
		||||
            Mainloop.source_remove(this._windowSwitchTimeoutId);
 | 
			
		||||
            this._windowSwitchTimeoutId = 0;
 | 
			
		||||
            this._needsFakePointerEvent = false;
 | 
			
		||||
        }
 | 
			
		||||
        this._resetWindowSwitchTimeout();
 | 
			
		||||
 | 
			
		||||
        if (targetIsWindow) {
 | 
			
		||||
            this._lastHoveredWindow = dragEvent.targetActor._delegate.metaWindow;
 | 
			
		||||
            this._windowSwitchTimestamp = global.get_current_time();
 | 
			
		||||
            this._windowSwitchTimeoutId = Mainloop.timeout_add(DND_WINDOW_SWITCH_TIMEOUT,
 | 
			
		||||
                                            Lang.bind(this, function() {
 | 
			
		||||
                                                this._needsFakePointerEvent = true;
 | 
			
		||||
@@ -260,6 +313,9 @@ Overview.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setScrollAdjustment: function(adjustment, direction) {
 | 
			
		||||
        if (this.isDummy)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._scrollAdjustment = adjustment;
 | 
			
		||||
        if (this._scrollAdjustment == null)
 | 
			
		||||
            this._scrollDirection = SwipeScrollDirection.NONE;
 | 
			
		||||
@@ -268,7 +324,8 @@ Overview.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onButtonPress: function(actor, event) {
 | 
			
		||||
        if (this._scrollDirection == SwipeScrollDirection.NONE)
 | 
			
		||||
        if (this._scrollDirection == SwipeScrollDirection.NONE
 | 
			
		||||
            || event.get_button() != 1)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let [stageX, stageY] = event.get_coords();
 | 
			
		||||
@@ -377,7 +434,7 @@ Overview.prototype = {
 | 
			
		||||
                [stageX, stageY] = event.get_coords();
 | 
			
		||||
                let dx = this._dragX - stageX;
 | 
			
		||||
                let dy = this._dragY - stageY;
 | 
			
		||||
                let primary = global.get_primary_monitor();
 | 
			
		||||
                let primary = Main.layoutManager.primaryMonitor;
 | 
			
		||||
 | 
			
		||||
                this._dragX = stageX;
 | 
			
		||||
                this._dragY = stageY;
 | 
			
		||||
@@ -424,11 +481,16 @@ Overview.prototype = {
 | 
			
		||||
        return clone;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    relayout: function () {
 | 
			
		||||
        let primary = global.get_primary_monitor();
 | 
			
		||||
    _relayout: function () {
 | 
			
		||||
        // To avoid updating the position and size of the workspaces
 | 
			
		||||
        // we just hide the overview. The positions will be updated
 | 
			
		||||
        // when it is next shown.
 | 
			
		||||
        this.hide();
 | 
			
		||||
 | 
			
		||||
        let primary = Main.layoutManager.primaryMonitor;
 | 
			
		||||
        let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
 | 
			
		||||
 | 
			
		||||
        let contentY = Panel.PANEL_HEIGHT;
 | 
			
		||||
        let contentY = Main.panel.actor.height;
 | 
			
		||||
        let contentHeight = primary.height - contentY - Main.messageTray.actor.height;
 | 
			
		||||
 | 
			
		||||
        this._group.set_position(primary.x, primary.y);
 | 
			
		||||
@@ -446,15 +508,15 @@ Overview.prototype = {
 | 
			
		||||
        // Set the dash's x position - y is handled by a constraint
 | 
			
		||||
        let dashX;
 | 
			
		||||
        if (rtl) {
 | 
			
		||||
            this.dash.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
 | 
			
		||||
            this._dash.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
 | 
			
		||||
            dashX = primary.width;
 | 
			
		||||
        } else {
 | 
			
		||||
            dashX = 0;
 | 
			
		||||
        }
 | 
			
		||||
        this.dash.actor.set_x(dashX);
 | 
			
		||||
        this._dash.actor.set_x(dashX);
 | 
			
		||||
 | 
			
		||||
        this.viewSelector.actor.set_position(viewX, viewY);
 | 
			
		||||
        this.viewSelector.actor.set_size(viewWidth, viewHeight);
 | 
			
		||||
        this._viewSelector.actor.set_position(viewX, viewY);
 | 
			
		||||
        this._viewSelector.actor.set_size(viewWidth, viewHeight);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    //// Public methods ////
 | 
			
		||||
@@ -463,6 +525,10 @@ Overview.prototype = {
 | 
			
		||||
        this.emit('item-drag-begin');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    cancelledItemDrag: function(source) {
 | 
			
		||||
        this.emit('item-drag-cancelled');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    endItemDrag: function(source) {
 | 
			
		||||
        this.emit('item-drag-end');
 | 
			
		||||
    },
 | 
			
		||||
@@ -471,43 +537,24 @@ Overview.prototype = {
 | 
			
		||||
        this.emit('window-drag-begin');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    cancelledWindowDrag: function(source) {
 | 
			
		||||
        this.emit('window-drag-cancelled');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    endWindowDrag: function(source) {
 | 
			
		||||
        this.emit('window-drag-end');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Returns the scale the Overview has when we just start zooming out
 | 
			
		||||
    // to overview mode. That is, when just the active workspace is showing.
 | 
			
		||||
    getZoomedInScale : function() {
 | 
			
		||||
        return 1 / this.workspaces.getScale();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Returns the position the Overview has when we just start zooming out
 | 
			
		||||
    // to overview mode. That is, when just the active workspace is showing.
 | 
			
		||||
    getZoomedInPosition : function() {
 | 
			
		||||
        let [posX, posY] = this.workspaces.getActiveWorkspacePosition();
 | 
			
		||||
        let scale = this.getZoomedInScale();
 | 
			
		||||
 | 
			
		||||
        return [- posX * scale, - posY * scale];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Returns the current scale of the Overview.
 | 
			
		||||
    getScale : function() {
 | 
			
		||||
        return this.workspaces.actor.scaleX;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Returns the current position of the Overview.
 | 
			
		||||
    getPosition : function() {
 | 
			
		||||
        return [this.workspaces.actor.x, this.workspaces.actor.y];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // show:
 | 
			
		||||
    //
 | 
			
		||||
    // Animates the overview visible and grabs mouse and keyboard input
 | 
			
		||||
    show : function() {
 | 
			
		||||
        if (this.isDummy)
 | 
			
		||||
            return;
 | 
			
		||||
        if (this._shown)
 | 
			
		||||
            return;
 | 
			
		||||
        // Do this manually instead of using _syncInputMode, to handle failure
 | 
			
		||||
        if (!Main.pushModal(this.viewSelector.actor))
 | 
			
		||||
        if (!Main.pushModal(this._group))
 | 
			
		||||
            return;
 | 
			
		||||
        this._modal = true;
 | 
			
		||||
        this._animateVisible();
 | 
			
		||||
@@ -531,6 +578,9 @@ Overview.prototype = {
 | 
			
		||||
        //
 | 
			
		||||
        // If we switched to displaying the actors in the Overview rather than
 | 
			
		||||
        // clones of them, this would obviously no longer be necessary.
 | 
			
		||||
        //
 | 
			
		||||
        // Disable unredirection while in the overview
 | 
			
		||||
        Meta.disable_unredirect_for_screen(global.screen);
 | 
			
		||||
        global.window_group.hide();
 | 
			
		||||
        this._group.show();
 | 
			
		||||
        this._background.show();
 | 
			
		||||
@@ -553,30 +603,19 @@ Overview.prototype = {
 | 
			
		||||
                             });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Create a zoom out effect. First scale the workspaces view up and
 | 
			
		||||
        // position it so that the active workspace fills up the whole screen,
 | 
			
		||||
        // then transform it to its normal dimensions and position.
 | 
			
		||||
        // The opposite transition is used in hide().
 | 
			
		||||
        this.workspaces.actor.scaleX = this.workspaces.actor.scaleY = this.getZoomedInScale();
 | 
			
		||||
        [this.workspaces.actor.x, this.workspaces.actor.y] = this.getZoomedInPosition();
 | 
			
		||||
        let primary = global.get_primary_monitor();
 | 
			
		||||
        Tweener.addTween(this.workspaces.actor,
 | 
			
		||||
                         { x: primary.x - this._group.x,
 | 
			
		||||
                           y: primary.y - this._group.y,
 | 
			
		||||
                           scaleX: 1,
 | 
			
		||||
                           scaleY: 1,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           time: ANIMATION_TIME,
 | 
			
		||||
                           onComplete: this._showDone,
 | 
			
		||||
                           onCompleteScope: this
 | 
			
		||||
                          });
 | 
			
		||||
 | 
			
		||||
        // Make the other elements fade in.
 | 
			
		||||
        this._group.opacity = 0;
 | 
			
		||||
        Tweener.addTween(this._group,
 | 
			
		||||
                         { opacity: 255,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           time: ANIMATION_TIME
 | 
			
		||||
                           time: ANIMATION_TIME,
 | 
			
		||||
                           onComplete: this._showDone,
 | 
			
		||||
                           onCompleteScope: this
 | 
			
		||||
                         });
 | 
			
		||||
 | 
			
		||||
        Tweener.addTween(this._background,
 | 
			
		||||
                         { dim_factor: 0.4,
 | 
			
		||||
                           time: ANIMATION_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad'
 | 
			
		||||
                         });
 | 
			
		||||
 | 
			
		||||
        this._coverPane.raise_top();
 | 
			
		||||
@@ -591,6 +630,9 @@ Overview.prototype = {
 | 
			
		||||
    // will result in the overview not being hidden until hideTemporarily() is
 | 
			
		||||
    // called.
 | 
			
		||||
    showTemporarily: function() {
 | 
			
		||||
        if (this.isDummy)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (this._shownTemporarily)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
@@ -603,6 +645,9 @@ Overview.prototype = {
 | 
			
		||||
    //
 | 
			
		||||
    // Reverses the effect of show()
 | 
			
		||||
    hide: function() {
 | 
			
		||||
        if (this.isDummy)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (!this._shown)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
@@ -621,6 +666,9 @@ Overview.prototype = {
 | 
			
		||||
    //
 | 
			
		||||
    // Reverses the effect of showTemporarily()
 | 
			
		||||
    hideTemporarily: function() {
 | 
			
		||||
        if (this.isDummy)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (!this._shownTemporarily)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
@@ -632,24 +680,15 @@ Overview.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    toggle: function() {
 | 
			
		||||
        if (this.isDummy)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (this._shown)
 | 
			
		||||
            this.hide();
 | 
			
		||||
        else
 | 
			
		||||
            this.show();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * getWorkspacesForWindow:
 | 
			
		||||
     * @metaWindow: A #MetaWindow
 | 
			
		||||
     *
 | 
			
		||||
     * Returns the Workspaces object associated with the given window.
 | 
			
		||||
     * This method is not be accessible if the overview is not open
 | 
			
		||||
     * and will return %null.
 | 
			
		||||
     */
 | 
			
		||||
    getWorkspacesForWindow: function(metaWindow) {
 | 
			
		||||
        return this.workspaces;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    //// Private methods ////
 | 
			
		||||
 | 
			
		||||
    _syncInputMode: function() {
 | 
			
		||||
@@ -661,20 +700,20 @@ Overview.prototype = {
 | 
			
		||||
 | 
			
		||||
        if (this._shown) {
 | 
			
		||||
            if (!this._modal) {
 | 
			
		||||
                if (Main.pushModal(this.dash.actor))
 | 
			
		||||
                if (Main.pushModal(this._group))
 | 
			
		||||
                    this._modal = true;
 | 
			
		||||
                else
 | 
			
		||||
                    this.hide();
 | 
			
		||||
            }
 | 
			
		||||
        } else if (this._shownTemporarily) {
 | 
			
		||||
            if (this._modal) {
 | 
			
		||||
                Main.popModal(this.dash.actor);
 | 
			
		||||
                Main.popModal(this._group);
 | 
			
		||||
                this._modal = false;
 | 
			
		||||
            }
 | 
			
		||||
            global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
 | 
			
		||||
        } else {
 | 
			
		||||
            if (this._modal) {
 | 
			
		||||
                Main.popModal(this.dash.actor);
 | 
			
		||||
                Main.popModal(this._group);
 | 
			
		||||
                this._modal = false;
 | 
			
		||||
            }
 | 
			
		||||
            else if (global.stage_input_mode == Shell.StageInputMode.FULLSCREEN)
 | 
			
		||||
@@ -700,27 +739,19 @@ Overview.prototype = {
 | 
			
		||||
 | 
			
		||||
        this.workspaces.hide();
 | 
			
		||||
 | 
			
		||||
        // Create a zoom in effect by transforming the workspaces view so that
 | 
			
		||||
        // the active workspace fills up the whole screen. The opposite
 | 
			
		||||
        // transition is used in show().
 | 
			
		||||
        let scale = this.getZoomedInScale();
 | 
			
		||||
        let [posX, posY] = this.getZoomedInPosition();
 | 
			
		||||
        Tweener.addTween(this.workspaces.actor,
 | 
			
		||||
                         { x: posX,
 | 
			
		||||
                           y: posY,
 | 
			
		||||
                           scaleX: scale,
 | 
			
		||||
                           scaleY: scale,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           time: ANIMATION_TIME,
 | 
			
		||||
                           onComplete: this._hideDone,
 | 
			
		||||
                           onCompleteScope: this
 | 
			
		||||
                          });
 | 
			
		||||
 | 
			
		||||
        // Make other elements fade out.
 | 
			
		||||
        Tweener.addTween(this._group,
 | 
			
		||||
                         { opacity: 0,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           time: ANIMATION_TIME
 | 
			
		||||
                           time: ANIMATION_TIME,
 | 
			
		||||
                           onComplete: this._hideDone,
 | 
			
		||||
                           onCompleteScope: this
 | 
			
		||||
                         });
 | 
			
		||||
 | 
			
		||||
        Tweener.addTween(this._background,
 | 
			
		||||
                         { dim_factor: 1.0,
 | 
			
		||||
                           time: ANIMATION_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad'
 | 
			
		||||
                         });
 | 
			
		||||
 | 
			
		||||
        this._coverPane.raise_top();
 | 
			
		||||
@@ -739,9 +770,13 @@ Overview.prototype = {
 | 
			
		||||
            this._animateNotVisible();
 | 
			
		||||
 | 
			
		||||
        this._syncInputMode();
 | 
			
		||||
        global.sync_pointer();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _hideDone: function() {
 | 
			
		||||
        // Re-enable unredirection
 | 
			
		||||
        Meta.enable_unredirect_for_screen(global.screen);
 | 
			
		||||
 | 
			
		||||
        global.window_group.show();
 | 
			
		||||
 | 
			
		||||
        this.workspaces.destroy();
 | 
			
		||||
@@ -772,5 +807,5 @@ Overview.prototype = {
 | 
			
		||||
            this._needsFakePointerEvent = false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(Overview.prototype);
 | 
			
		||||
 
 | 
			
		||||