Compare commits
	
		
			1627 Commits
		
	
	
		
			3.1.90
			...
			screen-shi
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					6e448a2711 | ||
| 
						 | 
					1d484e2278 | ||
| 
						 | 
					0b7ca098ad | ||
| 
						 | 
					5cb9aa9cf3 | ||
| 
						 | 
					0171e561f2 | ||
| 
						 | 
					82f7431a28 | ||
| 
						 | 
					29958df7e7 | ||
| 
						 | 
					2f990346df | ||
| 
						 | 
					a29ceaa8ec | ||
| 
						 | 
					782e11b96c | ||
| 
						 | 
					fd3be5b7de | ||
| 
						 | 
					0b9a5c3441 | ||
| 
						 | 
					7431c4d611 | ||
| 
						 | 
					ec78dd60fc | ||
| 
						 | 
					b479eec758 | ||
| 
						 | 
					413ace2eb1 | ||
| 
						 | 
					d8390ef77f | ||
| 
						 | 
					e7e56e175a | ||
| 
						 | 
					e875b9cdca | ||
| 
						 | 
					66197b18b6 | ||
| 
						 | 
					ed991f79b1 | ||
| 
						 | 
					48b70f358d | ||
| 
						 | 
					56adbda2dc | ||
| 
						 | 
					7dbc78c95f | ||
| 
						 | 
					3ffa1e35e8 | ||
| 
						 | 
					114fb4219b | ||
| 
						 | 
					4d7d66bc1f | ||
| 
						 | 
					e134d2e5a5 | ||
| 
						 | 
					cca84761a5 | ||
| 
						 | 
					c2a5d6f61b | ||
| 
						 | 
					4449007bb4 | ||
| 
						 | 
					30cd1e84bc | ||
| 
						 | 
					dcf872b485 | ||
| 
						 | 
					c9d51ca775 | ||
| 
						 | 
					96c9f8058b | ||
| 
						 | 
					a3f4bca14e | ||
| 
						 | 
					e55f2dd3b9 | ||
| 
						 | 
					247566ca1d | ||
| 
						 | 
					aa120e0902 | ||
| 
						 | 
					5c7992beef | ||
| 
						 | 
					6a615f30dc | ||
| 
						 | 
					bfea41b771 | ||
| 
						 | 
					a2465e0670 | ||
| 
						 | 
					57044ea9a0 | ||
| 
						 | 
					1392be2952 | ||
| 
						 | 
					9e503aa69c | ||
| 
						 | 
					a004389f25 | ||
| 
						 | 
					d474261912 | ||
| 
						 | 
					144e959cab | ||
| 
						 | 
					626488e659 | ||
| 
						 | 
					5bae5574f0 | ||
| 
						 | 
					ce14d6d9db | ||
| 
						 | 
					519addf6ac | ||
| 
						 | 
					fd87468e36 | ||
| 
						 | 
					75e49610cb | ||
| 
						 | 
					414fe75d02 | ||
| 
						 | 
					26031eb761 | ||
| 
						 | 
					be801dff5f | ||
| 
						 | 
					5fd47ed742 | ||
| 
						 | 
					f7f2f50435 | ||
| 
						 | 
					e0bb15e572 | ||
| 
						 | 
					0e4171a87c | ||
| 
						 | 
					34cb92ff4c | ||
| 
						 | 
					22eea750f3 | ||
| 
						 | 
					c3afe1a83a | ||
| 
						 | 
					904ceba6b2 | ||
| 
						 | 
					a28d639c3b | ||
| 
						 | 
					c0652bcd8f | ||
| 
						 | 
					54dc0fd123 | ||
| 
						 | 
					c22a00afee | ||
| 
						 | 
					2c3ec7846f | ||
| 
						 | 
					46db9edacc | ||
| 
						 | 
					4e6fa56c87 | ||
| 
						 | 
					8970e17911 | ||
| 
						 | 
					ac6c808124 | ||
| 
						 | 
					26d3b1929e | ||
| 
						 | 
					a29507e452 | ||
| 
						 | 
					2c073fb005 | ||
| 
						 | 
					d9c3b83d1e | ||
| 
						 | 
					f5e58c500f | ||
| 
						 | 
					5e865f5bc4 | ||
| 
						 | 
					01a1255967 | ||
| 
						 | 
					dd80f39049 | ||
| 
						 | 
					19e4c953ef | ||
| 
						 | 
					ef218c95fc | ||
| 
						 | 
					eec9dba855 | ||
| 
						 | 
					f46a165886 | ||
| 
						 | 
					ec47bd1604 | ||
| 
						 | 
					bfd4016c1c | ||
| 
						 | 
					63cdb1848e | ||
| 
						 | 
					10a0762fe7 | ||
| 
						 | 
					76472b86ed | ||
| 
						 | 
					edb96cde70 | ||
| 
						 | 
					e06ecb8f0c | ||
| 
						 | 
					2791d948e9 | ||
| 
						 | 
					360e6e790a | ||
| 
						 | 
					d0807c8276 | ||
| 
						 | 
					75d0362cd8 | ||
| 
						 | 
					4f7c554d8d | ||
| 
						 | 
					8b81f23caf | ||
| 
						 | 
					0098c2b7f7 | ||
| 
						 | 
					f0e03b5e82 | ||
| 
						 | 
					be2f1001a5 | ||
| 
						 | 
					cf08b4d56a | ||
| 
						 | 
					04074f883f | ||
| 
						 | 
					14d3235f1a | ||
| 
						 | 
					e00c1cbd20 | ||
| 
						 | 
					3df3f0d9dc | ||
| 
						 | 
					985db40547 | ||
| 
						 | 
					c9fa0fdff0 | ||
| 
						 | 
					fe69ea305b | ||
| 
						 | 
					ff9088e42b | ||
| 
						 | 
					f556cdf0ca | ||
| 
						 | 
					c671ff74c6 | ||
| 
						 | 
					04570ac783 | ||
| 
						 | 
					6ab25cd791 | ||
| 
						 | 
					a04350f7ce | ||
| 
						 | 
					b7018de7e0 | ||
| 
						 | 
					d212d57466 | ||
| 
						 | 
					c4e7d8ed8c | ||
| 
						 | 
					464813ecbb | ||
| 
						 | 
					9812771dcd | ||
| 
						 | 
					6f605598de | ||
| 
						 | 
					85bc8ccccc | ||
| 
						 | 
					e756c2dbce | ||
| 
						 | 
					e82fe14f00 | ||
| 
						 | 
					de65739c01 | ||
| 
						 | 
					e1ec89a133 | ||
| 
						 | 
					bdb3410d9d | ||
| 
						 | 
					168e0b5a42 | ||
| 
						 | 
					f906cfe5f6 | ||
| 
						 | 
					9faac81a37 | ||
| 
						 | 
					b90e7eb95c | ||
| 
						 | 
					1e286e43ad | ||
| 
						 | 
					539993b4f4 | ||
| 
						 | 
					1363d30f79 | ||
| 
						 | 
					3a48daaa64 | ||
| 
						 | 
					d2b4a65e65 | ||
| 
						 | 
					1ead290c23 | ||
| 
						 | 
					6658660355 | ||
| 
						 | 
					85ab019987 | ||
| 
						 | 
					460cda2aa1 | ||
| 
						 | 
					2d913578e1 | ||
| 
						 | 
					34831796f6 | ||
| 
						 | 
					8754b2767c | ||
| 
						 | 
					04fb688f7d | ||
| 
						 | 
					58dbd285fc | ||
| 
						 | 
					cf6f149888 | ||
| 
						 | 
					8d017ceaf1 | ||
| 
						 | 
					02428019fa | ||
| 
						 | 
					b4464929cb | ||
| 
						 | 
					3ea22f8b0e | ||
| 
						 | 
					9745e97e14 | ||
| 
						 | 
					6c6e182ecc | ||
| 
						 | 
					7973dd45b7 | ||
| 
						 | 
					a1837dde68 | ||
| 
						 | 
					4448b65a18 | ||
| 
						 | 
					2231c23c4d | ||
| 
						 | 
					f17fc43d6e | ||
| 
						 | 
					f9dbe56785 | ||
| 
						 | 
					8845a2170c | ||
| 
						 | 
					a4b1ebd8c3 | ||
| 
						 | 
					66adeef9bd | ||
| 
						 | 
					20769f68a7 | ||
| 
						 | 
					e92719b98d | ||
| 
						 | 
					59246babea | ||
| 
						 | 
					23e86d7dd5 | ||
| 
						 | 
					c99e8eb29d | ||
| 
						 | 
					7949397958 | ||
| 
						 | 
					1d1359b58f | ||
| 
						 | 
					8915bb4892 | ||
| 
						 | 
					6a117ac12f | ||
| 
						 | 
					67689f1a6d | ||
| 
						 | 
					48b83f1ffd | ||
| 
						 | 
					7da0f398a5 | ||
| 
						 | 
					7e277fdd4a | ||
| 
						 | 
					5d10d8566b | ||
| 
						 | 
					a10295f584 | ||
| 
						 | 
					46cf9faa11 | ||
| 
						 | 
					971341bb53 | ||
| 
						 | 
					2b2a235a49 | ||
| 
						 | 
					970b9deeaa | ||
| 
						 | 
					fd256b624c | ||
| 
						 | 
					698fb64be9 | ||
| 
						 | 
					9561f77b17 | ||
| 
						 | 
					c3d3d346d4 | ||
| 
						 | 
					e43fe98263 | ||
| 
						 | 
					04dbf15d9b | ||
| 
						 | 
					de72065a4a | ||
| 
						 | 
					a1bb0ec738 | ||
| 
						 | 
					1a33cd9584 | ||
| 
						 | 
					00279dbd04 | ||
| 
						 | 
					eb759cf22f | ||
| 
						 | 
					ae16da4e81 | ||
| 
						 | 
					965287e724 | ||
| 
						 | 
					3d5312e8d2 | ||
| 
						 | 
					bc91b7dcae | ||
| 
						 | 
					4d77eb94ff | ||
| 
						 | 
					1b8d03f945 | ||
| 
						 | 
					de2dcfeb99 | ||
| 
						 | 
					c7196a519f | ||
| 
						 | 
					0d82ce5210 | ||
| 
						 | 
					3ce9ad05b3 | ||
| 
						 | 
					ab75faac74 | ||
| 
						 | 
					9e25e13218 | ||
| 
						 | 
					69e1503c6d | ||
| 
						 | 
					7eaf231e56 | ||
| 
						 | 
					a347a72091 | ||
| 
						 | 
					560daec913 | ||
| 
						 | 
					d9e968d863 | ||
| 
						 | 
					556d5d181e | ||
| 
						 | 
					4e4092f9e8 | ||
| 
						 | 
					fd62aba71c | ||
| 
						 | 
					ef0aa65774 | ||
| 
						 | 
					6b5f9a647a | ||
| 
						 | 
					01c07fbea1 | ||
| 
						 | 
					81929c2a92 | ||
| 
						 | 
					d9ff8e3122 | ||
| 
						 | 
					0c4692ae58 | ||
| 
						 | 
					df56ff4f09 | ||
| 
						 | 
					96cdc9c4eb | ||
| 
						 | 
					3b4ad5cd7d | ||
| 
						 | 
					317c6b77f3 | ||
| 
						 | 
					e5f5a2adaa | ||
| 
						 | 
					594c3174ab | ||
| 
						 | 
					5b7e4bb4a7 | ||
| 
						 | 
					f7c0f826d4 | ||
| 
						 | 
					66af7de6d6 | ||
| 
						 | 
					d1815a36d0 | ||
| 
						 | 
					61de3de909 | ||
| 
						 | 
					36888a34d6 | ||
| 
						 | 
					646435ee3e | ||
| 
						 | 
					cbb8d5b0dc | ||
| 
						 | 
					ebee01b355 | ||
| 
						 | 
					0e3795b2f3 | ||
| 
						 | 
					de73128d47 | ||
| 
						 | 
					281b0a3e63 | ||
| 
						 | 
					c414f9ac9d | ||
| 
						 | 
					77242cfec0 | ||
| 
						 | 
					8ebbba6eb8 | ||
| 
						 | 
					0804cefbee | ||
| 
						 | 
					2404d2935d | ||
| 
						 | 
					e6f5e21b5d | ||
| 
						 | 
					c303c6b5c1 | ||
| 
						 | 
					f58e8f2a35 | ||
| 
						 | 
					ededba0c6d | ||
| 
						 | 
					e112fa92fe | ||
| 
						 | 
					7524210d1f | ||
| 
						 | 
					201dc05416 | ||
| 
						 | 
					2b34978993 | ||
| 
						 | 
					447246da74 | ||
| 
						 | 
					1cf2bb6646 | ||
| 
						 | 
					de1eafb564 | ||
| 
						 | 
					22f0099a5d | ||
| 
						 | 
					300eb87016 | ||
| 
						 | 
					aa38b16368 | ||
| 
						 | 
					266bfdf739 | ||
| 
						 | 
					19ef6b0421 | ||
| 
						 | 
					75570b7995 | ||
| 
						 | 
					3290bfae68 | ||
| 
						 | 
					0805d7a35f | ||
| 
						 | 
					11278a0814 | ||
| 
						 | 
					86de6f5861 | ||
| 
						 | 
					498b023989 | ||
| 
						 | 
					5265884af9 | ||
| 
						 | 
					cdbe0bbf38 | ||
| 
						 | 
					feef35a8ca | ||
| 
						 | 
					3ff51da529 | ||
| 
						 | 
					496e9f7b16 | ||
| 
						 | 
					0b30dc29a5 | ||
| 
						 | 
					15b4d29e70 | ||
| 
						 | 
					9eee4b7687 | ||
| 
						 | 
					196f6c241a | ||
| 
						 | 
					c9296191a8 | ||
| 
						 | 
					c7b4022283 | ||
| 
						 | 
					a7ecc4cdd6 | ||
| 
						 | 
					df5298d59c | ||
| 
						 | 
					b79d17332e | ||
| 
						 | 
					675572a41a | ||
| 
						 | 
					0078fe9349 | ||
| 
						 | 
					dc004f6eb7 | ||
| 
						 | 
					07f1a05ab4 | ||
| 
						 | 
					54292a99af | ||
| 
						 | 
					f5933c8cb8 | ||
| 
						 | 
					6700f86145 | ||
| 
						 | 
					b31d22488e | ||
| 
						 | 
					6382eeb8fd | ||
| 
						 | 
					b07345a55c | ||
| 
						 | 
					06febdce22 | ||
| 
						 | 
					c31d9d5e3d | ||
| 
						 | 
					cda8a545f1 | ||
| 
						 | 
					f850e92524 | ||
| 
						 | 
					cc9d53e038 | ||
| 
						 | 
					7b048fc092 | ||
| 
						 | 
					4ba4a501fd | ||
| 
						 | 
					2b2cce6896 | ||
| 
						 | 
					c1f51a7bf3 | ||
| 
						 | 
					465556f0d8 | ||
| 
						 | 
					db7ac5208a | ||
| 
						 | 
					cfcd1bc014 | ||
| 
						 | 
					e63f7e8779 | ||
| 
						 | 
					7911154bad | ||
| 
						 | 
					ec0730f3e5 | ||
| 
						 | 
					76005f5adf | ||
| 
						 | 
					94493cde35 | ||
| 
						 | 
					a1f68720e5 | ||
| 
						 | 
					022376dd56 | ||
| 
						 | 
					934e5aacab | ||
| 
						 | 
					35b142f23f | ||
| 
						 | 
					41c3795a7b | ||
| 
						 | 
					95d7099133 | ||
| 
						 | 
					33dc9abb9b | ||
| 
						 | 
					5e4edac14d | ||
| 
						 | 
					cb5ae92986 | ||
| 
						 | 
					ebbd295ebe | ||
| 
						 | 
					65d23fb9a3 | ||
| 
						 | 
					ad6d986172 | ||
| 
						 | 
					985641cc2e | ||
| 
						 | 
					de0a714081 | ||
| 
						 | 
					3f942302d1 | ||
| 
						 | 
					96396163cf | ||
| 
						 | 
					0c736c4561 | ||
| 
						 | 
					33ad9d1035 | ||
| 
						 | 
					d57658d059 | ||
| 
						 | 
					031206cf1f | ||
| 
						 | 
					12c7cc278d | ||
| 
						 | 
					9d3750b9b8 | ||
| 
						 | 
					ba4b9f229e | ||
| 
						 | 
					850fe98cbb | ||
| 
						 | 
					8a9e3e0df2 | ||
| 
						 | 
					a277569d31 | ||
| 
						 | 
					7ed9516884 | ||
| 
						 | 
					ecff2fa2b7 | ||
| 
						 | 
					e49b94658c | ||
| 
						 | 
					e4f1572a3a | ||
| 
						 | 
					b5b13322d8 | ||
| 
						 | 
					c25e7f3c41 | ||
| 
						 | 
					f6a2c92bfa | ||
| 
						 | 
					ed17418101 | ||
| 
						 | 
					5264f39209 | ||
| 
						 | 
					de69c719fb | ||
| 
						 | 
					ab3173487d | ||
| 
						 | 
					a3fcb8c284 | ||
| 
						 | 
					ba92cfa064 | ||
| 
						 | 
					6bee51ed33 | ||
| 
						 | 
					122bca49ea | ||
| 
						 | 
					19318a1eeb | ||
| 
						 | 
					a7a46bbe1c | ||
| 
						 | 
					3d26224180 | ||
| 
						 | 
					940ddb104c | ||
| 
						 | 
					5617f91281 | ||
| 
						 | 
					a9a863aab4 | ||
| 
						 | 
					ca26347dea | ||
| 
						 | 
					41a14e808e | ||
| 
						 | 
					6452501275 | ||
| 
						 | 
					b61ada72cc | ||
| 
						 | 
					ace42d845c | ||
| 
						 | 
					850b6f28e5 | ||
| 
						 | 
					3c81e9f0e7 | ||
| 
						 | 
					e20ea19f34 | ||
| 
						 | 
					ce041a3190 | ||
| 
						 | 
					3a01aaf7fb | ||
| 
						 | 
					ec4a2aae95 | ||
| 
						 | 
					de8a66d4ce | ||
| 
						 | 
					dc3d3acb3b | ||
| 
						 | 
					48d6eb168f | ||
| 
						 | 
					6190d6c962 | ||
| 
						 | 
					76616dc98c | ||
| 
						 | 
					82c2f5221d | ||
| 
						 | 
					a3bbb7be14 | ||
| 
						 | 
					9e1a2cfeac | ||
| 
						 | 
					c6fabe504a | ||
| 
						 | 
					61a17d7fab | ||
| 
						 | 
					865cfa5211 | ||
| 
						 | 
					e2b857adae | ||
| 
						 | 
					f3924ccd91 | ||
| 
						 | 
					86e3e59530 | ||
| 
						 | 
					02e4726ba6 | ||
| 
						 | 
					66e470e073 | ||
| 
						 | 
					afaa5c24d6 | ||
| 
						 | 
					518282e169 | ||
| 
						 | 
					d955adbbad | ||
| 
						 | 
					83d3225e57 | ||
| 
						 | 
					6fa45975bf | ||
| 
						 | 
					e6087efb40 | ||
| 
						 | 
					4ce2f80a2f | ||
| 
						 | 
					0862d1c804 | ||
| 
						 | 
					333e380340 | ||
| 
						 | 
					58f77a19ed | ||
| 
						 | 
					f2d883dab2 | ||
| 
						 | 
					7ba8c7c2b5 | ||
| 
						 | 
					0bf6c93faa | ||
| 
						 | 
					b9f0158278 | ||
| 
						 | 
					25ee41f344 | ||
| 
						 | 
					5436634829 | ||
| 
						 | 
					915524e1ab | ||
| 
						 | 
					d579cd1605 | ||
| 
						 | 
					cb5941ec55 | ||
| 
						 | 
					a5ac183d86 | ||
| 
						 | 
					a36de92bb9 | ||
| 
						 | 
					01f9d551f1 | ||
| 
						 | 
					399df66b18 | ||
| 
						 | 
					723a1c843a | ||
| 
						 | 
					e333263fd6 | ||
| 
						 | 
					507df9eea1 | ||
| 
						 | 
					a9a3687ea0 | ||
| 
						 | 
					f05c649c61 | ||
| 
						 | 
					a2dfba1842 | ||
| 
						 | 
					c199da4dfa | ||
| 
						 | 
					ee9033e12f | ||
| 
						 | 
					54788d750e | ||
| 
						 | 
					78e894c6f2 | ||
| 
						 | 
					32107ba8b5 | ||
| 
						 | 
					6122f65e7a | ||
| 
						 | 
					43fd29f9bf | ||
| 
						 | 
					54c624b356 | ||
| 
						 | 
					8c33adfd29 | ||
| 
						 | 
					2e8881b77c | ||
| 
						 | 
					64aa729edd | ||
| 
						 | 
					ccf95b738d | ||
| 
						 | 
					b2847fedd3 | ||
| 
						 | 
					8befcb9bba | ||
| 
						 | 
					988fc52303 | ||
| 
						 | 
					7293ddb22c | ||
| 
						 | 
					f23c118e81 | ||
| 
						 | 
					f68b3be35a | ||
| 
						 | 
					3d95e7bb11 | ||
| 
						 | 
					337c484f01 | ||
| 
						 | 
					5d98e2bf04 | ||
| 
						 | 
					6f300d0cc6 | ||
| 
						 | 
					3422e1dca7 | ||
| 
						 | 
					963c6ae567 | ||
| 
						 | 
					6304169926 | ||
| 
						 | 
					221afde55e | ||
| 
						 | 
					0ae87270ad | ||
| 
						 | 
					9d33baec70 | ||
| 
						 | 
					0f37b22cdb | ||
| 
						 | 
					47afd87e84 | ||
| 
						 | 
					700c06023e | ||
| 
						 | 
					4fea5b5ca3 | ||
| 
						 | 
					521bddc1cc | ||
| 
						 | 
					bdfff20ec2 | ||
| 
						 | 
					bdd05aba3b | ||
| 
						 | 
					89c2538ff1 | ||
| 
						 | 
					7680819108 | ||
| 
						 | 
					d79e8b84c9 | ||
| 
						 | 
					731317230a | ||
| 
						 | 
					5046938913 | ||
| 
						 | 
					0e8fd45559 | ||
| 
						 | 
					6099a5dbc3 | ||
| 
						 | 
					2daa98a694 | ||
| 
						 | 
					5d2c6496fa | ||
| 
						 | 
					817dbbe73f | ||
| 
						 | 
					29c89c82f8 | ||
| 
						 | 
					0b714bd479 | ||
| 
						 | 
					8c94a5afb9 | ||
| 
						 | 
					aeb117c9d1 | ||
| 
						 | 
					a2d4f133b7 | ||
| 
						 | 
					b833aff3c8 | ||
| 
						 | 
					6601e4ddba | ||
| 
						 | 
					815da2d0ec | ||
| 
						 | 
					ddd35b3653 | ||
| 
						 | 
					8a32894c83 | ||
| 
						 | 
					49d8e6da40 | ||
| 
						 | 
					8089f24c81 | ||
| 
						 | 
					b6aab53d10 | ||
| 
						 | 
					55a4517cd1 | ||
| 
						 | 
					b095319a16 | ||
| 
						 | 
					5ea5806730 | ||
| 
						 | 
					bfbf812148 | ||
| 
						 | 
					168e9eeac1 | ||
| 
						 | 
					dd79c1a79a | ||
| 
						 | 
					fe3402589b | ||
| 
						 | 
					74dcaff21c | ||
| 
						 | 
					0a7968a2e5 | ||
| 
						 | 
					00091a2acb | ||
| 
						 | 
					c5aa834b6a | ||
| 
						 | 
					b1bde46694 | ||
| 
						 | 
					49e4fa494e | ||
| 
						 | 
					4622c52b71 | ||
| 
						 | 
					e9ac5dd5f4 | ||
| 
						 | 
					7570c43d11 | ||
| 
						 | 
					4332e7ec49 | ||
| 
						 | 
					9f26f1e225 | ||
| 
						 | 
					0c0319c415 | ||
| 
						 | 
					c16dbd7607 | ||
| 
						 | 
					7b1f10a5fe | ||
| 
						 | 
					dce74749b7 | ||
| 
						 | 
					1ba88b8c42 | ||
| 
						 | 
					9c50b57d46 | ||
| 
						 | 
					900bd3ee97 | ||
| 
						 | 
					b4affe00a7 | ||
| 
						 | 
					ca49c84bc1 | ||
| 
						 | 
					2cddf60226 | ||
| 
						 | 
					d9c3951f02 | ||
| 
						 | 
					aa5997d975 | ||
| 
						 | 
					c51acf7c2a | ||
| 
						 | 
					348044bc8a | ||
| 
						 | 
					7dbdf2aa07 | ||
| 
						 | 
					c933731ead | ||
| 
						 | 
					e7da715994 | ||
| 
						 | 
					6d82aefad4 | ||
| 
						 | 
					8a11ab7d96 | ||
| 
						 | 
					f465086405 | ||
| 
						 | 
					70313a8b79 | ||
| 
						 | 
					71679c38be | ||
| 
						 | 
					addd943074 | ||
| 
						 | 
					0b8470421c | ||
| 
						 | 
					bcf7c0f006 | ||
| 
						 | 
					2b87bb015c | ||
| 
						 | 
					07e10fa03e | ||
| 
						 | 
					bf992989c7 | ||
| 
						 | 
					00400e354d | ||
| 
						 | 
					19a49d34ce | ||
| 
						 | 
					e8badac282 | ||
| 
						 | 
					282a60fcab | ||
| 
						 | 
					e76a28ded5 | ||
| 
						 | 
					b22543ab66 | ||
| 
						 | 
					d5165cdc08 | ||
| 
						 | 
					1c0549f468 | ||
| 
						 | 
					a7316b0594 | ||
| 
						 | 
					634eeaf74c | ||
| 
						 | 
					1299e196be | ||
| 
						 | 
					92c325230d | ||
| 
						 | 
					827a466a5c | ||
| 
						 | 
					89b38b1361 | ||
| 
						 | 
					140de6dd60 | ||
| 
						 | 
					e64ff5832e | ||
| 
						 | 
					17b1543d44 | ||
| 
						 | 
					043e79a570 | ||
| 
						 | 
					5d036e3d54 | ||
| 
						 | 
					9d2a638988 | ||
| 
						 | 
					7943993fcb | ||
| 
						 | 
					026ddc2d9b | ||
| 
						 | 
					384c7e2c17 | ||
| 
						 | 
					700f706428 | ||
| 
						 | 
					0a4deb2a9b | ||
| 
						 | 
					5b8abe6809 | ||
| 
						 | 
					2c5005c1ea | ||
| 
						 | 
					c2b3022163 | ||
| 
						 | 
					644abb2dc9 | ||
| 
						 | 
					48b53c30f7 | ||
| 
						 | 
					bf3818eb22 | ||
| 
						 | 
					b3358aeed7 | ||
| 
						 | 
					a7d4c7d8de | ||
| 
						 | 
					369c1b0a41 | ||
| 
						 | 
					21636f3f29 | ||
| 
						 | 
					bf428312d7 | ||
| 
						 | 
					6218209dcb | ||
| 
						 | 
					1b7ead3455 | ||
| 
						 | 
					3a252a1b41 | ||
| 
						 | 
					fc7e6470b5 | ||
| 
						 | 
					3813a03117 | ||
| 
						 | 
					e59c29993c | ||
| 
						 | 
					92d2ebc3f9 | ||
| 
						 | 
					67ef448471 | ||
| 
						 | 
					207abe9a2c | ||
| 
						 | 
					05863227a6 | ||
| 
						 | 
					ac05cb323c | ||
| 
						 | 
					066d44636a | ||
| 
						 | 
					3dbf06420d | ||
| 
						 | 
					1983097d3a | ||
| 
						 | 
					1c60aa58ae | ||
| 
						 | 
					1626d9f9a4 | ||
| 
						 | 
					c7182589d2 | ||
| 
						 | 
					ceb17dc713 | ||
| 
						 | 
					46c0360b03 | ||
| 
						 | 
					0ebddfcf50 | ||
| 
						 | 
					36d20eb1b8 | ||
| 
						 | 
					db4b266874 | ||
| 
						 | 
					63cf470e07 | ||
| 
						 | 
					1f87eb4157 | ||
| 
						 | 
					9bb9999b46 | ||
| 
						 | 
					60e6349963 | ||
| 
						 | 
					581d1c5db1 | ||
| 
						 | 
					cf0b6dda25 | ||
| 
						 | 
					8a5faa3d2e | ||
| 
						 | 
					09607787cc | ||
| 
						 | 
					0aad74a670 | ||
| 
						 | 
					985f28bbea | ||
| 
						 | 
					22e1abbaff | ||
| 
						 | 
					21e8097b9c | ||
| 
						 | 
					14d267c246 | ||
| 
						 | 
					9420174477 | ||
| 
						 | 
					fb4878bb7c | ||
| 
						 | 
					c856cbb523 | ||
| 
						 | 
					2e42eb6bad | ||
| 
						 | 
					4f87e86603 | ||
| 
						 | 
					3c6737f738 | ||
| 
						 | 
					b2bc73c3fe | ||
| 
						 | 
					30ca25e978 | ||
| 
						 | 
					ecdd0875df | ||
| 
						 | 
					d05d748fe2 | ||
| 
						 | 
					8db193a172 | ||
| 
						 | 
					c064973c9d | ||
| 
						 | 
					01c66eaf0c | ||
| 
						 | 
					c2fdec188e | ||
| 
						 | 
					d7e2b0a771 | ||
| 
						 | 
					06354a8c9a | ||
| 
						 | 
					7c25dead17 | ||
| 
						 | 
					f4d3153e91 | ||
| 
						 | 
					7030d59b2f | ||
| 
						 | 
					6eae036ac3 | ||
| 
						 | 
					b6b6ed0e2f | ||
| 
						 | 
					51b5825665 | ||
| 
						 | 
					1c2629595e | ||
| 
						 | 
					e91f4e88b5 | ||
| 
						 | 
					bdb7dbdd00 | ||
| 
						 | 
					7092521253 | ||
| 
						 | 
					47f7fcd4fe | ||
| 
						 | 
					93a004b016 | ||
| 
						 | 
					2fad9d73d4 | ||
| 
						 | 
					252eb24522 | ||
| 
						 | 
					b7964e9efb | ||
| 
						 | 
					23e7a9e710 | ||
| 
						 | 
					36804a60c9 | ||
| 
						 | 
					73270345f5 | ||
| 
						 | 
					e1ffe06709 | ||
| 
						 | 
					3dd240bdbb | ||
| 
						 | 
					b58425d7d7 | ||
| 
						 | 
					a197ce6f53 | ||
| 
						 | 
					9dcdaf05b5 | ||
| 
						 | 
					c827cccdf3 | ||
| 
						 | 
					6805f2d71e | ||
| 
						 | 
					0ea690a2f2 | ||
| 
						 | 
					d68ff69c7a | ||
| 
						 | 
					f1f2bc28a2 | ||
| 
						 | 
					5f0389c07c | ||
| 
						 | 
					c2f304f3bc | ||
| 
						 | 
					ce9c1a1f7a | ||
| 
						 | 
					203382e007 | ||
| 
						 | 
					d2ba9eb967 | ||
| 
						 | 
					59ebec25f3 | ||
| 
						 | 
					b864b03a65 | ||
| 
						 | 
					c7a37660ce | ||
| 
						 | 
					02aae631d8 | ||
| 
						 | 
					d542f63d3f | ||
| 
						 | 
					74694a6e23 | ||
| 
						 | 
					a5baeac428 | ||
| 
						 | 
					e23e04953c | ||
| 
						 | 
					fa9f923697 | ||
| 
						 | 
					797e201946 | ||
| 
						 | 
					156a642d28 | ||
| 
						 | 
					96379b7517 | ||
| 
						 | 
					9b5bb62aa7 | ||
| 
						 | 
					895745ac14 | ||
| 
						 | 
					6cde2d8db4 | ||
| 
						 | 
					a277f8e0e1 | ||
| 
						 | 
					cf5c5d06e1 | ||
| 
						 | 
					722f45fa58 | ||
| 
						 | 
					c97390b9c6 | ||
| 
						 | 
					124c461a56 | ||
| 
						 | 
					4ac352637c | ||
| 
						 | 
					00cf62acfb | ||
| 
						 | 
					ee0c2a1152 | ||
| 
						 | 
					f32ab20267 | ||
| 
						 | 
					1316f93b21 | ||
| 
						 | 
					52d72fe8a1 | ||
| 
						 | 
					0406aaa591 | ||
| 
						 | 
					8f56660cfc | ||
| 
						 | 
					402cc6b90c | ||
| 
						 | 
					b8c14ad64e | ||
| 
						 | 
					1f9c83d88b | ||
| 
						 | 
					319667a25c | ||
| 
						 | 
					b047a37a80 | ||
| 
						 | 
					31af220483 | ||
| 
						 | 
					40d51ea59f | ||
| 
						 | 
					284cf83935 | ||
| 
						 | 
					5ba04a7478 | ||
| 
						 | 
					2b87051022 | ||
| 
						 | 
					a901f2dc5d | ||
| 
						 | 
					bd6f1f2c6d | ||
| 
						 | 
					ca612872a6 | ||
| 
						 | 
					feb33a6a28 | ||
| 
						 | 
					ff92d962f3 | ||
| 
						 | 
					79ca0d579c | ||
| 
						 | 
					c61ac862ba | ||
| 
						 | 
					64ce622f83 | ||
| 
						 | 
					772638c78e | ||
| 
						 | 
					24badb46fe | ||
| 
						 | 
					87d54b37e4 | ||
| 
						 | 
					98aa61e2a4 | ||
| 
						 | 
					bea5c6f4e6 | ||
| 
						 | 
					7d29e691a4 | ||
| 
						 | 
					b0d161faad | ||
| 
						 | 
					4c74fa81d1 | ||
| 
						 | 
					556a3e08db | ||
| 
						 | 
					e3fb77c051 | ||
| 
						 | 
					3ee07d0e82 | ||
| 
						 | 
					72c486cb3e | ||
| 
						 | 
					e37574510e | ||
| 
						 | 
					f4b58f35ba | ||
| 
						 | 
					01696f19e8 | ||
| 
						 | 
					1f5a27d5c5 | ||
| 
						 | 
					81476dedcb | ||
| 
						 | 
					90b08acbf1 | ||
| 
						 | 
					f967fd21f8 | ||
| 
						 | 
					8d854d5f1a | ||
| 
						 | 
					fde5932b45 | ||
| 
						 | 
					eb84227f78 | ||
| 
						 | 
					550d595034 | ||
| 
						 | 
					24cc4b49d6 | ||
| 
						 | 
					5f130d1925 | ||
| 
						 | 
					4f05787338 | ||
| 
						 | 
					a98db33c18 | ||
| 
						 | 
					a5d78f2943 | ||
| 
						 | 
					46ebe9ffc5 | ||
| 
						 | 
					e2b80658ca | ||
| 
						 | 
					0a586c5c92 | ||
| 
						 | 
					aa5d352a06 | ||
| 
						 | 
					760da64a4c | ||
| 
						 | 
					714ffc5ef1 | ||
| 
						 | 
					fd4d645687 | ||
| 
						 | 
					24ad59ea37 | ||
| 
						 | 
					15f881f967 | ||
| 
						 | 
					d5285674ae | ||
| 
						 | 
					bb862e20c0 | ||
| 
						 | 
					be3eb308b9 | ||
| 
						 | 
					e7f0b1dc59 | ||
| 
						 | 
					336cec8b2a | ||
| 
						 | 
					fad0b96f24 | ||
| 
						 | 
					d2aab9d6a6 | ||
| 
						 | 
					4005863e3d | ||
| 
						 | 
					70cdb67f31 | ||
| 
						 | 
					a9aec6956d | ||
| 
						 | 
					d871eda6be | ||
| 
						 | 
					49d620a414 | ||
| 
						 | 
					2e2e3281da | ||
| 
						 | 
					37cbfe29cf | ||
| 
						 | 
					a1f88fc17f | ||
| 
						 | 
					0065da61bd | ||
| 
						 | 
					d2b0706c40 | ||
| 
						 | 
					a95e585e39 | ||
| 
						 | 
					7d39fa76dd | ||
| 
						 | 
					ddf27c1a84 | ||
| 
						 | 
					87e46f3ff1 | ||
| 
						 | 
					33a6fda6c3 | ||
| 
						 | 
					7cc1bdb35d | ||
| 
						 | 
					60557f4e0f | ||
| 
						 | 
					914441218a | ||
| 
						 | 
					e322d98886 | ||
| 
						 | 
					ba1e5f8f71 | ||
| 
						 | 
					517075c605 | ||
| 
						 | 
					540e970170 | ||
| 
						 | 
					d0fd5641c1 | ||
| 
						 | 
					caaa21dec0 | ||
| 
						 | 
					22c606326f | ||
| 
						 | 
					00ed2973b2 | ||
| 
						 | 
					3837fc0a87 | ||
| 
						 | 
					07b95d3436 | ||
| 
						 | 
					1f5dd9c397 | ||
| 
						 | 
					007736a234 | ||
| 
						 | 
					c2a9f7fbb2 | ||
| 
						 | 
					b18cc8de86 | ||
| 
						 | 
					30e4f80894 | ||
| 
						 | 
					dd8a53d5e0 | ||
| 
						 | 
					0f01928402 | ||
| 
						 | 
					a8b081661c | ||
| 
						 | 
					c892610f27 | ||
| 
						 | 
					72dad591fa | ||
| 
						 | 
					ea19790828 | ||
| 
						 | 
					cc2f5d19c8 | ||
| 
						 | 
					64b2c5d1b4 | ||
| 
						 | 
					a9f728d2a7 | ||
| 
						 | 
					3736d81d8f | ||
| 
						 | 
					fbcea03ab3 | ||
| 
						 | 
					f19ee78fb2 | ||
| 
						 | 
					b47fd6df31 | ||
| 
						 | 
					786beccca5 | ||
| 
						 | 
					916c62a702 | ||
| 
						 | 
					11234c7cfc | ||
| 
						 | 
					80eac7370e | ||
| 
						 | 
					ac78a1e1c0 | ||
| 
						 | 
					34c6ff9645 | ||
| 
						 | 
					f6749fb204 | ||
| 
						 | 
					89fe43f70c | ||
| 
						 | 
					e2c66ce48a | ||
| 
						 | 
					eb0d803617 | ||
| 
						 | 
					53d9ea7a2c | ||
| 
						 | 
					0fbdd0b67f | ||
| 
						 | 
					f248aa69dc | ||
| 
						 | 
					9f1ed13a38 | ||
| 
						 | 
					9400d8f6db | ||
| 
						 | 
					c7a4b307af | ||
| 
						 | 
					0bac3a5dd7 | ||
| 
						 | 
					14b92a4897 | ||
| 
						 | 
					66bd8b553f | ||
| 
						 | 
					e80462a2c3 | ||
| 
						 | 
					b990ed2c23 | ||
| 
						 | 
					097e56f4ab | ||
| 
						 | 
					7a4b6138c1 | ||
| 
						 | 
					bc918d0d18 | ||
| 
						 | 
					8b08d8bf2d | ||
| 
						 | 
					d92c97f755 | ||
| 
						 | 
					6a367917f7 | ||
| 
						 | 
					b67138b5ae | ||
| 
						 | 
					0e5177c329 | ||
| 
						 | 
					c6ed3cdb61 | ||
| 
						 | 
					fd99d13f04 | ||
| 
						 | 
					36c3ce9333 | ||
| 
						 | 
					aee28616a9 | ||
| 
						 | 
					70830560ae | ||
| 
						 | 
					df6cd46bd6 | ||
| 
						 | 
					dce797f4d9 | ||
| 
						 | 
					f3232901d8 | ||
| 
						 | 
					d3e4f44d37 | ||
| 
						 | 
					d81958a074 | ||
| 
						 | 
					92ee17493c | ||
| 
						 | 
					f9e456bb47 | ||
| 
						 | 
					740388c778 | ||
| 
						 | 
					1c0c42e8e7 | ||
| 
						 | 
					e2726f3e38 | ||
| 
						 | 
					ed465a6ffe | ||
| 
						 | 
					fd8f3df2cd | ||
| 
						 | 
					0c2037875a | ||
| 
						 | 
					fbf6e032d0 | ||
| 
						 | 
					c8020e6559 | ||
| 
						 | 
					68b7e8437b | ||
| 
						 | 
					6528f8366f | ||
| 
						 | 
					88eb246b60 | ||
| 
						 | 
					bed50688d2 | ||
| 
						 | 
					44686bac3e | ||
| 
						 | 
					ca575ef0ae | ||
| 
						 | 
					c20503028a | ||
| 
						 | 
					4516e4cc3b | ||
| 
						 | 
					b2ec340f9e | ||
| 
						 | 
					570a029f27 | ||
| 
						 | 
					ebe72e197d | ||
| 
						 | 
					ce629b09b2 | ||
| 
						 | 
					97c2db1cfd | ||
| 
						 | 
					c5804c1929 | ||
| 
						 | 
					92276c5e70 | ||
| 
						 | 
					62c0088dd8 | ||
| 
						 | 
					e8498adaf1 | ||
| 
						 | 
					c7fa719cc3 | ||
| 
						 | 
					41f0e133a9 | ||
| 
						 | 
					7705a65beb | ||
| 
						 | 
					604e8f4f8a | ||
| 
						 | 
					de0116d8c8 | ||
| 
						 | 
					8d968e5c9b | ||
| 
						 | 
					758e573483 | ||
| 
						 | 
					eab4f4c963 | ||
| 
						 | 
					245c58842b | ||
| 
						 | 
					e508635c6e | ||
| 
						 | 
					138b8cf874 | ||
| 
						 | 
					d446b657f3 | ||
| 
						 | 
					019dd2e1b0 | ||
| 
						 | 
					602da771f6 | ||
| 
						 | 
					5de8a0a84b | ||
| 
						 | 
					d2198925e1 | ||
| 
						 | 
					44e02003ad | ||
| 
						 | 
					e8bfd990e4 | ||
| 
						 | 
					d1fc87577a | ||
| 
						 | 
					8b4c1a80d0 | ||
| 
						 | 
					6ca0d4a5ef | ||
| 
						 | 
					d0cd6ba47d | ||
| 
						 | 
					aa2a63bd84 | ||
| 
						 | 
					daa380fb0e | ||
| 
						 | 
					61e2e04f13 | ||
| 
						 | 
					db7e4ddc04 | ||
| 
						 | 
					c4aa277b19 | ||
| 
						 | 
					ab29ce872a | ||
| 
						 | 
					57beb0ade1 | ||
| 
						 | 
					e3d0b6f90f | ||
| 
						 | 
					e2aa954cb5 | ||
| 
						 | 
					05c285a945 | ||
| 
						 | 
					27b34992c6 | ||
| 
						 | 
					4886238761 | ||
| 
						 | 
					42d46aed90 | ||
| 
						 | 
					a622aba7eb | ||
| 
						 | 
					831099cca5 | ||
| 
						 | 
					b8a54faf94 | ||
| 
						 | 
					80ff6ff797 | ||
| 
						 | 
					2f27b94757 | ||
| 
						 | 
					b2f33e2895 | ||
| 
						 | 
					d1d4142052 | ||
| 
						 | 
					46caf6d673 | ||
| 
						 | 
					2864c360bc | ||
| 
						 | 
					e5dfc6323a | ||
| 
						 | 
					5bc042ba6f | ||
| 
						 | 
					c63fe5ee24 | ||
| 
						 | 
					ee6bc33cea | ||
| 
						 | 
					5c730dc53d | ||
| 
						 | 
					5a3de8d663 | ||
| 
						 | 
					fad88dd517 | ||
| 
						 | 
					39dd24310d | ||
| 
						 | 
					b13809d0c7 | ||
| 
						 | 
					87559414a3 | ||
| 
						 | 
					b5b5759829 | ||
| 
						 | 
					d254e2e1f2 | ||
| 
						 | 
					458b0b22fc | ||
| 
						 | 
					cd30128af8 | ||
| 
						 | 
					d61cdd8cea | ||
| 
						 | 
					0d0e545979 | ||
| 
						 | 
					6c5e96c33a | ||
| 
						 | 
					bae2359b54 | ||
| 
						 | 
					8cbbb456f0 | ||
| 
						 | 
					dfd39461cf | ||
| 
						 | 
					60d8683ae7 | ||
| 
						 | 
					f2cc5cf152 | ||
| 
						 | 
					d4a26fbf4b | ||
| 
						 | 
					025784fd83 | ||
| 
						 | 
					4e89a5edde | ||
| 
						 | 
					b3936ecadf | ||
| 
						 | 
					2c9e6bb589 | ||
| 
						 | 
					73261a4a66 | ||
| 
						 | 
					3d0dd38045 | ||
| 
						 | 
					8bcbf3030f | ||
| 
						 | 
					1bc7edc5d8 | ||
| 
						 | 
					0673720db9 | ||
| 
						 | 
					730a0d4c5a | ||
| 
						 | 
					9147dee0de | ||
| 
						 | 
					12746a1949 | ||
| 
						 | 
					bdd65fe755 | ||
| 
						 | 
					21e2280825 | ||
| 
						 | 
					e9d2a429eb | ||
| 
						 | 
					b67dfb9edf | ||
| 
						 | 
					55308917f9 | ||
| 
						 | 
					1b64b09532 | ||
| 
						 | 
					74dd298891 | ||
| 
						 | 
					5a85fc0e55 | ||
| 
						 | 
					26991988cb | ||
| 
						 | 
					15563444cf | ||
| 
						 | 
					3bcdba6e1d | ||
| 
						 | 
					ef56a78544 | ||
| 
						 | 
					049a561466 | ||
| 
						 | 
					b40b19997a | ||
| 
						 | 
					46505a8314 | ||
| 
						 | 
					78fb102002 | ||
| 
						 | 
					c6e924f788 | ||
| 
						 | 
					f6508b51a2 | ||
| 
						 | 
					b0ae596de8 | ||
| 
						 | 
					1d311e7916 | ||
| 
						 | 
					0c19f71c96 | ||
| 
						 | 
					8d6ab32b9a | ||
| 
						 | 
					6c1a2d531f | ||
| 
						 | 
					c6e9f9742b | ||
| 
						 | 
					d23aaf3cea | ||
| 
						 | 
					017fde91ad | ||
| 
						 | 
					31ffc5a85d | ||
| 
						 | 
					62b65a25d8 | ||
| 
						 | 
					882fe48d80 | ||
| 
						 | 
					90a691ed25 | ||
| 
						 | 
					eadb41b3bb | ||
| 
						 | 
					6829590c8f | ||
| 
						 | 
					29da720e6a | ||
| 
						 | 
					c5932c0f07 | ||
| 
						 | 
					6195386a06 | ||
| 
						 | 
					0080440118 | ||
| 
						 | 
					b5be62cd1b | ||
| 
						 | 
					1bac40fbe3 | ||
| 
						 | 
					11637bae43 | ||
| 
						 | 
					301bacec9f | ||
| 
						 | 
					8943b3b0e9 | ||
| 
						 | 
					f59018f2d7 | ||
| 
						 | 
					235cb9c505 | ||
| 
						 | 
					3f328463a8 | ||
| 
						 | 
					e58c82fc04 | ||
| 
						 | 
					91ca86ffe4 | ||
| 
						 | 
					33d4518e50 | ||
| 
						 | 
					b087191d2b | ||
| 
						 | 
					64baea1693 | ||
| 
						 | 
					b88b743428 | ||
| 
						 | 
					c606cf076d | ||
| 
						 | 
					d205d7e7c2 | ||
| 
						 | 
					efdd3375d0 | ||
| 
						 | 
					abcca3d3bc | ||
| 
						 | 
					f4d13b9801 | ||
| 
						 | 
					7da39031e1 | ||
| 
						 | 
					6cdb1bd60c | ||
| 
						 | 
					7c108e267c | ||
| 
						 | 
					5cf06fe9a7 | ||
| 
						 | 
					41f6956197 | ||
| 
						 | 
					417cbea79c | ||
| 
						 | 
					225c807550 | ||
| 
						 | 
					ff78d2655b | ||
| 
						 | 
					bde15f7c61 | ||
| 
						 | 
					30300f1aeb | ||
| 
						 | 
					d42c3a15d6 | ||
| 
						 | 
					14a65559af | ||
| 
						 | 
					ba1e7bd095 | ||
| 
						 | 
					951705a4b2 | ||
| 
						 | 
					36bf63a5de | ||
| 
						 | 
					66c4881fd2 | ||
| 
						 | 
					c6b169cb33 | ||
| 
						 | 
					0e753ed5a6 | ||
| 
						 | 
					785969feb5 | ||
| 
						 | 
					56036476a4 | ||
| 
						 | 
					936b1b5638 | ||
| 
						 | 
					bf3b94d654 | ||
| 
						 | 
					90b4a0856f | ||
| 
						 | 
					686190ce80 | ||
| 
						 | 
					45495c2474 | ||
| 
						 | 
					9caa88fecb | ||
| 
						 | 
					25948f214e | ||
| 
						 | 
					bea4faacd4 | ||
| 
						 | 
					a7bd9f811b | ||
| 
						 | 
					2b9561fcbb | ||
| 
						 | 
					7b9c9b2f7d | ||
| 
						 | 
					b47b82ed42 | ||
| 
						 | 
					c4c2c11dca | ||
| 
						 | 
					ce38293a0f | ||
| 
						 | 
					6c4e9d23f2 | ||
| 
						 | 
					4aa1fe9ca2 | ||
| 
						 | 
					951fff5aa0 | ||
| 
						 | 
					5ad8080cb9 | ||
| 
						 | 
					e53e3cbb09 | ||
| 
						 | 
					8a029f333f | ||
| 
						 | 
					4debedb275 | ||
| 
						 | 
					8764253861 | ||
| 
						 | 
					bbdce159fa | ||
| 
						 | 
					087d8e602e | ||
| 
						 | 
					50aa15dec9 | ||
| 
						 | 
					26580f8f2c | ||
| 
						 | 
					875b6d131b | ||
| 
						 | 
					77afd6782f | ||
| 
						 | 
					09ab13cf04 | ||
| 
						 | 
					56f312dc03 | ||
| 
						 | 
					f2cbddc196 | ||
| 
						 | 
					c7846e172f | ||
| 
						 | 
					54afb7b25e | ||
| 
						 | 
					f3cb9d0443 | ||
| 
						 | 
					fcee7f2f3a | ||
| 
						 | 
					faff0738eb | ||
| 
						 | 
					69e26c6dee | ||
| 
						 | 
					1acec65c5e | ||
| 
						 | 
					8a6a3968c3 | ||
| 
						 | 
					58e4870cb8 | ||
| 
						 | 
					102099cadd | ||
| 
						 | 
					efe6d06ddd | ||
| 
						 | 
					f0d0e025dd | ||
| 
						 | 
					fc2d0215f5 | ||
| 
						 | 
					02af8eb824 | ||
| 
						 | 
					102f2a91f9 | ||
| 
						 | 
					2c649d5da5 | ||
| 
						 | 
					7fa7d04ed0 | ||
| 
						 | 
					aad9179373 | ||
| 
						 | 
					d5b4e30eb7 | ||
| 
						 | 
					34ba6f2f71 | ||
| 
						 | 
					d845f40b98 | ||
| 
						 | 
					80c16aa8f7 | ||
| 
						 | 
					0cbaeaefed | ||
| 
						 | 
					ab6a7773ce | ||
| 
						 | 
					85e243982b | ||
| 
						 | 
					6eb168bc68 | ||
| 
						 | 
					47b55e29d4 | ||
| 
						 | 
					2c243b678f | ||
| 
						 | 
					a634f25d30 | ||
| 
						 | 
					26df6cf35c | ||
| 
						 | 
					84dde8e9bb | ||
| 
						 | 
					f2c79be11a | ||
| 
						 | 
					10df80b96a | ||
| 
						 | 
					bbb83656bf | ||
| 
						 | 
					ef49670ae4 | ||
| 
						 | 
					e4df00c77d | ||
| 
						 | 
					3d70662716 | ||
| 
						 | 
					8d0638a187 | ||
| 
						 | 
					06143396b7 | ||
| 
						 | 
					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 | 
							
								
								
									
										22
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -18,9 +18,26 @@ config
 | 
			
		||||
configure
 | 
			
		||||
data/gnome-shell.desktop
 | 
			
		||||
data/gnome-shell.desktop.in
 | 
			
		||||
data/gnome-shell-extension-prefs.desktop
 | 
			
		||||
data/gnome-shell-extension-prefs.desktop.in
 | 
			
		||||
data/gschemas.compiled
 | 
			
		||||
data/org.gnome.shell.gschema.xml
 | 
			
		||||
data/org.gnome.shell.gschema.valid
 | 
			
		||||
data/org.gnome.shell.evolution.calendar.gschema.xml
 | 
			
		||||
data/org.gnome.shell.evolution.calendar.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
 | 
			
		||||
@@ -33,6 +50,7 @@ po/gnome-shell.pot
 | 
			
		||||
po/*.header
 | 
			
		||||
po/*.sed
 | 
			
		||||
po/*.sin
 | 
			
		||||
po/.intltool-merge-cache
 | 
			
		||||
po/Makefile.in.in
 | 
			
		||||
po/Makevars.template
 | 
			
		||||
po/POTFILES
 | 
			
		||||
@@ -45,13 +63,17 @@ src/*-enum-types.[ch]
 | 
			
		||||
src/*-marshal.[ch]
 | 
			
		||||
src/Makefile
 | 
			
		||||
src/Makefile.in
 | 
			
		||||
src/calendar-server/evolution-calendar.desktop
 | 
			
		||||
src/calendar-server/evolution-calendar.desktop.in
 | 
			
		||||
src/calendar-server/org.gnome.Shell.CalendarServer.service
 | 
			
		||||
src/gnome-shell
 | 
			
		||||
src/gnome-shell-calendar-server
 | 
			
		||||
src/gnome-shell-extension-tool
 | 
			
		||||
src/gnome-shell-extension-prefs
 | 
			
		||||
src/gnome-shell-hotplug-sniffer
 | 
			
		||||
src/gnome-shell-jhbuild
 | 
			
		||||
src/gnome-shell-perf-helper
 | 
			
		||||
src/gnome-shell-perf-tool
 | 
			
		||||
src/gnome-shell-real
 | 
			
		||||
src/hotplug-sniffer/org.gnome.Shell.HotplugSniffer.service
 | 
			
		||||
src/run-js-test
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										779
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						@@ -1,3 +1,782 @@
 | 
			
		||||
3.5.4
 | 
			
		||||
=====
 | 
			
		||||
* Fix wrong result handling of remote calls [Florian; #678852]
 | 
			
		||||
* dateMenu: Fix regression that caused no date to be displayed [Colin]
 | 
			
		||||
* WindowTracker: Fix refcounting bug in get_app_for_window() [Giovanni; #678992]
 | 
			
		||||
* Show the workspace switcher for move-to-workspace keybinding
 | 
			
		||||
  [Giovanni, Jasper; #674104, #660839, #679005]
 | 
			
		||||
* userMenu: Move "Power off" item to the bottom [Florian; #678887]
 | 
			
		||||
* Remove contacts search provider [Florian, Rui; #677442]
 | 
			
		||||
* network: don't ask for always-ask secrets when interaction isn't allowed
 | 
			
		||||
  [Dan; #679091]
 | 
			
		||||
* PolkitAgent: Look for the right password prompt [Matthias; #675300]
 | 
			
		||||
* Implement extension updates [Jasper; #679099]
 | 
			
		||||
* userMenu: Don't disconnect account signals when disabled [Guillaume; #669112]
 | 
			
		||||
* Fix startup notification when opening calendar [Florian; #677907]
 | 
			
		||||
* networkAgent: use absolute path if configured [Clemens; #679212]
 | 
			
		||||
* recorder: Port to GStreamer-1.0 API [Florian; #679445]
 | 
			
		||||
* telepathyClient: don't add log messages on presence changes [Ana; #669508]
 | 
			
		||||
* lookingGlass: Don't use a signal callback on 'paint' to draw the border
 | 
			
		||||
  [Jasper; #679464]
 | 
			
		||||
* Add support for inhibiting automount [Hans; #678597]
 | 
			
		||||
* Implemented banner support for the login screen [Matthias, Marius; #665346]
 | 
			
		||||
* boxpointer: Flip side if we would end outside the monitor [Rui; #678164]
 | 
			
		||||
* boxpointer: Change 'animate' parameter on show/hide to a bitmask
 | 
			
		||||
  [Rui; #678337]
 | 
			
		||||
* Add a grayscale effect [Matthias, Jasper, Florian: #676782, #674499]
 | 
			
		||||
* UserMenu: show "Install Updates & Restart" when appropriate
 | 
			
		||||
  [Giovanni; #677394, #680080]
 | 
			
		||||
* messageTray: don't show the message tray when a new notification is shown
 | 
			
		||||
  [Ana; #677210]
 | 
			
		||||
* panel: don't break when indicator has no menu [Jean-Philippe; #678694]
 | 
			
		||||
* appMenu: Disable app menu during startup animations [Florian; #672322]
 | 
			
		||||
* autorun: Add a notification when unmounting drives [Cosimo; #676125]
 | 
			
		||||
* st-icon: Fix potential crash involving shadows [Jasper; #679776]
 | 
			
		||||
* Remove manual garbage collection on tweeners end [Cosimo; #679832]
 | 
			
		||||
* dash: hide tooltips when overview begins hiding [Stefano; #674241]
 | 
			
		||||
* Update modal dialog animation for new centered position [Florian; #674499]
 | 
			
		||||
* calendar: Fix grid lines in RTL locales [Florian; #679879]
 | 
			
		||||
* Integrate IBus with keyboard indicator [Rui; #641531]
 | 
			
		||||
* Move ibus status icon under keyboard [Matthias]
 | 
			
		||||
* gdm: port from libgdmgreeter to libgdm [Ray; #676401]
 | 
			
		||||
* Misc bug fixes and cleanups [Antoine, Cosimo, Giovanni, Jasper, Rico;
 | 
			
		||||
  #678978, #672790, #679847, #679944]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Jean-Philippe Braun, Clemens Buchacher, Giovanni Campagna, Cosimo Cecchi,
 | 
			
		||||
 Matthias Clasen, Hans de Goede, Guillaume Desmottes, Stefano Facchini,
 | 
			
		||||
 Antoine Jacoutot, Rui Matos, Florian Müllner, Marius Rieder, Ana Risteska,
 | 
			
		||||
 Jasper St. Pierre, Rico Tzschichholz, Colin Walters, Dan Williams
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Matej Urbančič [sl], Khaled Hosny [ar], Nguyễn Thái Ngọc Duy [vi],
 | 
			
		||||
 Nilamdyuti Goswami [as], Alexander Shopov [bg], Ivaylo Valkov [bg],
 | 
			
		||||
 Daniel Mustieles [es], Kjartan Maraas [nb,nn], Yaron Shahrabani [he],
 | 
			
		||||
 Nilamdyuti Goswami [as], Chao-Hsiung Liao [zh_HK, zh_TW], Ihar Hrachyshka [be],
 | 
			
		||||
 Praveen Illa [te]
 | 
			
		||||
 | 
			
		||||
3.5.3
 | 
			
		||||
=====
 | 
			
		||||
* calendar: Adapt to Evolution-Data-Server API changes [Matthew; #677402]
 | 
			
		||||
* messageTray: Don't show non urgent notifications while in fullscreen
 | 
			
		||||
  [Adel; #677590]
 | 
			
		||||
* modalDialog: show dialogs on monitor with the mouse pointer [Tim; #642591]
 | 
			
		||||
* extensionSystem: Prepare for extension updating system [Jasper; #677586]
 | 
			
		||||
* appDisplay: Don't show apps in NoDisplay categories in the All view
 | 
			
		||||
  [Jasper; #658176]
 | 
			
		||||
* st: Trigger theme updates on resolution changes [Florian; #677975]
 | 
			
		||||
* Always enable a11y [Bastien; #678095]
 | 
			
		||||
* telepathyClient: ignore invalidated channels [Guillaume; #677457]
 | 
			
		||||
* shell-app: Update app menu if necessary [Florian; #676238]
 | 
			
		||||
* Enable the Screen Reader menu item [Matthias; #663256]
 | 
			
		||||
* Disable unredirection when a modal operation is active [Giovanni]
 | 
			
		||||
* Make folks optional [Colin]
 | 
			
		||||
* Improve mount-operation support [Cosimo]
 | 
			
		||||
  - Fix exception when showing password entry [#678428]
 | 
			
		||||
  - Close the password entry on operation abort [#673787]
 | 
			
		||||
  - autorun: Don't allow autorun for things we mount on startup [#660595]
 | 
			
		||||
  - Turn passphrase prompt into a dialog [#674962]
 | 
			
		||||
  - Implement org.Gtk.MountOperationHandler [#678516]
 | 
			
		||||
* Network menu improvements
 | 
			
		||||
  - Sort Wifi networks by strength [Giovanni; #658946]
 | 
			
		||||
  - Prefer wifi/3g over VPN in the panel [Cosimo; #672591]
 | 
			
		||||
* clock: Switch to using GnomeWallClock [Colin; #657074]
 | 
			
		||||
* remoteSearch: Allow to reference .desktop file for Title/Icon
 | 
			
		||||
  [Florian; #678816]
 | 
			
		||||
* Fix memory leaks [Jasper, Pavel; #678079, #678406, #678737]
 | 
			
		||||
* Misc fixes [Florian, Giovanni, Guillaume, Jasper, Kjartan, Piotr, Rui;
 | 
			
		||||
  #658955, #677497, #678396, #678502]
 | 
			
		||||
* Misc cleanups [Bastien, Florian, Jasper; #677426, #677515, #678096, #678416]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Matthew Barnes, Giovanni Campagna, Cosimo Cecchi, Matthias Clasen,
 | 
			
		||||
 Guillaume Desmottes, Piotr Drąg, Adel Gadllah, Tim L, Kjartan Maraas,
 | 
			
		||||
 Rui Matos, Florian Müllner, Bastien Nocera, Jasper St. Pierre, Colin Walters
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Matej Urbančič [sl], Yuri Kozlov [ru], Tom Tryfonidis [el],
 | 
			
		||||
 Kjartan Maraas [nb], Žygimantas Beručka [lt], Luca Ferretti [it],
 | 
			
		||||
 Khaled Hosny [ar], Daniel Mustieles [es], Fran Diéguez [gl], A S Alam [pa]
 | 
			
		||||
 | 
			
		||||
3.5.2
 | 
			
		||||
=====
 | 
			
		||||
* main: Move 'toggle-recording' binding into the shell [Florian; #674377]
 | 
			
		||||
* popupMenu: make sure to break the grab when the slider is not visible
 | 
			
		||||
  [Stefano; #672713]
 | 
			
		||||
* st-theme-node-drawing: Don't use GL types [Neil; #672711]
 | 
			
		||||
* Mirror Evolution calendar settings into our own schema [Owen; #674424]
 | 
			
		||||
* shell-network-agent: don't crash if a request isn't found [Dan; #674961]
 | 
			
		||||
* notificationDaemon: Match app based on WM_CLASS [Jasper; #673761]
 | 
			
		||||
* NetworkMenu: use network-offline while loading [Giovanni; #674426]
 | 
			
		||||
* lookingGlass: Remove the Errors tab [Jasper; #675104]
 | 
			
		||||
* searchDisplay: Reset keyboard focus after displaying async results
 | 
			
		||||
  [Rui; #675078]
 | 
			
		||||
* gdm: don't fail if fprintd is unavailable [Ray; #675006]
 | 
			
		||||
* messageTray: Fix scrolling up [Jasper; #661615]
 | 
			
		||||
* main: Close the recorder instead of pausing it [Rui; #675128]
 | 
			
		||||
* Accessibility [Alejandro]
 | 
			
		||||
  - Use the proper label_actor for date menu on top panel [#675307]
 | 
			
		||||
  - Set the proper role/label_actor for SearchResult.content [#672242]
 | 
			
		||||
  - do not expose a label text if 'hidden' style class is used [#675341]
 | 
			
		||||
* Magnifier: Add brightness and contrast functionality [Joseph; #639851]
 | 
			
		||||
* theme: use a smaller border-radius for top bar [Jakub; #672430]
 | 
			
		||||
* placeDisplay: use new bookmark file location [Matthias; #675443]
 | 
			
		||||
* port all synchronous search providers to the async API [Jasper, Rui; #675328]
 | 
			
		||||
* NetworkAgent: disallow multiple requests for the same connection/setting
 | 
			
		||||
  [Giovanni; #674961]
 | 
			
		||||
* userMenu: Update to latest mockups [Florian; #675802]
 | 
			
		||||
* util: Don't double-fork when spawning from Alt-F2 [Colin; #675789]
 | 
			
		||||
* messageTray: Make Source usable without subclassing [Jasper; #661236]
 | 
			
		||||
* panel: Check for appMenu button's reactivity before opening [Florian; #676316]
 | 
			
		||||
* Fix formatting of bluetooth passkey [Florian; #651251]
 | 
			
		||||
* notificationDaemon: Filter out file-transfer notifications [Jasper; #676175]
 | 
			
		||||
* Don't use global.log() [Jasper; #675790]
 | 
			
		||||
* Fix broken extension loading in some distributions [Owen, Alexandre; #670477]
 | 
			
		||||
* shell-app: Raise windows in reverse order to preserve the stacking
 | 
			
		||||
  [Rui; #676371]
 | 
			
		||||
* Generalize gdm-mode [Florian; #676156]
 | 
			
		||||
* Switch string formatting to the one inside gjs [Jasper; #675479]
 | 
			
		||||
* extensionUtils: Support subdirectories in getCurrentExtension
 | 
			
		||||
  [Jasper; #677001]
 | 
			
		||||
* panel: Refuse to add (legacy) status icons not part of the session mode
 | 
			
		||||
  [Florian; #677058]
 | 
			
		||||
* Add an initial-setup mode [Matthias; #676697]
 | 
			
		||||
* status/keyboard: Port to the new input sources settings [Rui; #641531]
 | 
			
		||||
* NetworkMenu: show notifications for failed VPN connections [Giovanni; #676330]
 | 
			
		||||
* userMenu: Indicate progress on status changes [Florian; #659067]
 | 
			
		||||
* recorder: Honor "disable-save-to-disk" lockdown key [Rūdolfs; #673630]
 | 
			
		||||
* searchDisplay: Use the rowLimit we pass to the IconGrid [Christian; #675527]
 | 
			
		||||
* endSessionDialog: Factor out _updateDescription from _updateContent
 | 
			
		||||
  [Alejandro; #674210]
 | 
			
		||||
* Fix empathy's appMenu freezing the shell [Alban; #676447]
 | 
			
		||||
* Code cleanups [Florian, Giovanni, Jasper; #672807, #672413, #676837, #676850,
 | 
			
		||||
  #672272]
 | 
			
		||||
* Misc bug fixes [Alban, Florian, Giovanni, Guillaume, Jasper, Piotr, Rico,
 | 
			
		||||
  Ron, Rui, Stefano; #659968, #672192, #673177, #673198, #674323, #675301,
 | 
			
		||||
  #675370, #676347, #676806, #677097]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Alban Browaeys, Giovanni Campagna, Matthias Clasen, Guillaume Desmottes,
 | 
			
		||||
 Piotr Drąg, Stefano Facchini, Rui Matos, Rūdolfs Mazurs, Florian Müllner,
 | 
			
		||||
 Alejandro Piñeiro, Neil Roberts, Alexandre Rostovtsev, Joseph Scheuhammer,
 | 
			
		||||
 Jakub Steiner, Jasper St. Pierre, Ray Strode, Owen Taylor, Rico Tzschichholz,
 | 
			
		||||
 Colin Walters, Dan Winship, Ron Yorston
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 OKANO Takayoshi [ja], Daniel Mustieles [es], Changwoo Ryu [ko],
 | 
			
		||||
 Yaron Shahrabani [he], Fran Diéguez [gl], Jonh Wendell [pt_BR],
 | 
			
		||||
 Kjartan Maraas [nb], Luca Ferretti [it], Tom Tryfonidis [el],
 | 
			
		||||
 Sandeep Sheshrao Shedmake [mr], Takanori MATSUURA [ja], Dirgita [id],
 | 
			
		||||
 Mantas Kriaučiūnas [lt], Matej Urbančič [sl], Jiro Matsuzawa [ja]
 | 
			
		||||
 | 
			
		||||
3.4.1
 | 
			
		||||
=====
 | 
			
		||||
* Fix crash that occurred when an icon theme change caused unexpected
 | 
			
		||||
  reentrancy in the icon loading code [Jasper; #673512]
 | 
			
		||||
* Don't show system and other disabled users in the GDM user list
 | 
			
		||||
  [Adel; #673784]
 | 
			
		||||
* Make gnome-shell-calendar-server initialize GTK+ so it can display
 | 
			
		||||
  password prompts if needed [#673608; Owen, Rico]
 | 
			
		||||
* Adapt to Mutter API change for keybinding addition [Florian; #673014]
 | 
			
		||||
* Fix crash when an extension was installed as both a user extension
 | 
			
		||||
  and a system extension [#673613; Jasper]
 | 
			
		||||
* Fix bug where chat entry could end up partially offscreen [Joost, 661944]
 | 
			
		||||
* Fix problem where icons weren't updating when theme was changed
 | 
			
		||||
  [#672941; Florian]
 | 
			
		||||
* Look for Evolution calendar settings in GSettings, not GConf [#673610; Owen]
 | 
			
		||||
* Add <super>F10 for the application menu [#672909; Florian]
 | 
			
		||||
* Fix %Id format characters to work in translations [#673106; Cosimo]
 | 
			
		||||
  (were already used in fa translation)
 | 
			
		||||
* Fix error when NetworkManager restarts [#673043; Giovanni]
 | 
			
		||||
* Improve efficiency of overview redraws by working around Clutter issue
 | 
			
		||||
  [Stefano; #670636]
 | 
			
		||||
* Misc bug fixes [Florian, Giovanni, Jasper, Rui, Stefano;
 | 
			
		||||
  #672592, #672641, #672719, #673187, #673233, #673656]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Giovanni Campagna, Cosimo Cecchi, Stefano Facchini, Adel Gadllah, Rui Matos,
 | 
			
		||||
 Florian Müllner, Jasper St. Pierre, Owen Taylor, Rico Tzschichholz,
 | 
			
		||||
 Joost Verdoorn
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Khaled Hosny [ar], Ihar Hrachyshka [be], Alexander Shopov [bg], Gil Forcada,
 | 
			
		||||
 Jordi Serratosa [ca], Petr Kovar [cs], Bruce Cowan [en_GB],
 | 
			
		||||
 Carles Ferrando [ca@valencia], Wolfgang Stöggl [de], Daniel Mustieles [es],
 | 
			
		||||
 Arash Mousavi [fa], Bruno Brouard [fr], Fran Diéguez [gl],
 | 
			
		||||
 Sweta Kothari [gu], Yaron Shahrabani [he], Gabor Kelemen [hu],
 | 
			
		||||
 Shankar Prasad [kn], Žygimantas Beručka [lt], Rudolfs Mazurs [lv],
 | 
			
		||||
 Sandeep Sheshrao Shedmake [mr], Kjartan Maraas [nb], Piotr Drąg [pl],
 | 
			
		||||
 Yuri Myasoedov [ru], Daniel Nylander [se], Matej Urbančič [sl],
 | 
			
		||||
 Miroslav Nikolić [sr], Sasi Bhushan, Praveen Illa [te], Yinghua Wang [zh_CN]
 | 
			
		||||
 | 
			
		||||
3.4.0
 | 
			
		||||
=====
 | 
			
		||||
* Don't crash when taking screenshots [Jasper; #672775]
 | 
			
		||||
* Fix dialog-resizing problem [Florian; #672543]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Florian Müllner, Jasper St. Pierre
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Khaled Hosny, Abderrahim Kitouni [ar], Ihar Hrachyshka [be],
 | 
			
		||||
 Alexander Shopov [bg], Marek Černocký [cs], Jiri Grönroos, Timo Jyrinki [fi],
 | 
			
		||||
 Bruno Brouard [fr], Fran Diéguez [gl], Yaron Shahrabani [he],
 | 
			
		||||
 Gabor Kelemen [hu], Jiro Matsuzawa [ja], Kenneth Nielsen [dk],
 | 
			
		||||
 Mattias Põldaru [et], Changwoo Ryu [ko], Rudolfs Mazurs [lv],
 | 
			
		||||
 Jonh Wendell [pt_BR], Yuri Myasoedov[ru], Daniel Korostil [uk],
 | 
			
		||||
 Nguyễn Thái Ngọc Duy [vi], Chao-Hsiung Liao [zh_HK, zh_TW]
 | 
			
		||||
 | 
			
		||||
3.3.92
 | 
			
		||||
======
 | 
			
		||||
* Add shell-dialogs for GNOME Keyring prompts [Stef; #652459, #652460, #671034]
 | 
			
		||||
* When the user returns from idle, bring up the message tray if there were
 | 
			
		||||
  messages while they were away [Marina; #643014]
 | 
			
		||||
* https://live.gnome.org/EveryDetailMatters
 | 
			
		||||
  - Make the workspace thumbnails clickable all the way to the edge of the
 | 
			
		||||
    screen [Stefano; #643319]
 | 
			
		||||
  - Don't slide out the workspace thumbnails if the mouse is over them when
 | 
			
		||||
    entering the overview [Joost, #651092]
 | 
			
		||||
  - Fix placeholder jumps while dragging a dash item [Joost; #651842]
 | 
			
		||||
  - Don't favorite apps if they are dropped back at the same position
 | 
			
		||||
    [Jean-Philippe; #656333]
 | 
			
		||||
  - To avoid confusion, don't allow removing running apps from favorites
 | 
			
		||||
    [Florian; #644853]
 | 
			
		||||
  - Fix creation of new workspaces by dragging application launchers
 | 
			
		||||
    [Stefano; #664202]
 | 
			
		||||
  - Make it easier to drag dash items without triggering the menu
 | 
			
		||||
    [Florian; #637103]
 | 
			
		||||
* Accessibility [Alejandro]
 | 
			
		||||
  - Add StWidget API for easily adding accessible states and setting roles,
 | 
			
		||||
    names [#668366, #667432, #671378]
 | 
			
		||||
  - Set accessibility information on UI elements
 | 
			
		||||
    [#644255, #667432, #668361, #672047, #670308, #670312, #670719, #671404]
 | 
			
		||||
* Improve key-navigation in the overview [Rui, Florian; #663901]
 | 
			
		||||
* Key navigation bug fixes [Rui, Florian; #662493, #663437, #665215, #671998]
 | 
			
		||||
* Honor a 'org.gnome.shell.overrides.dynamic-workspaces' setting that
 | 
			
		||||
  determines whether the workspace count is dynamic and unsaved in GSettings
 | 
			
		||||
  or static and saved. [Florian; #671568]
 | 
			
		||||
* Avoid saving user presence to GSettings when not necessary
 | 
			
		||||
  [Florian; #665701, #668214]
 | 
			
		||||
* Save screencasts in the users Videos/ directory [Adel; #670749]
 | 
			
		||||
  Use a "human readable" filename [Florian, Adel, Ray; #670753]
 | 
			
		||||
* Allow dragging from the empty part of the top panel to unmaximize a window
 | 
			
		||||
  [Florian; #666359]
 | 
			
		||||
* Fix hangs that could occur when switching away to a VT [Ray; #653833]
 | 
			
		||||
* Fix problems with installing from extensions.gnome.org [Giovanni; #671134]
 | 
			
		||||
* Fix locking the screen when suspending via menu [David, Gert; #670820]
 | 
			
		||||
* Fix browser plugin with Konqueror and Opera [Jasper]
 | 
			
		||||
* Fix shell restart not to bring up failure screen [Giovanni; #648384]
 | 
			
		||||
* Reorganize and clean up CSS theming [Allan; #668209]
 | 
			
		||||
* Improve appearance of modal dialogs [Allan, Florian; #670227, #668209]
 | 
			
		||||
* Update the calendar code to use ECalClient [Giovanni; #671177]
 | 
			
		||||
* Update jhbuild script to use the main moduleset [Owen, Will; #668440]
 | 
			
		||||
* StTextureCache: code cleanup, evict unused icons, merge together
 | 
			
		||||
  simulataneous requests for the same icon [Jasper; #670771, #671656, #672273]
 | 
			
		||||
* Clean up St for recent Clutter changes and fix bugs. StContainer and
 | 
			
		||||
  StGroup are removed [Jasper, Florian; #670034, #670640, #670904]
 | 
			
		||||
* Code cleanup [Adel, Jasper, Rui; #613194, #671086, #671103]
 | 
			
		||||
* Misc bug fixes
 | 
			
		||||
  [Adel, Colin G, Cosimo, Florian, Giovanni, Jasper, Marius, Rui, Stefano;
 | 
			
		||||
  #651130, #658946, #667552, #670076, #671001, #670979, #671410, #671411,
 | 
			
		||||
  #671556, #671656, #671657, #672011, #672024, #672240, #672265, #672270,
 | 
			
		||||
  #672321, #672326, #672413, #672471]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Jean-Philippe Braun, Giovanni Campagna, Cosimo Cecchi, Allan Day,
 | 
			
		||||
 Stefano Facchini, David Foerster, Adel Gadllah, Marius Gedminas,
 | 
			
		||||
 Colin Guthrie, Gert Michael Kulyk, William Lachance, Rui Matos,
 | 
			
		||||
 Florian Müllner, Alejandro Piñeiro, Jan Alexander Steffens,
 | 
			
		||||
 Jasper St. Pierre, Ray Strode, Owen Taylor, Joost Verdoorn, Stef Walter,
 | 
			
		||||
 Marina Zhurakhinskaya
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Nilamdyuti Goswami [as], Ihar Hrachyshka, Kasia Bondarava [be],
 | 
			
		||||
 Alexander Shopov, Ivaylo Valkov [bg], Gil Forcada [ca], Marek Černocký [cs],
 | 
			
		||||
 Mario Blättermann [de], Kris Thomsen [dk], Bruce Cowan [en_GB],
 | 
			
		||||
 Kristjan Schmidt [eo], Daniel Mustieles [es], Mattias Põldaru [et],
 | 
			
		||||
 Inaki Larranaga Murgoitio [eu], Arash Mousavi [fa], Timo Jyrinki [fi],
 | 
			
		||||
 Bruno Brouard [fr], Fran Diéguez [gl], Sweta Kothari [gu],
 | 
			
		||||
 Yaron Shahrabani [he], Gabor Kelemen [hu], Jiro Matsuzawa [ja],
 | 
			
		||||
 Baurzhan Muftakhidinov [kk], Seong-ho Cho [ko], Žygimantas Beručka [lt],
 | 
			
		||||
 Anita Reitere [lv], Anish A, Praveen Arimbrathodiyil, Mohammed Sadiq [ml],
 | 
			
		||||
 fKjartan Maraas [nb], Wouter Bolsterlee [nl], A S Alam [pa], Piotr Drąg [pl],
 | 
			
		||||
 Duarte Loreto [pt], Jonh Wendell [pt_BR], Yuri Myasoedov [ru],
 | 
			
		||||
 Matej Urbančič [sl], Miroslav Nikolić [sr], Tirumurti Vasudevan [ta],
 | 
			
		||||
 Sasi Bhushan, Krishnababu Krothapalli [te], Daniel Korostil [uk],
 | 
			
		||||
 Nguyễn Thái Ngọc Duy [vi], YunQiang Su, Yinghua Wang [zh_CN],
 | 
			
		||||
 Chao-Hsiung Liao [zh_HK, zh_TW]
 | 
			
		||||
 | 
			
		||||
3.3.90
 | 
			
		||||
======
 | 
			
		||||
 | 
			
		||||
* Allow other applications to implement search providers via D-Bus
 | 
			
		||||
  [Florian; #663125, #670148]
 | 
			
		||||
* Remove "Recent Items" search, as replaced by Documents search
 | 
			
		||||
  [Florian; #663125]
 | 
			
		||||
* Allow NetworkManager VPN plugins to use a shell-themed dialog
 | 
			
		||||
  [Giovanni; #658484]
 | 
			
		||||
* Port away from deprecated Clutter API [Jasper, Florian, Adel; #670034]
 | 
			
		||||
  - StTooltip is removed
 | 
			
		||||
  - StWidget is now a concrete class and can be instantiated
 | 
			
		||||
  - st_container_destroy_children(), st_box_layout_insert_actor(),
 | 
			
		||||
    and other functions removed in favor of new replacements in Clutter.
 | 
			
		||||
* Use systemd for console/session handling when available [Lennart]
 | 
			
		||||
* Visual improvements to contact search, padding, top panel, checkboxes
 | 
			
		||||
  [Allan, Florian, Jakub; #669489, #669811, #669993]
 | 
			
		||||
* Add a include_cursor parameter to Screenshot and ScreenshotWindow
 | 
			
		||||
  D-Bus methods [Adel; #670086]
 | 
			
		||||
* Add a "FlashArea" D-Bus method to do the screenshot flash without a
 | 
			
		||||
  screenshot [Adel; #669660]
 | 
			
		||||
* Build fixes [Adel, Giovanni, Jasper; #658484, #669637]
 | 
			
		||||
* Misc bug fixes [Adel, Florian, Giovanni, Guillaume, Jasper, Jeff,
 | 
			
		||||
  Marc-Antoine, Stef, Stefano, Will; #642135, #658484, #658908, #667694,
 | 
			
		||||
  #669098, #669921, #669662, #669694, #669776, #669887, #669921, #670005,
 | 
			
		||||
  #670006, #670319, #670418, #670489]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Giovanni Campagna, Cosimo Cecchi, Allan Day, Guillaume Desmottes, Jeff Epler,
 | 
			
		||||
 Stefano Facchini, Adel Gadllah, Florian Müllner, Marc-Antoine Perennou,
 | 
			
		||||
 Jasper St. Pierre, Lennart Poettering, Jakub Steiner, Jasper St. Pierre,
 | 
			
		||||
 Will Thompson, Stef Walter
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Ihar Hrachyshka [be], Marek Černocký, Adam Matoušek [cs],
 | 
			
		||||
 Kenneth Nielsen [dk], Daniel Mustieles [es], Mattias Põldaru [et],
 | 
			
		||||
 Fran Diéguez [gl], Yaron Shahrabani [he], Luca Ferretti [it],
 | 
			
		||||
 Baurzhan Muftakhidinov [kk], Aurimas Černius [lt], Kjartan Maraas [nb],
 | 
			
		||||
 A S Alam [pa], Matej Urbančič [sl], Miroslav Nikolić [sr],
 | 
			
		||||
 Praveen Illa [te], Chao-Hsiung Liao [zh_HK, zh_TW]
 | 
			
		||||
 | 
			
		||||
3.3.5
 | 
			
		||||
=====
 | 
			
		||||
 | 
			
		||||
* Extension system: [Jasper; #668429]
 | 
			
		||||
  http://blog.mecheye.net/2012/02/more-extension-api-breaks/
 | 
			
		||||
 - Add a 'gnome-shell-extension-prefs' application for displaying extension
 | 
			
		||||
   preferences as provided by the extension in a prefs.js file.
 | 
			
		||||
 - Allow launching gnome-shell-extension-prefs from extensions.gnome.org
 | 
			
		||||
   throuhg the browser plugin.
 | 
			
		||||
 - Add ExtensionUtils.getCurrentExtension() for an extension to get a
 | 
			
		||||
   handle to an extension object, to get local imports or paths.
 | 
			
		||||
 - Add an onshellrestart callback to the browser plugin [Jasper; #668517]
 | 
			
		||||
* Screenshots:
 | 
			
		||||
  - Move the screenshot "flash" to the shell [Cosimo; #668618]
 | 
			
		||||
  - Move saving screenshots to a thread [Adel; #652952]
 | 
			
		||||
  - Correctly screenshot rounded decorations [Jasper; #662486]
 | 
			
		||||
* Screen recorder:
 | 
			
		||||
  - Change the default pipeline to favor speed over quality [Owen; #669066]
 | 
			
		||||
  - Drop frames to keep from running the user out of memory [Owen; #669066]
 | 
			
		||||
* Work around a slow implementation of glReadPixels() in the Intel drivers,
 | 
			
		||||
  improving performance for screenshots and the screen recorder.
 | 
			
		||||
  [Owen; #669065]
 | 
			
		||||
* Use Keywords: field in desktop files when search for applications
 | 
			
		||||
  [Florian; #609702]
 | 
			
		||||
* Strip debian- when matching desktop file names [Jasper; #665647]
 | 
			
		||||
* Fix up various problems from CSS background size-addition
 | 
			
		||||
  [Florian, Jasper; #668430, #633462]
 | 
			
		||||
* UI tweaks and behavior fixes
 | 
			
		||||
  [Florian, Giovanni, Stefano; #643867, #666197, #664622]
 | 
			
		||||
* Some improvements to exported accessibility information  [Alejando; #667376]
 | 
			
		||||
* Don't show contacts without IM information as offline [Florian; #662685]
 | 
			
		||||
* Don't change status from hidden to extended_away when going idle
 | 
			
		||||
  [Florian; #642408]
 | 
			
		||||
* Cleanups [Emmanuele, Jasper; #662152, #669239]
 | 
			
		||||
* Misc bug fixes [Cosimo, Dan, Florian, Jasper, Rui, Stefano;
 | 
			
		||||
  #633462, #643867, #662213, #662386, #662747, #665000, #665017, #665322,
 | 
			
		||||
  #667371, #667860, #668020, #668517, #668541, #669236]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Emmanuele Bassi, Giovanni Campagna, Cosimo Cecchi, Stefano Facchini,
 | 
			
		||||
 Adel Gadllah, Rui Matos, Florian Müllner, Alejandro Piñeiro,
 | 
			
		||||
 Jasper St. Pierre, Owen Taylor, Dan Winship
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Daniel Mustieles [es], Timo Jyrinki [fi], Seán de Búrca [ga],
 | 
			
		||||
 Fran Diéguez [gl], Kjartan Maraas [nb], Wouter Bolsterlee [nl],
 | 
			
		||||
 Danishka Navin [si], Yaron Shahrabani [he], Matej Urbančič [sl],
 | 
			
		||||
 Chao-Hsiung Liao [zh_HK, zh_TW]
 | 
			
		||||
 | 
			
		||||
3.3.4
 | 
			
		||||
=====
 | 
			
		||||
* https://live.gnome.org/EveryDetailMatters
 | 
			
		||||
  - Add "browse" for labels for dash items - once a tooltip is
 | 
			
		||||
    showing, switch to other items without a delay [Seif; #666170]
 | 
			
		||||
  - Always scale down windows in the overview at least to 70% [Vit; #646704]
 | 
			
		||||
  - Fix the new-workspace drop indicator sometimes getting stuck
 | 
			
		||||
    [Stefano; #664201]
 | 
			
		||||
  - Delay rearranging windows in the overview as long as the pointer
 | 
			
		||||
    is over a window [Vit; #645325]
 | 
			
		||||
* Add a GConf => DConf migration file for overriden Mutter settings
 | 
			
		||||
  [Florian; #667636]
 | 
			
		||||
* When a VPN connection is active, show that as the network icon
 | 
			
		||||
  [Giovanni; #665115]
 | 
			
		||||
* Handle the "ExtendedAway" IM status as away, not offline [Guillaume; #667813]
 | 
			
		||||
* Improve the appearance of the labels in "Applications" [Alex; #642392]
 | 
			
		||||
* Adjust for GTK+ and Mutter API changes for application menu [Ryan; #668118]
 | 
			
		||||
* Add section label support to the application menu [Giovanni; #666681]
 | 
			
		||||
* Fix screenshot methods to work again [Cosimo; #667662]
 | 
			
		||||
* Fix several crashers related to updating workspace thumbnails [Owen; #667652]
 | 
			
		||||
* Fix memory management error causing gnome-shell-hotplug-sniffer to crash
 | 
			
		||||
  [Owen; #667378]
 | 
			
		||||
* Build fixes [Emmanuele, Rico; #667864]
 | 
			
		||||
* Code cleanups [Adel; #668087]
 | 
			
		||||
* Misc bug fixes [Colin, Florian, Giovanni, Owen, Xavier; #633028, #658817,
 | 
			
		||||
  #664138, #667881, #668048, #668050]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Emmanuele Bassi, Giovanni Campagna, Cosimo Cecchi, Xavier Claessens,
 | 
			
		||||
 Guillaume Desmottes, Stefano Facchini, Adel Gadllah, Alex Hultman,
 | 
			
		||||
 Ryan Lortie, Seif Lotfy, Florian Müllner, Vit Stanislav, Owen Taylor,
 | 
			
		||||
 Rico Tzschichholz, Colin Walters
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Ihar Hrachyshka [be], Alexander Shopov [bg], Arash Mousavi [fa],
 | 
			
		||||
 Jiri Grönroos, Timo Jyrinki [fi], Fran Diéguez [gl], Kjartan Maraas [nb],
 | 
			
		||||
 Yuri Myasoedov [ru], Matej Urbančič [sl], Nguyễn Thái Ngọc Duy [vi]
 | 
			
		||||
 | 
			
		||||
3.3.3
 | 
			
		||||
=====
 | 
			
		||||
* https://live.gnome.org/EveryDetailMatters
 | 
			
		||||
  - Stop flashing the window labels on actions in overview [Zan; #644861]
 | 
			
		||||
  - Improve the look of window captions in the overview [Marc; #664487]
 | 
			
		||||
  - Move dash tooltips beside the icon [Seif, Stefano; #666166]
 | 
			
		||||
* Support application menus exported from applications via new GLib API
 | 
			
		||||
   and D-Bus protocol. [Giovanni, Colin, Matthias, Cosimo]
 | 
			
		||||
* For removable device prompts, show "Open with Rhythmbox], rather
 | 
			
		||||
  than "Open with Rhythmbox Music Player' [Florian; #664561]
 | 
			
		||||
* Switch to activating the message tray only with a hot corner rather
 | 
			
		||||
  than a full row of pixels, allowing mouse events to apps [Rui; #663366]
 | 
			
		||||
* Fully handle the case where the workspaces-only-on-primary
 | 
			
		||||
  GSetting is set to false [Florian; #652580]
 | 
			
		||||
* Add support for background-size CSS property to St [Quentin; #633462]
 | 
			
		||||
* Port to new GJS Lang.Class framework [Giovanni; #664436]
 | 
			
		||||
* Finish port to GDBus [Giovanni; #664436]
 | 
			
		||||
* Stop using the deprecated Clutter default stage [Florian, Jasper; #664052]
 | 
			
		||||
* Fix bugs that kept browser plugin from working in WebKit-based browser
 | 
			
		||||
  [Jasper; #666444]
 | 
			
		||||
* Fix typo that made uninstalling extensions not work [Jasper]
 | 
			
		||||
* Fix crash in browser plugin if shell is not run [Jürg]
 | 
			
		||||
* Reintroduce piscine paschal ovum [Giovanni; #666606]
 | 
			
		||||
* Network menu bug fixes
 | 
			
		||||
  Giovanni; #664124, #665194, #665680, #666429, #666614]
 | 
			
		||||
* Misc bug fixes [Florian, Jasper, Jonny, Marina, Ron; #647587, #659272,
 | 
			
		||||
  #664138, #665261, #666020, #666243]
 | 
			
		||||
* Build fixes [Owen]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
 Jürg Billeter, Giovanni Campagna, Stefano Candori, Cosimo Cecchi,
 | 
			
		||||
 Matthias Clasen, Zan Dobersek, Quentin Glidic, Jonny Lamb, Ryan Lortie,
 | 
			
		||||
 Seif Lotfy, Rui Matos, Florian Müllner, Bastien Nocera, Jasper St. Pierre,
 | 
			
		||||
 Marc Plano-Lesay, Owen Taylor, Colin Walters, Ron Yorsten,
 | 
			
		||||
 Marina Zhurakhinskaya
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
 Petr Kovar [cs], Kris Thomsen [dk], Daniel Mustieles [es],
 | 
			
		||||
 Ville-Pekka Vainio [fi], Yaron Shahrabani [he], Luca Ferretti [it],
 | 
			
		||||
 Hideki Yamane [ja], Žygimantas Beručka [lt], Jovan Naumovski [mk],
 | 
			
		||||
 Kjartan Maraas [nb], "Andreas N" [nn], Lucian Adrian Grijincu [ro],
 | 
			
		||||
 Matej Urbančič [sl], Praveen Illa [te], Muhammet Kara [tr],
 | 
			
		||||
 Daniel Korostil [uk], Aron Xu [zh_CN]
 | 
			
		||||
 | 
			
		||||
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 [cs], 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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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/
 | 
			
		||||
							
								
								
									
										1041
									
								
								browser-plugin/browser-plugin.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										893
									
								
								browser-plugin/npapi/npapi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,893 @@
 | 
			
		||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
			
		||||
/* ***** BEGIN LICENSE BLOCK *****
 | 
			
		||||
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 | 
			
		||||
 *
 | 
			
		||||
 * The contents of this file are subject to the Mozilla Public License Version
 | 
			
		||||
 * 1.1 (the "License"); you may not use this file except in compliance with
 | 
			
		||||
 * the License. You may obtain a copy of the License at
 | 
			
		||||
 * http://www.mozilla.org/MPL/
 | 
			
		||||
 *
 | 
			
		||||
 * Software distributed under the License is distributed on an "AS IS" basis,
 | 
			
		||||
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 | 
			
		||||
 * for the specific language governing rights and limitations under the
 | 
			
		||||
 * License.
 | 
			
		||||
 *
 | 
			
		||||
 * The Original Code is mozilla.org code.
 | 
			
		||||
 *
 | 
			
		||||
 * The Initial Developer of the Original Code is
 | 
			
		||||
 * Netscape Communications Corporation.
 | 
			
		||||
 * Portions created by the Initial Developer are Copyright (C) 1998
 | 
			
		||||
 * the Initial Developer. All Rights Reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Contributor(s):
 | 
			
		||||
 *
 | 
			
		||||
 * Alternatively, the contents of this file may be used under the terms of
 | 
			
		||||
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 | 
			
		||||
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 | 
			
		||||
 * in which case the provisions of the GPL or the LGPL are applicable instead
 | 
			
		||||
 * of those above. If you wish to allow use of your version of this file only
 | 
			
		||||
 * under the terms of either the GPL or the LGPL, and not to allow others to
 | 
			
		||||
 * use your version of this file under the terms of the MPL, indicate your
 | 
			
		||||
 * decision by deleting the provisions above and replace them with the notice
 | 
			
		||||
 * and other provisions required by the GPL or the LGPL. If you do not delete
 | 
			
		||||
 * the provisions above, a recipient may use your version of this file under
 | 
			
		||||
 * the terms of any one of the MPL, the GPL or the LGPL.
 | 
			
		||||
 *
 | 
			
		||||
 * ***** END LICENSE BLOCK ***** */
 | 
			
		||||
 | 
			
		||||
#ifndef npapi_h_
 | 
			
		||||
#define npapi_h_
 | 
			
		||||
 | 
			
		||||
#if defined(__OS2__)
 | 
			
		||||
#pragma pack(1)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "nptypes.h"
 | 
			
		||||
 | 
			
		||||
#if defined(__OS2__) || defined(OS2)
 | 
			
		||||
#ifndef XP_OS2
 | 
			
		||||
#define XP_OS2 1
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32) && !defined(__SYMBIAN32__)
 | 
			
		||||
#include <windef.h>
 | 
			
		||||
#ifndef XP_WIN
 | 
			
		||||
#define XP_WIN 1
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__SYMBIAN32__)
 | 
			
		||||
#ifndef XP_SYMBIAN
 | 
			
		||||
#define XP_SYMBIAN 1
 | 
			
		||||
#undef XP_WIN
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__APPLE_CC__) && !defined(XP_UNIX)
 | 
			
		||||
#ifndef XP_MACOSX
 | 
			
		||||
#define XP_MACOSX 1
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX) && defined(__LP64__)
 | 
			
		||||
#define NP_NO_QUICKDRAW
 | 
			
		||||
#define NP_NO_CARBON
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
#include <ApplicationServices/ApplicationServices.h>
 | 
			
		||||
#include <OpenGL/OpenGL.h>
 | 
			
		||||
#ifndef NP_NO_CARBON
 | 
			
		||||
#include <Carbon/Carbon.h>
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(XP_UNIX)
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#if defined(MOZ_X11)
 | 
			
		||||
#include <X11/Xlib.h>
 | 
			
		||||
#include <X11/Xutil.h>
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(XP_SYMBIAN)
 | 
			
		||||
#include <QEvent>
 | 
			
		||||
#include <QRegion>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
/*                        Plugin Version Constants                      */
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
#define NP_VERSION_MAJOR 0
 | 
			
		||||
#define NP_VERSION_MINOR 27
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* The OS/2 version of Netscape uses RC_DATA to define the
 | 
			
		||||
   mime types, file extensions, etc that are required.
 | 
			
		||||
   Use a vertical bar to separate types, end types with \0.
 | 
			
		||||
   FileVersion and ProductVersion are 32bit ints, all other
 | 
			
		||||
   entries are strings that MUST be terminated with a \0.
 | 
			
		||||
 | 
			
		||||
AN EXAMPLE:
 | 
			
		||||
 | 
			
		||||
RCDATA NP_INFO_ProductVersion { 1,0,0,1,}
 | 
			
		||||
 | 
			
		||||
RCDATA NP_INFO_MIMEType    { "video/x-video|",
 | 
			
		||||
                             "video/x-flick\0" }
 | 
			
		||||
RCDATA NP_INFO_FileExtents { "avi|",
 | 
			
		||||
                             "flc\0" }
 | 
			
		||||
RCDATA NP_INFO_FileOpenName{ "MMOS2 video player(*.avi)|",
 | 
			
		||||
                             "MMOS2 Flc/Fli player(*.flc)\0" }
 | 
			
		||||
 | 
			
		||||
RCDATA NP_INFO_FileVersion       { 1,0,0,1 }
 | 
			
		||||
RCDATA NP_INFO_CompanyName       { "Netscape Communications\0" }
 | 
			
		||||
RCDATA NP_INFO_FileDescription   { "NPAVI32 Extension DLL\0"
 | 
			
		||||
RCDATA NP_INFO_InternalName      { "NPAVI32\0" )
 | 
			
		||||
RCDATA NP_INFO_LegalCopyright    { "Copyright Netscape Communications \251 1996\0"
 | 
			
		||||
RCDATA NP_INFO_OriginalFilename  { "NVAPI32.DLL" }
 | 
			
		||||
RCDATA NP_INFO_ProductName       { "NPAVI32 Dynamic Link Library\0" }
 | 
			
		||||
*/
 | 
			
		||||
/* RC_DATA types for version info - required */
 | 
			
		||||
#define NP_INFO_ProductVersion      1
 | 
			
		||||
#define NP_INFO_MIMEType            2
 | 
			
		||||
#define NP_INFO_FileOpenName        3
 | 
			
		||||
#define NP_INFO_FileExtents         4
 | 
			
		||||
/* RC_DATA types for version info - used if found */
 | 
			
		||||
#define NP_INFO_FileDescription     5
 | 
			
		||||
#define NP_INFO_ProductName         6
 | 
			
		||||
/* RC_DATA types for version info - optional */
 | 
			
		||||
#define NP_INFO_CompanyName         7
 | 
			
		||||
#define NP_INFO_FileVersion         8
 | 
			
		||||
#define NP_INFO_InternalName        9
 | 
			
		||||
#define NP_INFO_LegalCopyright      10
 | 
			
		||||
#define NP_INFO_OriginalFilename    11
 | 
			
		||||
 | 
			
		||||
#ifndef RC_INVOKED
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
/*                       Definition of Basic Types                      */
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
typedef unsigned char NPBool;
 | 
			
		||||
typedef int16_t       NPError;
 | 
			
		||||
typedef int16_t       NPReason;
 | 
			
		||||
typedef char*         NPMIMEType;
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
/*                       Structures and definitions                     */
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
#if !defined(__LP64__)
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
#pragma options align=mac68k
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* __LP64__ */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  NPP is a plug-in's opaque instance handle
 | 
			
		||||
 */
 | 
			
		||||
typedef struct _NPP
 | 
			
		||||
{
 | 
			
		||||
  void* pdata;      /* plug-in private data */
 | 
			
		||||
  void* ndata;      /* netscape private data */
 | 
			
		||||
} NPP_t;
 | 
			
		||||
 | 
			
		||||
typedef NPP_t*  NPP;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPStream
 | 
			
		||||
{
 | 
			
		||||
  void*    pdata; /* plug-in private data */
 | 
			
		||||
  void*    ndata; /* netscape private data */
 | 
			
		||||
  const    char* url;
 | 
			
		||||
  uint32_t end;
 | 
			
		||||
  uint32_t lastmodified;
 | 
			
		||||
  void*    notifyData;
 | 
			
		||||
  const    char* headers; /* Response headers from host.
 | 
			
		||||
                           * Exists only for >= NPVERS_HAS_RESPONSE_HEADERS.
 | 
			
		||||
                           * Used for HTTP only; NULL for non-HTTP.
 | 
			
		||||
                           * Available from NPP_NewStream onwards.
 | 
			
		||||
                           * Plugin should copy this data before storing it.
 | 
			
		||||
                           * Includes HTTP status line and all headers,
 | 
			
		||||
                           * preferably verbatim as received from server,
 | 
			
		||||
                           * headers formatted as in HTTP ("Header: Value"),
 | 
			
		||||
                           * and newlines (\n, NOT \r\n) separating lines.
 | 
			
		||||
                           * Terminated by \n\0 (NOT \n\n\0). */
 | 
			
		||||
} NPStream;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPByteRange
 | 
			
		||||
{
 | 
			
		||||
  int32_t  offset; /* negative offset means from the end */
 | 
			
		||||
  uint32_t length;
 | 
			
		||||
  struct _NPByteRange* next;
 | 
			
		||||
} NPByteRange;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPSavedData
 | 
			
		||||
{
 | 
			
		||||
  int32_t len;
 | 
			
		||||
  void*   buf;
 | 
			
		||||
} NPSavedData;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPRect
 | 
			
		||||
{
 | 
			
		||||
  uint16_t top;
 | 
			
		||||
  uint16_t left;
 | 
			
		||||
  uint16_t bottom;
 | 
			
		||||
  uint16_t right;
 | 
			
		||||
} NPRect;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPSize
 | 
			
		||||
{
 | 
			
		||||
  int32_t width;
 | 
			
		||||
  int32_t height;
 | 
			
		||||
} NPSize;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
  NPFocusNext = 0,
 | 
			
		||||
  NPFocusPrevious = 1
 | 
			
		||||
} NPFocusDirection;
 | 
			
		||||
 | 
			
		||||
/* Return values for NPP_HandleEvent */
 | 
			
		||||
#define kNPEventNotHandled 0
 | 
			
		||||
#define kNPEventHandled 1
 | 
			
		||||
/* Exact meaning must be spec'd in event model. */
 | 
			
		||||
#define kNPEventStartIME 2
 | 
			
		||||
 | 
			
		||||
#if defined(XP_UNIX)
 | 
			
		||||
/*
 | 
			
		||||
 * Unix specific structures and definitions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Callback Structures.
 | 
			
		||||
 *
 | 
			
		||||
 * These are used to pass additional platform specific information.
 | 
			
		||||
 */
 | 
			
		||||
enum {
 | 
			
		||||
  NP_SETWINDOW = 1,
 | 
			
		||||
  NP_PRINT
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  int32_t type;
 | 
			
		||||
} NPAnyCallbackStruct;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  int32_t      type;
 | 
			
		||||
#if defined(MOZ_X11)
 | 
			
		||||
  Display*     display;
 | 
			
		||||
  Visual*      visual;
 | 
			
		||||
  Colormap     colormap;
 | 
			
		||||
  unsigned int depth;
 | 
			
		||||
#endif
 | 
			
		||||
} NPSetWindowCallbackStruct;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  int32_t type;
 | 
			
		||||
  FILE* fp;
 | 
			
		||||
} NPPrintCallbackStruct;
 | 
			
		||||
 | 
			
		||||
#endif /* XP_UNIX */
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
typedef enum {
 | 
			
		||||
#ifndef NP_NO_QUICKDRAW
 | 
			
		||||
  NPDrawingModelQuickDraw = 0,
 | 
			
		||||
#endif
 | 
			
		||||
  NPDrawingModelCoreGraphics = 1,
 | 
			
		||||
  NPDrawingModelOpenGL = 2,
 | 
			
		||||
  NPDrawingModelCoreAnimation = 3,
 | 
			
		||||
  NPDrawingModelInvalidatingCoreAnimation = 4
 | 
			
		||||
} NPDrawingModel;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
#ifndef NP_NO_CARBON
 | 
			
		||||
  NPEventModelCarbon = 0,
 | 
			
		||||
#endif
 | 
			
		||||
  NPEventModelCocoa = 1
 | 
			
		||||
} NPEventModel;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *   The following masks are applied on certain platforms to NPNV and
 | 
			
		||||
 *   NPPV selectors that pass around pointers to COM interfaces. Newer
 | 
			
		||||
 *   compilers on some platforms may generate vtables that are not
 | 
			
		||||
 *   compatible with older compilers. To prevent older plugins from
 | 
			
		||||
 *   not understanding a new browser's ABI, these masks change the
 | 
			
		||||
 *   values of those selectors on those platforms. To remain backwards
 | 
			
		||||
 *   compatible with different versions of the browser, plugins can
 | 
			
		||||
 *   use these masks to dynamically determine and use the correct C++
 | 
			
		||||
 *   ABI that the browser is expecting. This does not apply to Windows
 | 
			
		||||
 *   as Microsoft's COM ABI will likely not change.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define NP_ABI_GCC3_MASK  0x10000000
 | 
			
		||||
/*
 | 
			
		||||
 *   gcc 3.x generated vtables on UNIX and OSX are incompatible with
 | 
			
		||||
 *   previous compilers.
 | 
			
		||||
 */
 | 
			
		||||
#if (defined(XP_UNIX) && defined(__GNUC__) && (__GNUC__ >= 3))
 | 
			
		||||
#define _NP_ABI_MIXIN_FOR_GCC3 NP_ABI_GCC3_MASK
 | 
			
		||||
#else
 | 
			
		||||
#define _NP_ABI_MIXIN_FOR_GCC3 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
#define NP_ABI_MACHO_MASK 0x01000000
 | 
			
		||||
#define _NP_ABI_MIXIN_FOR_MACHO NP_ABI_MACHO_MASK
 | 
			
		||||
#else
 | 
			
		||||
#define _NP_ABI_MIXIN_FOR_MACHO 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define NP_ABI_MASK (_NP_ABI_MIXIN_FOR_GCC3 | _NP_ABI_MIXIN_FOR_MACHO)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * List of variable names for which NPP_GetValue shall be implemented
 | 
			
		||||
 */
 | 
			
		||||
typedef enum {
 | 
			
		||||
  NPPVpluginNameString = 1,
 | 
			
		||||
  NPPVpluginDescriptionString,
 | 
			
		||||
  NPPVpluginWindowBool,
 | 
			
		||||
  NPPVpluginTransparentBool,
 | 
			
		||||
  NPPVjavaClass,
 | 
			
		||||
  NPPVpluginWindowSize,
 | 
			
		||||
  NPPVpluginTimerInterval,
 | 
			
		||||
  NPPVpluginScriptableInstance = (10 | NP_ABI_MASK),
 | 
			
		||||
  NPPVpluginScriptableIID = 11,
 | 
			
		||||
  NPPVjavascriptPushCallerBool = 12,
 | 
			
		||||
  NPPVpluginKeepLibraryInMemory = 13,
 | 
			
		||||
  NPPVpluginNeedsXEmbed         = 14,
 | 
			
		||||
 | 
			
		||||
  /* Get the NPObject for scripting the plugin. Introduced in NPAPI minor version 14.
 | 
			
		||||
   */
 | 
			
		||||
  NPPVpluginScriptableNPObject  = 15,
 | 
			
		||||
 | 
			
		||||
  /* Get the plugin value (as \0-terminated UTF-8 string data) for
 | 
			
		||||
   * form submission if the plugin is part of a form. Use
 | 
			
		||||
   * NPN_MemAlloc() to allocate memory for the string data. Introduced
 | 
			
		||||
   * in NPAPI minor version 15.
 | 
			
		||||
   */
 | 
			
		||||
  NPPVformValue = 16,
 | 
			
		||||
 | 
			
		||||
  NPPVpluginUrlRequestsDisplayedBool = 17,
 | 
			
		||||
 | 
			
		||||
  /* Checks if the plugin is interested in receiving the http body of
 | 
			
		||||
   * all http requests (including failed ones, http status != 200).
 | 
			
		||||
   */
 | 
			
		||||
  NPPVpluginWantsAllNetworkStreams = 18,
 | 
			
		||||
 | 
			
		||||
  /* Browsers can retrieve a native ATK accessibility plug ID via this variable. */
 | 
			
		||||
  NPPVpluginNativeAccessibleAtkPlugId = 19,
 | 
			
		||||
 | 
			
		||||
  /* Checks to see if the plug-in would like the browser to load the "src" attribute. */
 | 
			
		||||
  NPPVpluginCancelSrcStream = 20,
 | 
			
		||||
 | 
			
		||||
  NPPVsupportsAdvancedKeyHandling = 21,
 | 
			
		||||
 | 
			
		||||
  NPPVpluginUsesDOMForCursorBool = 22
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
  /* Used for negotiating drawing models */
 | 
			
		||||
  , NPPVpluginDrawingModel = 1000
 | 
			
		||||
  /* Used for negotiating event models */
 | 
			
		||||
  , NPPVpluginEventModel = 1001
 | 
			
		||||
  /* In the NPDrawingModelCoreAnimation drawing model, the browser asks the plug-in for a Core Animation layer. */
 | 
			
		||||
  , NPPVpluginCoreAnimationLayer = 1003
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
 | 
			
		||||
  , NPPVpluginWindowlessLocalBool = 2002
 | 
			
		||||
#endif
 | 
			
		||||
} NPPVariable;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * List of variable names for which NPN_GetValue should be implemented.
 | 
			
		||||
 */
 | 
			
		||||
typedef enum {
 | 
			
		||||
  NPNVxDisplay = 1,
 | 
			
		||||
  NPNVxtAppContext,
 | 
			
		||||
  NPNVnetscapeWindow,
 | 
			
		||||
  NPNVjavascriptEnabledBool,
 | 
			
		||||
  NPNVasdEnabledBool,
 | 
			
		||||
  NPNVisOfflineBool,
 | 
			
		||||
 | 
			
		||||
  NPNVserviceManager = (10 | NP_ABI_MASK),
 | 
			
		||||
  NPNVDOMElement     = (11 | NP_ABI_MASK),
 | 
			
		||||
  NPNVDOMWindow      = (12 | NP_ABI_MASK),
 | 
			
		||||
  NPNVToolkit        = (13 | NP_ABI_MASK),
 | 
			
		||||
  NPNVSupportsXEmbedBool = 14,
 | 
			
		||||
 | 
			
		||||
  /* Get the NPObject wrapper for the browser window. */
 | 
			
		||||
  NPNVWindowNPObject = 15,
 | 
			
		||||
 | 
			
		||||
  /* Get the NPObject wrapper for the plugins DOM element. */
 | 
			
		||||
  NPNVPluginElementNPObject = 16,
 | 
			
		||||
 | 
			
		||||
  NPNVSupportsWindowless = 17,
 | 
			
		||||
 | 
			
		||||
  NPNVprivateModeBool = 18,
 | 
			
		||||
 | 
			
		||||
  NPNVsupportsAdvancedKeyHandling = 21
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
  /* Used for negotiating drawing models */
 | 
			
		||||
  , NPNVpluginDrawingModel = 1000
 | 
			
		||||
#ifndef NP_NO_QUICKDRAW
 | 
			
		||||
  , NPNVsupportsQuickDrawBool = 2000
 | 
			
		||||
#endif
 | 
			
		||||
  , NPNVsupportsCoreGraphicsBool = 2001
 | 
			
		||||
  , NPNVsupportsOpenGLBool = 2002
 | 
			
		||||
  , NPNVsupportsCoreAnimationBool = 2003
 | 
			
		||||
  , NPNVsupportsInvalidatingCoreAnimationBool = 2004
 | 
			
		||||
#ifndef NP_NO_CARBON
 | 
			
		||||
  , NPNVsupportsCarbonBool = 3000 /* TRUE if the browser supports the Carbon event model */
 | 
			
		||||
#endif
 | 
			
		||||
  , NPNVsupportsCocoaBool = 3001 /* TRUE if the browser supports the Cocoa event model */
 | 
			
		||||
  , NPNVsupportsUpdatedCocoaTextInputBool = 3002 /* TRUE if the browser supports the updated
 | 
			
		||||
                                                    Cocoa text input specification. */
 | 
			
		||||
  , NPNVsupportsCompositingCoreAnimationPluginsBool = 74656 /* TRUE if the browser supports
 | 
			
		||||
                                                               CA model compositing */
 | 
			
		||||
#endif
 | 
			
		||||
#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
 | 
			
		||||
  , NPNVSupportsWindowlessLocal = 2002
 | 
			
		||||
#endif
 | 
			
		||||
} NPNVariable;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
  NPNURLVCookie = 501,
 | 
			
		||||
  NPNURLVProxy
 | 
			
		||||
} NPNURLVariable;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The type of Toolkit the widgets use
 | 
			
		||||
 */
 | 
			
		||||
typedef enum {
 | 
			
		||||
  NPNVGtk12 = 1,
 | 
			
		||||
  NPNVGtk2
 | 
			
		||||
} NPNToolkitType;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The type of a NPWindow - it specifies the type of the data structure
 | 
			
		||||
 * returned in the window field.
 | 
			
		||||
 */
 | 
			
		||||
typedef enum {
 | 
			
		||||
  NPWindowTypeWindow = 1,
 | 
			
		||||
  NPWindowTypeDrawable
 | 
			
		||||
} NPWindowType;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPWindow
 | 
			
		||||
{
 | 
			
		||||
  void* window;  /* Platform specific window handle */
 | 
			
		||||
                 /* OS/2: x - Position of bottom left corner */
 | 
			
		||||
                 /* OS/2: y - relative to visible netscape window */
 | 
			
		||||
  int32_t  x;      /* Position of top left corner relative */
 | 
			
		||||
  int32_t  y;      /* to a netscape page. */
 | 
			
		||||
  uint32_t width;  /* Maximum window size */
 | 
			
		||||
  uint32_t height;
 | 
			
		||||
  NPRect   clipRect; /* Clipping rectangle in port coordinates */
 | 
			
		||||
#if (defined(XP_UNIX) || defined(XP_SYMBIAN)) && !defined(XP_MACOSX)
 | 
			
		||||
  void * ws_info; /* Platform-dependent additional data */
 | 
			
		||||
#endif /* XP_UNIX */
 | 
			
		||||
  NPWindowType type; /* Is this a window or a drawable? */
 | 
			
		||||
} NPWindow;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPImageExpose
 | 
			
		||||
{
 | 
			
		||||
  char*    data;       /* image pointer */
 | 
			
		||||
  int32_t  stride;     /* Stride of data image pointer */
 | 
			
		||||
  int32_t  depth;      /* Depth of image pointer */
 | 
			
		||||
  int32_t  x;          /* Expose x */
 | 
			
		||||
  int32_t  y;          /* Expose y */
 | 
			
		||||
  uint32_t width;      /* Expose width */
 | 
			
		||||
  uint32_t height;     /* Expose height */
 | 
			
		||||
  NPSize   dataSize;   /* Data buffer size */
 | 
			
		||||
  float    translateX; /* translate X matrix value */
 | 
			
		||||
  float    translateY; /* translate Y matrix value */
 | 
			
		||||
  float    scaleX;     /* scale X matrix value */
 | 
			
		||||
  float    scaleY;     /* scale Y matrix value */
 | 
			
		||||
} NPImageExpose;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPFullPrint
 | 
			
		||||
{
 | 
			
		||||
  NPBool pluginPrinted;/* Set TRUE if plugin handled fullscreen printing */
 | 
			
		||||
  NPBool printOne;     /* TRUE if plugin should print one copy to default
 | 
			
		||||
                          printer */
 | 
			
		||||
  void* platformPrint; /* Platform-specific printing info */
 | 
			
		||||
} NPFullPrint;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPEmbedPrint
 | 
			
		||||
{
 | 
			
		||||
  NPWindow window;
 | 
			
		||||
  void* platformPrint; /* Platform-specific printing info */
 | 
			
		||||
} NPEmbedPrint;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPPrint
 | 
			
		||||
{
 | 
			
		||||
  uint16_t mode;               /* NP_FULL or NP_EMBED */
 | 
			
		||||
  union
 | 
			
		||||
  {
 | 
			
		||||
    NPFullPrint fullPrint;   /* if mode is NP_FULL */
 | 
			
		||||
    NPEmbedPrint embedPrint; /* if mode is NP_EMBED */
 | 
			
		||||
  } print;
 | 
			
		||||
} NPPrint;
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
#ifndef NP_NO_CARBON
 | 
			
		||||
typedef EventRecord NPEvent;
 | 
			
		||||
#endif
 | 
			
		||||
#elif defined(XP_SYMBIAN)
 | 
			
		||||
typedef QEvent NPEvent;
 | 
			
		||||
#elif defined(XP_WIN)
 | 
			
		||||
typedef struct _NPEvent
 | 
			
		||||
{
 | 
			
		||||
  uint16_t event;
 | 
			
		||||
  uintptr_t wParam;
 | 
			
		||||
  uintptr_t lParam;
 | 
			
		||||
} NPEvent;
 | 
			
		||||
#elif defined(XP_OS2)
 | 
			
		||||
typedef struct _NPEvent
 | 
			
		||||
{
 | 
			
		||||
  uint32_t event;
 | 
			
		||||
  uint32_t wParam;
 | 
			
		||||
  uint32_t lParam;
 | 
			
		||||
} NPEvent;
 | 
			
		||||
#elif defined(XP_UNIX) && defined(MOZ_X11)
 | 
			
		||||
typedef XEvent NPEvent;
 | 
			
		||||
#else
 | 
			
		||||
typedef void*  NPEvent;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
typedef void* NPRegion;
 | 
			
		||||
#ifndef NP_NO_QUICKDRAW
 | 
			
		||||
typedef RgnHandle NPQDRegion;
 | 
			
		||||
#endif
 | 
			
		||||
typedef CGPathRef NPCGRegion;
 | 
			
		||||
#elif defined(XP_WIN)
 | 
			
		||||
typedef HRGN NPRegion;
 | 
			
		||||
#elif defined(XP_UNIX) && defined(MOZ_X11)
 | 
			
		||||
typedef Region NPRegion;
 | 
			
		||||
#elif defined(XP_SYMBIAN)
 | 
			
		||||
typedef QRegion* NPRegion;
 | 
			
		||||
#else
 | 
			
		||||
typedef void *NPRegion;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct _NPNSString NPNSString;
 | 
			
		||||
typedef struct _NPNSWindow NPNSWindow;
 | 
			
		||||
typedef struct _NPNSMenu   NPNSMenu;
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
typedef NPNSMenu NPMenu;
 | 
			
		||||
#else
 | 
			
		||||
typedef void *NPMenu;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
  NPCoordinateSpacePlugin = 1,
 | 
			
		||||
  NPCoordinateSpaceWindow,
 | 
			
		||||
  NPCoordinateSpaceFlippedWindow,
 | 
			
		||||
  NPCoordinateSpaceScreen,
 | 
			
		||||
  NPCoordinateSpaceFlippedScreen
 | 
			
		||||
} NPCoordinateSpace;
 | 
			
		||||
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
 | 
			
		||||
#ifndef NP_NO_QUICKDRAW
 | 
			
		||||
typedef struct NP_Port
 | 
			
		||||
{
 | 
			
		||||
  CGrafPtr port;
 | 
			
		||||
  int32_t portx; /* position inside the topmost window */
 | 
			
		||||
  int32_t porty;
 | 
			
		||||
} NP_Port;
 | 
			
		||||
#endif /* NP_NO_QUICKDRAW */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * NP_CGContext is the type of the NPWindow's 'window' when the plugin specifies NPDrawingModelCoreGraphics
 | 
			
		||||
 * as its drawing model.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
typedef struct NP_CGContext
 | 
			
		||||
{
 | 
			
		||||
  CGContextRef context;
 | 
			
		||||
  void *window; /* A WindowRef under the Carbon event model. */
 | 
			
		||||
} NP_CGContext;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * NP_GLContext is the type of the NPWindow's 'window' when the plugin specifies NPDrawingModelOpenGL as its
 | 
			
		||||
 * drawing model.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
typedef struct NP_GLContext
 | 
			
		||||
{
 | 
			
		||||
  CGLContextObj context;
 | 
			
		||||
#ifdef NP_NO_CARBON
 | 
			
		||||
  NPNSWindow *window;
 | 
			
		||||
#else
 | 
			
		||||
  void *window; /* Can be either an NSWindow or a WindowRef depending on the event model */
 | 
			
		||||
#endif
 | 
			
		||||
} NP_GLContext;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
  NPCocoaEventDrawRect = 1,
 | 
			
		||||
  NPCocoaEventMouseDown,
 | 
			
		||||
  NPCocoaEventMouseUp,
 | 
			
		||||
  NPCocoaEventMouseMoved,
 | 
			
		||||
  NPCocoaEventMouseEntered,
 | 
			
		||||
  NPCocoaEventMouseExited,
 | 
			
		||||
  NPCocoaEventMouseDragged,
 | 
			
		||||
  NPCocoaEventKeyDown,
 | 
			
		||||
  NPCocoaEventKeyUp,
 | 
			
		||||
  NPCocoaEventFlagsChanged,
 | 
			
		||||
  NPCocoaEventFocusChanged,
 | 
			
		||||
  NPCocoaEventWindowFocusChanged,
 | 
			
		||||
  NPCocoaEventScrollWheel,
 | 
			
		||||
  NPCocoaEventTextInput
 | 
			
		||||
} NPCocoaEventType;
 | 
			
		||||
 | 
			
		||||
typedef struct _NPCocoaEvent {
 | 
			
		||||
  NPCocoaEventType type;
 | 
			
		||||
  uint32_t version;
 | 
			
		||||
  union {
 | 
			
		||||
    struct {
 | 
			
		||||
      uint32_t modifierFlags;
 | 
			
		||||
      double   pluginX;
 | 
			
		||||
      double   pluginY;
 | 
			
		||||
      int32_t  buttonNumber;
 | 
			
		||||
      int32_t  clickCount;
 | 
			
		||||
      double   deltaX;
 | 
			
		||||
      double   deltaY;
 | 
			
		||||
      double   deltaZ;
 | 
			
		||||
    } mouse;
 | 
			
		||||
    struct {
 | 
			
		||||
      uint32_t    modifierFlags;
 | 
			
		||||
      NPNSString *characters;
 | 
			
		||||
      NPNSString *charactersIgnoringModifiers;
 | 
			
		||||
      NPBool      isARepeat;
 | 
			
		||||
      uint16_t    keyCode;
 | 
			
		||||
    } key;
 | 
			
		||||
    struct {
 | 
			
		||||
      CGContextRef context;
 | 
			
		||||
      double x;
 | 
			
		||||
      double y;
 | 
			
		||||
      double width;
 | 
			
		||||
      double height;
 | 
			
		||||
    } draw;
 | 
			
		||||
    struct {
 | 
			
		||||
      NPBool hasFocus;
 | 
			
		||||
    } focus;
 | 
			
		||||
    struct {
 | 
			
		||||
      NPNSString *text;
 | 
			
		||||
    } text;
 | 
			
		||||
  } data;
 | 
			
		||||
} NPCocoaEvent;
 | 
			
		||||
 | 
			
		||||
#ifndef NP_NO_CARBON
 | 
			
		||||
/* Non-standard event types that can be passed to HandleEvent */
 | 
			
		||||
enum NPEventType {
 | 
			
		||||
  NPEventType_GetFocusEvent = (osEvt + 16),
 | 
			
		||||
  NPEventType_LoseFocusEvent,
 | 
			
		||||
  NPEventType_AdjustCursorEvent,
 | 
			
		||||
  NPEventType_MenuCommandEvent,
 | 
			
		||||
  NPEventType_ClippingChangedEvent,
 | 
			
		||||
  NPEventType_ScrollingBeginsEvent = 1000,
 | 
			
		||||
  NPEventType_ScrollingEndsEvent
 | 
			
		||||
};
 | 
			
		||||
#endif /* NP_NO_CARBON */
 | 
			
		||||
 | 
			
		||||
#endif /* XP_MACOSX */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Values for mode passed to NPP_New:
 | 
			
		||||
 */
 | 
			
		||||
#define NP_EMBED 1
 | 
			
		||||
#define NP_FULL  2
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Values for stream type passed to NPP_NewStream:
 | 
			
		||||
 */
 | 
			
		||||
#define NP_NORMAL     1
 | 
			
		||||
#define NP_SEEK       2
 | 
			
		||||
#define NP_ASFILE     3
 | 
			
		||||
#define NP_ASFILEONLY 4
 | 
			
		||||
 | 
			
		||||
#define NP_MAXREADY (((unsigned)(~0)<<1)>>1)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Flags for NPP_ClearSiteData.
 | 
			
		||||
 */
 | 
			
		||||
#define NP_CLEAR_ALL   0
 | 
			
		||||
#define NP_CLEAR_CACHE (1 << 0)
 | 
			
		||||
 | 
			
		||||
#if !defined(__LP64__)
 | 
			
		||||
#if defined(XP_MACOSX)
 | 
			
		||||
#pragma options align=reset
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* __LP64__ */
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
/*       Error and Reason Code definitions                              */
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Values of type NPError:
 | 
			
		||||
 */
 | 
			
		||||
#define NPERR_BASE                         0
 | 
			
		||||
#define NPERR_NO_ERROR                    (NPERR_BASE + 0)
 | 
			
		||||
#define NPERR_GENERIC_ERROR               (NPERR_BASE + 1)
 | 
			
		||||
#define NPERR_INVALID_INSTANCE_ERROR      (NPERR_BASE + 2)
 | 
			
		||||
#define NPERR_INVALID_FUNCTABLE_ERROR     (NPERR_BASE + 3)
 | 
			
		||||
#define NPERR_MODULE_LOAD_FAILED_ERROR    (NPERR_BASE + 4)
 | 
			
		||||
#define NPERR_OUT_OF_MEMORY_ERROR         (NPERR_BASE + 5)
 | 
			
		||||
#define NPERR_INVALID_PLUGIN_ERROR        (NPERR_BASE + 6)
 | 
			
		||||
#define NPERR_INVALID_PLUGIN_DIR_ERROR    (NPERR_BASE + 7)
 | 
			
		||||
#define NPERR_INCOMPATIBLE_VERSION_ERROR  (NPERR_BASE + 8)
 | 
			
		||||
#define NPERR_INVALID_PARAM               (NPERR_BASE + 9)
 | 
			
		||||
#define NPERR_INVALID_URL                 (NPERR_BASE + 10)
 | 
			
		||||
#define NPERR_FILE_NOT_FOUND              (NPERR_BASE + 11)
 | 
			
		||||
#define NPERR_NO_DATA                     (NPERR_BASE + 12)
 | 
			
		||||
#define NPERR_STREAM_NOT_SEEKABLE         (NPERR_BASE + 13)
 | 
			
		||||
#define NPERR_TIME_RANGE_NOT_SUPPORTED    (NPERR_BASE + 14)
 | 
			
		||||
#define NPERR_MALFORMED_SITE              (NPERR_BASE + 15)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Values of type NPReason:
 | 
			
		||||
 */
 | 
			
		||||
#define NPRES_BASE          0
 | 
			
		||||
#define NPRES_DONE         (NPRES_BASE + 0)
 | 
			
		||||
#define NPRES_NETWORK_ERR  (NPRES_BASE + 1)
 | 
			
		||||
#define NPRES_USER_BREAK   (NPRES_BASE + 2)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Don't use these obsolete error codes any more.
 | 
			
		||||
 */
 | 
			
		||||
#define NP_NOERR  NP_NOERR_is_obsolete_use_NPERR_NO_ERROR
 | 
			
		||||
#define NP_EINVAL NP_EINVAL_is_obsolete_use_NPERR_GENERIC_ERROR
 | 
			
		||||
#define NP_EABORT NP_EABORT_is_obsolete_use_NPRES_USER_BREAK
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Version feature information
 | 
			
		||||
 */
 | 
			
		||||
#define NPVERS_HAS_STREAMOUTPUT             8
 | 
			
		||||
#define NPVERS_HAS_NOTIFICATION             9
 | 
			
		||||
#define NPVERS_HAS_LIVECONNECT              9
 | 
			
		||||
#define NPVERS_68K_HAS_LIVECONNECT          11
 | 
			
		||||
#define NPVERS_HAS_WINDOWLESS               11
 | 
			
		||||
#define NPVERS_HAS_XPCONNECT_SCRIPTING      13
 | 
			
		||||
#define NPVERS_HAS_NPRUNTIME_SCRIPTING      14
 | 
			
		||||
#define NPVERS_HAS_FORM_VALUES              15
 | 
			
		||||
#define NPVERS_HAS_POPUPS_ENABLED_STATE     16
 | 
			
		||||
#define NPVERS_HAS_RESPONSE_HEADERS         17
 | 
			
		||||
#define NPVERS_HAS_NPOBJECT_ENUM            18
 | 
			
		||||
#define NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL 19
 | 
			
		||||
#define NPVERS_HAS_ALL_NETWORK_STREAMS      20
 | 
			
		||||
#define NPVERS_HAS_URL_AND_AUTH_INFO        21
 | 
			
		||||
#define NPVERS_HAS_PRIVATE_MODE             22
 | 
			
		||||
#define NPVERS_MACOSX_HAS_COCOA_EVENTS      23
 | 
			
		||||
#define NPVERS_HAS_ADVANCED_KEY_HANDLING    25
 | 
			
		||||
#define NPVERS_HAS_URL_REDIRECT_HANDLING    26
 | 
			
		||||
#define NPVERS_HAS_CLEAR_SITE_DATA          27
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
/*                        Function Prototypes                           */
 | 
			
		||||
/*----------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
#if defined(__OS2__)
 | 
			
		||||
#define NP_LOADDS _System
 | 
			
		||||
#else
 | 
			
		||||
#define NP_LOADDS
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* NPP_* functions are provided by the plugin and called by the navigator. */
 | 
			
		||||
 | 
			
		||||
#if defined(XP_UNIX)
 | 
			
		||||
const char* NPP_GetMIMEDescription(void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
NPError NP_LOADDS NPP_New(NPMIMEType pluginType, NPP instance,
 | 
			
		||||
                          uint16_t mode, int16_t argc, char* argn[],
 | 
			
		||||
                          char* argv[], NPSavedData* saved);
 | 
			
		||||
NPError NP_LOADDS NPP_Destroy(NPP instance, NPSavedData** save);
 | 
			
		||||
NPError NP_LOADDS NPP_SetWindow(NPP instance, NPWindow* window);
 | 
			
		||||
NPError NP_LOADDS NPP_NewStream(NPP instance, NPMIMEType type,
 | 
			
		||||
                                NPStream* stream, NPBool seekable,
 | 
			
		||||
                                uint16_t* stype);
 | 
			
		||||
NPError NP_LOADDS NPP_DestroyStream(NPP instance, NPStream* stream,
 | 
			
		||||
                                    NPReason reason);
 | 
			
		||||
int32_t NP_LOADDS NPP_WriteReady(NPP instance, NPStream* stream);
 | 
			
		||||
int32_t NP_LOADDS NPP_Write(NPP instance, NPStream* stream, int32_t offset,
 | 
			
		||||
                            int32_t len, void* buffer);
 | 
			
		||||
void    NP_LOADDS NPP_StreamAsFile(NPP instance, NPStream* stream,
 | 
			
		||||
                                   const char* fname);
 | 
			
		||||
void    NP_LOADDS NPP_Print(NPP instance, NPPrint* platformPrint);
 | 
			
		||||
int16_t NP_LOADDS NPP_HandleEvent(NPP instance, void* event);
 | 
			
		||||
void    NP_LOADDS NPP_URLNotify(NPP instance, const char* url,
 | 
			
		||||
                                NPReason reason, void* notifyData);
 | 
			
		||||
NPError NP_LOADDS NPP_GetValue(NPP instance, NPPVariable variable, void *value);
 | 
			
		||||
NPError NP_LOADDS NPP_SetValue(NPP instance, NPNVariable variable, void *value);
 | 
			
		||||
NPBool  NP_LOADDS NPP_GotFocus(NPP instance, NPFocusDirection direction);
 | 
			
		||||
void    NP_LOADDS NPP_LostFocus(NPP instance);
 | 
			
		||||
void    NP_LOADDS NPP_URLRedirectNotify(NPP instance, const char* url, int32_t status, void* notifyData);
 | 
			
		||||
NPError NP_LOADDS NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge);
 | 
			
		||||
char**  NP_LOADDS NPP_GetSitesWithData(void);
 | 
			
		||||
 | 
			
		||||
/* NPN_* functions are provided by the navigator and called by the plugin. */
 | 
			
		||||
void        NP_LOADDS NPN_Version(int* plugin_major, int* plugin_minor,
 | 
			
		||||
                                  int* netscape_major, int* netscape_minor);
 | 
			
		||||
NPError     NP_LOADDS NPN_GetURLNotify(NPP instance, const char* url,
 | 
			
		||||
                                       const char* target, void* notifyData);
 | 
			
		||||
NPError     NP_LOADDS NPN_GetURL(NPP instance, const char* url,
 | 
			
		||||
                                 const char* target);
 | 
			
		||||
NPError     NP_LOADDS NPN_PostURLNotify(NPP instance, const char* url,
 | 
			
		||||
                                        const char* target, uint32_t len,
 | 
			
		||||
                                        const char* buf, NPBool file,
 | 
			
		||||
                                        void* notifyData);
 | 
			
		||||
NPError     NP_LOADDS NPN_PostURL(NPP instance, const char* url,
 | 
			
		||||
                                  const char* target, uint32_t len,
 | 
			
		||||
                                  const char* buf, NPBool file);
 | 
			
		||||
NPError     NP_LOADDS NPN_RequestRead(NPStream* stream, NPByteRange* rangeList);
 | 
			
		||||
NPError     NP_LOADDS NPN_NewStream(NPP instance, NPMIMEType type,
 | 
			
		||||
                                    const char* target, NPStream** stream);
 | 
			
		||||
int32_t     NP_LOADDS NPN_Write(NPP instance, NPStream* stream, int32_t len,
 | 
			
		||||
                                void* buffer);
 | 
			
		||||
NPError     NP_LOADDS NPN_DestroyStream(NPP instance, NPStream* stream,
 | 
			
		||||
                                        NPReason reason);
 | 
			
		||||
void        NP_LOADDS NPN_Status(NPP instance, const char* message);
 | 
			
		||||
const char* NP_LOADDS NPN_UserAgent(NPP instance);
 | 
			
		||||
void*       NP_LOADDS NPN_MemAlloc(uint32_t size);
 | 
			
		||||
void        NP_LOADDS NPN_MemFree(void* ptr);
 | 
			
		||||
uint32_t    NP_LOADDS NPN_MemFlush(uint32_t size);
 | 
			
		||||
void        NP_LOADDS NPN_ReloadPlugins(NPBool reloadPages);
 | 
			
		||||
NPError     NP_LOADDS NPN_GetValue(NPP instance, NPNVariable variable,
 | 
			
		||||
                                   void *value);
 | 
			
		||||
NPError     NP_LOADDS NPN_SetValue(NPP instance, NPPVariable variable,
 | 
			
		||||
                                   void *value);
 | 
			
		||||
void        NP_LOADDS NPN_InvalidateRect(NPP instance, NPRect *invalidRect);
 | 
			
		||||
void        NP_LOADDS NPN_InvalidateRegion(NPP instance,
 | 
			
		||||
                                           NPRegion invalidRegion);
 | 
			
		||||
void        NP_LOADDS NPN_ForceRedraw(NPP instance);
 | 
			
		||||
void        NP_LOADDS NPN_PushPopupsEnabledState(NPP instance, NPBool enabled);
 | 
			
		||||
void        NP_LOADDS NPN_PopPopupsEnabledState(NPP instance);
 | 
			
		||||
void        NP_LOADDS NPN_PluginThreadAsyncCall(NPP instance,
 | 
			
		||||
                                                void (*func) (void *),
 | 
			
		||||
                                                void *userData);
 | 
			
		||||
NPError     NP_LOADDS NPN_GetValueForURL(NPP instance, NPNURLVariable variable,
 | 
			
		||||
                                         const char *url, char **value,
 | 
			
		||||
                                         uint32_t *len);
 | 
			
		||||
NPError     NP_LOADDS NPN_SetValueForURL(NPP instance, NPNURLVariable variable,
 | 
			
		||||
                                         const char *url, const char *value,
 | 
			
		||||
                                         uint32_t len);
 | 
			
		||||
NPError     NP_LOADDS NPN_GetAuthenticationInfo(NPP instance,
 | 
			
		||||
                                                const char *protocol,
 | 
			
		||||
                                                const char *host, int32_t port,
 | 
			
		||||
                                                const char *scheme,
 | 
			
		||||
                                                const char *realm,
 | 
			
		||||
                                                char **username, uint32_t *ulen,
 | 
			
		||||
                                                char **password,
 | 
			
		||||
                                                uint32_t *plen);
 | 
			
		||||
uint32_t    NP_LOADDS NPN_ScheduleTimer(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID));
 | 
			
		||||
void        NP_LOADDS NPN_UnscheduleTimer(NPP instance, uint32_t timerID);
 | 
			
		||||
NPError     NP_LOADDS NPN_PopUpContextMenu(NPP instance, NPMenu* menu);
 | 
			
		||||
NPBool      NP_LOADDS NPN_ConvertPoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
 | 
			
		||||
NPBool      NP_LOADDS NPN_HandleEvent(NPP instance, void *event, NPBool handled);
 | 
			
		||||
NPBool      NP_LOADDS NPN_UnfocusInstance(NPP instance, NPFocusDirection direction);
 | 
			
		||||
void        NP_LOADDS NPN_URLRedirectResponse(NPP instance, void* notifyData, NPBool allow);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}  /* end extern "C" */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* RC_INVOKED */
 | 
			
		||||
#if defined(__OS2__)
 | 
			
		||||
#pragma pack()
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* npapi_h_ */
 | 
			
		||||
							
								
								
									
										322
									
								
								browser-plugin/npapi/npfunctions.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -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_ */
 | 
			
		||||
							
								
								
									
										112
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						@@ -1,5 +1,5 @@
 | 
			
		||||
AC_PREREQ(2.63)
 | 
			
		||||
AC_INIT([gnome-shell],[3.1.90],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
 | 
			
		||||
AC_INIT([gnome-shell],[3.5.4],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
 | 
			
		||||
 | 
			
		||||
AC_CONFIG_HEADERS([config.h])
 | 
			
		||||
AC_CONFIG_SRCDIR([src/shell-global.c])
 | 
			
		||||
@@ -9,8 +9,8 @@ AC_CONFIG_AUX_DIR([config])
 | 
			
		||||
AC_SUBST([PACKAGE_NAME], ["$PACKAGE_NAME"])
 | 
			
		||||
AC_SUBST([PACKAGE_VERSION], ["$PACKAGE_VERSION"])
 | 
			
		||||
 | 
			
		||||
AM_INIT_AUTOMAKE([1.10 dist-bzip2 no-dist-gzip foreign])
 | 
			
		||||
AM_MAINTAINER_MODE
 | 
			
		||||
AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar foreign])
 | 
			
		||||
AM_MAINTAINER_MODE([enable])
 | 
			
		||||
 | 
			
		||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
 | 
			
		||||
 | 
			
		||||
@@ -36,10 +36,6 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",
 | 
			
		||||
 | 
			
		||||
PKG_PROG_PKG_CONFIG([0.22])
 | 
			
		||||
 | 
			
		||||
# GConf stuff
 | 
			
		||||
AC_PATH_PROG(GCONFTOOL, gconftool-2, no)
 | 
			
		||||
AM_GCONF_SOURCE_2
 | 
			
		||||
 | 
			
		||||
GLIB_GSETTINGS
 | 
			
		||||
 | 
			
		||||
# Get a value to substitute into gnome-shell.in
 | 
			
		||||
@@ -48,46 +44,50 @@ AC_SUBST(PYTHON)
 | 
			
		||||
 | 
			
		||||
# We need at least this, since gst_plugin_register_static() was added
 | 
			
		||||
# in 0.10.16, but nothing older than 0.10.21 has been tested.
 | 
			
		||||
GSTREAMER_MIN_VERSION=0.10.16
 | 
			
		||||
GSTREAMER_MIN_VERSION=0.11.92
 | 
			
		||||
 | 
			
		||||
recorder_modules=
 | 
			
		||||
build_recorder=false
 | 
			
		||||
AC_MSG_CHECKING([for GStreamer (needed for recording functionality)])
 | 
			
		||||
if $PKG_CONFIG --exists gstreamer-0.10 '>=' $GSTREAMER_MIN_VERSION ; then
 | 
			
		||||
if $PKG_CONFIG --exists gstreamer-1.0 '>=' $GSTREAMER_MIN_VERSION ; then
 | 
			
		||||
   AC_MSG_RESULT(yes)
 | 
			
		||||
   build_recorder=true
 | 
			
		||||
   recorder_modules="gstreamer-0.10 gstreamer-base-0.10 x11"
 | 
			
		||||
   PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0 xfixes)
 | 
			
		||||
   recorder_modules="gstreamer-1.0 gstreamer-base-1.0 x11"
 | 
			
		||||
   PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0 xfixes gl)
 | 
			
		||||
else
 | 
			
		||||
   AC_MSG_RESULT(no)
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
 | 
			
		||||
 | 
			
		||||
CLUTTER_MIN_VERSION=1.7.5
 | 
			
		||||
CLUTTER_MIN_VERSION=1.9.16
 | 
			
		||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
 | 
			
		||||
GJS_MIN_VERSION=1.29.15
 | 
			
		||||
MUTTER_MIN_VERSION=3.0.0
 | 
			
		||||
FOLKS_MIN_VERSION=0.5.2
 | 
			
		||||
GTK_MIN_VERSION=3.0.0
 | 
			
		||||
GIO_MIN_VERSION=2.29.10
 | 
			
		||||
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
 | 
			
		||||
GJS_MIN_VERSION=1.33.2
 | 
			
		||||
MUTTER_MIN_VERSION=3.5.4
 | 
			
		||||
GTK_MIN_VERSION=3.3.9
 | 
			
		||||
GIO_MIN_VERSION=2.31.6
 | 
			
		||||
LIBECAL_MIN_VERSION=3.5.3
 | 
			
		||||
LIBEDATASERVER_MIN_VERSION=3.5.3
 | 
			
		||||
LIBEDATASERVERUI_MIN_VERSION=3.5.3
 | 
			
		||||
TELEPATHY_GLIB_MIN_VERSION=0.17.5
 | 
			
		||||
TELEPATHY_LOGGER_MIN_VERSION=0.2.4
 | 
			
		||||
POLKIT_MIN_VERSION=0.100
 | 
			
		||||
STARTUP_NOTIFICATION_MIN_VERSION=0.11
 | 
			
		||||
GCR_MIN_VERSION=3.3.90
 | 
			
		||||
GNOME_DESKTOP_REQUIRED_VERSION=3.5.1
 | 
			
		||||
GNOME_MENUS_REQUIRED_VERSION=3.5.3
 | 
			
		||||
 | 
			
		||||
# Collect more than 20 libraries for a prize!
 | 
			
		||||
PKG_CHECK_MODULES(GNOME_SHELL, gio-2.0 >= $GIO_MIN_VERSION
 | 
			
		||||
                               gio-unix-2.0 dbus-glib-1 libxml-2.0
 | 
			
		||||
PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
 | 
			
		||||
			       libxml-2.0
 | 
			
		||||
                               gtk+-3.0 >= $GTK_MIN_VERSION
 | 
			
		||||
                               folks >= $FOLKS_MIN_VERSION
 | 
			
		||||
                               atk-bridge-2.0
 | 
			
		||||
                               libmutter >= $MUTTER_MIN_VERSION
 | 
			
		||||
                               gjs-internals-1.0 >= $GJS_MIN_VERSION
 | 
			
		||||
			       libgnome-menu-3.0 $recorder_modules gconf-2.0
 | 
			
		||||
			       libgnome-menu-3.0 >= $GNOME_MENUS_REQUIRED_VERSION
 | 
			
		||||
                               $recorder_modules
 | 
			
		||||
                               gdk-x11-3.0 libsoup-2.4
 | 
			
		||||
                               gl
 | 
			
		||||
			       clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
 | 
			
		||||
			       clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
 | 
			
		||||
                               libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION
 | 
			
		||||
@@ -96,19 +96,17 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-2.0 >= $GIO_MIN_VERSION
 | 
			
		||||
                               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)
 | 
			
		||||
                               libnm-glib libnm-util gnome-keyring-1
 | 
			
		||||
                               gcr-3 >= $GCR_MIN_VERSION
 | 
			
		||||
                               gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION)
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(SHELL_HOTPLUG_SNIFFER, gio-2.0 gdk-pixbuf-2.0)
 | 
			
		||||
 | 
			
		||||
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"])
 | 
			
		||||
PKG_CHECK_MODULES(BROWSER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION json-glib-1.0 >= 0.13.2)
 | 
			
		||||
 | 
			
		||||
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
 | 
			
		||||
JHBUILD_TYPELIBDIR="$INTROSPECTION_TYPELIBDIR"
 | 
			
		||||
AC_SUBST(JHBUILD_TYPELIBDIR)
 | 
			
		||||
 | 
			
		||||
saved_CFLAGS=$CFLAGS
 | 
			
		||||
saved_LIBS=$LIBS
 | 
			
		||||
@@ -118,17 +116,18 @@ 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 >= 0.6.2 gnome-desktop-3.0 >= 2.90.0 x11)
 | 
			
		||||
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-3.0)
 | 
			
		||||
PKG_CHECK_MODULES(GNOME_SHELL_JS, gio-2.0 gjs-internals-1.0 >= $GJS_MIN_VERSION)
 | 
			
		||||
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.2 x11)
 | 
			
		||||
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
 | 
			
		||||
PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
 | 
			
		||||
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 0.1.7)
 | 
			
		||||
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.5.4)
 | 
			
		||||
 | 
			
		||||
AC_MSG_CHECKING([for bluetooth support])
 | 
			
		||||
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])
 | 
			
		||||
@@ -141,6 +140,33 @@ PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedatas
 | 
			
		||||
AC_SUBST(CALENDAR_SERVER_CFLAGS)
 | 
			
		||||
AC_SUBST(CALENDAR_SERVER_LIBS)
 | 
			
		||||
 | 
			
		||||
AC_ARG_WITH(systemd,
 | 
			
		||||
            AS_HELP_STRING([--with-systemd],
 | 
			
		||||
                           [Add systemd support]),
 | 
			
		||||
            [with_systemd=$withval], [with_systemd=auto])
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(SYSTEMD,
 | 
			
		||||
                  [libsystemd-login libsystemd-daemon],
 | 
			
		||||
                  [have_systemd=yes], [have_systemd=no])
 | 
			
		||||
 | 
			
		||||
if test "x$with_systemd" = "xauto" ; then
 | 
			
		||||
        if test x$have_systemd = xno ; then
 | 
			
		||||
                use_systemd=no
 | 
			
		||||
        else
 | 
			
		||||
                use_systemd=yes
 | 
			
		||||
        fi
 | 
			
		||||
else
 | 
			
		||||
        use_systemd=$with_systemd
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test "x$use_systemd" = "xyes"; then
 | 
			
		||||
        if test "x$have_systemd" = "xno"; then
 | 
			
		||||
                AC_MSG_ERROR([Systemd support explicitly required, but systemd not found])
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        AC_DEFINE(WITH_SYSTEMD, 1, [systemd support])
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
MUTTER_GIR_DIR=`$PKG_CONFIG --variable=girdir libmutter`
 | 
			
		||||
MUTTER_TYPELIB_DIR=`$PKG_CONFIG --variable=typelibdir libmutter`
 | 
			
		||||
AC_SUBST(MUTTER_GIR_DIR)
 | 
			
		||||
@@ -177,6 +203,8 @@ 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,
 | 
			
		||||
@@ -197,7 +225,7 @@ if test "$enable_compile_warnings" != no ; then
 | 
			
		||||
    if test "$enable_compile_warnings" = error ; then
 | 
			
		||||
      case " $CFLAGS " in
 | 
			
		||||
      *[\ \	]-Werror[\ \	]*) ;;
 | 
			
		||||
      *) CFLAGS="$CFLAGS -Werror" ;;
 | 
			
		||||
      *) CFLAGS="$CFLAGS -Werror -Wno-error=deprecated-declarations" ;;
 | 
			
		||||
      esac
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
@@ -205,15 +233,25 @@ fi
 | 
			
		||||
changequote([,])dnl
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
  AS_HELP_STRING([--enable-jhbuild-wrapper-script],[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)
 | 
			
		||||
 | 
			
		||||
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/calendar-server/evolution-calendar.desktop.in
 | 
			
		||||
  src/Makefile
 | 
			
		||||
  browser-plugin/Makefile
 | 
			
		||||
  tests/Makefile
 | 
			
		||||
  po/Makefile.in
 | 
			
		||||
  man/Makefile
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
desktopdir=$(datadir)/applications
 | 
			
		||||
desktop_DATA = gnome-shell.desktop
 | 
			
		||||
desktop_DATA = gnome-shell.desktop gnome-shell-extension-prefs.desktop
 | 
			
		||||
 | 
			
		||||
# We substitute in bindir so it works as an autostart
 | 
			
		||||
# file when built in a non-system prefix
 | 
			
		||||
@@ -8,20 +8,25 @@ desktop_DATA = gnome-shell.desktop
 | 
			
		||||
	    -e "s|@VERSION[@]|$(VERSION)|" \
 | 
			
		||||
	    $< > $@ || rm $@
 | 
			
		||||
 | 
			
		||||
# Placeholder until we add intltool
 | 
			
		||||
%.desktop:%.desktop.in
 | 
			
		||||
	$(AM_V_GEN) sed s/^_// < $< > $@ || rm $@
 | 
			
		||||
@INTLTOOL_DESKTOP_RULE@
 | 
			
		||||
 | 
			
		||||
searchprovidersdir = $(pkgdatadir)/search_providers
 | 
			
		||||
searchprovidersdir = $(pkgdatadir)/open-search-providers
 | 
			
		||||
dist_searchproviders_DATA =				\
 | 
			
		||||
	search_providers/google.xml				\
 | 
			
		||||
	search_providers/wikipedia.xml
 | 
			
		||||
	open-search-providers/google.xml		\
 | 
			
		||||
	open-search-providers/wikipedia.xml
 | 
			
		||||
 | 
			
		||||
introspectiondir = $(datadir)/dbus-1/interfaces
 | 
			
		||||
introspection_DATA = org.gnome.ShellSearchProvider.xml
 | 
			
		||||
 | 
			
		||||
themedir = $(pkgdatadir)/theme
 | 
			
		||||
dist_theme_DATA =				\
 | 
			
		||||
	theme/calendar-arrow-left.svg		\
 | 
			
		||||
	theme/calendar-arrow-right.svg		\
 | 
			
		||||
	theme/calendar-today.svg		\
 | 
			
		||||
	theme/checkbox-focused.svg		\
 | 
			
		||||
	theme/checkbox-off-focused.svg		\
 | 
			
		||||
	theme/checkbox-off.svg			\
 | 
			
		||||
	theme/checkbox.svg			\
 | 
			
		||||
	theme/close-window.svg			\
 | 
			
		||||
	theme/close.svg				\
 | 
			
		||||
	theme/corner-ripple-ltr.png		\
 | 
			
		||||
@@ -29,16 +34,14 @@ dist_theme_DATA =				\
 | 
			
		||||
	theme/dash-placeholder.svg		\
 | 
			
		||||
	theme/filter-selected-ltr.svg		\
 | 
			
		||||
	theme/filter-selected-rtl.svg		\
 | 
			
		||||
	theme/gdm.css				\
 | 
			
		||||
	theme/gnome-shell.css			\
 | 
			
		||||
	theme/panel-border.svg			\
 | 
			
		||||
	theme/logged-in-indicator.svg		\
 | 
			
		||||
	theme/noise-texture.png			\
 | 
			
		||||
	theme/panel-button-border.svg		\
 | 
			
		||||
	theme/panel-button-highlight-narrow.svg	\
 | 
			
		||||
	theme/panel-button-highlight-wide.svg	\
 | 
			
		||||
	theme/process-working.svg		\
 | 
			
		||||
	theme/running-indicator.svg		\
 | 
			
		||||
	theme/scroll-hhandle.svg		\
 | 
			
		||||
	theme/scroll-vhandle.svg		\
 | 
			
		||||
	theme/source-button-border.svg		\
 | 
			
		||||
	theme/toggle-off-us.svg			\
 | 
			
		||||
	theme/toggle-off-intl.svg		\
 | 
			
		||||
@@ -50,6 +53,11 @@ dist_theme_DATA =				\
 | 
			
		||||
gsettings_SCHEMAS = org.gnome.shell.gschema.xml
 | 
			
		||||
 | 
			
		||||
@INTLTOOL_XML_NOMERGE_RULE@
 | 
			
		||||
 | 
			
		||||
%.gschema.xml.in: %.gschema.xml.in.in Makefile
 | 
			
		||||
	$(AM_V_GEN) sed -e 's|@GETTEXT_PACKAGE[@]|$(GETTEXT_PACKAGE)|g' \
 | 
			
		||||
	$< > $@ || rm $@
 | 
			
		||||
 | 
			
		||||
@GSETTINGS_RULES@
 | 
			
		||||
 | 
			
		||||
# We need to compile schemas at make time
 | 
			
		||||
@@ -59,30 +67,22 @@ gschemas.compiled: $(gsettings_SCHEMAS:.xml=.valid)
 | 
			
		||||
 | 
			
		||||
all-local: gschemas.compiled
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# GConf schemas: provide defaults for keys from Metacity we are overriding
 | 
			
		||||
gconfschemadir  = @GCONF_SCHEMA_FILE_DIR@
 | 
			
		||||
gconfschema_DATA = gnome-shell.schemas
 | 
			
		||||
 | 
			
		||||
shadersdir = $(pkgdatadir)/shaders
 | 
			
		||||
shaders_DATA = \
 | 
			
		||||
	shaders/dim-window.glsl
 | 
			
		||||
 | 
			
		||||
install-data-local:
 | 
			
		||||
	GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(srcdir)/$(gconfschema_DATA)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
convertdir = $(datadir)/GConf/gsettings
 | 
			
		||||
convert_DATA = gnome-shell-overrides.convert
 | 
			
		||||
 | 
			
		||||
EXTRA_DIST =						\
 | 
			
		||||
	gnome-shell.desktop.in.in			\
 | 
			
		||||
	gnome-shell-extension-prefs.desktop.in.in	\
 | 
			
		||||
	$(introspection_DATA)				\
 | 
			
		||||
	$(menu_DATA)					\
 | 
			
		||||
	$(gconfschema_DATA)				\
 | 
			
		||||
	$(shaders_DATA)					\
 | 
			
		||||
	org.gnome.shell.gschema.xml.in
 | 
			
		||||
	$(convert_DATA)					\
 | 
			
		||||
	org.gnome.shell.gschema.xml.in.in
 | 
			
		||||
 | 
			
		||||
CLEANFILES =						\
 | 
			
		||||
	gnome-shell.desktop.in				\
 | 
			
		||||
	gnome-shell-extension-prefs.in			\
 | 
			
		||||
	$(desktop_DATA)					\
 | 
			
		||||
	$(gsettings_SCHEMAS)				\
 | 
			
		||||
	gschemas.compiled
 | 
			
		||||
 | 
			
		||||
	gschemas.compiled				\
 | 
			
		||||
	org.gnome.shell.gschema.valid			\
 | 
			
		||||
	org.gnome.shell.gschema.xml.in
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								data/gnome-shell-extension-prefs.desktop.in.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,12 @@
 | 
			
		||||
[Desktop Entry]
 | 
			
		||||
Type=Application
 | 
			
		||||
_Name=GNOME Shell Extension Preferences
 | 
			
		||||
_Comment=Configure GNOME Shell Extensions
 | 
			
		||||
Exec=@bindir@/gnome-shell-extension-prefs %u
 | 
			
		||||
X-GNOME-Bugzilla-Bugzilla=GNOME
 | 
			
		||||
X-GNOME-Bugzilla-Product=gnome-shell
 | 
			
		||||
X-GNOME-Bugzilla-Component=extensions
 | 
			
		||||
X-GNOME-Bugzilla-Version=@VERSION@
 | 
			
		||||
Categories=GNOME;GTK;
 | 
			
		||||
OnlyShowIn=GNOME;
 | 
			
		||||
NoDisplay=true
 | 
			
		||||
							
								
								
									
										5
									
								
								data/gnome-shell-overrides.convert
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,5 @@
 | 
			
		||||
[org.gnome.shell.overrides]
 | 
			
		||||
attach-modal-dialogs = /desktop/gnome/shell/windows/attach_modal_dialogs
 | 
			
		||||
button-layout = /desktop/gnome/shell/windows/button_layout
 | 
			
		||||
edge-tiling = /desktop/gnome/shell/windows/edge_tiling
 | 
			
		||||
workspaces-only-on-primary = /desktop/gnome/shell/windows/workspaces_only_on_primary
 | 
			
		||||
@@ -13,4 +13,4 @@ NoDisplay=true
 | 
			
		||||
X-GNOME-Autostart-Phase=WindowManager
 | 
			
		||||
X-GNOME-Provides=panel;windowmanager;
 | 
			
		||||
X-GNOME-Autostart-Notify=true
 | 
			
		||||
X-GNOME-AutoRestart=true
 | 
			
		||||
X-GNOME-AutoRestart=false
 | 
			
		||||
 
 | 
			
		||||
@@ -1,100 +0,0 @@
 | 
			
		||||
<gconfschemafile>
 | 
			
		||||
    <schemalist>
 | 
			
		||||
 | 
			
		||||
      <!-- Metacity overrides -->
 | 
			
		||||
      <schema>
 | 
			
		||||
        <key>/schemas/desktop/gnome/shell/windows/attach_modal_dialogs</key>
 | 
			
		||||
        <applyto>/desktop/gnome/shell/windows/attach_modal_dialogs</applyto>
 | 
			
		||||
        <owner>gnome-shell</owner>
 | 
			
		||||
        <type>bool</type>
 | 
			
		||||
        <default>true</default>
 | 
			
		||||
        <locale name="C">
 | 
			
		||||
          <short>Attach modal dialog to the parent window</short>
 | 
			
		||||
          <long>
 | 
			
		||||
             This key overrides /apps/mutter/general/attach_modal_dialogs when
 | 
			
		||||
             running GNOME Shell.
 | 
			
		||||
          </long>
 | 
			
		||||
        </locale>
 | 
			
		||||
      </schema>
 | 
			
		||||
 | 
			
		||||
      <schema>
 | 
			
		||||
        <key>/schemas/desktop/gnome/shell/windows/button_layout</key>
 | 
			
		||||
        <applyto>/desktop/gnome/shell/windows/button_layout</applyto>
 | 
			
		||||
        <owner>gnome-shell</owner>
 | 
			
		||||
        <type>string</type>
 | 
			
		||||
        <default>:close</default>
 | 
			
		||||
        <locale name="C">
 | 
			
		||||
           <short>Arrangement of buttons on the titlebar</short>
 | 
			
		||||
           <long>
 | 
			
		||||
             Arrangement of buttons on the titlebar. The
 | 
			
		||||
             value should be a string, such as
 | 
			
		||||
             "menu:minimize,maximize,spacer,close"; the colon separates the
 | 
			
		||||
             left corner of the window from the right corner, and
 | 
			
		||||
             the button names are comma-separated. Duplicate buttons
 | 
			
		||||
             are not allowed. Unknown button names are silently ignored
 | 
			
		||||
             so that buttons can be added in future gnome-shell versions
 | 
			
		||||
             without breaking older versions.
 | 
			
		||||
             A special spacer tag can be used to insert some space between
 | 
			
		||||
             two adjacent buttons.
 | 
			
		||||
 | 
			
		||||
             This key overrides /apps/metacity/general/button_layout when
 | 
			
		||||
             running GNOME Shell.
 | 
			
		||||
           </long>
 | 
			
		||||
        </locale>
 | 
			
		||||
      </schema>
 | 
			
		||||
 | 
			
		||||
      <schema>
 | 
			
		||||
        <key>/schemas/desktop/gnome/shell/windows/edge_tiling</key>
 | 
			
		||||
        <applyto>/desktop/gnome/shell/windows/edge_tiling</applyto>
 | 
			
		||||
        <owner>gnome-shell</owner>
 | 
			
		||||
        <type>bool</type>
 | 
			
		||||
        <default>true</default>
 | 
			
		||||
        <locale name="C">
 | 
			
		||||
          <short>enable edge tiling when dropping windows on screen edges</short>
 | 
			
		||||
          <long>
 | 
			
		||||
             If enabled, dropping windows on vertical screen edges maximizes them
 | 
			
		||||
             vertically and resizes them horizontally to cover half of the
 | 
			
		||||
             available area. Dropping windows on the top screen edge maximizes them
 | 
			
		||||
             completely.
 | 
			
		||||
 | 
			
		||||
             This key overrides /apps/metacity/general/edge_tiling when
 | 
			
		||||
             running GNOME Shell.
 | 
			
		||||
          </long>
 | 
			
		||||
        </locale>
 | 
			
		||||
      </schema>
 | 
			
		||||
 | 
			
		||||
      <schema>
 | 
			
		||||
        <key>/schemas/desktop/gnome/shell/windows/theme</key>
 | 
			
		||||
        <applyto>/desktop/gnome/shell/windows/theme</applyto>
 | 
			
		||||
        <owner>gnome-shell</owner>
 | 
			
		||||
        <type>string</type>
 | 
			
		||||
        <default>Adwaita</default>
 | 
			
		||||
        <locale name="C">
 | 
			
		||||
          <short>Current theme</short>
 | 
			
		||||
          <long>
 | 
			
		||||
            The theme determines the appearance of window borders,
 | 
			
		||||
            titlebar, and so forth.
 | 
			
		||||
 | 
			
		||||
            This key overrides /apps/metacity/general/theme when
 | 
			
		||||
            running GNOME Shell.
 | 
			
		||||
          </long>
 | 
			
		||||
        </locale>
 | 
			
		||||
      </schema>
 | 
			
		||||
 | 
			
		||||
      <schema>
 | 
			
		||||
        <key>/schemas/desktop/gnome/shell/windows/workspaces_only_on_primary</key>
 | 
			
		||||
        <applyto>/desktop/gnome/shell/windows/workspaces_only_on_primary</applyto>
 | 
			
		||||
        <owner>gnome-shell</owner>
 | 
			
		||||
        <type>bool</type>
 | 
			
		||||
        <default>true</default>
 | 
			
		||||
        <locale name="C">
 | 
			
		||||
          <short>Workspaces only on primary monitor</short>
 | 
			
		||||
          <long>
 | 
			
		||||
             This key overrides /apps/mutter/general/workspaces_only_on_primary when
 | 
			
		||||
             running GNOME Shell.
 | 
			
		||||
          </long>
 | 
			
		||||
        </locale>
 | 
			
		||||
      </schema>
 | 
			
		||||
 | 
			
		||||
  </schemalist>
 | 
			
		||||
</gconfschemafile>
 | 
			
		||||
							
								
								
									
										147
									
								
								data/org.gnome.ShellSearchProvider.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,147 @@
 | 
			
		||||
<!DOCTYPE node PUBLIC
 | 
			
		||||
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
 | 
			
		||||
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
 | 
			
		||||
<node>
 | 
			
		||||
  <interface name="org.gnome.Shell.SearchProvider">
 | 
			
		||||
    <doc:doc>
 | 
			
		||||
      <doc:description>
 | 
			
		||||
        <doc:para>
 | 
			
		||||
          The interface used for integrating into GNOME Shell's search
 | 
			
		||||
          interface.
 | 
			
		||||
        </doc:para>
 | 
			
		||||
      </doc:description>
 | 
			
		||||
    </doc:doc>
 | 
			
		||||
 | 
			
		||||
    <method name="GetInitialResultSet">
 | 
			
		||||
      <doc:doc>
 | 
			
		||||
        <doc:description>
 | 
			
		||||
          <doc:para>
 | 
			
		||||
            Called when the user first begins a search.
 | 
			
		||||
          </doc:para>
 | 
			
		||||
        </doc:description>
 | 
			
		||||
      </doc:doc>
 | 
			
		||||
      <arg type="as" direction="in">
 | 
			
		||||
        <doc:doc>
 | 
			
		||||
          <doc:summary>
 | 
			
		||||
            <doc:para>
 | 
			
		||||
              Array of search terms, which the provider should treat as
 | 
			
		||||
              logical AND.
 | 
			
		||||
            </doc:para>
 | 
			
		||||
          </doc:summary>
 | 
			
		||||
        </doc:doc>
 | 
			
		||||
      </arg>
 | 
			
		||||
      <arg type="as" direction="out">
 | 
			
		||||
        <doc:doc>
 | 
			
		||||
          <doc:summary>
 | 
			
		||||
            <doc:para>
 | 
			
		||||
              An array of result identifier strings representing items which
 | 
			
		||||
              match the given search terms. Identifiers must be unique within
 | 
			
		||||
              the provider's domain, but other than that may be chosen freely
 | 
			
		||||
              by the provider.
 | 
			
		||||
            </doc:para>
 | 
			
		||||
          </doc:summary>
 | 
			
		||||
        </doc:doc>
 | 
			
		||||
      </arg>
 | 
			
		||||
    </method>
 | 
			
		||||
 | 
			
		||||
    <method name="GetSubsearchResultSet">
 | 
			
		||||
      <doc:doc>
 | 
			
		||||
        <doc:description>
 | 
			
		||||
          <doc:para>
 | 
			
		||||
            Called when a search is performed which is a "subsearch" of
 | 
			
		||||
            the previous search, e.g. the method may return less results, but
 | 
			
		||||
            not more or different results.
 | 
			
		||||
 | 
			
		||||
            This allows search providers to only search through the previous
 | 
			
		||||
            result set, rather than possibly performing a full re-query.
 | 
			
		||||
          </doc:para>
 | 
			
		||||
        </doc:description>
 | 
			
		||||
      </doc:doc>
 | 
			
		||||
      <arg type="as" direction="in">
 | 
			
		||||
        <doc:doc>
 | 
			
		||||
          <doc:summary>
 | 
			
		||||
            <doc:para>
 | 
			
		||||
              Array of item identifiers
 | 
			
		||||
            </doc:para>
 | 
			
		||||
          </doc:summary>
 | 
			
		||||
        </doc:doc>
 | 
			
		||||
      </arg>
 | 
			
		||||
      <arg type="as" direction="in">
 | 
			
		||||
        <doc:doc>
 | 
			
		||||
          <doc:summary>
 | 
			
		||||
            <doc:para>
 | 
			
		||||
              Array of updated search terms, which the provider should treat as
 | 
			
		||||
              logical AND.
 | 
			
		||||
            </doc:para>
 | 
			
		||||
          </doc:summary>
 | 
			
		||||
        </doc:doc>
 | 
			
		||||
      </arg>
 | 
			
		||||
      <arg type="as" direction="out">
 | 
			
		||||
        <doc:doc>
 | 
			
		||||
          <doc:summary>
 | 
			
		||||
            <doc:para>
 | 
			
		||||
              An array of result identifier strings representing items which
 | 
			
		||||
              match the given search terms. Identifiers must be unique within
 | 
			
		||||
              the provider's domain, but other than that may be chosen freely
 | 
			
		||||
              by the provider.
 | 
			
		||||
            </doc:para>
 | 
			
		||||
          </doc:summary>
 | 
			
		||||
        </doc:doc>
 | 
			
		||||
      </arg>
 | 
			
		||||
    </method>
 | 
			
		||||
 | 
			
		||||
    <method name="GetResultMetas">
 | 
			
		||||
      <doc:doc>
 | 
			
		||||
        <doc:description>
 | 
			
		||||
          <doc:para>
 | 
			
		||||
            Return an array of meta data used to display each given result
 | 
			
		||||
          </doc:para>
 | 
			
		||||
        </doc:description>
 | 
			
		||||
      </doc:doc>
 | 
			
		||||
      <arg type="as" direction="in">
 | 
			
		||||
        <doc:doc>
 | 
			
		||||
          <doc:summary>
 | 
			
		||||
            <doc:para>
 | 
			
		||||
              An array of result identifiers as returned by
 | 
			
		||||
              GetInitialResultSet() or GetSubsearchResultSet()
 | 
			
		||||
            </doc:para>
 | 
			
		||||
          </doc:summary>
 | 
			
		||||
        </doc:doc>
 | 
			
		||||
      </arg>
 | 
			
		||||
      <arg type="a{sv}" direction="out">
 | 
			
		||||
        <doc:doc>
 | 
			
		||||
          <doc:summary>
 | 
			
		||||
            <doc:para>
 | 
			
		||||
              A dictionary describing the given search result, containing
 | 
			
		||||
              'id', 'name' (both strings) and either 'icon' (a serialized
 | 
			
		||||
              GIcon) or 'icon-data' (raw image data as (iiibiiay) - width,
 | 
			
		||||
              height, rowstride, has-alpha, bits per sample, channels, data)
 | 
			
		||||
            </doc:para>
 | 
			
		||||
          </doc:summary>
 | 
			
		||||
        </doc:doc>
 | 
			
		||||
      </arg>
 | 
			
		||||
    </method>
 | 
			
		||||
 | 
			
		||||
    <method name="ActivateResult">
 | 
			
		||||
      <doc:doc>
 | 
			
		||||
        <doc:description>
 | 
			
		||||
          <doc:para>
 | 
			
		||||
            Called when the users chooses a given result. The result should
 | 
			
		||||
            be displayed in the application associated with the corresponding
 | 
			
		||||
            provider.
 | 
			
		||||
          </doc:para>
 | 
			
		||||
        </doc:description>
 | 
			
		||||
      </doc:doc>
 | 
			
		||||
      <arg type="s" direction="in">
 | 
			
		||||
        <doc:doc>
 | 
			
		||||
          <doc:summary>
 | 
			
		||||
            <doc:para>
 | 
			
		||||
              A result identifier as returned by GetInitialResultSet() or
 | 
			
		||||
              GetSubsearchResultSet()
 | 
			
		||||
            </doc:para>
 | 
			
		||||
          </doc:summary>
 | 
			
		||||
        </doc:doc>
 | 
			
		||||
      </arg>
 | 
			
		||||
    </method>
 | 
			
		||||
  </interface>
 | 
			
		||||
</node>
 | 
			
		||||
@@ -16,8 +16,9 @@
 | 
			
		||||
      <_summary>Uuids of extensions to enable</_summary>
 | 
			
		||||
      <_description>
 | 
			
		||||
        GNOME Shell extensions have a uuid property; this key lists extensions
 | 
			
		||||
        which should be loaded.  disabled-extensions overrides this setting for
 | 
			
		||||
        extensions that appear in both lists.
 | 
			
		||||
        which should be loaded. Any extension that wants to be loaded needs
 | 
			
		||||
        to be in this list. You can also manipulate this list with the
 | 
			
		||||
        EnableExtension and DisableExtension DBus methods on org.gnome.Shell.
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="enable-app-monitoring" type="b">
 | 
			
		||||
@@ -31,7 +32,7 @@
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="favorite-apps" type="as">
 | 
			
		||||
      <default>[ 'firefox.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'libreoffice-writer.desktop', 'nautilus.desktop', 'gnome-documents.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
 | 
			
		||||
@@ -50,9 +51,19 @@
 | 
			
		||||
      <default>[]</default>
 | 
			
		||||
      <_summary>History for the looking glass dialog</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <child name="clock" schema="org.gnome.shell.clock"/>
 | 
			
		||||
    <key name="saved-im-presence" type="i">
 | 
			
		||||
      <default>1</default>
 | 
			
		||||
      <_summary>Internally used to store the last IM presence explicitly set by the user. The
 | 
			
		||||
value here is from the TpConnectionPresenceType enumeration.</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="saved-session-presence" type="i">
 | 
			
		||||
      <default>0</default>
 | 
			
		||||
      <_summary>Internally used to store the last session presence status for the user. The
 | 
			
		||||
value here is from the GsmPresenceStatus enumeration.</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <child name="calendar" schema="org.gnome.shell.calendar"/>
 | 
			
		||||
    <child name="recorder" schema="org.gnome.shell.recorder"/>
 | 
			
		||||
    <child name="keybindings" schema="org.gnome.shell.keybindings"/>
 | 
			
		||||
    <child name="keyboard" schema="org.gnome.shell.keyboard"/>
 | 
			
		||||
  </schema>
 | 
			
		||||
 | 
			
		||||
@@ -67,15 +78,26 @@
 | 
			
		||||
      </key>
 | 
			
		||||
  </schema>
 | 
			
		||||
 | 
			
		||||
  <schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/"
 | 
			
		||||
  <schema id="org.gnome.shell.keybindings" path="/org/gnome/shell/keybindings/"
 | 
			
		||||
          gettext-domain="@GETTEXT_PACKAGE@">
 | 
			
		||||
    <key name="show-keyboard" type="b">
 | 
			
		||||
      <default>false</default>
 | 
			
		||||
      <_summary>Show the onscreen keyboard</_summary>
 | 
			
		||||
    <key name="open-application-menu" type="as">
 | 
			
		||||
      <default>["<Super>F10"]</default>
 | 
			
		||||
      <_summary>Keybinding to open the application menu</_summary>
 | 
			
		||||
      <_description>
 | 
			
		||||
        If true, display onscreen keyboard.
 | 
			
		||||
        Keybinding to open the application menu.
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="toggle-recording" type="as">
 | 
			
		||||
      <default><![CDATA[['<Control><Shift><Alt>r']]]></default>
 | 
			
		||||
      <_summary>Keybinding to toggle the screen recorder</_summary>
 | 
			
		||||
      <_description>
 | 
			
		||||
        Keybinding to start/stop the builtin screen recorder.
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
  </schema>
 | 
			
		||||
 | 
			
		||||
  <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>
 | 
			
		||||
@@ -85,28 +107,10 @@
 | 
			
		||||
    </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>
 | 
			
		||||
      <_summary>Show time with seconds</_summary>
 | 
			
		||||
      <_description>
 | 
			
		||||
        If true, display seconds in time.
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="show-date" type="b">
 | 
			
		||||
      <default>false</default>
 | 
			
		||||
      <_summary>Show date in clock</_summary>
 | 
			
		||||
      <_description>
 | 
			
		||||
        If true, display date in the clock, in addition to time.
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
  </schema>
 | 
			
		||||
 | 
			
		||||
  <schema id="org.gnome.shell.recorder" path="/org/gnome/shell/recorder/"
 | 
			
		||||
          gettext-domain="@GETTEXT_PACKAGE@">
 | 
			
		||||
    <key name="framerate" type="i">
 | 
			
		||||
      <default>15</default>
 | 
			
		||||
      <default>30</default>
 | 
			
		||||
      <_summary>Framerate used for recording screencasts.</_summary>
 | 
			
		||||
      <_description>
 | 
			
		||||
        The framerate of the resulting screencast recordered
 | 
			
		||||
@@ -125,7 +129,7 @@
 | 
			
		||||
        take care of its own output - this might be used to send the output
 | 
			
		||||
        to an icecast server via shout2send or similar. When unset or set
 | 
			
		||||
        to an empty value, the default pipeline will be used. This is currently
 | 
			
		||||
        'videorate ! vp8enc quality=10 speed=2 threads=%T ! queue ! webmmux'
 | 
			
		||||
        'vp8enc quality=8 speed=6 threads=%T ! queue ! webmmux'
 | 
			
		||||
        and records to WEBM using the VP8 codec. %T is used as a placeholder
 | 
			
		||||
        for a guess at the optimal thread count on the system.
 | 
			
		||||
      </_description>
 | 
			
		||||
@@ -140,4 +144,48 @@
 | 
			
		||||
      </_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="dynamic-workspaces" type="b">
 | 
			
		||||
      <default>true</default>
 | 
			
		||||
      <summary>Workspaces are managed dynamically</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,26 +0,0 @@
 | 
			
		||||
#version 110
 | 
			
		||||
uniform sampler2D sampler0;
 | 
			
		||||
uniform float fraction;
 | 
			
		||||
uniform float height;
 | 
			
		||||
const float c = -0.2;
 | 
			
		||||
const float border_max_height = 60.0;
 | 
			
		||||
 | 
			
		||||
mat4 contrast = mat4 (1.0 + c, 0.0, 0.0, 0.0,
 | 
			
		||||
                      0.0, 1.0 + c, 0.0, 0.0,
 | 
			
		||||
                      0.0, 0.0, 1.0 + c, 0.0,
 | 
			
		||||
                      0.0, 0.0, 0.0, 1.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];
 | 
			
		||||
 | 
			
		||||
  // To reduce contrast, blend with a mid gray
 | 
			
		||||
  gl_FragColor = color * contrast - off * c;
 | 
			
		||||
 | 
			
		||||
  // We only fully dim at a distance of BORDER_MAX_HEIGHT from the edge 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;
 | 
			
		||||
}
 | 
			
		||||
@@ -10,11 +10,11 @@
 | 
			
		||||
   xmlns:xlink="http://www.w3.org/1999/xlink"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   width="28"
 | 
			
		||||
   height="25"
 | 
			
		||||
   width="29"
 | 
			
		||||
   height="29"
 | 
			
		||||
   id="svg10621"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.48.1 r9760"
 | 
			
		||||
   inkscape:version="0.48.2 r9819"
 | 
			
		||||
   sodipodi:docname="calendar-today.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs10623">
 | 
			
		||||
@@ -118,6 +118,17 @@
 | 
			
		||||
       fx="51"
 | 
			
		||||
       fy="30"
 | 
			
		||||
       r="42" />
 | 
			
		||||
    <radialGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       xlink:href="#linearGradient34508-1-3"
 | 
			
		||||
       id="radialGradient3113"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
 | 
			
		||||
       cx="51"
 | 
			
		||||
       cy="30"
 | 
			
		||||
       fx="51"
 | 
			
		||||
       fy="30"
 | 
			
		||||
       r="42" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
@@ -127,20 +138,29 @@
 | 
			
		||||
     inkscape:pageopacity="0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="15.839192"
 | 
			
		||||
     inkscape:cx="8.3750933"
 | 
			
		||||
     inkscape:cy="8.0837211"
 | 
			
		||||
     inkscape:cx="20.652108"
 | 
			
		||||
     inkscape:cy="11.839084"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     showgrid="true"
 | 
			
		||||
     fit-margin-top="0"
 | 
			
		||||
     fit-margin-left="0"
 | 
			
		||||
     fit-margin-right="0"
 | 
			
		||||
     fit-margin-bottom="0"
 | 
			
		||||
     inkscape:window-width="1440"
 | 
			
		||||
     inkscape:window-height="843"
 | 
			
		||||
     inkscape:window-width="1280"
 | 
			
		||||
     inkscape:window-height="741"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="26"
 | 
			
		||||
     inkscape:window-maximized="1" />
 | 
			
		||||
     inkscape:window-y="27"
 | 
			
		||||
     inkscape:window-maximized="1"
 | 
			
		||||
     borderlayer="true">
 | 
			
		||||
    <inkscape:grid
 | 
			
		||||
       type="xygrid"
 | 
			
		||||
       id="grid3109"
 | 
			
		||||
       empspacing="5"
 | 
			
		||||
       visible="true"
 | 
			
		||||
       enabled="true"
 | 
			
		||||
       snapvisiblegridlinesonly="true" />
 | 
			
		||||
  </sodipodi:namedview>
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata10626">
 | 
			
		||||
    <rdf:RDF>
 | 
			
		||||
@@ -157,31 +177,28 @@
 | 
			
		||||
     inkscape:label="Layer 1"
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     transform="translate(-469.08263,-536.99307)">
 | 
			
		||||
    <g
 | 
			
		||||
       id="g3003">
 | 
			
		||||
      <path
 | 
			
		||||
         inkscape:export-ydpi="90"
 | 
			
		||||
         inkscape:export-xdpi="90"
 | 
			
		||||
         inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/motion/textures/panel.png"
 | 
			
		||||
         transform="matrix(0.43692393,0,0,1.3783114,460.60467,517.48289)"
 | 
			
		||||
         sodipodi:end="6.2831853"
 | 
			
		||||
         sodipodi:start="3.1415927"
 | 
			
		||||
         d="M 9,29.999999 C 9.0000011,21.163443 27.804042,14 51.000002,14 74.195961,14 93,21.163444 93,30 l -42,0 z"
 | 
			
		||||
         sodipodi:ry="16"
 | 
			
		||||
         sodipodi:rx="42"
 | 
			
		||||
         sodipodi:cy="30"
 | 
			
		||||
         sodipodi:cx="51"
 | 
			
		||||
         id="path34506-3"
 | 
			
		||||
         style="opacity:0.4625;color:#000000;fill:url(#radialGradient2997);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
         sodipodi:type="arc" />
 | 
			
		||||
      <rect
 | 
			
		||||
         y="558.85046"
 | 
			
		||||
         x="468.96878"
 | 
			
		||||
         height="3.1425927"
 | 
			
		||||
         width="28.149134"
 | 
			
		||||
         id="rect2996"
 | 
			
		||||
         style="fill:#ffffff;fill-opacity:0.50196078;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none" />
 | 
			
		||||
    </g>
 | 
			
		||||
     transform="translate(-469.08263,-532.99307)">
 | 
			
		||||
    <path
 | 
			
		||||
       sodipodi:type="arc"
 | 
			
		||||
       style="opacity:0.4625;color:#000000;fill:url(#radialGradient3113);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
       id="path34506-3"
 | 
			
		||||
       sodipodi:cx="51"
 | 
			
		||||
       sodipodi:cy="30"
 | 
			
		||||
       sodipodi:rx="42"
 | 
			
		||||
       sodipodi:ry="16"
 | 
			
		||||
       d="M 9,29.999999 A 42,16 0 0 1 93,30 l -42,0 z"
 | 
			
		||||
       sodipodi:start="3.1415927"
 | 
			
		||||
       sodipodi:end="6.2831853"
 | 
			
		||||
       transform="matrix(0.43692393,0,0,1.3783114,461.29951,517.6437)"
 | 
			
		||||
       inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/motion/textures/panel.png"
 | 
			
		||||
       inkscape:export-xdpi="90"
 | 
			
		||||
       inkscape:export-ydpi="90" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:0.50196078;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
       id="rect2996"
 | 
			
		||||
       width="31"
 | 
			
		||||
       height="3"
 | 
			
		||||
       x="468.08264"
 | 
			
		||||
       y="558.99304" />
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
 
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 6.1 KiB  | 
							
								
								
									
										289
									
								
								data/theme/checkbox-focused.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,289 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
 | 
			
		||||
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:xlink="http://www.w3.org/1999/xlink"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   width="24"
 | 
			
		||||
   height="22"
 | 
			
		||||
   id="svg3199"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.48.1 r9760"
 | 
			
		||||
   sodipodi:docname="checkbox.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs3201">
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       id="linearGradient15404"
 | 
			
		||||
       inkscape:collect="always">
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop15406"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         style="stop-color:#515151;stop-opacity:1" />
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop15408"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         style="stop-color:#292929;stop-opacity:1" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <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="perspective3207" />
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       id="perspective3187"
 | 
			
		||||
       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
 | 
			
		||||
       inkscape:vp_z="1 : 0.5 : 1"
 | 
			
		||||
       inkscape:vp_y="0 : 1000 : 0"
 | 
			
		||||
       inkscape:vp_x="0 : 0.5 : 1"
 | 
			
		||||
       sodipodi:type="inkscape:persp3d" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       xlink:href="#linearGradient5872-5-1"
 | 
			
		||||
       id="linearGradient5891-0-4"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       x1="205.84143"
 | 
			
		||||
       y1="246.7094"
 | 
			
		||||
       x2="206.74803"
 | 
			
		||||
       y2="231.24142" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       id="linearGradient5872-5-1">
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#0b2e52;stop-opacity:1"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         id="stop5874-4-4" />
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#1862af;stop-opacity:1"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         id="stop5876-0-5" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <inkscape:path-effect
 | 
			
		||||
       effect="spiro"
 | 
			
		||||
       id="path-effect5837-4-6"
 | 
			
		||||
       is_visible="true" />
 | 
			
		||||
    <inkscape:path-effect
 | 
			
		||||
       effect="spiro"
 | 
			
		||||
       id="path-effect14768"
 | 
			
		||||
       is_visible="true" />
 | 
			
		||||
    <inkscape:path-effect
 | 
			
		||||
       effect="spiro"
 | 
			
		||||
       id="path-effect5884-4-7"
 | 
			
		||||
       is_visible="true" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       y2="-388.72955"
 | 
			
		||||
       x2="-93.031357"
 | 
			
		||||
       y1="-396.34738"
 | 
			
		||||
       x1="-93.031357"
 | 
			
		||||
       gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.685418)"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       id="linearGradient14219"
 | 
			
		||||
       xlink:href="#linearGradient15404"
 | 
			
		||||
       inkscape:collect="always" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       id="linearGradient10013-4-63-6">
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#333333;stop-opacity:1;"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         id="stop10015-2-76-1" />
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#292929;stop-opacity:1"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         id="stop10017-46-15-8" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       id="linearGradient10597-5">
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#16191a;stop-opacity:1;"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         id="stop10599-2" />
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#2b3133;stop-opacity:1"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         id="stop10601-5" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       y2="-322.16354"
 | 
			
		||||
       x2="921.22498"
 | 
			
		||||
       y1="-330.05121"
 | 
			
		||||
       x1="921.32812"
 | 
			
		||||
       gradientTransform="matrix(1.5918367,0,0,0.85714285,-1456.5464,275.45191)"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       id="linearGradient15374"
 | 
			
		||||
       xlink:href="#linearGradient10013-4-63-6"
 | 
			
		||||
       inkscape:collect="always" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       gradientTransform="translate(-1199.9852,216.38048)"
 | 
			
		||||
       y2="-227.07961"
 | 
			
		||||
       x2="1203.9177"
 | 
			
		||||
       y1="-217.56708"
 | 
			
		||||
       x1="1203.9177"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       id="linearGradient15376"
 | 
			
		||||
       xlink:href="#linearGradient10597-5"
 | 
			
		||||
       inkscape:collect="always" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       y2="-388.72955"
 | 
			
		||||
       x2="-93.031357"
 | 
			
		||||
       y1="-396.34738"
 | 
			
		||||
       x1="-93.031357"
 | 
			
		||||
       gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.685418)"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       id="linearGradient14219-6"
 | 
			
		||||
       xlink:href="#linearGradient15404-9"
 | 
			
		||||
       inkscape:collect="always" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       id="linearGradient15404-9"
 | 
			
		||||
       inkscape:collect="always">
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop15406-6"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         style="stop-color:#515151;stop-opacity:1" />
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop15408-7"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         style="stop-color:#292929;stop-opacity:1" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#000000"
 | 
			
		||||
     bordercolor="#2d2d2d"
 | 
			
		||||
     borderopacity="1"
 | 
			
		||||
     inkscape:pageopacity="1"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="1"
 | 
			
		||||
     inkscape:cx="71.516955"
 | 
			
		||||
     inkscape:cy="5.8710559"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:window-width="1412"
 | 
			
		||||
     inkscape:window-height="1067"
 | 
			
		||||
     inkscape:window-x="2635"
 | 
			
		||||
     inkscape:window-y="226"
 | 
			
		||||
     inkscape:window-maximized="0"
 | 
			
		||||
     borderlayer="true"
 | 
			
		||||
     inkscape:showpageshadow="false"
 | 
			
		||||
     inkscape:snap-nodes="false"
 | 
			
		||||
     inkscape:snap-bbox="true"
 | 
			
		||||
     showborder="false">
 | 
			
		||||
    <inkscape:grid
 | 
			
		||||
       type="xygrid"
 | 
			
		||||
       id="grid14843"
 | 
			
		||||
       empspacing="5"
 | 
			
		||||
       visible="true"
 | 
			
		||||
       enabled="true"
 | 
			
		||||
       snapvisiblegridlinesonly="true" />
 | 
			
		||||
  </sodipodi:namedview>
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata3204">
 | 
			
		||||
    <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(-342.5,-521.36218)">
 | 
			
		||||
    <g
 | 
			
		||||
       transform="matrix(0.80230061,0,0,0.80230061,-87.624044,-453.10297)"
 | 
			
		||||
       id="g14586-0"
 | 
			
		||||
       style="stroke-width:2.3714385;stroke-miterlimit:4;stroke-dasharray:none">
 | 
			
		||||
      <g
 | 
			
		||||
         inkscape:export-ydpi="90"
 | 
			
		||||
         inkscape:export-xdpi="90"
 | 
			
		||||
         inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
 | 
			
		||||
         transform="matrix(1.9969286,0,0,1.9969286,-397.05491,877.00482)"
 | 
			
		||||
         id="g15291-9-6"
 | 
			
		||||
         style="stroke-width:1.18754292;stroke-miterlimit:4;stroke-dasharray:none;display:inline;enable-background:new">
 | 
			
		||||
        <g
 | 
			
		||||
           transform="translate(877.50354,-102.83507)"
 | 
			
		||||
           id="g16853-4-9"
 | 
			
		||||
           style="stroke-width:1.18754292;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new">
 | 
			
		||||
          <rect
 | 
			
		||||
             transform="scale(1,-1)"
 | 
			
		||||
             style="color:#000000;fill:url(#linearGradient14219-6);fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:1.24833274;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:new"
 | 
			
		||||
             id="rect6506-6"
 | 
			
		||||
             width="11.281681"
 | 
			
		||||
             height="11.26221"
 | 
			
		||||
             x="-409.59354"
 | 
			
		||||
             y="-284.40115"
 | 
			
		||||
             rx="1.0052766"
 | 
			
		||||
             ry="1.0052764" />
 | 
			
		||||
        </g>
 | 
			
		||||
      </g>
 | 
			
		||||
      <g
 | 
			
		||||
         inkscape:export-ydpi="90"
 | 
			
		||||
         inkscape:export-xdpi="90"
 | 
			
		||||
         inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
 | 
			
		||||
         transform="translate(343.99999,987.99997)"
 | 
			
		||||
         id="g5886-5"
 | 
			
		||||
         style="stroke-width:2.3714385;stroke-miterlimit:4;stroke-dasharray:none;display:inline;enable-background:new" />
 | 
			
		||||
    </g>
 | 
			
		||||
    <g
 | 
			
		||||
       transform="matrix(0.84337,0,0,0.84337,-110.16632,-503.56182)"
 | 
			
		||||
       id="g14586">
 | 
			
		||||
      <g
 | 
			
		||||
         inkscape:export-ydpi="90"
 | 
			
		||||
         inkscape:export-xdpi="90"
 | 
			
		||||
         inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
 | 
			
		||||
         transform="matrix(1.9969286,0,0,1.9969286,-397.05491,877.00482)"
 | 
			
		||||
         id="g15291-9"
 | 
			
		||||
         style="display:inline;enable-background:new">
 | 
			
		||||
        <g
 | 
			
		||||
           transform="translate(877.50354,-102.83507)"
 | 
			
		||||
           id="g16853-4"
 | 
			
		||||
           style="enable-background:new" />
 | 
			
		||||
      </g>
 | 
			
		||||
      <g
 | 
			
		||||
         inkscape:export-ydpi="90"
 | 
			
		||||
         inkscape:export-xdpi="90"
 | 
			
		||||
         inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
 | 
			
		||||
         transform="translate(343.99999,987.99997)"
 | 
			
		||||
         id="g5886"
 | 
			
		||||
         style="display:inline;enable-background:new">
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;stroke:url(#linearGradient5891-0-4);stroke-width:7.11431503;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
 | 
			
		||||
           d="m 198.5,240 5.25,5.25 13.98616,-14.43081"
 | 
			
		||||
           id="path5835"
 | 
			
		||||
           inkscape:path-effect="#path-effect5837-4-6"
 | 
			
		||||
           inkscape:original-d="m 198.5,240 5.25,5.25 13.98616,-14.43081"
 | 
			
		||||
           inkscape:connector-curvature="0"
 | 
			
		||||
           sodipodi:nodetypes="ccc" />
 | 
			
		||||
        <path
 | 
			
		||||
           inkscape:connector-curvature="0"
 | 
			
		||||
           inkscape:original-d="m 198.5,240 5.25,5.25 13.91205,-14.31964"
 | 
			
		||||
           inkscape:path-effect="#path-effect5837-4-6"
 | 
			
		||||
           id="path5880"
 | 
			
		||||
           d="m 198.5,240 5.25,5.25 13.91205,-14.31964"
 | 
			
		||||
           style="fill:none;stroke:#4787c8;stroke-width:3.55715752;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
 | 
			
		||||
           sodipodi:nodetypes="ccc" />
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;stroke:#7ea7d3;stroke-width:1.18571913px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
           d="m 197.45937,240.47455 c -0.17828,-0.29362 -0.20087,-0.67548 -0.0603,-0.98892 0.14055,-0.31344 0.43739,-0.54812 0.77144,-0.62817 0.33405,-0.08 0.69314,-0.01 0.99635,0.15175 0.30321,0.16144 0.55146,0.40727 0.79165,0.65284 l 3.66429,3.74643 12.87946,-12.98973 c 0.20796,-0.20974 0.42306,-0.41969 0.68548,-0.55522 0.26242,-0.13553 0.57293,-0.19052 0.85827,-0.11426 0.14267,0.0381 0.27708,0.10787 0.38874,0.20452 0.11167,0.0966 0.20021,0.22004 0.25479,0.35726 0.0546,0.13722 0.075,0.28793 0.0585,0.43468 -0.0165,0.14674 -0.07,0.28919 -0.15422,0.41052"
 | 
			
		||||
           id="path5882"
 | 
			
		||||
           inkscape:path-effect="#path-effect5884-4-7"
 | 
			
		||||
           inkscape:original-d="m 197.45937,240.47455 c 0.65604,-0.56057 2.02485,-1.34847 2.49911,-0.8125 l 3.66429,3.74643 12.87946,-12.98973 c 0.6875,-0.6875 2.09152,0.7375 2.09152,0.7375"
 | 
			
		||||
           inkscape:connector-curvature="0"
 | 
			
		||||
           sodipodi:nodetypes="csccc" />
 | 
			
		||||
      </g>
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 11 KiB  | 
							
								
								
									
										198
									
								
								data/theme/checkbox-off-focused.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,198 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
 | 
			
		||||
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:xlink="http://www.w3.org/1999/xlink"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   width="24"
 | 
			
		||||
   height="22"
 | 
			
		||||
   id="svg3199"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.48.1 r9760"
 | 
			
		||||
   sodipodi:docname="checkbox-off.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs3201">
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       id="linearGradient15404"
 | 
			
		||||
       inkscape:collect="always">
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop15406"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         style="stop-color:#515151;stop-opacity:1" />
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop15408"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         style="stop-color:#292929;stop-opacity:1" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <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="perspective3207" />
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       id="perspective3187"
 | 
			
		||||
       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
 | 
			
		||||
       inkscape:vp_z="1 : 0.5 : 1"
 | 
			
		||||
       inkscape:vp_y="0 : 1000 : 0"
 | 
			
		||||
       inkscape:vp_x="0 : 0.5 : 1"
 | 
			
		||||
       sodipodi:type="inkscape:persp3d" />
 | 
			
		||||
    <inkscape:path-effect
 | 
			
		||||
       effect="spiro"
 | 
			
		||||
       id="path-effect5837-4-6"
 | 
			
		||||
       is_visible="true" />
 | 
			
		||||
    <inkscape:path-effect
 | 
			
		||||
       effect="spiro"
 | 
			
		||||
       id="path-effect14768"
 | 
			
		||||
       is_visible="true" />
 | 
			
		||||
    <inkscape:path-effect
 | 
			
		||||
       effect="spiro"
 | 
			
		||||
       id="path-effect5884-4-7"
 | 
			
		||||
       is_visible="true" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       y2="-388.72955"
 | 
			
		||||
       x2="-93.031357"
 | 
			
		||||
       y1="-396.34738"
 | 
			
		||||
       x1="-93.031357"
 | 
			
		||||
       gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.685418)"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       id="linearGradient14219"
 | 
			
		||||
       xlink:href="#linearGradient15404"
 | 
			
		||||
       inkscape:collect="always" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       id="linearGradient10013-4-63-6">
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#333333;stop-opacity:1;"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         id="stop10015-2-76-1" />
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#292929;stop-opacity:1"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         id="stop10017-46-15-8" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       id="linearGradient10597-5">
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#16191a;stop-opacity:1;"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         id="stop10599-2" />
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#2b3133;stop-opacity:1"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         id="stop10601-5" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       y2="-322.16354"
 | 
			
		||||
       x2="921.22498"
 | 
			
		||||
       y1="-330.05121"
 | 
			
		||||
       x1="921.32812"
 | 
			
		||||
       gradientTransform="matrix(1.5918367,0,0,0.85714285,-1456.5464,275.45191)"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       id="linearGradient15374"
 | 
			
		||||
       xlink:href="#linearGradient10013-4-63-6"
 | 
			
		||||
       inkscape:collect="always" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       gradientTransform="translate(-1199.9852,216.38048)"
 | 
			
		||||
       y2="-227.07961"
 | 
			
		||||
       x2="1203.9177"
 | 
			
		||||
       y1="-217.56708"
 | 
			
		||||
       x1="1203.9177"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       id="linearGradient15376"
 | 
			
		||||
       xlink:href="#linearGradient10597-5"
 | 
			
		||||
       inkscape:collect="always" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#000000"
 | 
			
		||||
     bordercolor="#2d2d2d"
 | 
			
		||||
     borderopacity="1"
 | 
			
		||||
     inkscape:pageopacity="1"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="1"
 | 
			
		||||
     inkscape:cx="6.1225392"
 | 
			
		||||
     inkscape:cy="3.6003241"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:window-width="1412"
 | 
			
		||||
     inkscape:window-height="1067"
 | 
			
		||||
     inkscape:window-x="2116"
 | 
			
		||||
     inkscape:window-y="261"
 | 
			
		||||
     inkscape:window-maximized="0"
 | 
			
		||||
     borderlayer="true"
 | 
			
		||||
     inkscape:showpageshadow="false"
 | 
			
		||||
     inkscape:snap-nodes="false"
 | 
			
		||||
     inkscape:snap-bbox="true"
 | 
			
		||||
     showborder="false">
 | 
			
		||||
    <inkscape:grid
 | 
			
		||||
       type="xygrid"
 | 
			
		||||
       id="grid14843"
 | 
			
		||||
       empspacing="5"
 | 
			
		||||
       visible="true"
 | 
			
		||||
       enabled="true"
 | 
			
		||||
       snapvisiblegridlinesonly="true" />
 | 
			
		||||
  </sodipodi:namedview>
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata3204">
 | 
			
		||||
    <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(-342.5,-521.36218)">
 | 
			
		||||
    <g
 | 
			
		||||
       transform="matrix(0.80230061,0,0,0.80230061,-87.624044,-453.10297)"
 | 
			
		||||
       id="g14586"
 | 
			
		||||
       style="stroke-width:2.3714385;stroke-miterlimit:4;stroke-dasharray:none">
 | 
			
		||||
      <g
 | 
			
		||||
         inkscape:export-ydpi="90"
 | 
			
		||||
         inkscape:export-xdpi="90"
 | 
			
		||||
         inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
 | 
			
		||||
         transform="matrix(1.9969286,0,0,1.9969286,-397.05491,877.00482)"
 | 
			
		||||
         id="g15291-9"
 | 
			
		||||
         style="stroke-width:1.18754292;stroke-miterlimit:4;stroke-dasharray:none;display:inline;enable-background:new">
 | 
			
		||||
        <g
 | 
			
		||||
           transform="translate(877.50354,-102.83507)"
 | 
			
		||||
           id="g16853-4"
 | 
			
		||||
           style="stroke-width:1.18754292;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new">
 | 
			
		||||
          <rect
 | 
			
		||||
             transform="scale(1,-1)"
 | 
			
		||||
             style="color:#000000;fill:url(#linearGradient14219);fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:1.24833274;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:new"
 | 
			
		||||
             id="rect6506-6"
 | 
			
		||||
             width="11.281681"
 | 
			
		||||
             height="11.26221"
 | 
			
		||||
             x="-409.59354"
 | 
			
		||||
             y="-284.40115"
 | 
			
		||||
             rx="1.0052766"
 | 
			
		||||
             ry="1.0052764" />
 | 
			
		||||
        </g>
 | 
			
		||||
      </g>
 | 
			
		||||
      <g
 | 
			
		||||
         inkscape:export-ydpi="90"
 | 
			
		||||
         inkscape:export-xdpi="90"
 | 
			
		||||
         inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
 | 
			
		||||
         transform="translate(343.99999,987.99997)"
 | 
			
		||||
         id="g5886"
 | 
			
		||||
         style="stroke-width:2.3714385;stroke-miterlimit:4;stroke-dasharray:none;display:inline;enable-background:new" />
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 6.5 KiB  | 
							
								
								
									
										218
									
								
								data/theme/checkbox-off.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,218 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
 | 
			
		||||
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:xlink="http://www.w3.org/1999/xlink"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   width="24"
 | 
			
		||||
   height="22"
 | 
			
		||||
   id="svg3199"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.48.1 r9760"
 | 
			
		||||
   sodipodi:docname="checkbox.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs3201">
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       id="linearGradient15404"
 | 
			
		||||
       inkscape:collect="always">
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop15406"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         style="stop-color:#515151;stop-opacity:1" />
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop15408"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         style="stop-color:#292929;stop-opacity:1" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <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="perspective3207" />
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       id="perspective3187"
 | 
			
		||||
       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
 | 
			
		||||
       inkscape:vp_z="1 : 0.5 : 1"
 | 
			
		||||
       inkscape:vp_y="0 : 1000 : 0"
 | 
			
		||||
       inkscape:vp_x="0 : 0.5 : 1"
 | 
			
		||||
       sodipodi:type="inkscape:persp3d" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       xlink:href="#linearGradient5872-5-1"
 | 
			
		||||
       id="linearGradient5891-0-4"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       x1="205.84143"
 | 
			
		||||
       y1="246.7094"
 | 
			
		||||
       x2="206.74803"
 | 
			
		||||
       y2="231.24142" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       id="linearGradient5872-5-1">
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#0b2e52;stop-opacity:1"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         id="stop5874-4-4" />
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#1862af;stop-opacity:1"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         id="stop5876-0-5" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <inkscape:path-effect
 | 
			
		||||
       effect="spiro"
 | 
			
		||||
       id="path-effect5837-4-6"
 | 
			
		||||
       is_visible="true" />
 | 
			
		||||
    <inkscape:path-effect
 | 
			
		||||
       effect="spiro"
 | 
			
		||||
       id="path-effect14768"
 | 
			
		||||
       is_visible="true" />
 | 
			
		||||
    <inkscape:path-effect
 | 
			
		||||
       effect="spiro"
 | 
			
		||||
       id="path-effect5884-4-7"
 | 
			
		||||
       is_visible="true" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       y2="-388.72955"
 | 
			
		||||
       x2="-93.031357"
 | 
			
		||||
       y1="-396.34738"
 | 
			
		||||
       x1="-93.031357"
 | 
			
		||||
       gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.685418)"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       id="linearGradient14219"
 | 
			
		||||
       xlink:href="#linearGradient15404"
 | 
			
		||||
       inkscape:collect="always" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       id="linearGradient10013-4-63-6">
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#333333;stop-opacity:1;"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         id="stop10015-2-76-1" />
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#292929;stop-opacity:1"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         id="stop10017-46-15-8" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       id="linearGradient10597-5">
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#16191a;stop-opacity:1;"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         id="stop10599-2" />
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#2b3133;stop-opacity:1"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         id="stop10601-5" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       y2="-322.16354"
 | 
			
		||||
       x2="921.22498"
 | 
			
		||||
       y1="-330.05121"
 | 
			
		||||
       x1="921.32812"
 | 
			
		||||
       gradientTransform="matrix(1.5918367,0,0,0.85714285,-1456.5464,275.45191)"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       id="linearGradient15374"
 | 
			
		||||
       xlink:href="#linearGradient10013-4-63-6"
 | 
			
		||||
       inkscape:collect="always" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       gradientTransform="translate(-1199.9852,216.38048)"
 | 
			
		||||
       y2="-227.07961"
 | 
			
		||||
       x2="1203.9177"
 | 
			
		||||
       y1="-217.56708"
 | 
			
		||||
       x1="1203.9177"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       id="linearGradient15376"
 | 
			
		||||
       xlink:href="#linearGradient10597-5"
 | 
			
		||||
       inkscape:collect="always" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#000000"
 | 
			
		||||
     bordercolor="#2d2d2d"
 | 
			
		||||
     borderopacity="1"
 | 
			
		||||
     inkscape:pageopacity="1"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="4"
 | 
			
		||||
     inkscape:cx="71.247925"
 | 
			
		||||
     inkscape:cy="33.339093"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:window-width="1412"
 | 
			
		||||
     inkscape:window-height="1067"
 | 
			
		||||
     inkscape:window-x="2116"
 | 
			
		||||
     inkscape:window-y="261"
 | 
			
		||||
     inkscape:window-maximized="0"
 | 
			
		||||
     borderlayer="true"
 | 
			
		||||
     inkscape:showpageshadow="false"
 | 
			
		||||
     inkscape:snap-nodes="false"
 | 
			
		||||
     inkscape:snap-bbox="true"
 | 
			
		||||
     showborder="false">
 | 
			
		||||
    <inkscape:grid
 | 
			
		||||
       type="xygrid"
 | 
			
		||||
       id="grid14843"
 | 
			
		||||
       empspacing="5"
 | 
			
		||||
       visible="true"
 | 
			
		||||
       enabled="true"
 | 
			
		||||
       snapvisiblegridlinesonly="true" />
 | 
			
		||||
  </sodipodi:namedview>
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata3204">
 | 
			
		||||
    <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(-342.5,-521.36218)">
 | 
			
		||||
    <g
 | 
			
		||||
       transform="matrix(0.84337,0,0,0.84337,-110.16632,-503.56182)"
 | 
			
		||||
       id="g14586">
 | 
			
		||||
      <g
 | 
			
		||||
         inkscape:export-ydpi="90"
 | 
			
		||||
         inkscape:export-xdpi="90"
 | 
			
		||||
         inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
 | 
			
		||||
         transform="matrix(1.9969286,0,0,1.9969286,-397.05491,877.00482)"
 | 
			
		||||
         id="g15291-9"
 | 
			
		||||
         style="display:inline;enable-background:new">
 | 
			
		||||
        <g
 | 
			
		||||
           transform="translate(877.50354,-102.83507)"
 | 
			
		||||
           id="g16853-4"
 | 
			
		||||
           style="enable-background:new">
 | 
			
		||||
          <rect
 | 
			
		||||
             transform="scale(1,-1)"
 | 
			
		||||
             style="color:#000000;fill:url(#linearGradient14219);fill-opacity:1;fill-rule:nonzero;stroke:#868686;stroke-width:0.59377144999999998;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:new"
 | 
			
		||||
             id="rect6506-6"
 | 
			
		||||
             width="11.281681"
 | 
			
		||||
             height="11.26221"
 | 
			
		||||
             x="-409.59354"
 | 
			
		||||
             y="-284.40115"
 | 
			
		||||
             rx="0.95632279"
 | 
			
		||||
             ry="0.95632273" />
 | 
			
		||||
        </g>
 | 
			
		||||
      </g>
 | 
			
		||||
      <g
 | 
			
		||||
         inkscape:export-ydpi="90"
 | 
			
		||||
         inkscape:export-xdpi="90"
 | 
			
		||||
         inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
 | 
			
		||||
         transform="translate(343.99999,987.99997)"
 | 
			
		||||
         id="g5886"
 | 
			
		||||
         style="display:inline;enable-background:new" />
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 6.8 KiB  | 
							
								
								
									
										243
									
								
								data/theme/checkbox.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,243 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
 | 
			
		||||
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:xlink="http://www.w3.org/1999/xlink"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   width="24"
 | 
			
		||||
   height="22"
 | 
			
		||||
   id="svg3199"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.48.1 r9760"
 | 
			
		||||
   sodipodi:docname="checkbox-focused.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs3201">
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       id="linearGradient15404"
 | 
			
		||||
       inkscape:collect="always">
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop15406"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         style="stop-color:#515151;stop-opacity:1" />
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop15408"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         style="stop-color:#292929;stop-opacity:1" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <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="perspective3207" />
 | 
			
		||||
    <inkscape:perspective
 | 
			
		||||
       id="perspective3187"
 | 
			
		||||
       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
 | 
			
		||||
       inkscape:vp_z="1 : 0.5 : 1"
 | 
			
		||||
       inkscape:vp_y="0 : 1000 : 0"
 | 
			
		||||
       inkscape:vp_x="0 : 0.5 : 1"
 | 
			
		||||
       sodipodi:type="inkscape:persp3d" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       xlink:href="#linearGradient5872-5-1"
 | 
			
		||||
       id="linearGradient5891-0-4"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       x1="205.84143"
 | 
			
		||||
       y1="246.7094"
 | 
			
		||||
       x2="206.74803"
 | 
			
		||||
       y2="231.24142" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       id="linearGradient5872-5-1">
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#0b2e52;stop-opacity:1"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         id="stop5874-4-4" />
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#1862af;stop-opacity:1"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         id="stop5876-0-5" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <inkscape:path-effect
 | 
			
		||||
       effect="spiro"
 | 
			
		||||
       id="path-effect5837-4-6"
 | 
			
		||||
       is_visible="true" />
 | 
			
		||||
    <inkscape:path-effect
 | 
			
		||||
       effect="spiro"
 | 
			
		||||
       id="path-effect14768"
 | 
			
		||||
       is_visible="true" />
 | 
			
		||||
    <inkscape:path-effect
 | 
			
		||||
       effect="spiro"
 | 
			
		||||
       id="path-effect5884-4-7"
 | 
			
		||||
       is_visible="true" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       y2="-388.72955"
 | 
			
		||||
       x2="-93.031357"
 | 
			
		||||
       y1="-396.34738"
 | 
			
		||||
       x1="-93.031357"
 | 
			
		||||
       gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.685418)"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       id="linearGradient14219"
 | 
			
		||||
       xlink:href="#linearGradient15404"
 | 
			
		||||
       inkscape:collect="always" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       id="linearGradient10013-4-63-6">
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#333333;stop-opacity:1;"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         id="stop10015-2-76-1" />
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#292929;stop-opacity:1"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         id="stop10017-46-15-8" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       id="linearGradient10597-5">
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#16191a;stop-opacity:1;"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         id="stop10599-2" />
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#2b3133;stop-opacity:1"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         id="stop10601-5" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       y2="-322.16354"
 | 
			
		||||
       x2="921.22498"
 | 
			
		||||
       y1="-330.05121"
 | 
			
		||||
       x1="921.32812"
 | 
			
		||||
       gradientTransform="matrix(1.5918367,0,0,0.85714285,-1456.5464,275.45191)"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       id="linearGradient15374"
 | 
			
		||||
       xlink:href="#linearGradient10013-4-63-6"
 | 
			
		||||
       inkscape:collect="always" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       gradientTransform="translate(-1199.9852,216.38048)"
 | 
			
		||||
       y2="-227.07961"
 | 
			
		||||
       x2="1203.9177"
 | 
			
		||||
       y1="-217.56708"
 | 
			
		||||
       x1="1203.9177"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       id="linearGradient15376"
 | 
			
		||||
       xlink:href="#linearGradient10597-5"
 | 
			
		||||
       inkscape:collect="always" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#000000"
 | 
			
		||||
     bordercolor="#2d2d2d"
 | 
			
		||||
     borderopacity="1"
 | 
			
		||||
     inkscape:pageopacity="1"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="1"
 | 
			
		||||
     inkscape:cx="64.516955"
 | 
			
		||||
     inkscape:cy="13.871056"
 | 
			
		||||
     inkscape:document-units="px"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:window-width="1412"
 | 
			
		||||
     inkscape:window-height="1067"
 | 
			
		||||
     inkscape:window-x="2635"
 | 
			
		||||
     inkscape:window-y="226"
 | 
			
		||||
     inkscape:window-maximized="0"
 | 
			
		||||
     borderlayer="true"
 | 
			
		||||
     inkscape:showpageshadow="false"
 | 
			
		||||
     inkscape:snap-nodes="false"
 | 
			
		||||
     inkscape:snap-bbox="true"
 | 
			
		||||
     showborder="false">
 | 
			
		||||
    <inkscape:grid
 | 
			
		||||
       type="xygrid"
 | 
			
		||||
       id="grid14843"
 | 
			
		||||
       empspacing="5"
 | 
			
		||||
       visible="true"
 | 
			
		||||
       enabled="true"
 | 
			
		||||
       snapvisiblegridlinesonly="true" />
 | 
			
		||||
  </sodipodi:namedview>
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata3204">
 | 
			
		||||
    <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(-342.5,-521.36218)">
 | 
			
		||||
    <g
 | 
			
		||||
       transform="matrix(0.84337,0,0,0.84337,-110.16632,-503.56182)"
 | 
			
		||||
       id="g14586">
 | 
			
		||||
      <g
 | 
			
		||||
         inkscape:export-ydpi="90"
 | 
			
		||||
         inkscape:export-xdpi="90"
 | 
			
		||||
         inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
 | 
			
		||||
         transform="matrix(1.9969286,0,0,1.9969286,-397.05491,877.00482)"
 | 
			
		||||
         id="g15291-9"
 | 
			
		||||
         style="display:inline;enable-background:new">
 | 
			
		||||
        <g
 | 
			
		||||
           transform="translate(877.50354,-102.83507)"
 | 
			
		||||
           id="g16853-4"
 | 
			
		||||
           style="enable-background:new">
 | 
			
		||||
          <rect
 | 
			
		||||
             transform="scale(1,-1)"
 | 
			
		||||
             style="color:#000000;fill:url(#linearGradient14219);fill-opacity:1;fill-rule:nonzero;stroke:#868686;stroke-width:0.59377144999999998;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:new"
 | 
			
		||||
             id="rect6506-6"
 | 
			
		||||
             width="11.281681"
 | 
			
		||||
             height="11.26221"
 | 
			
		||||
             x="-409.59354"
 | 
			
		||||
             y="-284.40115"
 | 
			
		||||
             rx="0.95632279"
 | 
			
		||||
             ry="0.95632273" />
 | 
			
		||||
        </g>
 | 
			
		||||
      </g>
 | 
			
		||||
      <g
 | 
			
		||||
         inkscape:export-ydpi="90"
 | 
			
		||||
         inkscape:export-xdpi="90"
 | 
			
		||||
         inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
 | 
			
		||||
         transform="translate(343.99999,987.99997)"
 | 
			
		||||
         id="g5886"
 | 
			
		||||
         style="display:inline;enable-background:new">
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;stroke:url(#linearGradient5891-0-4);stroke-width:7.11431503;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
 | 
			
		||||
           d="m 198.5,240 5.25,5.25 13.98616,-14.43081"
 | 
			
		||||
           id="path5835"
 | 
			
		||||
           inkscape:path-effect="#path-effect5837-4-6"
 | 
			
		||||
           inkscape:original-d="m 198.5,240 5.25,5.25 13.98616,-14.43081"
 | 
			
		||||
           inkscape:connector-curvature="0"
 | 
			
		||||
           sodipodi:nodetypes="ccc" />
 | 
			
		||||
        <path
 | 
			
		||||
           inkscape:connector-curvature="0"
 | 
			
		||||
           inkscape:original-d="m 198.5,240 5.25,5.25 13.91205,-14.31964"
 | 
			
		||||
           inkscape:path-effect="#path-effect5837-4-6"
 | 
			
		||||
           id="path5880"
 | 
			
		||||
           d="m 198.5,240 5.25,5.25 13.91205,-14.31964"
 | 
			
		||||
           style="fill:none;stroke:#4787c8;stroke-width:3.55715752;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
 | 
			
		||||
           sodipodi:nodetypes="ccc" />
 | 
			
		||||
        <path
 | 
			
		||||
           style="fill:none;stroke:#7ea7d3;stroke-width:1.18571913px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
           d="m 197.45937,240.47455 c -0.17828,-0.29362 -0.20087,-0.67548 -0.0603,-0.98892 0.14055,-0.31344 0.43739,-0.54812 0.77144,-0.62817 0.33405,-0.08 0.69314,-0.01 0.99635,0.15175 0.30321,0.16144 0.55146,0.40727 0.79165,0.65284 l 3.66429,3.74643 12.87946,-12.98973 c 0.20796,-0.20974 0.42306,-0.41969 0.68548,-0.55522 0.26242,-0.13553 0.57293,-0.19052 0.85827,-0.11426 0.14267,0.0381 0.27708,0.10787 0.38874,0.20452 0.11167,0.0966 0.20021,0.22004 0.25479,0.35726 0.0546,0.13722 0.075,0.28793 0.0585,0.43468 -0.0165,0.14674 -0.07,0.28919 -0.15422,0.41052"
 | 
			
		||||
           id="path5882"
 | 
			
		||||
           inkscape:path-effect="#path-effect5884-4-7"
 | 
			
		||||
           inkscape:original-d="m 197.45937,240.47455 c 0.65604,-0.56057 2.02485,-1.34847 2.49911,-0.8125 l 3.66429,3.74643 12.87946,-12.98973 c 0.6875,-0.6875 2.09152,0.7375 2.09152,0.7375"
 | 
			
		||||
           inkscape:connector-curvature="0"
 | 
			
		||||
           sodipodi:nodetypes="csccc" />
 | 
			
		||||
      </g>
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 8.8 KiB  | 
@@ -1,161 +0,0 @@
 | 
			
		||||
/* 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-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-prompt-layout {
 | 
			
		||||
    padding-bottom: 64px;
 | 
			
		||||
}
 | 
			
		||||
.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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										130
									
								
								data/theme/logged-in-indicator.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,130 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
 | 
			
		||||
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:xlink="http://www.w3.org/1999/xlink"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   width="300"
 | 
			
		||||
   height="80"
 | 
			
		||||
   id="svg7355"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.48.2 r9819"
 | 
			
		||||
   sodipodi:docname="logged-in-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="1440"
 | 
			
		||||
     inkscape:window-height="843"
 | 
			
		||||
     id="namedview4173"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:zoom="2.8760889"
 | 
			
		||||
     inkscape:cx="106.00403"
 | 
			
		||||
     inkscape:cy="80.68078"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="27"
 | 
			
		||||
     inkscape:window-maximized="1"
 | 
			
		||||
     inkscape:current-layer="g30864" />
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs7357">
 | 
			
		||||
    <radialGradient
 | 
			
		||||
       xlink:href="#linearGradient36429"
 | 
			
		||||
       id="radialGradient7461"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       gradientTransform="matrix(2.5919312,0,0,0.57582113,-20.687059,48.400487)"
 | 
			
		||||
       cx="47.428951"
 | 
			
		||||
       cy="167.16817"
 | 
			
		||||
       fx="47.428951"
 | 
			
		||||
       fy="167.16817"
 | 
			
		||||
       r="37" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       id="linearGradient36429">
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop36431"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         style="stop-color:#ffffff;stop-opacity:1;" />
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop36433"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         style="stop-color:#ffffff;stop-opacity:0;" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <radialGradient
 | 
			
		||||
       xlink:href="#linearGradient36471"
 | 
			
		||||
       id="radialGradient7463"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       gradientTransform="matrix(1.1891549,0,0,0.55513246,-9.281289,36.12653)"
 | 
			
		||||
       cx="49.067139"
 | 
			
		||||
       cy="242.50381"
 | 
			
		||||
       fx="49.067139"
 | 
			
		||||
       fy="242.50381"
 | 
			
		||||
       r="37.00671" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       id="linearGradient36471">
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop36473"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         style="stop-color:#ffffff;stop-opacity:1;" />
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop36475"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         style="stop-color:#ffffff;stop-opacity:0;" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <radialGradient
 | 
			
		||||
       r="37.00671"
 | 
			
		||||
       fy="242.50381"
 | 
			
		||||
       fx="49.067139"
 | 
			
		||||
       cy="242.50381"
 | 
			
		||||
       cx="49.067139"
 | 
			
		||||
       gradientTransform="matrix(3.4218418,0,0,0.03365337,-61.309005,138.5071)"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       id="radialGradient7488"
 | 
			
		||||
       xlink:href="#linearGradient36471" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <g
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     transform="matrix(1.6213276,0,0,1.6213276,-431.6347,-272.5745)">
 | 
			
		||||
    <g
 | 
			
		||||
       style="display:inline"
 | 
			
		||||
       id="g30864"
 | 
			
		||||
       transform="translate(255.223,70.118091)">
 | 
			
		||||
      <rect
 | 
			
		||||
         ry="3.4593496"
 | 
			
		||||
         rx="8.8641119"
 | 
			
		||||
         y="76.159348"
 | 
			
		||||
         x="12.596948"
 | 
			
		||||
         height="71.116341"
 | 
			
		||||
         width="182.22595"
 | 
			
		||||
         id="rect14000"
 | 
			
		||||
         style="opacity:0.371875;fill:url(#radialGradient7461);fill-opacity:1;stroke:none" />
 | 
			
		||||
      <path
 | 
			
		||||
         id="rect34520"
 | 
			
		||||
         d="m 194.80022,146.83551 -182.559919,0"
 | 
			
		||||
         style="opacity:0.35;fill:none;stroke:url(#radialGradient7488);stroke-width:0.61184424;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
 | 
			
		||||
         connector-curvature="0"
 | 
			
		||||
         inkscape:connector-curvature="0"
 | 
			
		||||
         sodipodi:nodetypes="cc" />
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 3.8 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								data/theme/noise-texture.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 78 KiB  | 
@@ -1,33 +0,0 @@
 | 
			
		||||
<?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>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 787 B  | 
@@ -9,7 +9,7 @@
 | 
			
		||||
   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"
 | 
			
		||||
   width="17"
 | 
			
		||||
   height="10"
 | 
			
		||||
   id="svg2"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
@@ -66,9 +66,9 @@
 | 
			
		||||
    <rect
 | 
			
		||||
       style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
       id="rect3796"
 | 
			
		||||
       width="3"
 | 
			
		||||
       width="7"
 | 
			
		||||
       height="2"
 | 
			
		||||
       x="9"
 | 
			
		||||
       x="5"
 | 
			
		||||
       y="8" />
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
 
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB  | 
@@ -1,64 +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: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="10"
 | 
			
		||||
   height="4"
 | 
			
		||||
   id="svg2"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.47 r22583"
 | 
			
		||||
   sodipodi:docname="scroll-hhandle.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs4">
 | 
			
		||||
  </defs>
 | 
			
		||||
  <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 />
 | 
			
		||||
      </cc:Work>
 | 
			
		||||
    </rdf:RDF>
 | 
			
		||||
  </metadata>
 | 
			
		||||
  <g
 | 
			
		||||
     inkscape:label="Layer 1"
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     id="layer1">
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#323232;fill-opacity:1;fill-rule:evenodd;stroke:none"
 | 
			
		||||
       id="rect3592"
 | 
			
		||||
       width="2"
 | 
			
		||||
       height="4"
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="0"
 | 
			
		||||
       rx="0"
 | 
			
		||||
       ry="0" />
 | 
			
		||||
    <use
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="0"
 | 
			
		||||
       xlink:href="#rect3592"
 | 
			
		||||
       id="use2825"
 | 
			
		||||
       transform="translate(8,0)"
 | 
			
		||||
       width="10"
 | 
			
		||||
       height="4" />
 | 
			
		||||
    <use
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="0"
 | 
			
		||||
       xlink:href="#use2825"
 | 
			
		||||
       id="use2827"
 | 
			
		||||
       transform="translate(-4,0)"
 | 
			
		||||
       width="10"
 | 
			
		||||
       height="4" />
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 1.6 KiB  | 
@@ -1,62 +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: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="4"
 | 
			
		||||
   height="10"
 | 
			
		||||
   id="svg2"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.47 r22583"
 | 
			
		||||
   sodipodi:docname="scroll-hhandle.svg">
 | 
			
		||||
  <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="fill:#323232;fill-opacity:1;fill-rule:evenodd;stroke:none"
 | 
			
		||||
       id="rect3592"
 | 
			
		||||
       width="2"
 | 
			
		||||
       height="4"
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="-4"
 | 
			
		||||
       rx="0"
 | 
			
		||||
       ry="0"
 | 
			
		||||
       transform="matrix(0,1,-1,0,0,0)" />
 | 
			
		||||
    <use
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="0"
 | 
			
		||||
       xlink:href="#rect3592"
 | 
			
		||||
       id="use3705"
 | 
			
		||||
       transform="translate(0,4)"
 | 
			
		||||
       width="4"
 | 
			
		||||
       height="10" />
 | 
			
		||||
    <use
 | 
			
		||||
       x="0"
 | 
			
		||||
       y="0"
 | 
			
		||||
       xlink:href="#use3705"
 | 
			
		||||
       id="use3707"
 | 
			
		||||
       transform="translate(0,4)"
 | 
			
		||||
       width="4"
 | 
			
		||||
       height="10" />
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 1.6 KiB  | 
@@ -9,7 +9,7 @@
 | 
			
		||||
   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="64"
 | 
			
		||||
   width="65"
 | 
			
		||||
   height="22"
 | 
			
		||||
   id="svg3273"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
 
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB  | 
@@ -9,7 +9,7 @@
 | 
			
		||||
   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="64"
 | 
			
		||||
   width="65"
 | 
			
		||||
   height="22"
 | 
			
		||||
   id="svg3012"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
 
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 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
 | 
			
		||||
							
								
								
									
										117
									
								
								docs/reference/shell/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,117 @@
 | 
			
		||||
## 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
 | 
			
		||||
# gtk-doc will search all .c and .h files beneath these paths
 | 
			
		||||
# for inline comments documenting functions and macros.
 | 
			
		||||
DOC_SOURCE_DIR=$(top_srcdir)/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					\
 | 
			
		||||
	gactionmuxer.h				\
 | 
			
		||||
	gactionobservable.h			\
 | 
			
		||||
	gactionobserver.h			\
 | 
			
		||||
	shell-recorder-src.h
 | 
			
		||||
 | 
			
		||||
if !BUILD_RECORDER
 | 
			
		||||
IGNORE_HFILES += shell-recorder.h
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# 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) $(BLUETOOTH_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>
 | 
			
		||||
							
								
								
									
										104
									
								
								docs/reference/st/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,104 @@
 | 
			
		||||
## 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
 | 
			
		||||
# gtk-doc will search all .c and .h files beneath these paths
 | 
			
		||||
# for inline comments documenting functions and macros.
 | 
			
		||||
DOC_SOURCE_DIR=$(top_srcdir)/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
 | 
			
		||||
							
								
								
									
										64
									
								
								docs/reference/st/st-docs.sgml.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,64 @@
 | 
			
		||||
<?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-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"/>
 | 
			
		||||
    </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-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>
 | 
			
		||||
@@ -66,4 +66,11 @@ its dependencies to build from tarballs.</description>
 | 
			
		||||
      <gnome:userid>marinaz</gnome:userid>
 | 
			
		||||
    </foaf:Person>
 | 
			
		||||
  </maintainer>
 | 
			
		||||
  <maintainer>
 | 
			
		||||
    <foaf:Person>
 | 
			
		||||
      <foaf:name>Florian Müllner</foaf:name>
 | 
			
		||||
      <foaf:mbox rdf:resource="mailto:fmuellner@gnome.org" />
 | 
			
		||||
      <gnome:userid>fmuellner</gnome:userid>
 | 
			
		||||
    </foaf:Person>
 | 
			
		||||
  </maintainer>
 | 
			
		||||
</Project>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,37 @@
 | 
			
		||||
 | 
			
		||||
EXTRA_DIST = misc/config.js.in
 | 
			
		||||
CLEANFILES = misc/config.js
 | 
			
		||||
 | 
			
		||||
misc/config.js: misc/config.js.in Makefile
 | 
			
		||||
	[ -d $(@D) ] || $(mkdir_p) $(@D) ; \
 | 
			
		||||
	sed -e "s|[@]PACKAGE_NAME@|$(PACKAGE_NAME)|g" \
 | 
			
		||||
	    -e "s|[@]PACKAGE_VERSION@|$(PACKAGE_VERSION)|g" \
 | 
			
		||||
	    -e "s|[@]HAVE_BLUETOOTH@|$(HAVE_BLUETOOTH)|g" \
 | 
			
		||||
	    -e "s|[@]GETTEXT_PACKAGE@|$(GETTEXT_PACKAGE)|g" \
 | 
			
		||||
	    -e "s|[@]datadir@|$(datadir)|g" \
 | 
			
		||||
	    -e "s|[@]libexecdir@|$(libexecdir)|g" \
 | 
			
		||||
	    -e "s|[@]sysconfdir@|$(sysconfdir)|g" \
 | 
			
		||||
               $< > $@
 | 
			
		||||
 | 
			
		||||
jsdir = $(pkgdatadir)/js
 | 
			
		||||
 | 
			
		||||
nobase_dist_js_DATA = 	\
 | 
			
		||||
	gdm/batch.js		\
 | 
			
		||||
	gdm/consoleKit.js	\
 | 
			
		||||
	gdm/fingerprint.js	\
 | 
			
		||||
	gdm/loginDialog.js	\
 | 
			
		||||
	gdm/powerMenu.js	\
 | 
			
		||||
	gdm/systemd.js	 	\
 | 
			
		||||
	gdm/util.js		\
 | 
			
		||||
	extensionPrefs/main.js	\
 | 
			
		||||
	misc/config.js		\
 | 
			
		||||
	misc/docInfo.js		\
 | 
			
		||||
	misc/extensionUtils.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		\
 | 
			
		||||
@@ -22,20 +41,22 @@ nobase_dist_js_DATA = 	\
 | 
			
		||||
	ui/autorunManager.js    \
 | 
			
		||||
	ui/boxpointer.js	\
 | 
			
		||||
	ui/calendar.js		\
 | 
			
		||||
	ui/contactDisplay.js \
 | 
			
		||||
	ui/checkBox.js		\
 | 
			
		||||
	ui/ctrlAltTab.js	\
 | 
			
		||||
	ui/dash.js		\
 | 
			
		||||
	ui/dateMenu.js		\
 | 
			
		||||
	ui/dnd.js		\
 | 
			
		||||
	ui/docDisplay.js	\
 | 
			
		||||
	ui/endSessionDialog.js	\
 | 
			
		||||
	ui/environment.js	\
 | 
			
		||||
	ui/extensionSystem.js	\
 | 
			
		||||
	ui/extensionDownloader.js \
 | 
			
		||||
	ui/flashspot.js		\
 | 
			
		||||
	ui/ibusCandidatePopup.js\
 | 
			
		||||
	ui/iconGrid.js		\
 | 
			
		||||
	ui/keyboard.js		\
 | 
			
		||||
	ui/keyringPrompt.js	\
 | 
			
		||||
	ui/layout.js		\
 | 
			
		||||
	ui/lightbox.js		\
 | 
			
		||||
	ui/link.js		\
 | 
			
		||||
	ui/lookingGlass.js	\
 | 
			
		||||
	ui/magnifier.js		\
 | 
			
		||||
	ui/magnifierDBus.js	\
 | 
			
		||||
@@ -43,6 +64,8 @@ nobase_dist_js_DATA = 	\
 | 
			
		||||
	ui/messageTray.js	\
 | 
			
		||||
	ui/modalDialog.js	\
 | 
			
		||||
	ui/networkAgent.js	\
 | 
			
		||||
	ui/sessionMode.js	\
 | 
			
		||||
	ui/shellEntry.js	\
 | 
			
		||||
	ui/shellMountOperation.js \
 | 
			
		||||
	ui/notificationDaemon.js \
 | 
			
		||||
	ui/overview.js		\
 | 
			
		||||
@@ -51,12 +74,13 @@ nobase_dist_js_DATA = 	\
 | 
			
		||||
	ui/placeDisplay.js	\
 | 
			
		||||
	ui/polkitAuthenticationAgent.js \
 | 
			
		||||
	ui/popupMenu.js		\
 | 
			
		||||
	ui/remoteSearch.js	\
 | 
			
		||||
	ui/runDialog.js		\
 | 
			
		||||
        ui/screenShield.js	\
 | 
			
		||||
	ui/scripting.js		\
 | 
			
		||||
	ui/search.js		\
 | 
			
		||||
	ui/searchDisplay.js	\
 | 
			
		||||
	ui/shellDBus.js		\
 | 
			
		||||
	ui/statusIconDispatcher.js	\
 | 
			
		||||
	ui/status/accessibility.js	\
 | 
			
		||||
	ui/status/keyboard.js	\
 | 
			
		||||
	ui/status/network.js	\
 | 
			
		||||
@@ -65,8 +89,10 @@ nobase_dist_js_DATA = 	\
 | 
			
		||||
	ui/status/bluetooth.js	\
 | 
			
		||||
	ui/telepathyClient.js	\
 | 
			
		||||
	ui/tweener.js		\
 | 
			
		||||
	ui/unlockDialog.js	\
 | 
			
		||||
	ui/userMenu.js		\
 | 
			
		||||
	ui/viewSelector.js	\
 | 
			
		||||
	ui/wanda.js		\
 | 
			
		||||
	ui/windowAttentionHandler.js	\
 | 
			
		||||
	ui/windowManager.js	\
 | 
			
		||||
	ui/workspace.js		\
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										270
									
								
								js/extensionPrefs/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,270 @@
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Gettext = imports.gettext;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const GObject = imports.gi.GObject;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
const Pango = imports.gi.Pango;
 | 
			
		||||
const Format = imports.format;
 | 
			
		||||
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
 | 
			
		||||
const Config = imports.misc.config;
 | 
			
		||||
const ExtensionUtils = imports.misc.extensionUtils;
 | 
			
		||||
 | 
			
		||||
const GnomeShellIface = <interface name="org.gnome.Shell.Extensions">
 | 
			
		||||
<signal name="ExtensionStatusChanged">
 | 
			
		||||
    <arg type="s" name="uuid"/>
 | 
			
		||||
    <arg type="i" name="state"/>
 | 
			
		||||
    <arg type="s" name="error"/>
 | 
			
		||||
</signal>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
 | 
			
		||||
 | 
			
		||||
function stripPrefix(string, prefix) {
 | 
			
		||||
    if (string.slice(0, prefix.length) == prefix)
 | 
			
		||||
        return string.slice(prefix.length);
 | 
			
		||||
    return string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Application = new Lang.Class({
 | 
			
		||||
    Name: 'Application',
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        GLib.set_prgname('gnome-shell-extension-prefs');
 | 
			
		||||
        this.application = new Gtk.Application({
 | 
			
		||||
            application_id: 'org.gnome.shell.ExtensionPrefs',
 | 
			
		||||
            flags: Gio.ApplicationFlags.HANDLES_COMMAND_LINE
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.application.connect('activate', Lang.bind(this, this._onActivate));
 | 
			
		||||
        this.application.connect('command-line', Lang.bind(this, this._onCommandLine));
 | 
			
		||||
        this.application.connect('startup', Lang.bind(this, this._onStartup));
 | 
			
		||||
 | 
			
		||||
        this._extensionPrefsModules = {};
 | 
			
		||||
 | 
			
		||||
        this._extensionIters = {};
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _buildModel: function() {
 | 
			
		||||
        this._model = new Gtk.ListStore();
 | 
			
		||||
        this._model.set_column_types([GObject.TYPE_STRING, GObject.TYPE_STRING]);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _extensionAvailable: function(uuid) {
 | 
			
		||||
        let extension = ExtensionUtils.extensions[uuid];
 | 
			
		||||
 | 
			
		||||
        if (!extension)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (ExtensionUtils.isOutOfDate(extension))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (!extension.dir.get_child('prefs.js').query_exists(null))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setExtensionInsensitive: function(layout, cell, model, iter, data) {
 | 
			
		||||
        let uuid = model.get_value(iter, 0);
 | 
			
		||||
        cell.set_sensitive(this._extensionAvailable(uuid));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getExtensionPrefsModule: function(extension) {
 | 
			
		||||
        let uuid = extension.metadata.uuid;
 | 
			
		||||
 | 
			
		||||
        if (this._extensionPrefsModules.hasOwnProperty(uuid))
 | 
			
		||||
            return this._extensionPrefsModules[uuid];
 | 
			
		||||
 | 
			
		||||
        ExtensionUtils.installImporter(extension);
 | 
			
		||||
 | 
			
		||||
        let prefsModule = extension.imports.prefs;
 | 
			
		||||
        prefsModule.init(extension.metadata);
 | 
			
		||||
 | 
			
		||||
        this._extensionPrefsModules[uuid] = prefsModule;
 | 
			
		||||
        return prefsModule;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _selectExtension: function(uuid) {
 | 
			
		||||
        if (!this._extensionAvailable(uuid))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let extension = ExtensionUtils.extensions[uuid];
 | 
			
		||||
        let widget;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            let prefsModule = this._getExtensionPrefsModule(extension);
 | 
			
		||||
            widget = prefsModule.buildPrefsWidget();
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            widget = this._buildErrorUI(extension, e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Destroy the current prefs widget, if it exists
 | 
			
		||||
        if (this._extensionPrefsBin.get_child())
 | 
			
		||||
            this._extensionPrefsBin.get_child().destroy();
 | 
			
		||||
 | 
			
		||||
        this._extensionPrefsBin.add(widget);
 | 
			
		||||
        this._extensionSelector.set_active_iter(this._extensionIters[uuid]);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _extensionSelected: function() {
 | 
			
		||||
        let [success, iter] = this._extensionSelector.get_active_iter();
 | 
			
		||||
        if (!success)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let uuid = this._model.get_value(iter, 0);
 | 
			
		||||
        this._selectExtension(uuid);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _buildErrorUI: function(extension, exc) {
 | 
			
		||||
        let box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
 | 
			
		||||
        let label = new Gtk.Label({
 | 
			
		||||
            label: _("There was an error loading the preferences dialog for %s:").format(extension.metadata.name)
 | 
			
		||||
        });
 | 
			
		||||
        box.add(label);
 | 
			
		||||
 | 
			
		||||
        let errortext = '';
 | 
			
		||||
        errortext += exc;
 | 
			
		||||
        errortext += '\n\n';
 | 
			
		||||
        errortext += 'Stack trace:\n';
 | 
			
		||||
 | 
			
		||||
        // Indent stack trace.
 | 
			
		||||
        errortext += exc.stack.split('\n').map(function(line) {
 | 
			
		||||
            return '  ' + line;
 | 
			
		||||
        }).join('\n');
 | 
			
		||||
 | 
			
		||||
        let scroll = new Gtk.ScrolledWindow({ vexpand: true });
 | 
			
		||||
        let buffer = new Gtk.TextBuffer({ text: errortext });
 | 
			
		||||
        let textview = new Gtk.TextView({ buffer: buffer });
 | 
			
		||||
        textview.override_font(Pango.font_description_from_string('monospace'));
 | 
			
		||||
        scroll.add(textview);
 | 
			
		||||
        box.add(scroll);
 | 
			
		||||
 | 
			
		||||
        box.show_all();
 | 
			
		||||
        return box;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _buildUI: function(app) {
 | 
			
		||||
        this._window = new Gtk.ApplicationWindow({ application: app,
 | 
			
		||||
                                                   window_position: Gtk.WindowPosition.CENTER,
 | 
			
		||||
                                                   title: _("GNOME Shell Extension Preferences") });
 | 
			
		||||
 | 
			
		||||
        this._window.set_size_request(600, 400);
 | 
			
		||||
 | 
			
		||||
        let vbox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
 | 
			
		||||
        this._window.add(vbox);
 | 
			
		||||
 | 
			
		||||
        let toolbar = new Gtk.Toolbar();
 | 
			
		||||
        toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR);
 | 
			
		||||
        vbox.add(toolbar);
 | 
			
		||||
        let toolitem;
 | 
			
		||||
 | 
			
		||||
        let label = new Gtk.Label({ label: '<b>' + _("Extension") + '</b>',
 | 
			
		||||
                                    use_markup: true });
 | 
			
		||||
        toolitem = new Gtk.ToolItem({ child: label });
 | 
			
		||||
        toolbar.add(toolitem);
 | 
			
		||||
 | 
			
		||||
        this._extensionSelector = new Gtk.ComboBox({ model: this._model,
 | 
			
		||||
                                                     margin_left: 8,
 | 
			
		||||
                                                     hexpand: true });
 | 
			
		||||
        this._extensionSelector.get_style_context().add_class(Gtk.STYLE_CLASS_RAISED);
 | 
			
		||||
 | 
			
		||||
        let renderer = new Gtk.CellRendererText();
 | 
			
		||||
        this._extensionSelector.pack_start(renderer, true);
 | 
			
		||||
        this._extensionSelector.add_attribute(renderer, 'text', 1);
 | 
			
		||||
        this._extensionSelector.set_cell_data_func(renderer, Lang.bind(this, this._setExtensionInsensitive), null);
 | 
			
		||||
        this._extensionSelector.connect('changed', Lang.bind(this, this._extensionSelected));
 | 
			
		||||
 | 
			
		||||
        toolitem = new Gtk.ToolItem({ child: this._extensionSelector });
 | 
			
		||||
        toolitem.set_expand(true);
 | 
			
		||||
        toolbar.add(toolitem);
 | 
			
		||||
 | 
			
		||||
        this._extensionPrefsBin = new Gtk.Frame();
 | 
			
		||||
        vbox.add(this._extensionPrefsBin);
 | 
			
		||||
 | 
			
		||||
        let label = new Gtk.Label({
 | 
			
		||||
            label: _("Select an extension to configure using the combobox above."),
 | 
			
		||||
            vexpand: true
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._extensionPrefsBin.add(label);
 | 
			
		||||
 | 
			
		||||
        this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
 | 
			
		||||
        this._shellProxy.connectSignal('ExtensionStatusChanged', Lang.bind(this, function(proxy, senderName, [uuid, state, error]) {
 | 
			
		||||
            if (ExtensionUtils.extensions[uuid] !== undefined)
 | 
			
		||||
                this._scanExtensions();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        this._window.show_all();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _scanExtensions: function() {
 | 
			
		||||
        let finder = new ExtensionUtils.ExtensionFinder();
 | 
			
		||||
        finder.connect('extension-found', Lang.bind(this, this._extensionFound));
 | 
			
		||||
        finder.scanExtensions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _extensionFound: function(signals, extension) {
 | 
			
		||||
        let iter = this._model.append();
 | 
			
		||||
        this._model.set(iter, [0, 1], [extension.uuid, extension.metadata.name]);
 | 
			
		||||
        this._extensionIters[extension.uuid] = iter;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    _onActivate: function() {
 | 
			
		||||
        this._window.present();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onStartup: function(app) {
 | 
			
		||||
        this._buildModel();
 | 
			
		||||
        this._buildUI(app);
 | 
			
		||||
        this._scanExtensions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onCommandLine: function(app, commandLine) {
 | 
			
		||||
        app.activate();
 | 
			
		||||
        let args = commandLine.get_arguments();
 | 
			
		||||
        if (args.length) {
 | 
			
		||||
            let uuid = args[0];
 | 
			
		||||
 | 
			
		||||
            // Strip off "extension:///" prefix which fakes a URI, if it exists
 | 
			
		||||
            uuid = stripPrefix(uuid, "extension:///");
 | 
			
		||||
 | 
			
		||||
            if (!this._extensionAvailable(uuid))
 | 
			
		||||
                return 1;
 | 
			
		||||
 | 
			
		||||
            this._selectExtension(uuid);
 | 
			
		||||
        }
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function initEnvironment() {
 | 
			
		||||
    // Monkey-patch in a "global" object that fakes some Shell utilities
 | 
			
		||||
    // that ExtensionUtils depends on.
 | 
			
		||||
    window.global = {
 | 
			
		||||
        log: function() {
 | 
			
		||||
            print([].join.call(arguments, ', '));
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        logError: function(s) {
 | 
			
		||||
            log('ERROR: ' + s);
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        userdatadir: GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell'])
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    String.prototype.format = Format.format;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function main(argv) {
 | 
			
		||||
    initEnvironment();
 | 
			
		||||
 | 
			
		||||
    Gettext.bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
 | 
			
		||||
    Gettext.textdomain(Config.GETTEXT_PACKAGE);
 | 
			
		||||
 | 
			
		||||
    let app = new Application();
 | 
			
		||||
    app.application.run(argv);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 *
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2011 Red Hat, Inc
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
@@ -21,11 +21,9 @@
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
function Task() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
const Task = new Lang.Class({
 | 
			
		||||
    Name: 'Task',
 | 
			
		||||
 | 
			
		||||
Task.prototype = {
 | 
			
		||||
    _init: function(scope, handler) {
 | 
			
		||||
        if (scope)
 | 
			
		||||
            this.scope = scope;
 | 
			
		||||
@@ -41,22 +39,17 @@ Task.prototype = {
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(Task.prototype);
 | 
			
		||||
 | 
			
		||||
function Hold() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Hold.prototype = {
 | 
			
		||||
    __proto__: Task.prototype,
 | 
			
		||||
const Hold = new Lang.Class({
 | 
			
		||||
    Name: 'Hold',
 | 
			
		||||
    Extends: Task,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        Task.prototype._init.call(this,
 | 
			
		||||
                                  this,
 | 
			
		||||
                                  function () {
 | 
			
		||||
                                      return this;
 | 
			
		||||
                                  });
 | 
			
		||||
        this.parent(this, function () {
 | 
			
		||||
            return this;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._acquisitions = 1;
 | 
			
		||||
    },
 | 
			
		||||
@@ -88,18 +81,15 @@ Hold.prototype = {
 | 
			
		||||
    isAcquired: function() {
 | 
			
		||||
        return this._acquisitions > 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(Hold.prototype);
 | 
			
		||||
 | 
			
		||||
function Batch() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Batch.prototype = {
 | 
			
		||||
    __proto__: Task.prototype,
 | 
			
		||||
const Batch = new Lang.Class({
 | 
			
		||||
    Name: 'Batch',
 | 
			
		||||
    Extends: Task,
 | 
			
		||||
 | 
			
		||||
    _init: function(scope, tasks) {
 | 
			
		||||
        Task.prototype._init.call(this);
 | 
			
		||||
        this.parent();
 | 
			
		||||
 | 
			
		||||
        this.tasks = [];
 | 
			
		||||
 | 
			
		||||
@@ -166,20 +156,12 @@ Batch.prototype = {
 | 
			
		||||
    cancel: function() {
 | 
			
		||||
        this.tasks = this.tasks.splice(0, this._currentTaskIndex + 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(Batch.prototype);
 | 
			
		||||
 | 
			
		||||
function ConcurrentBatch() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConcurrentBatch.prototype = {
 | 
			
		||||
    __proto__: Batch.prototype,
 | 
			
		||||
 | 
			
		||||
    _init: function(scope, tasks) {
 | 
			
		||||
        Batch.prototype._init.call(this, scope, tasks);
 | 
			
		||||
    },
 | 
			
		||||
const ConcurrentBatch = new Lang.Class({
 | 
			
		||||
    Name: 'ConcurrentBatch',
 | 
			
		||||
    Extends: Batch,
 | 
			
		||||
 | 
			
		||||
    process: function() {
 | 
			
		||||
       let hold = this.runTask();
 | 
			
		||||
@@ -193,19 +175,12 @@ ConcurrentBatch.prototype = {
 | 
			
		||||
       // concurrently.
 | 
			
		||||
       this.nextTask();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ConcurrentBatch.prototype);
 | 
			
		||||
 | 
			
		||||
function ConsecutiveBatch() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConsecutiveBatch.prototype = {
 | 
			
		||||
    __proto__: Batch.prototype,
 | 
			
		||||
 | 
			
		||||
    _init: function(scope, tasks) {
 | 
			
		||||
        Batch.prototype._init.call(this, scope, tasks);
 | 
			
		||||
    },
 | 
			
		||||
const ConsecutiveBatch = new Lang.Class({
 | 
			
		||||
    Name: 'ConsecutiveBatch',
 | 
			
		||||
    Extends: Batch,
 | 
			
		||||
 | 
			
		||||
    process: function() {
 | 
			
		||||
       let hold = this.runTask();
 | 
			
		||||
@@ -224,5 +199,5 @@ ConsecutiveBatch.prototype = {
 | 
			
		||||
           this.nextTask();
 | 
			
		||||
       }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ConsecutiveBatch.prototype);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								js/gdm/consoleKit.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -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');
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										27
									
								
								js/gdm/fingerprint.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,27 @@
 | 
			
		||||
// -*- 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 FprintManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(FprintManagerIface);
 | 
			
		||||
 | 
			
		||||
function FprintManager() {
 | 
			
		||||
    var self = new Gio.DBusProxy({ g_connection: Gio.DBus.system,
 | 
			
		||||
                                   g_interface_name: FprintManagerInfo.name,
 | 
			
		||||
                                   g_interface_info: FprintManagerInfo,
 | 
			
		||||
                                   g_name: 'net.reactivated.Fprint',
 | 
			
		||||
                                   g_object_path: '/net/reactivated/Fprint/Manager',
 | 
			
		||||
                                   g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
 | 
			
		||||
                                             Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
 | 
			
		||||
 | 
			
		||||
    self.init(null);
 | 
			
		||||
    return self;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 *
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2011 Red Hat, Inc
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
@@ -30,74 +30,23 @@ const Pango = imports.gi.Pango;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const GdmGreeter = imports.gi.GdmGreeter;
 | 
			
		||||
const Gdm = imports.gi.Gdm;
 | 
			
		||||
 | 
			
		||||
const Batch = imports.misc.batch;
 | 
			
		||||
const Batch = imports.gdm.batch;
 | 
			
		||||
const Fprint = imports.gdm.fingerprint;
 | 
			
		||||
const GdmUtil = imports.gdm.util;
 | 
			
		||||
const Lightbox = imports.ui.lightbox;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
const _FADE_ANIMATION_TIME = 0.16;
 | 
			
		||||
const _RESIZE_ANIMATION_TIME = 0.25;
 | 
			
		||||
const _SCROLL_ANIMATION_TIME = 2.0;
 | 
			
		||||
const _SCROLL_ANIMATION_TIME = 0.5;
 | 
			
		||||
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
 | 
			
		||||
const _LOGO_ICON_NAME_SIZE = 48;
 | 
			
		||||
 | 
			
		||||
let _loginDialog = null;
 | 
			
		||||
 | 
			
		||||
function _fadeInActor(actor) {
 | 
			
		||||
    let hold = new Batch.Hold();
 | 
			
		||||
 | 
			
		||||
    if (actor.opacity == 255 && actor.visible)
 | 
			
		||||
        return null;
 | 
			
		||||
 | 
			
		||||
    actor.show();
 | 
			
		||||
    let [minHeight, naturalHeight] = actor.get_preferred_height(-1);
 | 
			
		||||
 | 
			
		||||
    actor.opacity = 0;
 | 
			
		||||
    actor.set_height(0);
 | 
			
		||||
    Tweener.addTween(actor,
 | 
			
		||||
                     { opacity: 255,
 | 
			
		||||
                       height: naturalHeight,
 | 
			
		||||
                       time: _FADE_ANIMATION_TIME,
 | 
			
		||||
                       transition: 'easeOutQuad',
 | 
			
		||||
                       onComplete: function() {
 | 
			
		||||
                           actor.set_height(-1);
 | 
			
		||||
                           hold.release();
 | 
			
		||||
                       },
 | 
			
		||||
                       onCompleteScope: this
 | 
			
		||||
                     });
 | 
			
		||||
    return hold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _fadeOutActor(actor) {
 | 
			
		||||
    let hold = new Batch.Hold();
 | 
			
		||||
 | 
			
		||||
    if (!actor.visible) {
 | 
			
		||||
        actor.opacity = 0;
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (actor.opacity == 0) {
 | 
			
		||||
        actor.hide();
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Tweener.addTween(actor,
 | 
			
		||||
                     { opacity: 0,
 | 
			
		||||
                       height: 0,
 | 
			
		||||
                       time: _FADE_ANIMATION_TIME,
 | 
			
		||||
                       transition: 'easeOutQuad',
 | 
			
		||||
                       onComplete: function() {
 | 
			
		||||
                           actor.hide();
 | 
			
		||||
                           actor.set_height(-1);
 | 
			
		||||
                           hold.release();
 | 
			
		||||
                       },
 | 
			
		||||
                       onCompleteScope: this
 | 
			
		||||
                     });
 | 
			
		||||
    return hold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _smoothlyResizeActor(actor, width, height) {
 | 
			
		||||
    let finalWidth;
 | 
			
		||||
    let finalHeight;
 | 
			
		||||
@@ -131,53 +80,45 @@ function _smoothlyResizeActor(actor, width, height) {
 | 
			
		||||
    return hold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function UserListItem(user, reason) {
 | 
			
		||||
    this._init(user, reason);
 | 
			
		||||
}
 | 
			
		||||
const UserListItem = new Lang.Class({
 | 
			
		||||
    Name: 'UserListItem',
 | 
			
		||||
 | 
			
		||||
UserListItem.prototype = {
 | 
			
		||||
    _init: function(user) {
 | 
			
		||||
        this.user = user;
 | 
			
		||||
        this._userChangedId = this.user.connect('changed',
 | 
			
		||||
                                                 Lang.bind(this, this._onUserChanged));
 | 
			
		||||
 | 
			
		||||
        this._verticalBox = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-vertical-layout',
 | 
			
		||||
                                               vertical: true });
 | 
			
		||||
 | 
			
		||||
        let layout = new St.BoxLayout({ vertical: false });
 | 
			
		||||
        this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
 | 
			
		||||
                                     can_focus: true,
 | 
			
		||||
                                     child: this._verticalBox,
 | 
			
		||||
                                     child: layout,
 | 
			
		||||
                                     reactive: true,
 | 
			
		||||
                                     x_align: St.Align.START,
 | 
			
		||||
                                     x_fill: true });
 | 
			
		||||
        let layout = new St.BoxLayout({ vertical: false });
 | 
			
		||||
 | 
			
		||||
        this._verticalBox.add(layout,
 | 
			
		||||
                              { y_fill: true,
 | 
			
		||||
                                x_fill: true,
 | 
			
		||||
                                expand: true });
 | 
			
		||||
 | 
			
		||||
        this._focusBin = new St.Bin({ style_class: 'login-dialog-user-list-item-focus-bin' });
 | 
			
		||||
        this._verticalBox.add(this._focusBin,
 | 
			
		||||
                              { x_fill: false,
 | 
			
		||||
                                x_align: St.Align.MIDDLE,
 | 
			
		||||
                                y_fill: false,
 | 
			
		||||
                                expand: true });
 | 
			
		||||
 | 
			
		||||
        this._iconBin = new St.Bin();
 | 
			
		||||
        layout.add(this._iconBin);
 | 
			
		||||
        let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
 | 
			
		||||
                                            vertical:    true });
 | 
			
		||||
        layout.add(textLayout,
 | 
			
		||||
                   { y_fill: false,
 | 
			
		||||
                     y_align: St.Align.MIDDLE,
 | 
			
		||||
                     expand: true });
 | 
			
		||||
        layout.add(textLayout, { expand: true });
 | 
			
		||||
 | 
			
		||||
        this._nameLabel = new St.Label({ text:        this.user.get_real_name(),
 | 
			
		||||
                                         style_class: 'login-dialog-user-list-item-name' });
 | 
			
		||||
        textLayout.add(this._nameLabel);
 | 
			
		||||
        textLayout.add(this._nameLabel,
 | 
			
		||||
                       { y_fill: false,
 | 
			
		||||
                         y_align: St.Align.MIDDLE,
 | 
			
		||||
                         expand: true });
 | 
			
		||||
 | 
			
		||||
        this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator',
 | 
			
		||||
                                                 scale_x: 0 });
 | 
			
		||||
        textLayout.add(this._timedLoginIndicator,
 | 
			
		||||
                       { x_fill: true,
 | 
			
		||||
                         x_align: St.Align.MIDDLE,
 | 
			
		||||
                         y_fill: false,
 | 
			
		||||
                         y_align: St.Align.END });
 | 
			
		||||
 | 
			
		||||
        this._updateIcon();
 | 
			
		||||
        this._updateLoggedIn();
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('clicked', Lang.bind(this, this._onClicked));
 | 
			
		||||
    },
 | 
			
		||||
@@ -185,6 +126,7 @@ UserListItem.prototype = {
 | 
			
		||||
    _onUserChanged: function() {
 | 
			
		||||
        this._nameLabel.set_text(this.user.get_real_name());
 | 
			
		||||
        this._updateIcon();
 | 
			
		||||
        this._updateLoggedIn();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setIconFromFile: function(iconFile, styleClass) {
 | 
			
		||||
@@ -198,7 +140,8 @@ UserListItem.prototype = {
 | 
			
		||||
            // We use background-image instead of, say, St.TextureCache
 | 
			
		||||
            // so the theme writers can add a rounded frame around the image
 | 
			
		||||
            // and so theme writers can pick the icon size.
 | 
			
		||||
            this._iconBin.set_style('background-image: url("' + iconFile + '");');
 | 
			
		||||
            this._iconBin.set_style('background-image: url("' + iconFile + '");' +
 | 
			
		||||
                                    'background-size: contain;');
 | 
			
		||||
        } else {
 | 
			
		||||
            this._iconBin.hide();
 | 
			
		||||
        }
 | 
			
		||||
@@ -231,27 +174,40 @@ UserListItem.prototype = {
 | 
			
		||||
            this._setIconFromName('avatar-default', 'login-dialog-user-list-item-icon');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    syncStyleClasses: function() {
 | 
			
		||||
        this._updateLoggedIn();
 | 
			
		||||
 | 
			
		||||
        if (global.stage.get_key_focus() == this.actor)
 | 
			
		||||
            this.actor.add_style_pseudo_class('focus');
 | 
			
		||||
        else
 | 
			
		||||
            this.actor.remove_style_pseudo_class('focus');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateLoggedIn: function() {
 | 
			
		||||
        if (this.user.is_logged_in())
 | 
			
		||||
            this.actor.add_style_pseudo_class('logged-in');
 | 
			
		||||
        else
 | 
			
		||||
            this.actor.remove_style_pseudo_class('logged-in');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onClicked: function() {
 | 
			
		||||
        this.emit('activate');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    fadeOutName: function() {
 | 
			
		||||
        return _fadeOutActor(this._nameLabel);
 | 
			
		||||
        return GdmUtil.fadeOutActor(this._nameLabel);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    fadeInName: function() {
 | 
			
		||||
        return _fadeInActor(this._nameLabel);
 | 
			
		||||
        return GdmUtil.fadeInActor(this._nameLabel);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    showFocusAnimation: function(time) {
 | 
			
		||||
    showTimedLoginIndicator: function(time) {
 | 
			
		||||
        let hold = new Batch.Hold();
 | 
			
		||||
 | 
			
		||||
        let box = this._verticalBox.get_allocation_box();
 | 
			
		||||
 | 
			
		||||
        Tweener.removeTweens(this._focusBin);
 | 
			
		||||
        this._focusBin.width = 0;
 | 
			
		||||
        Tweener.addTween(this._focusBin,
 | 
			
		||||
                         { width: box.x2 - box.x1,
 | 
			
		||||
        this.hideTimedLoginIndicator();
 | 
			
		||||
        Tweener.addTween(this._timedLoginIndicator,
 | 
			
		||||
                         { scale_x: 1.,
 | 
			
		||||
                           time: time,
 | 
			
		||||
                           transition: 'linear',
 | 
			
		||||
                           onComplete: function() {
 | 
			
		||||
@@ -260,35 +216,48 @@ UserListItem.prototype = {
 | 
			
		||||
                           onCompleteScope: this
 | 
			
		||||
                         });
 | 
			
		||||
        return hold;
 | 
			
		||||
    }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
    hideTimedLoginIndicator: function() {
 | 
			
		||||
        Tweener.removeTweens(this._timedLoginIndicator);
 | 
			
		||||
        this._timedLoginIndicator.scale_x = 0.;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(UserListItem.prototype);
 | 
			
		||||
 | 
			
		||||
function UserList() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
const UserList = new Lang.Class({
 | 
			
		||||
    Name: 'UserList',
 | 
			
		||||
 | 
			
		||||
UserList.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.actor = new St.ScrollView({ style_class: 'login-dialog-user-list-view'});
 | 
			
		||||
        this.actor.set_policy(Gtk.PolicyType.NEVER,
 | 
			
		||||
                              Gtk.PolicyType.AUTOMATIC);
 | 
			
		||||
 | 
			
		||||
        this._box = new St.BoxLayout({ vertical: true,
 | 
			
		||||
                                       style_class: 'login-dialog-user-list' });
 | 
			
		||||
                                       style_class: 'login-dialog-user-list',
 | 
			
		||||
                                       pseudo_class: 'expanded' });
 | 
			
		||||
 | 
			
		||||
        this.actor.add_actor(this._box,
 | 
			
		||||
                             { x_fill: true,
 | 
			
		||||
                               y_fill: true,
 | 
			
		||||
                               x_align: St.Align.START,
 | 
			
		||||
                               y_align: St.Align.MIDDLE });
 | 
			
		||||
        this.actor.add_actor(this._box);
 | 
			
		||||
        this._items = {};
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('key-focus-in', Lang.bind(this, this._moveFocusToItems));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _moveFocusToItems: function() {
 | 
			
		||||
        let hasItems = Object.keys(this._items).length > 0;
 | 
			
		||||
 | 
			
		||||
        if (!hasItems)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (global.stage.get_key_focus() != this.actor)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showItem: function(item) {
 | 
			
		||||
        let tasks = [function() {
 | 
			
		||||
                         return _fadeInActor(item.actor);
 | 
			
		||||
                         return GdmUtil.fadeInActor(item.actor);
 | 
			
		||||
                     },
 | 
			
		||||
 | 
			
		||||
                     function() {
 | 
			
		||||
@@ -345,17 +314,21 @@ UserList.prototype = {
 | 
			
		||||
        for (let userName in this._items) {
 | 
			
		||||
            let item = this._items[userName];
 | 
			
		||||
 | 
			
		||||
            item.actor.set_hover(false);
 | 
			
		||||
            item.actor.reactive = false;
 | 
			
		||||
            item.actor.can_focus = false;
 | 
			
		||||
            item._focusBin.width = 0;
 | 
			
		||||
            item.syncStyleClasses();
 | 
			
		||||
            item._timedLoginIndicator.scale_x = 0.;
 | 
			
		||||
            if (item != exception)
 | 
			
		||||
                tasks.push(function() {
 | 
			
		||||
                    return _fadeOutActor(item.actor);
 | 
			
		||||
                    return GdmUtil.fadeOutActor(item.actor);
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._box.remove_style_pseudo_class('expanded');
 | 
			
		||||
        let batch = new Batch.ConsecutiveBatch(this,
 | 
			
		||||
                                               [function() {
 | 
			
		||||
                                                    return _fadeOutActor(this.actor.vscroll);
 | 
			
		||||
                                                    return GdmUtil.fadeOutActor(this.actor.vscroll);
 | 
			
		||||
                                                },
 | 
			
		||||
 | 
			
		||||
                                                new Batch.ConcurrentBatch(this, tasks)
 | 
			
		||||
@@ -399,12 +372,16 @@ UserList.prototype = {
 | 
			
		||||
 | 
			
		||||
        for (let userName in this._items) {
 | 
			
		||||
            let item = this._items[userName];
 | 
			
		||||
            item.actor.sync_hover();
 | 
			
		||||
            item.actor.reactive = true;
 | 
			
		||||
            item.actor.can_focus = true;
 | 
			
		||||
            item.syncStyleClasses();
 | 
			
		||||
            tasks.push(function() {
 | 
			
		||||
                return this._showItem(item);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._box.add_style_pseudo_class('expanded');
 | 
			
		||||
        let batch = new Batch.ConsecutiveBatch(this,
 | 
			
		||||
                                               [function() {
 | 
			
		||||
                                                    this.takeOverWhitespace();
 | 
			
		||||
@@ -422,7 +399,7 @@ UserList.prototype = {
 | 
			
		||||
                                                },
 | 
			
		||||
 | 
			
		||||
                                                function() {
 | 
			
		||||
                                                    return _fadeInActor(this.actor.vscroll);
 | 
			
		||||
                                                    return GdmUtil.fadeInActor(this.actor.vscroll);
 | 
			
		||||
                                                }]);
 | 
			
		||||
        return batch.run();
 | 
			
		||||
    },
 | 
			
		||||
@@ -437,7 +414,7 @@ UserList.prototype = {
 | 
			
		||||
        Tweener.addTween (adjustment,
 | 
			
		||||
                          { value: value,
 | 
			
		||||
                            time: _SCROLL_ANIMATION_TIME,
 | 
			
		||||
                            transition: 'linear' });
 | 
			
		||||
                            transition: 'easeOutQuad' });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    jumpToItem: function(item) {
 | 
			
		||||
@@ -466,6 +443,9 @@ UserList.prototype = {
 | 
			
		||||
        if (user.is_system_account())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (user.locked)
 | 
			
		||||
           return;
 | 
			
		||||
 | 
			
		||||
        let userName = user.get_user_name();
 | 
			
		||||
 | 
			
		||||
        if (!userName)
 | 
			
		||||
@@ -486,9 +466,10 @@ UserList.prototype = {
 | 
			
		||||
                           Lang.bind(this,
 | 
			
		||||
                                     function() {
 | 
			
		||||
                                         this.scrollToItem(item);
 | 
			
		||||
                                         item.showFocusAnimation(0);
 | 
			
		||||
                                     }));
 | 
			
		||||
 | 
			
		||||
        this._moveFocusToItems();
 | 
			
		||||
 | 
			
		||||
        this.emit('item-added', item);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -509,14 +490,12 @@ UserList.prototype = {
 | 
			
		||||
        item.actor.destroy();
 | 
			
		||||
        delete this._items[userName];
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(UserList.prototype);
 | 
			
		||||
 | 
			
		||||
function SessionListItem(id, name) {
 | 
			
		||||
    this._init(id, name);
 | 
			
		||||
}
 | 
			
		||||
const SessionListItem = new Lang.Class({
 | 
			
		||||
    Name: 'SessionListItem',
 | 
			
		||||
 | 
			
		||||
SessionListItem.prototype = {
 | 
			
		||||
    _init: function(id, name) {
 | 
			
		||||
        this.id = id;
 | 
			
		||||
 | 
			
		||||
@@ -528,10 +507,7 @@ SessionListItem.prototype = {
 | 
			
		||||
 | 
			
		||||
        this._box = new St.BoxLayout({ style_class: 'login-dialog-session-list-item-box' });
 | 
			
		||||
 | 
			
		||||
        this.actor.add_actor(this._box,
 | 
			
		||||
                             { expand: true,
 | 
			
		||||
                               x_fill: true,
 | 
			
		||||
                               y_fill: true });
 | 
			
		||||
        this.actor.add_actor(this._box);
 | 
			
		||||
        this.actor.connect('clicked', Lang.bind(this, this._onClicked));
 | 
			
		||||
 | 
			
		||||
        this._dot = new St.DrawingArea({ style_class: 'login-dialog-session-list-item-dot' });
 | 
			
		||||
@@ -542,10 +518,7 @@ SessionListItem.prototype = {
 | 
			
		||||
        let label = new St.Label({ style_class: 'login-dialog-session-list-item-label',
 | 
			
		||||
                                   text: name });
 | 
			
		||||
 | 
			
		||||
        this._box.add_actor(label,
 | 
			
		||||
                            { expand: true,
 | 
			
		||||
                              x_fill: true,
 | 
			
		||||
                              y_fill: true });
 | 
			
		||||
        this._box.add_actor(label);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setShowDot: function(show) {
 | 
			
		||||
@@ -571,27 +544,25 @@ SessionListItem.prototype = {
 | 
			
		||||
    _onClicked: function() {
 | 
			
		||||
        this.emit('activate');
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(SessionListItem.prototype);
 | 
			
		||||
 | 
			
		||||
function SessionList() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const SessionList = new Lang.Class({
 | 
			
		||||
    Name: 'SessionList',
 | 
			
		||||
 | 
			
		||||
SessionList.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.actor = new St.BoxLayout({ style_class: 'login-dialog-session-list',
 | 
			
		||||
                                        vertical: true});
 | 
			
		||||
        this.actor = new St.Bin();
 | 
			
		||||
 | 
			
		||||
        this._box = new St.BoxLayout({ style_class: 'login-dialog-session-list',
 | 
			
		||||
                                       vertical: true});
 | 
			
		||||
        this.actor.child = this._box;
 | 
			
		||||
 | 
			
		||||
        this._button = new St.Button({ style_class: 'login-dialog-session-list-button',
 | 
			
		||||
                                       can_focus: true,
 | 
			
		||||
                                       x_fill: true,
 | 
			
		||||
                                       y_fill: true });
 | 
			
		||||
        let box = new St.BoxLayout();
 | 
			
		||||
        this._button.add_actor(box,
 | 
			
		||||
                               { x_fill: true,
 | 
			
		||||
                                 y_fill: true,
 | 
			
		||||
                                 expand: true });
 | 
			
		||||
        this._button.add_actor(box);
 | 
			
		||||
 | 
			
		||||
        this._triangle = new St.Label({ style_class: 'login-dialog-session-list-triangle',
 | 
			
		||||
                                        text: '\u25B8' });
 | 
			
		||||
@@ -599,30 +570,18 @@ SessionList.prototype = {
 | 
			
		||||
 | 
			
		||||
        let label = new St.Label({ style_class: 'login-dialog-session-list-label',
 | 
			
		||||
                                   text: _("Session...") });
 | 
			
		||||
        box.add_actor(label,
 | 
			
		||||
                      { x_fill: true,
 | 
			
		||||
                        y_fill: true,
 | 
			
		||||
                        expand: true });
 | 
			
		||||
        box.add_actor(label);
 | 
			
		||||
 | 
			
		||||
        this._button.connect('clicked',
 | 
			
		||||
                             Lang.bind(this, this._onClicked));
 | 
			
		||||
        this.actor.add_actor(this._button,
 | 
			
		||||
                             { x_fill: true,
 | 
			
		||||
                               y_fill: true,
 | 
			
		||||
                               expand: true });
 | 
			
		||||
        this._box.add_actor(this._button);
 | 
			
		||||
        this._scrollView = new St.ScrollView({ style_class: 'login-dialog-session-list-scroll-view'});
 | 
			
		||||
        this._scrollView.set_policy(Gtk.PolicyType.NEVER,
 | 
			
		||||
                                    Gtk.PolicyType.AUTOMATIC);
 | 
			
		||||
        this.actor.add_actor(this._scrollView,
 | 
			
		||||
                             { x_fill: true,
 | 
			
		||||
                               y_fill: true,
 | 
			
		||||
                               expand: true });
 | 
			
		||||
        this._box.add_actor(this._scrollView);
 | 
			
		||||
        this._itemList = new St.BoxLayout({ style_class: 'login-dialog-session-item-list',
 | 
			
		||||
                                            vertical: true });
 | 
			
		||||
        this._scrollView.add_actor(this._itemList,
 | 
			
		||||
                                   { x_fill: true,
 | 
			
		||||
                                     y_fill: true,
 | 
			
		||||
                                     expand: true });
 | 
			
		||||
        this._scrollView.add_actor(this._itemList);
 | 
			
		||||
        this._scrollView.hide();
 | 
			
		||||
        this.isOpen = false;
 | 
			
		||||
        this._populate();
 | 
			
		||||
@@ -671,27 +630,26 @@ SessionList.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _populate: function() {
 | 
			
		||||
        this._itemList.destroy_children();
 | 
			
		||||
        this._itemList.destroy_all_children();
 | 
			
		||||
        this._activeSessionId = null;
 | 
			
		||||
        this._items = {};
 | 
			
		||||
 | 
			
		||||
        let ids = GdmGreeter.get_session_ids();
 | 
			
		||||
        let ids = Gdm.get_session_ids();
 | 
			
		||||
        ids.sort();
 | 
			
		||||
 | 
			
		||||
        if (ids.length <= 1)
 | 
			
		||||
            this.actor.hide();
 | 
			
		||||
        else
 | 
			
		||||
            this.actor.show();
 | 
			
		||||
        if (ids.length <= 1) {
 | 
			
		||||
            this._box.hide();
 | 
			
		||||
            this._button.hide();
 | 
			
		||||
        } else {
 | 
			
		||||
            this._button.show();
 | 
			
		||||
            this._box.show();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < ids.length; i++) {
 | 
			
		||||
            let [sessionName, sessionDescription] = GdmGreeter.get_session_name_and_description(ids[i]);
 | 
			
		||||
            let [sessionName, sessionDescription] = Gdm.get_session_name_and_description(ids[i]);
 | 
			
		||||
 | 
			
		||||
            let item = new SessionListItem(ids[i], sessionName);
 | 
			
		||||
            this._itemList.add_actor(item.actor,
 | 
			
		||||
                              { x_align: St.Align.START,
 | 
			
		||||
                                y_align: St.Align.START,
 | 
			
		||||
                                x_fill: true,
 | 
			
		||||
                                y_fill: true });
 | 
			
		||||
            this._itemList.add_actor(item.actor);
 | 
			
		||||
            this._items[ids[i]] = item;
 | 
			
		||||
 | 
			
		||||
            if (!this._activeSessionId)
 | 
			
		||||
@@ -703,59 +661,64 @@ SessionList.prototype = {
 | 
			
		||||
                         }));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(SessionList.prototype);
 | 
			
		||||
 | 
			
		||||
function LoginDialog() {
 | 
			
		||||
    if (_loginDialog == null) {
 | 
			
		||||
        this._init();
 | 
			
		||||
        _loginDialog = this;
 | 
			
		||||
    }
 | 
			
		||||
const LoginDialog = new Lang.Class({
 | 
			
		||||
    Name: 'LoginDialog',
 | 
			
		||||
    Extends: ModalDialog.ModalDialog,
 | 
			
		||||
 | 
			
		||||
    return _loginDialog;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LoginDialog.prototype = {
 | 
			
		||||
    __proto__: ModalDialog.ModalDialog.prototype,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        ModalDialog.ModalDialog.prototype._init.call(this, { shellReactive: true,
 | 
			
		||||
                                                             styleClass: 'login-dialog' });
 | 
			
		||||
    _init: function(parentActor) {
 | 
			
		||||
        this.parent({ shellReactive: true,
 | 
			
		||||
                      styleClass: 'login-dialog',
 | 
			
		||||
                      parentActor: parentActor
 | 
			
		||||
                    });
 | 
			
		||||
        this.connect('destroy',
 | 
			
		||||
                     Lang.bind(this, this._onDestroy));
 | 
			
		||||
        this.connect('opened',
 | 
			
		||||
                     Lang.bind(this, this._onOpened));
 | 
			
		||||
 | 
			
		||||
        this._userManager = AccountsService.UserManager.get_default()
 | 
			
		||||
        this._greeterClient = new GdmGreeter.Client();
 | 
			
		||||
        this._greeterClient = new Gdm.Client();
 | 
			
		||||
 | 
			
		||||
        this._greeterClient.open_connection();
 | 
			
		||||
        this._greeter = this._greeterClient.get_greeter_sync(null);
 | 
			
		||||
 | 
			
		||||
        this._greeterClient.call_start_conversation('gdm-password');
 | 
			
		||||
        this._greeter.connect('default-session-name-changed',
 | 
			
		||||
                              Lang.bind(this, this._onDefaultSessionChanged));
 | 
			
		||||
 | 
			
		||||
        this._greeterClient.connect('reset',
 | 
			
		||||
                                    Lang.bind(this, this._onReset));
 | 
			
		||||
        this._greeterClient.connect('default-session-changed',
 | 
			
		||||
                                    Lang.bind(this, this._onDefaultSessionChanged));
 | 
			
		||||
        this._greeterClient.connect('info',
 | 
			
		||||
                                    Lang.bind(this, this._onInfo));
 | 
			
		||||
        this._greeterClient.connect('problem',
 | 
			
		||||
                                    Lang.bind(this, this._onProblem));
 | 
			
		||||
        this._greeterClient.connect('info-query',
 | 
			
		||||
                                    Lang.bind(this, this._onInfoQuery));
 | 
			
		||||
        this._greeterClient.connect('secret-info-query',
 | 
			
		||||
                                    Lang.bind(this, this._onSecretInfoQuery));
 | 
			
		||||
        this._greeterClient.connect('session-opened',
 | 
			
		||||
                                    Lang.bind(this, this._onSessionOpened));
 | 
			
		||||
        this._greeterClient.connect('timed-login-requested',
 | 
			
		||||
                                    Lang.bind(this, this._onTimedLoginRequested));
 | 
			
		||||
        this._greeterClient.connect('authentication-failed',
 | 
			
		||||
                                    Lang.bind(this, this._onAuthenticationFailed));
 | 
			
		||||
        this._greeterClient.connect('conversation-stopped',
 | 
			
		||||
                                    Lang.bind(this, this._onConversationStopped));
 | 
			
		||||
        this._greeter.connect('session-opened',
 | 
			
		||||
                              Lang.bind(this, this._onSessionOpened));
 | 
			
		||||
        this._greeter.connect('timed-login-requested',
 | 
			
		||||
                              Lang.bind(this, this._onTimedLoginRequested));
 | 
			
		||||
 | 
			
		||||
        this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient);
 | 
			
		||||
        this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion));
 | 
			
		||||
        this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
 | 
			
		||||
        this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
 | 
			
		||||
 | 
			
		||||
        this._userVerifier.connect('show-fingerprint-prompt', Lang.bind(this, this._showFingerprintPrompt));
 | 
			
		||||
        this._userVerifier.connect('hide-fingerprint-prompt', Lang.bind(this, this._hideFingerprintPrompt));
 | 
			
		||||
 | 
			
		||||
        this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
 | 
			
		||||
 | 
			
		||||
        this._settings.connect('changed::' + GdmUtil.LOGO_KEY,
 | 
			
		||||
                               Lang.bind(this, this._updateLogo));
 | 
			
		||||
        this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
 | 
			
		||||
                               Lang.bind(this, this._updateBanner));
 | 
			
		||||
        this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_TEXT_KEY,
 | 
			
		||||
                               Lang.bind(this, this._updateBanner));
 | 
			
		||||
 | 
			
		||||
        this._logoBox = new St.Bin({ style_class: 'login-dialog-logo-box' });
 | 
			
		||||
        this.contentLayout.add(this._logoBox);
 | 
			
		||||
        this._updateLogo();
 | 
			
		||||
 | 
			
		||||
        this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner',
 | 
			
		||||
                                           text: '' });
 | 
			
		||||
        this.contentLayout.add(this._bannerLabel);
 | 
			
		||||
        this._updateBanner();
 | 
			
		||||
 | 
			
		||||
        this._titleLabel = new St.Label({ style_class: 'login-dialog-title',
 | 
			
		||||
                                          text: _("Sign In") });
 | 
			
		||||
                                          text: C_("title", "Sign In") });
 | 
			
		||||
 | 
			
		||||
        this.contentLayout.add(this._titleLabel,
 | 
			
		||||
                              { y_fill: false,
 | 
			
		||||
@@ -798,21 +761,29 @@ LoginDialog.prototype = {
 | 
			
		||||
                              x_fill: true,
 | 
			
		||||
                              y_fill: false,
 | 
			
		||||
                              x_align: St.Align.START });
 | 
			
		||||
        // Translators: this message is shown below the password entry field
 | 
			
		||||
        // to indicate the user can swipe their finger instead
 | 
			
		||||
        this._promptFingerprintMessage = new St.Label({ text: _("(or swipe finger)"),
 | 
			
		||||
                                                        style_class: 'login-dialog-prompt-fingerprint-message' });
 | 
			
		||||
        this._promptFingerprintMessage.hide();
 | 
			
		||||
        this._promptBox.add(this._promptFingerprintMessage);
 | 
			
		||||
 | 
			
		||||
        this._sessionList = new SessionList();
 | 
			
		||||
        this._sessionList.connect('session-activated',
 | 
			
		||||
                                  Lang.bind(this, function(list, sessionId) {
 | 
			
		||||
                                                this._greeterClient.call_select_session (sessionId);
 | 
			
		||||
                                                this._greeter.call_select_session_sync (sessionId, null);
 | 
			
		||||
                                            }));
 | 
			
		||||
 | 
			
		||||
        this._promptBox.add(this._sessionList.actor,
 | 
			
		||||
                               { expand: true,
 | 
			
		||||
                                 x_fill: true,
 | 
			
		||||
                                 y_fill: true,
 | 
			
		||||
                                 x_align: St.Align.START,
 | 
			
		||||
                                 y_align: St.Align.START});
 | 
			
		||||
                            { expand: true,
 | 
			
		||||
                              x_fill: false,
 | 
			
		||||
                              y_fill: true,
 | 
			
		||||
                              x_align: St.Align.START });
 | 
			
		||||
        this._promptBox.hide();
 | 
			
		||||
 | 
			
		||||
        // translators: this message is shown below the user list on the
 | 
			
		||||
        // login screen. It can be activated to reveal an entry for
 | 
			
		||||
        // manually entering the username.
 | 
			
		||||
        let notListedLabel = new St.Label({ text: _("Not listed?"),
 | 
			
		||||
                                            style_class: 'login-dialog-not-listed-label' });
 | 
			
		||||
        this._notListedButton = new St.Button({ style_class: 'login-dialog-not-listed-button',
 | 
			
		||||
@@ -846,18 +817,44 @@ LoginDialog.prototype = {
 | 
			
		||||
                                   this._onUserListActivated(item);
 | 
			
		||||
                               }));
 | 
			
		||||
 | 
			
		||||
   },
 | 
			
		||||
 | 
			
		||||
    _updateLogo: function() {
 | 
			
		||||
        this._logoBox.child = null;
 | 
			
		||||
        let path = this._settings.get_string(GdmUtil.LOGO_KEY);
 | 
			
		||||
 | 
			
		||||
        if (path) {
 | 
			
		||||
            let file = Gio.file_new_for_path(path);
 | 
			
		||||
            let uri = file.get_uri();
 | 
			
		||||
 | 
			
		||||
            let textureCache = St.TextureCache.get_default();
 | 
			
		||||
            this._logoBox.child = textureCache.load_uri_async(uri, -1, _LOGO_ICON_NAME_SIZE);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateBanner: function() {
 | 
			
		||||
        let enabled = this._settings.get_boolean(GdmUtil.BANNER_MESSAGE_KEY);
 | 
			
		||||
        let text = this._settings.get_string(GdmUtil.BANNER_MESSAGE_TEXT_KEY);
 | 
			
		||||
 | 
			
		||||
        if (enabled && text) {
 | 
			
		||||
            this._bannerLabel.set_text(text);
 | 
			
		||||
            this._fadeInBanner();
 | 
			
		||||
        } else {
 | 
			
		||||
            this._fadeOutBanner();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onReset: function(client, serviceName) {
 | 
			
		||||
        this._greeterClient.call_start_conversation('gdm-password');
 | 
			
		||||
 | 
			
		||||
        let tasks = [this._hidePrompt,
 | 
			
		||||
 | 
			
		||||
                     new Batch.ConcurrentBatch(this, [this._fadeInTitleLabel,
 | 
			
		||||
                                                      this._fadeInNotListedButton]),
 | 
			
		||||
                                                      this._fadeInNotListedButton,
 | 
			
		||||
                                                      this._fadeInLogo]),
 | 
			
		||||
 | 
			
		||||
                     function() {
 | 
			
		||||
                         this._sessionList.close();
 | 
			
		||||
                         this._promptFingerprintMessage.hide();
 | 
			
		||||
                         this._userList.actor.show();
 | 
			
		||||
                         this._userList.actor.opacity = 255;
 | 
			
		||||
                         return this._userList.showItems();
 | 
			
		||||
@@ -878,36 +875,43 @@ LoginDialog.prototype = {
 | 
			
		||||
        this._sessionList.setActiveSession(sessionId);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onInfo: function(client, serviceName, info) {
 | 
			
		||||
        Main.notifyError(info);
 | 
			
		||||
    _showFingerprintPrompt: function() {
 | 
			
		||||
        GdmUtil.fadeInActor(this._promptFingerprintMessage);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onProblem: function(client, serviceName, problem) {
 | 
			
		||||
        Main.notifyError(problem);
 | 
			
		||||
    _hideFingerprintPrompt: function() {
 | 
			
		||||
        GdmUtil.fadeOutActor(this._promptFingerprintMessage);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onCancel: function(client) {
 | 
			
		||||
        this._greeterClient.call_cancel();
 | 
			
		||||
    cancel: function() {
 | 
			
		||||
        this._userVerifier.cancel();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _fadeInPrompt: function() {
 | 
			
		||||
        let tasks = [function() {
 | 
			
		||||
                         return _fadeInActor(this._promptLabel);
 | 
			
		||||
                         return GdmUtil.fadeInActor(this._promptLabel);
 | 
			
		||||
                     },
 | 
			
		||||
 | 
			
		||||
                     function() {
 | 
			
		||||
                         return _fadeInActor(this._promptEntry);
 | 
			
		||||
                         return GdmUtil.fadeInActor(this._promptEntry);
 | 
			
		||||
                     },
 | 
			
		||||
 | 
			
		||||
                     function() {
 | 
			
		||||
                         return _fadeInActor(this._promptBox);
 | 
			
		||||
                         // Show it with 0 opacity so we preallocate space for it
 | 
			
		||||
                         // in the event we need to fade in the message
 | 
			
		||||
                         this._promptFingerprintMessage.opacity = 0;
 | 
			
		||||
                         this._promptFingerprintMessage.show();
 | 
			
		||||
                     },
 | 
			
		||||
 | 
			
		||||
                     function() {
 | 
			
		||||
                         return GdmUtil.fadeInActor(this._promptBox);
 | 
			
		||||
                     },
 | 
			
		||||
 | 
			
		||||
                     function() {
 | 
			
		||||
                         if (this._user && this._user.is_logged_in())
 | 
			
		||||
                             return null;
 | 
			
		||||
 | 
			
		||||
                         return _fadeInActor(this._sessionList.actor);
 | 
			
		||||
                         return GdmUtil.fadeInActor(this._sessionList.actor);
 | 
			
		||||
                     },
 | 
			
		||||
 | 
			
		||||
                     function() {
 | 
			
		||||
@@ -922,13 +926,14 @@ LoginDialog.prototype = {
 | 
			
		||||
    _showPrompt: function() {
 | 
			
		||||
        let hold = new Batch.Hold();
 | 
			
		||||
 | 
			
		||||
        let buttons = [{ action: Lang.bind(this, this._onCancel),
 | 
			
		||||
        let buttons = [{ action: Lang.bind(this, this.cancel),
 | 
			
		||||
                         label: _("Cancel"),
 | 
			
		||||
                         key: Clutter.Escape },
 | 
			
		||||
                       { action: Lang.bind(this, function() {
 | 
			
		||||
                                     hold.release();
 | 
			
		||||
                                 }),
 | 
			
		||||
                         label: _("Sign In") }];
 | 
			
		||||
                         label: C_("button", "Sign In"),
 | 
			
		||||
                         default: true }];
 | 
			
		||||
 | 
			
		||||
        this._promptEntryActivateCallbackId = this._promptEntry.clutter_text.connect('activate',
 | 
			
		||||
                                                                                     Lang.bind(this, function() {
 | 
			
		||||
@@ -963,10 +968,13 @@ LoginDialog.prototype = {
 | 
			
		||||
        this.setButtons([]);
 | 
			
		||||
 | 
			
		||||
        let tasks = [function() {
 | 
			
		||||
                         return _fadeOutActor(this._promptBox);
 | 
			
		||||
                         return GdmUtil.fadeOutActor(this._promptBox);
 | 
			
		||||
                     },
 | 
			
		||||
 | 
			
		||||
                     function() {
 | 
			
		||||
                         this._promptFingerprintMessage.hide();
 | 
			
		||||
                         this._promptEntry.reactive = true;
 | 
			
		||||
                         this._promptEntry.remove_style_pseudo_class('insensitive');
 | 
			
		||||
                         this._promptEntry.set_text('');
 | 
			
		||||
                     }];
 | 
			
		||||
 | 
			
		||||
@@ -975,34 +983,27 @@ LoginDialog.prototype = {
 | 
			
		||||
        return batch.run();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _askQuestion: function(serviceName, question) {
 | 
			
		||||
    _askQuestion: function(verifier, serviceName, question, passwordChar) {
 | 
			
		||||
        this._promptLabel.set_text(question);
 | 
			
		||||
 | 
			
		||||
        this._promptEntry.set_text('');
 | 
			
		||||
        this._promptEntry.clutter_text.set_password_char(passwordChar);
 | 
			
		||||
 | 
			
		||||
        let tasks = [this._showPrompt,
 | 
			
		||||
 | 
			
		||||
                     function() {
 | 
			
		||||
                         let _text = this._promptEntry.get_text();
 | 
			
		||||
                         this._promptEntry.set_text('');
 | 
			
		||||
                         this._greeterClient.call_answer_query(serviceName, _text);
 | 
			
		||||
                         this._promptEntry.reactive = false;
 | 
			
		||||
                         this._promptEntry.add_style_pseudo_class('insensitive');
 | 
			
		||||
                         this._userVerifier.answerQuery(serviceName, _text);
 | 
			
		||||
                     }];
 | 
			
		||||
 | 
			
		||||
        let batch = new Batch.ConsecutiveBatch(this, tasks);
 | 
			
		||||
        return batch.run();
 | 
			
		||||
    },
 | 
			
		||||
    _onInfoQuery: function(client, serviceName, question) {
 | 
			
		||||
        this._promptEntry.set_text('');
 | 
			
		||||
        this._promptEntry.clutter_text.set_password_char('');
 | 
			
		||||
        this._askQuestion(serviceName, question);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onSecretInfoQuery: function(client, serviceName, secretQuestion) {
 | 
			
		||||
        this._promptEntry.set_text('');
 | 
			
		||||
        this._promptEntry.clutter_text.set_password_char('\u25cf');
 | 
			
		||||
        this._askQuestion(serviceName, secretQuestion);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onSessionOpened: function(client, serviceName) {
 | 
			
		||||
        this._greeterClient.call_start_session_when_ready(serviceName, true);
 | 
			
		||||
        this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _waitForItemForUser: function(userName) {
 | 
			
		||||
@@ -1029,7 +1030,7 @@ LoginDialog.prototype = {
 | 
			
		||||
 | 
			
		||||
    _showTimedLoginAnimation: function() {
 | 
			
		||||
        this._timedLoginItem.actor.grab_key_focus();
 | 
			
		||||
        return this._timedLoginItem.showFocusAnimation(this._timedLoginAnimationTime);
 | 
			
		||||
        return this._timedLoginItem.showTimedLoginIndicator(this._timedLoginAnimationTime);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _blockTimedLoginUntilIdle: function() {
 | 
			
		||||
@@ -1070,7 +1071,6 @@ LoginDialog.prototype = {
 | 
			
		||||
                         // item.
 | 
			
		||||
                         if (!this.is_loaded) {
 | 
			
		||||
                             this._userList.jumpToItem(this._timedLoginItem);
 | 
			
		||||
                             this._timedLoginItem.showFocusAnimation(0);
 | 
			
		||||
                         }
 | 
			
		||||
                     },
 | 
			
		||||
 | 
			
		||||
@@ -1084,7 +1084,7 @@ LoginDialog.prototype = {
 | 
			
		||||
 | 
			
		||||
                     function() {
 | 
			
		||||
                         this._timedLoginBatch = null;
 | 
			
		||||
                         this._greeterClient.call_begin_auto_login(userName);
 | 
			
		||||
                         this._greeter.call_begin_auto_login_sync(userName, null);
 | 
			
		||||
                     }];
 | 
			
		||||
 | 
			
		||||
        this._timedLoginBatch = new Batch.ConsecutiveBatch(this, tasks);
 | 
			
		||||
@@ -1098,6 +1098,9 @@ LoginDialog.prototype = {
 | 
			
		||||
            this._timedLoginBatch = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._timedLoginItem)
 | 
			
		||||
            this._timedLoginItem.hideTimedLoginIndicator();
 | 
			
		||||
 | 
			
		||||
        let userName = this._timedLoginItem.user.get_user_name();
 | 
			
		||||
 | 
			
		||||
        if (userName)
 | 
			
		||||
@@ -1127,12 +1130,8 @@ LoginDialog.prototype = {
 | 
			
		||||
                             }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onAuthenticationFailed: function(client) {
 | 
			
		||||
        this._greeterClient.call_cancel();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onConversationStopped: function(client, serviceName) {
 | 
			
		||||
        this._greeterClient.call_cancel();
 | 
			
		||||
    _onVerificationFailed: function() {
 | 
			
		||||
        this._userVerifier.cancel();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onNotListedClicked: function(user) {
 | 
			
		||||
@@ -1149,33 +1148,62 @@ LoginDialog.prototype = {
 | 
			
		||||
                     },
 | 
			
		||||
 | 
			
		||||
                     new Batch.ConcurrentBatch(this, [this._fadeOutTitleLabel,
 | 
			
		||||
                                                      this._fadeOutNotListedButton]),
 | 
			
		||||
                                                      this._fadeOutNotListedButton,
 | 
			
		||||
                                                      this._fadeOutLogo]),
 | 
			
		||||
 | 
			
		||||
                     function() {
 | 
			
		||||
                         this._greeterClient.call_begin_verification('gdm-password');
 | 
			
		||||
                         let hold = new Batch.Hold();
 | 
			
		||||
 | 
			
		||||
                         this._userVerifier.begin(null, hold);
 | 
			
		||||
                         return hold;
 | 
			
		||||
                     }];
 | 
			
		||||
 | 
			
		||||
        let batch = new Batch.ConsecutiveBatch(this, tasks);
 | 
			
		||||
        batch.run();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _fadeInLogo: function() {
 | 
			
		||||
        return GdmUtil.fadeInActor(this._logoBox);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _fadeOutLogo: function() {
 | 
			
		||||
        return GdmUtil.fadeOutActor(this._logoBox);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _fadeInBanner: function() {
 | 
			
		||||
        return GdmUtil.fadeInActor(this._bannerLabel);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _fadeOutBanner: function() {
 | 
			
		||||
        return GdmUtil.fadeOutActor(this._bannerLabel);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _fadeInTitleLabel: function() {
 | 
			
		||||
        return _fadeInActor(this._titleLabel);
 | 
			
		||||
        return GdmUtil.fadeInActor(this._titleLabel);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _fadeOutTitleLabel: function() {
 | 
			
		||||
        return _fadeOutActor(this._titleLabel);
 | 
			
		||||
        return GdmUtil.fadeOutActor(this._titleLabel);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _fadeInNotListedButton: function() {
 | 
			
		||||
        return _fadeInActor(this._notListedButton);
 | 
			
		||||
        return GdmUtil.fadeInActor(this._notListedButton);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _fadeOutNotListedButton: function() {
 | 
			
		||||
        return _fadeOutActor(this._notListedButton);
 | 
			
		||||
        return GdmUtil.fadeOutActor(this._notListedButton);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _beginVerificationForUser: function(userName) {
 | 
			
		||||
        let hold = new Batch.Hold();
 | 
			
		||||
 | 
			
		||||
        this._userVerifier.begin(userName, hold);
 | 
			
		||||
        return hold;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onUserListActivated: function(activatedItem) {
 | 
			
		||||
        let userName;
 | 
			
		||||
 | 
			
		||||
        let tasks = [function() {
 | 
			
		||||
                         this._userList.actor.reactive = false;
 | 
			
		||||
                         return this._userList.pinInPlace();
 | 
			
		||||
@@ -1194,16 +1222,17 @@ LoginDialog.prototype = {
 | 
			
		||||
                     },
 | 
			
		||||
 | 
			
		||||
                     new Batch.ConcurrentBatch(this, [this._fadeOutTitleLabel,
 | 
			
		||||
                                                      this._fadeOutNotListedButton]),
 | 
			
		||||
                                                      this._fadeOutNotListedButton,
 | 
			
		||||
                                                      this._fadeOutLogo]),
 | 
			
		||||
 | 
			
		||||
                     function() {
 | 
			
		||||
                         return this._userList.shrinkToNaturalHeight();
 | 
			
		||||
                     },
 | 
			
		||||
 | 
			
		||||
                     function() {
 | 
			
		||||
                         let userName = activatedItem.user.get_user_name();
 | 
			
		||||
                         this._greeterClient.call_begin_verification_for_user('gdm-password',
 | 
			
		||||
                                                                              userName);
 | 
			
		||||
                         userName = activatedItem.user.get_user_name();
 | 
			
		||||
 | 
			
		||||
                         return this._beginVerificationForUser(userName);
 | 
			
		||||
                     }];
 | 
			
		||||
 | 
			
		||||
        this._user = activatedItem.user;
 | 
			
		||||
@@ -1255,8 +1284,8 @@ LoginDialog.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    close: function() {
 | 
			
		||||
        ModalDialog.ModalDialog.prototype.close.call(this);
 | 
			
		||||
        this.parent();
 | 
			
		||||
 | 
			
		||||
        Main.ctrlAltTabManager.removeGroup(this._group);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										170
									
								
								js/gdm/powerMenu.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,170 @@
 | 
			
		||||
// -*- 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 Systemd = imports.gdm.systemd;
 | 
			
		||||
 | 
			
		||||
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._upClient = new UPowerGlib.Client();
 | 
			
		||||
 | 
			
		||||
        if (Systemd.haveSystemd())
 | 
			
		||||
            this._systemdLoginManager = new Systemd.SystemdLoginManager();
 | 
			
		||||
        else
 | 
			
		||||
            this._consoleKitManager = new ConsoleKit.ConsoleKitManager();
 | 
			
		||||
 | 
			
		||||
        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() {
 | 
			
		||||
        let shouldBeVisible = (this._haveSuspend || this._haveShutdown || this._haveRestart);
 | 
			
		||||
        this.actor.visible = shouldBeVisible;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateHaveShutdown: function() {
 | 
			
		||||
 | 
			
		||||
        if (Systemd.haveSystemd()) {
 | 
			
		||||
            this._systemdLoginManager.CanPowerOffRemote(Lang.bind(this,
 | 
			
		||||
                function(result, error) {
 | 
			
		||||
                    if (!error)
 | 
			
		||||
                        this._haveShutdown = result[0] != 'no';
 | 
			
		||||
                    else
 | 
			
		||||
                        this._haveShutdown = false;
 | 
			
		||||
 | 
			
		||||
                    this._powerOffItem.actor.visible = this._haveShutdown;
 | 
			
		||||
                    this._updateVisibility();
 | 
			
		||||
                }));
 | 
			
		||||
        } else {
 | 
			
		||||
            this._consoleKitManager.CanStopRemote(Lang.bind(this,
 | 
			
		||||
                function(result, error) {
 | 
			
		||||
                    if (!error)
 | 
			
		||||
                        this._haveShutdown = result[0];
 | 
			
		||||
                    else
 | 
			
		||||
                        this._haveShutdown = false;
 | 
			
		||||
 | 
			
		||||
                    this._powerOffItem.actor.visible = this._haveShutdown;
 | 
			
		||||
                    this._updateVisibility();
 | 
			
		||||
                }));
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateHaveRestart: function() {
 | 
			
		||||
 | 
			
		||||
        if (Systemd.haveSystemd()) {
 | 
			
		||||
            this._systemdLoginManager.CanRebootRemote(Lang.bind(this,
 | 
			
		||||
                function(result, error) {
 | 
			
		||||
                    if (!error)
 | 
			
		||||
                        this._haveRestart = result[0] != 'no';
 | 
			
		||||
                    else
 | 
			
		||||
                        this._haveRestart = false;
 | 
			
		||||
 | 
			
		||||
                    this._restartItem.actor.visible = this._haveRestart;
 | 
			
		||||
                    this._updateVisibility();
 | 
			
		||||
                }));
 | 
			
		||||
        } else {
 | 
			
		||||
            this._consoleKitManager.CanRestartRemote(Lang.bind(this,
 | 
			
		||||
                function(result, error) {
 | 
			
		||||
                    if (!error)
 | 
			
		||||
                        this._haveRestart = result[0];
 | 
			
		||||
                    else
 | 
			
		||||
                        this._haveRestart = false;
 | 
			
		||||
 | 
			
		||||
                    this._restartItem.actor.visible = this._haveRestart;
 | 
			
		||||
                    this._updateVisibility();
 | 
			
		||||
                }));
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateHaveSuspend: function() {
 | 
			
		||||
        this._haveSuspend = this._upClient.get_can_suspend();
 | 
			
		||||
        this._suspendItem.actor.visible = this._haveSuspend;
 | 
			
		||||
        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)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (Systemd.haveSystemd())
 | 
			
		||||
            this._systemdLoginManager.RebootRemote(true);
 | 
			
		||||
        else
 | 
			
		||||
            this._consoleKitManager.RestartRemote();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onActivatePowerOff: function() {
 | 
			
		||||
        if (!this._haveShutdown)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (Systemd.haveSystemd())
 | 
			
		||||
            this._systemdLoginManager.PowerOffRemote(true);
 | 
			
		||||
        else
 | 
			
		||||
            this._consoleKitManager.StopRemote();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										31
									
								
								js/gdm/systemd.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,31 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
 | 
			
		||||
const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager'>
 | 
			
		||||
<method name='PowerOff'>
 | 
			
		||||
    <arg type='b' direction='in'/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name='Reboot'>
 | 
			
		||||
    <arg type='b' direction='in'/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name='CanPowerOff'>
 | 
			
		||||
    <arg type='s' direction='out'/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name='CanReboot'>
 | 
			
		||||
    <arg type='s' direction='out'/>
 | 
			
		||||
</method>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const SystemdLoginManagerProxy = Gio.DBusProxy.makeProxyWrapper(SystemdLoginManagerIface);
 | 
			
		||||
 | 
			
		||||
function SystemdLoginManager() {
 | 
			
		||||
    return new SystemdLoginManagerProxy(Gio.DBus.system,
 | 
			
		||||
                                        'org.freedesktop.login1',
 | 
			
		||||
                                        '/org/freedesktop/login1');
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function haveSystemd() {
 | 
			
		||||
    return GLib.access("/sys/fs/cgroup/systemd", 0) >= 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										268
									
								
								js/gdm/util.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,268 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const Batch = imports.gdm.batch;
 | 
			
		||||
const Fprint = imports.gdm.fingerprint;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
const PASSWORD_SERVICE_NAME = 'gdm-password';
 | 
			
		||||
const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
 | 
			
		||||
const FADE_ANIMATION_TIME = 0.16;
 | 
			
		||||
 | 
			
		||||
const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
 | 
			
		||||
const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
 | 
			
		||||
const BANNER_MESSAGE_KEY = 'banner-message-enable';
 | 
			
		||||
const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
 | 
			
		||||
 | 
			
		||||
const LOGO_KEY = 'logo';
 | 
			
		||||
 | 
			
		||||
function fadeInActor(actor) {
 | 
			
		||||
    if (actor.opacity == 255 && actor.visible)
 | 
			
		||||
        return null;
 | 
			
		||||
 | 
			
		||||
    let hold = new Batch.Hold();
 | 
			
		||||
    actor.show();
 | 
			
		||||
    let [minHeight, naturalHeight] = actor.get_preferred_height(-1);
 | 
			
		||||
 | 
			
		||||
    actor.opacity = 0;
 | 
			
		||||
    actor.set_height(0);
 | 
			
		||||
    Tweener.addTween(actor,
 | 
			
		||||
                     { opacity: 255,
 | 
			
		||||
                       height: naturalHeight,
 | 
			
		||||
                       time: FADE_ANIMATION_TIME,
 | 
			
		||||
                       transition: 'easeOutQuad',
 | 
			
		||||
                       onComplete: function() {
 | 
			
		||||
                           this.set_height(-1);
 | 
			
		||||
                           hold.release();
 | 
			
		||||
                       },
 | 
			
		||||
                     });
 | 
			
		||||
 | 
			
		||||
    return hold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function fadeOutActor(actor) {
 | 
			
		||||
    if (!actor.visible || actor.opacity == 0) {
 | 
			
		||||
        actor.opacity = 0;
 | 
			
		||||
        actor.hide();
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let hold = new Batch.Hold();
 | 
			
		||||
    Tweener.addTween(actor,
 | 
			
		||||
                     { opacity: 0,
 | 
			
		||||
                       height: 0,
 | 
			
		||||
                       time: FADE_ANIMATION_TIME,
 | 
			
		||||
                       transition: 'easeOutQuad',
 | 
			
		||||
                       onComplete: function() {
 | 
			
		||||
                           this.hide();
 | 
			
		||||
                           this.set_height(-1);
 | 
			
		||||
                           hold.release();
 | 
			
		||||
                       },
 | 
			
		||||
                     });
 | 
			
		||||
    return hold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ShellUserVerifier = new Lang.Class({
 | 
			
		||||
    Name: 'ShellUserVerifier',
 | 
			
		||||
 | 
			
		||||
    _init: function(client, params) {
 | 
			
		||||
        params = Params.parse(params, { reauthenticationOnly: false });
 | 
			
		||||
        this._reauthOnly = params.reauthenticationOnly;
 | 
			
		||||
 | 
			
		||||
        this._client = client;
 | 
			
		||||
 | 
			
		||||
        this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
 | 
			
		||||
 | 
			
		||||
        this._cancellable = new Gio.Cancellable();
 | 
			
		||||
 | 
			
		||||
        this._fprintManager = new Fprint.FprintManager();
 | 
			
		||||
        this._checkForFingerprintReader();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    begin: function(userName, hold) {
 | 
			
		||||
        this._hold = hold;
 | 
			
		||||
        this._userName = userName;
 | 
			
		||||
 | 
			
		||||
        if (userName) {
 | 
			
		||||
            // If possible, reauthenticate an already running session,
 | 
			
		||||
            // so any session specific credentials get updated appropriately
 | 
			
		||||
            this._client.open_reauthentication_channel(userName, this._cancellable,
 | 
			
		||||
                                                       Lang.bind(this, this._reauthenticationChannelOpened));
 | 
			
		||||
        } else {
 | 
			
		||||
            this._client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot));
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    cancel: function() {
 | 
			
		||||
        this._cancellable.cancel();
 | 
			
		||||
 | 
			
		||||
        if (this._userVerifier)
 | 
			
		||||
            this._userVerifier.call_cancel_sync(null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    clear: function() {
 | 
			
		||||
        this._cancellable.cancel();
 | 
			
		||||
 | 
			
		||||
        if (this._userVerifier) {
 | 
			
		||||
            this._userVerifier.run_dispose();
 | 
			
		||||
            this._userVerifier = null;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    answerQuery: function(serviceName, answer) {
 | 
			
		||||
        this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _checkForFingerprintReader: function() {
 | 
			
		||||
        this._haveFingerprintReader = false;
 | 
			
		||||
 | 
			
		||||
        if (!this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._fprintManager.GetDefaultDeviceRemote(Gio.DBusCallFlags.NONE, this._cancellable, Lang.bind(this,
 | 
			
		||||
            function(device, error) {
 | 
			
		||||
                if (!error && device)
 | 
			
		||||
                    this._haveFingerprintReader = true;
 | 
			
		||||
            }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _reauthenticationChannelOpened: function(client, result) {
 | 
			
		||||
        try {
 | 
			
		||||
            this._userVerifier = client.open_reauthentication_channel_finish(result);
 | 
			
		||||
            this._connectSignals();
 | 
			
		||||
            this._beginVerification();
 | 
			
		||||
 | 
			
		||||
            this._hold.release();
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            if (this._reauthOnly) {
 | 
			
		||||
                logError(e, 'Failed to open reauthentication channel');
 | 
			
		||||
 | 
			
		||||
                this._hold.release();
 | 
			
		||||
                this.emit('verification-failed');
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // If there's no session running, or it otherwise fails, then fall back
 | 
			
		||||
            // to performing verification from this login session
 | 
			
		||||
            client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot));
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _userVerifierGot: function(client, result) {
 | 
			
		||||
        this._userVerifier = client.get_user_verifier_finish(result);
 | 
			
		||||
        this._connectSignals();
 | 
			
		||||
        this._beginVerification();
 | 
			
		||||
 | 
			
		||||
        this._hold.release();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _connectSignals: function() {
 | 
			
		||||
        this._userVerifier.connect('info', Lang.bind(this, this._onInfo));
 | 
			
		||||
        this._userVerifier.connect('problem', Lang.bind(this, this._onProblem));
 | 
			
		||||
        this._userVerifier.connect('info-query', Lang.bind(this, this._onInfoQuery));
 | 
			
		||||
        this._userVerifier.connect('secret-info-query', Lang.bind(this, this._onSecretInfoQuery));
 | 
			
		||||
        this._userVerifier.connect('conversation-stopped', Lang.bind(this, this._onConversationStopped));
 | 
			
		||||
        this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
 | 
			
		||||
        this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _beginVerification: function() {
 | 
			
		||||
        this._hold.acquire();
 | 
			
		||||
 | 
			
		||||
        if (this._userName) {
 | 
			
		||||
            this._userVerifier.call_begin_verification_for_user(PASSWORD_SERVICE_NAME,
 | 
			
		||||
                                                                this._userName,
 | 
			
		||||
                                                                this._cancellable,
 | 
			
		||||
                                                                Lang.bind(this, function(obj, result) {
 | 
			
		||||
                obj.call_begin_verification_for_user_finish(result);
 | 
			
		||||
                this._hold.release();
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            if (this._haveFingerprintReader) {
 | 
			
		||||
                this._hold.acquire();
 | 
			
		||||
 | 
			
		||||
                this._userVerifier.call_begin_verification_for_user(FINGERPRINT_SERVICE_NAME,
 | 
			
		||||
                                                                    this._userName,
 | 
			
		||||
                                                                    this._cancellable,
 | 
			
		||||
                                                                    Lang.bind(this, function(obj, result) {
 | 
			
		||||
                    obj.call_begin_verification_for_user_finish(result);
 | 
			
		||||
                    this._hold.release();
 | 
			
		||||
                }));
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            this._userVerifier.call_begin_verification(PASSWORD_SERVICE_NAME,
 | 
			
		||||
                                                       this._cancellable,
 | 
			
		||||
                                                       Lang.bind(this, function(obj, result) {
 | 
			
		||||
                obj.call_begin_verification_finish(result);
 | 
			
		||||
                this._hold.release();
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onInfo: function(client, serviceName, info) {
 | 
			
		||||
        // We don't display fingerprint messages, because they
 | 
			
		||||
        // have words like UPEK in them. Instead we use the messages
 | 
			
		||||
        // as a cue to display our own message.
 | 
			
		||||
        if (serviceName == FINGERPRINT_SERVICE_NAME &&
 | 
			
		||||
            this._haveFingerprintReader) {
 | 
			
		||||
            this.emit('show-fingerprint-prompt');
 | 
			
		||||
        } else if (serviceName == PASSWORD_SERVICE_NAME) {
 | 
			
		||||
            Main.notifyError(info);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onProblem: function(client, serviceName, problem) {
 | 
			
		||||
        // we don't want to show auth failed messages to
 | 
			
		||||
        // users who haven't enrolled their fingerprint.
 | 
			
		||||
        if (serviceName != PASSWORD_SERVICE_NAME)
 | 
			
		||||
            return;
 | 
			
		||||
        Main.notifyError(problem);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onInfoQuery: function(client, serviceName, question) {
 | 
			
		||||
        // We only expect questions to come from the main auth service
 | 
			
		||||
        if (serviceName != PASSWORD_SERVICE_NAME)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.emit('ask-question', serviceName, question, '');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onSecretInfoQuery: function(client, serviceName, secretQuestion) {
 | 
			
		||||
        // We only expect secret requests to come from the main auth service
 | 
			
		||||
        if (serviceName != PASSWORD_SERVICE_NAME)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.emit('ask-question', serviceName, secretQuestion, '\u25cf');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onReset: function() {
 | 
			
		||||
        this._userVerifier.run_dispose();
 | 
			
		||||
        this._userVerifier = null;
 | 
			
		||||
 | 
			
		||||
        this._checkForFingerprintReader();
 | 
			
		||||
 | 
			
		||||
        this.emit('reset');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onVerificationComplete: function() {
 | 
			
		||||
        this.emit('verification-complete');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onConversationStopped: function(client, serviceName) {
 | 
			
		||||
        // if the password service fails, then cancel everything.
 | 
			
		||||
        // But if, e.g., fingerprint fails, still give
 | 
			
		||||
        // password authentication a chance to succeed
 | 
			
		||||
        if (serviceName == PASSWORD_SERVICE_NAME) {
 | 
			
		||||
            this.emit('verification-failed');
 | 
			
		||||
        } else if (serviceName == FINGERPRINT_SERVICE_NAME) {
 | 
			
		||||
            this.emit('hide-fingerprint-prompt');
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ShellUserVerifier.prototype);
 | 
			
		||||
@@ -1,10 +1,15 @@
 | 
			
		||||
/* 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 */
 | 
			
		||||
const PACKAGE_VERSION = '@PACKAGE_VERSION@';
 | 
			
		||||
/* The version of GJS we're linking to */
 | 
			
		||||
const GJS_VERSION = '@GJS_VERSION@';
 | 
			
		||||
/* 1 if gnome-bluetooth is available, 0 otherwise */
 | 
			
		||||
const HAVE_BLUETOOTH = @HAVE_BLUETOOTH@;
 | 
			
		||||
 | 
			
		||||
/* gettext package */
 | 
			
		||||
const GETTEXT_PACKAGE = '@GETTEXT_PACKAGE@';
 | 
			
		||||
/* locale dir */
 | 
			
		||||
const LOCALEDIR = '@datadir@/locale';
 | 
			
		||||
/* other standard directories */
 | 
			
		||||
const LIBEXECDIR = '@libexecdir@';
 | 
			
		||||
const SYSCONFDIR = '@sysconfdir@';
 | 
			
		||||
 
 | 
			
		||||
@@ -1,140 +0,0 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Search = imports.ui.search;
 | 
			
		||||
 | 
			
		||||
const THUMBNAIL_ICON_MARGIN = 2;
 | 
			
		||||
 | 
			
		||||
function DocInfo(recentInfo) {
 | 
			
		||||
    this._init(recentInfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DocInfo.prototype = {
 | 
			
		||||
    _init : function(recentInfo) {
 | 
			
		||||
        this.recentInfo = recentInfo;
 | 
			
		||||
        // We actually used get_modified() instead of get_visited()
 | 
			
		||||
        // here, as GtkRecentInfo doesn't updated get_visited()
 | 
			
		||||
        // correctly. See http://bugzilla.gnome.org/show_bug.cgi?id=567094
 | 
			
		||||
        this.timestamp = recentInfo.get_modified();
 | 
			
		||||
        this.name = recentInfo.get_display_name();
 | 
			
		||||
        this._lowerName = this.name.toLowerCase();
 | 
			
		||||
        this.uri = recentInfo.get_uri();
 | 
			
		||||
        this.mimeType = recentInfo.get_mime_type();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createIcon : function(size) {
 | 
			
		||||
        return St.TextureCache.get_default().load_recent_thumbnail(size, this.recentInfo);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    launch : function(workspaceIndex) {
 | 
			
		||||
        Shell.DocSystem.get_default().open(this.recentInfo, workspaceIndex);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    matchTerms: function(terms) {
 | 
			
		||||
        let mtype = Search.MatchType.NONE;
 | 
			
		||||
        for (let i = 0; i < terms.length; i++) {
 | 
			
		||||
            let term = terms[i];
 | 
			
		||||
            let idx = this._lowerName.indexOf(term);
 | 
			
		||||
            if (idx == 0) {
 | 
			
		||||
                mtype = Search.MatchType.PREFIX;
 | 
			
		||||
            } else if (idx > 0) {
 | 
			
		||||
                if (mtype == Search.MatchType.NONE)
 | 
			
		||||
                    mtype = Search.MatchType.SUBSTRING;
 | 
			
		||||
            } else {
 | 
			
		||||
                return Search.MatchType.NONE;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return mtype;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
var docManagerInstance = null;
 | 
			
		||||
 | 
			
		||||
function getDocManager() {
 | 
			
		||||
    if (docManagerInstance == null)
 | 
			
		||||
        docManagerInstance = new DocManager();
 | 
			
		||||
    return docManagerInstance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * DocManager wraps the DocSystem, primarily to expose DocInfo objects.
 | 
			
		||||
 */
 | 
			
		||||
function DocManager() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DocManager.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._docSystem = Shell.DocSystem.get_default();
 | 
			
		||||
        this._infosByTimestamp = [];
 | 
			
		||||
        this._infosByUri = {};
 | 
			
		||||
        this._docSystem.connect('changed', Lang.bind(this, this._reload));
 | 
			
		||||
        this._reload();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _reload: function() {
 | 
			
		||||
        let docs = this._docSystem.get_all();
 | 
			
		||||
        this._infosByTimestamp = [];
 | 
			
		||||
        this._infosByUri = {};
 | 
			
		||||
        for (let i = 0; i < docs.length; i++) {
 | 
			
		||||
            let recentInfo = docs[i];
 | 
			
		||||
 | 
			
		||||
            let docInfo = new DocInfo(recentInfo);
 | 
			
		||||
            this._infosByTimestamp.push(docInfo);
 | 
			
		||||
            this._infosByUri[docInfo.uri] = docInfo;
 | 
			
		||||
        }
 | 
			
		||||
        this.emit('changed');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getTimestampOrderedInfos: function() {
 | 
			
		||||
        return this._infosByTimestamp;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getInfosByUri: function() {
 | 
			
		||||
        return this._infosByUri;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    lookupByUri: function(uri) {
 | 
			
		||||
        return this._infosByUri[uri];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    queueExistenceCheck: function(count) {
 | 
			
		||||
        return this._docSystem.queue_existence_check(count);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _searchDocs: function(items, terms) {
 | 
			
		||||
        let multiplePrefixMatches = [];
 | 
			
		||||
        let prefixMatches = [];
 | 
			
		||||
        let multipleSubtringMatches = [];
 | 
			
		||||
        let substringMatches = [];
 | 
			
		||||
        for (let i = 0; i < items.length; i++) {
 | 
			
		||||
            let item = items[i];
 | 
			
		||||
            let mtype = item.matchTerms(terms);
 | 
			
		||||
            if (mtype == Search.MatchType.MULTIPLE_PREFIX)
 | 
			
		||||
                multiplePrefixMatches.push(item.uri);
 | 
			
		||||
            else if (mtype == Search.MatchType.PREFIX)
 | 
			
		||||
                prefixMatches.push(item.uri);
 | 
			
		||||
            else if (mtype == Search.MatchType.MULTIPLE_SUBSTRING)
 | 
			
		||||
                multipleSubtringMatches.push(item.uri);
 | 
			
		||||
            else if (mtype == Search.MatchType.SUBSTRING)
 | 
			
		||||
                substringMatches.push(item.uri);
 | 
			
		||||
         }
 | 
			
		||||
        return multiplePrefixMatches.concat(prefixMatches.concat(multipleSubtringMatches.concat(substringMatches)));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    initialSearch: function(terms) {
 | 
			
		||||
        return this._searchDocs(this._infosByTimestamp, terms);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    subsearch: function(previousResults, terms) {
 | 
			
		||||
        return this._searchDocs(previousResults.map(Lang.bind(this,
 | 
			
		||||
            function(url) {
 | 
			
		||||
                return this._infosByUri[url];
 | 
			
		||||
            })), terms);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(DocManager.prototype);
 | 
			
		||||
							
								
								
									
										206
									
								
								js/misc/extensionUtils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,206 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
// Common utils for the extension system and the extension
 | 
			
		||||
// preferences tool
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const ShellJS = imports.gi.ShellJS;
 | 
			
		||||
 | 
			
		||||
const Config = imports.misc.config;
 | 
			
		||||
 | 
			
		||||
const ExtensionType = {
 | 
			
		||||
    SYSTEM: 1,
 | 
			
		||||
    PER_USER: 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Maps uuid -> metadata object
 | 
			
		||||
const extensions = {};
 | 
			
		||||
 | 
			
		||||
function getCurrentExtension() {
 | 
			
		||||
    let stack = (new Error()).stack;
 | 
			
		||||
 | 
			
		||||
    // Assuming we're importing this directly from an extension (and we shouldn't
 | 
			
		||||
    // ever not be), its UUID should be directly in the path here.
 | 
			
		||||
    let extensionStackLine = stack.split('\n')[1];
 | 
			
		||||
    if (!extensionStackLine)
 | 
			
		||||
        throw new Error('Could not find current extension');
 | 
			
		||||
 | 
			
		||||
    // The stack line is like:
 | 
			
		||||
    //   init([object Object])@/home/user/data/gnome-shell/extensions/u@u.id/prefs.js:8
 | 
			
		||||
    //
 | 
			
		||||
    // In the case that we're importing from
 | 
			
		||||
    // module scope, the first field is blank:
 | 
			
		||||
    //   @/home/user/data/gnome-shell/extensions/u@u.id/prefs.js:8
 | 
			
		||||
    let match = new RegExp('@(.+):\\d+').exec(extensionStackLine);
 | 
			
		||||
    if (!match)
 | 
			
		||||
        throw new Error('Could not find current extension');
 | 
			
		||||
 | 
			
		||||
    let path = match[1];
 | 
			
		||||
    let file = Gio.File.new_for_path(path);
 | 
			
		||||
 | 
			
		||||
    // Walk up the directory tree, looking for an extesion with
 | 
			
		||||
    // the same UUID as a directory name.
 | 
			
		||||
    while (file != null) {
 | 
			
		||||
        let extension = extensions[file.get_basename()];
 | 
			
		||||
        if (extension !== undefined)
 | 
			
		||||
            return extension;
 | 
			
		||||
        file = file.get_parent();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    throw new Error('Could not find current extension');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * versionCheck:
 | 
			
		||||
 * @required: an array of versions we're compatible with
 | 
			
		||||
 * @current: the version we have
 | 
			
		||||
 *
 | 
			
		||||
 * Check if a component is compatible for an extension.
 | 
			
		||||
 * @required is an array, and at least one version must match.
 | 
			
		||||
 * @current must be in the format <major>.<minor>.<point>.<micro>
 | 
			
		||||
 * <micro> is always ignored
 | 
			
		||||
 * <point> is ignored if <minor> is even (so you can target the
 | 
			
		||||
 * whole stable release)
 | 
			
		||||
 * <minor> and <major> must match
 | 
			
		||||
 * Each target version must be at least <major> and <minor>
 | 
			
		||||
 */
 | 
			
		||||
function versionCheck(required, current) {
 | 
			
		||||
    let currentArray = current.split('.');
 | 
			
		||||
    let major = currentArray[0];
 | 
			
		||||
    let minor = currentArray[1];
 | 
			
		||||
    let point = currentArray[2];
 | 
			
		||||
    for (let i = 0; i < required.length; i++) {
 | 
			
		||||
        let requiredArray = required[i].split('.');
 | 
			
		||||
        if (requiredArray[0] == major &&
 | 
			
		||||
            requiredArray[1] == minor &&
 | 
			
		||||
            (requiredArray[2] == point ||
 | 
			
		||||
             (requiredArray[2] == undefined && parseInt(minor) % 2 == 0)))
 | 
			
		||||
            return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isOutOfDate(extension) {
 | 
			
		||||
    if (!versionCheck(extension.metadata['shell-version'], Config.PACKAGE_VERSION))
 | 
			
		||||
        return true;
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createExtensionObject(uuid, dir, type) {
 | 
			
		||||
    let info;
 | 
			
		||||
 | 
			
		||||
    let metadataFile = dir.get_child('metadata.json');
 | 
			
		||||
    if (!metadataFile.query_exists(null)) {
 | 
			
		||||
        throw new Error('Missing metadata.json');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let metadataContents, success, tag;
 | 
			
		||||
    try {
 | 
			
		||||
        [success, metadataContents, tag] = metadataFile.load_contents(null);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        throw new Error('Failed to load metadata.json: ' + e);
 | 
			
		||||
    }
 | 
			
		||||
    let meta;
 | 
			
		||||
    try {
 | 
			
		||||
        meta = JSON.parse(metadataContents);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        throw new Error('Failed to parse metadata.json: ' + e);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let requiredProperties = ['uuid', 'name', 'description', 'shell-version'];
 | 
			
		||||
    for (let i = 0; i < requiredProperties.length; i++) {
 | 
			
		||||
        let prop = requiredProperties[i];
 | 
			
		||||
        if (!meta[prop]) {
 | 
			
		||||
            throw new Error('missing "' + prop + '" property in metadata.json');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Encourage people to add this
 | 
			
		||||
    if (!meta.url) {
 | 
			
		||||
        log('Warning: Missing "url" property in %s/metadata.json'.format(uuid));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (uuid != meta.uuid) {
 | 
			
		||||
        throw new Error('uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let extension = {};
 | 
			
		||||
 | 
			
		||||
    extension.metadata = meta;
 | 
			
		||||
    extension.uuid = meta.uuid;
 | 
			
		||||
    extension.type = type;
 | 
			
		||||
    extension.dir = dir;
 | 
			
		||||
    extension.path = dir.get_path();
 | 
			
		||||
    extension.error = '';
 | 
			
		||||
    extension.hasPrefs = dir.get_child('prefs.js').query_exists(null);
 | 
			
		||||
 | 
			
		||||
    extensions[uuid] = extension;
 | 
			
		||||
 | 
			
		||||
    return extension;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _extension = null;
 | 
			
		||||
 | 
			
		||||
function installImporter(extension) {
 | 
			
		||||
    _extension = extension;
 | 
			
		||||
    ShellJS.add_extension_importer('imports.misc.extensionUtils._extension', 'imports', extension.path);
 | 
			
		||||
    _extension = null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ExtensionFinder = new Lang.Class({
 | 
			
		||||
    Name: 'ExtensionFinder',
 | 
			
		||||
 | 
			
		||||
    _scanExtensionsInDirectory: function(dir, type) {
 | 
			
		||||
        let fileEnum;
 | 
			
		||||
        let file, info;
 | 
			
		||||
        try {
 | 
			
		||||
            fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            logError(e, 'Could not enumerate extensions directory');
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        while ((info = fileEnum.next_file(null)) != null) {
 | 
			
		||||
            let fileType = info.get_file_type();
 | 
			
		||||
            if (fileType != Gio.FileType.DIRECTORY)
 | 
			
		||||
                continue;
 | 
			
		||||
            let uuid = info.get_name();
 | 
			
		||||
            let extensionDir = dir.get_child(uuid);
 | 
			
		||||
 | 
			
		||||
            let existing = extensions[uuid];
 | 
			
		||||
            if (existing) {
 | 
			
		||||
                log('Extension %s already installed in %s. %s will not be loaded'.format(uuid, existing.path, extensionDir.get_path()));
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let extension;
 | 
			
		||||
            try {
 | 
			
		||||
                extension = createExtensionObject(uuid, extensionDir, type);
 | 
			
		||||
            } catch(e) {
 | 
			
		||||
                logError(e, 'Could not load extension %s'.format(uuid));
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            this.emit('extension-found', extension);
 | 
			
		||||
        }
 | 
			
		||||
        fileEnum.close(null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    scanExtensions: function() {
 | 
			
		||||
        let userExtensionsDir = Gio.File.new_for_path(GLib.build_filenamev([global.userdatadir, 'extensions']));
 | 
			
		||||
        this._scanExtensionsInDirectory(userExtensionsDir, ExtensionType.PER_USER);
 | 
			
		||||
 | 
			
		||||
        let systemDataDirs = GLib.get_system_data_dirs();
 | 
			
		||||
        for (let i = 0; i < systemDataDirs.length; i++) {
 | 
			
		||||
            let dirPath = GLib.build_filenamev([systemDataDirs[i], 'gnome-shell', 'extensions']);
 | 
			
		||||
            let dir = Gio.file_new_for_path(dirPath);
 | 
			
		||||
            if (dir.query_exists(null))
 | 
			
		||||
                this._scanExtensionsInDirectory(dir, ExtensionType.SYSTEM);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ExtensionFinder.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,46 @@ 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, deleteParent) {
 | 
			
		||||
    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.FileType.DIRECTORY)
 | 
			
		||||
            recursivelyDeleteDir(child, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (deleteParent)
 | 
			
		||||
        deleteGFile(dir);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function recursivelyMoveDir(srcDir, destDir) {
 | 
			
		||||
    let children = srcDir.enumerate_children('standard::name,standard::type',
 | 
			
		||||
                                             Gio.FileQueryInfoFlags.NONE, null);
 | 
			
		||||
 | 
			
		||||
    if (!destDir.query_exists(null))
 | 
			
		||||
        destDir.make_directory_with_parents(null);
 | 
			
		||||
 | 
			
		||||
    let info, child;
 | 
			
		||||
    while ((info = children.next_file(null)) != null) {
 | 
			
		||||
        let type = info.get_file_type();
 | 
			
		||||
        let srcChild = srcDir.get_child(info.get_name());
 | 
			
		||||
        let destChild = destDir.get_child(info.get_name());
 | 
			
		||||
        log([srcChild.get_path(), destChild.get_path()]);
 | 
			
		||||
        if (type == Gio.FileType.REGULAR)
 | 
			
		||||
            srcChild.move(destChild, Gio.FileCopyFlags.NONE, null, null);
 | 
			
		||||
        else if (type == Gio.FileType.DIRECTORY)
 | 
			
		||||
            recursivelyMoveDir(srcChild, destChild);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,60 +0,0 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This function is intended to extend the String object and provide
 | 
			
		||||
 * an String.format API for string formatting.
 | 
			
		||||
 * It has to be set up using String.prototype.format = Format.format;
 | 
			
		||||
 * Usage:
 | 
			
		||||
 * "somestring %s %d".format('hello', 5);
 | 
			
		||||
 * It supports %s, %d, %x and %f, for %f it also support precisions like
 | 
			
		||||
 * "%.2f".format(1.526). All specifiers can be prefixed with a minimum
 | 
			
		||||
 * field width, e.g. "%5s".format("foo"). Unless the width is prefixed
 | 
			
		||||
 * with '0', the formatted string will be padded with spaces.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
function format() {
 | 
			
		||||
    let str = this;
 | 
			
		||||
    let i = 0;
 | 
			
		||||
    let args = arguments;
 | 
			
		||||
 | 
			
		||||
    return str.replace(/%([0-9]+)?(?:\.([0-9]+))?(.)/g, function (str, widthGroup, precisionGroup, genericGroup) {
 | 
			
		||||
 | 
			
		||||
                    if (precisionGroup != '' && genericGroup != 'f')
 | 
			
		||||
                        throw new Error("Precision can only be specified for 'f'");
 | 
			
		||||
 | 
			
		||||
                    let fillChar = (widthGroup[0] == '0') ? '0' : ' ';
 | 
			
		||||
                    let width = parseInt(widthGroup, 10) || 0;
 | 
			
		||||
 | 
			
		||||
                    function fillWidth(s, c, w) {
 | 
			
		||||
                        let fill = '';
 | 
			
		||||
                        for (let i = 0; i < w; i++)
 | 
			
		||||
                            fill += c;
 | 
			
		||||
                        return fill.substr(s.length) + s;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    let s = '';
 | 
			
		||||
                    switch (genericGroup) {
 | 
			
		||||
                        case '%':
 | 
			
		||||
                            return '%';
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 's':
 | 
			
		||||
                            s = args[i++].toString();
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 'd':
 | 
			
		||||
                            s = parseInt(args[i++]).toString();
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 'x':
 | 
			
		||||
                            s = parseInt(args[i++]).toString(16);
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 'f':
 | 
			
		||||
                            if (precisionGroup == '')
 | 
			
		||||
                                s = parseFloat(args[i++]).toString();
 | 
			
		||||
                            else
 | 
			
		||||
                                s = parseFloat(args[i++]).toFixed(parseInt(precisionGroup));
 | 
			
		||||
                            break;
 | 
			
		||||
                        default:
 | 
			
		||||
                            throw new Error('Unsupported conversion character %' + genericGroup);
 | 
			
		||||
                    }
 | 
			
		||||
                    return fillWidth(s, fillChar, width);
 | 
			
		||||
                });
 | 
			
		||||
}
 | 
			
		||||
@@ -1,20 +1,18 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const DBus = imports.dbus;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const PresenceIface = {
 | 
			
		||||
    name: 'org.gnome.SessionManager.Presence',
 | 
			
		||||
    methods: [{ name: 'SetStatus',
 | 
			
		||||
                inSignature: 'u',
 | 
			
		||||
                outSignature: '' }],
 | 
			
		||||
    properties: [{ name: 'status',
 | 
			
		||||
                   signature: 'u',
 | 
			
		||||
                   access: 'readwrite' }],
 | 
			
		||||
    signals: [{ name: 'StatusChanged',
 | 
			
		||||
                inSignature: 'u' }]
 | 
			
		||||
};
 | 
			
		||||
const PresenceIface = <interface name="org.gnome.SessionManager.Presence">
 | 
			
		||||
<method name="SetStatus">
 | 
			
		||||
    <arg type="u" direction="in"/>
 | 
			
		||||
</method>
 | 
			
		||||
<property name="status" type="u" access="readwrite"/>
 | 
			
		||||
<signal name="StatusChanged">
 | 
			
		||||
    <arg type="u" direction="out"/>
 | 
			
		||||
</signal>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const PresenceStatus = {
 | 
			
		||||
    AVAILABLE: 0,
 | 
			
		||||
@@ -23,104 +21,52 @@ 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">
 | 
			
		||||
<method name="GetAppId">
 | 
			
		||||
    <arg type="s" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="GetReason">
 | 
			
		||||
    <arg type="s" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
function Inhibitor(objectPath) {
 | 
			
		||||
    this._init(objectPath);
 | 
			
		||||
var InhibitorProxy = Gio.DBusProxy.makeProxyWrapper(InhibitorIface);
 | 
			
		||||
function Inhibitor(objectPath, initCallback, cancellable) {
 | 
			
		||||
    return new InhibitorProxy(Gio.DBus.session, 'org.gnome.SessionManager', objectPath, initCallback, cancellable);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Inhibitor.prototype = {
 | 
			
		||||
    _init: function(objectPath) {
 | 
			
		||||
        DBus.session.proxifyObject(this,
 | 
			
		||||
                                   "org.gnome.SessionManager",
 | 
			
		||||
                                   objectPath);
 | 
			
		||||
        this.isLoaded = false;
 | 
			
		||||
        this._loadingPropertiesCount = InhibitorIface.properties.length;
 | 
			
		||||
        for (let i = 0; i < InhibitorIface.properties.length; i++) {
 | 
			
		||||
            let propertyName = InhibitorIface.properties[i].name;
 | 
			
		||||
            this.GetRemote(propertyName, Lang.bind(this,
 | 
			
		||||
                function(value, exception) {
 | 
			
		||||
                    if (exception)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    this[propertyName] = value;
 | 
			
		||||
                    this._loadingPropertiesCount--;
 | 
			
		||||
 | 
			
		||||
                    if (this._loadingPropertiesCount == 0) {
 | 
			
		||||
                        this.isLoaded = true;
 | 
			
		||||
                        this.emit("is-loaded");
 | 
			
		||||
                    }
 | 
			
		||||
                }));
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
DBus.proxifyPrototype(Inhibitor.prototype, InhibitorIface);
 | 
			
		||||
Signals.addSignalMethods(Inhibitor.prototype);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Not the full interface, only the methods we use
 | 
			
		||||
const SessionManagerIface = {
 | 
			
		||||
    name: 'org.gnome.SessionManager',
 | 
			
		||||
    methods: [
 | 
			
		||||
        { name: 'Logout', inSignature: 'u', outSignature: '' },
 | 
			
		||||
        { name: 'Shutdown', inSignature: '', outSignature: '' },
 | 
			
		||||
        { name: 'CanShutdown', inSignature: '', outSignature: 'b' }
 | 
			
		||||
    ]
 | 
			
		||||
};
 | 
			
		||||
const SessionManagerIface = <interface name="org.gnome.SessionManager">
 | 
			
		||||
<method name="Logout">
 | 
			
		||||
    <arg type="u" direction="in" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="Shutdown" />
 | 
			
		||||
<method name="Reboot" />
 | 
			
		||||
<method name="CanShutdown">
 | 
			
		||||
    <arg type="b" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="IsInhibited">
 | 
			
		||||
    <arg type="u" direction="in" />
 | 
			
		||||
    <arg type="b" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<signal name="InhibitorAdded">
 | 
			
		||||
    <arg type="o" direction="out"/>
 | 
			
		||||
</signal>
 | 
			
		||||
<signal name="InhibitorRemoved">
 | 
			
		||||
    <arg type="o" direction="out"/>
 | 
			
		||||
</signal>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
function SessionManager() {
 | 
			
		||||
    this._init();
 | 
			
		||||
var SessionManagerProxy = Gio.DBusProxy.makeProxyWrapper(SessionManagerIface);
 | 
			
		||||
function SessionManager(initCallback, cancellable) {
 | 
			
		||||
    return new SessionManagerProxy(Gio.DBus.session, 'org.gnome.SessionManager', '/org/gnome/SessionManager', initCallback, cancellable);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SessionManager.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        DBus.session.proxifyObject(this, 'org.gnome.SessionManager', '/org/gnome/SessionManager');
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
DBus.proxifyPrototype(SessionManager.prototype, SessionManagerIface);
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
@@ -7,11 +7,9 @@ const Params = imports.misc.params;
 | 
			
		||||
 | 
			
		||||
const DEFAULT_LIMIT = 512;
 | 
			
		||||
 | 
			
		||||
function HistoryManager(params) {
 | 
			
		||||
    this._init(params);
 | 
			
		||||
}
 | 
			
		||||
const HistoryManager = new Lang.Class({
 | 
			
		||||
    Name: 'HistoryManager',
 | 
			
		||||
 | 
			
		||||
HistoryManager.prototype = {
 | 
			
		||||
    _init: function(params) {
 | 
			
		||||
        params = Params.parse(params, { gsettingsKey: null,
 | 
			
		||||
                                        limit: DEFAULT_LIMIT,
 | 
			
		||||
@@ -111,5 +109,5 @@ HistoryManager.prototype = {
 | 
			
		||||
        if (this._key)
 | 
			
		||||
            global.settings.set_strv(this._key, this._history);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(HistoryManager.prototype);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										246
									
								
								js/misc/jsParse.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,246 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
 | 
			
		||||
// Returns a list of potential completions for text. Completions either
 | 
			
		||||
// follow a dot (e.g. foo.ba -> bar) or they are picked from globalCompletionList (e.g. fo -> foo)
 | 
			
		||||
// commandHeader is prefixed on any expression before it is eval'ed.  It will most likely
 | 
			
		||||
// consist of global constants that might not carry over from the calling environment.
 | 
			
		||||
//
 | 
			
		||||
// This function is likely the one you want to call from external modules
 | 
			
		||||
function getCompletions(text, commandHeader, globalCompletionList) {
 | 
			
		||||
    let methods = [];
 | 
			
		||||
    let expr, base;
 | 
			
		||||
    let attrHead = '';
 | 
			
		||||
    if (globalCompletionList == null) {
 | 
			
		||||
        globalCompletionList = [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let offset = getExpressionOffset(text, text.length - 1);
 | 
			
		||||
    if (offset >= 0) {
 | 
			
		||||
        text = text.slice(offset);
 | 
			
		||||
 | 
			
		||||
        // Look for expressions like "Main.panel.foo" and match Main.panel and foo
 | 
			
		||||
        let matches = text.match(/(.*)\.(.*)/);
 | 
			
		||||
        if (matches) {
 | 
			
		||||
            [expr, base, attrHead] = matches;
 | 
			
		||||
 | 
			
		||||
            methods = getPropertyNamesFromExpression(base, commandHeader).filter(function(attr) {
 | 
			
		||||
                return attr.slice(0, attrHead.length) == attrHead;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Look for the empty expression or partially entered words
 | 
			
		||||
        // not proceeded by a dot and match them against global constants
 | 
			
		||||
        matches = text.match(/^(\w*)$/);
 | 
			
		||||
        if (text == '' || matches) {
 | 
			
		||||
            [expr, attrHead] = matches;
 | 
			
		||||
            methods = globalCompletionList.filter(function(attr) {
 | 
			
		||||
                return attr.slice(0, attrHead.length) == attrHead;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return [methods, attrHead];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// A few functions for parsing strings of javascript code.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
// Identify characters that delimit an expression.  That is,
 | 
			
		||||
// if we encounter anything that isn't a letter, '.', ')', or ']',
 | 
			
		||||
// we should stop parsing.
 | 
			
		||||
function isStopChar(c) {
 | 
			
		||||
    return !c.match(/[\w\.\)\]]/);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Given the ending position of a quoted string, find where it starts
 | 
			
		||||
function findMatchingQuote(expr, offset) {
 | 
			
		||||
    let quoteChar = expr.charAt(offset);
 | 
			
		||||
    for (let i = offset - 1; i >= 0; --i) {
 | 
			
		||||
        if (expr.charAt(i) == quoteChar && expr.charAt(i-1) != '\\'){
 | 
			
		||||
            return i;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Given the ending position of a regex, find where it starts
 | 
			
		||||
function findMatchingSlash(expr, offset) {
 | 
			
		||||
    for (let i = offset - 1; i >= 0; --i) {
 | 
			
		||||
        if (expr.charAt(i) == '/' && expr.charAt(i-1) != '\\'){
 | 
			
		||||
            return i;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// If expr.charAt(offset) is ')' or ']',
 | 
			
		||||
// return the position of the corresponding '(' or '[' bracket.
 | 
			
		||||
// This function does not check for syntactic correctness.  e.g.,
 | 
			
		||||
// findMatchingBrace("[(])", 3) returns 1.
 | 
			
		||||
function findMatchingBrace(expr, offset) {
 | 
			
		||||
    let closeBrace = expr.charAt(offset);
 | 
			
		||||
    let openBrace = ({')': '(', ']': '['})[closeBrace];
 | 
			
		||||
 | 
			
		||||
    function findTheBrace(expr, offset) {
 | 
			
		||||
        if (offset < 0) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (expr.charAt(offset) == openBrace) {
 | 
			
		||||
            return offset;
 | 
			
		||||
        }
 | 
			
		||||
        if (expr.charAt(offset).match(/['"]/)) {
 | 
			
		||||
            return findTheBrace(expr, findMatchingQuote(expr, offset) - 1);
 | 
			
		||||
        }
 | 
			
		||||
        if (expr.charAt(offset) == '/') {
 | 
			
		||||
            return findTheBrace(expr, findMatchingSlash(expr, offset) - 1);
 | 
			
		||||
        }
 | 
			
		||||
        if (expr.charAt(offset) == closeBrace) {
 | 
			
		||||
            return findTheBrace(expr, findTheBrace(expr, offset - 1) - 1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return findTheBrace(expr, offset - 1);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return findTheBrace(expr, offset - 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Walk expr backwards from offset looking for the beginning of an
 | 
			
		||||
// expression suitable for passing to eval.
 | 
			
		||||
// There is no guarantee of correct javascript syntax between the return
 | 
			
		||||
// value and offset.  This function is meant to take a string like
 | 
			
		||||
// "foo(Obj.We.Are.Completing" and allow you to extract "Obj.We.Are.Completing"
 | 
			
		||||
function getExpressionOffset(expr, offset) {
 | 
			
		||||
    while (offset >= 0) {
 | 
			
		||||
        let currChar = expr.charAt(offset);
 | 
			
		||||
 | 
			
		||||
        if (isStopChar(currChar)){
 | 
			
		||||
            return offset + 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (currChar.match(/[\)\]]/)) {
 | 
			
		||||
            offset = findMatchingBrace(expr, offset);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        --offset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return offset + 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Things with non-word characters or that start with a number
 | 
			
		||||
// are not accessible via .foo notation and so aren't returned
 | 
			
		||||
function isValidPropertyName(w) {
 | 
			
		||||
    return !(w.match(/\W/) || w.match(/^\d/));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// To get all properties (enumerable and not), we need to walk
 | 
			
		||||
// the prototype chain ourselves
 | 
			
		||||
function getAllProps(obj) {
 | 
			
		||||
    if (obj === null || obj === undefined) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    return Object.getOwnPropertyNames(obj).concat( getAllProps(Object.getPrototypeOf(obj)) );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Given a string _expr_, returns all methods
 | 
			
		||||
// that can be accessed via '.' notation.
 | 
			
		||||
// e.g., expr="({ foo: null, bar: null, 4: null })" will
 | 
			
		||||
// return ["foo", "bar", ...] but the list will not include "4",
 | 
			
		||||
// since methods accessed with '.' notation must star with a letter or _.
 | 
			
		||||
function getPropertyNamesFromExpression(expr, commandHeader) {
 | 
			
		||||
    if (commandHeader == null) {
 | 
			
		||||
        commandHeader = '';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let obj = {};
 | 
			
		||||
    if (!isUnsafeExpression(expr)) {
 | 
			
		||||
        try {
 | 
			
		||||
                obj = eval(commandHeader + expr);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let propsUnique = {};
 | 
			
		||||
    if (typeof obj === 'object'){
 | 
			
		||||
        let allProps = getAllProps(obj);
 | 
			
		||||
        // Get only things we are allowed to complete following a '.'
 | 
			
		||||
        allProps = allProps.filter( isValidPropertyName );
 | 
			
		||||
 | 
			
		||||
        // Make sure propsUnique contains one key for every
 | 
			
		||||
        // property so we end up with a unique list of properties
 | 
			
		||||
        allProps.map(function(p){ propsUnique[p] = null; });
 | 
			
		||||
    }
 | 
			
		||||
    return Object.keys(propsUnique).sort();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Given a list of words, returns the longest prefix they all have in common
 | 
			
		||||
function getCommonPrefix(words) {
 | 
			
		||||
    let word = words[0];
 | 
			
		||||
    for (let i = 0; i < word.length; i++) {
 | 
			
		||||
        for (let w = 1; w < words.length; w++) {
 | 
			
		||||
            if (words[w].charAt(i) != word.charAt(i))
 | 
			
		||||
                return word.slice(0, i);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return word;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns true if there is reason to think that eval(str)
 | 
			
		||||
// will modify the global scope
 | 
			
		||||
function isUnsafeExpression(str) {
 | 
			
		||||
    // Remove any blocks that are quoted or are in a regex
 | 
			
		||||
    function removeLiterals(str) {
 | 
			
		||||
        if (str.length == 0) {
 | 
			
		||||
            return '';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let currChar = str.charAt(str.length - 1);
 | 
			
		||||
        if (currChar == '"' || currChar == '\'') {
 | 
			
		||||
            return removeLiterals(str.slice(0, findMatchingQuote(str, str.length - 1)));
 | 
			
		||||
        } else if (currChar == '/') {
 | 
			
		||||
            return removeLiterals(str.slice(0, findMatchingSlash(str, str.length - 1)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return removeLiterals(str.slice(0, str.length - 1)) + currChar;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check for any sort of assignment
 | 
			
		||||
    // The strategy used is dumb: remove any quotes
 | 
			
		||||
    // or regexs and comparison operators and see if there is an '=' character.
 | 
			
		||||
    // If there is, it might be an unsafe assignment.
 | 
			
		||||
 | 
			
		||||
    let prunedStr = removeLiterals(str);
 | 
			
		||||
    prunedStr = prunedStr.replace(/[=!]==/g, '');    //replace === and !== with nothing
 | 
			
		||||
    prunedStr = prunedStr.replace(/[=<>!]=/g, '');    //replace ==, <=, >=, != with nothing
 | 
			
		||||
 | 
			
		||||
    if (prunedStr.match(/=/)) {
 | 
			
		||||
        return true;
 | 
			
		||||
    } else if (prunedStr.match(/;/)) {
 | 
			
		||||
        // If we contain a semicolon not inside of a quote/regex, assume we're unsafe as well
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a list of global keywords derived from str
 | 
			
		||||
function getDeclaredConstants(str) {
 | 
			
		||||
    let ret = [];
 | 
			
		||||
    str.split(';').forEach(function(s) {
 | 
			
		||||
        let base, keyword;
 | 
			
		||||
        let match = s.match(/const\s+(\w+)\s*=/);
 | 
			
		||||
        if (match) {
 | 
			
		||||
            [base, keyword] = match;
 | 
			
		||||
            ret.push(keyword);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const DBus = imports.dbus;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
@@ -8,33 +8,39 @@ const Signals = imports.signals;
 | 
			
		||||
// The following are not the complete interfaces, just the methods we need
 | 
			
		||||
// (or may need in the future)
 | 
			
		||||
 | 
			
		||||
const ModemGsmNetworkInterface = {
 | 
			
		||||
    name: 'org.freedesktop.ModemManager.Modem.Gsm.Network',
 | 
			
		||||
    methods: [
 | 
			
		||||
        { name: 'GetRegistrationInfo', inSignature: '', outSignature: 'uss' },
 | 
			
		||||
        { name: 'GetSignalQuality', inSignature: '', outSignature: 'u' }
 | 
			
		||||
    ],
 | 
			
		||||
    properties: [
 | 
			
		||||
        { name: 'AccessTechnology', signature: 'u', access: 'read' }
 | 
			
		||||
    ],
 | 
			
		||||
    signals: [
 | 
			
		||||
        { name: 'SignalQuality', inSignature: 'u' },
 | 
			
		||||
        { name: 'RegistrationInfo', inSignature: 'uss' }
 | 
			
		||||
    ]
 | 
			
		||||
};
 | 
			
		||||
const ModemGsmNetworkProxy = DBus.makeProxyClass(ModemGsmNetworkInterface);
 | 
			
		||||
const ModemGsmNetworkInterface = <interface name="org.freedesktop.ModemManager.Modem.Gsm.Network">
 | 
			
		||||
<method name="GetRegistrationInfo">
 | 
			
		||||
    <arg type="(uss)" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="GetSignalQuality">
 | 
			
		||||
    <arg type="u" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<property name="AccessTechnology" type="u" access="read" />
 | 
			
		||||
<signal name="SignalQuality">
 | 
			
		||||
    <arg type="u" direction="out" />
 | 
			
		||||
</signal>
 | 
			
		||||
<signal name="RegistrationInfo">
 | 
			
		||||
    <arg type="u" direction="out" />
 | 
			
		||||
    <arg type="s" direction="out" />
 | 
			
		||||
    <arg type="s" direction="out" />
 | 
			
		||||
</signal>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const ModemCdmaInterface = {
 | 
			
		||||
    name: 'org.freedesktop.ModemManager.Modem.Cdma',
 | 
			
		||||
    methods: [
 | 
			
		||||
        { name: 'GetSignalQuality', inSignature: '', outSignature: 'u' },
 | 
			
		||||
        { name: 'GetServingSystem', inSignature: '', outSignature: 'usu' }
 | 
			
		||||
    ],
 | 
			
		||||
    signals: [
 | 
			
		||||
        { name: 'SignalQuality', inSignature: 'u' }
 | 
			
		||||
    ]
 | 
			
		||||
};
 | 
			
		||||
const ModemCdmaProxy = DBus.makeProxyClass(ModemCdmaInterface);
 | 
			
		||||
const ModemGsmNetworkProxy = Gio.DBusProxy.makeProxyWrapper(ModemGsmNetworkInterface);
 | 
			
		||||
 | 
			
		||||
const ModemCdmaInterface = <interface name="org.freedesktop.ModemManager.Modem.Cdma">
 | 
			
		||||
<method name="GetSignalQuality">
 | 
			
		||||
    <arg type="u" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="GetServingSystem">
 | 
			
		||||
    <arg type="(usu)" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<signal name="SignalQuality">
 | 
			
		||||
    <arg type="u" direction="out" />
 | 
			
		||||
</signal>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const ModemCdmaProxy = Gio.DBusProxy.makeProxyWrapper(ModemCdmaInterface);
 | 
			
		||||
 | 
			
		||||
let _providersTable;
 | 
			
		||||
function _getProvidersTable() {
 | 
			
		||||
@@ -44,27 +50,25 @@ function _getProvidersTable() {
 | 
			
		||||
    return _providersTable = providers;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ModemGsm() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
const ModemGsm = new Lang.Class({
 | 
			
		||||
    Name: 'ModemGsm',
 | 
			
		||||
 | 
			
		||||
ModemGsm.prototype = {
 | 
			
		||||
    _init: function(path) {
 | 
			
		||||
        this._proxy = new ModemGsmNetworkProxy(DBus.system, 'org.freedesktop.ModemManager', path);
 | 
			
		||||
        this._proxy = new ModemGsmNetworkProxy(Gio.DBus.system, 'org.freedesktop.ModemManager', path);
 | 
			
		||||
 | 
			
		||||
        this.signal_quality = 0;
 | 
			
		||||
        this.operator_name = null;
 | 
			
		||||
 | 
			
		||||
        // Code is duplicated because the function have different signatures
 | 
			
		||||
        this._proxy.connect('SignalQuality', Lang.bind(this, function(proxy, quality) {
 | 
			
		||||
        this._proxy.connectSignal('SignalQuality', Lang.bind(this, function(proxy, sender, [quality]) {
 | 
			
		||||
            this.signal_quality = quality;
 | 
			
		||||
            this.emit('notify::signal-quality');
 | 
			
		||||
        }));
 | 
			
		||||
        this._proxy.connect('RegistrationInfo', Lang.bind(this, function(proxy, status, code, name) {
 | 
			
		||||
        this._proxy.connectSignal('RegistrationInfo', Lang.bind(this, function(proxy, sender, [status, code, name]) {
 | 
			
		||||
            this.operator_name = this._findOperatorName(name, code);
 | 
			
		||||
            this.emit('notify::operator-name');
 | 
			
		||||
        }));
 | 
			
		||||
        this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function(result, err) {
 | 
			
		||||
        this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function([result], err) {
 | 
			
		||||
            if (err) {
 | 
			
		||||
                log(err);
 | 
			
		||||
                return;
 | 
			
		||||
@@ -146,21 +150,19 @@ ModemGsm.prototype = {
 | 
			
		||||
 | 
			
		||||
        return name3 || name2 || null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ModemGsm.prototype);
 | 
			
		||||
 | 
			
		||||
function ModemCdma() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
const ModemCdma = new Lang.Class({
 | 
			
		||||
    Name: 'ModemCdma',
 | 
			
		||||
 | 
			
		||||
ModemCdma.prototype = {
 | 
			
		||||
    _init: function(path) {
 | 
			
		||||
        this._proxy = new ModemCdmaProxy(DBus.system, 'org.freedesktop.ModemManager', path);
 | 
			
		||||
        this._proxy = new ModemCdmaProxy(Gio.DBus.system, 'org.freedesktop.ModemManager', path);
 | 
			
		||||
 | 
			
		||||
        this.signal_quality = 0;
 | 
			
		||||
        this.operator_name = null;
 | 
			
		||||
        this._proxy.connect('SignalQuality', Lang.bind(this, function(proxy, quality) {
 | 
			
		||||
            this.signal_quality = quality;
 | 
			
		||||
        this._proxy.connectSignal('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
 | 
			
		||||
@@ -181,7 +183,7 @@ ModemCdma.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _refreshServingSystem: function() {
 | 
			
		||||
        this._proxy.GetServingSystemRemote(Lang.bind(this, function(result, err) {
 | 
			
		||||
        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;
 | 
			
		||||
@@ -221,5 +223,5 @@ ModemCdma.prototype = {
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ModemCdma.prototype);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
// parse:
 | 
			
		||||
// @params: caller-provided parameter object, or %null
 | 
			
		||||
 
 | 
			
		||||
@@ -1,53 +0,0 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
 | 
			
		||||
const DBus = imports.dbus;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
 | 
			
		||||
const ScreenSaverIface = {
 | 
			
		||||
    name: 'org.gnome.ScreenSaver',
 | 
			
		||||
    methods: [{ name: 'GetActive',
 | 
			
		||||
                inSignature: '',
 | 
			
		||||
                outSignature: 'b' },
 | 
			
		||||
              { name: 'Lock',
 | 
			
		||||
                inSignature: '' },
 | 
			
		||||
              { name: 'SetActive',
 | 
			
		||||
                inSignature: 'b' }],
 | 
			
		||||
    signals: [{ name: 'ActiveChanged',
 | 
			
		||||
                inSignature: 'b' }]
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function ScreenSaverProxy() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ScreenSaverProxy.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        DBus.session.proxifyObject(this,
 | 
			
		||||
                                   'org.gnome.ScreenSaver',
 | 
			
		||||
                                   '/org/gnome/ScreenSaver');
 | 
			
		||||
 | 
			
		||||
        DBus.session.watch_name('org.gnome.ScreenSaver',
 | 
			
		||||
                                false, // do not launch a name-owner if none exists
 | 
			
		||||
                                Lang.bind(this, this._onSSAppeared),
 | 
			
		||||
                                Lang.bind(this, this._onSSVanished));
 | 
			
		||||
 | 
			
		||||
        this.screenSaverActive = false;
 | 
			
		||||
        this.connect('ActiveChanged',
 | 
			
		||||
                     Lang.bind(this, this._onActiveChanged));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onSSAppeared: function(owner) {
 | 
			
		||||
        this.GetActiveRemote(Lang.bind(this, function(isActive) {
 | 
			
		||||
            this.screenSaverActive = isActive;
 | 
			
		||||
        }))
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onSSVanished: function(oldOwner) {
 | 
			
		||||
        this.screenSaverActive = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onActiveChanged: function(object, isActive) {
 | 
			
		||||
        this.screenSaverActive = isActive;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
DBus.proxifyPrototype(ScreenSaverProxy.prototype, ScreenSaverIface);
 | 
			
		||||
							
								
								
									
										114
									
								
								js/misc/util.js
									
									
									
									
									
								
							
							
						
						@@ -1,14 +1,35 @@
 | 
			
		||||
/* -*- 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;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
 | 
			
		||||
/* http://daringfireball.net/2010/07/improved_regex_for_matching_urls */
 | 
			
		||||
const _urlRegexp = new RegExp('\\b(([a-z][\\w-]+:(/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)([^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:\'\\".,<>?«»“”‘’]))', 'gi');
 | 
			
		||||
// http://daringfireball.net/2010/07/improved_regex_for_matching_urls
 | 
			
		||||
const _balancedParens = '\\((?:[^\\s()<>]+|(?:\\(?:[^\\s()<>]+\\)))*\\)';
 | 
			
		||||
const _leadingJunk = '[\\s`(\\[{\'\\"<\u00AB\u201C\u2018]';
 | 
			
		||||
const _notTrailingJunk = '[^\\s`!()\\[\\]{};:\'\\".,<>?\u00AB\u00BB\u201C\u201D\u2018\u2019]';
 | 
			
		||||
 | 
			
		||||
const _urlRegexp = new RegExp(
 | 
			
		||||
    '(^|' + _leadingJunk + ')' +
 | 
			
		||||
    '(' +
 | 
			
		||||
        '(?:' +
 | 
			
		||||
            '[a-z][\\w-]+://' +                   // scheme://
 | 
			
		||||
            '|' +
 | 
			
		||||
            'www\\d{0,3}[.]' +                    // www.
 | 
			
		||||
            '|' +
 | 
			
		||||
            '[a-z0-9.\\-]+[.][a-z]{2,4}/' +       // foo.xx/
 | 
			
		||||
        ')' +
 | 
			
		||||
        '(?:' +                                   // one or more:
 | 
			
		||||
            '[^\\s()<>]+' +                       // run of non-space non-()
 | 
			
		||||
            '|' +                                 // or
 | 
			
		||||
            _balancedParens +                     // balanced parens
 | 
			
		||||
        ')+' +
 | 
			
		||||
        '(?:' +                                   // end with:
 | 
			
		||||
            _balancedParens +                     // balanced parens
 | 
			
		||||
            '|' +                                 // or
 | 
			
		||||
            _notTrailingJunk +                    // last non-junk char
 | 
			
		||||
        ')' +
 | 
			
		||||
    ')', 'gi');
 | 
			
		||||
 | 
			
		||||
// findUrls:
 | 
			
		||||
// @str: string to find URLs in
 | 
			
		||||
@@ -21,7 +42,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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -59,24 +80,33 @@ function spawnCommandLine(command_line) {
 | 
			
		||||
// this will throw an error.
 | 
			
		||||
function trySpawn(argv)
 | 
			
		||||
{
 | 
			
		||||
    var success, pid;
 | 
			
		||||
    try {
 | 
			
		||||
        GLib.spawn_async(null, argv, null,
 | 
			
		||||
                         GLib.SpawnFlags.SEARCH_PATH,
 | 
			
		||||
                         null, null);
 | 
			
		||||
        [success, pid] = GLib.spawn_async(null, argv, null,
 | 
			
		||||
                                          GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
 | 
			
		||||
                                          null, null);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
        if (err.code == GLib.SpawnError.G_SPAWN_ERROR_NOENT) {
 | 
			
		||||
            err.message = _("Command not found");
 | 
			
		||||
        } else {
 | 
			
		||||
        /* Rewrite the error in case of ENOENT */
 | 
			
		||||
        if (err.matches(GLib.SpawnError, GLib.SpawnError.NOENT)) {
 | 
			
		||||
            throw new GLib.SpawnError({ code: GLib.SpawnError.NOENT,
 | 
			
		||||
                                        message: _("Command not found") });
 | 
			
		||||
        } else if (err instanceof GLib.Error) {
 | 
			
		||||
            // The exception from gjs contains an error string like:
 | 
			
		||||
            //   Error invoking GLib.spawn_command_line_async: Failed to
 | 
			
		||||
            //   execute child process "foo" (No such file or directory)
 | 
			
		||||
            // We are only interested in the part in the parentheses. (And
 | 
			
		||||
            // we can't pattern match the text, since it gets localized.)
 | 
			
		||||
            err.message = err.message.replace(/.*\((.+)\)/, '$1');
 | 
			
		||||
            let message = err.message.replace(/.*\((.+)\)/, '$1');
 | 
			
		||||
            throw new (err.constructor)({ code: err.code,
 | 
			
		||||
                                          message: message });
 | 
			
		||||
        } else {
 | 
			
		||||
            throw err;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        throw err;
 | 
			
		||||
    }
 | 
			
		||||
    // Dummy child watch; we don't want to double-fork internally
 | 
			
		||||
    // because then we lose the parent-child relationship, which
 | 
			
		||||
    // can break polkit.  See https://bugzilla.redhat.com//show_bug.cgi?id=819275
 | 
			
		||||
    GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function () {}, null);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// trySpawnCommandLine:
 | 
			
		||||
@@ -120,7 +150,7 @@ function killall(processName) {
 | 
			
		||||
        // whatever...
 | 
			
		||||
 | 
			
		||||
        let argv = ['pkill', '-f', '^([^ ]*/)?' + processName + '($| )'];
 | 
			
		||||
        GLib.spawn_sync(null, argv, null, GLib.SpawnFlags.SEARCH_PATH, null, null);
 | 
			
		||||
        GLib.spawn_sync(null, argv, null, GLib.SpawnFlags.SEARCH_PATH, null);
 | 
			
		||||
        // It might be useful to return success/failure, but we'd need
 | 
			
		||||
        // a wrapper around WIFEXITED and WEXITSTATUS. Since none of
 | 
			
		||||
        // the current callers care, we don't bother.
 | 
			
		||||
@@ -208,3 +238,53 @@ function fixupPCIDescription(desc) {
 | 
			
		||||
 | 
			
		||||
    return out.join(' ');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// lowerBound:
 | 
			
		||||
// @array: an array or array-like object, already sorted
 | 
			
		||||
//         according to @cmp
 | 
			
		||||
// @val: the value to add
 | 
			
		||||
// @cmp: a comparator (or undefined to compare as numbers)
 | 
			
		||||
//
 | 
			
		||||
// Returns the position of the first element that is not
 | 
			
		||||
// lower than @val, according to @cmp.
 | 
			
		||||
// That is, returns the first position at which it
 | 
			
		||||
// is possible to insert @val without violating the
 | 
			
		||||
// order.
 | 
			
		||||
// This is quite like an ordinary binary search, except
 | 
			
		||||
// that it doesn't stop at first element comparing equal.
 | 
			
		||||
 | 
			
		||||
function lowerBound(array, val, cmp) {
 | 
			
		||||
    let min, max, mid, v;
 | 
			
		||||
    cmp = cmp || function(a, b) { return a - b; };
 | 
			
		||||
 | 
			
		||||
    if (array.length == 0)
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
    min = 0; max = array.length;
 | 
			
		||||
    while (min < (max - 1)) {
 | 
			
		||||
        mid = Math.floor((min + max) / 2);
 | 
			
		||||
        v = cmp(array[mid], val);
 | 
			
		||||
 | 
			
		||||
        if (v < 0)
 | 
			
		||||
            min = mid + 1;
 | 
			
		||||
        else
 | 
			
		||||
            max = mid;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (min == max || cmp(array[min], val) < 0) ? max : min;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// insertSorted:
 | 
			
		||||
// @array: an array sorted according to @cmp
 | 
			
		||||
// @val: a value to insert
 | 
			
		||||
// @cmp: the sorting function
 | 
			
		||||
//
 | 
			
		||||
// Inserts @val into @array, preserving the
 | 
			
		||||
// sorting invariants.
 | 
			
		||||
// Returns the position at which it was inserted
 | 
			
		||||
function insertSorted(array, val, cmp) {
 | 
			
		||||
    let pos = lowerBound(array, val, cmp);
 | 
			
		||||
    array.splice(pos, 0, val);
 | 
			
		||||
 | 
			
		||||
    return pos;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,6 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const System = imports.system;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Scripting = imports.ui.scripting;
 | 
			
		||||
@@ -99,7 +101,7 @@ function run() {
 | 
			
		||||
        Main.overview.hide();
 | 
			
		||||
        yield Scripting.waitLeisure();
 | 
			
		||||
 | 
			
		||||
        global.gc();
 | 
			
		||||
        System.gc();
 | 
			
		||||
        yield Scripting.sleep(1000);
 | 
			
		||||
        Scripting.collectStatistics();
 | 
			
		||||
        Scripting.scriptEvent('afterShowHide');
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										312
									
								
								js/ui/altTab.js
									
									
									
									
									
								
							
							
						
						@@ -1,13 +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 Gdk = imports.gi.Gdk;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
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 Atk = imports.gi.Atk;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
@@ -31,11 +33,21 @@ function mod(a, b) {
 | 
			
		||||
    return (a + b) % b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function AltTabPopup() {
 | 
			
		||||
    this._init();
 | 
			
		||||
function primaryModifier(mask) {
 | 
			
		||||
    if (mask == 0)
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
    let primary = 1;
 | 
			
		||||
    while (mask > 1) {
 | 
			
		||||
        mask >>= 1;
 | 
			
		||||
        primary <<= 1;
 | 
			
		||||
    }
 | 
			
		||||
    return primary;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AltTabPopup.prototype = {
 | 
			
		||||
const AltTabPopup = new Lang.Class({
 | 
			
		||||
    Name: 'AltTabPopup',
 | 
			
		||||
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        this.actor = new Shell.GenericContainer({ name: 'altTabPopup',
 | 
			
		||||
                                                  reactive: true,
 | 
			
		||||
@@ -48,6 +60,7 @@ AltTabPopup.prototype = {
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 | 
			
		||||
 | 
			
		||||
        this._haveModal = false;
 | 
			
		||||
        this._modifierMask = 0;
 | 
			
		||||
 | 
			
		||||
        this._currentApp = 0;
 | 
			
		||||
        this._currentWindow = -1;
 | 
			
		||||
@@ -114,23 +127,57 @@ AltTabPopup.prototype = {
 | 
			
		||||
            if (childBox.x2 > primary.x + primary.width - rightPadding)
 | 
			
		||||
                childBox.x2 = primary.x + primary.width - rightPadding;
 | 
			
		||||
            childBox.y1 = this._appSwitcher.actor.allocation.y2 + spacing;
 | 
			
		||||
            this._thumbnails.addClones(primary.height - bottomPadding - childBox.y1);
 | 
			
		||||
            this._thumbnails.addClones(primary.y + primary.height - bottomPadding - childBox.y1);
 | 
			
		||||
            let [childMinHeight, childNaturalHeight] = this._thumbnails.actor.get_preferred_height(-1);
 | 
			
		||||
            childBox.y2 = childBox.y1 + childNaturalHeight;
 | 
			
		||||
            this._thumbnails.actor.allocate(childBox, flags);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show : function(backward, binding) {
 | 
			
		||||
    _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_ALL, screen,
 | 
			
		||||
                                           screen.get_active_workspace());
 | 
			
		||||
 | 
			
		||||
        // windows is only the windows on the current workspace. For
 | 
			
		||||
        // each one, if it corresponds to an app we know, move that
 | 
			
		||||
        // app from allApps to apps.
 | 
			
		||||
        let apps = [];
 | 
			
		||||
        for (let i = 0; i < windows.length && allApps.length != 0; i++) {
 | 
			
		||||
            let app = tracker.get_window_app(windows[i]);
 | 
			
		||||
            let index = allApps.indexOf(app);
 | 
			
		||||
            if (index != -1) {
 | 
			
		||||
                apps.push(app);
 | 
			
		||||
                allApps.splice(index, 1);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Now @apps is a list of apps on the current workspace, in
 | 
			
		||||
        // standard Alt+Tab order (MRU except for minimized windows),
 | 
			
		||||
        // and allApps is a list of apps that only appear on other
 | 
			
		||||
        // workspaces, sorted by user_time, which is good enough.
 | 
			
		||||
        return [apps, allApps];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show : function(backward, binding, mask) {
 | 
			
		||||
        let [localApps, otherApps] = this._getAppLists();
 | 
			
		||||
 | 
			
		||||
        if (localApps.length == 0 && otherApps.length == 0)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (!Main.pushModal(this.actor))
 | 
			
		||||
            return false;
 | 
			
		||||
        if (!Main.pushModal(this.actor)) {
 | 
			
		||||
            // Probably someone else has a pointer grab, try again with keyboard only
 | 
			
		||||
            if (!Main.pushModal(this.actor, global.get_current_time(), Meta.ModalOptions.POINTER_ALREADY_GRABBED)) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        this._haveModal = true;
 | 
			
		||||
        this._modifierMask = primaryModifier(mask);
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
 | 
			
		||||
        this.actor.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
 | 
			
		||||
@@ -138,7 +185,7 @@ AltTabPopup.prototype = {
 | 
			
		||||
        this.actor.connect('button-press-event', Lang.bind(this, this._clickedOutside));
 | 
			
		||||
        this.actor.connect('scroll-event', Lang.bind(this, this._onScroll));
 | 
			
		||||
 | 
			
		||||
        this._appSwitcher = new AppSwitcher(apps, this);
 | 
			
		||||
        this._appSwitcher = new AppSwitcher(localApps, otherApps, this);
 | 
			
		||||
        this.actor.add_actor(this._appSwitcher.actor);
 | 
			
		||||
        this._appSwitcher.connect('item-activated', Lang.bind(this, this._appActivated));
 | 
			
		||||
        this._appSwitcher.connect('item-entered', Lang.bind(this, this._appEntered));
 | 
			
		||||
@@ -147,10 +194,12 @@ AltTabPopup.prototype = {
 | 
			
		||||
 | 
			
		||||
        // 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 (binding == 'switch_group') {
 | 
			
		||||
        if (binding == 'switch-group') {
 | 
			
		||||
            if (backward) {
 | 
			
		||||
                this._select(0, this._appIcons[0].cachedWindows.length - 1);
 | 
			
		||||
            } else {
 | 
			
		||||
@@ -159,9 +208,9 @@ AltTabPopup.prototype = {
 | 
			
		||||
                else
 | 
			
		||||
                    this._select(0, 0);
 | 
			
		||||
            }
 | 
			
		||||
        } else if (binding == 'switch_group_backward') {
 | 
			
		||||
        } else if (binding == 'switch-group-backward') {
 | 
			
		||||
            this._select(0, this._appIcons[0].cachedWindows.length - 1);
 | 
			
		||||
        } else if (binding == 'switch_windows_backward') {
 | 
			
		||||
        } else if (binding == 'switch-windows-backward') {
 | 
			
		||||
            this._select(this._appIcons.length - 1);
 | 
			
		||||
        } else if (this._appIcons.length == 1) {
 | 
			
		||||
            this._select(0);
 | 
			
		||||
@@ -177,7 +226,7 @@ AltTabPopup.prototype = {
 | 
			
		||||
        // details.) So we check now. (Have to do this after updating
 | 
			
		||||
        // selection.)
 | 
			
		||||
        let [x, y, mods] = global.get_pointer();
 | 
			
		||||
        if (!(mods & Gdk.ModifierType.MOD1_MASK)) {
 | 
			
		||||
        if (!(mods & this._modifierMask)) {
 | 
			
		||||
            this._finish();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
@@ -186,7 +235,7 @@ AltTabPopup.prototype = {
 | 
			
		||||
        // disturbed by the popup briefly flashing.
 | 
			
		||||
        this._initialDelayTimeoutId = Mainloop.timeout_add(POPUP_DELAY_TIMEOUT,
 | 
			
		||||
                                                           Lang.bind(this, function () {
 | 
			
		||||
                                                               this.actor.show();
 | 
			
		||||
                                                               this.actor.opacity = 255;
 | 
			
		||||
                                                               this._initialDelayTimeoutId = 0;
 | 
			
		||||
                                                           }));
 | 
			
		||||
 | 
			
		||||
@@ -217,7 +266,7 @@ AltTabPopup.prototype = {
 | 
			
		||||
 | 
			
		||||
    _keyPressEvent : function(actor, event) {
 | 
			
		||||
        let keysym = event.get_key_symbol();
 | 
			
		||||
        let event_state = Shell.get_event_state(event);
 | 
			
		||||
        let event_state = event.get_state();
 | 
			
		||||
        let backwards = event_state & Clutter.ModifierType.SHIFT_MASK;
 | 
			
		||||
        let action = global.display.get_keybinding_action(event.get_key_code(), event_state);
 | 
			
		||||
 | 
			
		||||
@@ -254,7 +303,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();
 | 
			
		||||
@@ -470,6 +519,7 @@ AltTabPopup.prototype = {
 | 
			
		||||
                                                        })
 | 
			
		||||
                         });
 | 
			
		||||
        this._thumbnails = null;
 | 
			
		||||
        this._appSwitcher._items[this._currentApp].remove_accessible_state (Atk.StateType.EXPANDED);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createThumbnails : function() {
 | 
			
		||||
@@ -479,6 +529,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,
 | 
			
		||||
@@ -486,14 +540,14 @@ AltTabPopup.prototype = {
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: Lang.bind(this, function () { this.thumbnailsVisible = true; })
 | 
			
		||||
                         });
 | 
			
		||||
 | 
			
		||||
        this._appSwitcher._items[this._currentApp].add_accessible_state (Atk.StateType.EXPANDED);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
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));
 | 
			
		||||
@@ -512,14 +566,14 @@ SwitcherList.prototype = {
 | 
			
		||||
        this._list.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
 | 
			
		||||
        this._list.connect('allocate', Lang.bind(this, this._allocate));
 | 
			
		||||
 | 
			
		||||
        this._clipBin = new St.Bin({style_class: 'cbin'});
 | 
			
		||||
        this._clipBin.child = this._list;
 | 
			
		||||
        this.actor.add_actor(this._clipBin);
 | 
			
		||||
        this._scrollView = new St.ScrollView({ style_class: 'hfade',
 | 
			
		||||
                                               enable_mouse_scrolling: false });
 | 
			
		||||
        this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER);
 | 
			
		||||
 | 
			
		||||
        this._leftGradient = new St.BoxLayout({style_class: 'thumbnail-scroll-gradient-left', vertical: true});
 | 
			
		||||
        this._rightGradient = new St.BoxLayout({style_class: 'thumbnail-scroll-gradient-right', vertical: true});
 | 
			
		||||
        this.actor.add_actor(this._leftGradient);
 | 
			
		||||
        this.actor.add_actor(this._rightGradient);
 | 
			
		||||
        let scrollBox = new St.BoxLayout();
 | 
			
		||||
        scrollBox.add_actor(this._list);
 | 
			
		||||
        this._scrollView.add_actor(scrollBox);
 | 
			
		||||
        this.actor.add_actor(this._scrollView);
 | 
			
		||||
 | 
			
		||||
        // Those arrows indicate whether scrolling in one direction is possible
 | 
			
		||||
        this._leftArrow = new St.DrawingArea({ style_class: 'switcher-arrow',
 | 
			
		||||
@@ -550,21 +604,9 @@ SwitcherList.prototype = {
 | 
			
		||||
        let childBox = new Clutter.ActorBox();
 | 
			
		||||
        let scrollable = this._minSize > box.x2 - box.x1;
 | 
			
		||||
 | 
			
		||||
        this._clipBin.allocate(box, flags);
 | 
			
		||||
 | 
			
		||||
        childBox.x1 = 0;
 | 
			
		||||
        childBox.y1 = 0;
 | 
			
		||||
        childBox.x2 = this._leftGradient.width;
 | 
			
		||||
        childBox.y2 = this.actor.height;
 | 
			
		||||
        this._leftGradient.allocate(childBox, flags);
 | 
			
		||||
        this._leftGradient.opacity = (this._scrollableLeft && scrollable) ? 255 : 0;
 | 
			
		||||
 | 
			
		||||
        childBox.x1 = (this.actor.allocation.x2 - this.actor.allocation.x1) - this._rightGradient.width;
 | 
			
		||||
        childBox.y1 = 0;
 | 
			
		||||
        childBox.x2 = childBox.x1 + this._rightGradient.width;
 | 
			
		||||
        childBox.y2 = this.actor.height;
 | 
			
		||||
        this._rightGradient.allocate(childBox, flags);
 | 
			
		||||
        this._rightGradient.opacity = (this._scrollableRight && scrollable) ? 255 : 0;
 | 
			
		||||
        box.y1 -= this.actor.get_theme_node().get_padding(St.Side.TOP);
 | 
			
		||||
        box.y2 += this.actor.get_theme_node().get_padding(St.Side.BOTTOM);
 | 
			
		||||
        this._scrollView.allocate(box, flags);
 | 
			
		||||
 | 
			
		||||
        let arrowWidth = Math.floor(leftPadding / 3);
 | 
			
		||||
        let arrowHeight = arrowWidth * 2;
 | 
			
		||||
@@ -573,7 +615,7 @@ SwitcherList.prototype = {
 | 
			
		||||
        childBox.x2 = childBox.x1 + arrowWidth;
 | 
			
		||||
        childBox.y2 = childBox.y1 + arrowHeight;
 | 
			
		||||
        this._leftArrow.allocate(childBox, flags);
 | 
			
		||||
        this._leftArrow.opacity = this._leftGradient.opacity;
 | 
			
		||||
        this._leftArrow.opacity = (this._scrollableLeft && scrollable) ? 255 : 0;
 | 
			
		||||
 | 
			
		||||
        arrowWidth = Math.floor(rightPadding / 3);
 | 
			
		||||
        arrowHeight = arrowWidth * 2;
 | 
			
		||||
@@ -582,7 +624,7 @@ SwitcherList.prototype = {
 | 
			
		||||
        childBox.x2 = childBox.x1 + arrowWidth;
 | 
			
		||||
        childBox.y2 = childBox.y1 + arrowHeight;
 | 
			
		||||
        this._rightArrow.allocate(childBox, flags);
 | 
			
		||||
        this._rightArrow.opacity = this._rightGradient.opacity;
 | 
			
		||||
        this._rightArrow.opacity = (this._scrollableRight && scrollable) ? 255 : 0;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addItem : function(item, label) {
 | 
			
		||||
@@ -599,6 +641,8 @@ SwitcherList.prototype = {
 | 
			
		||||
        bbox.label_actor = label;
 | 
			
		||||
 | 
			
		||||
        this._items.push(bbox);
 | 
			
		||||
 | 
			
		||||
        return bbox;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onItemClicked: function (index) {
 | 
			
		||||
@@ -630,48 +674,66 @@ SwitcherList.prototype = {
 | 
			
		||||
                this._items[this._highlighted].add_style_pseudo_class('selected');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let monitor = Main.layoutManager.primaryMonitor;
 | 
			
		||||
        let itemSize = this._items[index].allocation.x2 - this._items[index].allocation.x1;
 | 
			
		||||
        let [posX, posY] = this._items[index].get_transformed_position();
 | 
			
		||||
        posX += this.actor.x;
 | 
			
		||||
        if (posX + itemSize > monitor.width + monitor.x)
 | 
			
		||||
        let adjustment = this._scrollView.hscroll.adjustment;
 | 
			
		||||
        let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
 | 
			
		||||
        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)
 | 
			
		||||
        else if (this._items[index].allocation.x1 - value < 0)
 | 
			
		||||
            this._scrollToLeft();
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _scrollToLeft : function() {
 | 
			
		||||
        let x = this._items[this._highlighted].allocation.x1;
 | 
			
		||||
        let adjustment = this._scrollView.hscroll.adjustment;
 | 
			
		||||
        let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
 | 
			
		||||
 | 
			
		||||
        let item = this._items[this._highlighted];
 | 
			
		||||
 | 
			
		||||
        if (item.allocation.x1 < value)
 | 
			
		||||
            value = Math.min(0, item.allocation.x1);
 | 
			
		||||
        else if (item.allocation.x2 > value + pageSize)
 | 
			
		||||
            value = Math.max(upper, item.allocation.x2 - pageSize);
 | 
			
		||||
 | 
			
		||||
        this._scrollableRight = true;
 | 
			
		||||
        Tweener.addTween(this._list, { anchor_x: x,
 | 
			
		||||
                                        time: POPUP_SCROLL_TIME,
 | 
			
		||||
                                        transition: 'easeOutQuad',
 | 
			
		||||
                                        onComplete: Lang.bind(this, function () {
 | 
			
		||||
                                                                        if (this._highlighted == 0) {
 | 
			
		||||
                                                                            this._scrollableLeft = false;
 | 
			
		||||
                                                                            this.actor.queue_relayout();
 | 
			
		||||
                                                                        }
 | 
			
		||||
                                                             })
 | 
			
		||||
                        });
 | 
			
		||||
        Tweener.addTween(adjustment,
 | 
			
		||||
                         { value: value,
 | 
			
		||||
                           time: POPUP_SCROLL_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: Lang.bind(this, function () {
 | 
			
		||||
                                if (this._highlighted == 0) {
 | 
			
		||||
                                    this._scrollableLeft = false;
 | 
			
		||||
                                    this.actor.queue_relayout();
 | 
			
		||||
                                }
 | 
			
		||||
                           })
 | 
			
		||||
                          });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _scrollToRight : function() {
 | 
			
		||||
        let adjustment = this._scrollView.hscroll.adjustment;
 | 
			
		||||
        let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
 | 
			
		||||
 | 
			
		||||
        let item = this._items[this._highlighted];
 | 
			
		||||
 | 
			
		||||
        if (item.allocation.x1 < value)
 | 
			
		||||
            value = Math.max(0, item.allocation.x1);
 | 
			
		||||
        else if (item.allocation.x2 > value + pageSize)
 | 
			
		||||
            value = Math.min(upper, item.allocation.x2 - pageSize);
 | 
			
		||||
 | 
			
		||||
        this._scrollableLeft = true;
 | 
			
		||||
        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;
 | 
			
		||||
        Tweener.addTween(this._list, { anchor_x: x,
 | 
			
		||||
                                        time: POPUP_SCROLL_TIME,
 | 
			
		||||
                                        transition: 'easeOutQuad',
 | 
			
		||||
                                        onComplete: Lang.bind(this, function () {
 | 
			
		||||
                                                                        if (this._highlighted == this._items.length - 1) {
 | 
			
		||||
                                                                            this._scrollableRight = false;
 | 
			
		||||
                                                                            this.actor.queue_relayout();
 | 
			
		||||
                                                                        }
 | 
			
		||||
                                                             })
 | 
			
		||||
                        });
 | 
			
		||||
        Tweener.addTween(adjustment,
 | 
			
		||||
                         { value: value,
 | 
			
		||||
                           time: POPUP_SCROLL_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: Lang.bind(this, function () {
 | 
			
		||||
                                if (this._highlighted == this._items.length - 1) {
 | 
			
		||||
                                    this._scrollableRight = false;
 | 
			
		||||
                                    this.actor.queue_relayout();
 | 
			
		||||
                                }
 | 
			
		||||
                            })
 | 
			
		||||
                          });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _itemActivated: function(n) {
 | 
			
		||||
@@ -757,14 +819,6 @@ SwitcherList.prototype = {
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
                childWidth = childHeight;
 | 
			
		||||
            else {
 | 
			
		||||
                let [childMin, childNat] = children[0].get_preferred_width(childHeight);
 | 
			
		||||
                childWidth = childMin;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < children.length; i++) {
 | 
			
		||||
            if (this._items.indexOf(children[i]) != -1) {
 | 
			
		||||
@@ -790,24 +844,14 @@ SwitcherList.prototype = {
 | 
			
		||||
                // we don't allocate it.
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
 | 
			
		||||
        let rightPadding = this.actor.get_theme_node().get_padding(St.Side.RIGHT);
 | 
			
		||||
        let topPadding = this.actor.get_theme_node().get_padding(St.Side.TOP);
 | 
			
		||||
        let bottomPadding = this.actor.get_theme_node().get_padding(St.Side.BOTTOM);
 | 
			
		||||
 | 
			
		||||
        // 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',
 | 
			
		||||
@@ -825,35 +869,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 = [];
 | 
			
		||||
@@ -915,7 +955,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;
 | 
			
		||||
@@ -970,7 +1010,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) {
 | 
			
		||||
@@ -983,7 +1023,7 @@ AppSwitcher.prototype = {
 | 
			
		||||
 | 
			
		||||
    _addIcon : function(appIcon) {
 | 
			
		||||
        this.icons.push(appIcon);
 | 
			
		||||
        this.addItem(appIcon.actor, appIcon.label);
 | 
			
		||||
        let item = this.addItem(appIcon.actor, appIcon.label);
 | 
			
		||||
 | 
			
		||||
        let n = this._arrows.length;
 | 
			
		||||
        let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' });
 | 
			
		||||
@@ -993,31 +1033,17 @@ 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);
 | 
			
		||||
        else
 | 
			
		||||
            item.add_accessible_state (Atk.StateType.EXPANDABLE);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
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();
 | 
			
		||||
 | 
			
		||||
@@ -1095,7 +1121,7 @@ ThumbnailList.prototype = {
 | 
			
		||||
        // Make sure we only do this once
 | 
			
		||||
        this._thumbnailBins = new Array();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function _drawArrow(area, side) {
 | 
			
		||||
    let themeNode = area.get_theme_node();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
@@ -10,6 +10,7 @@ const Signals = imports.signals;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Atk = imports.gi.Atk;
 | 
			
		||||
 | 
			
		||||
const AppFavorites = imports.ui.appFavorites;
 | 
			
		||||
const DND = imports.ui.dnd;
 | 
			
		||||
@@ -21,22 +22,22 @@ const Search = imports.ui.search;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const Workspace = imports.ui.workspace;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const Util = imports.misc.util;
 | 
			
		||||
 | 
			
		||||
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._pendingAppLaterId = 0;
 | 
			
		||||
        this._appIcons = {}; // desktop file id
 | 
			
		||||
        this._allApps = [];
 | 
			
		||||
 | 
			
		||||
        let box = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        box.add(this._grid.actor, { y_align: St.Align.START, expand: true });
 | 
			
		||||
@@ -61,16 +62,22 @@ AlphabeticalView.prototype = {
 | 
			
		||||
            }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _removeAll: function() {
 | 
			
		||||
    removeAll: function() {
 | 
			
		||||
        this._grid.removeAll();
 | 
			
		||||
        this._appIcons = {};
 | 
			
		||||
        this._allApps = [];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _addApp: function(app) {
 | 
			
		||||
    addApp: function(app) {
 | 
			
		||||
        var id = app.get_id();
 | 
			
		||||
        let appIcon = new AppWellIcon(app);
 | 
			
		||||
        if (this._appIcons[id] !== undefined)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._grid.addItem(appIcon.actor);
 | 
			
		||||
        let appIcon = new AppWellIcon(app);
 | 
			
		||||
        let pos = Util.insertSorted(this._allApps, app, function(a, b) {
 | 
			
		||||
            return a.compare_by_name(b);
 | 
			
		||||
        });
 | 
			
		||||
        this._grid.addItem(appIcon.actor, pos);
 | 
			
		||||
        appIcon.actor.connect('key-focus-in', Lang.bind(this, this._ensureIconVisible));
 | 
			
		||||
 | 
			
		||||
        this._appIcons[id] = appIcon;
 | 
			
		||||
@@ -121,22 +128,12 @@ AlphabeticalView.prototype = {
 | 
			
		||||
                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' });
 | 
			
		||||
@@ -150,9 +147,10 @@ ViewByCategories.prototype = {
 | 
			
		||||
        // (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._categoryBox = new St.BoxLayout({ vertical: true,
 | 
			
		||||
                                               reactive: true,
 | 
			
		||||
                                               accessible_role: Atk.Role.LIST });
 | 
			
		||||
        this._categoryScroll = new St.ScrollView({ x_fill: false,
 | 
			
		||||
                                                   y_fill: false,
 | 
			
		||||
                                                   style_class: 'vfade' });
 | 
			
		||||
@@ -205,26 +203,30 @@ ViewByCategories.prototype = {
 | 
			
		||||
            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())
 | 
			
		||||
                if (!entry.get_app_info().get_nodisplay()) {
 | 
			
		||||
                    this._view.addApp(app);
 | 
			
		||||
                    appList.push(app);
 | 
			
		||||
                }
 | 
			
		||||
            } else if (nextType == GMenu.TreeItemType.DIRECTORY) {
 | 
			
		||||
                this._loadCategory(iter.get_directory(), appList);
 | 
			
		||||
                var itemDir = iter.get_directory();
 | 
			
		||||
                if (!itemDir.get_is_nodisplay())
 | 
			
		||||
                    this._loadCategory(itemDir, appList);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _addCategory: function(name, index, dir, allApps) {
 | 
			
		||||
    _addCategory: function(name, index, dir) {
 | 
			
		||||
        let button = new St.Button({ label: GLib.markup_escape_text (name, -1),
 | 
			
		||||
                                     style_class: 'app-filter',
 | 
			
		||||
                                     x_align: St.Align.START,
 | 
			
		||||
                                     can_focus: true });
 | 
			
		||||
                                     can_focus: true ,
 | 
			
		||||
                                     accessible_role: Atk.Role.LIST_ITEM });
 | 
			
		||||
        button.connect('clicked', Lang.bind(this, function() {
 | 
			
		||||
            this._selectCategory(index);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        var apps;
 | 
			
		||||
        if (dir == null) {
 | 
			
		||||
            apps = allApps;
 | 
			
		||||
            this._allCategoryButton = button;
 | 
			
		||||
        } else {
 | 
			
		||||
            apps = [];
 | 
			
		||||
@@ -238,20 +240,16 @@ ViewByCategories.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _removeAll: function() {
 | 
			
		||||
        this._view.removeAll();
 | 
			
		||||
        this._categories = [];
 | 
			
		||||
        this._categoryBox.destroy_children();
 | 
			
		||||
        this._categoryBox.destroy_all_children();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    refresh: function() {
 | 
			
		||||
        this._removeAll();
 | 
			
		||||
 | 
			
		||||
        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._addCategory(_("All"), -1, null, allApps);
 | 
			
		||||
        this._addCategory(_("All"), -1, null);
 | 
			
		||||
 | 
			
		||||
        var tree = this._appSystem.get_tree();
 | 
			
		||||
        var root = tree.get_root_directory();
 | 
			
		||||
@@ -262,12 +260,13 @@ ViewByCategories.prototype = {
 | 
			
		||||
        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) {
 | 
			
		||||
@@ -278,16 +277,14 @@ ViewByCategories.prototype = {
 | 
			
		||||
                this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* This class represents a display containing a collection of application items.
 | 
			
		||||
 * The applications are sorted based on their name.
 | 
			
		||||
 */
 | 
			
		||||
function AllAppDisplay() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const AllAppDisplay = new Lang.Class({
 | 
			
		||||
    Name: 'AllAppDisplay',
 | 
			
		||||
 | 
			
		||||
AllAppDisplay.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._appSystem = Shell.AppSystem.get_default();
 | 
			
		||||
        this._appSystem.connect('installed-changed', Lang.bind(this, function() {
 | 
			
		||||
@@ -303,35 +300,37 @@ AllAppDisplay.prototype = {
 | 
			
		||||
    _redisplay: function() {
 | 
			
		||||
        this._appView.refresh();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function AppSearchProvider() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AppSearchProvider.prototype = {
 | 
			
		||||
    __proto__: Search.SearchProvider.prototype,
 | 
			
		||||
const AppSearchProvider = new Lang.Class({
 | 
			
		||||
    Name: 'AppSearchProvider',
 | 
			
		||||
    Extends: Search.SearchProvider,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        Search.SearchProvider.prototype._init.call(this, _("APPLICATIONS"));
 | 
			
		||||
        this.parent(_("APPLICATIONS"));
 | 
			
		||||
        this._appSys = Shell.AppSystem.get_default();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getResultMeta: function(app) {
 | 
			
		||||
        return { 'id': app,
 | 
			
		||||
                 'name': app.get_name(),
 | 
			
		||||
                 'createIcon': function(size) {
 | 
			
		||||
                                   return app.create_icon_texture(size);
 | 
			
		||||
                               }
 | 
			
		||||
               };
 | 
			
		||||
    getResultMetas: function(apps, callback) {
 | 
			
		||||
        let metas = [];
 | 
			
		||||
        for (let i = 0; i < apps.length; i++) {
 | 
			
		||||
            let app = apps[i];
 | 
			
		||||
            metas.push({ 'id': app,
 | 
			
		||||
                         'name': app.get_name(),
 | 
			
		||||
                         'createIcon': function(size) {
 | 
			
		||||
                             return app.create_icon_texture(size);
 | 
			
		||||
                         }
 | 
			
		||||
                       });
 | 
			
		||||
        }
 | 
			
		||||
        callback(metas);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getInitialResultSet: function(terms) {
 | 
			
		||||
        return this._appSys.initial_search(terms);
 | 
			
		||||
        this.searchSystem.pushResults(this, this._appSys.initial_search(terms));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getSubsearchResultSet: function(previousResults, terms) {
 | 
			
		||||
        return this._appSys.subsearch(previousResults, terms);
 | 
			
		||||
        this.searchSystem.pushResults(this, this._appSys.subsearch(previousResults, terms));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activateResult: function(app, params) {
 | 
			
		||||
@@ -339,7 +338,7 @@ AppSearchProvider.prototype = {
 | 
			
		||||
                                        timestamp: 0 });
 | 
			
		||||
 | 
			
		||||
        let event = Clutter.get_current_event();
 | 
			
		||||
        let modifiers = event ? Shell.get_event_state(event) : 0;
 | 
			
		||||
        let modifiers = event ? event.get_state() : 0;
 | 
			
		||||
        let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK;
 | 
			
		||||
 | 
			
		||||
        if (openNewWindow)
 | 
			
		||||
@@ -361,36 +360,39 @@ AppSearchProvider.prototype = {
 | 
			
		||||
        let icon = new AppWellIcon(app);
 | 
			
		||||
        return icon.actor;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function SettingsSearchProvider() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SettingsSearchProvider.prototype = {
 | 
			
		||||
    __proto__: Search.SearchProvider.prototype,
 | 
			
		||||
const SettingsSearchProvider = new Lang.Class({
 | 
			
		||||
    Name: 'SettingsSearchProvider',
 | 
			
		||||
    Extends: Search.SearchProvider,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        Search.SearchProvider.prototype._init.call(this, _("SETTINGS"));
 | 
			
		||||
        this.parent(_("SETTINGS"));
 | 
			
		||||
 | 
			
		||||
        this._appSys = Shell.AppSystem.get_default();
 | 
			
		||||
        this._gnomecc = this._appSys.lookup_app('gnome-control-center.desktop');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getResultMeta: function(pref) {
 | 
			
		||||
        return { 'id': pref,
 | 
			
		||||
                 'name': pref.get_name(),
 | 
			
		||||
                 'createIcon': function(size) {
 | 
			
		||||
                                   return pref.create_icon_texture(size);
 | 
			
		||||
                               }
 | 
			
		||||
               };
 | 
			
		||||
    getResultMetas: function(prefs, callback) {
 | 
			
		||||
        let metas = [];
 | 
			
		||||
        for (let i = 0; i < prefs.length; i++) {
 | 
			
		||||
            let pref = prefs[i];
 | 
			
		||||
            metas.push({ 'id': pref,
 | 
			
		||||
                         'name': pref.get_name(),
 | 
			
		||||
                         'createIcon': function(size) {
 | 
			
		||||
                             return pref.create_icon_texture(size);
 | 
			
		||||
                         }
 | 
			
		||||
                       });
 | 
			
		||||
        }
 | 
			
		||||
        callback(metas);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getInitialResultSet: function(terms) {
 | 
			
		||||
        return this._appSys.search_settings(terms);
 | 
			
		||||
        this.searchSystem.pushResults(this, this._appSys.search_settings(terms));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getSubsearchResultSet: function(previousResults, terms) {
 | 
			
		||||
        return this._appSys.search_settings(terms);
 | 
			
		||||
        this.searchSystem.pushResults(this, this._appSys.search_settings(terms));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activateResult: function(pref, params) {
 | 
			
		||||
@@ -409,35 +411,28 @@ SettingsSearchProvider.prototype = {
 | 
			
		||||
        let icon = new AppWellIcon(app);
 | 
			
		||||
        return icon.actor;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function AppIcon(app, params) {
 | 
			
		||||
    this._init(app, params);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AppIcon.prototype = {
 | 
			
		||||
    __proto__:  IconGrid.BaseIcon.prototype,
 | 
			
		||||
const AppIcon = new Lang.Class({
 | 
			
		||||
    Name: 'AppIcon',
 | 
			
		||||
    Extends: IconGrid.BaseIcon,
 | 
			
		||||
 | 
			
		||||
    _init : function(app, params) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
 | 
			
		||||
        let label = this.app.get_name();
 | 
			
		||||
 | 
			
		||||
        IconGrid.BaseIcon.prototype._init.call(this,
 | 
			
		||||
                                               label,
 | 
			
		||||
                                               params);
 | 
			
		||||
        this.parent(label, params);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createIcon: function(iconSize) {
 | 
			
		||||
        return this.app.create_icon_texture(iconSize);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function AppWellIcon(app, iconParams, onActivateOverride) {
 | 
			
		||||
    this._init(app, iconParams, onActivateOverride);
 | 
			
		||||
}
 | 
			
		||||
const AppWellIcon = new Lang.Class({
 | 
			
		||||
    Name: 'AppWellIcon',
 | 
			
		||||
 | 
			
		||||
AppWellIcon.prototype = {
 | 
			
		||||
    _init : function(app, iconParams, onActivateOverride) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        this.actor = new St.Button({ style_class: 'app-well-app',
 | 
			
		||||
@@ -484,6 +479,7 @@ AppWellIcon.prototype = {
 | 
			
		||||
                                                Lang.bind(this,
 | 
			
		||||
                                                          this._onStateChanged));
 | 
			
		||||
        this._onStateChanged();
 | 
			
		||||
        this.isMenuUp = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDestroy: function() {
 | 
			
		||||
@@ -556,7 +552,7 @@ AppWellIcon.prototype = {
 | 
			
		||||
            this._menu.connect('activate-window', Lang.bind(this, function (menu, window) {
 | 
			
		||||
                this.activateWindow(window);
 | 
			
		||||
            }));
 | 
			
		||||
            this._menu.connect('popup', Lang.bind(this, function (menu, isPoppedUp) {
 | 
			
		||||
            this._menu.connect('open-state-changed', Lang.bind(this, function (menu, isPoppedUp) {
 | 
			
		||||
                if (!isPoppedUp)
 | 
			
		||||
                    this._onMenuPoppedDown();
 | 
			
		||||
            }));
 | 
			
		||||
@@ -565,8 +561,8 @@ AppWellIcon.prototype = {
 | 
			
		||||
            this._menuManager.addMenu(this._menu);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.isMenuUp = true;
 | 
			
		||||
        this.actor.set_hover(true);
 | 
			
		||||
        this.actor.show_tooltip();
 | 
			
		||||
        this._menu.popup();
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
@@ -582,11 +578,12 @@ AppWellIcon.prototype = {
 | 
			
		||||
 | 
			
		||||
    _onMenuPoppedDown: function() {
 | 
			
		||||
        this.actor.sync_hover();
 | 
			
		||||
        this.isMenuUp = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onActivate: function (event) {
 | 
			
		||||
        this.emit('launching');
 | 
			
		||||
        let modifiers = Shell.get_event_state(event);
 | 
			
		||||
        let modifiers = event.get_state();
 | 
			
		||||
 | 
			
		||||
        if (this._onActivateOverride) {
 | 
			
		||||
            this._onActivateOverride(event);
 | 
			
		||||
@@ -617,22 +614,19 @@ AppWellIcon.prototype = {
 | 
			
		||||
    getDragActorSource: function() {
 | 
			
		||||
        return this.icon.icon;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(AppWellIcon.prototype);
 | 
			
		||||
 | 
			
		||||
function AppIconMenu(source) {
 | 
			
		||||
    this._init(source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AppIconMenu.prototype = {
 | 
			
		||||
    __proto__: PopupMenu.PopupMenu.prototype,
 | 
			
		||||
const AppIconMenu = new Lang.Class({
 | 
			
		||||
    Name: 'AppIconMenu',
 | 
			
		||||
    Extends: PopupMenu.PopupMenu,
 | 
			
		||||
 | 
			
		||||
    _init: function(source) {
 | 
			
		||||
        let side = St.Side.LEFT;
 | 
			
		||||
        if (St.Widget.get_default_direction() == St.TextDirection.RTL)
 | 
			
		||||
        if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
 | 
			
		||||
            side = St.Side.RIGHT;
 | 
			
		||||
 | 
			
		||||
        PopupMenu.PopupMenu.prototype._init.call(this, source.actor, 0.5, side);
 | 
			
		||||
        this.parent(source.actor, 0.5, side);
 | 
			
		||||
 | 
			
		||||
        // We want to keep the item hovered while the menu is up
 | 
			
		||||
        this.blockSourceEvents = true;
 | 
			
		||||
@@ -640,7 +634,6 @@ AppIconMenu.prototype = {
 | 
			
		||||
        this._source = source;
 | 
			
		||||
 | 
			
		||||
        this.connect('activate', Lang.bind(this, this._onActivate));
 | 
			
		||||
        this.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
 | 
			
		||||
 | 
			
		||||
        this.actor.add_style_class_name('app-well-menu');
 | 
			
		||||
 | 
			
		||||
@@ -704,14 +697,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;
 | 
			
		||||
@@ -729,5 +714,5 @@ AppIconMenu.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
        this.close();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(AppIconMenu.prototype);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
@@ -6,11 +6,9 @@ const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
 | 
			
		||||
function AppFavorites() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const AppFavorites = new Lang.Class({
 | 
			
		||||
    Name: 'AppFavorites',
 | 
			
		||||
 | 
			
		||||
AppFavorites.prototype = {
 | 
			
		||||
    FAVORITE_APPS_KEY: 'favorite-apps',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
@@ -122,7 +120,7 @@ AppFavorites.prototype = {
 | 
			
		||||
            this._addFavorite(appId, pos);
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(AppFavorites.prototype);
 | 
			
		||||
 | 
			
		||||
var appFavoritesInstance = null;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,17 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const DBus = imports.dbus;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const ShellMountOperation = imports.ui.shellMountOperation;
 | 
			
		||||
const ScreenSaver = imports.misc.screenSaver;
 | 
			
		||||
const GnomeSession = imports.misc.gnomeSession;
 | 
			
		||||
 | 
			
		||||
const GNOME_SESSION_AUTOMOUNT_INHIBIT = 16;
 | 
			
		||||
 | 
			
		||||
// GSettings keys
 | 
			
		||||
const SETTINGS_SCHEMA = 'org.gnome.desktop.media-handling';
 | 
			
		||||
@@ -16,79 +19,79 @@ const SETTING_ENABLE_AUTOMOUNT = 'automount';
 | 
			
		||||
 | 
			
		||||
const AUTORUN_EXPIRE_TIMEOUT_SECS = 10;
 | 
			
		||||
 | 
			
		||||
const ConsoleKitSessionIface = {
 | 
			
		||||
    name: 'org.freedesktop.ConsoleKit.Session',
 | 
			
		||||
    methods: [{ name: 'IsActive',
 | 
			
		||||
                inSignature: '',
 | 
			
		||||
                outSignature: 'b' }],
 | 
			
		||||
    signals: [{ name: 'ActiveChanged',
 | 
			
		||||
                inSignature: 'b' }]
 | 
			
		||||
};
 | 
			
		||||
const ConsoleKitSessionIface = <interface name="org.freedesktop.ConsoleKit.Session">
 | 
			
		||||
<method name="IsActive">
 | 
			
		||||
    <arg type="b" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<signal name="ActiveChanged">
 | 
			
		||||
    <arg type="b" direction="out" />
 | 
			
		||||
</signal>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const ConsoleKitSessionProxy = DBus.makeProxyClass(ConsoleKitSessionIface);
 | 
			
		||||
const ConsoleKitSessionProxy = Gio.DBusProxy.makeProxyWrapper(ConsoleKitSessionIface);
 | 
			
		||||
 | 
			
		||||
const ConsoleKitManagerIface = {
 | 
			
		||||
    name: 'org.freedesktop.ConsoleKit.Manager',
 | 
			
		||||
    methods: [{ name: 'GetCurrentSession',
 | 
			
		||||
                inSignature: '',
 | 
			
		||||
                outSignature: 'o' }]
 | 
			
		||||
};
 | 
			
		||||
const ConsoleKitManagerIface = <interface name="org.freedesktop.ConsoleKit.Manager">
 | 
			
		||||
<method name="GetCurrentSession">
 | 
			
		||||
    <arg type="o" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const ConsoleKitManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(ConsoleKitManagerIface);
 | 
			
		||||
 | 
			
		||||
function ConsoleKitManager() {
 | 
			
		||||
    this._init();
 | 
			
		||||
};
 | 
			
		||||
    var self = new Gio.DBusProxy({ g_connection: Gio.DBus.system,
 | 
			
		||||
				   g_interface_name: ConsoleKitManagerInfo.name,
 | 
			
		||||
				   g_interface_info: ConsoleKitManagerInfo,
 | 
			
		||||
				   g_name: 'org.freedesktop.ConsoleKit',
 | 
			
		||||
				   g_object_path: '/org/freedesktop/ConsoleKit/Manager',
 | 
			
		||||
                                   g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
 | 
			
		||||
                                             Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
 | 
			
		||||
 | 
			
		||||
ConsoleKitManager.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.sessionActive = true;
 | 
			
		||||
    self._updateSessionActive = function() {
 | 
			
		||||
        if (self.g_name_owner) {
 | 
			
		||||
            self.GetCurrentSessionRemote(function([session]) {
 | 
			
		||||
                self._ckSession = new ConsoleKitSessionProxy(Gio.DBus.system, 'org.freedesktop.ConsoleKit', session);
 | 
			
		||||
 | 
			
		||||
        DBus.system.proxifyObject(this,
 | 
			
		||||
                                  'org.freedesktop.ConsoleKit',
 | 
			
		||||
                                  '/org/freedesktop/ConsoleKit/Manager');
 | 
			
		||||
                self._ckSession.connectSignal('ActiveChanged', function(object, senderName, [isActive]) {
 | 
			
		||||
                    self.sessionActive = isActive;
 | 
			
		||||
                });
 | 
			
		||||
                self._ckSession.IsActiveRemote(function([isActive]) {
 | 
			
		||||
                    self.sessionActive = isActive;
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            self.sessionActive = true;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    self.connect('notify::g-name-owner',
 | 
			
		||||
                 Lang.bind(self, self._updateSessionActive));
 | 
			
		||||
 | 
			
		||||
        DBus.system.watch_name('org.freedesktop.ConsoleKit',
 | 
			
		||||
                               false, // do not launch a name-owner if none exists
 | 
			
		||||
                               Lang.bind(this, this._onManagerAppeared),
 | 
			
		||||
                               Lang.bind(this, this._onManagerVanished));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onManagerAppeared: function(owner) {
 | 
			
		||||
        this.GetCurrentSessionRemote(Lang.bind(this, this._onCurrentSession));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onManagerVanished: function(oldOwner) {
 | 
			
		||||
        this.sessionActive = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onCurrentSession: function(session) {
 | 
			
		||||
        this._ckSession = new ConsoleKitSessionProxy(DBus.system, 'org.freedesktop.ConsoleKit', session);
 | 
			
		||||
 | 
			
		||||
        this._ckSession.connect
 | 
			
		||||
            ('ActiveChanged', Lang.bind(this, function(object, isActive) {
 | 
			
		||||
                this.sessionActive = isActive;            
 | 
			
		||||
            }));
 | 
			
		||||
        this._ckSession.IsActiveRemote(Lang.bind(this, function(isActive) {
 | 
			
		||||
            this.sessionActive = isActive;            
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
DBus.proxifyPrototype(ConsoleKitManager.prototype, ConsoleKitManagerIface);
 | 
			
		||||
 | 
			
		||||
function AutomountManager() {
 | 
			
		||||
    this._init();
 | 
			
		||||
    self._updateSessionActive();
 | 
			
		||||
    self.init(null);
 | 
			
		||||
    return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AutomountManager.prototype = {
 | 
			
		||||
function haveSystemd() {
 | 
			
		||||
    return GLib.access("/sys/fs/cgroup/systemd", 0) >= 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const AutomountManager = new Lang.Class({
 | 
			
		||||
    Name: 'AutomountManager',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
 | 
			
		||||
        this._volumeQueue = [];
 | 
			
		||||
        this._session = new GnomeSession.SessionManager();
 | 
			
		||||
        this._session.connectSignal('InhibitorAdded',
 | 
			
		||||
                                    Lang.bind(this, this._InhibitorsChanged));
 | 
			
		||||
        this._session.connectSignal('InhibitorRemoved',
 | 
			
		||||
                                    Lang.bind(this, this._InhibitorsChanged));
 | 
			
		||||
        this._inhibited = false;
 | 
			
		||||
 | 
			
		||||
        this.ckListener = new ConsoleKitManager();
 | 
			
		||||
        if (!haveSystemd())
 | 
			
		||||
            this.ckListener = new ConsoleKitManager();
 | 
			
		||||
 | 
			
		||||
        this._ssProxy = new ScreenSaver.ScreenSaverProxy();
 | 
			
		||||
        this._ssProxy.connect('ActiveChanged',
 | 
			
		||||
                              Lang.bind(this,
 | 
			
		||||
                                        this._screenSaverActiveChanged));
 | 
			
		||||
        Main.screenShield.connect('lock-status-changed', Lang.bind(this, this._lockStatusChanged));
 | 
			
		||||
 | 
			
		||||
        this._volumeMonitor = Gio.VolumeMonitor.get();
 | 
			
		||||
 | 
			
		||||
@@ -111,8 +114,18 @@ AutomountManager.prototype = {
 | 
			
		||||
        Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _screenSaverActiveChanged: function(object, isActive) {
 | 
			
		||||
        if (!isActive) {
 | 
			
		||||
    _InhibitorsChanged: function(object, senderName, [inhibtor]) {
 | 
			
		||||
        this._session.IsInhibitedRemote(GNOME_SESSION_AUTOMOUNT_INHIBIT,
 | 
			
		||||
            Lang.bind(this,
 | 
			
		||||
                function(result, error) {
 | 
			
		||||
                    if (!error) {
 | 
			
		||||
                        this._inhibited = result[0];
 | 
			
		||||
                    }
 | 
			
		||||
                }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _lockStatusChanged: function(shield, locked) {
 | 
			
		||||
        if (!locked) {
 | 
			
		||||
            this._volumeQueue.forEach(Lang.bind(this, function(volume) {
 | 
			
		||||
                this._checkAndMountVolume(volume);
 | 
			
		||||
            }));
 | 
			
		||||
@@ -126,19 +139,31 @@ AutomountManager.prototype = {
 | 
			
		||||
        let volumes = this._volumeMonitor.get_volumes();
 | 
			
		||||
        volumes.forEach(Lang.bind(this, function(volume) {
 | 
			
		||||
            this._checkAndMountVolume(volume, { checkSession: false,
 | 
			
		||||
                                                useMountOp: false });
 | 
			
		||||
                                                useMountOp: false,
 | 
			
		||||
                                                allowAutorun: false });
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    isSessionActive: function() {
 | 
			
		||||
        // Return whether the current session is active, using the
 | 
			
		||||
        // right mechanism: either systemd if available or ConsoleKit
 | 
			
		||||
        // as fallback.
 | 
			
		||||
 | 
			
		||||
        if (haveSystemd())
 | 
			
		||||
            return Shell.session_is_active_for_systemd();
 | 
			
		||||
 | 
			
		||||
        return this.ckListener.sessionActive;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDriveConnected: function() {
 | 
			
		||||
        // if we're not in the current ConsoleKit session,
 | 
			
		||||
        // or screensaver is active, don't play sounds
 | 
			
		||||
        if (!this.ckListener.sessionActive)
 | 
			
		||||
            return;        
 | 
			
		||||
        if (!this.isSessionActive())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (this._ssProxy.screenSaverActive)
 | 
			
		||||
        if (Main.screenShield.locked)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        global.play_theme_sound(0, 'device-added-media');
 | 
			
		||||
@@ -147,10 +172,10 @@ AutomountManager.prototype = {
 | 
			
		||||
    _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.isSessionActive())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (this._ssProxy.screenSaverActive)
 | 
			
		||||
        if (Main.screenShield.locked)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        global.play_theme_sound(0, 'device-removed-media');        
 | 
			
		||||
@@ -159,7 +184,7 @@ AutomountManager.prototype = {
 | 
			
		||||
    _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)
 | 
			
		||||
        if (!this.isSessionActive())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // we force stop/eject in this case, so we don't have to pass a
 | 
			
		||||
@@ -193,15 +218,16 @@ AutomountManager.prototype = {
 | 
			
		||||
 | 
			
		||||
    _checkAndMountVolume: function(volume, params) {
 | 
			
		||||
        params = Params.parse(params, { checkSession: true,
 | 
			
		||||
                                        useMountOp: true });
 | 
			
		||||
                                        useMountOp: true,
 | 
			
		||||
                                        allowAutorun: true });
 | 
			
		||||
 | 
			
		||||
        if (params.checkSession) {
 | 
			
		||||
            // if we're not in the current ConsoleKit session,
 | 
			
		||||
            // don't attempt automount
 | 
			
		||||
            if (!this.ckListener.sessionActive)
 | 
			
		||||
            if (!this.isSessionActive())
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            if (this._ssProxy.screenSaverActive) {
 | 
			
		||||
            if (Main.screenShield.locked) {
 | 
			
		||||
                if (this._volumeQueue.indexOf(volume) == -1)
 | 
			
		||||
                    this._volumeQueue.push(volume);
 | 
			
		||||
 | 
			
		||||
@@ -209,10 +235,17 @@ AutomountManager.prototype = {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._inhibited)
 | 
			
		||||
            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
 | 
			
		||||
            // 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.
 | 
			
		||||
@@ -224,15 +257,20 @@ AutomountManager.prototype = {
 | 
			
		||||
 | 
			
		||||
        if (params.useMountOp) {
 | 
			
		||||
            let operation = new ShellMountOperation.ShellMountOperation(volume);
 | 
			
		||||
            this._mountVolume(volume, operation.mountOp);
 | 
			
		||||
            this._mountVolume(volume, operation, params.allowAutorun);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._mountVolume(volume, null);
 | 
			
		||||
            this._mountVolume(volume, null, params.allowAutorun);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _mountVolume: function(volume, operation) {
 | 
			
		||||
        this._allowAutorun(volume);
 | 
			
		||||
        volume.mount(0, operation, null,
 | 
			
		||||
    _mountVolume: function(volume, operation, allowAutorun) {
 | 
			
		||||
        if (allowAutorun)
 | 
			
		||||
            this._allowAutorun(volume);
 | 
			
		||||
 | 
			
		||||
        let mountOp = operation ? operation.mountOp : null;
 | 
			
		||||
        volume._operation = operation;
 | 
			
		||||
 | 
			
		||||
        volume.mount(0, mountOp, null,
 | 
			
		||||
                     Lang.bind(this, this._onVolumeMounted));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -241,15 +279,19 @@ AutomountManager.prototype = {
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            volume.mount_finish(res);
 | 
			
		||||
            this._closeOperation(volume);
 | 
			
		||||
        } 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)
 | 
			
		||||
            // FIXME: we will always get G_IO_ERROR_FAILED from the gvfs udisks
 | 
			
		||||
            // backend in this case, see 
 | 
			
		||||
            // https://bugs.freedesktop.org/show_bug.cgi?id=51271
 | 
			
		||||
            if (e.message.indexOf('No key available with this passphrase') != -1) {
 | 
			
		||||
                this._reaskPassword(volume);
 | 
			
		||||
            else
 | 
			
		||||
                log('Unable to mount volume ' + volume.get_name() + ': ' + string);
 | 
			
		||||
            } else {
 | 
			
		||||
                if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED))
 | 
			
		||||
                    log('Unable to mount volume ' + volume.get_name() + ': ' + e.toString());
 | 
			
		||||
 | 
			
		||||
                this._closeOperation(volume);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -261,8 +303,16 @@ AutomountManager.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _reaskPassword: function(volume) {
 | 
			
		||||
        let operation = new ShellMountOperation.ShellMountOperation(volume, { reaskPassword: true });
 | 
			
		||||
        this._mountVolume(volume, operation.mountOp);        
 | 
			
		||||
        let existingDialog = volume._operation ? volume._operation.borrowDialog() : null;
 | 
			
		||||
        let operation = 
 | 
			
		||||
            new ShellMountOperation.ShellMountOperation(volume,
 | 
			
		||||
                                                        { existingDialog: existingDialog });
 | 
			
		||||
        this._mountVolume(volume, operation);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _closeOperation: function(volume) {
 | 
			
		||||
        if (volume._operation)
 | 
			
		||||
            volume._operation.close();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _allowAutorun: function(volume) {
 | 
			
		||||
@@ -275,4 +325,4 @@ AutomountManager.prototype = {
 | 
			
		||||
            return false;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const DBus = imports.dbus;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
@@ -23,15 +22,15 @@ const AutorunSetting = {
 | 
			
		||||
    ASK: 3
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const HOTPLUG_ICON_SIZE = 16;
 | 
			
		||||
 | 
			
		||||
// misc utils
 | 
			
		||||
function ignoreAutorunForMount(mount) {
 | 
			
		||||
function shouldAutorunMount(mount, forTransient) {
 | 
			
		||||
    let root = mount.get_root();
 | 
			
		||||
    let volume = mount.get_volume();
 | 
			
		||||
 | 
			
		||||
    if ((root.is_native() && !isMountRootHidden(root)) ||
 | 
			
		||||
        (volume && volume.allowAutorun && volume.should_automount()))
 | 
			
		||||
    if (!volume || (!volume.allowAutorun && forTransient))
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    if (!root.is_native() || isMountRootHidden(root))
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
@@ -64,31 +63,23 @@ function startAppForMount(app, mount) {
 | 
			
		||||
 | 
			
		||||
/******************************************/
 | 
			
		||||
 | 
			
		||||
const HotplugSnifferIface = {
 | 
			
		||||
    name: 'org.gnome.Shell.HotplugSniffer',
 | 
			
		||||
    methods: [{ name: 'SniffURI',
 | 
			
		||||
                inSignature: 's',
 | 
			
		||||
                outSignature: 'as' }]
 | 
			
		||||
};
 | 
			
		||||
const HotplugSnifferIface = <interface name="org.gnome.Shell.HotplugSniffer">
 | 
			
		||||
<method name="SniffURI">
 | 
			
		||||
    <arg type="s" direction="in" />
 | 
			
		||||
    <arg type="as" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const HotplugSniffer = function() {
 | 
			
		||||
    this._init();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
HotplugSniffer.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        DBus.session.proxifyObject(this,
 | 
			
		||||
const HotplugSnifferProxy = Gio.DBusProxy.makeProxyWrapper(HotplugSnifferIface);
 | 
			
		||||
function HotplugSniffer() {
 | 
			
		||||
    return new HotplugSnifferProxy(Gio.DBus.session,
 | 
			
		||||
                                   'org.gnome.Shell.HotplugSniffer',
 | 
			
		||||
                                   '/org/gnome/Shell/HotplugSniffer');
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
DBus.proxifyPrototype(HotplugSniffer.prototype, HotplugSnifferIface);
 | 
			
		||||
 | 
			
		||||
function ContentTypeDiscoverer(callback) {
 | 
			
		||||
    this._init(callback);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ContentTypeDiscoverer.prototype = {
 | 
			
		||||
const ContentTypeDiscoverer = new Lang.Class({
 | 
			
		||||
    Name: 'ContentTypeDiscoverer',
 | 
			
		||||
 | 
			
		||||
    _init: function(callback) {
 | 
			
		||||
        this._callback = callback;
 | 
			
		||||
    },
 | 
			
		||||
@@ -116,9 +107,8 @@ ContentTypeDiscoverer.prototype = {
 | 
			
		||||
            let root = mount.get_root();
 | 
			
		||||
 | 
			
		||||
            let hotplugSniffer = new HotplugSniffer();
 | 
			
		||||
            hotplugSniffer.SniffURIRemote
 | 
			
		||||
                (root.get_uri(), DBus.CALL_FLAG_START,
 | 
			
		||||
                 Lang.bind(this, function(contentTypes) {
 | 
			
		||||
            hotplugSniffer.SniffURIRemote(root.get_uri(),
 | 
			
		||||
                 Lang.bind(this, function([contentTypes]) {
 | 
			
		||||
                     this._emitCallback(mount, contentTypes);
 | 
			
		||||
                 }));
 | 
			
		||||
        }
 | 
			
		||||
@@ -146,13 +136,11 @@ ContentTypeDiscoverer.prototype = {
 | 
			
		||||
 | 
			
		||||
        this._callback(mount, apps, contentTypes);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function AutorunManager() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const AutorunManager = new Lang.Class({
 | 
			
		||||
    Name: 'AutorunManager',
 | 
			
		||||
 | 
			
		||||
AutorunManager.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._volumeMonitor = Gio.VolumeMonitor.get();
 | 
			
		||||
 | 
			
		||||
@@ -188,7 +176,7 @@ AutorunManager.prototype = {
 | 
			
		||||
    _onMountAdded: function(monitor, mount) {
 | 
			
		||||
        // don't do anything if our session is not the currently
 | 
			
		||||
        // active one
 | 
			
		||||
        if (!Main.automountManager.ckListener.sessionActive)
 | 
			
		||||
        if (!Main.automountManager.isSessionActive())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let discoverer = new ContentTypeDiscoverer(Lang.bind (this,
 | 
			
		||||
@@ -238,11 +226,9 @@ AutorunManager.prototype = {
 | 
			
		||||
        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());
 | 
			
		||||
            if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED))
 | 
			
		||||
                log('Unable to eject the mount ' + mount.get_name() 
 | 
			
		||||
                    + ': ' + e.toString());
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -250,11 +236,9 @@ AutorunManager.prototype = {
 | 
			
		||||
        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());
 | 
			
		||||
            if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED))
 | 
			
		||||
                log('Unable to eject the drive ' + source.get_name()
 | 
			
		||||
                    + ': ' + e.toString());
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -262,33 +246,27 @@ AutorunManager.prototype = {
 | 
			
		||||
        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());
 | 
			
		||||
            if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED))
 | 
			
		||||
                log('Unable to stop the drive ' + drive.get_name() 
 | 
			
		||||
                    + ': ' + e.toString());
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function AutorunResidentSource() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AutorunResidentSource.prototype = {
 | 
			
		||||
    __proto__: MessageTray.Source.prototype,
 | 
			
		||||
const AutorunResidentSource = new Lang.Class({
 | 
			
		||||
    Name: 'AutorunResidentSource',
 | 
			
		||||
    Extends: MessageTray.Source,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        MessageTray.Source.prototype._init.call(this, _('Removable Devices'));
 | 
			
		||||
        this.parent(_("Removable Devices"), 'media-removable', St.IconType.FULLCOLOR);
 | 
			
		||||
 | 
			
		||||
        this._mounts = [];
 | 
			
		||||
 | 
			
		||||
        this._notification = new AutorunResidentNotification(this);
 | 
			
		||||
        this._setSummaryIcon(this.createNotificationIcon(HOTPLUG_ICON_SIZE));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addMount: function(mount, apps) {
 | 
			
		||||
        if (ignoreAutorunForMount(mount))
 | 
			
		||||
        if (!shouldAutorunMount(mount, false))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let filtered = this._mounts.filter(function (element) {
 | 
			
		||||
@@ -327,25 +305,15 @@ AutorunResidentSource.prototype = {
 | 
			
		||||
            Main.messageTray.add(this);
 | 
			
		||||
            this.pushNotification(this._notification);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createNotificationIcon: function(iconSize) {
 | 
			
		||||
        return new St.Icon ({ icon_name: 'drive-harddisk',
 | 
			
		||||
                              icon_size: iconSize ? iconSize : this.ICON_SIZE });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function AutorunResidentNotification(source) {
 | 
			
		||||
    this._init(source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AutorunResidentNotification.prototype = {
 | 
			
		||||
    __proto__: MessageTray.Notification.prototype,
 | 
			
		||||
const AutorunResidentNotification = new Lang.Class({
 | 
			
		||||
    Name: 'AutorunResidentNotification',
 | 
			
		||||
    Extends: MessageTray.Notification,
 | 
			
		||||
 | 
			
		||||
    _init: function(source) {
 | 
			
		||||
        MessageTray.Notification.prototype._init.call(this, source,
 | 
			
		||||
                                                      source.title, null,
 | 
			
		||||
                                                      { customContent: true });
 | 
			
		||||
        this.parent(source, source.title, null, { customContent: true });
 | 
			
		||||
 | 
			
		||||
        // set the notification as resident
 | 
			
		||||
        this.setResident(true);
 | 
			
		||||
@@ -360,7 +328,7 @@ AutorunResidentNotification.prototype = {
 | 
			
		||||
 | 
			
		||||
    updateForMounts: function(mounts) {
 | 
			
		||||
        // remove all the layout content
 | 
			
		||||
        this._layout.destroy_children();
 | 
			
		||||
        this._layout.destroy_all_children();
 | 
			
		||||
 | 
			
		||||
        for (let idx = 0; idx < mounts.length; idx++) {
 | 
			
		||||
            let element = mounts[idx];
 | 
			
		||||
@@ -419,13 +387,11 @@ AutorunResidentNotification.prototype = {
 | 
			
		||||
 | 
			
		||||
        return item;
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function AutorunTransientDispatcher() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const AutorunTransientDispatcher = new Lang.Class({
 | 
			
		||||
    Name: 'AutorunTransientDispatcher',
 | 
			
		||||
 | 
			
		||||
AutorunTransientDispatcher.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._sources = [];
 | 
			
		||||
        this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
 | 
			
		||||
@@ -478,7 +444,7 @@ AutorunTransientDispatcher.prototype = {
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // if the mount doesn't want to be autorun, return
 | 
			
		||||
        if (ignoreAutorunForMount(mount))
 | 
			
		||||
        if (!shouldAutorunMount(mount, true))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let setting = this._getAutorunSettingForType(contentTypes[0]);
 | 
			
		||||
@@ -492,7 +458,7 @@ AutorunTransientDispatcher.prototype = {
 | 
			
		||||
        let app = null;
 | 
			
		||||
 | 
			
		||||
        if (setting == AutorunSetting.RUN) {
 | 
			
		||||
            app = Gio.app_info_get_default_for_type(type, false);
 | 
			
		||||
            app = Gio.app_info_get_default_for_type(contentTypes[0], false);
 | 
			
		||||
        } else if (setting == AutorunSetting.FILES) {
 | 
			
		||||
            app = Gio.app_info_get_default_for_type('inode/directory', false);
 | 
			
		||||
        }
 | 
			
		||||
@@ -516,46 +482,37 @@ AutorunTransientDispatcher.prototype = {
 | 
			
		||||
        // destroy the notification source
 | 
			
		||||
        source.destroy();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function AutorunTransientSource(mount, apps) {
 | 
			
		||||
    this._init(mount, apps);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AutorunTransientSource.prototype = {
 | 
			
		||||
    __proto__: MessageTray.Source.prototype,
 | 
			
		||||
const AutorunTransientSource = new Lang.Class({
 | 
			
		||||
    Name: 'AutorunTransientSource',
 | 
			
		||||
    Extends: MessageTray.Source,
 | 
			
		||||
 | 
			
		||||
    _init: function(mount, apps) {
 | 
			
		||||
        MessageTray.Source.prototype._init.call(this, mount.get_name());
 | 
			
		||||
 | 
			
		||||
        this.mount = mount;
 | 
			
		||||
        this.apps = apps;
 | 
			
		||||
 | 
			
		||||
        this.parent(mount.get_name());
 | 
			
		||||
 | 
			
		||||
        this._notification = new AutorunTransientNotification(this);
 | 
			
		||||
        this._setSummaryIcon(this.createNotificationIcon(this.ICON_SIZE));
 | 
			
		||||
 | 
			
		||||
        // add ourselves as a source, and popup the notification
 | 
			
		||||
        Main.messageTray.add(this);
 | 
			
		||||
        this.notify(this._notification);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createNotificationIcon: function(iconSize) {
 | 
			
		||||
    createIcon: function(size) {
 | 
			
		||||
        return new St.Icon({ gicon: this.mount.get_icon(),
 | 
			
		||||
                             icon_size: iconSize ? iconSize : this.ICON_SIZE });
 | 
			
		||||
                             icon_size: size });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function AutorunTransientNotification(source) {
 | 
			
		||||
    this._init(source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AutorunTransientNotification.prototype = {
 | 
			
		||||
    __proto__: MessageTray.Notification.prototype,
 | 
			
		||||
const AutorunTransientNotification = new Lang.Class({
 | 
			
		||||
    Name: 'AutorunTransientNotification',
 | 
			
		||||
    Extends: MessageTray.Notification,
 | 
			
		||||
 | 
			
		||||
    _init: function(source) {
 | 
			
		||||
        MessageTray.Notification.prototype._init.call(this, source,
 | 
			
		||||
                                                      source.title, null,
 | 
			
		||||
                                                      { customContent: true });
 | 
			
		||||
        this.parent(source, source.title, null, { customContent: true });
 | 
			
		||||
 | 
			
		||||
        this._box = new St.BoxLayout({ style_class: 'hotplug-transient-box',
 | 
			
		||||
                                       vertical: true });
 | 
			
		||||
@@ -588,7 +545,7 @@ AutorunTransientNotification.prototype = {
 | 
			
		||||
 | 
			
		||||
        let label = new St.Bin({ y_align: St.Align.MIDDLE,
 | 
			
		||||
                                 child: new St.Label
 | 
			
		||||
                                 ({ text: _("Open with %s").format(app.get_display_name()) })
 | 
			
		||||
                                 ({ text: _("Open with %s").format(app.get_name()) })
 | 
			
		||||
                               });
 | 
			
		||||
        box.add(label);
 | 
			
		||||
 | 
			
		||||
@@ -630,5 +587,5 @@ AutorunTransientNotification.prototype = {
 | 
			
		||||
 | 
			
		||||
        return button;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
@@ -9,6 +9,13 @@ const Shell = imports.gi.Shell;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
const PopupAnimation = {
 | 
			
		||||
    NONE:  0,
 | 
			
		||||
    SLIDE: 1 << 0,
 | 
			
		||||
    FADE:  1 << 1,
 | 
			
		||||
    FULL:  ~0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const POPUP_ANIMATION_TIME = 0.15;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -18,16 +25,18 @@ const POPUP_ANIMATION_TIME = 0.15;
 | 
			
		||||
 *
 | 
			
		||||
 * An actor which displays a triangle "arrow" pointing to a given
 | 
			
		||||
 * side.  The .bin property is a container in which content can be
 | 
			
		||||
 * placed.  The arrow position may be controlled via setArrowOrigin().
 | 
			
		||||
 * placed.  The arrow position may be controlled via
 | 
			
		||||
 * setArrowOrigin(). The arrow side might be temporarily flipped
 | 
			
		||||
 * depending on the box size and source position to keep the box
 | 
			
		||||
 * totally inside the monitor if possible.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
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._userArrowSide = arrowSide;
 | 
			
		||||
        this._arrowOrigin = 0;
 | 
			
		||||
        this.actor = new St.Bin({ x_fill: true,
 | 
			
		||||
                                  y_fill: true });
 | 
			
		||||
@@ -46,16 +55,37 @@ BoxPointer.prototype = {
 | 
			
		||||
        this._yOffset = 0;
 | 
			
		||||
        this._xPosition = 0;
 | 
			
		||||
        this._yPosition = 0;
 | 
			
		||||
        this._sourceAlignment = 0.5;
 | 
			
		||||
        this._capturedEventId = 0;
 | 
			
		||||
        this._muteInput();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _muteInput: function() {
 | 
			
		||||
        if (this._capturedEventId == 0)
 | 
			
		||||
            this._capturedEventId = this.actor.connect('captured-event',
 | 
			
		||||
                                                       function() { return true; });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _unmuteInput: function() {
 | 
			
		||||
        if (this._capturedEventId != 0) {
 | 
			
		||||
            this.actor.disconnect(this._capturedEventId);
 | 
			
		||||
            this._capturedEventId = 0;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show: function(animate, onComplete) {
 | 
			
		||||
        let themeNode = this.actor.get_theme_node();
 | 
			
		||||
        let rise = themeNode.get_length('-arrow-rise');
 | 
			
		||||
        let animationTime = (animate & PopupAnimation.FULL) ? POPUP_ANIMATION_TIME : 0;
 | 
			
		||||
 | 
			
		||||
        if (animate & PopupAnimation.FADE)
 | 
			
		||||
            this.opacity = 0;
 | 
			
		||||
        else
 | 
			
		||||
            this.opacity = 255;
 | 
			
		||||
 | 
			
		||||
        this.opacity = 0;
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
 | 
			
		||||
        if (animate) {
 | 
			
		||||
        if (animate & PopupAnimation.SLIDE) {
 | 
			
		||||
            switch (this._arrowSide) {
 | 
			
		||||
                case St.Side.TOP:
 | 
			
		||||
                    this.yOffset = -rise;
 | 
			
		||||
@@ -75,9 +105,13 @@ BoxPointer.prototype = {
 | 
			
		||||
        Tweener.addTween(this, { opacity: 255,
 | 
			
		||||
                                 xOffset: 0,
 | 
			
		||||
                                 yOffset: 0,
 | 
			
		||||
                                 transition: "linear",
 | 
			
		||||
                                 onComplete: onComplete,
 | 
			
		||||
                                 time: POPUP_ANIMATION_TIME });
 | 
			
		||||
                                 transition: 'linear',
 | 
			
		||||
                                 onComplete: Lang.bind(this, function() {
 | 
			
		||||
                                     this._unmuteInput();
 | 
			
		||||
                                     if (onComplete)
 | 
			
		||||
                                         onComplete();
 | 
			
		||||
                                 }),
 | 
			
		||||
                                 time: animationTime });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hide: function(animate, onComplete) {
 | 
			
		||||
@@ -85,8 +119,10 @@ BoxPointer.prototype = {
 | 
			
		||||
        let yOffset = 0;
 | 
			
		||||
        let themeNode = this.actor.get_theme_node();
 | 
			
		||||
        let rise = themeNode.get_length('-arrow-rise');
 | 
			
		||||
        let fade = (animate & PopupAnimation.FADE);
 | 
			
		||||
        let animationTime = (animate & PopupAnimation.FULL) ? POPUP_ANIMATION_TIME : 0;
 | 
			
		||||
 | 
			
		||||
        if (animate) {
 | 
			
		||||
        if (animate & PopupAnimation.SLIDE) {
 | 
			
		||||
            switch (this._arrowSide) {
 | 
			
		||||
                case St.Side.TOP:
 | 
			
		||||
                    yOffset = rise;
 | 
			
		||||
@@ -103,13 +139,16 @@ BoxPointer.prototype = {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Tweener.addTween(this, { opacity: 0,
 | 
			
		||||
        this._muteInput();
 | 
			
		||||
 | 
			
		||||
        Tweener.addTween(this, { opacity: fade ? 0 : 255,
 | 
			
		||||
                                 xOffset: xOffset,
 | 
			
		||||
                                 yOffset: yOffset,
 | 
			
		||||
                                 transition: "linear",
 | 
			
		||||
                                 time: POPUP_ANIMATION_TIME,
 | 
			
		||||
                                 transition: 'linear',
 | 
			
		||||
                                 time: animationTime,
 | 
			
		||||
                                 onComplete: Lang.bind(this, function () {
 | 
			
		||||
                                     this.actor.hide();
 | 
			
		||||
                                     this.opacity = 0;
 | 
			
		||||
                                     this.xOffset = 0;
 | 
			
		||||
                                     this.yOffset = 0;
 | 
			
		||||
                                     if (onComplete)
 | 
			
		||||
@@ -179,8 +218,27 @@ BoxPointer.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
        this.bin.allocate(childBox, flags);
 | 
			
		||||
 | 
			
		||||
        if (this._sourceActor && this._sourceActor.mapped)
 | 
			
		||||
            this._reposition(this._sourceActor, this._alignment);
 | 
			
		||||
        if (this._sourceActor && this._sourceActor.mapped) {
 | 
			
		||||
            this._reposition(this._sourceActor, this._arrowAlignment);
 | 
			
		||||
 | 
			
		||||
            if (this._shouldFlip()) {
 | 
			
		||||
                switch (this._arrowSide) {
 | 
			
		||||
                case St.Side.TOP:
 | 
			
		||||
                    this._arrowSide = St.Side.BOTTOM;
 | 
			
		||||
                    break;
 | 
			
		||||
                case St.Side.BOTTOM:
 | 
			
		||||
                    this._arrowSide = St.Side.TOP;
 | 
			
		||||
                    break;
 | 
			
		||||
                case St.Side.LEFT:
 | 
			
		||||
                    this._arrowSide = St.Side.RIGHT;
 | 
			
		||||
                    break;
 | 
			
		||||
                case St.Side.RIGHT:
 | 
			
		||||
                    this._arrowSide = St.Side.LEFT;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                this._reposition(this._sourceActor, this._arrowAlignment);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _drawBorder: function(area) {
 | 
			
		||||
@@ -194,7 +252,6 @@ BoxPointer.prototype = {
 | 
			
		||||
        let halfBorder = borderWidth / 2;
 | 
			
		||||
        let halfBase = Math.floor(base/2);
 | 
			
		||||
 | 
			
		||||
        let borderColor = themeNode.get_color('-arrow-border-color');
 | 
			
		||||
        let backgroundColor = themeNode.get_color('-arrow-background-color');
 | 
			
		||||
 | 
			
		||||
        let [width, height] = area.get_surface_size();
 | 
			
		||||
@@ -205,7 +262,6 @@ BoxPointer.prototype = {
 | 
			
		||||
            boxWidth -= rise;
 | 
			
		||||
        }
 | 
			
		||||
        let cr = area.get_context();
 | 
			
		||||
        Clutter.cairo_set_source_color(cr, borderColor);
 | 
			
		||||
 | 
			
		||||
        // Translate so that box goes from 0,0 to boxWidth,boxHeight,
 | 
			
		||||
        // with the arrow poking out of that
 | 
			
		||||
@@ -301,35 +357,50 @@ BoxPointer.prototype = {
 | 
			
		||||
 | 
			
		||||
        Clutter.cairo_set_source_color(cr, backgroundColor);
 | 
			
		||||
        cr.fillPreserve();
 | 
			
		||||
        Clutter.cairo_set_source_color(cr, borderColor);
 | 
			
		||||
        cr.setLineWidth(borderWidth);
 | 
			
		||||
        cr.stroke();
 | 
			
		||||
 | 
			
		||||
        if (borderWidth > 0) {
 | 
			
		||||
            let borderColor = themeNode.get_color('-arrow-border-color');
 | 
			
		||||
            Clutter.cairo_set_source_color(cr, borderColor);
 | 
			
		||||
            cr.setLineWidth(borderWidth);
 | 
			
		||||
            cr.stroke();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setPosition: function(sourceActor, alignment) {
 | 
			
		||||
        this._arrowSide = this._userArrowSide;
 | 
			
		||||
 | 
			
		||||
        // 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._alignment = alignment;
 | 
			
		||||
        this._arrowAlignment = alignment;
 | 
			
		||||
 | 
			
		||||
        this._reposition(sourceActor, alignment);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setSourceAlignment: function(alignment) {
 | 
			
		||||
        this._sourceAlignment = alignment;
 | 
			
		||||
 | 
			
		||||
        if (!this._sourceActor)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.setPosition(this._sourceActor, this._arrowAlignment);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _reposition: function(sourceActor, alignment) {
 | 
			
		||||
        // Position correctly relative to the sourceActor
 | 
			
		||||
        let sourceNode = sourceActor.get_theme_node();
 | 
			
		||||
        let sourceContentBox = sourceNode.get_content_box(sourceActor.get_allocation_box());
 | 
			
		||||
        let sourceAllocation = Shell.util_get_transformed_allocation(sourceActor);
 | 
			
		||||
        let sourceCenterX = sourceAllocation.x1 + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) / 2;
 | 
			
		||||
        let sourceCenterY = sourceAllocation.y1 + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) / 2;
 | 
			
		||||
        let sourceCenterX = sourceAllocation.x1 + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * this._sourceAlignment;
 | 
			
		||||
        let sourceCenterY = sourceAllocation.y1 + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) * this._sourceAlignment;
 | 
			
		||||
        let [minWidth, minHeight, natWidth, natHeight] = this.actor.get_preferred_size();
 | 
			
		||||
 | 
			
		||||
        // We also want to keep it onscreen, and separated from the
 | 
			
		||||
        // edge by the same distance as the main part of the box is
 | 
			
		||||
        // separated from its sourceActor
 | 
			
		||||
        let primary = Main.layoutManager.primaryMonitor;
 | 
			
		||||
        let monitor = Main.layoutManager.findMonitorForActor(sourceActor);
 | 
			
		||||
        let themeNode = this.actor.get_theme_node();
 | 
			
		||||
        let borderWidth = themeNode.get_length('-arrow-border-width');
 | 
			
		||||
        let arrowBase = themeNode.get_length('-arrow-base');
 | 
			
		||||
@@ -364,8 +435,8 @@ BoxPointer.prototype = {
 | 
			
		||||
        case St.Side.BOTTOM:
 | 
			
		||||
            resX = sourceCenterX - (halfMargin + (natWidth - margin) * alignment);
 | 
			
		||||
 | 
			
		||||
            resX = Math.max(resX, primary.x + 10);
 | 
			
		||||
            resX = Math.min(resX, primary.x + primary.width - (10 + natWidth));
 | 
			
		||||
            resX = Math.max(resX, monitor.x + 10);
 | 
			
		||||
            resX = Math.min(resX, monitor.x + monitor.width - (10 + natWidth));
 | 
			
		||||
            this.setArrowOrigin(sourceCenterX - resX);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
@@ -373,8 +444,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;
 | 
			
		||||
@@ -413,6 +484,39 @@ BoxPointer.prototype = {
 | 
			
		||||
                                    -(this._yPosition + this._yOffset));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _shouldFlip: function() {
 | 
			
		||||
        let sourceAllocation = Shell.util_get_transformed_allocation(this._sourceActor);
 | 
			
		||||
        let boxAllocation = Shell.util_get_transformed_allocation(this.actor);
 | 
			
		||||
        let boxWidth = boxAllocation.x2 - boxAllocation.x1;
 | 
			
		||||
        let boxHeight = boxAllocation.y2 - boxAllocation.y1;
 | 
			
		||||
        let monitor = Main.layoutManager.findMonitorForActor(this.actor);
 | 
			
		||||
 | 
			
		||||
        switch (this._arrowSide) {
 | 
			
		||||
        case St.Side.TOP:
 | 
			
		||||
            if (boxAllocation.y2 > monitor.y + monitor.height &&
 | 
			
		||||
                boxHeight < sourceAllocation.y1 - monitor.y)
 | 
			
		||||
                return true;
 | 
			
		||||
            break;
 | 
			
		||||
        case St.Side.BOTTOM:
 | 
			
		||||
            if (boxAllocation.y1 < monitor.y &&
 | 
			
		||||
                boxHeight < monitor.y + monitor.height - sourceAllocation.y2)
 | 
			
		||||
                return true;
 | 
			
		||||
            break;
 | 
			
		||||
        case St.Side.LEFT:
 | 
			
		||||
            if (boxAllocation.x2 > monitor.x + monitor.width &&
 | 
			
		||||
                boxWidth < sourceAllocation.x1 - monitor.x)
 | 
			
		||||
                return true;
 | 
			
		||||
            break;
 | 
			
		||||
        case St.Side.RIGHT:
 | 
			
		||||
            if (boxAllocation.x1 < monitor.x &&
 | 
			
		||||
                boxWidth < monitor.x + monitor.width - sourceAllocation.x2)
 | 
			
		||||
                return true;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    set xOffset(offset) {
 | 
			
		||||
        this._xOffset = offset;
 | 
			
		||||
        this._shiftActor();
 | 
			
		||||
@@ -438,4 +542,4 @@ BoxPointer.prototype = {
 | 
			
		||||
    get opacity() {
 | 
			
		||||
        return this.actor.opacity;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const DBus = imports.dbus;
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
@@ -156,28 +155,24 @@ function _getEventDayAbbreviation(dayNumber) {
 | 
			
		||||
 | 
			
		||||
// Abstraction for an appointment/event in a calendar
 | 
			
		||||
 | 
			
		||||
function CalendarEvent(date, end, summary, allDay) {
 | 
			
		||||
    this._init(date, end, summary, allDay);
 | 
			
		||||
}
 | 
			
		||||
const CalendarEvent = new Lang.Class({
 | 
			
		||||
    Name: 'CalendarEvent',
 | 
			
		||||
 | 
			
		||||
CalendarEvent.prototype = {
 | 
			
		||||
    _init: function(date, end, summary, allDay) {
 | 
			
		||||
        this.date = date;
 | 
			
		||||
        this.end = end;
 | 
			
		||||
        this.summary = summary;
 | 
			
		||||
        this.allDay = allDay;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Interface for appointments/events - e.g. the contents of a calendar
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
// First, an implementation with no events
 | 
			
		||||
function EmptyEventSource() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const EmptyEventSource = new Lang.Class({
 | 
			
		||||
    Name: 'EmptyEventSource',
 | 
			
		||||
 | 
			
		||||
EmptyEventSource.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -192,33 +187,32 @@ EmptyEventSource.prototype = {
 | 
			
		||||
    hasEvents: function(day) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(EmptyEventSource.prototype);
 | 
			
		||||
 | 
			
		||||
const CalendarServerIface = {
 | 
			
		||||
    name: 'org.gnome.Shell.CalendarServer',
 | 
			
		||||
    methods: [{ name: 'GetEvents',
 | 
			
		||||
                inSignature: 'xxb',
 | 
			
		||||
                outSignature: 'a(sssbxxa{sv})' }],
 | 
			
		||||
    signals: [{ name: 'Changed',
 | 
			
		||||
                inSignature: '' }]
 | 
			
		||||
};
 | 
			
		||||
const CalendarServerIface = <interface name="org.gnome.Shell.CalendarServer">
 | 
			
		||||
<method name="GetEvents">
 | 
			
		||||
    <arg type="x" direction="in" />
 | 
			
		||||
    <arg type="x" direction="in" />
 | 
			
		||||
    <arg type="b" direction="in" />
 | 
			
		||||
    <arg type="a(sssbxxa{sv})" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
<signal name="Changed" />
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const CalendarServer = function () {
 | 
			
		||||
    this._init();
 | 
			
		||||
};
 | 
			
		||||
const CalendarServerInfo  = Gio.DBusInterfaceInfo.new_for_xml(CalendarServerIface);
 | 
			
		||||
 | 
			
		||||
CalendarServer.prototype = {
 | 
			
		||||
     _init: function() {
 | 
			
		||||
         DBus.session.proxifyObject(this, 'org.gnome.Shell.CalendarServer', '/org/gnome/Shell/CalendarServer');
 | 
			
		||||
     }
 | 
			
		||||
};
 | 
			
		||||
function CalendarServer() {
 | 
			
		||||
    var self = new Gio.DBusProxy({ g_connection: Gio.DBus.session,
 | 
			
		||||
				   g_interface_name: CalendarServerInfo.name,
 | 
			
		||||
				   g_interface_info: CalendarServerInfo,
 | 
			
		||||
				   g_name: 'org.gnome.Shell.CalendarServer',
 | 
			
		||||
				   g_object_path: '/org/gnome/Shell/CalendarServer',
 | 
			
		||||
                                   g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
 | 
			
		||||
                                             Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
 | 
			
		||||
 | 
			
		||||
DBus.proxifyPrototype(CalendarServer.prototype, CalendarServerIface);
 | 
			
		||||
 | 
			
		||||
// an implementation that reads data from a session bus service
 | 
			
		||||
function DBusEventSource(owner) {
 | 
			
		||||
    this._init(owner);
 | 
			
		||||
    self.init(null);
 | 
			
		||||
    return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _datesEqual(a, b) {
 | 
			
		||||
@@ -239,18 +233,22 @@ function _dateIntervalsOverlap(a0, a1, b0, b1)
 | 
			
		||||
        return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// an implementation that reads data from a session bus service
 | 
			
		||||
const DBusEventSource = new Lang.Class({
 | 
			
		||||
    Name: 'DBusEventSource',
 | 
			
		||||
 | 
			
		||||
DBusEventSource.prototype = {
 | 
			
		||||
    _init: function(owner) {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._resetCache();
 | 
			
		||||
 | 
			
		||||
        this._dbusProxy = new CalendarServer(owner);
 | 
			
		||||
        this._dbusProxy.connect('Changed', Lang.bind(this, this._onChanged));
 | 
			
		||||
        this._dbusProxy = new CalendarServer();
 | 
			
		||||
        this._dbusProxy.connectSignal('Changed', Lang.bind(this, this._onChanged));
 | 
			
		||||
 | 
			
		||||
        DBus.session.watch_name('org.gnome.Shell.CalendarServer',
 | 
			
		||||
                                false, // do not launch a name-owner if none exists
 | 
			
		||||
                                Lang.bind(this, this._onNameAppeared),
 | 
			
		||||
                                Lang.bind(this, this._onNameVanished));
 | 
			
		||||
        this._dbusProxy.connect('notify::g-name-owner', Lang.bind(this, function() {
 | 
			
		||||
            if (this._dbusProxy.g_name_owner)
 | 
			
		||||
                this._onNameAppeared();
 | 
			
		||||
            else
 | 
			
		||||
                this._onNameVanished();
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _resetCache: function() {
 | 
			
		||||
@@ -273,7 +271,7 @@ DBusEventSource.prototype = {
 | 
			
		||||
        this._loadEvents(false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onEventsReceived: function(appointments) {
 | 
			
		||||
    _onEventsReceived: function([appointments]) {
 | 
			
		||||
        let newEvents = [];
 | 
			
		||||
        if (appointments != null) {
 | 
			
		||||
            for (let n = 0; n < appointments.length; n++) {
 | 
			
		||||
@@ -296,9 +294,9 @@ DBusEventSource.prototype = {
 | 
			
		||||
 | 
			
		||||
    _loadEvents: function(forceReload) {
 | 
			
		||||
        if (this._curRequestBegin && this._curRequestEnd){
 | 
			
		||||
            let callFlags = 0;
 | 
			
		||||
            let callFlags = Gio.DBusCallFlags.NO_AUTO_START;
 | 
			
		||||
            if (forceReload)
 | 
			
		||||
                callFlags |= DBus.CALL_FLAG_START;
 | 
			
		||||
                callFlags = Gio.DBusCallFlags.NONE;
 | 
			
		||||
            this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
 | 
			
		||||
                                            this._curRequestEnd.getTime() / 1000,
 | 
			
		||||
                                            forceReload,
 | 
			
		||||
@@ -339,17 +337,15 @@ DBusEventSource.prototype = {
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(DBusEventSource.prototype);
 | 
			
		||||
 | 
			
		||||
// Calendar:
 | 
			
		||||
// @eventSource: is an object implementing the EventSource API, e.g. the
 | 
			
		||||
// requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
 | 
			
		||||
function Calendar(eventSource) {
 | 
			
		||||
    this._init(eventSource);
 | 
			
		||||
}
 | 
			
		||||
const Calendar = new Lang.Class({
 | 
			
		||||
    Name: 'Calendar',
 | 
			
		||||
 | 
			
		||||
Calendar.prototype = {
 | 
			
		||||
    _init: function(eventSource) {
 | 
			
		||||
        if (eventSource) {
 | 
			
		||||
            this._eventSource = eventSource;
 | 
			
		||||
@@ -410,7 +406,7 @@ Calendar.prototype = {
 | 
			
		||||
 | 
			
		||||
    _buildHeader: function() {
 | 
			
		||||
        let offsetCols = this._useWeekdate ? 1 : 0;
 | 
			
		||||
        this.actor.destroy_children();
 | 
			
		||||
        this.actor.destroy_all_children();
 | 
			
		||||
 | 
			
		||||
        // Top line of the calendar '<| September 2009 |>'
 | 
			
		||||
        this._topBox = new St.BoxLayout();
 | 
			
		||||
@@ -452,7 +448,7 @@ Calendar.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // All the children after this are days, and get removed when we update the calendar
 | 
			
		||||
        this._firstDayIndex = this.actor.get_children().length;
 | 
			
		||||
        this._firstDayIndex = this.actor.get_n_children();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onStyleChange: function(actor, event) {
 | 
			
		||||
@@ -555,6 +551,7 @@ Calendar.prototype = {
 | 
			
		||||
        let row = 2;
 | 
			
		||||
        while (true) {
 | 
			
		||||
            let button = new St.Button({ label: iter.getDate().toString() });
 | 
			
		||||
            let rtl = button.get_text_direction() == Clutter.TextDirection.RTL;
 | 
			
		||||
 | 
			
		||||
            if (!this._eventSource)
 | 
			
		||||
                button.reactive = false;
 | 
			
		||||
@@ -575,7 +572,10 @@ Calendar.prototype = {
 | 
			
		||||
            // Hack used in lieu of border-collapse - see gnome-shell.css
 | 
			
		||||
            if (row == 2)
 | 
			
		||||
                styleClass = 'calendar-day-top ' + styleClass;
 | 
			
		||||
            if (iter.getDay() == this._weekStart)
 | 
			
		||||
 | 
			
		||||
            let leftMost = rtl ? iter.getDay() == (this._weekStart + 6) % 7
 | 
			
		||||
                               : iter.getDay() == this._weekStart;
 | 
			
		||||
            if (leftMost)
 | 
			
		||||
                styleClass = 'calendar-day-left ' + styleClass;
 | 
			
		||||
 | 
			
		||||
            if (_sameDay(now, iter))
 | 
			
		||||
@@ -615,15 +615,13 @@ Calendar.prototype = {
 | 
			
		||||
        if (this._eventSource)
 | 
			
		||||
            this._eventSource.requestRange(beginDate, iter, forceReload);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(Calendar.prototype);
 | 
			
		||||
 | 
			
		||||
function EventsList(eventSource) {
 | 
			
		||||
    this._init(eventSource);
 | 
			
		||||
}
 | 
			
		||||
const EventsList = new Lang.Class({
 | 
			
		||||
    Name: 'EventsList',
 | 
			
		||||
 | 
			
		||||
EventsList.prototype = {
 | 
			
		||||
    _init: function(eventSource) {
 | 
			
		||||
        this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'});
 | 
			
		||||
        this._date = new Date();
 | 
			
		||||
@@ -691,7 +689,7 @@ EventsList.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showOtherDay: function(day) {
 | 
			
		||||
        this.actor.destroy_children();
 | 
			
		||||
        this.actor.destroy_all_children();
 | 
			
		||||
 | 
			
		||||
        let dayBegin = _getBeginningOfDay(day);
 | 
			
		||||
        let dayEnd = _getEndOfDay(day);
 | 
			
		||||
@@ -708,7 +706,7 @@ EventsList.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showToday: function() {
 | 
			
		||||
        this.actor.destroy_children();
 | 
			
		||||
        this.actor.destroy_all_children();
 | 
			
		||||
 | 
			
		||||
        let now = new Date();
 | 
			
		||||
        let dayBegin = _getBeginningOfDay(now);
 | 
			
		||||
@@ -754,4 +752,4 @@ EventsList.prototype = {
 | 
			
		||||
            this._showOtherDay(this._date);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										115
									
								
								js/ui/checkBox.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,115 @@
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Pango = imports.gi.Pango;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
 | 
			
		||||
const CheckBoxContainer = new Lang.Class({
 | 
			
		||||
    Name: 'CheckBoxContainer',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.actor = new Shell.GenericContainer();
 | 
			
		||||
        this.actor.connect('get-preferred-width',
 | 
			
		||||
                           Lang.bind(this, this._getPreferredWidth));
 | 
			
		||||
        this.actor.connect('get-preferred-height',
 | 
			
		||||
                           Lang.bind(this, this._getPreferredHeight));
 | 
			
		||||
        this.actor.connect('allocate',
 | 
			
		||||
                           Lang.bind(this, this._allocate));
 | 
			
		||||
        this.actor.connect('style-changed', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
                let node = this.actor.get_theme_node();
 | 
			
		||||
                this._spacing = node.get_length('spacing');
 | 
			
		||||
            }));
 | 
			
		||||
        this.actor.request_mode = Clutter.RequestMode.HEIGHT_FOR_WIDTH;
 | 
			
		||||
 | 
			
		||||
        this._box = new St.Bin();
 | 
			
		||||
        this.actor.add_actor(this._box);
 | 
			
		||||
 | 
			
		||||
        this.label = new St.Label();
 | 
			
		||||
        this.label.clutter_text.set_line_wrap(true);
 | 
			
		||||
        this.label.clutter_text.set_ellipsize(Pango.EllipsizeMode.NONE);
 | 
			
		||||
        this.actor.add_actor(this.label);
 | 
			
		||||
 | 
			
		||||
        this._spacing = 0;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getPreferredWidth: function(actor, forHeight, alloc) {
 | 
			
		||||
        let [minWidth, natWidth] = this._box.get_preferred_width(forHeight);
 | 
			
		||||
 | 
			
		||||
        alloc.min_size = minWidth + this._spacing;
 | 
			
		||||
        alloc.natural_size = natWidth + this._spacing;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getPreferredHeight: function(actor, forWidth, alloc) {
 | 
			
		||||
        /* FIXME: StBoxlayout currently does not handle
 | 
			
		||||
           height-for-width children correctly, so hard-code
 | 
			
		||||
           two lines for the label until that problem is fixed.
 | 
			
		||||
 | 
			
		||||
           https://bugzilla.gnome.org/show_bug.cgi?id=672543 */
 | 
			
		||||
/*
 | 
			
		||||
        let [minBoxHeight, natBoxHeight] =
 | 
			
		||||
            this._box.get_preferred_height(forWidth);
 | 
			
		||||
        let [minLabelHeight, natLabelHeight] =
 | 
			
		||||
            this.label.get_preferred_height(forWidth);
 | 
			
		||||
 | 
			
		||||
        alloc.min_size = Math.max(minBoxHeight, minLabelHeight);
 | 
			
		||||
        alloc.natural_size = Math.max(natBoxHeight, natLabelHeight);
 | 
			
		||||
*/
 | 
			
		||||
        let [minBoxHeight, natBoxHeight] =
 | 
			
		||||
            this._box.get_preferred_height(-1);
 | 
			
		||||
        let [minLabelHeight, natLabelHeight] =
 | 
			
		||||
            this.label.get_preferred_height(-1);
 | 
			
		||||
 | 
			
		||||
        alloc.min_size = Math.max(minBoxHeight, 2 * minLabelHeight);
 | 
			
		||||
        alloc.natural_size = Math.max(natBoxHeight, 2 * natLabelHeight);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _allocate: function(actor, box, flags) {
 | 
			
		||||
        let availWidth = box.x2 - box.x1;
 | 
			
		||||
        let availHeight = box.y2 - box.y1;
 | 
			
		||||
 | 
			
		||||
        let childBox = new Clutter.ActorBox();
 | 
			
		||||
        let [minBoxWidth, natBoxWidth] =
 | 
			
		||||
            this._box.get_preferred_width(-1);
 | 
			
		||||
        let [minBoxHeight, natBoxHeight] =
 | 
			
		||||
            this._box.get_preferred_height(-1);
 | 
			
		||||
        childBox.x1 = box.x1;
 | 
			
		||||
        childBox.x2 = box.x1 + natBoxWidth;
 | 
			
		||||
        childBox.y1 = box.y1;
 | 
			
		||||
        childBox.y2 = box.y1 + natBoxHeight;
 | 
			
		||||
        this._box.allocate(childBox, flags);
 | 
			
		||||
 | 
			
		||||
        childBox.x1 = box.x1 + natBoxWidth + this._spacing;
 | 
			
		||||
        childBox.x2 = availWidth - childBox.x1;
 | 
			
		||||
        childBox.y1 = box.y1;
 | 
			
		||||
        childBox.y2 = box.y2;
 | 
			
		||||
        this.label.allocate(childBox, flags);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const CheckBox = new Lang.Class({
 | 
			
		||||
    Name: 'CheckBox',
 | 
			
		||||
 | 
			
		||||
    _init: function(label) {
 | 
			
		||||
        this.actor = new St.Button({ style_class: 'check-box',
 | 
			
		||||
                                     button_mask: St.ButtonMask.ONE,
 | 
			
		||||
                                     toggle_mode: true,
 | 
			
		||||
                                     can_focus: true,
 | 
			
		||||
                                     x_fill: true,
 | 
			
		||||
                                     y_fill: true });
 | 
			
		||||
        this._container = new CheckBoxContainer();
 | 
			
		||||
        this.actor.set_child(this._container.actor);
 | 
			
		||||
 | 
			
		||||
        if (label)
 | 
			
		||||
            this.setLabel(label);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setLabel: function(label) {
 | 
			
		||||
        this._container.label.set_text(label);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getLabelActor: function() {
 | 
			
		||||
        return this._container.label;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
@@ -1,179 +0,0 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 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 */
 | 
			
		||||
function Contact(id) {
 | 
			
		||||
    this._init(id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Contact.prototype = {
 | 
			
		||||
    _init: function(id) {
 | 
			
		||||
        this.individual = Shell.ContactSystem.get_default().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 aliasText = this.individual.alias || _("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 */
 | 
			
		||||
function ContactSearchProvider() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ContactSearchProvider.prototype = {
 | 
			
		||||
    __proto__: Search.SearchProvider.prototype,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        Search.SearchProvider.prototype._init.call(this, _("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;
 | 
			
		||||
@@ -22,11 +22,9 @@ const SortGroup = {
 | 
			
		||||
    BOTTOM: 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function CtrlAltTabManager() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const CtrlAltTabManager = new Lang.Class({
 | 
			
		||||
    Name: 'CtrlAltTabManager',
 | 
			
		||||
 | 
			
		||||
CtrlAltTabManager.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._items = [];
 | 
			
		||||
        this._focusManager = St.FocusManager.get_for_stage(global.stage);
 | 
			
		||||
@@ -94,7 +92,7 @@ CtrlAltTabManager.prototype = {
 | 
			
		||||
        return a.x - b.x;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    popup: function(backwards) {
 | 
			
		||||
    popup: function(backwards, mask) {
 | 
			
		||||
        // Start with the set of focus groups that are currently mapped
 | 
			
		||||
        let items = this._items.filter(function (item) { return item.proxy.mapped; });
 | 
			
		||||
 | 
			
		||||
@@ -123,19 +121,26 @@ CtrlAltTabManager.prototype = {
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        items.sort(Lang.bind(this, this._sortItems));
 | 
			
		||||
        new CtrlAltTabPopup().show(items, backwards);
 | 
			
		||||
 | 
			
		||||
        if (!this._popup) {
 | 
			
		||||
            this._popup = new CtrlAltTabPopup();
 | 
			
		||||
            this._popup.show(items, backwards, mask);
 | 
			
		||||
 | 
			
		||||
            this._popup.actor.connect('destroy',
 | 
			
		||||
                                      Lang.bind(this, function() {
 | 
			
		||||
                                          this._popup = null;
 | 
			
		||||
                                      }));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function mod(a, b) {
 | 
			
		||||
    return (a + b) % b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function CtrlAltTabPopup() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const CtrlAltTabPopup = new Lang.Class({
 | 
			
		||||
    Name: 'CtrlAltTabPopup',
 | 
			
		||||
 | 
			
		||||
CtrlAltTabPopup.prototype = {
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        this.actor = new Shell.GenericContainer({ name: 'ctrlAltTabPopup',
 | 
			
		||||
                                                  reactive: true });
 | 
			
		||||
@@ -147,6 +152,7 @@ CtrlAltTabPopup.prototype = {
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 | 
			
		||||
 | 
			
		||||
        this._haveModal = false;
 | 
			
		||||
        this._modifierMask = 0;
 | 
			
		||||
        this._selection = 0;
 | 
			
		||||
 | 
			
		||||
        Main.uiGroup.add_actor(this.actor);
 | 
			
		||||
@@ -177,16 +183,17 @@ CtrlAltTabPopup.prototype = {
 | 
			
		||||
        let [childMinHeight, childNaturalHeight] = this._switcher.actor.get_preferred_height(primary.width - hPadding);
 | 
			
		||||
        let [childMinWidth, childNaturalWidth] = this._switcher.actor.get_preferred_width(childNaturalHeight);
 | 
			
		||||
        childBox.x1 = Math.max(primary.x + leftPadding, primary.x + Math.floor((primary.width - childNaturalWidth) / 2));
 | 
			
		||||
        childBox.x2 = Math.min(primary.width - hPadding, childBox.x1 + childNaturalWidth);
 | 
			
		||||
        childBox.x2 = Math.min(primary.x + primary.width - hPadding, childBox.x1 + childNaturalWidth);
 | 
			
		||||
        childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
 | 
			
		||||
        childBox.y2 = childBox.y1 + childNaturalHeight;
 | 
			
		||||
        this._switcher.actor.allocate(childBox, flags);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show : function(items, startBackwards) {
 | 
			
		||||
    show : function(items, startBackwards, mask) {
 | 
			
		||||
        if (!Main.pushModal(this.actor))
 | 
			
		||||
            return false;
 | 
			
		||||
        this._haveModal = true;
 | 
			
		||||
        this._modifierMask = AltTab.primaryModifier(mask);
 | 
			
		||||
 | 
			
		||||
        this._keyPressEventId = this.actor.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
 | 
			
		||||
        this._keyReleaseEventId = this.actor.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
 | 
			
		||||
@@ -200,7 +207,7 @@ CtrlAltTabPopup.prototype = {
 | 
			
		||||
        this._select(this._selection);
 | 
			
		||||
 | 
			
		||||
        let [x, y, mods] = global.get_pointer();
 | 
			
		||||
        if (!(mods & Gdk.ModifierType.MOD1_MASK)) {
 | 
			
		||||
        if (!(mods & this._modifierMask)) {
 | 
			
		||||
            this._finish();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
@@ -226,7 +233,7 @@ CtrlAltTabPopup.prototype = {
 | 
			
		||||
 | 
			
		||||
    _keyPressEvent : function(actor, event) {
 | 
			
		||||
        let keysym = event.get_key_symbol();
 | 
			
		||||
        let shift = (Shell.get_event_state(event) & Clutter.ModifierType.SHIFT_MASK);
 | 
			
		||||
        let shift = (event.get_state() & Clutter.ModifierType.SHIFT_MASK);
 | 
			
		||||
        if (shift && keysym == Clutter.KEY_Tab)
 | 
			
		||||
            keysym = Clutter.ISO_Left_Tab;
 | 
			
		||||
 | 
			
		||||
@@ -246,7 +253,7 @@ CtrlAltTabPopup.prototype = {
 | 
			
		||||
 | 
			
		||||
    _keyReleaseEvent : function(actor, event) {
 | 
			
		||||
        let [x, y, mods] = global.get_pointer();
 | 
			
		||||
        let state = mods & Clutter.ModifierType.MOD1_MASK;
 | 
			
		||||
        let state = mods & this._modifierMask;
 | 
			
		||||
 | 
			
		||||
        if (state == 0)
 | 
			
		||||
            this._finish();
 | 
			
		||||
@@ -292,17 +299,14 @@ CtrlAltTabPopup.prototype = {
 | 
			
		||||
        this._selection = num;
 | 
			
		||||
        this._switcher.highlight(num);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function CtrlAltTabSwitcher(items) {
 | 
			
		||||
    this._init(items);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CtrlAltTabSwitcher.prototype = {
 | 
			
		||||
    __proto__ : AltTab.SwitcherList.prototype,
 | 
			
		||||
const CtrlAltTabSwitcher = new Lang.Class({
 | 
			
		||||
    Name: 'CtrlAltTabSwitcher',
 | 
			
		||||
    Extends: AltTab.SwitcherList,
 | 
			
		||||
 | 
			
		||||
    _init : function(items) {
 | 
			
		||||
        AltTab.SwitcherList.prototype._init.call(this, true);
 | 
			
		||||
        this.parent(true);
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < items.length; i++)
 | 
			
		||||
            this._addIcon(items[i]);
 | 
			
		||||
@@ -325,4 +329,4 @@ CtrlAltTabSwitcher.prototype = {
 | 
			
		||||
 | 
			
		||||
        this.addItem(box, text);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										325
									
								
								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,6 +6,7 @@ const Lang = imports.lang;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
 | 
			
		||||
const AppDisplay = imports.ui.appDisplay;
 | 
			
		||||
const AppFavorites = imports.ui.appFavorites;
 | 
			
		||||
@@ -16,14 +17,15 @@ const Tweener = imports.ui.tweener;
 | 
			
		||||
const Workspace = imports.ui.workspace;
 | 
			
		||||
 | 
			
		||||
const DASH_ANIMATION_TIME = 0.2;
 | 
			
		||||
const DASH_ITEM_LABEL_SHOW_TIME = 0.15;
 | 
			
		||||
const DASH_ITEM_LABEL_HIDE_TIME = 0.1;
 | 
			
		||||
const DASH_ITEM_HOVER_TIMEOUT = 300;
 | 
			
		||||
 | 
			
		||||
// 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',
 | 
			
		||||
@@ -34,9 +36,12 @@ DashItemContainer.prototype = {
 | 
			
		||||
                           Lang.bind(this, this._allocate));
 | 
			
		||||
        this.actor._delegate = this;
 | 
			
		||||
 | 
			
		||||
        this.label = null;
 | 
			
		||||
 | 
			
		||||
        this.child = null;
 | 
			
		||||
        this._childScale = 1;
 | 
			
		||||
        this._childOpacity = 255;
 | 
			
		||||
        this.animatingOut = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _allocate: function(actor, box, flags) {
 | 
			
		||||
@@ -85,11 +90,64 @@ DashItemContainer.prototype = {
 | 
			
		||||
        alloc.natural_size = natWidth * this.child.scale_y;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    showLabel: function() {
 | 
			
		||||
        if (this.label == null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.label.opacity = 0;
 | 
			
		||||
        this.label.show();
 | 
			
		||||
 | 
			
		||||
        let [stageX, stageY] = this.actor.get_transformed_position();
 | 
			
		||||
 | 
			
		||||
        let itemHeight = this.actor.allocation.y2 - this.actor.allocation.y1;
 | 
			
		||||
 | 
			
		||||
        let labelHeight = this.label.get_height();
 | 
			
		||||
        let yOffset = Math.floor((itemHeight - labelHeight) / 2)
 | 
			
		||||
 | 
			
		||||
        let y = stageY + yOffset;
 | 
			
		||||
 | 
			
		||||
        let node = this.label.get_theme_node();
 | 
			
		||||
        let xOffset = node.get_length('-x-offset');
 | 
			
		||||
 | 
			
		||||
        let x;
 | 
			
		||||
        if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
 | 
			
		||||
            x = stageX - this.label.get_width() - xOffset;
 | 
			
		||||
        else
 | 
			
		||||
            x = stageX + this.actor.get_width() + xOffset;
 | 
			
		||||
 | 
			
		||||
        this.label.set_position(x, y);
 | 
			
		||||
        Tweener.addTween(this.label,
 | 
			
		||||
                         { opacity: 255,
 | 
			
		||||
                           time: DASH_ITEM_LABEL_SHOW_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                         });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setLabelText: function(text) {
 | 
			
		||||
        if (this.label == null)
 | 
			
		||||
            this.label = new St.Label({ style_class: 'dash-label'});
 | 
			
		||||
 | 
			
		||||
        this.label.set_text(text);
 | 
			
		||||
        Main.layoutManager.addChrome(this.label);
 | 
			
		||||
        this.label.hide();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hideLabel: function () {
 | 
			
		||||
        Tweener.addTween(this.label,
 | 
			
		||||
                         { opacity: 0,
 | 
			
		||||
                           time: DASH_ITEM_LABEL_HIDE_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: Lang.bind(this, function() {
 | 
			
		||||
                               this.label.hide();
 | 
			
		||||
                           })
 | 
			
		||||
                         });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setChild: function(actor) {
 | 
			
		||||
        if (this.child == actor)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.actor.destroy_children();
 | 
			
		||||
        this.actor.destroy_all_children();
 | 
			
		||||
 | 
			
		||||
        this.child = actor;
 | 
			
		||||
        this.actor.add_actor(this.child);
 | 
			
		||||
@@ -109,12 +167,23 @@ DashItemContainer.prototype = {
 | 
			
		||||
                         });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
        if (this.label)
 | 
			
		||||
            this.label.destroy();
 | 
			
		||||
 | 
			
		||||
        this.actor.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    animateOutAndDestroy: function() {
 | 
			
		||||
        if (this.label)
 | 
			
		||||
            this.label.destroy();
 | 
			
		||||
 | 
			
		||||
        if (this.child == null) {
 | 
			
		||||
            this.actor.destroy();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.animatingOut = true;
 | 
			
		||||
        this.childScale = 1.0;
 | 
			
		||||
        Tweener.addTween(this,
 | 
			
		||||
                         { childScale: 0.0,
 | 
			
		||||
@@ -155,17 +224,14 @@ DashItemContainer.prototype = {
 | 
			
		||||
    get childOpacity() {
 | 
			
		||||
        return this._childOpacity;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function RemoveFavoriteIcon() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RemoveFavoriteIcon.prototype = {
 | 
			
		||||
    __proto__: DashItemContainer.prototype,
 | 
			
		||||
const RemoveFavoriteIcon = new Lang.Class({
 | 
			
		||||
    Name: 'RemoveFavoriteIcon',
 | 
			
		||||
    Extends: DashItemContainer,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        DashItemContainer.prototype._init.call(this);
 | 
			
		||||
        this.parent();
 | 
			
		||||
 | 
			
		||||
        this._iconBin = new St.Bin({ style_class: 'remove-favorite' });
 | 
			
		||||
        this._iconActor = null;
 | 
			
		||||
@@ -177,12 +243,6 @@ RemoveFavoriteIcon.prototype = {
 | 
			
		||||
        this._iconBin._delegate = this;
 | 
			
		||||
 | 
			
		||||
        this.setChild(this._iconBin);
 | 
			
		||||
        this.hiding = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    animateOutAndDestroy: function() {
 | 
			
		||||
        DashItemContainer.prototype.animateOutAndDestroy.call(this);
 | 
			
		||||
        this.hiding = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createIcon: function(size) {
 | 
			
		||||
@@ -223,28 +283,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;
 | 
			
		||||
@@ -254,6 +307,9 @@ Dash.prototype = {
 | 
			
		||||
        this._dragPlaceholderPos = -1;
 | 
			
		||||
        this._animatingPlaceholdersCount = 0;
 | 
			
		||||
        this._favRemoveTarget = null;
 | 
			
		||||
        this._showLabelTimeoutId = 0;
 | 
			
		||||
        this._resetHoverTimeoutId = 0;
 | 
			
		||||
        this._labelShowing = false;
 | 
			
		||||
 | 
			
		||||
        this._box = new St.BoxLayout({ name: 'dash',
 | 
			
		||||
                                       vertical: true,
 | 
			
		||||
@@ -275,7 +331,7 @@ 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));
 | 
			
		||||
@@ -314,15 +370,12 @@ Dash.prototype = {
 | 
			
		||||
    _endDrag: function() {
 | 
			
		||||
        this._clearDragPlaceholder();
 | 
			
		||||
        if (this._favRemoveTarget) {
 | 
			
		||||
            this._favRemoveTarget.actor.hide();
 | 
			
		||||
            this._adjustIconSize();
 | 
			
		||||
            this._favRemoveTarget.actor.show();
 | 
			
		||||
 | 
			
		||||
            this._favRemoveTarget.animateOutAndDestroy();
 | 
			
		||||
            this._favRemoveTarget.actor.connect('destroy', Lang.bind(this,
 | 
			
		||||
                function() {
 | 
			
		||||
                    this._favRemoveTarget = null;
 | 
			
		||||
                }));
 | 
			
		||||
            this._adjustIconSize();
 | 
			
		||||
        }
 | 
			
		||||
        DND.removeDragMonitor(this._dragMonitor);
 | 
			
		||||
    },
 | 
			
		||||
@@ -343,6 +396,7 @@ Dash.prototype = {
 | 
			
		||||
        let srcIsFavorite = (id in favorites);
 | 
			
		||||
 | 
			
		||||
        if (srcIsFavorite &&
 | 
			
		||||
            app.get_state() != Shell.AppState.RUNNING &&
 | 
			
		||||
            dragEvent.source.actor &&
 | 
			
		||||
            this.actor.contains (dragEvent.source.actor) &&
 | 
			
		||||
            this._favRemoveTarget == null) {
 | 
			
		||||
@@ -390,19 +444,73 @@ 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);
 | 
			
		||||
 | 
			
		||||
        item.setLabelText(app.get_name());
 | 
			
		||||
        // Override default AppWellIcon label_actor
 | 
			
		||||
        display.actor.label_actor = item.label;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        display.icon.setIconSize(this.iconSize);
 | 
			
		||||
        display.actor.connect('notify::hover',
 | 
			
		||||
                               Lang.bind(this, function() {
 | 
			
		||||
                                   this._onHover(item, display)
 | 
			
		||||
                               }));
 | 
			
		||||
 | 
			
		||||
        Main.overview.connect('hiding',
 | 
			
		||||
                              Lang.bind(this, function() {
 | 
			
		||||
                                  this._labelShowing = false;
 | 
			
		||||
                                  item.hideLabel();
 | 
			
		||||
                              }));
 | 
			
		||||
 | 
			
		||||
        return item;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onHover: function (item, display) {
 | 
			
		||||
        if (display.actor.get_hover() && !display.isMenuUp) {
 | 
			
		||||
            if (this._showLabelTimeoutId == 0) {
 | 
			
		||||
                let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT;
 | 
			
		||||
                this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
 | 
			
		||||
                    Lang.bind(this, function() {
 | 
			
		||||
                        this._labelShowing = true;
 | 
			
		||||
                        item.showLabel();
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }));
 | 
			
		||||
                if (this._resetHoverTimeoutId > 0) {
 | 
			
		||||
                    Mainloop.source_remove(this._resetHoverTimeoutId);
 | 
			
		||||
                    this._resetHoverTimeoutId = 0;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if (this._showLabelTimeoutId > 0)
 | 
			
		||||
                Mainloop.source_remove(this._showLabelTimeoutId);
 | 
			
		||||
            this._showLabelTimeoutId = 0;
 | 
			
		||||
            item.hideLabel();
 | 
			
		||||
            if (this._labelShowing) {
 | 
			
		||||
                this._resetHoverTimeoutId = Mainloop.timeout_add(DASH_ITEM_HOVER_TIMEOUT,
 | 
			
		||||
                    Lang.bind(this, function() {
 | 
			
		||||
                        this._labelShowing = false;
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _adjustIconSize: function() {
 | 
			
		||||
        let children = this._box.get_children();
 | 
			
		||||
        if (children.length == 0) {
 | 
			
		||||
        // For the icon size, we only consider children which are "proper"
 | 
			
		||||
        // icons (i.e. ignoring drag placeholders) and which are not
 | 
			
		||||
        // animating out (which means they will be destroyed at the end of
 | 
			
		||||
        // the animation)
 | 
			
		||||
        let iconChildren = this._box.get_children().filter(function(actor) {
 | 
			
		||||
            return actor._delegate.child &&
 | 
			
		||||
                   actor._delegate.child._delegate &&
 | 
			
		||||
                   actor._delegate.child._delegate.icon &&
 | 
			
		||||
                   !actor._delegate.animatingOut;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (iconChildren.length == 0) {
 | 
			
		||||
            this._box.add_style_pseudo_class('empty');
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -412,23 +520,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._box.get_theme_node();
 | 
			
		||||
        let maxAllocation = new Clutter.ActorBox({ x1: 0, y1: 0,
 | 
			
		||||
                                                   x2: 42 /* whatever */,
 | 
			
		||||
                                                   y2: this._maxHeight });
 | 
			
		||||
        let maxContent = themeNode.get_content_box(maxAllocation);
 | 
			
		||||
        let availHeight = maxContent.y2 - maxContent.y1;
 | 
			
		||||
        let spacing = themeNode.get_length('spacing');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        let firstIcon = iconChildren[0]._delegate.child._delegate.icon;
 | 
			
		||||
 | 
			
		||||
        let minHeight, natHeight;
 | 
			
		||||
 | 
			
		||||
        // Enforce the current icon size during the size request if
 | 
			
		||||
        // the icon is animating
 | 
			
		||||
        if (firstIcon._animating) {
 | 
			
		||||
            let [currentWidth, currentHeight] = firstIcon.icon.get_size();
 | 
			
		||||
 | 
			
		||||
            firstIcon.icon.set_size(this.iconSize, this.iconSize);
 | 
			
		||||
            [minHeight, natHeight] = iconChildren[0].get_preferred_height(-1);
 | 
			
		||||
 | 
			
		||||
            firstIcon.icon.set_size(currentWidth, currentHeight);
 | 
			
		||||
        } else {
 | 
			
		||||
            [minHeight, natHeight] = iconChildren[0].get_preferred_height(-1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Subtract icon padding and box spacing from the available height
 | 
			
		||||
        availHeight -= iconChildren.length * (natHeight - this.iconSize) +
 | 
			
		||||
                       (iconChildren.length - 1) * spacing;
 | 
			
		||||
 | 
			
		||||
        let availSize = availHeight / iconChildren.length;
 | 
			
		||||
 | 
			
		||||
        let iconSizes = [ 16, 22, 24, 32, 48, 64 ];
 | 
			
		||||
 | 
			
		||||
        let newIconSize = 16;
 | 
			
		||||
        for (let i = 0; i < iconSizes.length; i++) {
 | 
			
		||||
            if (iconSizes[i] < this.iconSize + diff)
 | 
			
		||||
            if (iconSizes[i] < availSize)
 | 
			
		||||
                newIconSize = iconSizes[i];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -459,11 +589,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;
 | 
			
		||||
                               }
 | 
			
		||||
                             });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
@@ -471,10 +605,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 &&
 | 
			
		||||
@@ -566,39 +697,26 @@ Dash.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < addedItems.length; i++)
 | 
			
		||||
            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;
 | 
			
		||||
        }
 | 
			
		||||
            this._box.insert_child_at_index(addedItems[i].item.actor,
 | 
			
		||||
                                            addedItems[i].pos);
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
            if (Main.overview.visible)
 | 
			
		||||
                item.animateOutAndDestroy();
 | 
			
		||||
            else
 | 
			
		||||
                item.actor.destroy();
 | 
			
		||||
                item.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
 | 
			
		||||
@@ -645,20 +763,10 @@ Dash.prototype = {
 | 
			
		||||
            numChildren--;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let pos = Math.round(y * numChildren / boxHeight);
 | 
			
		||||
        let pos = Math.floor(y * numChildren / boxHeight);
 | 
			
		||||
 | 
			
		||||
        if (pos != this._dragPlaceholderPos && pos <= numFavorites) {
 | 
			
		||||
            if (this._animatingPlaceholdersCount > 0) {
 | 
			
		||||
                let appChildren = children.filter(function(actor) {
 | 
			
		||||
                    return actor._delegate &&
 | 
			
		||||
                           actor._delegate.child &&
 | 
			
		||||
                           actor._delegate.child._delegate &&
 | 
			
		||||
                           actor._delegate.child._delegate.app;
 | 
			
		||||
                });
 | 
			
		||||
                this._dragPlaceholderPos = children.indexOf(appChildren[pos]);
 | 
			
		||||
            } else {
 | 
			
		||||
                this._dragPlaceholderPos = pos;
 | 
			
		||||
            }
 | 
			
		||||
        if (pos != this._dragPlaceholderPos && pos <= numFavorites && this._animatingPlaceholdersCount == 0) {
 | 
			
		||||
            this._dragPlaceholderPos = pos;
 | 
			
		||||
 | 
			
		||||
            // Don't allow positioning before or after self
 | 
			
		||||
            if (favPos != -1 && (pos == favPos || pos == favPos + 1)) {
 | 
			
		||||
@@ -687,12 +795,22 @@ Dash.prototype = {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this._dragPlaceholder = new DragPlaceholderItem();
 | 
			
		||||
            this._box.insert_actor(this._dragPlaceholder.actor,
 | 
			
		||||
                                   this._dragPlaceholderPos);
 | 
			
		||||
            this._dragPlaceholder.child.set_width (this.iconSize);
 | 
			
		||||
            this._dragPlaceholder.child.set_height (this.iconSize / 2);
 | 
			
		||||
            this._box.insert_child_at_index(this._dragPlaceholder.actor,
 | 
			
		||||
                                            this._dragPlaceholderPos);
 | 
			
		||||
            if (fadeIn)
 | 
			
		||||
                this._dragPlaceholder.animateIn();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Remove the drag placeholder if we are not in the
 | 
			
		||||
        // "favorites zone"
 | 
			
		||||
        if (pos > numFavorites && this._dragPlaceholder) {
 | 
			
		||||
            this._clearDragPlaceholder();
 | 
			
		||||
        }
 | 
			
		||||
        if (!this._dragPlaceholder)
 | 
			
		||||
            return DND.DragMotionResult.NO_DROP;
 | 
			
		||||
 | 
			
		||||
        let srcIsFavorite = (favPos != -1);
 | 
			
		||||
 | 
			
		||||
        if (srcIsFavorite)
 | 
			
		||||
@@ -735,6 +853,11 @@ Dash.prototype = {
 | 
			
		||||
                favPos++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // No drag placeholder means we don't wan't to favorite the app
 | 
			
		||||
        // and we are dragging it to its original position
 | 
			
		||||
        if (!this._dragPlaceholder)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
 | 
			
		||||
            function () {
 | 
			
		||||
                let appFavorites = AppFavorites.getAppFavorites();
 | 
			
		||||
@@ -747,6 +870,6 @@ Dash.prototype = {
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(Dash.prototype);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,15 @@
 | 
			
		||||
/* -*- 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;
 | 
			
		||||
const GnomeDesktop = imports.gi.GnomeDesktop;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Cairo = imports.cairo;
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Atk = imports.gi.Atk;
 | 
			
		||||
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const Util = imports.misc.util;
 | 
			
		||||
@@ -15,14 +17,6 @@ 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';
 | 
			
		||||
 | 
			
		||||
// in org.gnome.shell.clock
 | 
			
		||||
const CLOCK_SHOW_DATE_KEY     = 'show-date';
 | 
			
		||||
const CLOCK_SHOW_SECONDS_KEY  = 'show-seconds';
 | 
			
		||||
 | 
			
		||||
function _onVertSepRepaint (area)
 | 
			
		||||
{
 | 
			
		||||
@@ -40,27 +34,27 @@ function _onVertSepRepaint (area)
 | 
			
		||||
    cr.stroke();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function DateMenuButton() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DateMenuButton.prototype = {
 | 
			
		||||
    __proto__: PanelMenu.Button.prototype,
 | 
			
		||||
 | 
			
		||||
    _init: function(params) {
 | 
			
		||||
        params = Params.parse(params, { showEvents: true });
 | 
			
		||||
const DateMenuButton = new Lang.Class({
 | 
			
		||||
    Name: 'DateMenuButton',
 | 
			
		||||
    Extends: PanelMenu.Button,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        let item;
 | 
			
		||||
        let hbox;
 | 
			
		||||
        let vbox;
 | 
			
		||||
 | 
			
		||||
        let menuAlignment = 0.25;
 | 
			
		||||
        if (St.Widget.get_default_direction() == St.TextDirection.RTL)
 | 
			
		||||
        if (Clutter.get_default_text_direction() == Clutter.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);
 | 
			
		||||
        // At this moment calendar menu is not keyboard navigable at
 | 
			
		||||
        // all (so not accessible), so it doesn't make sense to set as
 | 
			
		||||
        // role ATK_ROLE_MENU like other elements of the panel.
 | 
			
		||||
        this.actor.accessible_role = Atk.Role.LABEL;
 | 
			
		||||
 | 
			
		||||
        this._clockDisplay = new St.Label();
 | 
			
		||||
        this.actor.add_actor(this._clockDisplay);
 | 
			
		||||
 | 
			
		||||
        hbox = new St.BoxLayout({name: 'calendarArea' });
 | 
			
		||||
        this.menu.addActor(hbox);
 | 
			
		||||
@@ -72,10 +66,11 @@ DateMenuButton.prototype = {
 | 
			
		||||
 | 
			
		||||
        // Date
 | 
			
		||||
        this._date = new St.Label();
 | 
			
		||||
        this.actor.label_actor = this._clockDisplay;
 | 
			
		||||
        this._date.style_class = 'datemenu-date-label';
 | 
			
		||||
        vbox.add(this._date);
 | 
			
		||||
 | 
			
		||||
        if (params.showEvents) {
 | 
			
		||||
        if (Main.sessionMode.showCalendarEvents) {
 | 
			
		||||
            this._eventSource = new Calendar.DBusEventSource();
 | 
			
		||||
            this._eventList = new Calendar.EventsList(this._eventSource);
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -106,7 +101,7 @@ DateMenuButton.prototype = {
 | 
			
		||||
            item.actor.reparent(vbox);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (params.showEvents) {
 | 
			
		||||
        if (Main.sessionMode.showCalendarEvents) {
 | 
			
		||||
            // Add vertical separator
 | 
			
		||||
 | 
			
		||||
            item = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
 | 
			
		||||
@@ -153,77 +148,29 @@ DateMenuButton.prototype = {
 | 
			
		||||
 | 
			
		||||
        // Done with hbox for calendar and event list
 | 
			
		||||
 | 
			
		||||
        // Track changes to clock settings
 | 
			
		||||
        this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
 | 
			
		||||
        this._clockSettings = new Gio.Settings({ schema: 'org.gnome.shell.clock' });
 | 
			
		||||
        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._clock = new GnomeDesktop.WallClock();
 | 
			
		||||
        this._clock.connect('notify::clock', Lang.bind(this, this._updateClockAndDate));
 | 
			
		||||
        this._updateClockAndDate();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateClockAndDate: function() {
 | 
			
		||||
        let format = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);
 | 
			
		||||
        let showDate = this._clockSettings.get_boolean(CLOCK_SHOW_DATE_KEY);
 | 
			
		||||
        let showSeconds = this._clockSettings.get_boolean(CLOCK_SHOW_SECONDS_KEY);
 | 
			
		||||
 | 
			
		||||
        let clockFormat;
 | 
			
		||||
        let dateFormat;
 | 
			
		||||
 | 
			
		||||
        switch (format) {
 | 
			
		||||
            case '24h':
 | 
			
		||||
                if (showDate)
 | 
			
		||||
                    /* 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
 | 
			
		||||
                       in 24-hour mode. */
 | 
			
		||||
                    clockFormat = showSeconds ? _("%a %R:%S")
 | 
			
		||||
                                              : _("%a %R");
 | 
			
		||||
                break;
 | 
			
		||||
            case '12h':
 | 
			
		||||
            default:
 | 
			
		||||
                if (showDate)
 | 
			
		||||
                    /* 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
 | 
			
		||||
                       for AM/PM. */
 | 
			
		||||
                    clockFormat = showSeconds ? _("%a %l:%M:%S %p")
 | 
			
		||||
                                              : _("%a %l:%M %p");
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let displayDate = new Date();
 | 
			
		||||
 | 
			
		||||
        this._clock.set_text(displayDate.toLocaleFormat(clockFormat));
 | 
			
		||||
 | 
			
		||||
        this._clockDisplay.set_text(this._clock.clock);
 | 
			
		||||
        /* Translators: This is the date format to use when the calendar popup is
 | 
			
		||||
         * shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
 | 
			
		||||
         */
 | 
			
		||||
        dateFormat = _("%A %B %e, %Y");
 | 
			
		||||
        let dateFormat = _("%A %B %e, %Y");
 | 
			
		||||
        let displayDate = new Date();
 | 
			
		||||
        this._date.set_text(displayDate.toLocaleFormat(dateFormat));
 | 
			
		||||
 | 
			
		||||
        Mainloop.timeout_add_seconds(1, Lang.bind(this, this._updateClockAndDate));
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onOpenCalendarActivate: function() {
 | 
			
		||||
        this.menu.close();
 | 
			
		||||
        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') {
 | 
			
		||||
        if (tool.length == 0 || tool.substr(0, 9) == 'evolution') {
 | 
			
		||||
            // TODO: pass the selected day
 | 
			
		||||
            Util.spawn(['evolution', '-c', 'calendar']);
 | 
			
		||||
            let app = Shell.AppSystem.get_default().lookup_app('evolution-calendar.desktop');
 | 
			
		||||
            app.activate();
 | 
			
		||||
        } else {
 | 
			
		||||
            let needTerm = calendarSettings.get_boolean('needs-term');
 | 
			
		||||
            if (needTerm) {
 | 
			
		||||
@@ -239,4 +186,4 @@ DateMenuButton.prototype = {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										38
									
								
								js/ui/dnd.js
									
									
									
									
									
								
							
							
						
						@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
@@ -69,11 +69,9 @@ function removeDragMonitor(monitor) {
 | 
			
		||||
        }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _Draggable(actor, params) {
 | 
			
		||||
    this._init(actor, params);
 | 
			
		||||
}
 | 
			
		||||
const _Draggable = new Lang.Class({
 | 
			
		||||
    Name: 'Draggable',
 | 
			
		||||
 | 
			
		||||
_Draggable.prototype = {
 | 
			
		||||
    _init : function(actor, params) {
 | 
			
		||||
        params = Params.parse(params, { manualMode: false,
 | 
			
		||||
                                        restoreOnSuccess: false,
 | 
			
		||||
@@ -105,8 +103,8 @@ _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
 | 
			
		||||
        // During the drag, we eat enter/leave events so that actors don't prelight.
 | 
			
		||||
        // 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;
 | 
			
		||||
@@ -122,13 +120,7 @@ _Draggable.prototype = {
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        this._buttonDown = true;
 | 
			
		||||
        // special case St.Button: grabbing the pointer would mess up the
 | 
			
		||||
        // internal state, so we start the drag manually on hover change
 | 
			
		||||
        if (this.actor instanceof St.Button)
 | 
			
		||||
            this.actor.connect('notify::hover',
 | 
			
		||||
                               Lang.bind(this, this._onButtonHoverChanged));
 | 
			
		||||
        else
 | 
			
		||||
            this._grabActor();
 | 
			
		||||
        this._grabActor();
 | 
			
		||||
 | 
			
		||||
        let [stageX, stageY] = event.get_coords();
 | 
			
		||||
        this._dragStartX = stageX;
 | 
			
		||||
@@ -137,15 +129,6 @@ _Draggable.prototype = {
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onButtonHoverChanged: function(button) {
 | 
			
		||||
        if (button.hover || !button.pressed)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        button.fake_release();
 | 
			
		||||
        this.startDrag(this._dragStartX, this._dragStartY,
 | 
			
		||||
                       global.get_current_time());
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _grabActor: function() {
 | 
			
		||||
        Clutter.grab_pointer(this.actor);
 | 
			
		||||
        this._onEventId = this.actor.connect('event',
 | 
			
		||||
@@ -234,6 +217,13 @@ _Draggable.prototype = {
 | 
			
		||||
        currentDraggable = this;
 | 
			
		||||
        this._dragInProgress = true;
 | 
			
		||||
 | 
			
		||||
        // Special-case St.Button: the pointer grab messes with the internal
 | 
			
		||||
        // state, so force a reset to a reasonable state here
 | 
			
		||||
        if (this.actor instanceof St.Button) {
 | 
			
		||||
            this.actor.fake_release();
 | 
			
		||||
            this.actor.hover = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.emit('drag-begin', time);
 | 
			
		||||
        if (this._onEventId)
 | 
			
		||||
            this._ungrabActor();
 | 
			
		||||
@@ -596,7 +586,7 @@ _Draggable.prototype = {
 | 
			
		||||
        this._dragActor = undefined;
 | 
			
		||||
        currentDraggable = null;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(_Draggable.prototype);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,47 +0,0 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
 | 
			
		||||
const DocInfo = imports.misc.docInfo;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const Search = imports.ui.search;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function DocSearchProvider() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DocSearchProvider.prototype = {
 | 
			
		||||
    __proto__: Search.SearchProvider.prototype,
 | 
			
		||||
 | 
			
		||||
    _init: function(name) {
 | 
			
		||||
        Search.SearchProvider.prototype._init.call(this, _("RECENT ITEMS"));
 | 
			
		||||
        this._docManager = DocInfo.getDocManager();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getResultMeta: function(resultId) {
 | 
			
		||||
        let docInfo = this._docManager.lookupByUri(resultId);
 | 
			
		||||
        if (!docInfo)
 | 
			
		||||
            return null;
 | 
			
		||||
        return { 'id': resultId,
 | 
			
		||||
                 'name': docInfo.name,
 | 
			
		||||
                 'createIcon': function(size) {
 | 
			
		||||
                                   return docInfo.createIcon(size);
 | 
			
		||||
                               }
 | 
			
		||||
               };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activateResult: function(id, params) {
 | 
			
		||||
        params = Params.parse(params, { workspace: -1,
 | 
			
		||||
                                        timestamp: 0 });
 | 
			
		||||
 | 
			
		||||
        let docInfo = this._docManager.lookupByUri(id);
 | 
			
		||||
        docInfo.launch(params.workspace);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getInitialResultSet: function(terms) {
 | 
			
		||||
        return this._docManager.initialSearch(terms);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getSubsearchResultSet: function(previousResults, terms) {
 | 
			
		||||
        return this._docManager.subsearch(previousResults, terms);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 *
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2010 Red Hat, Inc
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
@@ -18,20 +18,19 @@
 | 
			
		||||
 * 02111-1307, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
const DBus = imports.dbus;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const AccountsService = imports.gi.AccountsService;
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
const Pango = imports.gi.Pango;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
 | 
			
		||||
const GnomeSession = imports.misc.gnomeSession
 | 
			
		||||
const Lightbox = imports.ui.lightbox;
 | 
			
		||||
const GnomeSession = imports.misc.gnomeSession;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
@@ -43,51 +42,68 @@ const _DIALOG_ICON_SIZE = 32;
 | 
			
		||||
 | 
			
		||||
const GSM_SESSION_MANAGER_LOGOUT_FORCE = 2;
 | 
			
		||||
 | 
			
		||||
const EndSessionDialogIface = {
 | 
			
		||||
    name: 'org.gnome.SessionManager.EndSessionDialog',
 | 
			
		||||
    methods: [{ name: 'Open',
 | 
			
		||||
                inSignature: 'uuuao',
 | 
			
		||||
                outSignature: ''
 | 
			
		||||
              }
 | 
			
		||||
             ],
 | 
			
		||||
    signals: [{ name: 'Canceled',
 | 
			
		||||
                inSignature: '',
 | 
			
		||||
              }],
 | 
			
		||||
    properties: []
 | 
			
		||||
};
 | 
			
		||||
const EndSessionDialogIface = <interface name="org.gnome.SessionManager.EndSessionDialog">
 | 
			
		||||
<method name="Open">
 | 
			
		||||
    <arg type="u" direction="in" />
 | 
			
		||||
    <arg type="u" direction="in" />
 | 
			
		||||
    <arg type="u" direction="in" />
 | 
			
		||||
    <arg type="ao" direction="in" />
 | 
			
		||||
</method>
 | 
			
		||||
<signal name="ConfirmedLogout" />
 | 
			
		||||
<signal name="ConfirmedReboot" />
 | 
			
		||||
<signal name="ConfirmedShutdown" />
 | 
			
		||||
<signal name="Canceled" />
 | 
			
		||||
<signal name="Closed" />
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const logoutDialogContent = {
 | 
			
		||||
    subjectWithUser: _("Log Out %s"),
 | 
			
		||||
    subject: _("Log Out"),
 | 
			
		||||
    subjectWithUser: C_("title", "Log Out %s"),
 | 
			
		||||
    subject: C_("title", "Log Out"),
 | 
			
		||||
    inhibitedDescription: _("Click Log Out to quit these applications and log out of the system."),
 | 
			
		||||
    uninhibitedDescriptionWithUser: _("%s will be logged out automatically in %d seconds."),
 | 
			
		||||
    uninhibitedDescription: _("You will be logged out automatically in %d seconds."),
 | 
			
		||||
    uninhibitedDescriptionWithUser: function(user, seconds) {
 | 
			
		||||
        return ngettext("%s will be logged out automatically in %d second.",
 | 
			
		||||
                        "%s will be logged out automatically in %d seconds.",
 | 
			
		||||
                        seconds).format(user, seconds);
 | 
			
		||||
    },
 | 
			
		||||
    uninhibitedDescription: function(seconds) {
 | 
			
		||||
        return ngettext("You will be logged out automatically in %d second.",
 | 
			
		||||
                        "You will be logged out automatically in %d seconds.",
 | 
			
		||||
                        seconds).format(seconds);
 | 
			
		||||
    },
 | 
			
		||||
    endDescription: _("Logging out of the system."),
 | 
			
		||||
    confirmButtons: [{ signal: 'ConfirmedLogout',
 | 
			
		||||
                       label:  _("Log Out") }],
 | 
			
		||||
                       label:  C_("button", "Log Out") }],
 | 
			
		||||
    iconStyleClass: 'end-session-dialog-logout-icon'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const shutdownDialogContent = {
 | 
			
		||||
    subject: _("Power Off"),
 | 
			
		||||
    subject: C_("title", "Power Off"),
 | 
			
		||||
    inhibitedDescription: _("Click Power Off to quit these applications and power off the system."),
 | 
			
		||||
    uninhibitedDescription: _("The system will power off automatically in %d seconds."),
 | 
			
		||||
    uninhibitedDescription: function(seconds) {
 | 
			
		||||
        return ngettext("The system will power off automatically in %d second.",
 | 
			
		||||
                        "The system will power off automatically in %d seconds.",
 | 
			
		||||
                        seconds).format(seconds);
 | 
			
		||||
    },
 | 
			
		||||
    endDescription: _("Powering off the system."),
 | 
			
		||||
    confirmButtons: [{ signal: 'ConfirmedReboot',
 | 
			
		||||
                       label:  _("Restart") },
 | 
			
		||||
                       label:  C_("button", "Restart") },
 | 
			
		||||
                     { signal: 'ConfirmedShutdown',
 | 
			
		||||
                       label:  _("Power Off") }],
 | 
			
		||||
                       label:  C_("button", "Power Off") }],
 | 
			
		||||
    iconName: 'system-shutdown',
 | 
			
		||||
    iconStyleClass: 'end-session-dialog-shutdown-icon'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const restartDialogContent = {
 | 
			
		||||
    subject: _("Restart"),
 | 
			
		||||
    subject: C_("title", "Restart"),
 | 
			
		||||
    inhibitedDescription: _("Click Restart to quit these applications and restart the system."),
 | 
			
		||||
    uninhibitedDescription: _("The system will restart automatically in %d seconds."),
 | 
			
		||||
    uninhibitedDescription: function(seconds) {
 | 
			
		||||
        return ngettext("The system will restart automatically in %d second.",
 | 
			
		||||
                        "The system will restart automatically in %d seconds.",
 | 
			
		||||
                        seconds).format(seconds);
 | 
			
		||||
    },
 | 
			
		||||
    endDescription: _("Restarting the system."),
 | 
			
		||||
    confirmButtons: [{ signal: 'ConfirmedReboot',
 | 
			
		||||
                       label:  _("Restart") }],
 | 
			
		||||
                       label:  C_("button", "Restart") }],
 | 
			
		||||
    iconName: 'system-shutdown',
 | 
			
		||||
    iconStyleClass: 'end-session-dialog-shutdown-icon'
 | 
			
		||||
};
 | 
			
		||||
@@ -99,37 +115,17 @@ const DialogContent = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function findAppFromInhibitor(inhibitor) {
 | 
			
		||||
    let desktopFile = inhibitor.app_id;
 | 
			
		||||
    let [desktopFile] = inhibitor.GetAppIdSync();
 | 
			
		||||
 | 
			
		||||
    if (!GLib.str_has_suffix(desktopFile, '.desktop'))
 | 
			
		||||
      desktopFile += '.desktop';
 | 
			
		||||
        desktopFile += '.desktop';
 | 
			
		||||
 | 
			
		||||
    let candidateDesktopFiles = [];
 | 
			
		||||
 | 
			
		||||
    candidateDesktopFiles.push(desktopFile);
 | 
			
		||||
    candidateDesktopFiles.push('gnome-' + desktopFile);
 | 
			
		||||
 | 
			
		||||
    let appSystem = Shell.AppSystem.get_default();
 | 
			
		||||
    let app = null;
 | 
			
		||||
    for (let i = 0; i < candidateDesktopFiles.length; i++) {
 | 
			
		||||
        try {
 | 
			
		||||
            app = appSystem.lookup_app(candidateDesktopFiles[i]);
 | 
			
		||||
 | 
			
		||||
            if (app)
 | 
			
		||||
                break;
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            // ignore errors
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return app;
 | 
			
		||||
    return Shell.AppSystem.get_default().lookup_heuristic_basename(desktopFile);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ListItem(app, reason) {
 | 
			
		||||
    this._init(app, reason);
 | 
			
		||||
}
 | 
			
		||||
const ListItem = new Lang.Class({
 | 
			
		||||
    Name: 'ListItem',
 | 
			
		||||
 | 
			
		||||
ListItem.prototype = {
 | 
			
		||||
    _init: function(app, reason) {
 | 
			
		||||
        this._app = app;
 | 
			
		||||
        this._reason = reason;
 | 
			
		||||
@@ -175,7 +171,7 @@ ListItem.prototype = {
 | 
			
		||||
        this.emit('activate');
 | 
			
		||||
        this._app.activate();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ListItem.prototype);
 | 
			
		||||
 | 
			
		||||
// The logout timer only shows updates every 10 seconds
 | 
			
		||||
@@ -213,29 +209,19 @@ function _setLabelText(label, text) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function EndSessionDialog() {
 | 
			
		||||
    if (_endSessionDialog == null) {
 | 
			
		||||
        this._init();
 | 
			
		||||
        DBus.session.exportObject('/org/gnome/SessionManager/EndSessionDialog',
 | 
			
		||||
                                  this);
 | 
			
		||||
        _endSessionDialog = this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return _endSessionDialog;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function init() {
 | 
			
		||||
    // This always returns the same singleton object
 | 
			
		||||
    // By instantiating it initially, we register the
 | 
			
		||||
    // bus object, etc.
 | 
			
		||||
    let dialog = new EndSessionDialog();
 | 
			
		||||
    _endSessionDialog = new EndSessionDialog();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
EndSessionDialog.prototype = {
 | 
			
		||||
    __proto__: ModalDialog.ModalDialog.prototype,
 | 
			
		||||
const EndSessionDialog = new Lang.Class({
 | 
			
		||||
    Name: 'EndSessionDialog',
 | 
			
		||||
    Extends: ModalDialog.ModalDialog,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'end-session-dialog' });
 | 
			
		||||
        this.parent({ styleClass: 'end-session-dialog' });
 | 
			
		||||
 | 
			
		||||
        this._user = AccountsService.UserManager.get_default().get_user(GLib.get_user_name());
 | 
			
		||||
 | 
			
		||||
@@ -293,23 +279,22 @@ EndSessionDialog.prototype = {
 | 
			
		||||
        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 });
 | 
			
		||||
        scrollView.add_actor(this._applicationList);
 | 
			
		||||
 | 
			
		||||
        this._applicationList.connect('actor-added',
 | 
			
		||||
                                      Lang.bind(this, function() {
 | 
			
		||||
                                          if (this._applicationList.get_children().length == 1)
 | 
			
		||||
                                          if (this._applicationList.get_n_children() == 1)
 | 
			
		||||
                                              scrollView.show();
 | 
			
		||||
                                      }));
 | 
			
		||||
 | 
			
		||||
        this._applicationList.connect('actor-removed',
 | 
			
		||||
                                      Lang.bind(this, function() {
 | 
			
		||||
                                          if (this._applicationList.get_children().length == 0)
 | 
			
		||||
                                          if (this._applicationList.get_n_children() == 0)
 | 
			
		||||
                                              scrollView.hide();
 | 
			
		||||
                                      }));
 | 
			
		||||
 | 
			
		||||
        this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(EndSessionDialogIface, this);
 | 
			
		||||
        this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDestroy: function() {
 | 
			
		||||
@@ -325,7 +310,8 @@ EndSessionDialog.prototype = {
 | 
			
		||||
        this._iconBin.child = null;
 | 
			
		||||
        if (iconFile) {
 | 
			
		||||
            this._iconBin.show();
 | 
			
		||||
            this._iconBin.set_style('background-image: url("' + iconFile + '");');
 | 
			
		||||
            this._iconBin.set_style('background-image: url("' + iconFile + '");' +
 | 
			
		||||
                                    'background-size: contain;');
 | 
			
		||||
        } else {
 | 
			
		||||
            this._iconBin.hide();
 | 
			
		||||
        }
 | 
			
		||||
@@ -351,7 +337,7 @@ EndSessionDialog.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateContent: function() {
 | 
			
		||||
    _updateDescription: function() {
 | 
			
		||||
        if (this.state != ModalDialog.State.OPENING &&
 | 
			
		||||
            this.state != ModalDialog.State.OPENED)
 | 
			
		||||
            return;
 | 
			
		||||
@@ -361,17 +347,6 @@ EndSessionDialog.prototype = {
 | 
			
		||||
        let subject = dialogContent.subject;
 | 
			
		||||
        let description;
 | 
			
		||||
 | 
			
		||||
        if (this._user.is_loaded && !dialogContent.iconName) {
 | 
			
		||||
            let iconFile = this._user.get_icon_file();
 | 
			
		||||
            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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._inhibitors.length > 0) {
 | 
			
		||||
            this._stopTimer();
 | 
			
		||||
            description = dialogContent.inhibitedDescription;
 | 
			
		||||
@@ -388,14 +363,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;
 | 
			
		||||
        }
 | 
			
		||||
@@ -404,6 +379,27 @@ EndSessionDialog.prototype = {
 | 
			
		||||
        _setLabelText(this._descriptionLabel, description);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateContent: function() {
 | 
			
		||||
        if (this.state != ModalDialog.State.OPENING &&
 | 
			
		||||
            this.state != ModalDialog.State.OPENED)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let dialogContent = DialogContent[this._type];
 | 
			
		||||
 | 
			
		||||
        if (this._user.is_loaded && !dialogContent.iconName) {
 | 
			
		||||
            let iconFile = this._user.get_icon_file();
 | 
			
		||||
            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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._updateDescription();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateButtons: function() {
 | 
			
		||||
        let dialogContent = DialogContent[this._type];
 | 
			
		||||
        let buttons = [{ action: Lang.bind(this, this.cancel),
 | 
			
		||||
@@ -423,26 +419,20 @@ EndSessionDialog.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    close: function() {
 | 
			
		||||
        ModalDialog.ModalDialog.prototype.close.call(this);
 | 
			
		||||
        DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
 | 
			
		||||
                                 'org.gnome.SessionManager.EndSessionDialog',
 | 
			
		||||
                                 'Closed', '', []);
 | 
			
		||||
        this.parent();
 | 
			
		||||
        this._dbusImpl.emit_signal('Closed', null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    cancel: function() {
 | 
			
		||||
        this._stopTimer();
 | 
			
		||||
        DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
 | 
			
		||||
                                 'org.gnome.SessionManager.EndSessionDialog',
 | 
			
		||||
                                 'Canceled', '', []);
 | 
			
		||||
        this._dbusImpl.emit_signal('Canceled', null);
 | 
			
		||||
        this.close(global.get_current_time());
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _confirm: function(signal) {
 | 
			
		||||
        this._fadeOutDialog();
 | 
			
		||||
        this._stopTimer();
 | 
			
		||||
        DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
 | 
			
		||||
                                 'org.gnome.SessionManager.EndSessionDialog',
 | 
			
		||||
                                 signal, '', []);
 | 
			
		||||
        this._dbusImpl.emit_signal(signal, null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onOpened: function() {
 | 
			
		||||
@@ -456,7 +446,7 @@ EndSessionDialog.prototype = {
 | 
			
		||||
                         { _secondsLeft: 0,
 | 
			
		||||
                           time: this._secondsLeft,
 | 
			
		||||
                           transition: 'linear',
 | 
			
		||||
                           onUpdate: Lang.bind(this, this._updateContent),
 | 
			
		||||
                           onUpdate: Lang.bind(this, this._updateDescription),
 | 
			
		||||
                           onComplete: Lang.bind(this, function() {
 | 
			
		||||
                                           let dialogContent = DialogContent[this._type];
 | 
			
		||||
                                           let button = dialogContent.confirmButtons[dialogContent.confirmButtons.length - 1];
 | 
			
		||||
@@ -479,7 +469,8 @@ EndSessionDialog.prototype = {
 | 
			
		||||
        let app = findAppFromInhibitor(inhibitor);
 | 
			
		||||
 | 
			
		||||
        if (app) {
 | 
			
		||||
            let item = new ListItem(app, inhibitor.reason);
 | 
			
		||||
            let [reason] = inhibitor.GetReasonSync();
 | 
			
		||||
            let item = new ListItem(app, reason);
 | 
			
		||||
            item.connect('activate',
 | 
			
		||||
                         Lang.bind(this, function() {
 | 
			
		||||
                             this.close(global.get_current_time());
 | 
			
		||||
@@ -494,39 +485,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._applicationList.destroy_all_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.return_dbus_error('org.gnome.Shell.ModalDialog.TypeError',
 | 
			
		||||
                                         "Unknown dialog type requested");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < inhibitorObjectPaths.length; i++) {
 | 
			
		||||
            let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i]);
 | 
			
		||||
            let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i], Lang.bind(this, function(proxy, error) {
 | 
			
		||||
                this._onInhibitorLoaded(proxy);
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            inhibitor.connect('is-loaded',
 | 
			
		||||
                              Lang.bind(this, function() {
 | 
			
		||||
                                  this._onInhibitorLoaded(inhibitor);
 | 
			
		||||
                              }));
 | 
			
		||||
            this._inhibitors.push(inhibitor);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._updateButtons();
 | 
			
		||||
 | 
			
		||||
        if (!this.open(timestamp))
 | 
			
		||||
            throw new DBus.DBusError('org.gnome.Shell.ModalDialog.GrabError',
 | 
			
		||||
                                     "Cannot grab pointer and keyboard");
 | 
			
		||||
        if (!this.open(timestamp)) {
 | 
			
		||||
            invocation.return_dbus_error('org.gnome.Shell.ModalDialog.GrabError',
 | 
			
		||||
                                         "Cannot grab pointer and keyboard");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._updateContent();
 | 
			
		||||
 | 
			
		||||
        let signalId = this.connect('opened',
 | 
			
		||||
                                    Lang.bind(this, function() {
 | 
			
		||||
                                        callback();
 | 
			
		||||
                                        invocation.return_value(null);
 | 
			
		||||
                                        this.disconnect(signalId);
 | 
			
		||||
                                    }));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
DBus.conformExport(EndSessionDialog.prototype, EndSessionDialogIface);
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
imports.gi.versions.Clutter = '1.0';
 | 
			
		||||
imports.gi.versions.Gio = '2.0';
 | 
			
		||||
@@ -39,20 +39,23 @@ function _patchContainerClass(containerClass) {
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _makeLoggingFunc(func) {
 | 
			
		||||
    return function() {
 | 
			
		||||
        return func([].join.call(arguments, ', '));
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function init() {
 | 
			
		||||
    // 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.log = _makeLoggingFunc(window.log);
 | 
			
		||||
 | 
			
		||||
    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 (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL) {
 | 
			
		||||
        St.Widget.set_default_direction(St.TextDirection.RTL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Miscellaneous monkeypatching
 | 
			
		||||
    _patchContainerClass(St.BoxLayout);
 | 
			
		||||
    _patchContainerClass(St.Table);
 | 
			
		||||
@@ -64,10 +67,14 @@ function init() {
 | 
			
		||||
    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
 | 
			
		||||
        try {
 | 
			
		||||
            if ('actor' in this && this.actor instanceof Clutter.Actor)
 | 
			
		||||
                return base.replace(/\]$/, ' delegate for ' + this.actor.toString().substring(1));
 | 
			
		||||
            else
 | 
			
		||||
                return base;
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            return base;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=508783
 | 
			
		||||
@@ -83,7 +90,7 @@ function init() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // OK, now things are initialized enough that we can import shell JS
 | 
			
		||||
    const Format = imports.misc.format;
 | 
			
		||||
    const Format = imports.format;
 | 
			
		||||
    const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
    Tweener.init();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										270
									
								
								js/ui/extensionDownloader.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,270 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Soup = imports.gi.Soup;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
 | 
			
		||||
const Config = imports.misc.config;
 | 
			
		||||
const ExtensionUtils = imports.misc.extensionUtils;
 | 
			
		||||
const ExtensionSystem = imports.ui.extensionSystem;
 | 
			
		||||
const FileUtils = imports.misc.fileUtils;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
 | 
			
		||||
const _signals = ExtensionSystem._signals;
 | 
			
		||||
 | 
			
		||||
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 REPOSITORY_URL_UPDATE   = REPOSITORY_URL_BASE + '/update-info/';
 | 
			
		||||
 | 
			
		||||
let _httpSession;
 | 
			
		||||
 | 
			
		||||
function installExtension(uuid, invocation) {
 | 
			
		||||
    let params = { uuid: uuid,
 | 
			
		||||
                   shell_version: Config.PACKAGE_VERSION };
 | 
			
		||||
 | 
			
		||||
    let message = Soup.form_request_new_from_hash('GET', REPOSITORY_URL_INFO, params);
 | 
			
		||||
 | 
			
		||||
    _httpSession.queue_message(message, function(session, message) {
 | 
			
		||||
        if (message.status_code != Soup.KnownStatusCode.OK) {
 | 
			
		||||
            ExtensionSystem.logExtensionError(uuid, 'downloading info: ' + message.status_code);
 | 
			
		||||
            invocation.return_dbus_error('org.gnome.Shell.DownloadInfoError', message.status_code.toString());
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let info;
 | 
			
		||||
        try {
 | 
			
		||||
            info = JSON.parse(message.response_body.data);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            ExtensionSystem.logExtensionError(uuid, 'parsing info: ' + e);
 | 
			
		||||
            invocation.return_dbus_error('org.gnome.Shell.ParseInfoError', e.toString());
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let dialog = new InstallExtensionDialog(uuid, info, invocation);
 | 
			
		||||
        dialog.open(global.get_current_time());
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function uninstallExtension(uuid) {
 | 
			
		||||
    let extension = ExtensionUtils.extensions[uuid];
 | 
			
		||||
    if (!extension)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    // Don't try to uninstall system extensions
 | 
			
		||||
    if (extension.type != ExtensionUtils.ExtensionType.PER_USER)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    if (!ExtensionSystem.unloadExtension(uuid))
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    FileUtils.recursivelyDeleteDir(extension.dir, true);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function gotExtensionZipFile(session, message, uuid, dir, callback, errback) {
 | 
			
		||||
    if (message.status_code != Soup.KnownStatusCode.OK) {
 | 
			
		||||
        errback('DownloadExtensionError', message.status_code);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        if (!dir.query_exists(null))
 | 
			
		||||
            dir.make_directory_with_parents(null);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        errback('CreateExtensionDirectoryError', e);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let [file, stream] = Gio.File.new_tmp('XXXXXX.shell-extension.zip');
 | 
			
		||||
    let contents = message.response_body.flatten().as_bytes();
 | 
			
		||||
    stream.output_stream.write_bytes(contents, null);
 | 
			
		||||
    stream.close(null);
 | 
			
		||||
    let [success, pid] = GLib.spawn_async(null,
 | 
			
		||||
                                          ['unzip', '-uod', dir.get_path(), '--', file.get_path()],
 | 
			
		||||
                                          null,
 | 
			
		||||
                                          GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
 | 
			
		||||
                                          null);
 | 
			
		||||
 | 
			
		||||
    if (!success) {
 | 
			
		||||
        errback('ExtractExtensionError');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function(pid, status) {
 | 
			
		||||
        GLib.spawn_close_pid(pid);
 | 
			
		||||
 | 
			
		||||
        if (status != 0)
 | 
			
		||||
            errback('ExtractExtensionError');
 | 
			
		||||
        else
 | 
			
		||||
            callback();
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function updateExtension(uuid) {
 | 
			
		||||
    // This gets a bit tricky. We want the update to be seamless -
 | 
			
		||||
    // if we have any error during downloading or extracting, we
 | 
			
		||||
    // want to not unload the current version.
 | 
			
		||||
 | 
			
		||||
    let oldExtensionTmpDir = GLib.Dir.make_tmp('XXXXXX-shell-extension');
 | 
			
		||||
    let newExtensionTmpDir = GLib.Dir.make_tmp('XXXXXX-shell-extension');
 | 
			
		||||
 | 
			
		||||
    let params = { shell_version: Config.PACKAGE_VERSION };
 | 
			
		||||
 | 
			
		||||
    let url = REPOSITORY_URL_DOWNLOAD.format(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, uuid, newExtensionTmpDir, function() {
 | 
			
		||||
            let oldExtension = ExtensionUtils.extensions[uuid];
 | 
			
		||||
            let extensionDir = oldExtension.dir;
 | 
			
		||||
 | 
			
		||||
            if (!ExtensionSystem.unloadExtension(uuid))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            FileUtils.recursivelyMoveDir(extensionDir, oldExtensionTmpDir);
 | 
			
		||||
            FileUtils.recursivelyMoveDir(newExtensionTmpDir, extensionDir);
 | 
			
		||||
 | 
			
		||||
            let extension = ExtensionUtils.createExtensionObject(uuid, extensionDir, ExtensionUtils.ExtensionType.PER_USER);
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                ExtensionSystem.loadExtension(extension);
 | 
			
		||||
            } catch(e) {
 | 
			
		||||
                ExtensionSystem.unloadExtension(uuid);
 | 
			
		||||
 | 
			
		||||
                logError(e, 'Error loading extension %s'.format(uuid));
 | 
			
		||||
 | 
			
		||||
                FileUtils.recursivelyDeleteDir(extensionDir, false);
 | 
			
		||||
                FileUtils.recursivelyMoveDir(oldExtensionTmpDir, extensionDir);
 | 
			
		||||
 | 
			
		||||
                // Restore what was there before. We can't do much if we
 | 
			
		||||
                // fail here.
 | 
			
		||||
                ExtensionSystem.loadExtension(oldExtension);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            FileUtils.recursivelyDeleteDir(oldExtensionTmpDir, true);
 | 
			
		||||
        }, function(code, message) {
 | 
			
		||||
            log('Error while updating extension %s: %s (%s)'.format(uuid, code, message ? message : ''));
 | 
			
		||||
        });
 | 
			
		||||
    }));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function checkForUpdates() {
 | 
			
		||||
    let metadatas = {};
 | 
			
		||||
    for (let uuid in ExtensionUtils.extensions) {
 | 
			
		||||
        metadatas[uuid] = ExtensionUtils.extensions[uuid].metadata;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let params = { shell_version: Config.PACKAGE_VERSION,
 | 
			
		||||
                   installed: JSON.stringify(metadatas) };
 | 
			
		||||
 | 
			
		||||
    let url = REPOSITORY_URL_UPDATE;
 | 
			
		||||
    let message = Soup.form_request_new_from_hash('GET', url, params);
 | 
			
		||||
    _httpSession.queue_message(message, function(session, message) {
 | 
			
		||||
        if (message.status_code != Soup.KnownStatusCode.OK)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let operations = JSON.parse(message.response_body.data);
 | 
			
		||||
        for (let uuid in operations) {
 | 
			
		||||
            let operation = operations[uuid];
 | 
			
		||||
            if (operation == 'blacklist')
 | 
			
		||||
                uninstallExtension(uuid);
 | 
			
		||||
            else if (operation == 'upgrade' || operation == 'downgrade')
 | 
			
		||||
                updateExtension(uuid);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const InstallExtensionDialog = new Lang.Class({
 | 
			
		||||
    Name: 'InstallExtensionDialog',
 | 
			
		||||
    Extends: ModalDialog.ModalDialog,
 | 
			
		||||
 | 
			
		||||
    _init: function(uuid, info, invocation) {
 | 
			
		||||
        this.parent({ styleClass: 'extension-dialog' });
 | 
			
		||||
 | 
			
		||||
        this._uuid = uuid;
 | 
			
		||||
        this._info = info;
 | 
			
		||||
        this._invocation = invocation;
 | 
			
		||||
 | 
			
		||||
        this.setButtons([{ label: _("Cancel"),
 | 
			
		||||
                           action: Lang.bind(this, this._onCancelButtonPressed),
 | 
			
		||||
                           key:    Clutter.Escape
 | 
			
		||||
                         },
 | 
			
		||||
                         { label:  _("Install"),
 | 
			
		||||
                           action: Lang.bind(this, this._onInstallButtonPressed),
 | 
			
		||||
                           default: true
 | 
			
		||||
                         }]);
 | 
			
		||||
 | 
			
		||||
        let message = _("Download and install '%s' from extensions.gnome.org?").format(info.name);
 | 
			
		||||
 | 
			
		||||
        let box = new St.BoxLayout();
 | 
			
		||||
        this.contentLayout.add(box);
 | 
			
		||||
 | 
			
		||||
        let gicon = new Gio.FileIcon({ file: Gio.File.new_for_uri(REPOSITORY_URL_BASE + info.icon) })
 | 
			
		||||
        let icon = new St.Icon({ gicon: gicon });
 | 
			
		||||
        box.add(icon);
 | 
			
		||||
 | 
			
		||||
        let label = new St.Label({ text: message });
 | 
			
		||||
        box.add(label);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onCancelButtonPressed: function(button, event) {
 | 
			
		||||
        this.close(global.get_current_time());
 | 
			
		||||
        this._invocation.return_value(GLib.Variant.new('(s)', ['cancelled']));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onInstallButtonPressed: function(button, event) {
 | 
			
		||||
        let params = { shell_version: Config.PACKAGE_VERSION };
 | 
			
		||||
 | 
			
		||||
        let url = REPOSITORY_URL_DOWNLOAD.format(this._uuid);
 | 
			
		||||
        let message = Soup.form_request_new_from_hash('GET', url, params);
 | 
			
		||||
 | 
			
		||||
        let uuid = this._uuid;
 | 
			
		||||
        let dir = Gio.File.new_for_path(GLib.build_filenamev([global.userdatadir, 'extensions', uuid]));
 | 
			
		||||
        let invocation = this._invocation;
 | 
			
		||||
        function errback(code, message) {
 | 
			
		||||
            invocation.return_dbus_error('org.gnome.Shell.' + code, message ? message.toString() : '');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function callback() {
 | 
			
		||||
            // Add extension to 'enabled-extensions' for the user, always...
 | 
			
		||||
            let enabledExtensions = global.settings.get_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY);
 | 
			
		||||
            if (enabledExtensions.indexOf(uuid) == -1) {
 | 
			
		||||
                enabledExtensions.push(uuid);
 | 
			
		||||
                global.settings.set_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY, enabledExtensions);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let extension = ExtensionUtils.createExtensionObject(uuid, dir, ExtensionUtils.ExtensionType.PER_USER);
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                ExtensionSystem.loadExtension(extension);
 | 
			
		||||
            } catch(e) {
 | 
			
		||||
                uninstallExtension(uuid);
 | 
			
		||||
                errback('LoadExtensionError', e);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            invocation.return_value(GLib.Variant.new('(s)', 'successful'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        _httpSession.queue_message(message, Lang.bind(this, function(session, message) {
 | 
			
		||||
            gotExtensionZipFile(session, message, uuid, dir, callback, errback);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        this.close(global.get_current_time());
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function init() {
 | 
			
		||||
    _httpSession = new Soup.SessionAsync({ ssl_use_system_ca_file: true });
 | 
			
		||||
 | 
			
		||||
    // See: https://bugzilla.gnome.org/show_bug.cgi?id=655189 for context.
 | 
			
		||||
    // _httpSession.add_feature(new Soup.ProxyResolverDefault());
 | 
			
		||||
    Soup.Session.prototype.add_feature.call(_httpSession, new Soup.ProxyResolverDefault());
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
@@ -6,10 +6,8 @@ const Signals = imports.signals;
 | 
			
		||||
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 ExtensionUtils = imports.misc.extensionUtils;
 | 
			
		||||
 | 
			
		||||
const ExtensionState = {
 | 
			
		||||
    ENABLED: 1,
 | 
			
		||||
@@ -17,36 +15,17 @@ const ExtensionState = {
 | 
			
		||||
    ERROR: 3,
 | 
			
		||||
    OUT_OF_DATE: 4,
 | 
			
		||||
    DOWNLOADING: 5,
 | 
			
		||||
    INITIALIZED: 6,
 | 
			
		||||
 | 
			
		||||
    // Used as an error state for operations on unknown extensions,
 | 
			
		||||
    // should never be in a real extensionMeta object.
 | 
			
		||||
    UNINSTALLED: 99
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const ExtensionType = {
 | 
			
		||||
    SYSTEM: 1,
 | 
			
		||||
    PER_USER: 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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());
 | 
			
		||||
 | 
			
		||||
// Maps uuid -> metadata object
 | 
			
		||||
const extensionMeta = {};
 | 
			
		||||
// Maps uuid -> importer object (extension directory tree)
 | 
			
		||||
const extensions = {};
 | 
			
		||||
// Maps uuid -> extension state object (returned from init())
 | 
			
		||||
const extensionStateObjs = {};
 | 
			
		||||
// Arrays of uuids
 | 
			
		||||
var enabledExtensions;
 | 
			
		||||
// GFile for user extensions
 | 
			
		||||
var userExtensionsDir = null;
 | 
			
		||||
// Contains the order that extensions were enabled in.
 | 
			
		||||
const extensionOrder = [];
 | 
			
		||||
 | 
			
		||||
// We don't really have a class to add signals on. So, create
 | 
			
		||||
// a simple dummy object, add the signal methods, and export those
 | 
			
		||||
@@ -57,313 +36,172 @@ 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
 | 
			
		||||
 * @current: the version we have
 | 
			
		||||
 *
 | 
			
		||||
 * Check if a component is compatible for an extension.
 | 
			
		||||
 * @required is an array, and at least one version must match.
 | 
			
		||||
 * @current must be in the format <major>.<minor>.<point>.<micro>
 | 
			
		||||
 * <micro> is always ignored
 | 
			
		||||
 * <point> is ignored if <minor> is even (so you can target the
 | 
			
		||||
 * whole stable release)
 | 
			
		||||
 * <minor> and <major> must match
 | 
			
		||||
 * Each target version must be at least <major> and <minor>
 | 
			
		||||
 */
 | 
			
		||||
function versionCheck(required, current) {
 | 
			
		||||
    let currentArray = current.split('.');
 | 
			
		||||
    let major = currentArray[0];
 | 
			
		||||
    let minor = currentArray[1];
 | 
			
		||||
    let point = currentArray[2];
 | 
			
		||||
    for (let i = 0; i < required.length; i++) {
 | 
			
		||||
        let requiredArray = required[i].split('.');
 | 
			
		||||
        if (requiredArray[0] == major &&
 | 
			
		||||
            requiredArray[1] == minor &&
 | 
			
		||||
            (requiredArray[2] == point ||
 | 
			
		||||
             (requiredArray[2] == undefined && parseInt(minor) % 2 == 0)))
 | 
			
		||||
            return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function installExtensionFromManifestURL(uuid, url) {
 | 
			
		||||
    _httpSession.queue_message(
 | 
			
		||||
        Soup.Message.new('GET', url),
 | 
			
		||||
        function(session, message) {
 | 
			
		||||
            if (message.status_code != Soup.KnownStatusCode.OK) {
 | 
			
		||||
                logExtensionError(uuid, 'downloading manifest: ' + message.status_code.toString());
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let manifest;
 | 
			
		||||
            try {
 | 
			
		||||
                manifest = JSON.parse(message.response_body.data);
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                logExtensionError(uuid, 'parsing: ' + e.toString());
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (uuid != manifest['uuid']) {
 | 
			
		||||
                logExtensionError(uuid, 'manifest: manifest uuids do not match');
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let meta = extensionMeta[uuid] = { uuid: uuid,
 | 
			
		||||
                                               state: ExtensionState.DOWNLOADING,
 | 
			
		||||
                                               error: '' };
 | 
			
		||||
 | 
			
		||||
            _signals.emit('extension-state-changed', meta);
 | 
			
		||||
 | 
			
		||||
            installExtensionFromManifest(manifest, meta);
 | 
			
		||||
        });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function installExtensionFromManifest(manifest, meta) {
 | 
			
		||||
    let uuid = manifest['uuid'];
 | 
			
		||||
    let name = manifest['name'];
 | 
			
		||||
 | 
			
		||||
    if (!versionCheck(manifest['shell-version'], Config.PACKAGE_VERSION)) {
 | 
			
		||||
        meta.state = ExtensionState.OUT_OF_DATE;
 | 
			
		||||
        logExtensionError(uuid, 'version: ' + name + ' is not compatible with current GNOME Shell version', meta.state);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let url = manifest['__installer'];
 | 
			
		||||
    _httpSession.queue_message(Soup.Message.new('GET', url),
 | 
			
		||||
                               function(session, message) {
 | 
			
		||||
                                   gotExtensionZipFile(session, message, uuid);
 | 
			
		||||
                               });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function gotExtensionZipFile(session, message, uuid) {
 | 
			
		||||
    if (message.status_code != Soup.KnownStatusCode.OK) {
 | 
			
		||||
        logExtensionError(uuid, 'downloading extension: ' + message.status_code);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 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);
 | 
			
		||||
        loadExtension(dir, true, ExtensionType.PER_USER);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function disableExtension(uuid) {
 | 
			
		||||
    let meta = extensionMeta[uuid];
 | 
			
		||||
    if (!meta)
 | 
			
		||||
    let extension = ExtensionUtils.extensions[uuid];
 | 
			
		||||
    if (!extension)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (meta.state != ExtensionState.ENABLED)
 | 
			
		||||
    if (extension.state != ExtensionState.ENABLED)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    let extensionState = extensionStateObjs[uuid];
 | 
			
		||||
    // "Rebase" the extension order by disabling and then enabling extensions
 | 
			
		||||
    // in order to help prevent conflicts.
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        extensionState.disable();
 | 
			
		||||
    } catch(e) {
 | 
			
		||||
        logExtensionError(uuid, e.toString());
 | 
			
		||||
        return;
 | 
			
		||||
    // 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 {
 | 
			
		||||
            ExtensionUtils.extensions[uuid].stateObj.disable();
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            logExtensionError(uuid, e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    meta.state = ExtensionState.DISABLED;
 | 
			
		||||
    _signals.emit('extension-state-changed', meta);
 | 
			
		||||
    if (extension.stylesheet) {
 | 
			
		||||
        let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
 | 
			
		||||
        theme.unload_stylesheet(extension.stylesheet.get_path());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    extension.stateObj.disable();
 | 
			
		||||
 | 
			
		||||
    for (let i = 0; i < order.length; i++) {
 | 
			
		||||
        let uuid = order[i];
 | 
			
		||||
        try {
 | 
			
		||||
            ExtensionUtils.extensions[uuid].stateObj.enable();
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            logExtensionError(uuid, e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    extensionOrder.splice(orderIdx, 1);
 | 
			
		||||
 | 
			
		||||
    extension.state = ExtensionState.DISABLED;
 | 
			
		||||
    _signals.emit('extension-state-changed', extension);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function enableExtension(uuid) {
 | 
			
		||||
    let meta = extensionMeta[uuid];
 | 
			
		||||
    if (!meta)
 | 
			
		||||
    let extension = ExtensionUtils.extensions[uuid];
 | 
			
		||||
    if (!extension)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (meta.state != ExtensionState.DISABLED)
 | 
			
		||||
    if (extension.state == ExtensionState.INITIALIZED)
 | 
			
		||||
        initExtension(uuid);
 | 
			
		||||
 | 
			
		||||
    if (extension.state != ExtensionState.DISABLED)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    let extensionState = extensionStateObjs[uuid];
 | 
			
		||||
    extensionOrder.push(uuid);
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        extensionState.enable();
 | 
			
		||||
    } catch(e) {
 | 
			
		||||
        logExtensionError(uuid, e.toString());
 | 
			
		||||
        return;
 | 
			
		||||
    extension.stateObj.enable();
 | 
			
		||||
 | 
			
		||||
    let stylesheetFile = extension.dir.get_child('stylesheet.css');
 | 
			
		||||
    if (stylesheetFile.query_exists(null)) {
 | 
			
		||||
        let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
 | 
			
		||||
        theme.load_stylesheet(stylesheetFile.get_path());
 | 
			
		||||
        extension.stylesheet = stylesheetFile;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    meta.state = ExtensionState.ENABLED;
 | 
			
		||||
    _signals.emit('extension-state-changed', meta);
 | 
			
		||||
    extension.state = ExtensionState.ENABLED;
 | 
			
		||||
    _signals.emit('extension-state-changed', extension);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
function logExtensionError(uuid, error) {
 | 
			
		||||
    let extension = ExtensionUtils.extensions[uuid];
 | 
			
		||||
    if (!extension)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    let message = '' + error;
 | 
			
		||||
 | 
			
		||||
    if (error.state)
 | 
			
		||||
        extension.state = error.state;
 | 
			
		||||
    else
 | 
			
		||||
        extension.state = ExtensionState.ERROR;
 | 
			
		||||
 | 
			
		||||
    if (!extension.errors)
 | 
			
		||||
        extension.errors = [];
 | 
			
		||||
 | 
			
		||||
    log('Extension "%s" had error: %s'.format(uuid, message));
 | 
			
		||||
    _signals.emit('extension-state-changed', { uuid: uuid,
 | 
			
		||||
                                               error: message,
 | 
			
		||||
                                               state: state });
 | 
			
		||||
                                               state: extension.state });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function loadExtension(dir, enabled, type) {
 | 
			
		||||
    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) {
 | 
			
		||||
        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]) {
 | 
			
		||||
            logExtensionError(uuid, 'missing "' + prop + '" property in metadata.json');
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (extensions[uuid] != undefined) {
 | 
			
		||||
        logExtensionError(uuid, "extension already loaded");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Encourage people to add this
 | 
			
		||||
    if (!meta['url']) {
 | 
			
		||||
        global.log('Warning: Missing "url" property in metadata.json');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (uuid != meta.uuid) {
 | 
			
		||||
        logExtensionError(uuid, 'uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!versionCheck(meta['shell-version'], Config.PACKAGE_VERSION) ||
 | 
			
		||||
        (meta['js-version'] && !versionCheck(meta['js-version'], Config.GJS_VERSION))) {
 | 
			
		||||
        logExtensionError(uuid, 'extension is not compatible with current GNOME Shell and/or GJS version');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    extensionMeta[uuid] = meta;
 | 
			
		||||
    meta.type = type;
 | 
			
		||||
    meta.path = dir.get_path();
 | 
			
		||||
    meta.error = '';
 | 
			
		||||
 | 
			
		||||
function loadExtension(extension) {
 | 
			
		||||
    // Default to error, we set success as the last step
 | 
			
		||||
    meta.state = ExtensionState.ERROR;
 | 
			
		||||
    extension.state = ExtensionState.ERROR;
 | 
			
		||||
 | 
			
		||||
    if (!versionCheck(meta['shell-version'], Config.PACKAGE_VERSION) ||
 | 
			
		||||
        (meta['js-version'] && !versionCheck(meta['js-version'], Config.GJS_VERSION))) {
 | 
			
		||||
        logExtensionError(uuid, 'extension is not compatible with current GNOME Shell and/or GJS version', ExtensionState.OUT_OF_DATE);
 | 
			
		||||
        meta.state = ExtensionState.OUT_OF_DATE;
 | 
			
		||||
        return;
 | 
			
		||||
    if (ExtensionUtils.isOutOfDate(extension)) {
 | 
			
		||||
        let error = new Error('extension is not compatible with current GNOME Shell and/or GJS version');
 | 
			
		||||
        error.state = ExtensionState.OUT_OF_DATE;
 | 
			
		||||
        throw error;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let enabled = enabledExtensions.indexOf(extension.uuid) != -1;
 | 
			
		||||
    if (enabled) {
 | 
			
		||||
        initExtension(extension.uuid);
 | 
			
		||||
        if (extension.state == ExtensionState.DISABLED)
 | 
			
		||||
            enableExtension(extension.uuid);
 | 
			
		||||
    } else {
 | 
			
		||||
        extension.state = ExtensionState.INITIALIZED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _signals.emit('extension-state-changed', extension);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function unloadExtension(uuid) {
 | 
			
		||||
    let extension = ExtensionUtils.extensions[uuid];
 | 
			
		||||
    if (!extension)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    // Try to disable it -- if it's ERROR'd, we can't guarantee that,
 | 
			
		||||
    // but it will be removed on next reboot, and hopefully nothing
 | 
			
		||||
    // broke too much.
 | 
			
		||||
    disableExtension(uuid);
 | 
			
		||||
 | 
			
		||||
    extension.state = ExtensionState.UNINSTALLED;
 | 
			
		||||
    _signals.emit('extension-state-changed', extension);
 | 
			
		||||
 | 
			
		||||
    delete ExtensionUtils.extensions[uuid];
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function initExtension(uuid) {
 | 
			
		||||
    let extension = ExtensionUtils.extensions[uuid];
 | 
			
		||||
    let dir = extension.dir;
 | 
			
		||||
 | 
			
		||||
    if (!extension)
 | 
			
		||||
        throw new Error("Extension was not properly created. Call loadExtension first");
 | 
			
		||||
 | 
			
		||||
    let extensionJs = dir.get_child('extension.js');
 | 
			
		||||
    if (!extensionJs.query_exists(null)) {
 | 
			
		||||
        logExtensionError(uuid, 'Missing extension.js');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    let stylesheetPath = null;
 | 
			
		||||
    let themeContext = St.ThemeContext.get_for_stage(global.stage);
 | 
			
		||||
    let theme = themeContext.get_theme();
 | 
			
		||||
    let stylesheetFile = dir.get_child('stylesheet.css');
 | 
			
		||||
    if (stylesheetFile.query_exists(null)) {
 | 
			
		||||
        try {
 | 
			
		||||
            theme.load_stylesheet(stylesheetFile.get_path());
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            logExtensionError(uuid, 'Stylesheet parse error: ' + e);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (!extensionJs.query_exists(null))
 | 
			
		||||
        throw new Error('Missing extension.js');
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
        logExtensionError(uuid, e);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!extensionModule.init) {
 | 
			
		||||
        logExtensionError(uuid, 'missing \'init\' function');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    ExtensionUtils.installImporter(extension);
 | 
			
		||||
    extensionModule = extension.imports.extension;
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        extensionState = extensionModule.init(meta);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        if (stylesheetPath != null)
 | 
			
		||||
            theme.unload_stylesheet(stylesheetPath);
 | 
			
		||||
        logExtensionError(uuid, 'Failed to evaluate init function:' + e);
 | 
			
		||||
        return;
 | 
			
		||||
    if (extensionModule.init) {
 | 
			
		||||
        extensionState = extensionModule.init(extension);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!extensionState)
 | 
			
		||||
        extensionState = extensionModule;
 | 
			
		||||
    extensionStateObjs[uuid] = extensionState;
 | 
			
		||||
    extension.stateObj = extensionState;
 | 
			
		||||
 | 
			
		||||
    if (!extensionState.enable) {
 | 
			
		||||
        logExtensionError(uuid, 'missing \'enable\' function');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (!extensionState.disable) {
 | 
			
		||||
        logExtensionError(uuid, 'missing \'disable\' function');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    meta.state = ExtensionState.DISABLED;
 | 
			
		||||
 | 
			
		||||
    if (enabled)
 | 
			
		||||
        enableExtension(uuid);
 | 
			
		||||
 | 
			
		||||
    _signals.emit('extension-loaded', meta.uuid);
 | 
			
		||||
    _signals.emit('extension-state-changed', meta);
 | 
			
		||||
    global.log('Loaded extension ' + meta.uuid);
 | 
			
		||||
    extension.state = ExtensionState.DISABLED;
 | 
			
		||||
    _signals.emit('extension-loaded', uuid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function onEnabledExtensionsChanged() {
 | 
			
		||||
@@ -374,7 +212,11 @@ function onEnabledExtensionsChanged() {
 | 
			
		||||
    newEnabledExtensions.filter(function(uuid) {
 | 
			
		||||
        return enabledExtensions.indexOf(uuid) == -1;
 | 
			
		||||
    }).forEach(function(uuid) {
 | 
			
		||||
        enableExtension(uuid);
 | 
			
		||||
        try {
 | 
			
		||||
            enableExtension(uuid);
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            logExtensionError(uuid, e);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Find and disable all the newly disabled extensions: UUIDs found in the
 | 
			
		||||
@@ -382,55 +224,27 @@ function onEnabledExtensionsChanged() {
 | 
			
		||||
    enabledExtensions.filter(function(item) {
 | 
			
		||||
        return newEnabledExtensions.indexOf(item) == -1;
 | 
			
		||||
    }).forEach(function(uuid) {
 | 
			
		||||
        disableExtension(uuid);
 | 
			
		||||
        try {
 | 
			
		||||
            disableExtension(uuid);
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            logExtensionError(uuid, e);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    enabledExtensions = newEnabledExtensions;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function init() {
 | 
			
		||||
    let userExtensionsPath = GLib.build_filenamev([global.userdatadir, 'extensions']);
 | 
			
		||||
    userExtensionsDir = Gio.file_new_for_path(userExtensionsPath);
 | 
			
		||||
    try {
 | 
			
		||||
        if (!userExtensionsDir.query_exists(null))
 | 
			
		||||
            userExtensionsDir.make_directory_with_parents(null);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        global.logError('' + e);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
function loadExtensions() {
 | 
			
		||||
    global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
 | 
			
		||||
    enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _loadExtensionsIn(dir, type) {
 | 
			
		||||
    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 child = dir.get_child(name);
 | 
			
		||||
        let enabled = enabledExtensions.indexOf(name) != -1;
 | 
			
		||||
        loadExtension(child, enabled, type);
 | 
			
		||||
    }
 | 
			
		||||
    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';
 | 
			
		||||
        let dir = Gio.file_new_for_path(dirPath);
 | 
			
		||||
        if (dir.query_exists(null))
 | 
			
		||||
            _loadExtensionsIn(dir, ExtensionType.SYSTEM);
 | 
			
		||||
    }
 | 
			
		||||
    let finder = new ExtensionUtils.ExtensionFinder();
 | 
			
		||||
    finder.connect('extension-found', function(signals, extension) {
 | 
			
		||||
        try {
 | 
			
		||||
            loadExtension(extension);
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            logExtensionError(extension.uuid, e);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    finder.scanExtensions();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										45
									
								
								js/ui/flashspot.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,45 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
 | 
			
		||||
const Lightbox = imports.ui.lightbox;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
const FLASHSPOT_ANIMATION_TIME = 0.25; // seconds
 | 
			
		||||
 | 
			
		||||
const Flashspot = new Lang.Class({
 | 
			
		||||
    Name: 'Flashspot',
 | 
			
		||||
    Extends: Lightbox.Lightbox,
 | 
			
		||||
 | 
			
		||||
    _init: function(area) {
 | 
			
		||||
        this.parent(Main.uiGroup, { inhibitEvents: true,
 | 
			
		||||
                                    width: area.width,
 | 
			
		||||
                                    height: area.height });
 | 
			
		||||
 | 
			
		||||
        this.actor.style_class = 'flashspot';
 | 
			
		||||
        this.actor.set_position(area.x, area.y);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    fire: function() {
 | 
			
		||||
        this.actor.opacity = 0;
 | 
			
		||||
        Tweener.addTween(this.actor,
 | 
			
		||||
                         { opacity: 255,
 | 
			
		||||
                           time: FLASHSPOT_ANIMATION_TIME,
 | 
			
		||||
                           transition: 'linear',
 | 
			
		||||
                           onComplete: Lang.bind(this, this._onFireShowComplete)
 | 
			
		||||
                         });
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onFireShowComplete: function() {
 | 
			
		||||
        Tweener.addTween(this.actor,
 | 
			
		||||
                         { opacity: 0,
 | 
			
		||||
                           time: FLASHSPOT_ANIMATION_TIME,
 | 
			
		||||
                           transition: 'linear',
 | 
			
		||||
                           onComplete: Lang.bind(this, function() {
 | 
			
		||||
                               this.destroy();
 | 
			
		||||
                           })
 | 
			
		||||
                         });
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										228
									
								
								js/ui/ibusCandidatePopup.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,228 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const IBus = imports.gi.IBus;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const BoxPointer = imports.ui.boxpointer;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const PopupMenu = imports.ui.popupMenu;
 | 
			
		||||
 | 
			
		||||
const MAX_CANDIDATES_PER_PAGE = 16;
 | 
			
		||||
 | 
			
		||||
const CandidateArea = new Lang.Class({
 | 
			
		||||
    Name: 'CandidateArea',
 | 
			
		||||
    Extends: PopupMenu.PopupBaseMenuItem,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.parent({ reactive: false });
 | 
			
		||||
 | 
			
		||||
        // St.Table exhibits some sizing problems so let's go with a
 | 
			
		||||
        // clutter layout manager for now.
 | 
			
		||||
        this._table = new Clutter.Actor();
 | 
			
		||||
        this.addActor(this._table);
 | 
			
		||||
 | 
			
		||||
        this._tableLayout = new Clutter.TableLayout();
 | 
			
		||||
        this._table.set_layout_manager(this._tableLayout);
 | 
			
		||||
 | 
			
		||||
        this._indexLabels = [];
 | 
			
		||||
        this._candidateLabels = [];
 | 
			
		||||
        for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
 | 
			
		||||
            this._indexLabels.push(new St.Label({ style_class: 'candidate-index' }));
 | 
			
		||||
            this._candidateLabels.push(new St.Label({ style_class: 'candidate-label' }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._orientation = -1;
 | 
			
		||||
        this._cursorPosition = 0;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setOrientation: function(orientation) {
 | 
			
		||||
        if (this._orientation == orientation)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._orientation = orientation;
 | 
			
		||||
 | 
			
		||||
        this._table.remove_all_children();
 | 
			
		||||
 | 
			
		||||
        if (this._orientation == IBus.Orientation.HORIZONTAL)
 | 
			
		||||
            for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
 | 
			
		||||
                this._tableLayout.pack(this._indexLabels[i], i*2, 0);
 | 
			
		||||
                this._tableLayout.pack(this._candidateLabels[i], i*2 + 1, 0);
 | 
			
		||||
            }
 | 
			
		||||
        else                    // VERTICAL || SYSTEM
 | 
			
		||||
            for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
 | 
			
		||||
                this._tableLayout.pack(this._indexLabels[i], 0, i);
 | 
			
		||||
                this._tableLayout.pack(this._candidateLabels[i], 1, i);
 | 
			
		||||
            }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setCandidates: function(indexes, candidates, orientation, cursorPosition, cursorVisible) {
 | 
			
		||||
        this._setOrientation(orientation);
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
 | 
			
		||||
            let visible = i < candidates.length;
 | 
			
		||||
            this._indexLabels[i].visible = visible;
 | 
			
		||||
            this._candidateLabels[i].visible = visible;
 | 
			
		||||
 | 
			
		||||
            if (!visible)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            this._indexLabels[i].text = ((indexes && indexes[i]) ? indexes[i] : '%x.'.format(i + 1));
 | 
			
		||||
            this._candidateLabels[i].text = candidates[i];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._candidateLabels[this._cursorPosition].remove_style_pseudo_class('selected');
 | 
			
		||||
        this._cursorPosition = cursorPosition;
 | 
			
		||||
        if (cursorVisible)
 | 
			
		||||
            this._candidateLabels[cursorPosition].add_style_pseudo_class('selected');
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const CandidatePopup = new Lang.Class({
 | 
			
		||||
    Name: 'CandidatePopup',
 | 
			
		||||
    Extends: PopupMenu.PopupMenu,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._cursor = new St.Bin({ opacity: 0 });
 | 
			
		||||
        Main.uiGroup.add_actor(this._cursor);
 | 
			
		||||
 | 
			
		||||
        this.parent(this._cursor, 0, St.Side.TOP);
 | 
			
		||||
        this.actor.hide();
 | 
			
		||||
        Main.uiGroup.add_actor(this.actor);
 | 
			
		||||
 | 
			
		||||
        this._preeditTextItem = new PopupMenu.PopupMenuItem('', { reactive: false });
 | 
			
		||||
        this._preeditTextItem.actor.hide();
 | 
			
		||||
        this.addMenuItem(this._preeditTextItem);
 | 
			
		||||
 | 
			
		||||
        this._auxTextItem = new PopupMenu.PopupMenuItem('', { reactive: false });
 | 
			
		||||
        this._auxTextItem.actor.hide();
 | 
			
		||||
        this.addMenuItem(this._auxTextItem);
 | 
			
		||||
 | 
			
		||||
        this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
 | 
			
		||||
 | 
			
		||||
        this._lookupTableItem = new CandidateArea();
 | 
			
		||||
        this._lookupTableItem.actor.hide();
 | 
			
		||||
        this.addMenuItem(this._lookupTableItem);
 | 
			
		||||
 | 
			
		||||
        this._panelService = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setPanelService: function(panelService) {
 | 
			
		||||
        this._panelService = panelService;
 | 
			
		||||
        if (!panelService)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        panelService.connect('set-cursor-location',
 | 
			
		||||
                             Lang.bind(this, function(ps, x, y, w, h) {
 | 
			
		||||
                                 this._cursor.set_position(x, y);
 | 
			
		||||
                                 this._cursor.set_size(w, h);
 | 
			
		||||
                             }));
 | 
			
		||||
        panelService.connect('update-preedit-text',
 | 
			
		||||
                             Lang.bind(this, function(ps, text, cursorPosition, visible) {
 | 
			
		||||
                                 if (visible)
 | 
			
		||||
                                     this._preeditTextItem.actor.show();
 | 
			
		||||
                                 else
 | 
			
		||||
                                     this._preeditTextItem.actor.hide();
 | 
			
		||||
                                 this._updateVisibility();
 | 
			
		||||
 | 
			
		||||
                                 this._preeditTextItem.actor.label_actor.text = text.get_text();
 | 
			
		||||
 | 
			
		||||
                                 let attrs = text.get_attributes();
 | 
			
		||||
                                 if (attrs)
 | 
			
		||||
                                     this._setTextAttributes(this._preeditTextItem.actor.label_actor.clutter_text,
 | 
			
		||||
                                                             attrs);
 | 
			
		||||
                             }));
 | 
			
		||||
        panelService.connect('show-preedit-text',
 | 
			
		||||
                             Lang.bind(this, function(ps) {
 | 
			
		||||
                                 this._preeditTextItem.actor.show();
 | 
			
		||||
                                 this._updateVisibility();
 | 
			
		||||
                             }));
 | 
			
		||||
        panelService.connect('hide-preedit-text',
 | 
			
		||||
                             Lang.bind(this, function(ps) {
 | 
			
		||||
                                 this._preeditTextItem.actor.hide();
 | 
			
		||||
                                 this._updateVisibility();
 | 
			
		||||
                             }));
 | 
			
		||||
        panelService.connect('update-auxiliary-text',
 | 
			
		||||
                             Lang.bind(this, function(ps, text, visible) {
 | 
			
		||||
                                 if (visible)
 | 
			
		||||
                                     this._auxTextItem.actor.show();
 | 
			
		||||
                                 else
 | 
			
		||||
                                     this._auxTextItem.actor.hide();
 | 
			
		||||
                                 this._updateVisibility();
 | 
			
		||||
 | 
			
		||||
                                 this._auxTextItem.actor.label_actor.text = text.get_text();
 | 
			
		||||
                             }));
 | 
			
		||||
        panelService.connect('show-auxiliary-text',
 | 
			
		||||
                             Lang.bind(this, function(ps) {
 | 
			
		||||
                                 this._auxTextItem.actor.show();
 | 
			
		||||
                                 this._updateVisibility();
 | 
			
		||||
                             }));
 | 
			
		||||
        panelService.connect('hide-auxiliary-text',
 | 
			
		||||
                             Lang.bind(this, function(ps) {
 | 
			
		||||
                                 this._auxTextItem.actor.hide();
 | 
			
		||||
                                 this._updateVisibility();
 | 
			
		||||
                             }));
 | 
			
		||||
        panelService.connect('update-lookup-table',
 | 
			
		||||
                             Lang.bind(this, function(ps, lookupTable, visible) {
 | 
			
		||||
                                 if (visible)
 | 
			
		||||
                                     this._lookupTableItem.actor.show();
 | 
			
		||||
                                 else
 | 
			
		||||
                                     this._lookupTableItem.actor.hide();
 | 
			
		||||
                                 this._updateVisibility();
 | 
			
		||||
 | 
			
		||||
                                 let cursorPos = lookupTable.get_cursor_pos();
 | 
			
		||||
                                 let pageSize = lookupTable.get_page_size();
 | 
			
		||||
                                 let page = ((cursorPos == 0) ? 0 : Math.floor(cursorPos / pageSize));
 | 
			
		||||
                                 let startIndex = page * pageSize;
 | 
			
		||||
                                 let endIndex = Math.min((page + 1) * pageSize,
 | 
			
		||||
                                                         lookupTable.get_number_of_candidates());
 | 
			
		||||
                                 let indexes = [];
 | 
			
		||||
                                 let indexLabel;
 | 
			
		||||
                                 for (let i = 0; indexLabel = lookupTable.get_label(i); ++i)
 | 
			
		||||
                                      indexes.push(indexLabel.get_text());
 | 
			
		||||
 | 
			
		||||
                                 let candidates = [];
 | 
			
		||||
                                 for (let i = startIndex; i < endIndex; ++i)
 | 
			
		||||
                                     candidates.push(lookupTable.get_candidate(i).get_text());
 | 
			
		||||
 | 
			
		||||
                                 this._lookupTableItem.setCandidates(indexes,
 | 
			
		||||
                                                                     candidates,
 | 
			
		||||
                                                                     lookupTable.get_orientation(),
 | 
			
		||||
                                                                     cursorPos % pageSize,
 | 
			
		||||
                                                                     lookupTable.is_cursor_visible());
 | 
			
		||||
                             }));
 | 
			
		||||
        panelService.connect('show-lookup-table',
 | 
			
		||||
                             Lang.bind(this, function(ps) {
 | 
			
		||||
                                 this._lookupTableItem.actor.show();
 | 
			
		||||
                                 this._updateVisibility();
 | 
			
		||||
                             }));
 | 
			
		||||
        panelService.connect('hide-lookup-table',
 | 
			
		||||
                             Lang.bind(this, function(ps) {
 | 
			
		||||
                                 this._lookupTableItem.actor.hide();
 | 
			
		||||
                                 this._updateVisibility();
 | 
			
		||||
                             }));
 | 
			
		||||
        panelService.connect('focus-out',
 | 
			
		||||
                             Lang.bind(this, function(ps) {
 | 
			
		||||
                                 this.close(BoxPointer.PopupAnimation.NONE);
 | 
			
		||||
                             }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateVisibility: function() {
 | 
			
		||||
        let isVisible = (this._preeditTextItem.actor.visible ||
 | 
			
		||||
                         this._auxTextItem.actor.visible ||
 | 
			
		||||
                         this._lookupTableItem.actor.visible);
 | 
			
		||||
 | 
			
		||||
        if (isVisible)
 | 
			
		||||
            this.open(BoxPointer.PopupAnimation.NONE);
 | 
			
		||||
        else
 | 
			
		||||
            this.close(BoxPointer.PopupAnimation.NONE);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setTextAttributes: function(clutterText, ibusAttrList) {
 | 
			
		||||
        let attr;
 | 
			
		||||
        for (let i = 0; attr = ibusAttrList.get(i); ++i)
 | 
			
		||||
            if (attr.get_attr_type() == IBus.AttrType.BACKGROUND)
 | 
			
		||||
                clutterText.set_selection(attr.get_start_index(), attr.get_end_index());
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
@@ -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,
 | 
			
		||||
@@ -37,7 +35,8 @@ BaseIcon.prototype = {
 | 
			
		||||
        this.actor.set_child(box);
 | 
			
		||||
 | 
			
		||||
        this.iconSize = ICON_SIZE;
 | 
			
		||||
        this._iconBin = new St.Bin();
 | 
			
		||||
        this._iconBin = new St.Bin({ x_align: St.Align.MIDDLE,
 | 
			
		||||
                                     y_align: St.Align.MIDDLE });
 | 
			
		||||
 | 
			
		||||
        box.add_actor(this._iconBin);
 | 
			
		||||
 | 
			
		||||
@@ -127,12 +126,12 @@ BaseIcon.prototype = {
 | 
			
		||||
        this.iconSize = size;
 | 
			
		||||
        this.icon = this.createIcon(this.iconSize);
 | 
			
		||||
 | 
			
		||||
        this._iconBin.child = this.icon;
 | 
			
		||||
 | 
			
		||||
        // 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;
 | 
			
		||||
        this._iconBin.set_size(this.iconSize, this.iconSize);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onStyleChanged: function() {
 | 
			
		||||
@@ -149,13 +148,11 @@ BaseIcon.prototype = {
 | 
			
		||||
 | 
			
		||||
        this._createIconTexture(size);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function IconGrid(params) {
 | 
			
		||||
    this._init(params);
 | 
			
		||||
}
 | 
			
		||||
const IconGrid = new Lang.Class({
 | 
			
		||||
    Name: 'IconGrid',
 | 
			
		||||
 | 
			
		||||
IconGrid.prototype = {
 | 
			
		||||
    _init: function(params) {
 | 
			
		||||
        params = Params.parse(params, { rowLimit: null,
 | 
			
		||||
                                        columnLimit: null,
 | 
			
		||||
@@ -168,7 +165,7 @@ IconGrid.prototype = {
 | 
			
		||||
                                        vertical: true });
 | 
			
		||||
        // Pulled from CSS, but hardcode some defaults here
 | 
			
		||||
        this._spacing = 0;
 | 
			
		||||
        this._item_size = ICON_SIZE;
 | 
			
		||||
        this._hItemSize = this._vItemSize = ICON_SIZE;
 | 
			
		||||
        this._grid = new Shell.GenericContainer();
 | 
			
		||||
        this.actor.add(this._grid, { expand: true, y_align: St.Align.START });
 | 
			
		||||
        this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
 | 
			
		||||
@@ -187,8 +184,8 @@ IconGrid.prototype = {
 | 
			
		||||
        // Kind of a lie, but not really an issue right now.  If
 | 
			
		||||
        // we wanted to support some sort of hidden/overflow that would
 | 
			
		||||
        // need higher level design
 | 
			
		||||
        alloc.min_size = this._item_size;
 | 
			
		||||
        alloc.natural_size = nColumns * this._item_size + totalSpacing;
 | 
			
		||||
        alloc.min_size = this._hItemSize;
 | 
			
		||||
        alloc.natural_size = nColumns * this._hItemSize + totalSpacing;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getVisibleChildren: function() {
 | 
			
		||||
@@ -210,7 +207,7 @@ IconGrid.prototype = {
 | 
			
		||||
        if (this._rowLimit)
 | 
			
		||||
            nRows = Math.min(nRows, this._rowLimit);
 | 
			
		||||
        let totalSpacing = Math.max(0, nRows - 1) * this._spacing;
 | 
			
		||||
        let height = nRows * this._item_size + totalSpacing;
 | 
			
		||||
        let height = nRows * this._vItemSize + totalSpacing;
 | 
			
		||||
        alloc.min_size = height;
 | 
			
		||||
        alloc.natural_size = height;
 | 
			
		||||
    },
 | 
			
		||||
@@ -243,13 +240,13 @@ IconGrid.prototype = {
 | 
			
		||||
                = children[i].get_preferred_size();
 | 
			
		||||
 | 
			
		||||
            /* Center the item in its allocation horizontally */
 | 
			
		||||
            let width = Math.min(this._item_size, childNaturalWidth);
 | 
			
		||||
            let width = Math.min(this._hItemSize, childNaturalWidth);
 | 
			
		||||
            let childXSpacing = Math.max(0, width - childNaturalWidth) / 2;
 | 
			
		||||
            let height = Math.min(this._item_size, childNaturalHeight);
 | 
			
		||||
            let height = Math.min(this._vItemSize, childNaturalHeight);
 | 
			
		||||
            let childYSpacing = Math.max(0, height - childNaturalHeight) / 2;
 | 
			
		||||
 | 
			
		||||
            let childBox = new Clutter.ActorBox();
 | 
			
		||||
            if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
 | 
			
		||||
            if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
 | 
			
		||||
                let _x = box.x2 - (x + width);
 | 
			
		||||
                childBox.x1 = Math.floor(_x - childXSpacing);
 | 
			
		||||
            } else {
 | 
			
		||||
@@ -273,10 +270,10 @@ IconGrid.prototype = {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (columnIndex == 0) {
 | 
			
		||||
                y += this._item_size + this._spacing;
 | 
			
		||||
                y += this._vItemSize + this._spacing;
 | 
			
		||||
                x = box.x1 + leftPadding;
 | 
			
		||||
            } else {
 | 
			
		||||
                x += this._item_size + this._spacing;
 | 
			
		||||
                x += this._hItemSize + this._spacing;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
@@ -285,12 +282,16 @@ IconGrid.prototype = {
 | 
			
		||||
        return this._computeLayout(rowWidth)[0];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getRowLimit: function() {
 | 
			
		||||
        return this._rowLimit;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _computeLayout: function (forWidth) {
 | 
			
		||||
        let nColumns = 0;
 | 
			
		||||
        let usedWidth = 0;
 | 
			
		||||
        while ((this._colLimit == null || nColumns < this._colLimit) &&
 | 
			
		||||
               (usedWidth + this._item_size <= forWidth)) {
 | 
			
		||||
            usedWidth += this._item_size + this._spacing;
 | 
			
		||||
               (usedWidth + this._hItemSize <= forWidth)) {
 | 
			
		||||
            usedWidth += this._hItemSize + this._spacing;
 | 
			
		||||
            nColumns += 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -303,25 +304,27 @@ IconGrid.prototype = {
 | 
			
		||||
    _onStyleChanged: function() {
 | 
			
		||||
        let themeNode = this.actor.get_theme_node();
 | 
			
		||||
        this._spacing = themeNode.get_length('spacing');
 | 
			
		||||
        this._item_size = themeNode.get_length('-shell-grid-item-size');
 | 
			
		||||
        this._hItemSize = themeNode.get_length('-shell-grid-horizontal-item-size') || ICON_SIZE;
 | 
			
		||||
        this._vItemSize = themeNode.get_length('-shell-grid-vertical-item-size') || ICON_SIZE;
 | 
			
		||||
        this._grid.queue_relayout();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    removeAll: function () {
 | 
			
		||||
        this._grid.get_children().forEach(Lang.bind(this, function (child) {
 | 
			
		||||
            child.destroy();
 | 
			
		||||
        }));
 | 
			
		||||
    removeAll: function() {
 | 
			
		||||
        this._grid.destroy_all_children();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addItem: function(actor) {
 | 
			
		||||
        this._grid.add_actor(actor);
 | 
			
		||||
    addItem: function(actor, index) {
 | 
			
		||||
        if (index !== undefined)
 | 
			
		||||
            this._grid.insert_child_at_index(actor, index);
 | 
			
		||||
        else
 | 
			
		||||
            this._grid.add_actor(actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getItemAtIndex: function(index) {
 | 
			
		||||
        return this._grid.get_children()[index];
 | 
			
		||||
        return this._grid.get_child_at_index(index);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    visibleItemsCount: function() {
 | 
			
		||||
        return this._grid.get_children().length - this._grid.get_n_skip_paint();
 | 
			
		||||
        return this._grid.get_n_children() - this._grid.get_n_skip_paint();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Caribou = imports.gi.Caribou;
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
@@ -15,9 +15,11 @@ const Main = imports.ui.main;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
 | 
			
		||||
const KEYBOARD_SCHEMA = 'org.gnome.shell.keyboard';
 | 
			
		||||
const SHOW_KEYBOARD = 'show-keyboard';
 | 
			
		||||
const KEYBOARD_TYPE = 'keyboard-type';
 | 
			
		||||
 | 
			
		||||
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
 | 
			
		||||
const SHOW_KEYBOARD = 'screen-keyboard-enabled';
 | 
			
		||||
 | 
			
		||||
// Key constants taken from Antler
 | 
			
		||||
// FIXME: ought to be moved into libcaribou
 | 
			
		||||
const PRETTY_KEYS = {
 | 
			
		||||
@@ -37,34 +39,31 @@ const PRETTY_KEYS = {
 | 
			
		||||
    'Alt_L': 'Alt'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const CaribouKeyboardIface = {
 | 
			
		||||
    name: 'org.gnome.Caribou.Keyboard',
 | 
			
		||||
    methods:    [ { name: 'Show',
 | 
			
		||||
                    inSignature: 'u',
 | 
			
		||||
                    outSignature: ''
 | 
			
		||||
                  },
 | 
			
		||||
                  { name: 'Hide',
 | 
			
		||||
                    inSignature: 'u',
 | 
			
		||||
                    outSignature: ''
 | 
			
		||||
                  },
 | 
			
		||||
                  { name: 'SetCursorLocation',
 | 
			
		||||
                    inSignature: 'iiii',
 | 
			
		||||
                    outSignature: ''
 | 
			
		||||
                  },
 | 
			
		||||
                  { name: 'SetEntryLocation',
 | 
			
		||||
                    inSignature: 'iiii',
 | 
			
		||||
                    outSignature: ''
 | 
			
		||||
                  } ],
 | 
			
		||||
    properties: [ { name: 'Name',
 | 
			
		||||
                    signature: 's',
 | 
			
		||||
                    access: 'read' } ]
 | 
			
		||||
};
 | 
			
		||||
const CaribouKeyboardIface = <interface name='org.gnome.Caribou.Keyboard'>
 | 
			
		||||
<method name='Show'>
 | 
			
		||||
    <arg type='u' direction='in' />
 | 
			
		||||
</method>
 | 
			
		||||
<method name='Hide'>
 | 
			
		||||
    <arg type='u' direction='in' />
 | 
			
		||||
</method>
 | 
			
		||||
<method name='SetCursorLocation'>
 | 
			
		||||
    <arg type='i' direction='in' />
 | 
			
		||||
    <arg type='i' direction='in' />
 | 
			
		||||
    <arg type='i' direction='in' />
 | 
			
		||||
    <arg type='i' direction='in' />
 | 
			
		||||
</method>
 | 
			
		||||
<method name='SetEntryLocation'>
 | 
			
		||||
    <arg type='i' direction='in' />
 | 
			
		||||
    <arg type='i' direction='in' />
 | 
			
		||||
    <arg type='i' direction='in' />
 | 
			
		||||
    <arg type='i' direction='in' />
 | 
			
		||||
</method>
 | 
			
		||||
<property name='Name' access='read' type='s' />
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
function Key() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
const Key = new Lang.Class({
 | 
			
		||||
    Name: 'Key',
 | 
			
		||||
 | 
			
		||||
Key.prototype = {
 | 
			
		||||
    _init : function(key) {
 | 
			
		||||
        this._key = key;
 | 
			
		||||
 | 
			
		||||
@@ -73,7 +72,7 @@ Key.prototype = {
 | 
			
		||||
        this._extended_keys = this._key.get_extended_keys();
 | 
			
		||||
        this._extended_keyboard = null;
 | 
			
		||||
 | 
			
		||||
        if (this._key.name == "Control_L" || this._key.name == "Alt_L")
 | 
			
		||||
        if (this._key.name == 'Control_L' || this._key.name == 'Alt_L')
 | 
			
		||||
            this._key.latch = true;
 | 
			
		||||
 | 
			
		||||
        this._key.connect('key-pressed', Lang.bind(this, function ()
 | 
			
		||||
@@ -94,7 +93,7 @@ Key.prototype = {
 | 
			
		||||
            this._getExtendedKeys();
 | 
			
		||||
            this.actor._extended_keys = this._extended_keyboard;
 | 
			
		||||
            this._boxPointer.actor.hide();
 | 
			
		||||
            Main.layoutManager.addChrome(this._boxPointer.actor, { visibleInFullscreen: true });
 | 
			
		||||
            Main.layoutManager.addChrome(this._boxPointer.actor);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -176,7 +175,7 @@ Key.prototype = {
 | 
			
		||||
            this.actor.fake_release();
 | 
			
		||||
            this._boxPointer.actor.raise_top();
 | 
			
		||||
            this._boxPointer.setPosition(this.actor, 0.5);
 | 
			
		||||
            this._boxPointer.show(true);
 | 
			
		||||
            this._boxPointer.show(BoxPointer.PopupAnimation.FULL);
 | 
			
		||||
            this.actor.set_hover(false);
 | 
			
		||||
            if (!this._grabbed) {
 | 
			
		||||
                 Main.pushModal(this.actor);
 | 
			
		||||
@@ -187,38 +186,37 @@ Key.prototype = {
 | 
			
		||||
        } else {
 | 
			
		||||
            if (this._grabbed)
 | 
			
		||||
                this._ungrab();
 | 
			
		||||
            this._boxPointer.hide(true);
 | 
			
		||||
            this._boxPointer.hide(BoxPointer.PopupAnimation.FULL);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function Keyboard() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
const Keyboard = new Lang.Class({
 | 
			
		||||
    // HACK: we can't set Name, because it collides with Name dbus property
 | 
			
		||||
    // Name: 'Keyboard',
 | 
			
		||||
 | 
			
		||||
Keyboard.prototype = {
 | 
			
		||||
    _init: function () {
 | 
			
		||||
        DBus.session.exportObject('/org/gnome/Caribou/Keyboard', this);
 | 
			
		||||
        DBus.session.acquire_name('org.gnome.Caribou.Keyboard', 0, null, null);
 | 
			
		||||
        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();
 | 
			
		||||
        this.actor = new St.BoxLayout({ name: 'keyboard', vertical: true, reactive: true });
 | 
			
		||||
        Main.layoutManager.keyboardBox.add_actor(this.actor);
 | 
			
		||||
        Main.layoutManager.trackChrome(this.actor);
 | 
			
		||||
        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 () {
 | 
			
		||||
        if (this._enableKeyboard)
 | 
			
		||||
            this._redraw();
 | 
			
		||||
        this._redraw();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _settingsChanged: function () {
 | 
			
		||||
        this._enableKeyboard = this._keyboardSettings.get_boolean(SHOW_KEYBOARD);
 | 
			
		||||
    _settingsChanged: function (settings, key) {
 | 
			
		||||
        this._enableKeyboard = this._a11yApplicationsSettings.get_boolean(SHOW_KEYBOARD);
 | 
			
		||||
        if (!this._enableKeyboard && !this._keyboard)
 | 
			
		||||
            return;
 | 
			
		||||
        if (this._enableKeyboard && this._keyboard &&
 | 
			
		||||
@@ -227,9 +225,20 @@ Keyboard.prototype = {
 | 
			
		||||
 | 
			
		||||
        if (this._keyboard)
 | 
			
		||||
            this._destroyKeyboard();
 | 
			
		||||
        if (this._enableKeyboard)
 | 
			
		||||
            this._setupKeyboard();
 | 
			
		||||
        else
 | 
			
		||||
 | 
			
		||||
        if (this._enableKeyboard) {
 | 
			
		||||
            // If we've been called because the setting actually just
 | 
			
		||||
            // changed to true (as opposed to being called from
 | 
			
		||||
            // this._init()), then we want to pop up the keyboard.
 | 
			
		||||
            let showKeyboard = (settings != null);
 | 
			
		||||
 | 
			
		||||
            // However, caribou-gtk-module or this._onKeyFocusChanged
 | 
			
		||||
            // will probably immediately tell us to hide it, so we
 | 
			
		||||
            // have to fake things out so we'll ignore that request.
 | 
			
		||||
            if (showKeyboard)
 | 
			
		||||
                this._timestamp = global.display.get_current_time_roundtrip() + 1;
 | 
			
		||||
            this._setupKeyboard(showKeyboard);
 | 
			
		||||
        } else
 | 
			
		||||
            Main.layoutManager.hideKeyboard(true);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -239,12 +248,17 @@ Keyboard.prototype = {
 | 
			
		||||
        if (this._focusNotifyId)
 | 
			
		||||
            global.stage.disconnect(this._focusNotifyId);
 | 
			
		||||
        this._keyboard = null;
 | 
			
		||||
        this.actor.destroy_children();
 | 
			
		||||
        this.actor.destroy();
 | 
			
		||||
        this.actor = null;
 | 
			
		||||
 | 
			
		||||
        this._destroySource();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setupKeyboard: function() {
 | 
			
		||||
    _setupKeyboard: function(show) {
 | 
			
		||||
        this.actor = new St.BoxLayout({ name: 'keyboard', vertical: true, reactive: true });
 | 
			
		||||
        Main.layoutManager.keyboardBox.add_actor(this.actor);
 | 
			
		||||
        Main.layoutManager.trackChrome(this.actor);
 | 
			
		||||
 | 
			
		||||
        this._keyboard = new Caribou.KeyboardModel({ keyboard_type: this._keyboardSettings.get_string(KEYBOARD_TYPE) });
 | 
			
		||||
        this._groups = {};
 | 
			
		||||
        this._current_page = null;
 | 
			
		||||
@@ -255,23 +269,33 @@ Keyboard.prototype = {
 | 
			
		||||
 | 
			
		||||
        this._addKeys();
 | 
			
		||||
 | 
			
		||||
        // Keys should be layout according to the group, not the
 | 
			
		||||
        // locale; as Caribou already provides the expected layout,
 | 
			
		||||
        // this means enforcing LTR for all locales.
 | 
			
		||||
        this.actor.text_direction = Clutter.TextDirection.LTR;
 | 
			
		||||
 | 
			
		||||
        this._keyboardNotifyId = this._keyboard.connect('notify::active-group', Lang.bind(this, this._onGroupChanged));
 | 
			
		||||
        this._focusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
 | 
			
		||||
        this._createSource();
 | 
			
		||||
 | 
			
		||||
        if (show)
 | 
			
		||||
            this.show();
 | 
			
		||||
        else
 | 
			
		||||
            this._createSource();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeyFocusChanged: function () {
 | 
			
		||||
        let focus = global.stage.key_focus;
 | 
			
		||||
 | 
			
		||||
        if (focus == global.stage || focus == null)
 | 
			
		||||
        // Showing an extended key popup and clicking a key from the extended keys
 | 
			
		||||
        // will grab focus, but ignore that
 | 
			
		||||
        if (focus && (focus._extended_keys || (focus._key && focus._key.extended_key)))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let time = global.get_current_time();
 | 
			
		||||
        if (focus instanceof Clutter.Text)
 | 
			
		||||
            this.show();
 | 
			
		||||
        else {
 | 
			
		||||
            if (focus._extended_keys == null)
 | 
			
		||||
                this.hide();
 | 
			
		||||
        }
 | 
			
		||||
            this.Show(time);
 | 
			
		||||
        else
 | 
			
		||||
            this.Hide(time);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _addKeys: function () {
 | 
			
		||||
@@ -300,7 +324,8 @@ Keyboard.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getTrayIcon: function () {
 | 
			
		||||
        let trayButton = new St.Button ({ label: "tray", style_class: 'keyboard-key' });
 | 
			
		||||
        let trayButton = new St.Button ({ label: _("tray"),
 | 
			
		||||
                                          style_class: 'keyboard-key' });
 | 
			
		||||
        trayButton.key_width = 1;
 | 
			
		||||
        trayButton.connect('button-press-event', Lang.bind(this, function () {
 | 
			
		||||
            Main.messageTray.toggle();
 | 
			
		||||
@@ -334,7 +359,7 @@ Keyboard.prototype = {
 | 
			
		||||
                    right_box.add(button.actor);
 | 
			
		||||
                else
 | 
			
		||||
                    left_box.add(button.actor);
 | 
			
		||||
                if (key.name == "Caribou_Prefs") {
 | 
			
		||||
                if (key.name == 'Caribou_Prefs') {
 | 
			
		||||
                    key.connect('key-released', Lang.bind(this, this.hide));
 | 
			
		||||
 | 
			
		||||
                    // Add new key for hiding message tray
 | 
			
		||||
@@ -359,6 +384,9 @@ Keyboard.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _redraw: function () {
 | 
			
		||||
        if (!this._enableKeyboard)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let monitor = Main.layoutManager.bottomMonitor;
 | 
			
		||||
        let maxHeight = monitor.height / 3;
 | 
			
		||||
        this.actor.width = monitor.width;
 | 
			
		||||
@@ -468,6 +496,9 @@ Keyboard.prototype = {
 | 
			
		||||
 | 
			
		||||
    // D-Bus methods
 | 
			
		||||
    Show: function(timestamp) {
 | 
			
		||||
        if (!this._enableKeyboard)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (timestamp - this._timestamp < 0)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
@@ -476,6 +507,9 @@ Keyboard.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    Hide: function(timestamp) {
 | 
			
		||||
        if (!this._enableKeyboard)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (timestamp - this._timestamp < 0)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
@@ -484,40 +518,34 @@ Keyboard.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    SetCursorLocation: function(x, y, w, h) {
 | 
			
		||||
        this._setLocation(x, y);
 | 
			
		||||
        if (!this._enableKeyboard)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
//        this._setLocation(x, y);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    SetEntryLocation: function(x, y, w, h) {
 | 
			
		||||
        this._setLocation(x, y);
 | 
			
		||||
        if (!this._enableKeyboard)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
//        this._setLocation(x, y);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get Name() {
 | 
			
		||||
        return 'gnome-shell';
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
DBus.conformExport(Keyboard.prototype, CaribouKeyboardIface);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function KeyboardSource() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
KeyboardSource.prototype = {
 | 
			
		||||
    __proto__: MessageTray.Source.prototype,
 | 
			
		||||
const KeyboardSource = new Lang.Class({
 | 
			
		||||
    Name: 'KeyboardSource',
 | 
			
		||||
    Extends: MessageTray.Source,
 | 
			
		||||
 | 
			
		||||
    _init: function(keyboard) {
 | 
			
		||||
        this._keyboard = keyboard;
 | 
			
		||||
        MessageTray.Source.prototype._init.call(this, _("Keyboard"));
 | 
			
		||||
 | 
			
		||||
        this._setSummaryIcon(this.createNotificationIcon());
 | 
			
		||||
        this.parent(_("Keyboard"), 'input-keyboard', St.IconType.SYMBOLIC);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createNotificationIcon: function() {
 | 
			
		||||
        return new St.Icon({ icon_name: 'input-keyboard',
 | 
			
		||||
                             icon_type: St.IconType.SYMBOLIC,
 | 
			
		||||
                             icon_size: this.ICON_SIZE });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
     handleSummaryClick: function() {
 | 
			
		||||
    handleSummaryClick: function() {
 | 
			
		||||
        let event = Clutter.get_current_event();
 | 
			
		||||
        if (event.type() != Clutter.EventType.BUTTON_RELEASE)
 | 
			
		||||
            return false;
 | 
			
		||||
@@ -529,4 +557,4 @@ KeyboardSource.prototype = {
 | 
			
		||||
    open: function() {
 | 
			
		||||
        this._keyboard.show();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										208
									
								
								js/ui/keyringPrompt.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,208 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Pango = imports.gi.Pango;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GObject = imports.gi.GObject;
 | 
			
		||||
const Gcr = imports.gi.Gcr;
 | 
			
		||||
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const ShellEntry = imports.ui.shellEntry;
 | 
			
		||||
const CheckBox = imports.ui.checkBox;
 | 
			
		||||
 | 
			
		||||
let prompter = null;
 | 
			
		||||
 | 
			
		||||
const KeyringDialog = new Lang.Class({
 | 
			
		||||
    Name: 'KeyringDialog',
 | 
			
		||||
    Extends: ModalDialog.ModalDialog,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.parent({ styleClass: 'prompt-dialog' });
 | 
			
		||||
 | 
			
		||||
        this.prompt = new Shell.KeyringPrompt();
 | 
			
		||||
        this.prompt.connect('show-password', Lang.bind(this, this._onShowPassword));
 | 
			
		||||
        this.prompt.connect('show-confirm', Lang.bind(this, this._onShowConfirm));
 | 
			
		||||
        this.prompt.connect('hide-prompt', Lang.bind(this, this._onHidePrompt));
 | 
			
		||||
 | 
			
		||||
        let mainContentBox = new St.BoxLayout({ style_class: 'prompt-dialog-main-layout',
 | 
			
		||||
                                                vertical: false });
 | 
			
		||||
        this.contentLayout.add(mainContentBox);
 | 
			
		||||
 | 
			
		||||
        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 });
 | 
			
		||||
 | 
			
		||||
        this._messageBox = new St.BoxLayout({ style_class: 'prompt-dialog-message-layout',
 | 
			
		||||
                                              vertical: true });
 | 
			
		||||
        mainContentBox.add(this._messageBox,
 | 
			
		||||
                           { y_align: St.Align.START, expand: true, x_fill: true, y_fill: true });
 | 
			
		||||
 | 
			
		||||
        let subject = new St.Label({ style_class: 'prompt-dialog-headline' });
 | 
			
		||||
        this.prompt.bind_property('message', subject, 'text', GObject.BindingFlags.SYNC_CREATE);
 | 
			
		||||
 | 
			
		||||
        this._messageBox.add(subject,
 | 
			
		||||
                             { y_fill:  false,
 | 
			
		||||
                               y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        let description = new St.Label({ style_class: 'prompt-dialog-description' });
 | 
			
		||||
        description.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
 | 
			
		||||
        description.clutter_text.line_wrap = true;
 | 
			
		||||
        this.prompt.bind_property('description', description, 'text', GObject.BindingFlags.SYNC_CREATE);
 | 
			
		||||
        this._messageBox.add(description,
 | 
			
		||||
                            { y_fill:  true,
 | 
			
		||||
                              y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        this._controlTable = null;
 | 
			
		||||
 | 
			
		||||
        let buttons = [{ label: '',
 | 
			
		||||
                         action: Lang.bind(this, this._onCancelButton),
 | 
			
		||||
                         key:    Clutter.Escape
 | 
			
		||||
                       },
 | 
			
		||||
                       { label: '',
 | 
			
		||||
                         action: Lang.bind(this, this._onContinueButton),
 | 
			
		||||
                         default: true
 | 
			
		||||
                       }]
 | 
			
		||||
 | 
			
		||||
        this.setButtons(buttons);
 | 
			
		||||
        this._cancelButton = buttons[0].button;
 | 
			
		||||
        this._continueButton = buttons[1].button;
 | 
			
		||||
 | 
			
		||||
        this.prompt.bind_property('cancel-label', this._cancelButton, 'label', GObject.BindingFlags.SYNC_CREATE);
 | 
			
		||||
        this.prompt.bind_property('continue-label', this._continueButton, 'label', GObject.BindingFlags.SYNC_CREATE);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _buildControlTable: function() {
 | 
			
		||||
        let table = new St.Table({ style_class: 'keyring-dialog-control-table' });
 | 
			
		||||
        let row = 0;
 | 
			
		||||
 | 
			
		||||
        if (this.prompt.password_visible) {
 | 
			
		||||
            let label = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
 | 
			
		||||
            label.set_text(_("Password:"));
 | 
			
		||||
            table.add(label, { row: row, col: 0, x_expand: false, x_fill: true, x_align: St.Align.START });
 | 
			
		||||
            this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
 | 
			
		||||
                                                 text: '',
 | 
			
		||||
                                                 can_focus: true});
 | 
			
		||||
            this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
 | 
			
		||||
            ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
 | 
			
		||||
            this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onPasswordActivate));
 | 
			
		||||
            table.add(this._passwordEntry, { row: row, col: 1, x_expand: true, x_fill: true, x_align: St.Align.START });
 | 
			
		||||
            row++;
 | 
			
		||||
        } else {
 | 
			
		||||
            this._passwordEntry = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.prompt.confirm_visible) {
 | 
			
		||||
            var label = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
 | 
			
		||||
            label.set_text(_("Type again:"));
 | 
			
		||||
            table.add(label, { row: row, col: 0, x_expand: false, x_fill: true, x_align: St.Align.START });
 | 
			
		||||
            this._confirmEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
 | 
			
		||||
                                                text: '',
 | 
			
		||||
                                                can_focus: true});
 | 
			
		||||
            this._confirmEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
 | 
			
		||||
            ShellEntry.addContextMenu(this._confirmEntry, { isPassword: true });
 | 
			
		||||
            this._confirmEntry.clutter_text.connect('activate', Lang.bind(this, this._onConfirmActivate));
 | 
			
		||||
            table.add(this._confirmEntry, { row: row, col: 1, x_expand: true, x_fill: true, x_align: St.Align.START });
 | 
			
		||||
            row++;
 | 
			
		||||
        } else {
 | 
			
		||||
            this._confirmEntry = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.prompt.set_password_actor(this._passwordEntry ? this._passwordEntry.clutter_text : null);
 | 
			
		||||
        this.prompt.set_confirm_actor(this._confirmEntry ? this._confirmEntry.clutter_text : null);
 | 
			
		||||
 | 
			
		||||
        if (this.prompt.choice_visible) {
 | 
			
		||||
            let choice = new CheckBox.CheckBox();
 | 
			
		||||
            this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE);
 | 
			
		||||
            this.prompt.bind_property('choice-chosen', choice.actor, 'checked', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL);
 | 
			
		||||
            table.add(choice.actor, { row: row, col: 1, x_expand: false, x_fill: true, x_align: St.Align.START });
 | 
			
		||||
            row++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let warning = new St.Label({ style_class: 'prompt-dialog-error-label' });
 | 
			
		||||
        warning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
 | 
			
		||||
        warning.clutter_text.line_wrap = true;
 | 
			
		||||
        table.add(warning, { row: row, col: 1, x_expand: false, x_fill: false, x_align: St.Align.START });
 | 
			
		||||
        this.prompt.bind_property('warning-visible', warning, 'visible', GObject.BindingFlags.SYNC_CREATE);
 | 
			
		||||
        this.prompt.bind_property('warning', warning, 'text', GObject.BindingFlags.SYNC_CREATE);
 | 
			
		||||
 | 
			
		||||
        if (this._controlTable) {
 | 
			
		||||
            this._controlTable.destroy_all_children();
 | 
			
		||||
            this._controlTable.destroy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._controlTable = table;
 | 
			
		||||
        this._messageBox.add(table, { x_fill: true, y_fill: true });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _ensureOpen: function() {
 | 
			
		||||
        // NOTE: ModalDialog.open() is safe to call if the dialog is
 | 
			
		||||
        // already open - it just returns true without side-effects
 | 
			
		||||
        if (this.open())
 | 
			
		||||
          return true;
 | 
			
		||||
 | 
			
		||||
        // The above fail if e.g. unable to get input grab
 | 
			
		||||
        //
 | 
			
		||||
        // In an ideal world this wouldn't happen (because the
 | 
			
		||||
        // Shell is in complete control of the session) but that's
 | 
			
		||||
        // just not how things work right now.
 | 
			
		||||
 | 
			
		||||
        log('keyringPrompt: Failed to show modal dialog.' +
 | 
			
		||||
            ' Dismissing prompt request');
 | 
			
		||||
        this.prompt.cancel()
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onShowPassword: function(prompt) {
 | 
			
		||||
        this._buildControlTable();
 | 
			
		||||
        this._ensureOpen();
 | 
			
		||||
        this._passwordEntry.grab_key_focus();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onShowConfirm: function(prompt) {
 | 
			
		||||
        this._buildControlTable();
 | 
			
		||||
        this._ensureOpen();
 | 
			
		||||
        this._continueButton.grab_key_focus();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onHidePrompt: function(prompt) {
 | 
			
		||||
        this.close();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onPasswordActivate: function() {
 | 
			
		||||
        if (this.prompt.confirm_visible)
 | 
			
		||||
            this._confirmEntry.grab_key_focus();
 | 
			
		||||
        else
 | 
			
		||||
            this._onContinueButton();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onConfirmActivate: function() {
 | 
			
		||||
        this._onContinueButton();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onContinueButton: function() {
 | 
			
		||||
        this.prompt.complete()
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onCancelButton: function() {
 | 
			
		||||
        this.prompt.cancel()
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function init() {
 | 
			
		||||
    prompter = new Gcr.SystemPrompter();
 | 
			
		||||
    prompter.connect('new-prompt', function(prompter) {
 | 
			
		||||
        let dialog = new KeyringDialog();
 | 
			
		||||
        return dialog.prompt;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    let connection = Gio.DBus.session;
 | 
			
		||||
    prompter.register(connection);
 | 
			
		||||
    Gio.bus_own_name_on_connection (connection, 'org.gnome.keyring.SystemPrompter',
 | 
			
		||||
                                    Gio.BusNameOwnerFlags.REPLACE, null, null);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										290
									
								
								js/ui/layout.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 Lang = imports.lang;
 | 
			
		||||
@@ -8,22 +8,20 @@ const Shell = imports.gi.Shell;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const DND = imports.ui.dnd;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const 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;
 | 
			
		||||
 | 
			
		||||
function LayoutManager() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
const LayoutManager = new Lang.Class({
 | 
			
		||||
    Name: 'LayoutManager',
 | 
			
		||||
 | 
			
		||||
LayoutManager.prototype = {
 | 
			
		||||
    _init: function () {
 | 
			
		||||
        this._rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL);
 | 
			
		||||
        this._rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL);
 | 
			
		||||
        this.monitors = [];
 | 
			
		||||
        this.primaryMonitor = null;
 | 
			
		||||
        this.primaryIndex = -1;
 | 
			
		||||
@@ -34,30 +32,37 @@ LayoutManager.prototype = {
 | 
			
		||||
 | 
			
		||||
        this._chrome = new Chrome(this);
 | 
			
		||||
 | 
			
		||||
        this.screenShieldGroup = new St.Widget({ name: 'screenShieldGroup',
 | 
			
		||||
                                                 visible: false,
 | 
			
		||||
                                                 clip_to_allocation: true,
 | 
			
		||||
                                               });
 | 
			
		||||
        this.addChrome(this.screenShieldGroup);
 | 
			
		||||
 | 
			
		||||
        this.panelBox = new St.BoxLayout({ name: 'panelBox',
 | 
			
		||||
                                           vertical: true });
 | 
			
		||||
        this.addChrome(this.panelBox, { affectsStruts: true });
 | 
			
		||||
        this.addChrome(this.panelBox, { affectsStruts: true,
 | 
			
		||||
                                        trackFullscreen: true });
 | 
			
		||||
        this.panelBox.connect('allocation-changed',
 | 
			
		||||
                              Lang.bind(this, this._updatePanelBarriers));
 | 
			
		||||
 | 
			
		||||
        // bottomBox contains the tray and keyboard (which move
 | 
			
		||||
        // together, since the tray slides up from the top of the
 | 
			
		||||
        // keyboard when the keyboard is visible).
 | 
			
		||||
        this._bottomBox = new St.BoxLayout({ name: 'bottomBox',
 | 
			
		||||
                                             vertical: true });
 | 
			
		||||
        this.addChrome(this._bottomBox, { visibleInFullscreen: true });
 | 
			
		||||
 | 
			
		||||
        this.trayBox = new St.BoxLayout({ name: 'trayBox' }); 
 | 
			
		||||
        this.addChrome(this.trayBox);
 | 
			
		||||
        this.trayBox.connect('allocation-changed',
 | 
			
		||||
                             Lang.bind(this, this._updateTrayBarrier));
 | 
			
		||||
        this._bottomBox.add_actor(this.trayBox);
 | 
			
		||||
 | 
			
		||||
        this.keyboardBox = new St.BoxLayout({ name: 'keyboardBox' });
 | 
			
		||||
        this._bottomBox.add_actor(this.keyboardBox);
 | 
			
		||||
        this.keyboardBox = new St.BoxLayout({ name: 'keyboardBox',
 | 
			
		||||
                                              reactive: true,
 | 
			
		||||
                                              track_hover: true });
 | 
			
		||||
        this.addChrome(this.keyboardBox);
 | 
			
		||||
        this._keyboardHeightNotifyId = 0;
 | 
			
		||||
 | 
			
		||||
        global.screen.connect('monitors-changed',
 | 
			
		||||
                              Lang.bind(this, this._monitorsChanged));
 | 
			
		||||
        this._monitorsChanged();
 | 
			
		||||
 | 
			
		||||
        this._chrome.connect('primary-fullscreen-changed', Lang.bind(this, function(chrome, state) {
 | 
			
		||||
            this.emit('primary-fullscreen-changed', state);
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // This is called by Main after everything else is constructed;
 | 
			
		||||
@@ -150,14 +155,19 @@ LayoutManager.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateBoxes: function() {
 | 
			
		||||
        this.screenShieldGroup.set_position(0, 0);
 | 
			
		||||
        this.screenShieldGroup.set_size(global.screen_width, global.screen_height);
 | 
			
		||||
 | 
			
		||||
        this.panelBox.set_position(this.primaryMonitor.x, this.primaryMonitor.y);
 | 
			
		||||
        this.panelBox.set_size(this.primaryMonitor.width, -1);
 | 
			
		||||
 | 
			
		||||
        this._bottomBox.set_position(this.bottomMonitor.x,
 | 
			
		||||
                                     this.bottomMonitor.y + this.bottomMonitor.height);
 | 
			
		||||
        this._bottomBox.set_size(this.bottomMonitor.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.width = this.bottomMonitor.width;
 | 
			
		||||
        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
 | 
			
		||||
@@ -218,55 +228,53 @@ LayoutManager.prototype = {
 | 
			
		||||
        let monitorLeft = monitor.x, monitorRight = monitor.x + monitor.width;
 | 
			
		||||
        let primaryLeft = primary.x, primaryRight = primary.x + primary.width;
 | 
			
		||||
 | 
			
		||||
        if ((monitorLeft >= primaryLeft && monitorLeft <= primaryRight) ||
 | 
			
		||||
            (monitorRight >= primaryLeft && monitorRight <= primaryRight) ||
 | 
			
		||||
            (primaryLeft >= monitorLeft && primaryLeft <= monitorRight) ||
 | 
			
		||||
            (primaryRight >= monitorLeft && primaryRight <= monitorRight))
 | 
			
		||||
        if ((monitorLeft >= primaryLeft && monitorLeft < primaryRight) ||
 | 
			
		||||
            (monitorRight > primaryLeft && monitorRight <= primaryRight) ||
 | 
			
		||||
            (primaryLeft >= monitorLeft && primaryLeft < monitorRight) ||
 | 
			
		||||
            (primaryRight > monitorLeft && primaryRight <= monitorRight))
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    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];
 | 
			
		||||
    get currentMonitor() {
 | 
			
		||||
        let index = global.screen.get_current_monitor();
 | 
			
		||||
        return Main.layoutManager.monitors[index];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _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'
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: this._startupAnimationComplete,
 | 
			
		||||
                           onCompleteScope: this
 | 
			
		||||
                         });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _startupAnimationComplete: function() {
 | 
			
		||||
        this._chrome.thawUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    showKeyboard: function () {
 | 
			
		||||
        Main.messageTray.hide();
 | 
			
		||||
        Tweener.addTween(this._bottomBox,
 | 
			
		||||
                         { anchor_y: this._bottomBox.height,
 | 
			
		||||
        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() {
 | 
			
		||||
@@ -274,20 +282,30 @@ LayoutManager.prototype = {
 | 
			
		||||
        // anchor point changes
 | 
			
		||||
        this._chrome.updateRegions();
 | 
			
		||||
 | 
			
		||||
        this._bottomBox.connect('notify::height', Lang.bind(this, function () {
 | 
			
		||||
            this._bottomBoxAnchor = this._bottomBox.height;
 | 
			
		||||
        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();
 | 
			
		||||
        Tweener.addTween(this._bottomBox,
 | 
			
		||||
        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._showKeyboardComplete,
 | 
			
		||||
                           onComplete: this._hideKeyboardComplete,
 | 
			
		||||
                           onCompleteScope: this
 | 
			
		||||
                         });
 | 
			
		||||
        Tweener.addTween(this.trayBox,
 | 
			
		||||
                         { anchor_y: 0,
 | 
			
		||||
                           time: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad'
 | 
			
		||||
                         });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _hideKeyboardComplete: function() {
 | 
			
		||||
@@ -295,11 +313,11 @@ LayoutManager.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // addChrome:
 | 
			
		||||
    // @actor: an actor to add to the chrome layer
 | 
			
		||||
    // @actor: an actor to add to the chrome
 | 
			
		||||
    // @params: (optional) additional params
 | 
			
		||||
    //
 | 
			
		||||
    // Adds @actor to the chrome layer and (unless %affectsInputRegion
 | 
			
		||||
    // in @params is %false) extends the input region to include it.
 | 
			
		||||
    // 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.
 | 
			
		||||
@@ -309,8 +327,10 @@ LayoutManager.prototype = {
 | 
			
		||||
    // 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.
 | 
			
		||||
    // If %trackFullscreen in @params is %true, the actor's visibility
 | 
			
		||||
    // will be bound to the presence of fullscreen windows on the same
 | 
			
		||||
    // monitor (it will be hidden whenever a fullscreen window is visible,
 | 
			
		||||
    // and shown otherwise)
 | 
			
		||||
    addChrome: function(actor, params) {
 | 
			
		||||
        this._chrome.addActor(actor, params);
 | 
			
		||||
    },
 | 
			
		||||
@@ -324,10 +344,8 @@ LayoutManager.prototype = {
 | 
			
		||||
    // 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.
 | 
			
		||||
    // though some possibilities don't make sense. By default, @actor has
 | 
			
		||||
    // the same params as its chrome ancestor.
 | 
			
		||||
    trackChrome: function(actor, params) {
 | 
			
		||||
        this._chrome.trackActor(actor, params);
 | 
			
		||||
    },
 | 
			
		||||
@@ -341,13 +359,17 @@ LayoutManager.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // removeChrome:
 | 
			
		||||
    // @actor: a child of the chrome layer
 | 
			
		||||
    // @actor: a chrome actor
 | 
			
		||||
    //
 | 
			
		||||
    // Removes @actor from the chrome layer
 | 
			
		||||
    // Removes @actor from the chrome
 | 
			
		||||
    removeChrome: function(actor) {
 | 
			
		||||
        this._chrome.removeActor(actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    findMonitorForActor: function(actor) {
 | 
			
		||||
        return this._chrome.findMonitorForActor(actor);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(LayoutManager.prototype);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -355,11 +377,9 @@ Signals.addSignalMethods(LayoutManager.prototype);
 | 
			
		||||
//
 | 
			
		||||
// This class manages a "hot corner" that can toggle switching to
 | 
			
		||||
// overview.
 | 
			
		||||
function HotCorner() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const HotCorner = new Lang.Class({
 | 
			
		||||
    Name: 'HotCorner',
 | 
			
		||||
 | 
			
		||||
HotCorner.prototype = {
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        // We use this flag to mark the case where the user has entered the
 | 
			
		||||
        // hot corner and has not left both the hot corner and a surrounding
 | 
			
		||||
@@ -381,7 +401,7 @@ HotCorner.prototype = {
 | 
			
		||||
 | 
			
		||||
        this.actor.add_actor(this._corner);
 | 
			
		||||
 | 
			
		||||
        if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
 | 
			
		||||
        if (Clutter.get_default_text_direction() == Clutter.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 {
 | 
			
		||||
@@ -410,9 +430,9 @@ HotCorner.prototype = {
 | 
			
		||||
                             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 });
 | 
			
		||||
        this._ripple1 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
 | 
			
		||||
        this._ripple2 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
 | 
			
		||||
        this._ripple3 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
 | 
			
		||||
 | 
			
		||||
        Main.uiGroup.add_actor(this._ripple1);
 | 
			
		||||
        Main.uiGroup.add_actor(this._ripple2);
 | 
			
		||||
@@ -433,7 +453,7 @@ HotCorner.prototype = {
 | 
			
		||||
 | 
			
		||||
        ripple._opacity = startOpacity;
 | 
			
		||||
 | 
			
		||||
        if (ripple.get_direction() == St.TextDirection.RTL)
 | 
			
		||||
        if (ripple.get_text_direction() == Clutter.TextDirection.RTL)
 | 
			
		||||
            ripple.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
 | 
			
		||||
 | 
			
		||||
        ripple.visible = true;
 | 
			
		||||
@@ -467,13 +487,15 @@ HotCorner.prototype = {
 | 
			
		||||
 | 
			
		||||
    handleDragOver: function(source, actor, x, y, time) {
 | 
			
		||||
        if (source != Main.xdndHandler)
 | 
			
		||||
            return;
 | 
			
		||||
            return DND.DragMotionResult.CONTINUE;
 | 
			
		||||
 | 
			
		||||
        if (!Main.overview.visible && !Main.overview.animationInProgress) {
 | 
			
		||||
            this.rippleAnimation();
 | 
			
		||||
            Main.overview.showTemporarily();
 | 
			
		||||
            Main.overview.beginItemDrag(actor);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return DND.DragMotionResult.CONTINUE;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onCornerEntered : function() {
 | 
			
		||||
@@ -521,7 +543,7 @@ HotCorner.prototype = {
 | 
			
		||||
            return true;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// This manages the shell "chrome"; the UI that's visible in the
 | 
			
		||||
@@ -529,26 +551,22 @@ HotCorner.prototype = {
 | 
			
		||||
// workspace content.
 | 
			
		||||
 | 
			
		||||
const defaultParams = {
 | 
			
		||||
    visibleInFullscreen: false,
 | 
			
		||||
    trackFullscreen: false,
 | 
			
		||||
    affectsStruts: false,
 | 
			
		||||
    affectsInputRegion: true
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function Chrome() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
const Chrome = new Lang.Class({
 | 
			
		||||
    Name: 'Chrome',
 | 
			
		||||
 | 
			
		||||
Chrome.prototype = {
 | 
			
		||||
    _init: function(layoutManager) {
 | 
			
		||||
        this._layoutManager = layoutManager;
 | 
			
		||||
 | 
			
		||||
        // 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._monitors = [];
 | 
			
		||||
        this._inOverview = false;
 | 
			
		||||
        this._isLocked = false;
 | 
			
		||||
        this._updateRegionIdle = 0;
 | 
			
		||||
        this._freezeUpdateCount = 0;
 | 
			
		||||
 | 
			
		||||
        this._trackedActors = [];
 | 
			
		||||
 | 
			
		||||
@@ -561,14 +579,6 @@ Chrome.prototype = {
 | 
			
		||||
        global.screen.connect('notify::n-workspaces',
 | 
			
		||||
                              Lang.bind(this, this._queueUpdateRegions));
 | 
			
		||||
 | 
			
		||||
        this._screenSaverProxy = new ScreenSaver.ScreenSaverProxy();
 | 
			
		||||
        this._screenSaverProxy.connect('ActiveChanged', Lang.bind(this, this._onScreenSaverActiveChanged));
 | 
			
		||||
        this._screenSaverProxy.GetActiveRemote(Lang.bind(this,
 | 
			
		||||
            function(result, err) {
 | 
			
		||||
                if (!err)
 | 
			
		||||
                    this._onScreenSaverActiveChanged(this._screenSaverProxy, result);
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        this._relayout();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -577,16 +587,12 @@ Chrome.prototype = {
 | 
			
		||||
                             Lang.bind(this, this._overviewShowing));
 | 
			
		||||
        Main.overview.connect('hidden',
 | 
			
		||||
                             Lang.bind(this, this._overviewHidden));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _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);
 | 
			
		||||
        Main.screenShield.connect('lock-status-changed',
 | 
			
		||||
                                  Lang.bind(this, this._lockStatusChanged));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addActor: function(actor, params) {
 | 
			
		||||
        this.actor.add_actor(actor);
 | 
			
		||||
        Main.uiGroup.add_actor(actor);
 | 
			
		||||
        this._trackActor(actor, params);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -598,7 +604,7 @@ Chrome.prototype = {
 | 
			
		||||
            index = this._findActor(ancestor);
 | 
			
		||||
        }
 | 
			
		||||
        if (!ancestor)
 | 
			
		||||
            throw new Error('actor is not a descendent of the chrome layer');
 | 
			
		||||
            throw new Error('actor is not a descendent of a chrome actor');
 | 
			
		||||
 | 
			
		||||
        let ancestorData = this._trackedActors[index];
 | 
			
		||||
        if (!params)
 | 
			
		||||
@@ -606,7 +612,7 @@ Chrome.prototype = {
 | 
			
		||||
        // We can't use Params.parse here because we want to drop
 | 
			
		||||
        // the extra values like ancestorData.actor
 | 
			
		||||
        for (let prop in defaultParams) {
 | 
			
		||||
            if (!params[prop])
 | 
			
		||||
            if (!params.hasOwnProperty(prop))
 | 
			
		||||
                params[prop] = ancestorData[prop];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -618,7 +624,7 @@ Chrome.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    removeActor: function(actor) {
 | 
			
		||||
        this.actor.remove_actor(actor);
 | 
			
		||||
        Main.uiGroup.remove_actor(actor);
 | 
			
		||||
        this._untrackActor(actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -637,6 +643,7 @@ Chrome.prototype = {
 | 
			
		||||
 | 
			
		||||
        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',
 | 
			
		||||
@@ -666,18 +673,28 @@ Chrome.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _actorReparented: function(actor, oldParent) {
 | 
			
		||||
        if (!this.actor.contains(actor))
 | 
			
		||||
        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];
 | 
			
		||||
            if (!this._inOverview && !actorData.visibleInFullscreen &&
 | 
			
		||||
                this._findMonitorForActor(actorData.actor).inFullscreen)
 | 
			
		||||
                this.actor.set_skip_paint(actorData.actor, true);
 | 
			
		||||
            let actorData = this._trackedActors[i], visible;
 | 
			
		||||
            if (!actorData.trackFullscreen)
 | 
			
		||||
                continue;
 | 
			
		||||
            if (!actorData.isToplevel)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (this._inOverview || this._isLocked)
 | 
			
		||||
                visible = true;
 | 
			
		||||
            else if (this.findMonitorForActor(actorData.actor).inFullscreen)
 | 
			
		||||
                visible = false;
 | 
			
		||||
            else
 | 
			
		||||
                this.actor.set_skip_paint(actorData.actor, false);
 | 
			
		||||
                visible = true;
 | 
			
		||||
            actorData.actor.visible = visible;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -693,6 +710,12 @@ Chrome.prototype = {
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _lockStatusChanged: function(shield, locked) {
 | 
			
		||||
        this._isLocked = locked;
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _relayout: function() {
 | 
			
		||||
        this._monitors = this._layoutManager.monitors;
 | 
			
		||||
        this._primaryMonitor = this._layoutManager.primaryMonitor;
 | 
			
		||||
@@ -702,11 +725,6 @@ Chrome.prototype = {
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onScreenSaverActiveChanged: function(proxy, screenSaverActive) {
 | 
			
		||||
        this.actor.visible = !screenSaverActive;
 | 
			
		||||
        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;
 | 
			
		||||
@@ -734,7 +752,7 @@ Chrome.prototype = {
 | 
			
		||||
 | 
			
		||||
    // This call guarantees that we return some monitor to simplify usage of it
 | 
			
		||||
    // In practice all tracked actors should be visible on some monitor anyway
 | 
			
		||||
    _findMonitorForActor: function(actor) {
 | 
			
		||||
    findMonitorForActor: function(actor) {
 | 
			
		||||
        let [x, y] = actor.get_transformed_position();
 | 
			
		||||
        let [w, h] = actor.get_transformed_size();
 | 
			
		||||
        let monitor = this._findMonitorForRect(x, y, w, h);
 | 
			
		||||
@@ -744,11 +762,22 @@ Chrome.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _queueUpdateRegions: function() {
 | 
			
		||||
        if (!this._updateRegionIdle)
 | 
			
		||||
        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());
 | 
			
		||||
 | 
			
		||||
@@ -756,7 +785,7 @@ Chrome.prototype = {
 | 
			
		||||
        for (let i = 0; i < this._monitors.length; i++)
 | 
			
		||||
            this._monitors[i].inFullscreen = false;
 | 
			
		||||
 | 
			
		||||
        // The chrome layer should be visible unless there is a window
 | 
			
		||||
        // 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
 | 
			
		||||
@@ -782,6 +811,18 @@ Chrome.prototype = {
 | 
			
		||||
                    monitor.inFullscreen = true;
 | 
			
		||||
            }
 | 
			
		||||
            if (layer == Meta.StackLayer.OVERRIDE_REDIRECT) {
 | 
			
		||||
                // Check whether the window is screen sized
 | 
			
		||||
                let isScreenSized =
 | 
			
		||||
                    (window.x == 0 && window.y == 0 &&
 | 
			
		||||
                    window.width == global.screen_width &&
 | 
			
		||||
                    window.height == global.screen_height);
 | 
			
		||||
 | 
			
		||||
                if (isScreenSized) {
 | 
			
		||||
                    for (let i = 0; i < this._monitors.length; i++)
 | 
			
		||||
                        this._monitors[i].inFullscreen = true;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Or whether it is monitor sized
 | 
			
		||||
                let monitor = this._findMonitorForWindow(window);
 | 
			
		||||
                if (monitor &&
 | 
			
		||||
                    window.x <= monitor.x &&
 | 
			
		||||
@@ -799,6 +840,8 @@ Chrome.prototype = {
 | 
			
		||||
        for (let i = 0; i < this._monitors.length; i++)
 | 
			
		||||
            wasInFullscreen[i] = this._monitors[i].inFullscreen;
 | 
			
		||||
 | 
			
		||||
        let primaryWasInFullscreen = this._primaryMonitor.inFullscreen;
 | 
			
		||||
 | 
			
		||||
        this._updateFullscreen();
 | 
			
		||||
 | 
			
		||||
        let changed = false;
 | 
			
		||||
@@ -808,10 +851,15 @@ Chrome.prototype = {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (changed) {
 | 
			
		||||
            this._updateVisibility();
 | 
			
		||||
            this._queueUpdateRegions();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (primaryWasInFullscreen != this._primaryMonitor.inFullscreen) {
 | 
			
		||||
            this.emit('primary-fullscreen-changed', this._primaryMonitor.inFullscreen);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    updateRegions: function() {
 | 
			
		||||
@@ -837,7 +885,7 @@ Chrome.prototype = {
 | 
			
		||||
 | 
			
		||||
            if (actorData.affectsInputRegion &&
 | 
			
		||||
                actorData.actor.get_paint_visibility() &&
 | 
			
		||||
                !this.actor.get_skip_paint(actorData.actor))
 | 
			
		||||
                !Main.uiGroup.get_skip_paint(actorData.actor))
 | 
			
		||||
                rects.push(rect);
 | 
			
		||||
 | 
			
		||||
            if (!actorData.affectsStruts)
 | 
			
		||||
@@ -925,4 +973,6 @@ Chrome.prototype = {
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(Chrome.prototype);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
@@ -7,6 +8,8 @@ const St = imports.gi.St;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
const DEFAULT_FADE_FACTOR = 0.4;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Lightbox:
 | 
			
		||||
 * @container: parent Clutter.Container
 | 
			
		||||
@@ -14,7 +17,8 @@ const Tweener = imports.ui.tweener;
 | 
			
		||||
 *           - inhibitEvents: whether to inhibit events for @container
 | 
			
		||||
 *           - width: shade actor width
 | 
			
		||||
 *           - height: shade actor height
 | 
			
		||||
 *           - fadeTime: seconds used to fade in/out
 | 
			
		||||
 *           - fadeInTime: seconds used to fade in
 | 
			
		||||
 *           - fadeOutTime: seconds used to fade out
 | 
			
		||||
 *
 | 
			
		||||
 * Lightbox creates a dark translucent "shade" actor to hide the
 | 
			
		||||
 * contents of @container, and allows you to specify particular actors
 | 
			
		||||
@@ -30,21 +34,23 @@ 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,
 | 
			
		||||
                                        height: null,
 | 
			
		||||
                                        fadeTime: null
 | 
			
		||||
                                        fadeInTime: null,
 | 
			
		||||
                                        fadeOutTime: null,
 | 
			
		||||
                                        fadeFactor: DEFAULT_FADE_FACTOR
 | 
			
		||||
                                      });
 | 
			
		||||
 | 
			
		||||
        this._container = container;
 | 
			
		||||
        this._children = container.get_children();
 | 
			
		||||
        this._fadeTime = params.fadeTime;
 | 
			
		||||
        this._fadeInTime = params.fadeInTime;
 | 
			
		||||
        this._fadeOutTime = params.fadeOutTime;
 | 
			
		||||
        this._fadeFactor = params.fadeFactor;
 | 
			
		||||
        this.actor = new St.Bin({ x: 0,
 | 
			
		||||
                                  y: 0,
 | 
			
		||||
                                  style_class: 'lightbox',
 | 
			
		||||
@@ -53,17 +59,17 @@ Lightbox.prototype = {
 | 
			
		||||
        container.add_actor(this.actor);
 | 
			
		||||
        this.actor.raise_top();
 | 
			
		||||
        this.actor.hide();
 | 
			
		||||
        this.shown = false;
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 | 
			
		||||
 | 
			
		||||
        if (params.width && params.height) {
 | 
			
		||||
            this.actor.width = params.width;
 | 
			
		||||
            this.actor.height = params.height;
 | 
			
		||||
            this._allocationChangedSignalId = 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            this.actor.width = container.width;
 | 
			
		||||
            this.actor.height = container.height;
 | 
			
		||||
            this._allocationChangedSignalId = container.connect('allocation-changed', Lang.bind(this, this._allocationChanged));
 | 
			
		||||
            let constraint = new Clutter.BindConstraint({ source: container,
 | 
			
		||||
                                                          coordinate: Clutter.BindCoordinate.ALL });
 | 
			
		||||
            this.actor.add_constraint(constraint);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._actorAddedSignalId = container.connect('actor-added', Lang.bind(this, this._actorAdded));
 | 
			
		||||
@@ -72,16 +78,6 @@ Lightbox.prototype = {
 | 
			
		||||
        this._highlighted = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _allocationChanged : function(container, box, flags) {
 | 
			
		||||
        Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
 | 
			
		||||
            this.actor.width = this.width;
 | 
			
		||||
            this.actor.height = this.height;
 | 
			
		||||
            return false;
 | 
			
		||||
        }));
 | 
			
		||||
        this.width = this._container.width;
 | 
			
		||||
        this.height = this._container.height;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _actorAdded : function(container, newChild) {
 | 
			
		||||
        let children = this._container.get_children();
 | 
			
		||||
        let myIndex = children.indexOf(this.actor);
 | 
			
		||||
@@ -105,24 +101,30 @@ Lightbox.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show: function() {
 | 
			
		||||
        if (this._fadeTime) {
 | 
			
		||||
        if (this._fadeInTime) {
 | 
			
		||||
            this.shown = false;
 | 
			
		||||
            this.actor.opacity = 0;
 | 
			
		||||
            Tweener.addTween(this.actor,
 | 
			
		||||
                             { opacity: 255,
 | 
			
		||||
                               time: this._fadeTime,
 | 
			
		||||
                               transition: 'easeOutQuad'
 | 
			
		||||
                             { opacity: 255 * this._fadeFactor,
 | 
			
		||||
                               time: this._fadeInTime,
 | 
			
		||||
                               transition: 'easeOutQuad',
 | 
			
		||||
                               onComplete: Lang.bind(this, function() {
 | 
			
		||||
                                   this.shown = true;
 | 
			
		||||
                               })
 | 
			
		||||
                             });
 | 
			
		||||
        } else {
 | 
			
		||||
            this.actor.opacity = 255;
 | 
			
		||||
            this.actor.opacity = 255 * this._fadeFactor;
 | 
			
		||||
            this.shown = true;
 | 
			
		||||
        }
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hide: function() {
 | 
			
		||||
        if (this._fadeTime) {
 | 
			
		||||
        this.shown = false;
 | 
			
		||||
        if (this._fadeOutTime) {
 | 
			
		||||
            Tweener.addTween(this.actor,
 | 
			
		||||
                             { opacity: 0,
 | 
			
		||||
                               time: this._fadeTime,
 | 
			
		||||
                               time: this._fadeOutTime,
 | 
			
		||||
                               transition: 'easeOutQuad',
 | 
			
		||||
                               onComplete: Lang.bind(this, function() {
 | 
			
		||||
                                   this.actor.hide();
 | 
			
		||||
@@ -189,11 +191,9 @@ Lightbox.prototype = {
 | 
			
		||||
     * by destroying its container or by explicitly calling this.destroy().
 | 
			
		||||
     */
 | 
			
		||||
    _onDestroy: function() {
 | 
			
		||||
        if (this._allocationChangedSignalId != 0)
 | 
			
		||||
            this._container.disconnect(this._allocationChangedSignalId);
 | 
			
		||||
        this._container.disconnect(this._actorAddedSignalId);
 | 
			
		||||
        this._container.disconnect(this._actorRemovedSignalId);
 | 
			
		||||
 | 
			
		||||
        this.highlight(null);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,24 +0,0 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
function Link(props) {
 | 
			
		||||
    this._init(props);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Link.prototype = {
 | 
			
		||||
    _init : function(props) {
 | 
			
		||||
        let realProps = { reactive: true,
 | 
			
		||||
                          track_hover: true,
 | 
			
		||||
                          style_class: 'shell-link' };
 | 
			
		||||
        // The user can pass in reactive: false to override the above and get
 | 
			
		||||
        // a non-reactive link (a link to the current page, perhaps)
 | 
			
		||||
        Lang.copyProperties(props, realProps);
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.Button(realProps);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(Link.prototype);
 | 
			
		||||
@@ -1,23 +1,28 @@
 | 
			
		||||
/* -*- 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 System = imports.system;
 | 
			
		||||
 | 
			
		||||
const History = imports.misc.history;
 | 
			
		||||
const ExtensionSystem = imports.ui.extensionSystem;
 | 
			
		||||
const Link = imports.ui.link;
 | 
			
		||||
const ExtensionUtils = imports.misc.extensionUtils;
 | 
			
		||||
const ShellEntry = imports.ui.shellEntry;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const JsParse = imports.misc.jsParse;
 | 
			
		||||
 | 
			
		||||
const CHEVRON = '>>> ';
 | 
			
		||||
 | 
			
		||||
/* Imports...feel free to add here as needed */
 | 
			
		||||
var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
 | 
			
		||||
@@ -35,16 +40,92 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
 | 
			
		||||
                    'const stage = global.stage; ' +
 | 
			
		||||
                    'const color = function(pixel) { let c= new Clutter.Color(); c.from_pixel(pixel); return c; }; ' +
 | 
			
		||||
                    /* Special lookingGlass functions */
 | 
			
		||||
                       'const it = Main.lookingGlass.getIt(); ' +
 | 
			
		||||
                    'const it = Main.lookingGlass.getIt(); ' +
 | 
			
		||||
                    '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 });
 | 
			
		||||
 | 
			
		||||
@@ -149,27 +230,41 @@ 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);
 | 
			
		||||
}
 | 
			
		||||
const ObjLink = new Lang.Class({
 | 
			
		||||
    Name: 'ObjLink',
 | 
			
		||||
 | 
			
		||||
ObjLink.prototype = {
 | 
			
		||||
    __proto__: Link.Link,
 | 
			
		||||
 | 
			
		||||
    _init: function(o, title) {
 | 
			
		||||
    _init: function(lookingGlass, o, title) {
 | 
			
		||||
        let text;
 | 
			
		||||
        if (title)
 | 
			
		||||
            text = title;
 | 
			
		||||
@@ -177,26 +272,31 @@ ObjLink.prototype = {
 | 
			
		||||
            text = objectToString(o);
 | 
			
		||||
        text = GLib.markup_escape_text(text, -1);
 | 
			
		||||
        this._obj = o;
 | 
			
		||||
        Link.Link.prototype._init.call(this, { label: text });
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.Button({ reactive: true,
 | 
			
		||||
                                     track_hover: true,
 | 
			
		||||
                                     style_class: 'shell-link',
 | 
			
		||||
                                     label: text });
 | 
			
		||||
        this.actor.get_child().single_line_mode = true;
 | 
			
		||||
        this.actor.connect('clicked', Lang.bind(this, this._onClicked));
 | 
			
		||||
 | 
			
		||||
        this._lookingGlass = lookingGlass;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onClicked: function (link) {
 | 
			
		||||
        Main.lookingGlass.inspectObject(this._obj, this.actor);
 | 
			
		||||
        this._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) {
 | 
			
		||||
    _init: function(lookingGlass, command, o, index) {
 | 
			
		||||
        this.index = index;
 | 
			
		||||
        this.o = o;
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        this._lookingGlass = lookingGlass;
 | 
			
		||||
 | 
			
		||||
        let cmdTxt = new St.Label({ text: command });
 | 
			
		||||
        cmdTxt.clutter_text.ellipsize = Pango.EllipsizeMode.END;
 | 
			
		||||
@@ -206,30 +306,30 @@ Result.prototype = {
 | 
			
		||||
        let resultTxt = new St.Label({ text: 'r(' + index + ') = ' });
 | 
			
		||||
        resultTxt.clutter_text.ellipsize = Pango.EllipsizeMode.END;
 | 
			
		||||
        box.add(resultTxt);
 | 
			
		||||
        let objLink = new ObjLink(o);
 | 
			
		||||
        let objLink = new ObjLink(this._lookingGlass, o);
 | 
			
		||||
        box.add(objLink.actor);
 | 
			
		||||
        let line = new Clutter.Rectangle({ name: 'Separator' });
 | 
			
		||||
        let padBin = new St.Bin({ name: 'Separator', x_fill: true, y_fill: true });
 | 
			
		||||
        padBin.add_actor(line);
 | 
			
		||||
        this.actor.add(padBin);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function WindowList() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const WindowList = new Lang.Class({
 | 
			
		||||
    Name: 'WindowList',
 | 
			
		||||
 | 
			
		||||
WindowList.prototype = {
 | 
			
		||||
    _init : function () {
 | 
			
		||||
    _init: function(lookingGlass) {
 | 
			
		||||
        this.actor = new St.BoxLayout({ name: 'Windows', vertical: true, style: 'spacing: 8px' });
 | 
			
		||||
        let tracker = Shell.WindowTracker.get_default();
 | 
			
		||||
        this._updateId = Main.initializeDeferredWork(this.actor, 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));
 | 
			
		||||
 | 
			
		||||
        this._lookingGlass = lookingGlass;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateWindowList: function() {
 | 
			
		||||
        this.actor.get_children().forEach(function (actor) { actor.destroy(); });
 | 
			
		||||
        this.actor.destroy_all_children();
 | 
			
		||||
        let windows = global.get_window_actors();
 | 
			
		||||
        let tracker = Shell.WindowTracker.get_default();
 | 
			
		||||
        for (let i = 0; i < windows.length; i++) {
 | 
			
		||||
@@ -241,7 +341,7 @@ WindowList.prototype = {
 | 
			
		||||
            }
 | 
			
		||||
            let box = new St.BoxLayout({ vertical: true });
 | 
			
		||||
            this.actor.add(box);
 | 
			
		||||
            let windowLink = new ObjLink(metaWindow, metaWindow.title);
 | 
			
		||||
            let windowLink = new ObjLink(this._lookingGlass, metaWindow, metaWindow.title);
 | 
			
		||||
            box.add(windowLink.actor, { x_align: St.Align.START, x_fill: false });
 | 
			
		||||
            let propsBox = new St.BoxLayout({ vertical: true, style: 'padding-left: 6px;' });
 | 
			
		||||
            box.add(propsBox);
 | 
			
		||||
@@ -252,7 +352,7 @@ WindowList.prototype = {
 | 
			
		||||
                let propBox = new St.BoxLayout({ style: 'spacing: 6px; ' });
 | 
			
		||||
                propsBox.add(propBox);
 | 
			
		||||
                propBox.add(new St.Label({ text: 'app: ' }), { y_fill: false });
 | 
			
		||||
                let appLink = new ObjLink(app, app.get_id());
 | 
			
		||||
                let appLink = new ObjLink(this._lookingGlass, app, app.get_id());
 | 
			
		||||
                propBox.add(appLink.actor, { y_fill: false });
 | 
			
		||||
                propBox.add(icon, { y_fill: false });
 | 
			
		||||
            } else {
 | 
			
		||||
@@ -260,15 +360,13 @@ WindowList.prototype = {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(WindowList.prototype);
 | 
			
		||||
 | 
			
		||||
function ObjInspector() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const ObjInspector = new Lang.Class({
 | 
			
		||||
    Name: 'ObjInspector',
 | 
			
		||||
 | 
			
		||||
ObjInspector.prototype = {
 | 
			
		||||
    _init : function () {
 | 
			
		||||
    _init: function(lookingGlass) {
 | 
			
		||||
        this._obj = null;
 | 
			
		||||
        this._previousObj = null;
 | 
			
		||||
 | 
			
		||||
@@ -280,6 +378,8 @@ ObjInspector.prototype = {
 | 
			
		||||
                                             style_class: 'lg-dialog',
 | 
			
		||||
                                             vertical: true });
 | 
			
		||||
        this.actor.add_actor(this._container);
 | 
			
		||||
 | 
			
		||||
        this._lookingGlass = lookingGlass;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    selectObject: function(obj, skipPrevious) {
 | 
			
		||||
@@ -289,7 +389,7 @@ ObjInspector.prototype = {
 | 
			
		||||
            this._previousObj = null;
 | 
			
		||||
        this._obj = obj;
 | 
			
		||||
 | 
			
		||||
        this._container.get_children().forEach(function (child) { child.destroy(); });
 | 
			
		||||
        this._container.destroy_all_children();
 | 
			
		||||
 | 
			
		||||
        let hbox = new St.BoxLayout({ style_class: 'lg-obj-inspector-title' });
 | 
			
		||||
        this._container.add_actor(hbox);
 | 
			
		||||
@@ -311,17 +411,24 @@ ObjInspector.prototype = {
 | 
			
		||||
        button.connect('clicked', Lang.bind(this, this.close));
 | 
			
		||||
        hbox.add(button);
 | 
			
		||||
        if (typeof(obj) == typeof({})) {
 | 
			
		||||
            let properties = [];
 | 
			
		||||
            for (let propName in obj) {
 | 
			
		||||
                properties.push(propName);
 | 
			
		||||
            }
 | 
			
		||||
            properties.sort();
 | 
			
		||||
 | 
			
		||||
            for (let i = 0; i < properties.length; i++) {
 | 
			
		||||
                let propName = properties[i];
 | 
			
		||||
                let valueStr;
 | 
			
		||||
                let link;
 | 
			
		||||
                try {
 | 
			
		||||
                    let prop = obj[propName];
 | 
			
		||||
                    link = new ObjLink(prop).actor;
 | 
			
		||||
                    link = new ObjLink(this._lookingGlass, prop).actor;
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
                    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);
 | 
			
		||||
@@ -342,7 +449,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,44 +468,44 @@ ObjInspector.prototype = {
 | 
			
		||||
    _onInsert: function() {
 | 
			
		||||
        let obj = this._obj;
 | 
			
		||||
        this.close();
 | 
			
		||||
        Main.lookingGlass.insertObject(obj);
 | 
			
		||||
        this._lookingGlass.insertObject(obj);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onBack: function() {
 | 
			
		||||
        this.selectObject(this._previousObj, true);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function addBorderPaintHook(actor) {
 | 
			
		||||
    let signalId = actor.connect_after('paint',
 | 
			
		||||
        function () {
 | 
			
		||||
            let color = new Cogl.Color();
 | 
			
		||||
            color.init_from_4ub(0xff, 0, 0, 0xc4);
 | 
			
		||||
            Cogl.set_source_color(color);
 | 
			
		||||
const RedBorderEffect = new Lang.Class({
 | 
			
		||||
    Name: 'RedBorderEffect',
 | 
			
		||||
    Extends: Clutter.Effect,
 | 
			
		||||
 | 
			
		||||
            let geom = actor.get_allocation_geometry();
 | 
			
		||||
            let width = 2;
 | 
			
		||||
    vfunc_paint: function() {
 | 
			
		||||
        let actor = this.get_actor();
 | 
			
		||||
        actor.continue_paint();
 | 
			
		||||
 | 
			
		||||
            // clockwise order
 | 
			
		||||
            Cogl.rectangle(0, 0, geom.width, width);
 | 
			
		||||
            Cogl.rectangle(geom.width - width, width,
 | 
			
		||||
                           geom.width, geom.height);
 | 
			
		||||
            Cogl.rectangle(0, geom.height,
 | 
			
		||||
                           geom.width - width, geom.height - width);
 | 
			
		||||
            Cogl.rectangle(0, geom.height - width,
 | 
			
		||||
                           width, width);
 | 
			
		||||
        });
 | 
			
		||||
        let color = new Cogl.Color();
 | 
			
		||||
        color.init_from_4ub(0xff, 0, 0, 0xc4);
 | 
			
		||||
        Cogl.set_source_color(color);
 | 
			
		||||
 | 
			
		||||
    actor.queue_redraw();
 | 
			
		||||
    return signalId;
 | 
			
		||||
}
 | 
			
		||||
        let geom = actor.get_allocation_geometry();
 | 
			
		||||
        let width = 2;
 | 
			
		||||
 | 
			
		||||
function Inspector() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
        // clockwise order
 | 
			
		||||
        Cogl.rectangle(0, 0, geom.width, width);
 | 
			
		||||
        Cogl.rectangle(geom.width - width, width,
 | 
			
		||||
                       geom.width, geom.height);
 | 
			
		||||
        Cogl.rectangle(0, geom.height,
 | 
			
		||||
                       geom.width - width, geom.height - width);
 | 
			
		||||
        Cogl.rectangle(0, geom.height - width,
 | 
			
		||||
                       width, width);
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Inspector.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
const Inspector = new Lang.Class({
 | 
			
		||||
    Name: 'Inspector',
 | 
			
		||||
 | 
			
		||||
    _init: function(lookingGlass) {
 | 
			
		||||
        let container = new Shell.GenericContainer({ width: 0,
 | 
			
		||||
                                                     height: 0 });
 | 
			
		||||
        container.connect('allocate', Lang.bind(this, this._allocate));
 | 
			
		||||
@@ -412,9 +519,6 @@ Inspector.prototype = {
 | 
			
		||||
        this._displayText = new St.Label();
 | 
			
		||||
        eventHandler.add(this._displayText, { expand: true });
 | 
			
		||||
 | 
			
		||||
        this._borderPaintTarget = null;
 | 
			
		||||
        this._borderPaintId = null;
 | 
			
		||||
        eventHandler.connect('destroy', Lang.bind(this, this._onDestroy));
 | 
			
		||||
        eventHandler.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
 | 
			
		||||
        eventHandler.connect('button-press-event', Lang.bind(this, this._onButtonPressEvent));
 | 
			
		||||
        eventHandler.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
 | 
			
		||||
@@ -429,6 +533,8 @@ Inspector.prototype = {
 | 
			
		||||
        // out, or move the pointer outside of _pointerTarget.
 | 
			
		||||
        this._target = null;
 | 
			
		||||
        this._pointerTarget = null;
 | 
			
		||||
 | 
			
		||||
        this._lookingGlass = lookingGlass;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _allocate: function(actor, box, flags) {
 | 
			
		||||
@@ -449,18 +555,13 @@ Inspector.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _close: function() {
 | 
			
		||||
        Clutter.ungrab_pointer(this._eventHandler);
 | 
			
		||||
        Clutter.ungrab_keyboard(this._eventHandler);
 | 
			
		||||
        Clutter.ungrab_pointer();
 | 
			
		||||
        Clutter.ungrab_keyboard();
 | 
			
		||||
        this._eventHandler.destroy();
 | 
			
		||||
        this._eventHandler = null;
 | 
			
		||||
        this.emit('closed');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDestroy: function() {
 | 
			
		||||
        if (this._borderPaintTarget != null)
 | 
			
		||||
            this._borderPaintTarget.disconnect(this._borderPaintId);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeyPressEvent: function (actor, event) {
 | 
			
		||||
        if (event.get_key_symbol() == Clutter.Escape)
 | 
			
		||||
            this._close();
 | 
			
		||||
@@ -529,63 +630,15 @@ Inspector.prototype = {
 | 
			
		||||
        this._displayText.text = '';
 | 
			
		||||
        this._displayText.text = position + ' ' + this._target;
 | 
			
		||||
 | 
			
		||||
        if (this._borderPaintTarget != this._target) {
 | 
			
		||||
            if (this._borderPaintTarget != null)
 | 
			
		||||
                this._borderPaintTarget.disconnect(this._borderPaintId);
 | 
			
		||||
            this._borderPaintTarget = this._target;
 | 
			
		||||
            this._borderPaintId = addBorderPaintHook(this._target);
 | 
			
		||||
        }
 | 
			
		||||
        this._lookingGlass.setBorderPaintTarget(this._target);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(Inspector.prototype);
 | 
			
		||||
 | 
			
		||||
function ErrorLog() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const Memory = new Lang.Class({
 | 
			
		||||
    Name: 'Memory',
 | 
			
		||||
 | 
			
		||||
ErrorLog.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.actor = new St.BoxLayout();
 | 
			
		||||
        this.text = new St.Label();
 | 
			
		||||
        this.actor.add(this.text);
 | 
			
		||||
        // We need to override StLabel's default ellipsization when
 | 
			
		||||
        // using line_wrap; otherwise ClutterText's layout is going
 | 
			
		||||
        // to constrain both the width and height, which prevents
 | 
			
		||||
        // scrolling.
 | 
			
		||||
        this.text.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
 | 
			
		||||
        this.text.clutter_text.line_wrap = true;
 | 
			
		||||
        this.actor.connect('notify::mapped', Lang.bind(this, this._renderText));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _formatTime: function(d){
 | 
			
		||||
        function pad(n) { return n < 10 ? '0' + n : n; }
 | 
			
		||||
        return d.getUTCFullYear()+'-'
 | 
			
		||||
            + pad(d.getUTCMonth()+1)+'-'
 | 
			
		||||
            + pad(d.getUTCDate())+'T'
 | 
			
		||||
            + pad(d.getUTCHours())+':'
 | 
			
		||||
            + pad(d.getUTCMinutes())+':'
 | 
			
		||||
            + pad(d.getUTCSeconds())+'Z';
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _renderText: function() {
 | 
			
		||||
        if (!this.actor.mapped)
 | 
			
		||||
            return;
 | 
			
		||||
        let text = this.text.text;
 | 
			
		||||
        let stack = Main._getAndClearErrorStack();
 | 
			
		||||
        for (let i = 0; i < stack.length; i++) {
 | 
			
		||||
            let logItem = stack[i];
 | 
			
		||||
            text += logItem.category + ' t=' + this._formatTime(new Date(logItem.timestamp)) + ' ' + logItem.message + '\n';
 | 
			
		||||
        }
 | 
			
		||||
        this.text.text = text;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function Memory() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Memory.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.actor = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        this._glibc_uordblks = new St.Label();
 | 
			
		||||
@@ -606,9 +659,12 @@ Memory.prototype = {
 | 
			
		||||
        this._gjs_closure = new St.Label();
 | 
			
		||||
        this.actor.add(this._gjs_closure);
 | 
			
		||||
 | 
			
		||||
        this._last_gc_seconds_ago = new St.Label();
 | 
			
		||||
        this.actor.add(this._last_gc_seconds_ago);
 | 
			
		||||
 | 
			
		||||
        this._gcbutton = new St.Button({ label: 'Full GC',
 | 
			
		||||
                                         style_class: 'lg-obj-inspector-button' });
 | 
			
		||||
        this._gcbutton.connect('clicked', Lang.bind(this, function () { global.gc(); this._renderText(); }));
 | 
			
		||||
        this._gcbutton.connect('clicked', Lang.bind(this, function () { System.gc(); this._renderText(); }));
 | 
			
		||||
        this.actor.add(this._gcbutton, { x_align: St.Align.START,
 | 
			
		||||
                                         x_fill: false });
 | 
			
		||||
 | 
			
		||||
@@ -625,14 +681,13 @@ Memory.prototype = {
 | 
			
		||||
        this._gjs_gobject.text = 'gjs_gobject: ' + memInfo.gjs_gobject;
 | 
			
		||||
        this._gjs_function.text = 'gjs_function: ' + memInfo.gjs_function;
 | 
			
		||||
        this._gjs_closure.text = 'gjs_closure: ' + memInfo.gjs_closure;
 | 
			
		||||
        this._last_gc_seconds_ago.text = 'last_gc_seconds_ago: ' + memInfo.last_gc_seconds_ago;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function Extensions() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const Extensions = new Lang.Class({
 | 
			
		||||
    Name: 'Extensions',
 | 
			
		||||
 | 
			
		||||
Extensions.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.actor = new St.BoxLayout({ vertical: true,
 | 
			
		||||
                                        name: 'lookingGlassExtensions' });
 | 
			
		||||
@@ -644,7 +699,7 @@ Extensions.prototype = {
 | 
			
		||||
        this._extensionsList.add(this._noExtensions);
 | 
			
		||||
        this.actor.add(this._extensionsList);
 | 
			
		||||
 | 
			
		||||
        for (let uuid in ExtensionSystem.extensionMeta)
 | 
			
		||||
        for (let uuid in ExtensionUtils.extensions)
 | 
			
		||||
            this._loadExtension(null, uuid);
 | 
			
		||||
 | 
			
		||||
        ExtensionSystem.connect('extension-loaded',
 | 
			
		||||
@@ -652,10 +707,10 @@ Extensions.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _loadExtension: function(o, uuid) {
 | 
			
		||||
        let extension = ExtensionSystem.extensionMeta[uuid];
 | 
			
		||||
        let extension = ExtensionUtils.extensions[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)
 | 
			
		||||
        if (!extension.metadata.name)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let extensionDisplay = this._createExtensionDisplay(extension);
 | 
			
		||||
@@ -667,17 +722,44 @@ Extensions.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onViewSource: function (actor) {
 | 
			
		||||
        let meta = actor._extensionMeta;
 | 
			
		||||
        let file = Gio.file_new_for_path(meta.path);
 | 
			
		||||
        let uri = file.get_uri();
 | 
			
		||||
        let extension = actor._extension;
 | 
			
		||||
        let uri = extension.dir.get_uri();
 | 
			
		||||
        Gio.app_info_launch_default_for_uri(uri, global.create_app_launch_context());
 | 
			
		||||
        Main.lookingGlass.close();
 | 
			
		||||
        this._lookingGlass.close();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onWebPage: function (actor) {
 | 
			
		||||
        let meta = actor._extensionMeta;
 | 
			
		||||
        Gio.app_info_launch_default_for_uri(meta.url, global.create_app_launch_context());
 | 
			
		||||
        Main.lookingGlass.close();
 | 
			
		||||
        let extension = actor._extension;
 | 
			
		||||
        Gio.app_info_launch_default_for_uri(extension.metadata.url, global.create_app_launch_context());
 | 
			
		||||
        this._lookingGlass.close();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onViewErrors: function (actor) {
 | 
			
		||||
        let extension = actor._extension;
 | 
			
		||||
        let shouldShow = !actor._isShowing;
 | 
			
		||||
 | 
			
		||||
        if (shouldShow) {
 | 
			
		||||
            let errors = extension.errors;
 | 
			
		||||
            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(extension.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) {
 | 
			
		||||
@@ -685,6 +767,7 @@ Extensions.prototype = {
 | 
			
		||||
            case ExtensionSystem.ExtensionState.ENABLED:
 | 
			
		||||
                return _("Enabled");
 | 
			
		||||
            case ExtensionSystem.ExtensionState.DISABLED:
 | 
			
		||||
            case ExtensionSystem.ExtensionState.INITIALIZED:
 | 
			
		||||
                return _("Disabled");
 | 
			
		||||
            case ExtensionSystem.ExtensionState.ERROR:
 | 
			
		||||
                return _("Error");
 | 
			
		||||
@@ -696,51 +779,60 @@ Extensions.prototype = {
 | 
			
		||||
        return 'Unknown'; // Not translated, shouldn't appear
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createExtensionDisplay: function(meta) {
 | 
			
		||||
    _createExtensionDisplay: function(extension) {
 | 
			
		||||
        let box = new St.BoxLayout({ style_class: 'lg-extension', vertical: true });
 | 
			
		||||
        let name = new St.Label({ style_class: 'lg-extension-name',
 | 
			
		||||
                                   text: meta.name });
 | 
			
		||||
                                   text: extension.metadata.name });
 | 
			
		||||
        box.add(name, { expand: true });
 | 
			
		||||
        let description = new St.Label({ style_class: 'lg-extension-description',
 | 
			
		||||
                                         text: meta.description || 'No description' });
 | 
			
		||||
                                         text: extension.metadata.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 stateString = this._stateToString(extension.state);
 | 
			
		||||
        let state = new St.Label({ style_class: 'lg-extension-state',
 | 
			
		||||
                                   text: this._stateToString(meta.state) });
 | 
			
		||||
                                   text: this._stateToString(extension.state) });
 | 
			
		||||
        metaBox.add(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);
 | 
			
		||||
        let viewsource = new St.Button({ reactive: true,
 | 
			
		||||
                                         track_hover: true,
 | 
			
		||||
                                         style_class: 'shell-link',
 | 
			
		||||
                                         label: _("View Source") });
 | 
			
		||||
        viewsource._extension = extension;
 | 
			
		||||
        viewsource.connect('clicked', Lang.bind(this, this._onViewSource));
 | 
			
		||||
        metaBox.add(viewsource);
 | 
			
		||||
 | 
			
		||||
        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);
 | 
			
		||||
 | 
			
		||||
        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);
 | 
			
		||||
        if (extension.metadata.url) {
 | 
			
		||||
            let webpage = new St.Button({ reactive: true,
 | 
			
		||||
                                          track_hover: true,
 | 
			
		||||
                                          style_class: 'shell-link',
 | 
			
		||||
                                          label: _("Web Page") });
 | 
			
		||||
            webpage._extension = extension;
 | 
			
		||||
            webpage.connect('clicked', Lang.bind(this, this._onWebPage));
 | 
			
		||||
            metaBox.add(webpage);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let viewerrors = new St.Button({ reactive: true,
 | 
			
		||||
                                         track_hover: true,
 | 
			
		||||
                                         style_class: 'shell-link',
 | 
			
		||||
                                         label: _("Show Errors") });
 | 
			
		||||
        viewerrors._extension = extension;
 | 
			
		||||
        viewerrors._parentBox = box;
 | 
			
		||||
        viewerrors._isShowing = false;
 | 
			
		||||
        viewerrors.connect('clicked', Lang.bind(this, this._onViewErrors));
 | 
			
		||||
        metaBox.add(viewerrors);
 | 
			
		||||
 | 
			
		||||
        return box;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function LookingGlass() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const LookingGlass = new Lang.Class({
 | 
			
		||||
    Name: 'LookingGlass',
 | 
			
		||||
 | 
			
		||||
LookingGlass.prototype = {
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        this._borderPaintTarget = null;
 | 
			
		||||
        this._borderPaintId = 0;
 | 
			
		||||
        this._borderDestroyId = 0;
 | 
			
		||||
        this._redBorderEffect = new RedBorderEffect();
 | 
			
		||||
 | 
			
		||||
        this._open = false;
 | 
			
		||||
 | 
			
		||||
@@ -753,7 +845,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' });
 | 
			
		||||
@@ -761,11 +854,15 @@ LookingGlass.prototype = {
 | 
			
		||||
                                        Lang.bind(this, this._updateFont));
 | 
			
		||||
        this._updateFont();
 | 
			
		||||
 | 
			
		||||
        // we add it to the chrome because we want it to appear to slide
 | 
			
		||||
        // out from underneath the panel
 | 
			
		||||
        Main.layoutManager.addChrome(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();
 | 
			
		||||
        this._objInspector = new ObjInspector(this);
 | 
			
		||||
        Main.uiGroup.add_actor(this._objInspector.actor);
 | 
			
		||||
        this._objInspector.actor.hide();
 | 
			
		||||
 | 
			
		||||
@@ -777,7 +874,7 @@ LookingGlass.prototype = {
 | 
			
		||||
        toolbar.add_actor(inspectIcon);
 | 
			
		||||
        inspectIcon.reactive = true;
 | 
			
		||||
        inspectIcon.connect('button-press-event', Lang.bind(this, function () {
 | 
			
		||||
            let inspector = new Inspector();
 | 
			
		||||
            let inspector = new Inspector(this);
 | 
			
		||||
            inspector.connect('target', Lang.bind(this, function(i, target, stageX, stageY) {
 | 
			
		||||
                this._pushResult('<inspect x:' + stageX + ' y:' + stageY + '>',
 | 
			
		||||
                                 target);
 | 
			
		||||
@@ -804,25 +901,19 @@ 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);
 | 
			
		||||
        let label = new St.Label({ text: CHEVRON });
 | 
			
		||||
        this._entryArea.add(label);
 | 
			
		||||
 | 
			
		||||
        this._entry = new St.Entry({ can_focus: true });
 | 
			
		||||
        entryArea.add(this._entry, { expand: true });
 | 
			
		||||
        ShellEntry.addContextMenu(this._entry);
 | 
			
		||||
        this._entryArea.add(this._entry, { expand: true });
 | 
			
		||||
 | 
			
		||||
        this._windowList = new WindowList();
 | 
			
		||||
        this._windowList.connect('selected', Lang.bind(this, function(list, window) {
 | 
			
		||||
            notebook.selectIndex(0);
 | 
			
		||||
            this._pushResult('<window selection>', window);
 | 
			
		||||
        }));
 | 
			
		||||
        this._windowList = new WindowList(this);
 | 
			
		||||
        notebook.appendPage('Windows', this._windowList.actor);
 | 
			
		||||
 | 
			
		||||
        this._errorLog = new ErrorLog();
 | 
			
		||||
        notebook.appendPage('Errors', this._errorLog.actor);
 | 
			
		||||
 | 
			
		||||
        this._memory = new Memory();
 | 
			
		||||
        notebook.appendPage('Memory', this._memory.actor);
 | 
			
		||||
 | 
			
		||||
@@ -830,6 +921,9 @@ LookingGlass.prototype = {
 | 
			
		||||
        notebook.appendPage('Extensions', this._extensions.actor);
 | 
			
		||||
 | 
			
		||||
        this._entry.clutter_text.connect('activate', Lang.bind(this, function (o, e) {
 | 
			
		||||
            // Hide any completions we are currently showing
 | 
			
		||||
            this._hideCompletions();
 | 
			
		||||
 | 
			
		||||
            let text = o.get_text();
 | 
			
		||||
            // Ensure we don't get newlines in the command; the history file is
 | 
			
		||||
            // newline-separated.
 | 
			
		||||
@@ -844,6 +938,19 @@ LookingGlass.prototype = {
 | 
			
		||||
 | 
			
		||||
        this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY, 
 | 
			
		||||
                                                     entry: this._entry.clutter_text });
 | 
			
		||||
 | 
			
		||||
        this._autoComplete = new AutoComplete(this._entry);
 | 
			
		||||
        this._autoComplete.connect('suggest', Lang.bind(this, function(a,e) {
 | 
			
		||||
            this._showCompletions(e.completions);
 | 
			
		||||
        }));
 | 
			
		||||
        // If a completion is completed unambiguously, the currently-displayed completion
 | 
			
		||||
        // suggestions become irrelevant.
 | 
			
		||||
        this._autoComplete.connect('completion', Lang.bind(this, function(a,e) {
 | 
			
		||||
            if (e.type == 'whole-word')
 | 
			
		||||
                this._hideCompletions();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        this._resize();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateFont: function() {
 | 
			
		||||
@@ -858,23 +965,22 @@ LookingGlass.prototype = {
 | 
			
		||||
            + 'font-family: "' + fontDesc.get_family() + '";';
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setBorderPaintTarget: function(obj) {
 | 
			
		||||
        if (this._borderPaintTarget != null)
 | 
			
		||||
            this._borderPaintTarget.remove_effect(this._redBorderEffect);
 | 
			
		||||
        this._borderPaintTarget = obj;
 | 
			
		||||
        if (this._borderPaintTarget != null)
 | 
			
		||||
            this._borderPaintTarget.add_effect(this._redBorderEffect);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _pushResult: function(command, obj) {
 | 
			
		||||
        let index = this._results.length + this._offset;
 | 
			
		||||
        let result = new Result('>>> ' + command, obj, index);
 | 
			
		||||
        let result = new Result(this, CHEVRON + command, obj, index);
 | 
			
		||||
        this._results.push(result);
 | 
			
		||||
        this._resultsArea.add(result.actor);
 | 
			
		||||
        if (this._borderPaintTarget != null) {
 | 
			
		||||
            this._borderPaintTarget.disconnect(this._borderPaintId);
 | 
			
		||||
            this._borderPaintTarget = null;
 | 
			
		||||
        }
 | 
			
		||||
        if (obj instanceof Clutter.Actor) {
 | 
			
		||||
            this._borderPaintTarget = obj;
 | 
			
		||||
            this._borderPaintId = addBorderPaintHook(obj);
 | 
			
		||||
            this._borderDestroyId = obj.connect('destroy', Lang.bind(this, function () {
 | 
			
		||||
                this._borderDestroyId = 0;
 | 
			
		||||
                this._borderPaintTarget = null;
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
        if (obj instanceof Clutter.Actor)
 | 
			
		||||
            this.setBorderPaintTarget(obj);
 | 
			
		||||
 | 
			
		||||
        let children = this._resultsArea.get_children();
 | 
			
		||||
        if (children.length > this._maxItems) {
 | 
			
		||||
            this._results.shift();
 | 
			
		||||
@@ -887,6 +993,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_child_below(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);
 | 
			
		||||
 | 
			
		||||
@@ -918,13 +1077,18 @@ LookingGlass.prototype = {
 | 
			
		||||
            this.open();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _resizeTo: function(actor) {
 | 
			
		||||
    _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;
 | 
			
		||||
@@ -934,14 +1098,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);
 | 
			
		||||
    },
 | 
			
		||||
@@ -954,6 +1110,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 = event.get_state();
 | 
			
		||||
        if (symbol == Clutter.Escape) {
 | 
			
		||||
            if (this._objInspector.actor.visible) {
 | 
			
		||||
                this._objInspector.close();
 | 
			
		||||
@@ -962,6 +1119,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;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -974,7 +1139,6 @@ LookingGlass.prototype = {
 | 
			
		||||
 | 
			
		||||
        this._notebook.selectIndex(0);
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
        this.actor.lower_bottom();
 | 
			
		||||
        this._open = true;
 | 
			
		||||
        this._history.lastItem();
 | 
			
		||||
 | 
			
		||||
@@ -997,15 +1161,10 @@ LookingGlass.prototype = {
 | 
			
		||||
        this._open = false;
 | 
			
		||||
        Tweener.removeTweens(this.actor);
 | 
			
		||||
 | 
			
		||||
        if (this._borderPaintTarget != null) {
 | 
			
		||||
            this._borderPaintTarget.disconnect(this._borderPaintId);
 | 
			
		||||
            this._borderPaintTarget.disconnect(this._borderDestroyId);
 | 
			
		||||
            this._borderPaintTarget = null;
 | 
			
		||||
        }
 | 
			
		||||
        this.setBorderPaintTarget(null);
 | 
			
		||||
 | 
			
		||||
        Main.popModal(this._entry);
 | 
			
		||||
 | 
			
		||||
        this.actor.lower_bottom();
 | 
			
		||||
        Tweener.addTween(this.actor, { time: 0.5 / St.get_slow_down_factor(),
 | 
			
		||||
                                       transition: 'easeOutQuad',
 | 
			
		||||
                                       y: this._hiddenY,
 | 
			
		||||
@@ -1014,5 +1173,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,25 +13,10 @@ 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];
 | 
			
		||||
const NO_CHANGE = 0.0;
 | 
			
		||||
 | 
			
		||||
// Settings
 | 
			
		||||
const APPLICATIONS_SCHEMA       = 'org.gnome.desktop.a11y.applications';
 | 
			
		||||
@@ -39,6 +25,14 @@ const SHOW_KEY                  = 'screen-magnifier-enabled';
 | 
			
		||||
const MAGNIFIER_SCHEMA          = 'org.gnome.desktop.a11y.magnifier';
 | 
			
		||||
const SCREEN_POSITION_KEY       = 'screen-position';
 | 
			
		||||
const MAG_FACTOR_KEY            = 'mag-factor';
 | 
			
		||||
const INVERT_LIGHTNESS_KEY      = 'invert-lightness';
 | 
			
		||||
const COLOR_SATURATION_KEY      = 'color-saturation';
 | 
			
		||||
const BRIGHT_RED_KEY            = 'brightness-red';
 | 
			
		||||
const BRIGHT_GREEN_KEY          = 'brightness-green';
 | 
			
		||||
const BRIGHT_BLUE_KEY           = 'brightness-blue';
 | 
			
		||||
const CONTRAST_RED_KEY          = 'contrast-red';
 | 
			
		||||
const CONTRAST_GREEN_KEY        = 'contrast-green';
 | 
			
		||||
const CONTRAST_BLUE_KEY         = 'contrast-blue';
 | 
			
		||||
const LENS_MODE_KEY             = 'lens-mode';
 | 
			
		||||
const CLAMP_MODE_KEY            = 'scroll-at-edges';
 | 
			
		||||
const MOUSE_TRACKING_KEY        = 'mouse-tracking';
 | 
			
		||||
@@ -51,17 +45,15 @@ 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 = [];
 | 
			
		||||
 | 
			
		||||
        // Create small clutter tree for the magnified mouse.
 | 
			
		||||
        let xfixesCursor = Shell.XFixesCursor.get_default();
 | 
			
		||||
        let xfixesCursor = Shell.XFixesCursor.get_for_stage(global.stage);
 | 
			
		||||
        this._mouseSprite = new Clutter.Texture();
 | 
			
		||||
        xfixesCursor.update_texture_image(this._mouseSprite);
 | 
			
		||||
        this._cursorRoot = new Clutter.Group();
 | 
			
		||||
@@ -460,6 +452,25 @@ Magnifier.prototype = {
 | 
			
		||||
            aPref = this._settings.get_enum(MOUSE_TRACKING_KEY);
 | 
			
		||||
            if (aPref)
 | 
			
		||||
                zoomRegion.setMouseTrackingMode(aPref);
 | 
			
		||||
 | 
			
		||||
            aPref = this._settings.get_boolean(INVERT_LIGHTNESS_KEY);
 | 
			
		||||
            if (aPref)
 | 
			
		||||
                zoomRegion.setInvertLightness(aPref);
 | 
			
		||||
 | 
			
		||||
            aPref = this._settings.get_double(COLOR_SATURATION_KEY);
 | 
			
		||||
            if (aPref)
 | 
			
		||||
                zoomRegion.setColorSaturation(aPref);
 | 
			
		||||
 | 
			
		||||
            let bc = {};
 | 
			
		||||
            bc.r = this._settings.get_double(BRIGHT_RED_KEY);
 | 
			
		||||
            bc.g = this._settings.get_double(BRIGHT_GREEN_KEY);
 | 
			
		||||
            bc.b = this._settings.get_double(BRIGHT_BLUE_KEY);
 | 
			
		||||
            zoomRegion.setBrightness(bc);
 | 
			
		||||
 | 
			
		||||
            bc.r = this._settings.get_double(CONTRAST_RED_KEY);
 | 
			
		||||
            bc.g = this._settings.get_double(CONTRAST_GREEN_KEY);
 | 
			
		||||
            bc.b = this._settings.get_double(CONTRAST_BLUE_KEY);
 | 
			
		||||
            zoomRegion.setContrast(bc);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let showCrosshairs = this._settings.get_boolean(SHOW_CROSS_HAIRS_KEY);
 | 
			
		||||
@@ -482,6 +493,25 @@ Magnifier.prototype = {
 | 
			
		||||
        this._settings.connect('changed::' + MOUSE_TRACKING_KEY,
 | 
			
		||||
                               Lang.bind(this, this._updateMouseTrackingMode));
 | 
			
		||||
 | 
			
		||||
        this._settings.connect('changed::' + INVERT_LIGHTNESS_KEY,
 | 
			
		||||
                               Lang.bind(this, this._updateInvertLightness));
 | 
			
		||||
        this._settings.connect('changed::' + COLOR_SATURATION_KEY,
 | 
			
		||||
                               Lang.bind(this, this._updateColorSaturation));
 | 
			
		||||
 | 
			
		||||
        this._settings.connect('changed::' + BRIGHT_RED_KEY,
 | 
			
		||||
                               Lang.bind(this, this._updateBrightness));
 | 
			
		||||
        this._settings.connect('changed::' + BRIGHT_GREEN_KEY,
 | 
			
		||||
                               Lang.bind(this, this._updateBrightness));
 | 
			
		||||
        this._settings.connect('changed::' + BRIGHT_BLUE_KEY,
 | 
			
		||||
                               Lang.bind(this, this._updateBrightness));
 | 
			
		||||
 | 
			
		||||
        this._settings.connect('changed::' + CONTRAST_RED_KEY,
 | 
			
		||||
                               Lang.bind(this, this._updateContrast));
 | 
			
		||||
        this._settings.connect('changed::' + CONTRAST_GREEN_KEY,
 | 
			
		||||
                               Lang.bind(this, this._updateContrast));
 | 
			
		||||
        this._settings.connect('changed::' + CONTRAST_BLUE_KEY,
 | 
			
		||||
                               Lang.bind(this, this._updateContrast));
 | 
			
		||||
 | 
			
		||||
        this._settings.connect('changed::' + SHOW_CROSS_HAIRS_KEY,
 | 
			
		||||
                               Lang.bind(this, function() {
 | 
			
		||||
            this.setCrosshairsVisible(this._settings.get_boolean(SHOW_CROSS_HAIRS_KEY));
 | 
			
		||||
@@ -520,7 +550,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();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
@@ -557,24 +587,67 @@ Magnifier.prototype = {
 | 
			
		||||
                this._settings.get_enum(MOUSE_TRACKING_KEY)
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateInvertLightness: function() {
 | 
			
		||||
        // Applies only to the first zoom region.
 | 
			
		||||
        if (this._zoomRegions.length) {
 | 
			
		||||
            this._zoomRegions[0].setInvertLightness(
 | 
			
		||||
                this._settings.get_boolean(INVERT_LIGHTNESS_KEY)
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateColorSaturation: function() {
 | 
			
		||||
        // Applies only to the first zoom region.
 | 
			
		||||
        if (this._zoomRegions.length) {
 | 
			
		||||
            this._zoomRegions[0].setColorSaturation(
 | 
			
		||||
                this._settings.get_double(COLOR_SATURATION_KEY)
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateBrightness: function() {
 | 
			
		||||
        // Applies only to the first zoom region.
 | 
			
		||||
        if (this._zoomRegions.length) {
 | 
			
		||||
            let brightness = {};
 | 
			
		||||
            brightness.r = this._settings.get_double(BRIGHT_RED_KEY);
 | 
			
		||||
            brightness.g = this._settings.get_double(BRIGHT_GREEN_KEY);
 | 
			
		||||
            brightness.b = this._settings.get_double(BRIGHT_BLUE_KEY);
 | 
			
		||||
            this._zoomRegions[0].setBrightness(brightness);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateContrast: function() {
 | 
			
		||||
        // Applies only to the first zoom region.
 | 
			
		||||
        if (this._zoomRegions.length) {
 | 
			
		||||
            let contrast = {};
 | 
			
		||||
            contrast.r = this._settings.get_double(CONTRAST_RED_KEY);
 | 
			
		||||
            contrast.g = this._settings.get_double(CONTRAST_GREEN_KEY);
 | 
			
		||||
            contrast.b = this._settings.get_double(CONTRAST_BLUE_KEY);
 | 
			
		||||
            this._zoomRegions[0].setContrast(contrast);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
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._invertLightness = false;
 | 
			
		||||
        this._colorSaturation = 1.0;
 | 
			
		||||
        this._brightness = { r: NO_CHANGE, g: NO_CHANGE, b: NO_CHANGE };
 | 
			
		||||
        this._contrast = { r: NO_CHANGE, g: NO_CHANGE, b: NO_CHANGE };
 | 
			
		||||
 | 
			
		||||
        this._magView = null;
 | 
			
		||||
        this._background = null;
 | 
			
		||||
        this._uiGroupClone = null;
 | 
			
		||||
        this._mouseSourceActor = mouseSourceActor;
 | 
			
		||||
        this._mouseActor  = null;
 | 
			
		||||
@@ -584,12 +657,15 @@ ZoomRegion.prototype = {
 | 
			
		||||
        this._viewPortX = 0;
 | 
			
		||||
        this._viewPortY = 0;
 | 
			
		||||
        this._viewPortWidth = global.screen_width;
 | 
			
		||||
        this._viewPortWidth = global.screen_height;
 | 
			
		||||
        this._viewPortHeight = global.screen_height;
 | 
			
		||||
        this._xCenter = this._viewPortWidth / 2;
 | 
			
		||||
        this._yCenter = this._viewPortHeight / 2;
 | 
			
		||||
        this._xMagFactor = 1;
 | 
			
		||||
        this._yMagFactor = 1;
 | 
			
		||||
        this._followingCursor = false;
 | 
			
		||||
 | 
			
		||||
        Main.layoutManager.connect('monitors-changed',
 | 
			
		||||
                                   Lang.bind(this, this._monitorsChanged));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -647,7 +723,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 +745,7 @@ ZoomRegion.prototype = {
 | 
			
		||||
     */
 | 
			
		||||
    setViewPort: function(viewPort) {
 | 
			
		||||
        this._setViewPort(viewPort);
 | 
			
		||||
        this._screenPosition = ScreenPosition.NONE;
 | 
			
		||||
        this._screenPosition = GDesktopEnums.MagnifierScreenPosition.NONE;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -750,7 +827,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 +841,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 +855,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 +869,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 +885,7 @@ ZoomRegion.prototype = {
 | 
			
		||||
        viewPort.height = global.screen_height;
 | 
			
		||||
        this.setViewPort(viewPort);
 | 
			
		||||
 | 
			
		||||
        this._screenPosition = ScreenPosition.FULL_SCREEN;
 | 
			
		||||
        this._screenPosition = GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -821,19 +898,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 +933,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();
 | 
			
		||||
@@ -893,6 +970,107 @@ ZoomRegion.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * setInvertLightness:
 | 
			
		||||
     * Set whether to invert the lightness of the magnified view.
 | 
			
		||||
     * @flag    Boolean to either invert brightness (true), or not (false).
 | 
			
		||||
     */
 | 
			
		||||
    setInvertLightness: function(flag) {
 | 
			
		||||
        this._invertLightness = flag;
 | 
			
		||||
        if (this._magShaderEffects)
 | 
			
		||||
            this._magShaderEffects.setInvertLightness(this._invertLightness);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * getInvertLightness:
 | 
			
		||||
     * Retrieve whether the lightness is inverted.
 | 
			
		||||
     * @return    Boolean indicating inversion (true), or not (false).
 | 
			
		||||
     */
 | 
			
		||||
    getInvertLightness: function() {
 | 
			
		||||
        return this._invertLightness;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * setColorSaturation:
 | 
			
		||||
     * Set the color saturation of the magnified view.
 | 
			
		||||
     * @sauration  A value from 0.0 to 1.0 that defines the color
 | 
			
		||||
     *             saturation, with 0.0 defining no color (grayscale),
 | 
			
		||||
     *             and 1.0 defining full color.
 | 
			
		||||
     */
 | 
			
		||||
    setColorSaturation: function(saturation) {
 | 
			
		||||
        this._colorSaturation = saturation;
 | 
			
		||||
        if (this._magShaderEffects)
 | 
			
		||||
            this._magShaderEffects.setColorSaturation(this._colorSaturation);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * getColorSaturation:
 | 
			
		||||
     * Retrieve the color saturation of the magnified view.
 | 
			
		||||
     */
 | 
			
		||||
    getColorSaturation: function() {
 | 
			
		||||
        return this._colorSaturation;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * setBrightness:
 | 
			
		||||
     * Alter the brightness of the magnified view.
 | 
			
		||||
     * @brightness  Object containing the contrast for the red, green,
 | 
			
		||||
     *              and blue channels.  Values of 0.0 represent "standard"
 | 
			
		||||
     *              brightness (no change), whereas values less or greater than
 | 
			
		||||
     *              0.0 indicate decreased or incresaed brightness, respectively.
 | 
			
		||||
     */
 | 
			
		||||
    setBrightness: function(brightness) {
 | 
			
		||||
        this._brightness.r = brightness.r;
 | 
			
		||||
        this._brightness.g = brightness.g;
 | 
			
		||||
        this._brightness.b = brightness.b;
 | 
			
		||||
        if (this._magShaderEffects)
 | 
			
		||||
            this._magShaderEffects.setBrightness(this._brightness);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * getBrightness:
 | 
			
		||||
     * Retrive the current brightness of the Zoom Region.
 | 
			
		||||
     * @return  Object containing the brightness change for the red, green,
 | 
			
		||||
     *          and blue channels.
 | 
			
		||||
     */
 | 
			
		||||
    getBrightness: function() {
 | 
			
		||||
        let brightness = {};
 | 
			
		||||
        brightness.r = this._brightness.r;
 | 
			
		||||
        brightness.g = this._brightness.g;
 | 
			
		||||
        brightness.b = this._brightness.b;
 | 
			
		||||
        return brightness;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * setContrast:
 | 
			
		||||
     * Alter the contrast of the magnified view.
 | 
			
		||||
     * @contrast    Object containing the contrast for the red, green,
 | 
			
		||||
     *              and blue channels.  Values of 0.0 represent "standard"
 | 
			
		||||
     *              contrast (no change), whereas values less or greater than
 | 
			
		||||
     *              0.0 indicate decreased or incresaed contrast, respectively.
 | 
			
		||||
     */
 | 
			
		||||
    setContrast: function(contrast) {
 | 
			
		||||
        this._contrast.r = contrast.r;
 | 
			
		||||
        this._contrast.g = contrast.g;
 | 
			
		||||
        this._contrast.b = contrast.b;
 | 
			
		||||
        if (this._magShaderEffects)
 | 
			
		||||
            this._magShaderEffects.setContrast(this._contrast);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * getContrast:
 | 
			
		||||
     * Retreive the contrast of the magnified view.
 | 
			
		||||
     * @return  Object containing the contrast for the red, green,
 | 
			
		||||
     *          and blue channels.
 | 
			
		||||
     */
 | 
			
		||||
    getContrast: function() {
 | 
			
		||||
        let contrast = {};
 | 
			
		||||
        contrast.r = this._contrast.r;
 | 
			
		||||
        contrast.g = this._contrast.g;
 | 
			
		||||
        contrast.b = this._contrast.b;
 | 
			
		||||
        return contrast;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    //// Private methods ////
 | 
			
		||||
 | 
			
		||||
    _createActors: function() {
 | 
			
		||||
@@ -909,15 +1087,15 @@ ZoomRegion.prototype = {
 | 
			
		||||
 | 
			
		||||
        // Add a background for when the magnified uiGroup is scrolled
 | 
			
		||||
        // out of view (don't want to see desktop showing through).
 | 
			
		||||
        let background = new Clutter.Rectangle({ color: Main.DEFAULT_BACKGROUND_COLOR });
 | 
			
		||||
        mainGroup.add_actor(background);
 | 
			
		||||
        this._background = new Clutter.Rectangle({ color: Main.DEFAULT_BACKGROUND_COLOR });
 | 
			
		||||
        mainGroup.add_actor(this._background);
 | 
			
		||||
 | 
			
		||||
        // Clone the group that contains all of UI on the screen.  This is the
 | 
			
		||||
        // chrome, the windows, etc.
 | 
			
		||||
        this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup });
 | 
			
		||||
        mainGroup.add_actor(this._uiGroupClone);
 | 
			
		||||
        Main.uiGroup.set_size(global.screen_width, global.screen_height);
 | 
			
		||||
        background.set_size(global.screen_width, global.screen_height);
 | 
			
		||||
        this._background.set_size(global.screen_width, global.screen_height);
 | 
			
		||||
 | 
			
		||||
        // Add either the given mouseSourceActor to the ZoomRegion, or a clone of
 | 
			
		||||
        // it.
 | 
			
		||||
@@ -931,6 +1109,13 @@ ZoomRegion.prototype = {
 | 
			
		||||
            this._crossHairsActor = this._crossHairs.addToZoomRegion(this, this._mouseActor);
 | 
			
		||||
        else
 | 
			
		||||
            this._crossHairsActor = null;
 | 
			
		||||
 | 
			
		||||
        // Contrast and brightness effects.
 | 
			
		||||
        this._magShaderEffects = new MagShaderEffects(this._uiGroupClone);
 | 
			
		||||
        this._magShaderEffects.setColorSaturation(this._colorSaturation);
 | 
			
		||||
        this._magShaderEffects.setInvertLightness(this._invertLightness);
 | 
			
		||||
        this._magShaderEffects.setBrightness(this._brightness);
 | 
			
		||||
        this._magShaderEffects.setContrast(this._contrast);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _destroyActors: function() {
 | 
			
		||||
@@ -939,8 +1124,11 @@ ZoomRegion.prototype = {
 | 
			
		||||
        if (this._crossHairs)
 | 
			
		||||
            this._crossHairs.removeFromParent(this._crossHairsActor);
 | 
			
		||||
 | 
			
		||||
        this._magShaderEffects.destroyEffects();
 | 
			
		||||
        this._magShaderEffects = null;
 | 
			
		||||
        this._magView.destroy();
 | 
			
		||||
        this._magView = null;
 | 
			
		||||
        this._background = null;
 | 
			
		||||
        this._uiGroupClone = null;
 | 
			
		||||
        this._mouseActor = null;
 | 
			
		||||
        this._crossHairsActor = null;
 | 
			
		||||
@@ -991,7 +1179,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 +1229,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 +1246,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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -1163,14 +1351,28 @@ ZoomRegion.prototype = {
 | 
			
		||||
            this._crossHairsActor.set_position(xMagMouse - groupWidth / 2,
 | 
			
		||||
                                               yMagMouse - groupHeight / 2);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _monitorsChanged: function() {
 | 
			
		||||
        if (!this.isActive())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Main.uiGroup.set_size(global.screen_width, global.screen_height);
 | 
			
		||||
        this._background.set_size(global.screen_width, global.screen_height);
 | 
			
		||||
 | 
			
		||||
        if (this._screenPosition == GDesktopEnums.MagnifierScreenPosition.NONE)
 | 
			
		||||
            this._setViewPort({ x: this._viewPortX,
 | 
			
		||||
                                y: this._viewPortY,
 | 
			
		||||
                                width: this._viewPortWidth,
 | 
			
		||||
                                height: this._viewPortHeight });
 | 
			
		||||
        else
 | 
			
		||||
            this.setScreenPosition(this._screenPosition);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
@@ -1195,6 +1397,14 @@ Crosshairs.prototype = {
 | 
			
		||||
        this._clipSize = [0, 0];
 | 
			
		||||
        this._clones = [];
 | 
			
		||||
        this.reCenter();
 | 
			
		||||
 | 
			
		||||
        Main.layoutManager.connect('monitors-changed',
 | 
			
		||||
                                   Lang.bind(this, this._monitorsChanged));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _monitorsChanged: function() {
 | 
			
		||||
        this._actor.set_size(global.screen_width * 3, global.screen_height * 3);
 | 
			
		||||
        this.reCenter();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
   /**
 | 
			
		||||
@@ -1219,10 +1429,7 @@ Crosshairs.prototype = {
 | 
			
		||||
                    crosshairsActor = new Clutter.Clone({ source: this._actor });
 | 
			
		||||
                    this._clones.push(crosshairsActor);
 | 
			
		||||
                }
 | 
			
		||||
                if (this._actor.visible)
 | 
			
		||||
                    crosshairsActor.show();
 | 
			
		||||
                else
 | 
			
		||||
                    crosshairsActor.hide();
 | 
			
		||||
                crosshairsActor.visible = this._actor.visible;
 | 
			
		||||
 | 
			
		||||
                container.add_actor(crosshairsActor);
 | 
			
		||||
                container.raise_child(magnifiedMouse, crosshairsActor);
 | 
			
		||||
@@ -1426,4 +1633,145 @@ Crosshairs.prototype = {
 | 
			
		||||
        this._vertTopHair.set_position((groupWidth - thickness) / 2, top);
 | 
			
		||||
        this._vertBottomHair.set_position((groupWidth - thickness) / 2, bottom);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const MagShaderEffects = new Lang.Class({
 | 
			
		||||
    Name: 'MagShaderEffects',
 | 
			
		||||
 | 
			
		||||
    _init: function(uiGroupClone) {
 | 
			
		||||
        this._inverse = new Shell.InvertLightnessEffect();
 | 
			
		||||
        this._brightnessContrast = new Clutter.BrightnessContrastEffect();
 | 
			
		||||
        this._colorDesaturation = new Clutter.DesaturateEffect();
 | 
			
		||||
        this._inverse.set_enabled(false);
 | 
			
		||||
        this._brightnessContrast.set_enabled(false);
 | 
			
		||||
 | 
			
		||||
        this._magView = uiGroupClone;
 | 
			
		||||
        this._magView.add_effect(this._inverse);
 | 
			
		||||
        this._magView.add_effect(this._brightnessContrast);
 | 
			
		||||
        this._magView.add_effect(this._colorDesaturation);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * destroyEffects:
 | 
			
		||||
     * Remove contrast and brightness effects from the magnified view, and
 | 
			
		||||
     * lose the reference to the actor they were applied to.  Don't use this
 | 
			
		||||
     * object after calling this.
 | 
			
		||||
     */
 | 
			
		||||
    destroyEffects: function() {
 | 
			
		||||
        this._magView.clear_effects();
 | 
			
		||||
        this._colorDesaturation = null;
 | 
			
		||||
        this._brightnessContrast = null;
 | 
			
		||||
        this._inverse = null;
 | 
			
		||||
        this._magView = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * setInvertLightness:
 | 
			
		||||
     * Enable/disable invert lightness effect.
 | 
			
		||||
     * @invertFlag:     Enabled flag.
 | 
			
		||||
     */
 | 
			
		||||
    setInvertLightness: function(invertFlag) {
 | 
			
		||||
        this._inverse.set_enabled(invertFlag);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * getInvertLightness:
 | 
			
		||||
     * Report whether the inversion effect is enabled.
 | 
			
		||||
     * @return:     Boolean.
 | 
			
		||||
     */
 | 
			
		||||
    getInvertLightness: function() {
 | 
			
		||||
        return this._inverse.get_enabled();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setColorSaturation: function(factor) {
 | 
			
		||||
        this._colorDesaturation.set_factor(1.0 - factor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getColorSaturation: function() {
 | 
			
		||||
        return 1.0 - this._colorDesaturation.get_factor();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * setBrightness:
 | 
			
		||||
     * Set the brightness of the magnified view.
 | 
			
		||||
     * @brightness: Object containing the brightness for the red, green,
 | 
			
		||||
     *              and blue channels.  Values of 0.0 represent "standard"
 | 
			
		||||
     *              brightness (no change), whereas values less or greater than
 | 
			
		||||
     *              0.0 indicate decreased or incresaed brightness,
 | 
			
		||||
     *              respectively.
 | 
			
		||||
     */
 | 
			
		||||
    setBrightness: function(brightness) {
 | 
			
		||||
        let bRed = brightness.r;
 | 
			
		||||
        let bGreen = brightness.g;
 | 
			
		||||
        let bBlue = brightness.b;
 | 
			
		||||
        this._brightnessContrast.set_brightness_full(bRed, bGreen, bBlue);
 | 
			
		||||
 | 
			
		||||
        // Enable the effect if the brightness OR contrast change are such that
 | 
			
		||||
        // it modifies the brightness and/or contrast.
 | 
			
		||||
        let [cRed, cGreen, cBlue] = this._brightnessContrast.get_contrast();
 | 
			
		||||
        this._brightnessContrast.set_enabled(
 | 
			
		||||
            (bRed != NO_CHANGE || bGreen != NO_CHANGE || bBlue != NO_CHANGE ||
 | 
			
		||||
             cRed != NO_CHANGE || cGreen != NO_CHANGE || cBlue != NO_CHANGE)
 | 
			
		||||
        );
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * getBrightness:
 | 
			
		||||
     * Retrieve current brightness of the magnified view.
 | 
			
		||||
     * @return: Object containing the brightness for the red, green,
 | 
			
		||||
     *          and blue channels.  Values of 0.0 represent "standard" 
 | 
			
		||||
     *          brightness (no change), whereas values less or greater than
 | 
			
		||||
     *          0.0 indicate decreased or incresaed brightness, respectively.
 | 
			
		||||
     */
 | 
			
		||||
    getBrightness: function() {
 | 
			
		||||
        let result = {};
 | 
			
		||||
        let [bRed, bGreen, bBlue] = this._brightnessContrast.get_brightness();
 | 
			
		||||
        result.r = bRed;
 | 
			
		||||
        result.g = bGreen;
 | 
			
		||||
        result.b = bBlue;
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the contrast of the magnified view.
 | 
			
		||||
     * @contrast:   Object containing the contrast for the red, green,
 | 
			
		||||
     *              and blue channels.  Values of 0.0 represent "standard"
 | 
			
		||||
     *              contrast (no change), whereas values less or greater than
 | 
			
		||||
     *              0.0 indicate decreased or incresaed contrast, respectively.
 | 
			
		||||
     */
 | 
			
		||||
    setContrast: function(contrast) {
 | 
			
		||||
        let cRed = contrast.r;
 | 
			
		||||
        let cGreen = contrast.g;
 | 
			
		||||
        let cBlue = contrast.b;
 | 
			
		||||
 | 
			
		||||
        this._brightnessContrast.set_contrast_full(cRed, cGreen, cBlue);
 | 
			
		||||
 | 
			
		||||
        // Enable the effect if the contrast OR brightness change are such that
 | 
			
		||||
        // it modifies the brightness and/or contrast.
 | 
			
		||||
        // should be able to use Clutter.color_equal(), but that complains of
 | 
			
		||||
        // a null first argument.
 | 
			
		||||
        let [bRed, bGreen, bBlue] = this._brightnessContrast.get_brightness();
 | 
			
		||||
        this._brightnessContrast.set_enabled(
 | 
			
		||||
             cRed != NO_CHANGE || cGreen != NO_CHANGE || cBlue != NO_CHANGE ||
 | 
			
		||||
             bRed != NO_CHANGE || bGreen != NO_CHANGE || bBlue != NO_CHANGE
 | 
			
		||||
        );
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieve current contrast of the magnified view.
 | 
			
		||||
     * @return: Object containing the contrast for the red, green,
 | 
			
		||||
     *          and blue channels.  Values of 0.0 represent "standard"
 | 
			
		||||
     *          contrast (no change), whereas values less or greater than
 | 
			
		||||
     *          0.0 indicate decreased or incresaed contrast, respectively.
 | 
			
		||||
     */
 | 
			
		||||
    getContrast: function() {
 | 
			
		||||
        let resutl = {};
 | 
			
		||||
        let [cRed, cGreen, cBlue] = this._brightnessContrast.get_contrast();
 | 
			
		||||
        result.r = cRed;
 | 
			
		||||
        result.g = cGreen;
 | 
			
		||||
        result.b = cBlue;
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										334
									
								
								js/ui/main.js
									
									
									
									
									
								
							
							
						
						@@ -1,11 +1,9 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const DBus = imports.dbus;
 | 
			
		||||
const Gdk = imports.gi.Gdk;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const GConf = imports.gi.GConf;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
@@ -17,8 +15,10 @@ const AutorunManager = imports.ui.autorunManager;
 | 
			
		||||
const CtrlAltTab = imports.ui.ctrlAltTab;
 | 
			
		||||
const EndSessionDialog = imports.ui.endSessionDialog;
 | 
			
		||||
const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent;
 | 
			
		||||
const KeyringPrompt = imports.ui.keyringPrompt;
 | 
			
		||||
const Environment = imports.ui.environment;
 | 
			
		||||
const ExtensionSystem = imports.ui.extensionSystem;
 | 
			
		||||
const ExtensionDownloader = imports.ui.extensionDownloader;
 | 
			
		||||
const Keyboard = imports.ui.keyboard;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
const Overview = imports.ui.overview;
 | 
			
		||||
@@ -30,15 +30,19 @@ const LookingGlass = imports.ui.lookingGlass;
 | 
			
		||||
const NetworkAgent = imports.ui.networkAgent;
 | 
			
		||||
const NotificationDaemon = imports.ui.notificationDaemon;
 | 
			
		||||
const WindowAttentionHandler = imports.ui.windowAttentionHandler;
 | 
			
		||||
const ScreenShield = imports.ui.screenShield;
 | 
			
		||||
const Scripting = imports.ui.scripting;
 | 
			
		||||
const SessionMode = imports.ui.sessionMode;
 | 
			
		||||
const ShellDBus = imports.ui.shellDBus;
 | 
			
		||||
const ShellMountOperation = imports.ui.shellMountOperation;
 | 
			
		||||
const TelepathyClient = imports.ui.telepathyClient;
 | 
			
		||||
const UnlockDialog = imports.ui.unlockDialog;
 | 
			
		||||
const WindowManager = imports.ui.windowManager;
 | 
			
		||||
const Magnifier = imports.ui.magnifier;
 | 
			
		||||
const XdndHandler = imports.ui.xdndHandler;
 | 
			
		||||
const StatusIconDispatcher = imports.ui.statusIconDispatcher;
 | 
			
		||||
const Util = imports.misc.util;
 | 
			
		||||
 | 
			
		||||
const OVERRIDES_SCHEMA = 'org.gnome.shell.overrides';
 | 
			
		||||
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
 | 
			
		||||
DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
 | 
			
		||||
 | 
			
		||||
@@ -46,73 +50,92 @@ let automountManager = null;
 | 
			
		||||
let autorunManager = null;
 | 
			
		||||
let panel = null;
 | 
			
		||||
let hotCorners = [];
 | 
			
		||||
let placesManager = null;
 | 
			
		||||
let overview = null;
 | 
			
		||||
let runDialog = null;
 | 
			
		||||
let lookingGlass = null;
 | 
			
		||||
let wm = null;
 | 
			
		||||
let messageTray = null;
 | 
			
		||||
let screenShield = null;
 | 
			
		||||
let notificationDaemon = null;
 | 
			
		||||
let windowAttentionHandler = null;
 | 
			
		||||
let telepathyClient = null;
 | 
			
		||||
let ctrlAltTabManager = null;
 | 
			
		||||
let recorder = null;
 | 
			
		||||
let sessionMode = null;
 | 
			
		||||
let shellDBusService = null;
 | 
			
		||||
let shellMountOpDBusService = null;
 | 
			
		||||
let screenSaverDBus = null;
 | 
			
		||||
let modalCount = 0;
 | 
			
		||||
let modalActorFocusStack = [];
 | 
			
		||||
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 _overridesSettings = null;
 | 
			
		||||
 | 
			
		||||
let background = null;
 | 
			
		||||
 | 
			
		||||
function _createUserSession() {
 | 
			
		||||
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();
 | 
			
		||||
 | 
			
		||||
    placesManager = new PlaceDisplay.PlacesManager();
 | 
			
		||||
    telepathyClient = new TelepathyClient.Client();
 | 
			
		||||
    automountManager = new AutomountManager.AutomountManager();
 | 
			
		||||
    autorunManager = new AutorunManager.AutorunManager();
 | 
			
		||||
    networkAgent = new NetworkAgent.NetworkAgent();
 | 
			
		||||
 | 
			
		||||
    _initRecorder();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _createGDMSession() {
 | 
			
		||||
function createGDMSession() {
 | 
			
		||||
    screenShield.showDialog();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createGDMLoginDialog(parentActor) {
 | 
			
		||||
    // We do this this here instead of at the top to prevent GDM
 | 
			
		||||
    // related code from getting loaded in normal user sessions
 | 
			
		||||
    const LoginDialog = imports.gdm.loginDialog;
 | 
			
		||||
 | 
			
		||||
    let loginDialog = new LoginDialog.LoginDialog();
 | 
			
		||||
    loginDialog.connect('loaded', function() {
 | 
			
		||||
                            loginDialog.open();
 | 
			
		||||
                        });
 | 
			
		||||
    let loginDialog = new LoginDialog.LoginDialog(parentActor);
 | 
			
		||||
    return [loginDialog, true];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createSessionUnlockDialog(parentActor) {
 | 
			
		||||
    let dialog = new UnlockDialog.UnlockDialog(parentActor);
 | 
			
		||||
    return [dialog, false];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createInitialSetupSession() {
 | 
			
		||||
    networkAgent = new NetworkAgent.NetworkAgent();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _initRecorder() {
 | 
			
		||||
    let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
 | 
			
		||||
    let desktopLockdownSettings = new Gio.Settings({ schema: 'org.gnome.desktop.lockdown' });
 | 
			
		||||
    let bindingSettings = new Gio.Settings({ schema: 'org.gnome.shell.keybindings' });
 | 
			
		||||
 | 
			
		||||
    global.screen.connect('toggle-recording', function() {
 | 
			
		||||
    global.display.add_keybinding('toggle-recording',
 | 
			
		||||
                                  bindingSettings,
 | 
			
		||||
                                  Meta.KeyBindingFlags.NONE, function() {
 | 
			
		||||
        if (recorder == null) {
 | 
			
		||||
            recorder = new Shell.Recorder({ stage: global.stage });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (recorder.is_recording()) {
 | 
			
		||||
            recorder.pause();
 | 
			
		||||
            recorder.close();
 | 
			
		||||
            Meta.enable_unredirect_for_screen(global.screen);
 | 
			
		||||
        } else {
 | 
			
		||||
        } else if (!desktopLockdownSettings.get_boolean('disable-save-to-disk')) {
 | 
			
		||||
            // read the parameters from GSettings always in case they have changed
 | 
			
		||||
            recorder.set_framerate(recorderSettings.get_int('framerate'));
 | 
			
		||||
            recorder.set_filename('shell-%d%u-%c.' + recorderSettings.get_string('file-extension'));
 | 
			
		||||
            /* Translators: this is a filename used for screencast recording */
 | 
			
		||||
            // xgettext:no-c-format
 | 
			
		||||
            recorder.set_filename(_("Screencast from %d %t") + '.' + recorderSettings.get_string('file-extension'));
 | 
			
		||||
            let pipeline = recorderSettings.get_string('pipeline');
 | 
			
		||||
 | 
			
		||||
            if (!pipeline.match(/^\s*$/))
 | 
			
		||||
@@ -126,50 +149,19 @@ function _initRecorder() {
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _initUserSession() {
 | 
			
		||||
    _initRecorder();
 | 
			
		||||
 | 
			
		||||
    keyboard.init();
 | 
			
		||||
 | 
			
		||||
    global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT, false, -1, 1);
 | 
			
		||||
 | 
			
		||||
    ExtensionSystem.init();
 | 
			
		||||
    ExtensionSystem.loadExtensions();
 | 
			
		||||
 | 
			
		||||
    let shellwm = global.window_manager;
 | 
			
		||||
 | 
			
		||||
    shellwm.takeover_keybinding('panel_run_dialog');
 | 
			
		||||
    shellwm.connect('keybinding::panel_run_dialog', function () {
 | 
			
		||||
       getRunDialog().open();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    shellwm.takeover_keybinding('panel_main_menu');
 | 
			
		||||
    shellwm.connect('keybinding::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;
 | 
			
		||||
    // These are here so we don't break compatibility.
 | 
			
		||||
    global.logError = window.log;
 | 
			
		||||
    global.log = window.log;
 | 
			
		||||
 | 
			
		||||
    // Chain up async errors reported from C
 | 
			
		||||
    global.connect('notify-error', function (global, msg, detail) { notifyError(msg, detail); });
 | 
			
		||||
 | 
			
		||||
    Gio.DesktopAppInfo.set_desktop_env('GNOME');
 | 
			
		||||
 | 
			
		||||
    sessionMode = new SessionMode.SessionMode();
 | 
			
		||||
    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();
 | 
			
		||||
    shellMountOpDBusService = new ShellMountOperation.GnomeShellMountOpHandler();
 | 
			
		||||
 | 
			
		||||
    // Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
 | 
			
		||||
    // also initialize ShellAppSystem first.  ShellAppSystem
 | 
			
		||||
@@ -179,9 +171,11 @@ function start() {
 | 
			
		||||
    // and recalculate application associations, so to avoid
 | 
			
		||||
    // races for now we initialize it here.  It's better to
 | 
			
		||||
    // be predictable anyways.
 | 
			
		||||
    Shell.WindowTracker.get_default();
 | 
			
		||||
    let tracker = Shell.WindowTracker.get_default();
 | 
			
		||||
    Shell.AppUsage.get_default();
 | 
			
		||||
 | 
			
		||||
    tracker.connect('startup-sequence-changed', _queueCheckWorkspaces);
 | 
			
		||||
 | 
			
		||||
    // The stage is always covered so Clutter doesn't need to clear it; however
 | 
			
		||||
    // the color is used as the default contents for the Mutter root background
 | 
			
		||||
    // actor so set it anyways.
 | 
			
		||||
@@ -189,12 +183,26 @@ function start() {
 | 
			
		||||
    global.stage.no_clear_hint = true;
 | 
			
		||||
 | 
			
		||||
    _defaultCssStylesheet = global.datadir + '/theme/gnome-shell.css';
 | 
			
		||||
    _gdmCssStylesheet = global.datadir + '/theme/gdm.css';
 | 
			
		||||
    loadTheme();
 | 
			
		||||
 | 
			
		||||
    // Set up stage hierarchy to group all UI actors under one container.
 | 
			
		||||
    uiGroup = new Clutter.Group();
 | 
			
		||||
    St.set_ui_root(global.stage, uiGroup);
 | 
			
		||||
    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);
 | 
			
		||||
                    });
 | 
			
		||||
    uiGroup.connect('get-preferred-width',
 | 
			
		||||
                    function(actor, forHeight, alloc) {
 | 
			
		||||
                        let width = global.stage.width;
 | 
			
		||||
                        [alloc.min_size, alloc.natural_size] = [width, width];
 | 
			
		||||
                    });
 | 
			
		||||
    uiGroup.connect('get-preferred-height',
 | 
			
		||||
                    function(actor, forWidth, alloc) {
 | 
			
		||||
                        let height = global.stage.height;
 | 
			
		||||
                        [alloc.min_size, alloc.natural_size] = [height, height];
 | 
			
		||||
                    });
 | 
			
		||||
    global.window_group.reparent(uiGroup);
 | 
			
		||||
    global.overlay_group.reparent(uiGroup);
 | 
			
		||||
    global.stage.add_actor(uiGroup);
 | 
			
		||||
@@ -202,10 +210,10 @@ function start() {
 | 
			
		||||
    layoutManager = new Layout.LayoutManager();
 | 
			
		||||
    xdndHandler = new XdndHandler.XdndHandler();
 | 
			
		||||
    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 });
 | 
			
		||||
    overview = new Overview.Overview();
 | 
			
		||||
    magnifier = new Magnifier.Magnifier();
 | 
			
		||||
    statusIconDispatcher = new StatusIconDispatcher.StatusIconDispatcher();
 | 
			
		||||
    screenShield = new ScreenShield.ScreenShield();
 | 
			
		||||
    screenSaverDBus = new ShellDBus.ScreenSaverDBus();
 | 
			
		||||
    panel = new Panel.Panel();
 | 
			
		||||
    wm = new WindowManager.WindowManager();
 | 
			
		||||
    messageTray = new MessageTray.MessageTray();
 | 
			
		||||
@@ -213,19 +221,37 @@ function start() {
 | 
			
		||||
    notificationDaemon = new NotificationDaemon.NotificationDaemon();
 | 
			
		||||
    windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
 | 
			
		||||
 | 
			
		||||
    if (global.session_type == Shell.SessionType.USER)
 | 
			
		||||
        _createUserSession();
 | 
			
		||||
    else if (global.session_type == Shell.SessionType.GDM)
 | 
			
		||||
        _createGDMSession();
 | 
			
		||||
    sessionMode.createSession();
 | 
			
		||||
 | 
			
		||||
    panel.startStatusArea();
 | 
			
		||||
 | 
			
		||||
    layoutManager.init();
 | 
			
		||||
    keyboard.init();
 | 
			
		||||
    overview.init();
 | 
			
		||||
 | 
			
		||||
    if (global.session_type == Shell.SessionType.USER)
 | 
			
		||||
        _initUserSession();
 | 
			
		||||
    statusIconDispatcher.start(messageTray.actor);
 | 
			
		||||
    if (sessionMode.hasWorkspaces)
 | 
			
		||||
        global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
 | 
			
		||||
                                                false, -1, 1);
 | 
			
		||||
 | 
			
		||||
    if (sessionMode.allowExtensions) {
 | 
			
		||||
        ExtensionDownloader.init();
 | 
			
		||||
        ExtensionSystem.loadExtensions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (sessionMode.hasRunDialog) {
 | 
			
		||||
        Meta.keybindings_set_custom_handler('panel-run-dialog', function() {
 | 
			
		||||
           getRunDialog().open();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (sessionMode.hasOverview) {
 | 
			
		||||
        Meta.keybindings_set_custom_handler('panel-main-menu', function () {
 | 
			
		||||
            overview.toggle();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        global.display.connect('overlay-key',
 | 
			
		||||
                               Lang.bind(overview, overview.toggle));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Provide the bus object for gnome-session to
 | 
			
		||||
    // initiate logouts.
 | 
			
		||||
@@ -234,11 +260,13 @@ function start() {
 | 
			
		||||
    // Attempt to become a PolicyKit authentication agent
 | 
			
		||||
    PolkitAuthenticationAgent.init()
 | 
			
		||||
 | 
			
		||||
    // Become a prompter for gnome keyring
 | 
			
		||||
    KeyringPrompt.init();
 | 
			
		||||
 | 
			
		||||
    _startDate = new Date();
 | 
			
		||||
 | 
			
		||||
    global.stage.connect('captured-event', _globalKeyPressHandler);
 | 
			
		||||
 | 
			
		||||
    _log('info', 'loaded at ' + _startDate);
 | 
			
		||||
    log('GNOME Shell started at ' + _startDate);
 | 
			
		||||
 | 
			
		||||
    let perfModuleName = GLib.getenv("SHELL_PERF_MODULE");
 | 
			
		||||
@@ -248,6 +276,9 @@ function start() {
 | 
			
		||||
        Scripting.runPerfScript(module, perfOutput);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _overridesSettings = new Gio.Settings({ schema: OVERRIDES_SCHEMA });
 | 
			
		||||
    _overridesSettings.connect('changed::dynamic-workspaces', _queueCheckWorkspaces);
 | 
			
		||||
 | 
			
		||||
    global.screen.connect('notify::n-workspaces', _nWorkspacesChanged);
 | 
			
		||||
 | 
			
		||||
    global.screen.connect('window-entered-monitor', _windowEnteredMonitor);
 | 
			
		||||
@@ -272,17 +303,30 @@ function _checkWorkspaces() {
 | 
			
		||||
    let i;
 | 
			
		||||
    let emptyWorkspaces = [];
 | 
			
		||||
 | 
			
		||||
    if (!Meta.prefs_get_dynamic_workspaces()) {
 | 
			
		||||
        _checkWorkspacesId = 0;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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))
 | 
			
		||||
        if ((lastRemoved &&
 | 
			
		||||
             (lastRemoved.get_window_type() == Meta.WindowType.SPLASHSCREEN ||
 | 
			
		||||
              lastRemoved.get_window_type() == Meta.WindowType.DIALOG ||
 | 
			
		||||
              lastRemoved.get_window_type() == Meta.WindowType.MODAL_DIALOG)) ||
 | 
			
		||||
            _workspaces[i]._keepAliveId)
 | 
			
		||||
                emptyWorkspaces[i] = false;
 | 
			
		||||
        else
 | 
			
		||||
            emptyWorkspaces[i] = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let sequences = Shell.WindowTracker.get_default().get_startup_sequences();
 | 
			
		||||
    for (i = 0; i < sequences.length; i++) {
 | 
			
		||||
        let index = sequences[i].get_workspace();
 | 
			
		||||
        if (index >= 0 && index <= global.screen.n_workspaces)
 | 
			
		||||
            emptyWorkspaces[index] = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let windows = global.get_window_actors();
 | 
			
		||||
    for (i = 0; i < windows.length; i++) {
 | 
			
		||||
        let win = windows[i];
 | 
			
		||||
@@ -330,6 +374,17 @@ function _checkWorkspaces() {
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function keepWorkspaceAlive(workspace, duration) {
 | 
			
		||||
    if (workspace._keepAliveId)
 | 
			
		||||
        Mainloop.source_remove(workspace._keepAliveId);
 | 
			
		||||
 | 
			
		||||
    workspace._keepAliveId = Mainloop.timeout_add(duration, function() {
 | 
			
		||||
        workspace._keepAliveId = 0;
 | 
			
		||||
        _queueCheckWorkspaces();
 | 
			
		||||
        return false;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _windowRemoved(workspace, window) {
 | 
			
		||||
    workspace._lastRemovedWindow = window;
 | 
			
		||||
    _queueCheckWorkspaces();
 | 
			
		||||
@@ -338,6 +393,7 @@ function _windowRemoved(workspace, window) {
 | 
			
		||||
            workspace._lastRemovedWindow = null;
 | 
			
		||||
            _queueCheckWorkspaces();
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -453,8 +509,8 @@ function loadTheme() {
 | 
			
		||||
 | 
			
		||||
    let theme = new St.Theme ({ application_stylesheet: cssStylesheet });
 | 
			
		||||
 | 
			
		||||
    if (global.session_type == Shell.SessionType.GDM)
 | 
			
		||||
        theme.load_stylesheet(_gdmCssStylesheet);
 | 
			
		||||
    if (sessionMode.extraStylesheet)
 | 
			
		||||
        theme.load_stylesheet(sessionMode.extraStylesheet);
 | 
			
		||||
 | 
			
		||||
    if (previousTheme) {
 | 
			
		||||
        let customStylesheets = previousTheme.get_custom_stylesheets();
 | 
			
		||||
@@ -476,6 +532,7 @@ function notify(msg, details) {
 | 
			
		||||
    messageTray.add(source);
 | 
			
		||||
    let notification = new MessageTray.Notification(source, msg, details);
 | 
			
		||||
    notification.setTransient(true);
 | 
			
		||||
    notification.setShowWhenLocked(true);
 | 
			
		||||
    source.notify(notification);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -489,66 +546,13 @@ function notify(msg, details) {
 | 
			
		||||
function notifyError(msg, details) {
 | 
			
		||||
    // Also print to stderr so it's logged somewhere
 | 
			
		||||
    if (details)
 | 
			
		||||
        log("error: " + msg + ": " + details);
 | 
			
		||||
        log('error: ' + msg + ': ' + details);
 | 
			
		||||
    else
 | 
			
		||||
        log("error: " + msg)
 | 
			
		||||
        log('error: ' + msg);
 | 
			
		||||
 | 
			
		||||
    notify(msg, details);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * _log:
 | 
			
		||||
 * @category: string message type ('info', 'error')
 | 
			
		||||
 * @msg: A message string
 | 
			
		||||
 * ...: Any further arguments are converted into JSON notation,
 | 
			
		||||
 *      and appended to the log message, separated by spaces.
 | 
			
		||||
 *
 | 
			
		||||
 * Log a message into the LookingGlass error
 | 
			
		||||
 * stream.  This is primarily intended for use by the
 | 
			
		||||
 * extension system as well as debugging.
 | 
			
		||||
 */
 | 
			
		||||
function _log(category, msg) {
 | 
			
		||||
    let text = msg;
 | 
			
		||||
    if (arguments.length > 2) {
 | 
			
		||||
        text += ': ';
 | 
			
		||||
        for (let i = 2; i < arguments.length; i++) {
 | 
			
		||||
            text += JSON.stringify(arguments[i]);
 | 
			
		||||
            if (i < arguments.length - 1)
 | 
			
		||||
                text += ' ';
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    _errorLogStack.push({timestamp: new Date().getTime(),
 | 
			
		||||
                         category: category,
 | 
			
		||||
                         message: text });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _logError(msg) {
 | 
			
		||||
    return _log('error', msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _logDebug(msg) {
 | 
			
		||||
    return _log('debug', msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Used by the error display in lookingGlass.js
 | 
			
		||||
function _getAndClearErrorStack() {
 | 
			
		||||
    let errors = _errorLogStack;
 | 
			
		||||
    _errorLogStack = [];
 | 
			
		||||
    return errors;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
    return win.get_workspace() == workspaceIndex ||
 | 
			
		||||
        (win.get_meta_window() && win.get_meta_window().is_on_all_workspaces());
 | 
			
		||||
@@ -571,28 +575,19 @@ function _globalKeyPressHandler(actor, event) {
 | 
			
		||||
    if (event.type() != Clutter.EventType.KEY_PRESS)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    if (!sessionMode.allowKeybindingsWhenModal) {
 | 
			
		||||
        if (modalCount > (overview.visible ? 1 : 0))
 | 
			
		||||
            return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let symbol = event.get_key_symbol();
 | 
			
		||||
    let keyCode = event.get_key_code();
 | 
			
		||||
    let modifierState = Shell.get_event_state(event);
 | 
			
		||||
    let ignoredModifiers = global.display.get_ignored_modifier_mask();
 | 
			
		||||
    let modifierState = event.get_state() & ~ignoredModifiers;
 | 
			
		||||
 | 
			
		||||
    // This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType
 | 
			
		||||
    let action = global.display.get_keybinding_action(keyCode, modifierState);
 | 
			
		||||
 | 
			
		||||
    // The screenshot action should always be available (even if a
 | 
			
		||||
    // modal dialog is present)
 | 
			
		||||
    if (action == Meta.KeyBindingAction.COMMAND_SCREENSHOT) {
 | 
			
		||||
        let gconf = GConf.Client.get_default();
 | 
			
		||||
        let command = gconf.get_string('/apps/metacity/keybinding_commands/command_screenshot');
 | 
			
		||||
        if (command != null && command != '')
 | 
			
		||||
            Util.spawnCommandLine(command);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Other bindings are only available when the overview is up and
 | 
			
		||||
    // no modal dialog is present.
 | 
			
		||||
    if (!overview.visible || modalCount > 1)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    // This isn't a Meta.KeyBindingAction yet
 | 
			
		||||
    if (symbol == Clutter.Super_L || symbol == Clutter.Super_R) {
 | 
			
		||||
        overview.hide();
 | 
			
		||||
@@ -600,32 +595,44 @@ function _globalKeyPressHandler(actor, event) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (action == Meta.KeyBindingAction.SWITCH_PANELS) {
 | 
			
		||||
        ctrlAltTabManager.popup(modifierState & Clutter.ModifierType.SHIFT_MASK);
 | 
			
		||||
        ctrlAltTabManager.popup(modifierState & Clutter.ModifierType.SHIFT_MASK,
 | 
			
		||||
                                modifierState);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 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.
 | 
			
		||||
        //
 | 
			
		||||
        // case Meta.KeyBindingAction.WORKSPACE_LEFT:
 | 
			
		||||
        //  if (!sessionMode.hasWorkspaces)
 | 
			
		||||
        //      return false;
 | 
			
		||||
        //
 | 
			
		||||
        //     wm.actionMoveWorkspaceLeft();
 | 
			
		||||
        //     return true;
 | 
			
		||||
        // case Meta.KeyBindingAction.WORKSPACE_RIGHT:
 | 
			
		||||
        //  if (!sessionMode.hasWorkspaces)
 | 
			
		||||
        //      return false;
 | 
			
		||||
        //
 | 
			
		||||
        //     wm.actionMoveWorkspaceRight();
 | 
			
		||||
        //     return true;
 | 
			
		||||
        case Meta.KeyBindingAction.WORKSPACE_UP:
 | 
			
		||||
            wm.actionMoveWorkspaceUp();
 | 
			
		||||
            if (!sessionMode.hasWorkspaces)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            wm.actionMoveWorkspace(Meta.MotionDirection.UP);
 | 
			
		||||
            return true;
 | 
			
		||||
        case Meta.KeyBindingAction.WORKSPACE_DOWN:
 | 
			
		||||
            wm.actionMoveWorkspaceDown();
 | 
			
		||||
            if (!sessionMode.hasWorkspaces)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            wm.actionMoveWorkspace(Meta.MotionDirection.DOWN);
 | 
			
		||||
            return true;
 | 
			
		||||
        case Meta.KeyBindingAction.PANEL_RUN_DIALOG:
 | 
			
		||||
        case Meta.KeyBindingAction.COMMAND_2:
 | 
			
		||||
            if (!sessionMode.hasRunDialog)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            getRunDialog().open();
 | 
			
		||||
            return true;
 | 
			
		||||
        case Meta.KeyBindingAction.PANEL_MAIN_MENU:
 | 
			
		||||
@@ -644,6 +651,10 @@ function _findModal(actor) {
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isInModalStack(actor) {
 | 
			
		||||
    return _findModal(actor) != -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * pushModal:
 | 
			
		||||
 * @actor: #ClutterActor which will be given keyboard focus
 | 
			
		||||
@@ -662,17 +673,21 @@ 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;
 | 
			
		||||
        }
 | 
			
		||||
        Meta.disable_unredirect_for_screen(global.screen);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
 | 
			
		||||
@@ -681,7 +696,7 @@ function pushModal(actor, timestamp) {
 | 
			
		||||
    let actorDestroyId = actor.connect('destroy', function() {
 | 
			
		||||
        let index = _findModal(actor);
 | 
			
		||||
        if (index >= 0)
 | 
			
		||||
            modalActorFocusStack.splice(index, 1);
 | 
			
		||||
            popModal(actor);
 | 
			
		||||
    });
 | 
			
		||||
    let curFocus = global.stage.get_key_focus();
 | 
			
		||||
    let curFocusDestroyId;
 | 
			
		||||
@@ -753,12 +768,12 @@ function popModal(actor, timestamp) {
 | 
			
		||||
 | 
			
		||||
    global.end_modal(timestamp);
 | 
			
		||||
    global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
 | 
			
		||||
    Meta.enable_unredirect_for_screen(global.screen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createLookingGlass() {
 | 
			
		||||
    if (lookingGlass == null) {
 | 
			
		||||
        lookingGlass = new LookingGlass.LookingGlass();
 | 
			
		||||
        lookingGlass.slaveTo(panel.actor);
 | 
			
		||||
    }
 | 
			
		||||
    return lookingGlass;
 | 
			
		||||
}
 | 
			
		||||
@@ -896,7 +911,8 @@ function initializeDeferredWork(actor, callback, props) {
 | 
			
		||||
function queueDeferredWork(workId) {
 | 
			
		||||
    let data = _deferredWorkData[workId];
 | 
			
		||||
    if (!data) {
 | 
			
		||||
        global.logError('invalid work id ', workId);
 | 
			
		||||
        let message = 'Invalid work id %d'.format(workId);
 | 
			
		||||
        logError(new Error(message), message);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (_deferredWorkQueue.indexOf(workId) < 0)
 | 
			
		||||
 
 | 
			
		||||
@@ -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,6 +10,7 @@ const Pango = imports.gi.Pango;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Atk = imports.gi.Atk;
 | 
			
		||||
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
 | 
			
		||||
@@ -29,32 +30,33 @@ const State = {
 | 
			
		||||
    FADED_OUT: 4
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function ModalDialog() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const ModalDialog = new Lang.Class({
 | 
			
		||||
    Name: 'ModalDialog',
 | 
			
		||||
 | 
			
		||||
ModalDialog.prototype = {
 | 
			
		||||
    _init: function(params) {
 | 
			
		||||
        params = Params.parse(params, { shellReactive: false,
 | 
			
		||||
                                        styleClass: null });
 | 
			
		||||
                                        styleClass: null,
 | 
			
		||||
                                        parentActor: Main.uiGroup
 | 
			
		||||
                                      });
 | 
			
		||||
 | 
			
		||||
        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);
 | 
			
		||||
        this._group = new St.Widget({ visible: false,
 | 
			
		||||
                                      x: 0,
 | 
			
		||||
                                      y: 0,
 | 
			
		||||
                                      accessible_role: Atk.Role.DIALOG });
 | 
			
		||||
        params.parentActor.add_actor(this._group);
 | 
			
		||||
 | 
			
		||||
        let constraint = new Clutter.BindConstraint({ source: global.stage,
 | 
			
		||||
                                                      coordinate: Clutter.BindCoordinate.POSITION | Clutter.BindCoordinate.SIZE });
 | 
			
		||||
                                                      coordinate: Clutter.BindCoordinate.ALL });
 | 
			
		||||
        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._group.connect('key-release-event', Lang.bind(this, this._onKeyReleaseEvent));
 | 
			
		||||
 | 
			
		||||
        this._backgroundBin = new St.Bin();
 | 
			
		||||
        this._group.add_actor(this._backgroundBin);
 | 
			
		||||
@@ -89,6 +91,7 @@ ModalDialog.prototype = {
 | 
			
		||||
                                 y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        this._buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box',
 | 
			
		||||
                                                visible:     false,
 | 
			
		||||
                                                vertical:    false });
 | 
			
		||||
        this._dialogLayout.add(this._buttonLayout,
 | 
			
		||||
                               { expand:  true,
 | 
			
		||||
@@ -97,6 +100,7 @@ ModalDialog.prototype = {
 | 
			
		||||
 | 
			
		||||
        global.focus_manager.add_group(this._dialogLayout);
 | 
			
		||||
        this._initialKeyFocus = this._dialogLayout;
 | 
			
		||||
        this._initialKeyFocusDestroyId = 0;
 | 
			
		||||
        this._savedKeyFocus = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -104,23 +108,34 @@ ModalDialog.prototype = {
 | 
			
		||||
        this._group.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setActionKey: function(key, action) {
 | 
			
		||||
        this._actionKeys[key] = action;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setButtons: function(buttons) {
 | 
			
		||||
        let hadChildren = this._buttonLayout.get_children() > 0;
 | 
			
		||||
 | 
			
		||||
        this._buttonLayout.destroy_children();
 | 
			
		||||
        this._buttonLayout.destroy_all_children();
 | 
			
		||||
        this._actionKeys = {};
 | 
			
		||||
 | 
			
		||||
        let i = 0;
 | 
			
		||||
        for (let index in buttons) {
 | 
			
		||||
            let buttonInfo = buttons[index];
 | 
			
		||||
        this._buttonLayout.visible = (buttons.length > 0);
 | 
			
		||||
 | 
			
		||||
        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 isDefault = buttonInfo['default'];
 | 
			
		||||
 | 
			
		||||
            if (isDefault && !key)
 | 
			
		||||
                key = Clutter.KEY_Return;
 | 
			
		||||
 | 
			
		||||
            buttonInfo.button = new St.Button({ style_class: 'modal-dialog-button',
 | 
			
		||||
                                                reactive:    true,
 | 
			
		||||
                                                can_focus:   true,
 | 
			
		||||
                                                label:       label });
 | 
			
		||||
            if (isDefault)
 | 
			
		||||
                buttonInfo.button.add_style_pseudo_class('default');
 | 
			
		||||
 | 
			
		||||
            let x_alignment;
 | 
			
		||||
            if (buttons.length == 1)
 | 
			
		||||
@@ -132,7 +147,8 @@ ModalDialog.prototype = {
 | 
			
		||||
            else
 | 
			
		||||
                x_alignment = St.Align.MIDDLE;
 | 
			
		||||
 | 
			
		||||
            this._initialKeyFocus = buttonInfo.button;
 | 
			
		||||
            if (!this._initialKeyFocusDestroyId)
 | 
			
		||||
                this._initialKeyFocus = buttonInfo.button;
 | 
			
		||||
            this._buttonLayout.add(buttonInfo.button,
 | 
			
		||||
                                   { expand: true,
 | 
			
		||||
                                     x_fill: false,
 | 
			
		||||
@@ -144,11 +160,10 @@ ModalDialog.prototype = {
 | 
			
		||||
 | 
			
		||||
            if (key)
 | 
			
		||||
                this._actionKeys[key] = action;
 | 
			
		||||
            i++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Fade in buttons if there weren't any before
 | 
			
		||||
        if (!hadChildren && i > 0) {
 | 
			
		||||
        if (!hadChildren && buttons.length > 0) {
 | 
			
		||||
            this._buttonLayout.opacity = 0;
 | 
			
		||||
            Tweener.addTween(this._buttonLayout,
 | 
			
		||||
                             { opacity: 255,
 | 
			
		||||
@@ -164,12 +179,16 @@ ModalDialog.prototype = {
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeyPressEvent: function(object, keyPressEvent) {
 | 
			
		||||
        let symbol = keyPressEvent.get_key_symbol();
 | 
			
		||||
    _onKeyReleaseEvent: function(object, event) {
 | 
			
		||||
        let symbol = event.get_key_symbol();
 | 
			
		||||
        let action = this._actionKeys[symbol];
 | 
			
		||||
 | 
			
		||||
        if (action)
 | 
			
		||||
        if (action) {
 | 
			
		||||
            action();
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onGroupDestroy: function() {
 | 
			
		||||
@@ -177,7 +196,7 @@ ModalDialog.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _fadeOpen: function() {
 | 
			
		||||
        let monitor = Main.layoutManager.focusMonitor;
 | 
			
		||||
        let monitor = Main.layoutManager.currentMonitor;
 | 
			
		||||
 | 
			
		||||
        this._backgroundBin.set_position(monitor.x, monitor.y);
 | 
			
		||||
        this._backgroundBin.set_size(monitor.width, monitor.height);
 | 
			
		||||
@@ -202,7 +221,15 @@ ModalDialog.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setInitialKeyFocus: function(actor) {
 | 
			
		||||
        if (this._initialKeyFocusDestroyId)
 | 
			
		||||
            this._initialKeyFocus.disconnect(this._initialKeyFocusDestroyId);
 | 
			
		||||
 | 
			
		||||
        this._initialKeyFocus = actor;
 | 
			
		||||
 | 
			
		||||
        this._initialKeyFocusDestroyId = actor.connect('destroy', Lang.bind(this, function() {
 | 
			
		||||
            this._initialKeyFocus = this._dialogLayout;
 | 
			
		||||
            this._initialKeyFocusDestroyId = 0;
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    open: function(timestamp) {
 | 
			
		||||
@@ -303,5 +330,5 @@ ModalDialog.prototype = {
 | 
			
		||||
                               })
 | 
			
		||||
                         });
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ModalDialog.prototype);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 *
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2011 Giovanni Campagna <scampa.giovanni@gmail.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
@@ -21,6 +21,8 @@
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const GObject = imports.gi.GObject;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const NetworkManager = imports.gi.NetworkManager;
 | 
			
		||||
const NMClient = imports.gi.NMClient;
 | 
			
		||||
@@ -28,18 +30,19 @@ const Pango = imports.gi.Pango;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const Config = imports.misc.config;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const PopupMenu = imports.ui.popupMenu;
 | 
			
		||||
const ShellEntry = imports.ui.shellEntry;
 | 
			
		||||
 | 
			
		||||
function NetworkSecretDialog() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
const VPN_UI_GROUP = 'VPN Plugin UI';
 | 
			
		||||
 | 
			
		||||
NetworkSecretDialog.prototype = {
 | 
			
		||||
    __proto__: ModalDialog.ModalDialog.prototype,
 | 
			
		||||
const NetworkSecretDialog = new Lang.Class({
 | 
			
		||||
    Name: 'NetworkSecretDialog',
 | 
			
		||||
    Extends: ModalDialog.ModalDialog,
 | 
			
		||||
 | 
			
		||||
    _init: function(agent, requestId, connection, settingName, hints) {
 | 
			
		||||
        ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'polkit-dialog' });
 | 
			
		||||
    _init: function(agent, requestId, connection, settingName, hints, contentOverride) {
 | 
			
		||||
        this.parent({ styleClass: 'prompt-dialog' });
 | 
			
		||||
 | 
			
		||||
        this._agent = agent;
 | 
			
		||||
        this._requestId = requestId;
 | 
			
		||||
@@ -47,9 +50,12 @@ NetworkSecretDialog.prototype = {
 | 
			
		||||
        this._settingName = settingName;
 | 
			
		||||
        this._hints = hints;
 | 
			
		||||
 | 
			
		||||
        this._content = this._getContent();
 | 
			
		||||
        if (contentOverride)
 | 
			
		||||
            this._content = contentOverride;
 | 
			
		||||
        else
 | 
			
		||||
            this._content = this._getContent();
 | 
			
		||||
 | 
			
		||||
        let mainContentBox = new St.BoxLayout({ style_class: 'polkit-dialog-main-layout',
 | 
			
		||||
        let mainContentBox = new St.BoxLayout({ style_class: 'prompt-dialog-main-layout',
 | 
			
		||||
                                                vertical: false });
 | 
			
		||||
        this.contentLayout.add(mainContentBox,
 | 
			
		||||
                               { x_fill: true,
 | 
			
		||||
@@ -62,19 +68,19 @@ NetworkSecretDialog.prototype = {
 | 
			
		||||
                             x_align: St.Align.END,
 | 
			
		||||
                             y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        let messageBox = new St.BoxLayout({ style_class: 'polkit-dialog-message-layout',
 | 
			
		||||
        let messageBox = new St.BoxLayout({ style_class: 'prompt-dialog-message-layout',
 | 
			
		||||
                                            vertical: true });
 | 
			
		||||
        mainContentBox.add(messageBox,
 | 
			
		||||
                           { y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        let subjectLabel = new St.Label({ style_class: 'polkit-dialog-headline',
 | 
			
		||||
        let subjectLabel = new St.Label({ style_class: 'prompt-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',
 | 
			
		||||
            let descriptionLabel = new St.Label({ style_class: 'prompt-dialog-description',
 | 
			
		||||
                                                  text: this._content.message,
 | 
			
		||||
                                                  // HACK: for reasons unknown to me, the label
 | 
			
		||||
                                                  // is not asked the correct height for width,
 | 
			
		||||
@@ -91,17 +97,20 @@ NetworkSecretDialog.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let secretTable = new St.Table({ style_class: 'network-dialog-secret-table' });
 | 
			
		||||
        let initialFocusSet = false;
 | 
			
		||||
        let pos = 0;
 | 
			
		||||
        for (let i = 0; i < this._content.secrets.length; i++) {
 | 
			
		||||
            let secret = this._content.secrets[i];
 | 
			
		||||
            let label = new St.Label({ style_class: 'polkit-dialog-password-label',
 | 
			
		||||
            let label = new St.Label({ style_class: 'prompt-dialog-password-label',
 | 
			
		||||
                                       text: secret.label });
 | 
			
		||||
 | 
			
		||||
            let reactive = secret.key != null;
 | 
			
		||||
 | 
			
		||||
            secret.entry = new St.Entry({ style_class: 'polkit-dialog-password-entry',
 | 
			
		||||
            secret.entry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
 | 
			
		||||
                                          text: secret.value, can_focus: reactive,
 | 
			
		||||
                                          reactive: reactive });
 | 
			
		||||
            ShellEntry.addContextMenu(secret.entry,
 | 
			
		||||
                                      { isPassword: secret.password });
 | 
			
		||||
 | 
			
		||||
            if (secret.validate)
 | 
			
		||||
                secret.valid = secret.validate(secret);
 | 
			
		||||
@@ -109,6 +118,12 @@ NetworkSecretDialog.prototype = {
 | 
			
		||||
                secret.valid = secret.value.length > 0;
 | 
			
		||||
 | 
			
		||||
            if (reactive) {
 | 
			
		||||
                if (!initialFocusSet) {
 | 
			
		||||
                    this.setInitialKeyFocus(secret.entry);
 | 
			
		||||
                    initialFocusSet = true;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                secret.entry.clutter_text.connect('activate', Lang.bind(this, this._onOk));
 | 
			
		||||
                secret.entry.clutter_text.connect('text-changed', Lang.bind(this, function() {
 | 
			
		||||
                    secret.value = secret.entry.get_text();
 | 
			
		||||
                    if (secret.validate)
 | 
			
		||||
@@ -120,39 +135,19 @@ NetworkSecretDialog.prototype = {
 | 
			
		||||
            } else
 | 
			
		||||
                secret.valid = true;
 | 
			
		||||
 | 
			
		||||
            secretTable.add(label, { row: pos, col: 0, x_align: St.Align.START, y_align: St.Align.START });
 | 
			
		||||
            secretTable.add(label, { row: pos, col: 0, x_expand: false, x_fill: true, x_align: St.Align.START, y_align: St.Align.START });
 | 
			
		||||
            secretTable.add(secret.entry, { row: pos, col: 1, x_expand: true, x_fill: true, y_align: St.Align.END });
 | 
			
		||||
            pos++;
 | 
			
		||||
 | 
			
		||||
            if (secret.password) {
 | 
			
		||||
            if (secret.password)
 | 
			
		||||
                secret.entry.clutter_text.set_password_char('\u25cf');
 | 
			
		||||
 | 
			
		||||
                // FIXME: need a real checkbox here
 | 
			
		||||
                let button = new St.Button({ button_mask: St.ButtonMask.ONE,
 | 
			
		||||
                                             can_focus: true });
 | 
			
		||||
                let checkbox = new St.BoxLayout({ vertical: false,
 | 
			
		||||
                                                  style_class: 'network-dialog-show-password-checkbox' 
 | 
			
		||||
                                                });
 | 
			
		||||
                let _switch = new PopupMenu.Switch(false);
 | 
			
		||||
                checkbox.add(_switch.actor);
 | 
			
		||||
                checkbox.add(new St.Label({ text: _("Show password") }), { expand: true });
 | 
			
		||||
                button.connect('clicked', function() {
 | 
			
		||||
                    _switch.toggle();
 | 
			
		||||
                    if (_switch.state)
 | 
			
		||||
                        secret.entry.clutter_text.set_password_char('');
 | 
			
		||||
                    else
 | 
			
		||||
                        secret.entry.clutter_text.set_password_char('\u25cf');
 | 
			
		||||
                });
 | 
			
		||||
                button.child = checkbox;
 | 
			
		||||
                secretTable.add(button, { row: pos, col: 1, x_expand: true, x_fill: true, y_fill: true })
 | 
			
		||||
                pos++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        messageBox.add(secretTable);
 | 
			
		||||
 | 
			
		||||
        this._okButton = { label:  _("Connect"),
 | 
			
		||||
                           action: Lang.bind(this, this._onOk),
 | 
			
		||||
                           key:    Clutter.KEY_Return,
 | 
			
		||||
                           default: true
 | 
			
		||||
                         };
 | 
			
		||||
 | 
			
		||||
        this.setButtons([{ label: _("Cancel"),
 | 
			
		||||
@@ -170,11 +165,6 @@ NetworkSecretDialog.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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() {
 | 
			
		||||
@@ -187,14 +177,14 @@ NetworkSecretDialog.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (valid) {
 | 
			
		||||
            this._agent.respond(this._requestId, false);
 | 
			
		||||
            this._agent.respond(this._requestId, Shell.NetworkAgentResponse.CONFIRMED);
 | 
			
		||||
            this.close(global.get_current_time());
 | 
			
		||||
        }
 | 
			
		||||
        // do nothing if not valid
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    cancel: function() {
 | 
			
		||||
        this._agent.respond(this._requestId, true);
 | 
			
		||||
        this._agent.respond(this._requestId, Shell.NetworkAgentResponse.USER_CANCELED);
 | 
			
		||||
        this.close(global.get_current_time());
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -360,7 +350,7 @@ NetworkSecretDialog.prototype = {
 | 
			
		||||
        case 'bluetooth':
 | 
			
		||||
            content.title = _("Mobile broadband network password");
 | 
			
		||||
            content.message = _("A password is required to connect to '%s'.").format(connectionSetting.get_id());
 | 
			
		||||
            this._getMobileSecrets(content.secrets);
 | 
			
		||||
            this._getMobileSecrets(content.secrets, connectionType);
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            log('Invalid connection type: ' + connectionType);
 | 
			
		||||
@@ -368,23 +358,263 @@ NetworkSecretDialog.prototype = {
 | 
			
		||||
 | 
			
		||||
        return content;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function NetworkAgent() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
const VPNRequestHandler = new Lang.Class({
 | 
			
		||||
    Name: 'VPNRequestHandler',
 | 
			
		||||
 | 
			
		||||
    _init: function(agent, requestId, authHelper, serviceType, connection, hints, flags) {
 | 
			
		||||
        this._agent = agent;
 | 
			
		||||
        this._requestId = requestId;
 | 
			
		||||
        this._connection = connection;
 | 
			
		||||
        this._pluginOutBuffer = [];
 | 
			
		||||
        this._title = null;
 | 
			
		||||
        this._description = null;
 | 
			
		||||
        this._content = [ ];
 | 
			
		||||
        this._shellDialog = null;
 | 
			
		||||
 | 
			
		||||
        let connectionSetting = connection.get_setting_connection();
 | 
			
		||||
 | 
			
		||||
        let argv = [ authHelper.fileName,
 | 
			
		||||
                     '-u', connectionSetting.uuid,
 | 
			
		||||
                     '-n', connectionSetting.id,
 | 
			
		||||
                     '-s', serviceType
 | 
			
		||||
                   ];
 | 
			
		||||
        if (authHelper.externalUIMode)
 | 
			
		||||
            argv.push('--external-ui-mode');
 | 
			
		||||
        if (flags & NMClient.SecretAgentGetSecretsFlags.ALLOW_INTERACTION)
 | 
			
		||||
            argv.push('-i');
 | 
			
		||||
        if (flags & NMClient.SecretAgentGetSecretsFlags.REQUEST_NEW)
 | 
			
		||||
            argv.push('-r');
 | 
			
		||||
 | 
			
		||||
        this._newStylePlugin = authHelper.externalUIMode;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            let [success, pid, stdin, stdout, stderr] =
 | 
			
		||||
                GLib.spawn_async_with_pipes(null, /* pwd */
 | 
			
		||||
                                            argv,
 | 
			
		||||
                                            null, /* envp */
 | 
			
		||||
                                            GLib.SpawnFlags.DO_NOT_REAP_CHILD,
 | 
			
		||||
                                            null /* child_setup */);
 | 
			
		||||
 | 
			
		||||
            this._childPid = pid;
 | 
			
		||||
            this._stdin = new Gio.UnixOutputStream({ fd: stdin, close_fd: true });
 | 
			
		||||
            this._stdout = new Gio.UnixInputStream({ fd: stdout, close_fd: true });
 | 
			
		||||
            // We need this one too, even if don't actually care of what the process
 | 
			
		||||
            // has to say on stderr, because otherwise the fd opened by g_spawn_async_with_pipes
 | 
			
		||||
            // is kept open indefinitely
 | 
			
		||||
            let stderrStream = new Gio.UnixInputStream({ fd: stderr, close_fd: true });
 | 
			
		||||
            stderrStream.close(null);
 | 
			
		||||
            this._dataStdout = new Gio.DataInputStream({ base_stream: this._stdout });
 | 
			
		||||
 | 
			
		||||
            if (this._newStylePlugin)
 | 
			
		||||
                this._readStdoutNewStyle();
 | 
			
		||||
            else
 | 
			
		||||
                this._readStdoutOldStyle();
 | 
			
		||||
 | 
			
		||||
            this._childWatch = GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid,
 | 
			
		||||
                                                    Lang.bind(this, this._vpnChildFinished));
 | 
			
		||||
 | 
			
		||||
            this._writeConnection();
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            logError(e, 'error while spawning VPN auth helper');
 | 
			
		||||
 | 
			
		||||
            this._agent.respond(requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    cancel: function() {
 | 
			
		||||
        if (this._newStylePlugin && this._shellDialog) {
 | 
			
		||||
            this._shellDialog.close(global.get_current_time());
 | 
			
		||||
            this._shellDialog.destroy();
 | 
			
		||||
        } else {
 | 
			
		||||
            try {
 | 
			
		||||
                this._stdin.write('QUIT\n\n', null);
 | 
			
		||||
            } catch(e) { /* ignore broken pipe errors */ }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
        if (this._destroyed)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        GLib.source_remove(this._childWatch);
 | 
			
		||||
 | 
			
		||||
        this._stdin.close(null);
 | 
			
		||||
        // Stdout is closed when we finish reading from it
 | 
			
		||||
 | 
			
		||||
        this._destroyed = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _vpnChildFinished: function(pid, status, requestObj) {
 | 
			
		||||
        if (this._newStylePlugin) {
 | 
			
		||||
            // For new style plugin, all work is done in the async reading functions
 | 
			
		||||
            // Just reap the process here
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let [exited, exitStatus] = Shell.util_wifexited(status);
 | 
			
		||||
 | 
			
		||||
        if (exited) {
 | 
			
		||||
            if (exitStatus != 0)
 | 
			
		||||
                this._agent.respond(this._requestId, Shell.NetworkAgentResponse.USER_CANCELED);
 | 
			
		||||
            else
 | 
			
		||||
                this._agent.respond(this._requestId, Shell.NetworkAgentResponse.CONFIRMED);
 | 
			
		||||
        } else
 | 
			
		||||
            this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
 | 
			
		||||
 | 
			
		||||
        this.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _vpnChildProcessLineOldStyle: function(line) {
 | 
			
		||||
        if (this._previousLine != undefined) {
 | 
			
		||||
            // Two consecutive newlines mean that the child should be closed
 | 
			
		||||
            // (the actual newlines are eaten by Gio.DataInputStream)
 | 
			
		||||
            // Send a termination message
 | 
			
		||||
            if (line == '' && this._previousLine == '') {
 | 
			
		||||
                try {
 | 
			
		||||
                    this._stdin.write('QUIT\n\n', null);
 | 
			
		||||
                } catch(e) { /* ignore broken pipe errors */ }
 | 
			
		||||
            } else {
 | 
			
		||||
                this._agent.set_password(this._requestId, this._previousLine, line);
 | 
			
		||||
                this._previousLine = undefined;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            this._previousLine = line;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _readStdoutOldStyle: function() {
 | 
			
		||||
        this._dataStdout.read_line_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(stream, result) {
 | 
			
		||||
            let [line, len] = this._dataStdout.read_line_finish_utf8(result);
 | 
			
		||||
 | 
			
		||||
            if (line == null) {
 | 
			
		||||
                // end of file
 | 
			
		||||
                this._stdout.close(null);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this._vpnChildProcessLineOldStyle(line);
 | 
			
		||||
 | 
			
		||||
            // try to read more!
 | 
			
		||||
            this._readStdoutOldStyle();
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _readStdoutNewStyle: function() {
 | 
			
		||||
        this._dataStdout.fill_async(-1, GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(stream, result) {
 | 
			
		||||
            let cnt = this._dataStdout.fill_finish(result);
 | 
			
		||||
 | 
			
		||||
            if (cnt == 0) {
 | 
			
		||||
                // end of file
 | 
			
		||||
                this._showNewStyleDialog();
 | 
			
		||||
 | 
			
		||||
                this._stdout.close(null);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Try to read more
 | 
			
		||||
            this._dataStdout.set_buffer_size(2 * this._dataStdout.get_buffer_size());
 | 
			
		||||
            this._readStdoutNewStyle();
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showNewStyleDialog: function() {
 | 
			
		||||
        let keyfile = new GLib.KeyFile();
 | 
			
		||||
        let contentOverride;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            let data = this._dataStdout.peek_buffer();
 | 
			
		||||
            keyfile.load_from_data(data.toString(), data.length,
 | 
			
		||||
                                   GLib.KeyFileFlags.NONE);
 | 
			
		||||
 | 
			
		||||
            if (keyfile.get_integer(VPN_UI_GROUP, 'Version') != 2)
 | 
			
		||||
                throw new Error('Invalid plugin keyfile version, is %d');
 | 
			
		||||
 | 
			
		||||
            contentOverride = { title: keyfile.get_string(VPN_UI_GROUP, 'Title'),
 | 
			
		||||
                                message: keyfile.get_string(VPN_UI_GROUP, 'Description'),
 | 
			
		||||
                                secrets: [] };
 | 
			
		||||
 | 
			
		||||
            let [groups, len] = keyfile.get_groups();
 | 
			
		||||
            for (let i = 0; i < groups.length; i++) {
 | 
			
		||||
                if (groups[i] == VPN_UI_GROUP)
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                let value = keyfile.get_string(groups[i], 'Value');
 | 
			
		||||
                let shouldAsk = keyfile.get_boolean(groups[i], 'ShouldAsk');
 | 
			
		||||
 | 
			
		||||
                if (shouldAsk) {
 | 
			
		||||
                    contentOverride.secrets.push({ label: keyfile.get_string(groups[i], 'Label'),
 | 
			
		||||
                                                   key: groups[i],
 | 
			
		||||
                                                   value: value,
 | 
			
		||||
                                                   password: keyfile.get_boolean(groups[i], 'IsSecret')
 | 
			
		||||
                                                 });
 | 
			
		||||
                } else {
 | 
			
		||||
                    if (!value.length) // Ignore empty secrets
 | 
			
		||||
                        continue;
 | 
			
		||||
 | 
			
		||||
                    this._agent.set_password(this._requestId, groups[i], value);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            logError(e, 'error while reading VPN plugin output keyfile');
 | 
			
		||||
 | 
			
		||||
            this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (contentOverride.secrets.length) {
 | 
			
		||||
            // Only show the dialog if we actually have something to ask
 | 
			
		||||
            this._shellDialog = new NetworkSecretDialog(this._agent, this._requestId, this._connection, 'vpn', [], contentOverride);
 | 
			
		||||
            this._shellDialog.open(global.get_current_time());
 | 
			
		||||
        } else {
 | 
			
		||||
            this._agent.respond(this._requestId, Shell.NetworkAgentResponse.CONFIRMED);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _writeConnection: function() {
 | 
			
		||||
        let vpnSetting = this._connection.get_setting_vpn();
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            vpnSetting.foreach_data_item(Lang.bind(this, function(key, value) {
 | 
			
		||||
                this._stdin.write('DATA_KEY=' + key + '\n', null);
 | 
			
		||||
                this._stdin.write('DATA_VAL=' + (value || '') + '\n\n', null);
 | 
			
		||||
            }));
 | 
			
		||||
            vpnSetting.foreach_secret(Lang.bind(this, function(key, value) {
 | 
			
		||||
                this._stdin.write('SECRET_KEY=' + key + '\n', null);
 | 
			
		||||
                this._stdin.write('SECRET_VAL=' + (value || '') + '\n\n', null);
 | 
			
		||||
            }));
 | 
			
		||||
            this._stdin.write('DONE\n\n', null);
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            logError(e, 'internal error while writing connection to helper');
 | 
			
		||||
 | 
			
		||||
            this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const NetworkAgent = new Lang.Class({
 | 
			
		||||
    Name: 'NetworkAgent',
 | 
			
		||||
 | 
			
		||||
NetworkAgent.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._native = new Shell.NetworkAgent({ auto_register: true,
 | 
			
		||||
                                                identifier: 'org.gnome.Shell.NetworkAgent' });
 | 
			
		||||
 | 
			
		||||
        this._dialogs = { };
 | 
			
		||||
        this._vpnRequests = { };
 | 
			
		||||
 | 
			
		||||
        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) {
 | 
			
		||||
    _newRequest:  function(agent, requestId, connection, settingName, hints, flags) {
 | 
			
		||||
        if (settingName == 'vpn') {
 | 
			
		||||
            this._vpnRequest(requestId, connection, hints, flags);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let dialog = new NetworkSecretDialog(agent, requestId, connection, settingName, hints);
 | 
			
		||||
        dialog.connect('destroy', Lang.bind(this, function() {
 | 
			
		||||
            delete this._dialogs[requestId];
 | 
			
		||||
@@ -394,7 +624,77 @@ NetworkAgent.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _cancelRequest: function(agent, requestId) {
 | 
			
		||||
        this._dialogs[requestId].close(global.get_current_time());
 | 
			
		||||
        this._dialogs[requestId].destroy();
 | 
			
		||||
        if (this._dialogs[requestId]) {
 | 
			
		||||
            this._dialogs[requestId].close(global.get_current_time());
 | 
			
		||||
            this._dialogs[requestId].destroy();
 | 
			
		||||
            delete this._dialogs[requestId];
 | 
			
		||||
        } else if (this._vpnRequests[requestId]) {
 | 
			
		||||
            this._vpnRequests[requestId].cancel();
 | 
			
		||||
            delete this._vpnRequests[requestId];
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _vpnRequest: function(requestId, connection, hints, flags) {
 | 
			
		||||
        let vpnSetting = connection.get_setting_vpn();
 | 
			
		||||
        let serviceType = vpnSetting.service_type;
 | 
			
		||||
 | 
			
		||||
        this._buildVPNServiceCache();
 | 
			
		||||
 | 
			
		||||
        let binary = this._vpnBinaries[serviceType];
 | 
			
		||||
        if (!binary) {
 | 
			
		||||
            log('Invalid VPN service type (cannot find authentication binary)');
 | 
			
		||||
 | 
			
		||||
            /* cancel the auth process */
 | 
			
		||||
            this._native.respond(requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._vpnRequests[requestId] = new VPNRequestHandler(this._native, requestId, binary, serviceType, connection, hints, flags);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _buildVPNServiceCache: function() {
 | 
			
		||||
        if (this._vpnCacheBuilt)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._vpnCacheBuilt = true;
 | 
			
		||||
        this._vpnBinaries = { };
 | 
			
		||||
 | 
			
		||||
        let dir = Gio.file_new_for_path(GLib.build_filenamev([Config.SYSCONFDIR, 'NetworkManager/VPN']));
 | 
			
		||||
        try {
 | 
			
		||||
            let fileEnum = dir.enumerate_children('standard::name', Gio.FileQueryInfoFlags.NONE, null);
 | 
			
		||||
            let info;
 | 
			
		||||
 | 
			
		||||
            while ((info = fileEnum.next_file(null))) {
 | 
			
		||||
                let name = info.get_name();
 | 
			
		||||
                if (name.substr(-5) != '.name')
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                try {
 | 
			
		||||
                    let keyfile = new GLib.KeyFile();
 | 
			
		||||
                    keyfile.load_from_file(dir.get_child(name).get_path(), GLib.KeyFileFlags.NONE);
 | 
			
		||||
                    let service = keyfile.get_string('VPN Connection', 'service');
 | 
			
		||||
                    let binary = keyfile.get_string('GNOME', 'auth-dialog');
 | 
			
		||||
                    let externalUIMode = false;
 | 
			
		||||
                    try {
 | 
			
		||||
                        externalUIMode = keyfile.get_boolean('GNOME', 'supports-external-ui-mode');
 | 
			
		||||
                    } catch(e) { } // ignore errors if key does not exist
 | 
			
		||||
                    let path = binary;
 | 
			
		||||
                    if (!GLib.path_is_absolute(path)) {
 | 
			
		||||
                        path = GLib.build_filenamev([Config.LIBEXECDIR, path]);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (GLib.file_test(path, GLib.FileTest.IS_EXECUTABLE))
 | 
			
		||||
                        this._vpnBinaries[service] = { fileName: path, externalUIMode: externalUIMode };
 | 
			
		||||
                    else
 | 
			
		||||
                        throw new Error('VPN plugin at %s is not executable'.format(path));
 | 
			
		||||
                } catch(e) {
 | 
			
		||||
                    log('Error \'%s\' while processing VPN keyfile \'%s\''.
 | 
			
		||||
                        format(e.message, dir.get_child(name).get_path()));
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            logError(e, 'error while enumerating VPN auth helpers');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,8 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const DBus = imports.dbus;
 | 
			
		||||
const GdkPixbuf = imports.gi.GdkPixbuf;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
@@ -16,49 +17,52 @@ const Util = imports.misc.util;
 | 
			
		||||
 | 
			
		||||
let nextNotificationId = 1;
 | 
			
		||||
 | 
			
		||||
// Should really be defined in dbus.js
 | 
			
		||||
const BusIface = {
 | 
			
		||||
    name: 'org.freedesktop.DBus',
 | 
			
		||||
    methods: [{ name: 'GetConnectionUnixProcessID',
 | 
			
		||||
                inSignature: 's',
 | 
			
		||||
                outSignature: 'i' }]
 | 
			
		||||
};
 | 
			
		||||
// Should really be defined in Gio.js
 | 
			
		||||
const BusIface = <interface name="org.freedesktop.DBus">
 | 
			
		||||
<method name="GetConnectionUnixProcessID">
 | 
			
		||||
    <arg type="s" direction="in" />
 | 
			
		||||
    <arg type="u" direction="out" />
 | 
			
		||||
</method>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const Bus = function () {
 | 
			
		||||
    this._init();
 | 
			
		||||
};
 | 
			
		||||
var BusProxy = Gio.DBusProxy.makeProxyWrapper(BusIface);
 | 
			
		||||
function Bus() {
 | 
			
		||||
    return new BusProxy(Gio.DBus.session, 'org.freedesktop.DBus', '/org/freedesktop/DBus');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Bus.prototype = {
 | 
			
		||||
     _init: function() {
 | 
			
		||||
         DBus.session.proxifyObject(this, 'org.freedesktop.DBus', '/org/freedesktop/DBus');
 | 
			
		||||
     }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
DBus.proxifyPrototype(Bus.prototype, BusIface);
 | 
			
		||||
 | 
			
		||||
const NotificationDaemonIface = {
 | 
			
		||||
    name: 'org.freedesktop.Notifications',
 | 
			
		||||
    methods: [{ name: 'Notify',
 | 
			
		||||
                inSignature: 'susssasa{sv}i',
 | 
			
		||||
                outSignature: 'u'
 | 
			
		||||
              },
 | 
			
		||||
              { name: 'CloseNotification',
 | 
			
		||||
                inSignature: 'u',
 | 
			
		||||
                outSignature: ''
 | 
			
		||||
              },
 | 
			
		||||
              { name: 'GetCapabilities',
 | 
			
		||||
                inSignature: '',
 | 
			
		||||
                outSignature: 'as'
 | 
			
		||||
              },
 | 
			
		||||
              { name: 'GetServerInformation',
 | 
			
		||||
                inSignature: '',
 | 
			
		||||
                outSignature: 'ssss'
 | 
			
		||||
              }],
 | 
			
		||||
    signals: [{ name: 'NotificationClosed',
 | 
			
		||||
                inSignature: 'uu' },
 | 
			
		||||
              { name: 'ActionInvoked',
 | 
			
		||||
                inSignature: 'us' }]
 | 
			
		||||
};
 | 
			
		||||
const NotificationDaemonIface = <interface name="org.freedesktop.Notifications">
 | 
			
		||||
<method name="Notify">
 | 
			
		||||
    <arg type="s" direction="in"/>
 | 
			
		||||
    <arg type="u" direction="in"/>
 | 
			
		||||
    <arg type="s" direction="in"/>
 | 
			
		||||
    <arg type="s" direction="in"/>
 | 
			
		||||
    <arg type="s" direction="in"/>
 | 
			
		||||
    <arg type="as" direction="in"/>
 | 
			
		||||
    <arg type="a{sv}" direction="in"/>
 | 
			
		||||
    <arg type="i" direction="in"/>
 | 
			
		||||
    <arg type="u" direction="out"/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name="CloseNotification">
 | 
			
		||||
    <arg type="u" direction="in"/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name="GetCapabilities">
 | 
			
		||||
    <arg type="as" direction="out"/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name="GetServerInformation">
 | 
			
		||||
    <arg type="s" direction="out"/>
 | 
			
		||||
    <arg type="s" direction="out"/>
 | 
			
		||||
    <arg type="s" direction="out"/>
 | 
			
		||||
    <arg type="s" direction="out"/>
 | 
			
		||||
</method>
 | 
			
		||||
<signal name="NotificationClosed">
 | 
			
		||||
    <arg type="u"/>
 | 
			
		||||
    <arg type="u"/>
 | 
			
		||||
</signal>
 | 
			
		||||
<signal name="ActionInvoked">
 | 
			
		||||
    <arg type="u"/>
 | 
			
		||||
    <arg type="s"/>
 | 
			
		||||
</signal>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const NotificationClosedReason = {
 | 
			
		||||
    EXPIRED: 1,
 | 
			
		||||
@@ -84,41 +88,68 @@ const rewriteRules = {
 | 
			
		||||
    ]
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function NotificationDaemon() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
 | 
			
		||||
    'bluetooth-applet': 'bluetooth',
 | 
			
		||||
    'gnome-volume-control-applet': 'volume', // renamed to gnome-sound-applet
 | 
			
		||||
                                             // when moved to control center
 | 
			
		||||
    'gnome-sound-applet': 'volume',
 | 
			
		||||
    'nm-applet': 'network',
 | 
			
		||||
    'gnome-power-manager': 'battery',
 | 
			
		||||
    'keyboard': 'keyboard',
 | 
			
		||||
    'a11y-keyboard': 'a11y',
 | 
			
		||||
    'kbd-scrolllock': 'keyboard',
 | 
			
		||||
    'kbd-numlock': 'keyboard',
 | 
			
		||||
    'kbd-capslock': 'keyboard',
 | 
			
		||||
    'ibus-ui-gtk': 'keyboard'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const NotificationDaemon = new Lang.Class({
 | 
			
		||||
    Name: 'NotificationDaemon',
 | 
			
		||||
 | 
			
		||||
NotificationDaemon.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        DBus.session.exportObject('/org/freedesktop/Notifications', this);
 | 
			
		||||
        this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(NotificationDaemonIface, this);
 | 
			
		||||
        this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
 | 
			
		||||
 | 
			
		||||
        this._sources = {};
 | 
			
		||||
        this._sources = [];
 | 
			
		||||
        this._senderToPid = {};
 | 
			
		||||
        this._notifications = {};
 | 
			
		||||
        this._busProxy = new Bus();
 | 
			
		||||
 | 
			
		||||
        Main.statusIconDispatcher.connect('message-icon-added', Lang.bind(this, this._onTrayIconAdded));
 | 
			
		||||
        Main.statusIconDispatcher.connect('message-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
 | 
			
		||||
        this._trayManager = new Shell.TrayManager();
 | 
			
		||||
        this._trayManager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
 | 
			
		||||
        this._trayManager.connect('tray-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
 | 
			
		||||
 | 
			
		||||
        Shell.WindowTracker.get_default().connect('notify::focus-app',
 | 
			
		||||
            Lang.bind(this, this._onFocusAppChanged));
 | 
			
		||||
        Main.overview.connect('hidden',
 | 
			
		||||
            Lang.bind(this, this._onFocusAppChanged));
 | 
			
		||||
 | 
			
		||||
        this._trayManager.manage_stage(global.stage, Main.messageTray.actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _iconForNotificationData: function(icon, hints, size) {
 | 
			
		||||
        let textureCache = St.TextureCache.get_default();
 | 
			
		||||
 | 
			
		||||
    _iconForNotificationData: function(icon, hints) {
 | 
			
		||||
        // 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);
 | 
			
		||||
                return new Gio.FileIcon({ file: Gio.File.new_for_uri(icon) });
 | 
			
		||||
            else if (icon[0] == '/') {
 | 
			
		||||
                let uri = GLib.filename_to_uri(icon, null);
 | 
			
		||||
                return textureCache.load_uri_async(uri, size, size);
 | 
			
		||||
                return new Gio.FileIcon({ file: Gio.File.new_for_path(icon) });
 | 
			
		||||
            } else
 | 
			
		||||
                return new St.Icon({ icon_name: icon,
 | 
			
		||||
                                     icon_type: St.IconType.FULLCOLOR,
 | 
			
		||||
                                     icon_size: size });
 | 
			
		||||
                return new Gio.ThemedIcon({ name: icon });
 | 
			
		||||
        } else if (hints['image-data']) {
 | 
			
		||||
            let [width, height, rowStride, hasAlpha,
 | 
			
		||||
                 bitsPerSample, nChannels, data] = hints['image-data'];
 | 
			
		||||
            return Shell.util_create_pixbuf_from_data(data, GdkPixbuf.Colorspace.RGB, hasAlpha,
 | 
			
		||||
                                                      bitsPerSample, width, height, rowStride);
 | 
			
		||||
        } else if (hints['image-path']) {
 | 
			
		||||
            return new Gio.FileIcon({ file: Gio.File.new_for_path(hints['image-path']) });
 | 
			
		||||
        } else {
 | 
			
		||||
            let stockIcon;
 | 
			
		||||
            switch (hints.urgency) {
 | 
			
		||||
@@ -130,20 +161,34 @@ NotificationDaemon.prototype = {
 | 
			
		||||
                    stockIcon = 'gtk-dialog-error';
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
            return new St.Icon({ icon_name: stockIcon,
 | 
			
		||||
                                 icon_type: St.IconType.FULLCOLOR,
 | 
			
		||||
                                 icon_size: size });
 | 
			
		||||
            return new Gio.ThemedIcon({ name: stockIcon });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _lookupSource: function(title, pid, trayIcon) {
 | 
			
		||||
        for (let i = 0; i < this._sources.length; i++) {
 | 
			
		||||
            let source = this._sources[i];
 | 
			
		||||
            if (source.pid == pid &&
 | 
			
		||||
                (source.initialTitle == title || source.trayIcon || trayIcon))
 | 
			
		||||
                return source;
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Returns the source associated with ndata.notification if it is set.
 | 
			
		||||
    // Otherwise, returns the source associated with the pid if one is
 | 
			
		||||
    // stored in this._sources and the notification is not transient.
 | 
			
		||||
    // Otherwise, creates a new source as long as pid is provided.
 | 
			
		||||
    // Otherwise, returns the source associated with the title and pid if
 | 
			
		||||
    // such source is stored in this._sources and the notification is not
 | 
			
		||||
    // transient. If the existing or requested source is associated with
 | 
			
		||||
    // a tray icon and passed in pid matches a pid of an existing source,
 | 
			
		||||
    // the title match is ignored to enable representing a tray icon and
 | 
			
		||||
    // notifications from the same application with a single source.
 | 
			
		||||
    //
 | 
			
		||||
    // If no existing source is found, a new source is created as long as
 | 
			
		||||
    // pid is provided.
 | 
			
		||||
    //
 | 
			
		||||
    // Either a pid or ndata.notification is needed to retrieve or
 | 
			
		||||
    // create a source.
 | 
			
		||||
    _getSource: function(title, pid, ndata, sender) {
 | 
			
		||||
    _getSource: function(title, pid, ndata, sender, trayIcon) {
 | 
			
		||||
        if (!pid && !(ndata && ndata.notification))
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
@@ -160,20 +205,24 @@ 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]) {
 | 
			
		||||
            let source = this._sources[pid];
 | 
			
		||||
            source.setTitle(title);
 | 
			
		||||
            return source;
 | 
			
		||||
        if (!isForTransientNotification) {
 | 
			
		||||
            let source = this._lookupSource(title, pid, trayIcon);
 | 
			
		||||
            if (source) {
 | 
			
		||||
                source.setTitle(title);
 | 
			
		||||
                return source;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let source = new Source(title, pid, sender);
 | 
			
		||||
        let source = new Source(title, pid, sender, trayIcon);
 | 
			
		||||
        source.setTransient(isForTransientNotification);
 | 
			
		||||
 | 
			
		||||
        if (!isForTransientNotification) {
 | 
			
		||||
            this._sources[pid] = source;
 | 
			
		||||
            this._sources.push(source);
 | 
			
		||||
            source.connect('destroy', Lang.bind(this,
 | 
			
		||||
                function() {
 | 
			
		||||
                    delete this._sources[pid];
 | 
			
		||||
                    let index = this._sources.indexOf(source);
 | 
			
		||||
                    if (index >= 0)
 | 
			
		||||
                        this._sources.splice(index, 1);
 | 
			
		||||
                }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -181,16 +230,23 @@ 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;
 | 
			
		||||
 | 
			
		||||
        for (let hint in hints) {
 | 
			
		||||
            // unpack the variants
 | 
			
		||||
            hints[hint] = hints[hint].deep_unpack();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        hints = Params.parse(hints, { urgency: Urgency.NORMAL }, true);
 | 
			
		||||
 | 
			
		||||
        // 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.transfer.incoming' ||
 | 
			
		||||
              hints['category'] == 'x-empathy.im.subscription-request' ||
 | 
			
		||||
              hints['category'] == 'presence.online' ||
 | 
			
		||||
              hints['category'] == 'presence.offline')) {
 | 
			
		||||
@@ -201,7 +257,7 @@ NotificationDaemon.prototype = {
 | 
			
		||||
                                        function () {
 | 
			
		||||
                                            this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
 | 
			
		||||
                                        }));
 | 
			
		||||
            return id;
 | 
			
		||||
            return invocation.return_value(GLib.Variant.new('(u)', [id]));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let rewrites = rewriteRules[appName];
 | 
			
		||||
@@ -213,8 +269,6 @@ NotificationDaemon.prototype = {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        hints = Params.parse(hints, { urgency: Urgency.NORMAL }, true);
 | 
			
		||||
 | 
			
		||||
        // 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
 | 
			
		||||
 | 
			
		||||
@@ -244,51 +298,55 @@ NotificationDaemon.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
        this._notifications[id] = ndata;
 | 
			
		||||
 | 
			
		||||
        let sender = DBus.getCurrentMessageContext().sender;
 | 
			
		||||
        let sender = invocation.get_sender();
 | 
			
		||||
        let pid = this._senderToPid[sender];
 | 
			
		||||
 | 
			
		||||
        let source = this._getSource(appName, pid, ndata, sender);
 | 
			
		||||
        let source = this._getSource(appName, pid, ndata, sender, null);
 | 
			
		||||
 | 
			
		||||
        if (source) {
 | 
			
		||||
            this._notifyForSource(source, ndata);
 | 
			
		||||
            return id;
 | 
			
		||||
            return invocation.return_value(GLib.Variant.new('(u)', [id]));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (replacesId) {
 | 
			
		||||
            // There's already a pending call to GetConnectionUnixProcessID,
 | 
			
		||||
            // which will see the new notification data when it finishes,
 | 
			
		||||
            // so we don't have to do anything.
 | 
			
		||||
            return id;
 | 
			
		||||
            return invocation.return_value(GLib.Variant.new('(u)', [id]));;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._busProxy.GetConnectionUnixProcessIDRemote(sender, Lang.bind(this,
 | 
			
		||||
            function (pid, ex) {
 | 
			
		||||
                // The app may have updated or removed the notification
 | 
			
		||||
                ndata = this._notifications[id];
 | 
			
		||||
                if (!ndata)
 | 
			
		||||
                    return;
 | 
			
		||||
        this._busProxy.GetConnectionUnixProcessIDRemote(sender, Lang.bind(this, function (result, excp) {
 | 
			
		||||
            // The app may have updated or removed the notification
 | 
			
		||||
            ndata = this._notifications[id];
 | 
			
		||||
            if (!ndata)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
                source = this._getSource(appName, pid, ndata, sender);
 | 
			
		||||
            if (excp) {
 | 
			
		||||
                logError(excp, 'Call to GetConnectionUnixProcessID failed');
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
                // We only store sender-pid entries for persistent sources.
 | 
			
		||||
                // Removing the entries once the source is destroyed
 | 
			
		||||
                // would result in the entries associated with transient
 | 
			
		||||
                // sources removed once the notification is shown anyway.
 | 
			
		||||
                // However, keeping these pairs would mean that we would
 | 
			
		||||
                // possibly remove an entry associated with a persistent
 | 
			
		||||
                // source when a transient source for the same sender is
 | 
			
		||||
                // distroyed.
 | 
			
		||||
                if (!source.isTransient) {
 | 
			
		||||
                    this._senderToPid[sender] = pid;
 | 
			
		||||
                    source.connect('destroy', Lang.bind(this,
 | 
			
		||||
                        function() {
 | 
			
		||||
                            delete this._senderToPid[sender];
 | 
			
		||||
                        }));
 | 
			
		||||
                }
 | 
			
		||||
                this._notifyForSource(source, ndata);
 | 
			
		||||
            }));
 | 
			
		||||
            let [pid] = result;
 | 
			
		||||
            source = this._getSource(appName, pid, ndata, sender, null);
 | 
			
		||||
 | 
			
		||||
        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) {
 | 
			
		||||
@@ -296,7 +354,10 @@ NotificationDaemon.prototype = {
 | 
			
		||||
            [ndata.id, ndata.icon, ndata.summary, ndata.body,
 | 
			
		||||
             ndata.actions, ndata.hints, ndata.notification];
 | 
			
		||||
 | 
			
		||||
        let iconActor = this._iconForNotificationData(icon, hints, source.ICON_SIZE);
 | 
			
		||||
        let gicon = this._iconForNotificationData(icon, hints);
 | 
			
		||||
        let iconActor = new St.Icon({ gicon: gicon,
 | 
			
		||||
                                      icon_type: St.IconType.FULLCOLOR,
 | 
			
		||||
                                      icon_size: source.ICON_SIZE });
 | 
			
		||||
 | 
			
		||||
        if (notification == null) {
 | 
			
		||||
            notification = new MessageTray.Notification(source, summary, body,
 | 
			
		||||
@@ -330,7 +391,8 @@ NotificationDaemon.prototype = {
 | 
			
		||||
                                                 clear: true });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (hints['image-data'] || hints['image-path']) {
 | 
			
		||||
        // We only display a large image if an icon is also specified.
 | 
			
		||||
        if (icon && (hints['image-data'] || hints['image-path'])) {
 | 
			
		||||
            let image = null;
 | 
			
		||||
            if (hints['image-data']) {
 | 
			
		||||
                let [width, height, rowStride, hasAlpha,
 | 
			
		||||
@@ -375,8 +437,8 @@ NotificationDaemon.prototype = {
 | 
			
		||||
        // of the 'transient' hint with hints['transient'] rather than hints.transient
 | 
			
		||||
        notification.setTransient(hints['transient'] == true);
 | 
			
		||||
 | 
			
		||||
        let sourceIconActor = source.useNotificationIcon ? this._iconForNotificationData(icon, hints, source.ICON_SIZE) : null;
 | 
			
		||||
        source.processNotification(notification, sourceIconActor);
 | 
			
		||||
        let sourceGIcon = source.useNotificationIcon ? this._iconForNotificationData(icon, hints) : null;
 | 
			
		||||
        source.processNotification(notification, sourceGIcon);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    CloseNotification: function(id) {
 | 
			
		||||
@@ -417,8 +479,8 @@ NotificationDaemon.prototype = {
 | 
			
		||||
        if (!tracker.focus_app)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        for (let id in this._sources) {
 | 
			
		||||
            let source = this._sources[id];
 | 
			
		||||
        for (let i = 0; i < this._sources.length; i++) {
 | 
			
		||||
            let source = this._sources[i];
 | 
			
		||||
            if (source.app == tracker.focus_app) {
 | 
			
		||||
                source.destroyNonResidentNotifications();
 | 
			
		||||
                return;
 | 
			
		||||
@@ -427,61 +489,59 @@ NotificationDaemon.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _emitNotificationClosed: function(id, reason) {
 | 
			
		||||
        DBus.session.emit_signal('/org/freedesktop/Notifications',
 | 
			
		||||
                                 'org.freedesktop.Notifications',
 | 
			
		||||
                                 'NotificationClosed', 'uu',
 | 
			
		||||
                                 [id, reason]);
 | 
			
		||||
        this._dbusImpl.emit_signal('NotificationClosed',
 | 
			
		||||
                                   GLib.Variant.new('(uu)', [id, reason]));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _emitActionInvoked: function(id, action) {
 | 
			
		||||
        DBus.session.emit_signal('/org/freedesktop/Notifications',
 | 
			
		||||
                                 'org.freedesktop.Notifications',
 | 
			
		||||
                                 'ActionInvoked', 'us',
 | 
			
		||||
                                 [id, action]);
 | 
			
		||||
        this._dbusImpl.emit_signal('ActionInvoked',
 | 
			
		||||
                                   GLib.Variant.new('(us)', [id, action]));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onTrayIconAdded: function(o, icon) {
 | 
			
		||||
        let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null, null);
 | 
			
		||||
        source.setTrayIcon(icon);
 | 
			
		||||
        let wmClass = icon.wm_class.toLowerCase();
 | 
			
		||||
        if (STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass] !== undefined)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let source = this._getSource(icon.title || icon.wm_class || C_("program", "Unknown"), icon.pid, null, null, icon);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onTrayIconRemoved: function(o, icon) {
 | 
			
		||||
        let source = this._sources[icon.pid];
 | 
			
		||||
        let source = this._lookupSource(null, icon.pid, true);
 | 
			
		||||
        if (source)
 | 
			
		||||
            source.destroy();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
DBus.conformExport(NotificationDaemon.prototype, NotificationDaemonIface);
 | 
			
		||||
const Source = new Lang.Class({
 | 
			
		||||
    Name: 'NotificationDaemonSource',
 | 
			
		||||
    Extends: MessageTray.Source,
 | 
			
		||||
 | 
			
		||||
function Source(title, pid, sender) {
 | 
			
		||||
    this._init(title, pid, sender);
 | 
			
		||||
}
 | 
			
		||||
    _init: function(title, pid, sender, trayIcon) {
 | 
			
		||||
        this.parent(title);
 | 
			
		||||
 | 
			
		||||
Source.prototype = {
 | 
			
		||||
    __proto__:  MessageTray.Source.prototype,
 | 
			
		||||
        this.initialTitle = title;
 | 
			
		||||
 | 
			
		||||
    _init: function(title, pid, sender) {
 | 
			
		||||
        MessageTray.Source.prototype._init.call(this, title);
 | 
			
		||||
 | 
			
		||||
        this._pid = pid;
 | 
			
		||||
        this.pid = pid;
 | 
			
		||||
        if (sender)
 | 
			
		||||
            // TODO: dbus-glib implementation of watch_name() doesn’t return an id to be used for
 | 
			
		||||
            // unwatch_name() or implement unwatch_name(), however when we move to using GDBus implementation,
 | 
			
		||||
            // we should save the id here and call unwatch_name() with it in destroy().
 | 
			
		||||
            // Moving to GDBus is the work in progress: https://bugzilla.gnome.org/show_bug.cgi?id=648651
 | 
			
		||||
            // and https://bugzilla.gnome.org/show_bug.cgi?id=622921 .
 | 
			
		||||
            DBus.session.watch_name(sender,
 | 
			
		||||
                                    false,
 | 
			
		||||
                                    null,
 | 
			
		||||
                                    Lang.bind(this, this._onNameVanished));
 | 
			
		||||
            this._nameWatcherId = Gio.DBus.session.watch_name(sender,
 | 
			
		||||
                                                              Gio.BusNameWatcherFlags.NONE,
 | 
			
		||||
                                                              null,
 | 
			
		||||
                                                              Lang.bind(this, this._onNameVanished));
 | 
			
		||||
        else
 | 
			
		||||
            this._nameWatcherId = 0;
 | 
			
		||||
 | 
			
		||||
        this._setApp();
 | 
			
		||||
        if (this.app)
 | 
			
		||||
            this.title = this.app.get_name();
 | 
			
		||||
        else
 | 
			
		||||
            this.useNotificationIcon = true;
 | 
			
		||||
        this._trayIcon = null;
 | 
			
		||||
 | 
			
		||||
        this.trayIcon = trayIcon;
 | 
			
		||||
        if (this.trayIcon) {
 | 
			
		||||
           this._setSummaryIcon(this.trayIcon);
 | 
			
		||||
           this.useNotificationIcon = false;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onNameVanished: function() {
 | 
			
		||||
@@ -494,11 +554,11 @@ Source.prototype = {
 | 
			
		||||
            this.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    processNotification: function(notification, icon) {
 | 
			
		||||
        if (!this.app)
 | 
			
		||||
            this._setApp();
 | 
			
		||||
        if (!this.app && icon)
 | 
			
		||||
            this._setSummaryIcon(icon);
 | 
			
		||||
    processNotification: function(notification, gicon) {
 | 
			
		||||
        if (gicon)
 | 
			
		||||
            this._gicon = gicon;
 | 
			
		||||
        if (!this.trayIcon)
 | 
			
		||||
            this.iconUpdated();
 | 
			
		||||
 | 
			
		||||
        let tracker = Shell.WindowTracker.get_default();
 | 
			
		||||
        if (notification.resident && this.app && tracker.focus_app == this.app)
 | 
			
		||||
@@ -508,7 +568,7 @@ Source.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handleSummaryClick: function() {
 | 
			
		||||
        if (!this._trayIcon)
 | 
			
		||||
        if (!this.trayIcon)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        let event = Clutter.get_current_event();
 | 
			
		||||
@@ -529,44 +589,54 @@ Source.prototype = {
 | 
			
		||||
            let id = global.connect('notify::stage-input-mode', Lang.bind(this,
 | 
			
		||||
                function () {
 | 
			
		||||
                    global.disconnect(id);
 | 
			
		||||
                    this._trayIcon.click(event);
 | 
			
		||||
                    this.trayIcon.click(event);
 | 
			
		||||
                }));
 | 
			
		||||
            Main.overview.hide();
 | 
			
		||||
        } else {
 | 
			
		||||
            this._trayIcon.click(event);
 | 
			
		||||
            this.trayIcon.click(event);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getApp: function() {
 | 
			
		||||
        let app;
 | 
			
		||||
 | 
			
		||||
        app = Shell.WindowTracker.get_default().get_app_from_pid(this.pid);
 | 
			
		||||
        if (app != null)
 | 
			
		||||
            return app;
 | 
			
		||||
 | 
			
		||||
        if (this.trayIcon) {
 | 
			
		||||
            app = Shell.AppSystem.get_default().lookup_wmclass(this.trayIcon.wmclass);
 | 
			
		||||
            if (app != null)
 | 
			
		||||
                return app;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setApp: function() {
 | 
			
		||||
        if (this.app)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.app = Shell.WindowTracker.get_default().get_app_from_pid(this._pid);
 | 
			
		||||
        this.app = this._getApp();
 | 
			
		||||
        if (!this.app)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // Only override the icon if we were previously using
 | 
			
		||||
        // notification-based icons (ie, not a trayicon) or if it was unset before
 | 
			
		||||
        if (!this._trayIcon) {
 | 
			
		||||
        if (!this.trayIcon) {
 | 
			
		||||
            this.useNotificationIcon = false;
 | 
			
		||||
            this._setSummaryIcon(this.app.create_icon_texture (this.ICON_SIZE));
 | 
			
		||||
            this.iconUpdated();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setTrayIcon: function(icon) {
 | 
			
		||||
        this._setSummaryIcon(icon);
 | 
			
		||||
        this.useNotificationIcon = false;
 | 
			
		||||
        this._trayIcon = icon;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    open: function(notification) {
 | 
			
		||||
        this.destroyNonResidentNotifications();
 | 
			
		||||
        this.openApp();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _lastNotificationRemoved: function() {
 | 
			
		||||
        if (!this._trayIcon)
 | 
			
		||||
        if (!this.trayIcon)
 | 
			
		||||
            this.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -582,6 +652,26 @@ Source.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
        MessageTray.Source.prototype.destroy.call(this);
 | 
			
		||||
        if (this._nameWatcherId) {
 | 
			
		||||
            Gio.DBus.session.unwatch_name(this._nameWatcherId);
 | 
			
		||||
            this._nameWatcherId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.parent();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createIcon: function(size) {
 | 
			
		||||
        if (this.trayIcon) {
 | 
			
		||||
            return new Clutter.Clone({ width: size,
 | 
			
		||||
                                       height: size,
 | 
			
		||||
                                       source: this.trayIcon });
 | 
			
		||||
        } else if (this.app) {
 | 
			
		||||
            return this.app.create_icon_texture(size);
 | 
			
		||||
        } else if (this._gicon) {
 | 
			
		||||
            return new St.Icon({ gicon: this._gicon,
 | 
			
		||||
                                 icon_size: size });
 | 
			
		||||
        } else {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
@@ -11,18 +11,17 @@ const Shell = imports.gi.Shell;
 | 
			
		||||
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;
 | 
			
		||||
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 RemoteSearch = imports.ui.remoteSearch;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const ViewSelector = imports.ui.viewSelector;
 | 
			
		||||
const Wanda = imports.ui.wanda;
 | 
			
		||||
const WorkspacesView = imports.ui.workspacesView;
 | 
			
		||||
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
 | 
			
		||||
 | 
			
		||||
@@ -46,11 +45,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;
 | 
			
		||||
@@ -78,6 +75,7 @@ ShellInfo.prototype = {
 | 
			
		||||
        let notification = null;
 | 
			
		||||
        if (this._source.notifications.length == 0) {
 | 
			
		||||
            notification = new MessageTray.Notification(this._source, text, null);
 | 
			
		||||
            notification.setShowWhenLocked(true);
 | 
			
		||||
        } else {
 | 
			
		||||
            notification = this._source.notifications[0];
 | 
			
		||||
            notification.update(text, null, { clear: true });
 | 
			
		||||
@@ -95,24 +93,19 @@ ShellInfo.prototype = {
 | 
			
		||||
 | 
			
		||||
        this._source.notify(notification);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function Overview() {
 | 
			
		||||
    this._init.apply(this, arguments);
 | 
			
		||||
}
 | 
			
		||||
const Overview = new Lang.Class({
 | 
			
		||||
    Name: 'Overview',
 | 
			
		||||
 | 
			
		||||
Overview.prototype = {
 | 
			
		||||
    _init : function(params) {
 | 
			
		||||
        params = Params.parse(params, { isDummy: false });
 | 
			
		||||
 | 
			
		||||
        this.isDummy = params.isDummy;
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        this.isDummy = !Main.sessionMode.hasOverview;
 | 
			
		||||
 | 
			
		||||
        // 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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -130,8 +123,11 @@ Overview.prototype = {
 | 
			
		||||
 | 
			
		||||
        this._spacing = 0;
 | 
			
		||||
 | 
			
		||||
        this._group = new St.Group({ name: 'overview',
 | 
			
		||||
                                     reactive: true });
 | 
			
		||||
        /* Translators: This is the main view to select
 | 
			
		||||
           activities. See also note for "Activities" string. */
 | 
			
		||||
        this._group = new St.Widget({ name: 'overview',
 | 
			
		||||
                                      accessible_name: _("Overview"),
 | 
			
		||||
                                      reactive: true });
 | 
			
		||||
        this._group._delegate = this;
 | 
			
		||||
        this._group.connect('style-changed',
 | 
			
		||||
            Lang.bind(this, function() {
 | 
			
		||||
@@ -184,8 +180,6 @@ Overview.prototype = {
 | 
			
		||||
        this._lastActiveWorkspaceIndex = -1;
 | 
			
		||||
        this._lastHoveredWindow = null;
 | 
			
		||||
        this._needsFakePointerEvent = false;
 | 
			
		||||
 | 
			
		||||
        this.workspaces = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // The members we construct that are implemented in JS might
 | 
			
		||||
@@ -208,11 +202,14 @@ Overview.prototype = {
 | 
			
		||||
        this._viewSelector.addViewTab('applications', _("Applications"), appView.actor, 'system-run');
 | 
			
		||||
 | 
			
		||||
        // Default search providers
 | 
			
		||||
        this._viewSelector.addSearchProvider(new AppDisplay.AppSearchProvider());
 | 
			
		||||
        this._viewSelector.addSearchProvider(new AppDisplay.SettingsSearchProvider());
 | 
			
		||||
        this._viewSelector.addSearchProvider(new PlaceDisplay.PlaceSearchProvider());
 | 
			
		||||
        this._viewSelector.addSearchProvider(new DocDisplay.DocSearchProvider());
 | 
			
		||||
        this._viewSelector.addSearchProvider(new ContactDisplay.ContactSearchProvider());
 | 
			
		||||
        // Wanda comes obviously first
 | 
			
		||||
        this.addSearchProvider(new Wanda.WandaSearchProvider());
 | 
			
		||||
        this.addSearchProvider(new AppDisplay.AppSearchProvider());
 | 
			
		||||
        this.addSearchProvider(new AppDisplay.SettingsSearchProvider());
 | 
			
		||||
        this.addSearchProvider(new PlaceDisplay.PlaceSearchProvider());
 | 
			
		||||
 | 
			
		||||
        // Load remote search providers provided by applications
 | 
			
		||||
        RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
 | 
			
		||||
 | 
			
		||||
        // TODO - recalculate everything when desktop size changes
 | 
			
		||||
        this._dash = new Dash.Dash();
 | 
			
		||||
@@ -233,6 +230,14 @@ Overview.prototype = {
 | 
			
		||||
        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;
 | 
			
		||||
@@ -351,7 +356,7 @@ Overview.prototype = {
 | 
			
		||||
                let direction;
 | 
			
		||||
                if (this._scrollDirection == SwipeScrollDirection.HORIZONTAL) {
 | 
			
		||||
                    direction = stageX > this._dragStartX ? -1 : 1;
 | 
			
		||||
                    if (St.Widget.get_default_direction() == St.TextDirection.RTL)
 | 
			
		||||
                    if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
 | 
			
		||||
                        direction *= -1;
 | 
			
		||||
                } else {
 | 
			
		||||
                    direction = stageY > this._dragStartY ? -1 : 1;
 | 
			
		||||
@@ -443,7 +448,7 @@ Overview.prototype = {
 | 
			
		||||
                    return true;
 | 
			
		||||
 | 
			
		||||
                if (this._scrollDirection == SwipeScrollDirection.HORIZONTAL) {
 | 
			
		||||
                    if (St.Widget.get_default_direction() == St.TextDirection.RTL)
 | 
			
		||||
                    if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
 | 
			
		||||
                        this._scrollAdjustment.value -= (dx / primary.width) * this._scrollAdjustment.page_size;
 | 
			
		||||
                    else
 | 
			
		||||
                        this._scrollAdjustment.value += (dx / primary.width) * this._scrollAdjustment.page_size;
 | 
			
		||||
@@ -484,7 +489,7 @@ Overview.prototype = {
 | 
			
		||||
        this.hide();
 | 
			
		||||
 | 
			
		||||
        let primary = Main.layoutManager.primaryMonitor;
 | 
			
		||||
        let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
 | 
			
		||||
        let rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL);
 | 
			
		||||
 | 
			
		||||
        let contentY = Main.panel.actor.height;
 | 
			
		||||
        let contentHeight = primary.height - contentY - Main.messageTray.actor.height;
 | 
			
		||||
@@ -583,13 +588,10 @@ Overview.prototype = {
 | 
			
		||||
 | 
			
		||||
        this._workspacesDisplay.show();
 | 
			
		||||
 | 
			
		||||
        this.workspaces = this._workspacesDisplay.workspacesView;
 | 
			
		||||
        global.overlay_group.add_actor(this.workspaces.actor);
 | 
			
		||||
 | 
			
		||||
        if (!this._desktopFade.child)
 | 
			
		||||
            this._desktopFade.child = this._getDesktopClone();
 | 
			
		||||
 | 
			
		||||
        if (!this.workspaces.getActiveWorkspace().hasMaximizedWindows()) {
 | 
			
		||||
        if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows()) {
 | 
			
		||||
            this._desktopFade.opacity = 255;
 | 
			
		||||
            this._desktopFade.show();
 | 
			
		||||
            Tweener.addTween(this._desktopFade,
 | 
			
		||||
@@ -724,7 +726,7 @@ Overview.prototype = {
 | 
			
		||||
        this.animationInProgress = true;
 | 
			
		||||
        this._hideInProgress = true;
 | 
			
		||||
 | 
			
		||||
        if (!this.workspaces.getActiveWorkspace().hasMaximizedWindows()) {
 | 
			
		||||
        if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows()) {
 | 
			
		||||
            this._desktopFade.opacity = 0;
 | 
			
		||||
            this._desktopFade.show();
 | 
			
		||||
            Tweener.addTween(this._desktopFade,
 | 
			
		||||
@@ -733,7 +735,7 @@ Overview.prototype = {
 | 
			
		||||
                               transition: 'easeOutQuad' });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.workspaces.hide();
 | 
			
		||||
        this._workspacesDisplay.zoomFromOverview();
 | 
			
		||||
 | 
			
		||||
        // Make other elements fade out.
 | 
			
		||||
        Tweener.addTween(this._group,
 | 
			
		||||
@@ -775,9 +777,6 @@ Overview.prototype = {
 | 
			
		||||
 | 
			
		||||
        global.window_group.show();
 | 
			
		||||
 | 
			
		||||
        this.workspaces.destroy();
 | 
			
		||||
        this.workspaces = null;
 | 
			
		||||
 | 
			
		||||
        this._workspacesDisplay.hide();
 | 
			
		||||
 | 
			
		||||
        this._desktopFade.hide();
 | 
			
		||||
@@ -803,5 +802,5 @@ Overview.prototype = {
 | 
			
		||||
            this._needsFakePointerEvent = false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(Overview.prototype);
 | 
			
		||||
 
 | 
			
		||||