Compare commits
	
		
			350 Commits
		
	
	
		
			wip/smcv/i
			...
			wip/ewlsh/
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					170fe945a9 | ||
| 
						 | 
					08a5f41505 | ||
| 
						 | 
					ec36762309 | ||
| 
						 | 
					aa70020bc8 | ||
| 
						 | 
					1e77e6fc79 | ||
| 
						 | 
					68203e7091 | ||
| 
						 | 
					cff0752bcc | ||
| 
						 | 
					45d8e11123 | ||
| 
						 | 
					5aee714b70 | ||
| 
						 | 
					3c3c3b7c69 | ||
| 
						 | 
					6ba2913075 | ||
| 
						 | 
					75c4e1cd63 | ||
| 
						 | 
					fb4a4ca4a2 | ||
| 
						 | 
					4c2c1297be | ||
| 
						 | 
					c5dbdad5fc | ||
| 
						 | 
					4e05bcd3b6 | ||
| 
						 | 
					3555550d5e | ||
| 
						 | 
					8e05fa2728 | ||
| 
						 | 
					d7c3050e2d | ||
| 
						 | 
					89ba8562c3 | ||
| 
						 | 
					82da73baff | ||
| 
						 | 
					b2eeda9b46 | ||
| 
						 | 
					0db41a3773 | ||
| 
						 | 
					8d7f7e61dd | ||
| 
						 | 
					3f4b253dac | ||
| 
						 | 
					e4cbe5126a | ||
| 
						 | 
					8357739ef8 | ||
| 
						 | 
					6bef9334b7 | ||
| 
						 | 
					8c49f45ac8 | ||
| 
						 | 
					46600740fe | ||
| 
						 | 
					c281e868a0 | ||
| 
						 | 
					039431a73f | ||
| 
						 | 
					d4f8ea1c53 | ||
| 
						 | 
					96f5e2b33e | ||
| 
						 | 
					93a542d52c | ||
| 
						 | 
					f4fcba74ff | ||
| 
						 | 
					cadbf7cd8b | ||
| 
						 | 
					dd8e1aef51 | ||
| 
						 | 
					15dc37a139 | ||
| 
						 | 
					c23ad83c59 | ||
| 
						 | 
					4a6f550acb | ||
| 
						 | 
					8078d78c30 | ||
| 
						 | 
					d7185d71c6 | ||
| 
						 | 
					522ecba180 | ||
| 
						 | 
					9b22f6183f | ||
| 
						 | 
					b2c35e4fb0 | ||
| 
						 | 
					af543daf1c | ||
| 
						 | 
					baeb4079ee | ||
| 
						 | 
					f91f9801b4 | ||
| 
						 | 
					c5634335b0 | ||
| 
						 | 
					2b4317349f | ||
| 
						 | 
					96bfd1f8be | ||
| 
						 | 
					33ab53068e | ||
| 
						 | 
					40123ae6da | ||
| 
						 | 
					df149524d4 | ||
| 
						 | 
					f0ee9cdcf8 | ||
| 
						 | 
					a3257e8df5 | ||
| 
						 | 
					d2cf13eff4 | ||
| 
						 | 
					8cd352b72b | ||
| 
						 | 
					c210052dc6 | ||
| 
						 | 
					0561af66e7 | ||
| 
						 | 
					1e9b170d87 | ||
| 
						 | 
					be02f76aa7 | ||
| 
						 | 
					687928e7b7 | ||
| 
						 | 
					ffdf3feb04 | ||
| 
						 | 
					a60b8b3b50 | ||
| 
						 | 
					3d6add68c7 | ||
| 
						 | 
					85e055ffe3 | ||
| 
						 | 
					1691e422e7 | ||
| 
						 | 
					f442c9510e | ||
| 
						 | 
					0de98eb772 | ||
| 
						 | 
					30172b5625 | ||
| 
						 | 
					8ae99a6898 | ||
| 
						 | 
					5cfe5bf8c8 | ||
| 
						 | 
					c790c01a3b | ||
| 
						 | 
					d4a947b475 | ||
| 
						 | 
					60d7999b6a | ||
| 
						 | 
					c040d08b97 | ||
| 
						 | 
					3a53b25873 | ||
| 
						 | 
					d8e6f654a3 | ||
| 
						 | 
					fdfcacf1db | ||
| 
						 | 
					d3efbcce9b | ||
| 
						 | 
					ac34dbe353 | ||
| 
						 | 
					e0f3e13456 | ||
| 
						 | 
					fdd9def922 | ||
| 
						 | 
					771050f4d7 | ||
| 
						 | 
					8451df977c | ||
| 
						 | 
					ff55cf017e | ||
| 
						 | 
					d36a180852 | ||
| 
						 | 
					12c7f693d0 | ||
| 
						 | 
					e0a8cb565e | ||
| 
						 | 
					46547ae027 | ||
| 
						 | 
					68745328df | ||
| 
						 | 
					4582d7a183 | ||
| 
						 | 
					cc5ed2fbf5 | ||
| 
						 | 
					a2545d186a | ||
| 
						 | 
					1ea22a5281 | ||
| 
						 | 
					090057d2df | ||
| 
						 | 
					b3aab7f401 | ||
| 
						 | 
					8154728d09 | ||
| 
						 | 
					5569090d1c | ||
| 
						 | 
					fc3bc7678d | ||
| 
						 | 
					8914a46669 | ||
| 
						 | 
					e7ec373aee | ||
| 
						 | 
					fe131f926d | ||
| 
						 | 
					35d21c0bca | ||
| 
						 | 
					b487846c0a | ||
| 
						 | 
					7bbce1d5ad | ||
| 
						 | 
					bf40d96a83 | ||
| 
						 | 
					2d650e51a5 | ||
| 
						 | 
					85d2837466 | ||
| 
						 | 
					25985868e8 | ||
| 
						 | 
					393c6c6805 | ||
| 
						 | 
					775d6ec431 | ||
| 
						 | 
					988f996407 | ||
| 
						 | 
					315c8820ca | ||
| 
						 | 
					8a89de04a2 | ||
| 
						 | 
					63abfc163d | ||
| 
						 | 
					f58cb34065 | ||
| 
						 | 
					ece1329145 | ||
| 
						 | 
					989118981b | ||
| 
						 | 
					c511c469fe | ||
| 
						 | 
					dac05c7e53 | ||
| 
						 | 
					c90e7ce258 | ||
| 
						 | 
					963f96292d | ||
| 
						 | 
					989ee6593b | ||
| 
						 | 
					2a8eea1ff5 | ||
| 
						 | 
					55c287280b | ||
| 
						 | 
					1fdd4ff313 | ||
| 
						 | 
					3522338b3d | ||
| 
						 | 
					61e3349dc7 | ||
| 
						 | 
					dc27db0897 | ||
| 
						 | 
					f09fbb19cf | ||
| 
						 | 
					846fa77b37 | ||
| 
						 | 
					b57bcf823f | ||
| 
						 | 
					548e19a7cd | ||
| 
						 | 
					4ae04d5aa8 | ||
| 
						 | 
					5d5ca80d17 | ||
| 
						 | 
					d81237b9d6 | ||
| 
						 | 
					71b3b03b2f | ||
| 
						 | 
					8c909e37e9 | ||
| 
						 | 
					6508fa4349 | ||
| 
						 | 
					ce8fb83c36 | ||
| 
						 | 
					58ec607818 | ||
| 
						 | 
					f06223df48 | ||
| 
						 | 
					9a8ced9f5b | ||
| 
						 | 
					67c45e5648 | ||
| 
						 | 
					b88ed3f251 | ||
| 
						 | 
					669b0f193a | ||
| 
						 | 
					9cad7ae975 | ||
| 
						 | 
					48e6a58250 | ||
| 
						 | 
					d2583aa47b | ||
| 
						 | 
					0ab34fe21f | ||
| 
						 | 
					0f947d4ff9 | ||
| 
						 | 
					9dc421875b | ||
| 
						 | 
					9c3c9a155e | ||
| 
						 | 
					faaed642a7 | ||
| 
						 | 
					9b99b67fea | ||
| 
						 | 
					693dd79d28 | ||
| 
						 | 
					400d045a6a | ||
| 
						 | 
					e20cf1ac78 | ||
| 
						 | 
					8d4e650a95 | ||
| 
						 | 
					82fd68b985 | ||
| 
						 | 
					6ddd43f361 | ||
| 
						 | 
					4e2ae30a47 | ||
| 
						 | 
					32bc064d10 | ||
| 
						 | 
					87606c6a6b | ||
| 
						 | 
					955afb8711 | ||
| 
						 | 
					3309031fd1 | ||
| 
						 | 
					a2235c269a | ||
| 
						 | 
					1cf2c9edd0 | ||
| 
						 | 
					64a3ecf9b1 | ||
| 
						 | 
					f144ed6e87 | ||
| 
						 | 
					a47e0f9845 | ||
| 
						 | 
					0737c8f416 | ||
| 
						 | 
					fba350eaad | ||
| 
						 | 
					6d5e93b00b | ||
| 
						 | 
					f526e592fe | ||
| 
						 | 
					751a94ab5d | ||
| 
						 | 
					e0e128e207 | ||
| 
						 | 
					137e6c8493 | ||
| 
						 | 
					72751c2d92 | ||
| 
						 | 
					b84fa852f6 | ||
| 
						 | 
					d20961f323 | ||
| 
						 | 
					5a01395a2b | ||
| 
						 | 
					e59ca7053b | ||
| 
						 | 
					6895592a7b | ||
| 
						 | 
					eed27a2a4c | ||
| 
						 | 
					43c6afa80f | ||
| 
						 | 
					7d60f418e7 | ||
| 
						 | 
					94dca1606f | ||
| 
						 | 
					27774582b6 | ||
| 
						 | 
					7dc08b06b1 | ||
| 
						 | 
					a9d73b1017 | ||
| 
						 | 
					25e4d0ba8b | ||
| 
						 | 
					2d56395921 | ||
| 
						 | 
					0ecddafc20 | ||
| 
						 | 
					af34c8d2f4 | ||
| 
						 | 
					5223599145 | ||
| 
						 | 
					c96af776d6 | ||
| 
						 | 
					34da48453e | ||
| 
						 | 
					13dcd78be1 | ||
| 
						 | 
					3bfa9916da | ||
| 
						 | 
					b17017679b | ||
| 
						 | 
					9d7832ea44 | ||
| 
						 | 
					49605c7b00 | ||
| 
						 | 
					bf8b9cecf5 | ||
| 
						 | 
					c291291304 | ||
| 
						 | 
					e08a4acd06 | ||
| 
						 | 
					0397a104ba | ||
| 
						 | 
					a41c1d4fda | ||
| 
						 | 
					8ae3ed907a | ||
| 
						 | 
					31cd8f738c | ||
| 
						 | 
					a4cd9e0038 | ||
| 
						 | 
					e06109c23c | ||
| 
						 | 
					05485fe04c | ||
| 
						 | 
					13062af7ef | ||
| 
						 | 
					5e254666b0 | ||
| 
						 | 
					d29eb8646a | ||
| 
						 | 
					f1af37f220 | ||
| 
						 | 
					d3880c0bff | ||
| 
						 | 
					4dfa39457e | ||
| 
						 | 
					325ff73c5b | ||
| 
						 | 
					1fa4e3b1b2 | ||
| 
						 | 
					f89091d0f0 | ||
| 
						 | 
					859927df39 | ||
| 
						 | 
					e7512fcd79 | ||
| 
						 | 
					2b70151794 | ||
| 
						 | 
					153b7d525d | ||
| 
						 | 
					2e80995f19 | ||
| 
						 | 
					9232cbf8a7 | ||
| 
						 | 
					55f74bb863 | ||
| 
						 | 
					b02e3719b3 | ||
| 
						 | 
					3ba4304da9 | ||
| 
						 | 
					49d6db34b7 | ||
| 
						 | 
					63a0e521fd | ||
| 
						 | 
					c00d79bae2 | ||
| 
						 | 
					30d902f898 | ||
| 
						 | 
					8f9da6f801 | ||
| 
						 | 
					20648e9207 | ||
| 
						 | 
					614fe202e0 | ||
| 
						 | 
					c3646a7642 | ||
| 
						 | 
					772df91762 | ||
| 
						 | 
					c90910731f | ||
| 
						 | 
					ba69cd99d1 | ||
| 
						 | 
					fb6e341efd | ||
| 
						 | 
					3dc4f01113 | ||
| 
						 | 
					d94d0f60c8 | ||
| 
						 | 
					8d79f6f4c8 | ||
| 
						 | 
					c5e5bb0be1 | ||
| 
						 | 
					8d139bbd95 | ||
| 
						 | 
					fb1bb291eb | ||
| 
						 | 
					3199620a83 | ||
| 
						 | 
					c88bb66369 | ||
| 
						 | 
					a60d57ea1f | ||
| 
						 | 
					527ce66cd4 | ||
| 
						 | 
					40415a6849 | ||
| 
						 | 
					1ff638a51f | ||
| 
						 | 
					2a9ccf2e2c | ||
| 
						 | 
					2909d91c13 | ||
| 
						 | 
					0dba12193d | ||
| 
						 | 
					02f40b3b63 | ||
| 
						 | 
					1fd51efc7f | ||
| 
						 | 
					6f881f232e | ||
| 
						 | 
					be12c71534 | ||
| 
						 | 
					6aa1b817c9 | ||
| 
						 | 
					300961e19e | ||
| 
						 | 
					b191e9ef91 | ||
| 
						 | 
					5ec5978d4a | ||
| 
						 | 
					f4d90bc127 | ||
| 
						 | 
					bfa34914db | ||
| 
						 | 
					8d1e4659d1 | ||
| 
						 | 
					b3b91f1699 | ||
| 
						 | 
					ff4c5270d3 | ||
| 
						 | 
					e240f7ea59 | ||
| 
						 | 
					9f1ad5d86d | ||
| 
						 | 
					a1ab32af0f | ||
| 
						 | 
					3fac0632a8 | ||
| 
						 | 
					c2b518929d | ||
| 
						 | 
					c422d82752 | ||
| 
						 | 
					da0c7fc2b6 | ||
| 
						 | 
					167bc080d9 | ||
| 
						 | 
					7d7a15f978 | ||
| 
						 | 
					1b5cf0b8a8 | ||
| 
						 | 
					306b005943 | ||
| 
						 | 
					d229abf07d | ||
| 
						 | 
					6f6251c0bc | ||
| 
						 | 
					fd034e3551 | ||
| 
						 | 
					f9bee05d49 | ||
| 
						 | 
					37c6fbc6b2 | ||
| 
						 | 
					9719604b79 | ||
| 
						 | 
					b6262f0666 | ||
| 
						 | 
					6c0bd207e9 | ||
| 
						 | 
					91b13effc8 | ||
| 
						 | 
					143ab6ac7f | ||
| 
						 | 
					3e5b90dbba | ||
| 
						 | 
					b82039e324 | ||
| 
						 | 
					83862d04a0 | ||
| 
						 | 
					52d07f6d9b | ||
| 
						 | 
					21de88c3ba | ||
| 
						 | 
					456ca3d3e0 | ||
| 
						 | 
					f4ba3e4ab8 | ||
| 
						 | 
					d4db5a59c1 | ||
| 
						 | 
					4aee87a31b | ||
| 
						 | 
					e8f5a842b1 | ||
| 
						 | 
					5c681a76b6 | ||
| 
						 | 
					53a24e6ddd | ||
| 
						 | 
					b27c89f836 | ||
| 
						 | 
					9f870aa1c7 | ||
| 
						 | 
					c9cfeb8318 | ||
| 
						 | 
					497e66ce6a | ||
| 
						 | 
					bc973b80d7 | ||
| 
						 | 
					85846d88f0 | ||
| 
						 | 
					6b7c85b079 | ||
| 
						 | 
					d80ef67d1d | ||
| 
						 | 
					62f3457a95 | ||
| 
						 | 
					636ab4b0e9 | ||
| 
						 | 
					23e382dd33 | ||
| 
						 | 
					f5a170ce46 | ||
| 
						 | 
					fbd6beea2c | ||
| 
						 | 
					360f5b1642 | ||
| 
						 | 
					f0a785df9d | ||
| 
						 | 
					e2c1bfbedd | ||
| 
						 | 
					7e5a1cfd90 | ||
| 
						 | 
					07deda593a | ||
| 
						 | 
					1ca39e8586 | ||
| 
						 | 
					402fd8ec29 | ||
| 
						 | 
					fbe2e30f38 | ||
| 
						 | 
					fb6ead2881 | ||
| 
						 | 
					7ff7fb5d3b | ||
| 
						 | 
					8030d9ad32 | ||
| 
						 | 
					45bc850715 | ||
| 
						 | 
					51a913730e | ||
| 
						 | 
					0a4974ac8c | ||
| 
						 | 
					1666fa195d | ||
| 
						 | 
					a9df4e7516 | ||
| 
						 | 
					343b3351f1 | ||
| 
						 | 
					407b12c3cb | ||
| 
						 | 
					455a8f3076 | ||
| 
						 | 
					5067bda61a | ||
| 
						 | 
					e138b6e3af | ||
| 
						 | 
					9bc9d5165f | ||
| 
						 | 
					26c2cb9f65 | ||
| 
						 | 
					da44649e6f | ||
| 
						 | 
					a0def23940 | ||
| 
						 | 
					f49b58cf97 | ||
| 
						 | 
					cadd9a99c0 | ||
| 
						 | 
					7061889a29 | ||
| 
						 | 
					764527c8c9 | ||
| 
						 | 
					18742fcc32 | 
@@ -18,7 +18,7 @@ variables:
 | 
			
		||||
        - merge_requests
 | 
			
		||||
 | 
			
		||||
check_commit_log:
 | 
			
		||||
    image: registry.gitlab.gnome.org/gnome/mutter/master:v3
 | 
			
		||||
    image: registry.gitlab.gnome.org/gnome/mutter/master:v4
 | 
			
		||||
    stage: review
 | 
			
		||||
    variables:
 | 
			
		||||
        GIT_DEPTH: "100"
 | 
			
		||||
@@ -28,10 +28,10 @@ check_commit_log:
 | 
			
		||||
        - merge_requests
 | 
			
		||||
 | 
			
		||||
js_check:
 | 
			
		||||
    image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
 | 
			
		||||
    image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2
 | 
			
		||||
    stage: review
 | 
			
		||||
    script:
 | 
			
		||||
        - find js -name '*.js' -exec js60 -c -s '{}' ';' 2>&1 | tee $JS_LOG
 | 
			
		||||
        - find js -name '*.js' -exec js68 -c -s '{}' ';' 2>&1 | tee $JS_LOG
 | 
			
		||||
        - (! grep -q . $JS_LOG)
 | 
			
		||||
    <<: *only_default
 | 
			
		||||
    artifacts:
 | 
			
		||||
@@ -40,7 +40,7 @@ js_check:
 | 
			
		||||
        when: on_failure
 | 
			
		||||
 | 
			
		||||
eslint:
 | 
			
		||||
    image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
 | 
			
		||||
    image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2
 | 
			
		||||
    stage: review
 | 
			
		||||
    script:
 | 
			
		||||
        - ./.gitlab-ci/run-eslint.sh
 | 
			
		||||
@@ -51,21 +51,21 @@ eslint:
 | 
			
		||||
        when: always
 | 
			
		||||
 | 
			
		||||
potfile_check:
 | 
			
		||||
    image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
 | 
			
		||||
    image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2
 | 
			
		||||
    stage: review
 | 
			
		||||
    script:
 | 
			
		||||
        - ./.gitlab-ci/check-potfiles.sh
 | 
			
		||||
    <<: *only_default
 | 
			
		||||
 | 
			
		||||
no_template_check:
 | 
			
		||||
    image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
 | 
			
		||||
    image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2
 | 
			
		||||
    stage: review
 | 
			
		||||
    script:
 | 
			
		||||
        - ./.gitlab-ci/check-template-strings.sh
 | 
			
		||||
    <<: *only_default
 | 
			
		||||
 | 
			
		||||
build:
 | 
			
		||||
    image: registry.gitlab.gnome.org/gnome/mutter/master:v3
 | 
			
		||||
    image: registry.gitlab.gnome.org/gnome/mutter/master:v4
 | 
			
		||||
    stage: build
 | 
			
		||||
    before_script:
 | 
			
		||||
        - .gitlab-ci/checkout-mutter.sh
 | 
			
		||||
@@ -83,7 +83,7 @@ build:
 | 
			
		||||
            - build
 | 
			
		||||
 | 
			
		||||
test:
 | 
			
		||||
    image: registry.gitlab.gnome.org/gnome/mutter/master:v3
 | 
			
		||||
    image: registry.gitlab.gnome.org/gnome/mutter/master:v4
 | 
			
		||||
    stage: test
 | 
			
		||||
    variables:
 | 
			
		||||
        XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir"
 | 
			
		||||
@@ -100,7 +100,7 @@ test:
 | 
			
		||||
        when: on_failure
 | 
			
		||||
 | 
			
		||||
test-pot:
 | 
			
		||||
    image: registry.gitlab.gnome.org/gnome/mutter/master:v3
 | 
			
		||||
    image: registry.gitlab.gnome.org/gnome/mutter/master:v4
 | 
			
		||||
    stage: test
 | 
			
		||||
    before_script:
 | 
			
		||||
        - ninja -C mutter/build install
 | 
			
		||||
@@ -124,11 +124,7 @@ flatpak:
 | 
			
		||||
        RUNTIME_REPO: "https://nightly.gnome.org/gnome-nightly.flatpakrepo"
 | 
			
		||||
        FLATPAK_MODULE: "gnome-extensions-app"
 | 
			
		||||
        APP_ID: "org.gnome.Extensions"
 | 
			
		||||
        MESON_ARGS: "$SUBPROJECT"
 | 
			
		||||
    extends: .flatpak
 | 
			
		||||
    before_script:
 | 
			
		||||
        - flatpak run --command=$SUBPROJECT/generate-translations.sh
 | 
			
		||||
                      --filesystem=host org.gnome.Sdk//master
 | 
			
		||||
    <<: *only_default
 | 
			
		||||
 | 
			
		||||
nightly:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								.gitlab-ci/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								.gitlab-ci/Dockerfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
# Rebuild and push with
 | 
			
		||||
#
 | 
			
		||||
#     cd .gitlab-ci/
 | 
			
		||||
#     podman build --format docker --no-cache -t registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2 .
 | 
			
		||||
#     podman push registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
FROM registry.fedoraproject.org/fedora:32
 | 
			
		||||
 | 
			
		||||
RUN dnf -y update && dnf -y upgrade && \
 | 
			
		||||
    dnf install -y 'dnf-command(copr)' git && \
 | 
			
		||||
 | 
			
		||||
    # For syntax checks with `find . -name '*.js' -exec js68 -c -s '{}' ';'`
 | 
			
		||||
    dnf install -y findutils mozjs68-devel && \
 | 
			
		||||
 | 
			
		||||
    # For static analysis with eslint
 | 
			
		||||
    dnf install -y nodejs && \
 | 
			
		||||
    npm install -g eslint && \
 | 
			
		||||
 | 
			
		||||
    # Shameless plug for my own tooling; useful for generating zip
 | 
			
		||||
    dnf copr enable -y fmuellner/gnome-shell-ci && \
 | 
			
		||||
    dnf install -y gnome-extensions-tool meson && \
 | 
			
		||||
 | 
			
		||||
    dnf clean all
 | 
			
		||||
@@ -1,18 +0,0 @@
 | 
			
		||||
FROM registry.fedoraproject.org/fedora:latest
 | 
			
		||||
 | 
			
		||||
RUN dnf -y update && dnf -y upgrade && \
 | 
			
		||||
    dnf install -y 'dnf-command(copr)' git && \
 | 
			
		||||
 | 
			
		||||
    # For syntax checks with `find . -name '*.js' -exec js60 -c -s '{}' ';'`
 | 
			
		||||
    dnf install -y findutils mozjs60-devel && \
 | 
			
		||||
 | 
			
		||||
    # For static analysis with eslint
 | 
			
		||||
    dnf install -y nodejs && \
 | 
			
		||||
    npm install -g eslint && \
 | 
			
		||||
 | 
			
		||||
    # Shameless plug for my own tooling; useful for generating zip
 | 
			
		||||
    dnf copr enable -y fmuellner/gnome-shell-ci && \
 | 
			
		||||
    dnf install -y gnome-extensions-tool meson && \
 | 
			
		||||
 | 
			
		||||
    dnf clean all && \
 | 
			
		||||
    rm -rf /var/cache/dnf
 | 
			
		||||
@@ -6,6 +6,11 @@ globs=('*.js' '*.c')
 | 
			
		||||
# find source files that contain gettext keywords
 | 
			
		||||
files=$(grep -lR ${globs[@]/#/--include=} '\(gettext\|[^I_)]_\)(' $srcdirs)
 | 
			
		||||
 | 
			
		||||
# filter out excluded files
 | 
			
		||||
if [ -f po/POTFILES.skip ]; then
 | 
			
		||||
  files=$(for f in $files; do ! grep -q ^$f po/POTFILES.skip && echo $f; done)
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# find those that aren't listed in POTFILES.in
 | 
			
		||||
missing=$(for f in $files; do ! grep -q ^$f po/POTFILES.in && echo $f; done)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,12 +18,14 @@ run_eslint() {
 | 
			
		||||
  local extra_args=ARGS_$1
 | 
			
		||||
  local output_var=OUTPUT_$1
 | 
			
		||||
  local output=${!output_var}
 | 
			
		||||
  local cache=.eslintcache-${1,,}
 | 
			
		||||
 | 
			
		||||
  # ensure output exists even if eslint doesn't report any errors
 | 
			
		||||
  mkdir -p $(dirname $output)
 | 
			
		||||
  touch $output
 | 
			
		||||
 | 
			
		||||
  eslint -f unix ${!extra_args} -o $output js subprojects/extensions-app/js
 | 
			
		||||
  eslint -f unix --cache --cache-location $cache ${!extra_args} -o $output \
 | 
			
		||||
    js subprojects/extensions-app/js
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
list_commit_range_additions() {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										197
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										197
									
								
								NEWS
									
									
									
									
									
								
							@@ -1,168 +1,87 @@
 | 
			
		||||
3.36.5
 | 
			
		||||
3.37.2
 | 
			
		||||
======
 | 
			
		||||
* Fix extension updates when many extensions are installed [Jeremias; !1363]
 | 
			
		||||
* Fix missing icons in on-screen keyboard [Emre; #2631, #3007]
 | 
			
		||||
* Fix delay when showing calendar events [Sebastian; #2992]
 | 
			
		||||
* Fix app picker regressions on small displays [Sebastian; #2234, !1375, !1378]
 | 
			
		||||
* Fix top bar navigation when NumLock is active [Olivier; #550]
 | 
			
		||||
* Delay login animation until wallpaper has loaded [Michael; #734996]
 | 
			
		||||
* Revert changes that caused mispositioning in overview in multi-monitor setups
 | 
			
		||||
  [Robert; #2971]
 | 
			
		||||
* Reset auth prompt on login screen on VT switch before fade in [Ray; #2997]
 | 
			
		||||
* Fix stuck grab when destroying open popup menu [Florian; #3022]
 | 
			
		||||
* Misc. bug fixes and cleanups [Florian, Carlos, Andre, Jonas; !1357, !1371,
 | 
			
		||||
  !1381, #3037, #3005, !1386, !1390]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Michael Catanzaro, Jonas Dreßler, Olivier Fourdan, Carlos Garnacho,
 | 
			
		||||
  Sebastian Keller, Robert Mader, Andre Moreira Magalhaes, Florian Müllner,
 | 
			
		||||
  Jeremias Ortega, Ray Strode, Emre Uyguroglu
 | 
			
		||||
 | 
			
		||||
Translators:
 | 
			
		||||
  Boyuan Yang [zh_CN], Rafael Fontenelle [pt_BR]
 | 
			
		||||
 | 
			
		||||
3.36.4
 | 
			
		||||
======
 | 
			
		||||
* Hide switch-user button on lock screen if unsupported [Chingkai; #2687]
 | 
			
		||||
* Improve world clocks styling [PrOF-kk; #2825]
 | 
			
		||||
* Improve calendar-server performance [Florian, Milan; #1875]
 | 
			
		||||
* Fix regressions in redesigned modal dialogs [Florian, Jonas; #2491, !1336]
 | 
			
		||||
* Better support sandboxed apps with multiple .desktop files [Florian; #219]
 | 
			
		||||
* Fix on-screen keyboard size in portrait orientation [Florian; #2349]
 | 
			
		||||
* Support scrolling anywhere in slider menu items [Peter; #2795]
 | 
			
		||||
* Fixed crash [Marco; #2643]
 | 
			
		||||
* Plugged leaks [Sebastian, Florian; !1306, !1341]
 | 
			
		||||
* Misc. bug fixes and cleanups [Jonas, Daniel, Florian, Sebastian, MOZGIII,
 | 
			
		||||
  Koki; !1119, !1289, !1331, !1192, !1340, !1327, !1279]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Marco Trevisan (Treviño), Chingkai, Milan Crha, Jonas Dreßler, Koki Fukuda,
 | 
			
		||||
  Sebastian Keller, MOZGIII, Robert Mader, Florian Müllner, PrOF-kk,
 | 
			
		||||
  Peter Simonyi, Daniel van Vugt
 | 
			
		||||
 | 
			
		||||
Translators:
 | 
			
		||||
  Matej Urbančič [sl], sicklylife [ja], Fabio Tomat [fur],
 | 
			
		||||
  Baurzhan Muftakhidinov [kk], Daniel Șerbănescu [ro]
 | 
			
		||||
 | 
			
		||||
3.36.3
 | 
			
		||||
======
 | 
			
		||||
* Add gnome-shell-extension-prefs wrapper for compatibility [Florian; !1220]
 | 
			
		||||
* Fix distorted fallback icons in top bar [Florian; #2578]
 | 
			
		||||
* Lower timeout for scrolling in overview [Alexander; #2602]
 | 
			
		||||
* Add support for "PrefersNonDefaultGPU" desktop key [Bastien; !1226]
 | 
			
		||||
* Only start systemd units when running under systemd
 | 
			
		||||
  [Carlos, Florian; #2755, !1242, !1252]
 | 
			
		||||
* Fix "ghost" media controls  [Bryan; #2776]
 | 
			
		||||
* Fix "ghost" media controls [Bryan; #2776]
 | 
			
		||||
* Fix zombie sockets from extensions downloader [Michael; #2774]
 | 
			
		||||
* Update world clocks offsets when timezone changes [Bryan; #2209]
 | 
			
		||||
* Support scrolling anywhere in slider menu items [Peter; #2795]
 | 
			
		||||
* Fix "Do Not Disturb" setting getting reset on startup [Florian; #2804]
 | 
			
		||||
* Fix pad OSD glitches [Carlos; !1290]
 | 
			
		||||
* Fix matching notifications by PID [Florian; #2592]
 | 
			
		||||
* Only allow updates for extensions that aren't cached [Florian; !1248]
 | 
			
		||||
* Fixed crashes [Jonas, Florian; #2709, #2757]
 | 
			
		||||
* Misc. bug fixes and cleanups [Michael, Piotr, Philip, Florian, Amr,
 | 
			
		||||
  AsciiWolf; !1233, !1205, !1229, #2751, !1232, #2796, !1249, !1263,
 | 
			
		||||
  !1277, #2286, !1288, !1291]
 | 
			
		||||
* Fix matching notifications by PID [Florian; #2592]
 | 
			
		||||
* Indicate extension errors in Extensions app [Florian; #2337]
 | 
			
		||||
* Add clipboard API for querying supported mimetypes [Andy; #2819]
 | 
			
		||||
* Add preview to color picker [Florian; #451]
 | 
			
		||||
* Improve world clocks styling [PrOF-kk; #2825]
 | 
			
		||||
* Remove Frequent view from app picker [Georges; !880]
 | 
			
		||||
* Fix pad OSD glitches [Carlos; !1290]
 | 
			
		||||
* Expose actor tree in looking glass [Georges; !1292]
 | 
			
		||||
* Fixed crashes [Jonas D., Florian; #2709, #2757]
 | 
			
		||||
* Misc. bug fixes and cleanups [Florian, AsciiWolf, Michael, Piotr, Ting-Wei,
 | 
			
		||||
  Amr, Alexander, Bryan, Georges, Jonas D., Andy, Björn, Koki, Carlos; !1229,
 | 
			
		||||
  !1231, !1233, !1235, #2578, #2735, #2751, #2602, #2777, !1249, #2796, !1268,
 | 
			
		||||
  !1269, !1265, !1245, !1273, #2816, !1274, !1263, !1188, !1276, #2652, !1277,
 | 
			
		||||
  !1281, #2286, !1267, !1286, !1279, !1288, !1293, !1294, !1291]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  AsciiWolf, Michael Catanzaro, Philip Chimento, Jonas Dreßler, Bryan Dunsmore,
 | 
			
		||||
  Carlos Garnacho, Amr Ibrahim, Michael Lass, Alexander Mikhaylenko,
 | 
			
		||||
  Florian Müllner
 | 
			
		||||
  AsciiWolf, Michael Catanzaro, Björn Daase, Jonas Dreßler, Bryan Dunsmore,
 | 
			
		||||
  Koki Fukuda, Carlos Garnacho, Andy Holmes, Amr Ibrahim, Soslan Khubulov,
 | 
			
		||||
  Ting-Wei Lan, Michael Lass, Alexander Mikhaylenko, Florian Müllner,
 | 
			
		||||
  Georges Basile Stavracas Neto, Bastien Nocera, PrOF-kk, Peter Simonyi
 | 
			
		||||
 | 
			
		||||
Translators:
 | 
			
		||||
  Fabio Tomat [fur], Cheng-Chia Tseng [zh_TW], Dušan Kazik [sk],
 | 
			
		||||
  Piotr Drąg [pl], Daniel Mustieles [es], Nathan Follens [nl],
 | 
			
		||||
  Bruce Cowan [en_GB], Florentina Mușat [ro], Yuri Chornoivan [uk],
 | 
			
		||||
  Milo Casagrande [it], Anders Jonsson [sv], Charles Monzat [fr],
 | 
			
		||||
  Daniel Șerbănescu [ro], sicklylife [ja], Kukuh Syafaat [id],
 | 
			
		||||
  Emin Tufan Çetin [tr], Jiri Grönroos [fi], Марко Костић [sr],
 | 
			
		||||
  Christian Kirbach [de], Changwoo Ryu [ko], Aurimas Černius [lt],
 | 
			
		||||
  Matej Urbančič [sl]
 | 
			
		||||
  Fabio Tomat [fur], Cheng-Chia Tseng [zh_TW], Yuri Chornoivan [uk],
 | 
			
		||||
  Dušan Kazik [sk], Piotr Drąg [pl], Soslan Khubulov [os],
 | 
			
		||||
  Daniel Mustieles [es], Nathan Follens [nl], Bruce Cowan [en_GB],
 | 
			
		||||
  Florentina Mușat [ro], Milo Casagrande [it], Anders Jonsson [sv],
 | 
			
		||||
  Charles Monzat [fr], Danial Behzadi [fa], sicklylife [ja], Kukuh Syafaat [id],
 | 
			
		||||
  Jordi Mas [ca], Emin Tufan Çetin [tr], Jiri Grönroos [fi], Марко Костић [sr],
 | 
			
		||||
  Christian Kirbach [de], Changwoo Ryu [ko], Matej Urbančič [sl]
 | 
			
		||||
 | 
			
		||||
3.36.2
 | 
			
		||||
3.37.1
 | 
			
		||||
======
 | 
			
		||||
* Improve bluetooth submenu title [Mariana; #2340]
 | 
			
		||||
* Add openPrefs() convenience method for extensions [Florian; !1163]
 | 
			
		||||
* Bring back support for empty StIcons [Andre, Jonas D.; !1173, !1178]
 | 
			
		||||
* Wake up screen when unlocking programmatically [Florian; !1158]
 | 
			
		||||
* Improve extensions tool error reporting [Florian; #2391]
 | 
			
		||||
* Improve handling of scale-factor changes [Georges; !1176]
 | 
			
		||||
* Fix translations of folder names [Florian; #2623]
 | 
			
		||||
* Fix delay on lock screen after entering wrong password [Jonas D.; #2655]
 | 
			
		||||
* Match ASCII alternatives of system actions [Will; #2688]
 | 
			
		||||
* Tone down weekend days with events in calendar [Jakub; #2588]
 | 
			
		||||
* Fix area screenshots on multi-monitor systems [Jonas Å; !1224]
 | 
			
		||||
* Fix showing bluetooth submenu when devices were set up [Florian; !1174]
 | 
			
		||||
* Add support for parental controls filtering [Philip W.; !465]
 | 
			
		||||
* Provide alternative extension templates [Florian; !812]
 | 
			
		||||
* Improve weather section's empty state [Mariana; #2179]
 | 
			
		||||
* Fix translations of folder names [Florian; #2623]
 | 
			
		||||
* Drop Tweener [Jonas Å.; !1200]
 | 
			
		||||
* Match ASCII alternatives of system actions [Will; #2688]
 | 
			
		||||
* Fix delay on lock screen after entering wrong password [Jonas D.; #2655]
 | 
			
		||||
* Use globalThis instead of window [Andy; #2322]
 | 
			
		||||
* Inhibit remote access when disabled by session mode [Jonas Å.; !1210]
 | 
			
		||||
* Improve calendar-server performance [Milan; #1875]
 | 
			
		||||
* Add gnome-shell-extension-prefs wrapper for compatibility [Florian; !1220]
 | 
			
		||||
* Fix stuck lock screen after unlock [Jonas D., Florian; #2446]
 | 
			
		||||
* Fixed crashes [Jonas D., Florian, Carlos; #2584, #2625, !1223, !1218]
 | 
			
		||||
* Misc. bug fixes and cleanups [Jonas Å., Marco, Andre, Florian, Jonas D.;
 | 
			
		||||
  !1155, !1156, !1169, !1168, #2551, #2563, !1172, !1179, !1160, #2562, #2578,
 | 
			
		||||
  !1203, #2649, #2628, #2691, #1615, #2607, !1228]
 | 
			
		||||
* Misc. bug fixes and cleanups [Florian, Jonas Å., Marco, Andre, Georges,
 | 
			
		||||
  Jonas D., Jan, Philip Ch.,, Xiaoguang, Will, Jordan, Matthew, qarmin;
 | 
			
		||||
  !1126, !1155, !1156, !1165, !1168, !1169, #2551, #2563, !1172, !1175, !1179,
 | 
			
		||||
  !1160, #2562, #2578, !1184, #2559, !1186, #2607, !1191, !1194, !1199, !1203,
 | 
			
		||||
  #2649, #2628, !1205, !1206, !1208, !1207, !1211, !1214, !1213, !1192, !1217,
 | 
			
		||||
  !1219, #1615, #2691, !1094, !1177]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Marco Trevisan (Treviño), Jonas Dreßler, Carlos Garnacho,
 | 
			
		||||
  Andre Moreira Magalhaes, Florian Müllner, Georges Basile Stavracas Neto,
 | 
			
		||||
  Jakub Steiner, Will Thompson, Jonas Ådahl
 | 
			
		||||
  Marco Trevisan (Treviño), Philip Chimento, Milan Crha, Jonas Dreßler,
 | 
			
		||||
  Carlos Garnacho, Andy Holmes, Matthew Leeds, Andre Moreira Magalhaes,
 | 
			
		||||
  Florian Müllner, Georges Basile Stavracas Neto, Jordan Petridis,
 | 
			
		||||
  Mariana Picolo, Jakub Steiner, Will Thompson, Jan Tojnar, Xiaoguang Wang,
 | 
			
		||||
  Philip Withnall, qarmin, Jonas Ådahl
 | 
			
		||||
 | 
			
		||||
Translators:
 | 
			
		||||
  Fabio Tomat [fur], Cheng-Chia Tseng [zh_TW], Danial Behzadi [fa],
 | 
			
		||||
  Jiri Grönroos [fi], Ibai Oihanguren Sala [eu], Марко Костић [sr],
 | 
			
		||||
  Rūdolfs Mazurs [lv], Rafael Fontenelle [pt_BR], Petr Kovář [cs],
 | 
			
		||||
  Daniel Rusek [cs]
 | 
			
		||||
 | 
			
		||||
3.36.1
 | 
			
		||||
======
 | 
			
		||||
* Improve app folders [Jonas D.; !1011]
 | 
			
		||||
* Fix launching ibus daemon [Alynx; !1080]
 | 
			
		||||
* Do not shutdown ibus/xsettings on X11 compositor restart [Carlos; #2329]
 | 
			
		||||
* Hide hint text in entries when preedit is used [Carlos; !1084]
 | 
			
		||||
* Do not load app infos on main thread [Christian; #2282]
 | 
			
		||||
* Don't expose FDO Notifications interface on main bus name [Florian; !547]
 | 
			
		||||
* Fix icon of mobile broadband connections [Cosimo, Reik; !1097, !1105]
 | 
			
		||||
* Fix high-contrast/symbolic icon mix-up [Florian; #2414]
 | 
			
		||||
* Don't ellipsize times in world clock [Florian; !1090]
 | 
			
		||||
* Only check for extension updates if there are any extensions [Florian; !1100]
 | 
			
		||||
* Fix crash when trying to update removed extensions [Florian; #2343]
 | 
			
		||||
* Make Extensions app available as flatpak [Florian; !1081, !1106, !1087, !1133]
 | 
			
		||||
* Display fractional timezones as hours:minutes [Jonas D.; #2438]
 | 
			
		||||
* Fix assigning pad keybindings [Carlos; #2451]
 | 
			
		||||
* Handle embedded newlines in lock screen notifications [Florian; #2463]
 | 
			
		||||
* Fix OSK layout fallback for unsupported variants [Florian; #2471]
 | 
			
		||||
* Do not apply text color to color glyphs (emojis) [Carlos; #850]
 | 
			
		||||
* Check "Install pending software updates" by default [Michael; #2427]
 | 
			
		||||
* Do not warn about missing GDM on each login [Florian; #2432]
 | 
			
		||||
* Fix telepathy chat notifications [Marco; !1112]
 | 
			
		||||
* Fix offline updates support in end session dialog [Michael; #2276]
 | 
			
		||||
* Fix activating notifications by keyboard [Florian; #2319]
 | 
			
		||||
* Remove handling of 'blacklisted' extensions [Florian; !1132]
 | 
			
		||||
* Only update extensions if Extensions app is installed [Florian; #2346]
 | 
			
		||||
* Improve Norwegian on-screen-keyboard layout [Bjørn; !1073]
 | 
			
		||||
* Fix IM support for deleting surrounding text [Takao; !477]
 | 
			
		||||
* Fix blur effect with fractional scaling [Jonas D.; !1000]
 | 
			
		||||
* Use better location name in weather section [Florian; #2468]
 | 
			
		||||
* Fix glitch in sound feedback on volume changes [Florian; !1147]
 | 
			
		||||
* Fix on-screen keyboard regressions [Jonas D.; !1142]
 | 
			
		||||
* Improve screen-reader support [Luke; #2508, #2517]
 | 
			
		||||
* Fix password entry resize on login/lock screen [Florian; #2423]
 | 
			
		||||
* Fix crash when opening app picker [Jonas Å.; !1154]
 | 
			
		||||
* Misc. bug fixes and cleanups [Florian, Sebastian, Jan, Daniel, Philip, Mario,
 | 
			
		||||
  Ray, Marco, Jonas D., Carlos, Georges; #2298, #2305, !1078, !1077, #2334,
 | 
			
		||||
  #2381, !1093, !1098, #2386, !1108, !1109, !1114, !1076, !1072, !1115, !1088,
 | 
			
		||||
  !1101, #2467, !1121, !1122, #2476, !1123, !1117, !1129, !1113, !1102, !1127,
 | 
			
		||||
  #2238, !1131, !1135, !1136, !849, #2504, #2371, !1146, !1141, #2510, !1150]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Marco Trevisan (Treviño), Michael Catanzaro, Cosimo Cecchi, Jonas Dreßler,
 | 
			
		||||
  Takao Fujiwara, Carlos Garnacho, Christian Hergert, Sebastian Keller,
 | 
			
		||||
  Reik Keutterling, Bjørn Lie, Florian Müllner, Jwtiyar Nariman,
 | 
			
		||||
  Georges Basile Stavracas Neto, Mario Sanchez Prada, Ray Strode, Jan Tojnar,
 | 
			
		||||
  Daniel van Vugt, Philip Withnall, Luke Yelavich, Alynx Zhou, Jonas Ådahl
 | 
			
		||||
 | 
			
		||||
Translators:
 | 
			
		||||
  Марко Костић [sr], Jordi Mas [ca], sicklylife [ja], Marek Černocký [cs],
 | 
			
		||||
  Daniel Rusek [cs], Kjartan Maraas [nb], Tim Sabsch [de], Stas Solovey [ru],
 | 
			
		||||
  Peter Mráz [sk], Rafael Fontenelle [pt_BR], Piotr Drąg [pl],
 | 
			
		||||
  Milo Casagrande [it], Anders Jonsson [sv], Yuri Chornoivan [uk],
 | 
			
		||||
  Kukuh Syafaat [id], Guillaume Bernard [fr], Daniel Mustieles [es],
 | 
			
		||||
  Danial Behzadi [fa], Goran Vidović [hr], Yosef Or Boczko [he],
 | 
			
		||||
  Emin Tufan Çetin [tr], Wolfgang Stöggl [de], Ibai Oihanguren Sala [eu],
 | 
			
		||||
  Jwtiyar Nariman [ckb], Aurimas Černius [lt]
 | 
			
		||||
  Rūdolfs Mazurs [lv], Yuri Chornoivan [uk], Carmen Bianca BAKKER [eo],
 | 
			
		||||
  Dingzhong Chen [zh_CN], Rafael Fontenelle [pt_BR], Petr Kovář [cs],
 | 
			
		||||
  Asier Sarasua Garmendia [eu], Daniel Mustieles [es], Emin Tufan Çetin [tr]
 | 
			
		||||
 | 
			
		||||
3.36.0
 | 
			
		||||
======
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@
 | 
			
		||||
<gresources>
 | 
			
		||||
  <gresource prefix="/org/gnome/shell/dbus-interfaces">
 | 
			
		||||
    <file preprocess="xml-stripblanks">net.hadess.SensorProxy.xml</file>
 | 
			
		||||
    <file preprocess="xml-stripblanks">net.hadess.SwitcherooControl.xml</file>
 | 
			
		||||
    <file preprocess="xml-stripblanks">org.freedesktop.Application.xml</file>
 | 
			
		||||
    <file preprocess="xml-stripblanks">org.freedesktop.bolt1.Device.xml</file>
 | 
			
		||||
    <file preprocess="xml-stripblanks">org.freedesktop.bolt1.Manager.xml</file>
 | 
			
		||||
 
 | 
			
		||||
@@ -6,24 +6,25 @@
 | 
			
		||||
    <file>checkbox-off-focused.svg</file>
 | 
			
		||||
    <file>checkbox-off.svg</file>
 | 
			
		||||
    <file>checkbox.svg</file>
 | 
			
		||||
    <file alias="icons/color-pick.svg">color-pick.svg</file>
 | 
			
		||||
    <file>dash-placeholder.svg</file>
 | 
			
		||||
    <file>gnome-shell.css</file>
 | 
			
		||||
    <file>gnome-shell-high-contrast.css</file>
 | 
			
		||||
    <file alias="icons/scalable/status/message-indicator-symbolic.svg">message-indicator-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/message-indicator-symbolic.svg">message-indicator-symbolic.svg</file>
 | 
			
		||||
    <file>no-events.svg</file>
 | 
			
		||||
    <file>no-notifications.svg</file>
 | 
			
		||||
    <file>pad-osd.css</file>
 | 
			
		||||
    <file alias="icons/scalable/status/eye-open-negative-filled-symbolic.svg">eye-open-negative-filled-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/scalable/status/eye-not-looking-symbolic.svg">eye-not-looking-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/scalable/actions/pointer-double-click-symbolic.svg">pointer-double-click-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/scalable/actions/pointer-drag-symbolic.svg">pointer-drag-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/scalable/actions/pointer-primary-click-symbolic.svg">pointer-primary-click-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/scalable/actions/pointer-secondary-click-symbolic.svg">pointer-secondary-click-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/scalable/status/keyboard-caps-lock-filled-symbolic.svg">keyboard-caps-lock-filled-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/scalable/status/keyboard-enter-symbolic.svg">keyboard-enter-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/scalable/status/keyboard-hide-symbolic.svg">keyboard-hide-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/scalable/status/keyboard-layout-filled-symbolic.svg">keyboard-layout-filled-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/scalable/status/keyboard-shift-filled-symbolic.svg">keyboard-shift-filled-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/eye-open-negative-filled-symbolic.svg">eye-open-negative-filled-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/eye-not-looking-symbolic.svg">eye-not-looking-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/pointer-double-click-symbolic.svg">pointer-double-click-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/pointer-drag-symbolic.svg">pointer-drag-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/pointer-primary-click-symbolic.svg">pointer-primary-click-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/pointer-secondary-click-symbolic.svg">pointer-secondary-click-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/keyboard-caps-lock-filled-symbolic.svg">keyboard-caps-lock-filled-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/keyboard-enter-symbolic.svg">keyboard-enter-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/keyboard-hide-symbolic.svg">keyboard-hide-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/keyboard-layout-filled-symbolic.svg">keyboard-layout-filled-symbolic.svg</file>
 | 
			
		||||
    <file alias="icons/keyboard-shift-filled-symbolic.svg">keyboard-shift-filled-symbolic.svg</file>
 | 
			
		||||
    <file>process-working.svg</file>
 | 
			
		||||
    <file>toggle-off.svg</file>
 | 
			
		||||
    <file>toggle-off-dark.svg</file>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										94
									
								
								data/theme/color-pick.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								data/theme/color-pick.svg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
 | 
			
		||||
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   width="5.4116011mm"
 | 
			
		||||
   height="5.1374583mm"
 | 
			
		||||
   viewBox="0 0 5.4116011 5.1374583"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   id="svg5595"
 | 
			
		||||
   inkscape:version="0.92.4 (unknown)"
 | 
			
		||||
   sodipodi:docname="color-pick.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs5589">
 | 
			
		||||
    <filter
 | 
			
		||||
       inkscape:collect="always"
 | 
			
		||||
       x="-0.10291173"
 | 
			
		||||
       width="1.2058235"
 | 
			
		||||
       y="-0.065432459"
 | 
			
		||||
       height="1.1308649"
 | 
			
		||||
       id="filter5601"
 | 
			
		||||
       style="color-interpolation-filters:sRGB">
 | 
			
		||||
      <feGaussianBlur
 | 
			
		||||
         inkscape:collect="always"
 | 
			
		||||
         stdDeviation="0.610872"
 | 
			
		||||
         id="feGaussianBlur5603" />
 | 
			
		||||
    </filter>
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#ffffff"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="0.0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="15.839192"
 | 
			
		||||
     inkscape:cx="39.387731"
 | 
			
		||||
     inkscape:cy="12.554326"
 | 
			
		||||
     inkscape:document-units="mm"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:window-width="1920"
 | 
			
		||||
     inkscape:window-height="1016"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="27"
 | 
			
		||||
     inkscape:window-maximized="1"
 | 
			
		||||
     fit-margin-top="0"
 | 
			
		||||
     fit-margin-left="0"
 | 
			
		||||
     fit-margin-right="0"
 | 
			
		||||
     fit-margin-bottom="0" />
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata5592">
 | 
			
		||||
    <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(-103.12753,-146.26461)">
 | 
			
		||||
    <circle
 | 
			
		||||
       r="8.4810486"
 | 
			
		||||
       cy="9.82623"
 | 
			
		||||
       cx="10.226647"
 | 
			
		||||
       id="circle7584"
 | 
			
		||||
       style="color:#000000;display:inline;overflow:visible;opacity:0.6;vector-effect:none;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;filter:url(#filter5601)"
 | 
			
		||||
       transform="matrix(0.26458333,0,0,0.26458333,103.12753,146.26461)" />
 | 
			
		||||
    <path
 | 
			
		||||
       style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.26399338;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
 | 
			
		||||
       d="m 108.07728,148.64122 c 0,1.2393 -1.00465,2.24394 -2.24395,2.24394 -1.23929,0 -2.24716,-1.00465 -2.25221,-2.24394 l -0.009,-2.24458 2.26136,6.4e-4 c 1.2393,3.4e-4 2.24395,1.00464 2.24395,2.24394 z"
 | 
			
		||||
       id="path7523-7"
 | 
			
		||||
       inkscape:connector-curvature="0"
 | 
			
		||||
       sodipodi:nodetypes="ssscss" />
 | 
			
		||||
    <circle
 | 
			
		||||
       style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#50dbb5;fill-opacity:1;stroke:none;stroke-width:0.36885914;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
 | 
			
		||||
       id="path7482-1"
 | 
			
		||||
       cx="105.83707"
 | 
			
		||||
       cy="148.64352"
 | 
			
		||||
       r="1.844296" />
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 3.7 KiB  | 
@@ -1,21 +1,15 @@
 | 
			
		||||
/* App Grid */
 | 
			
		||||
 | 
			
		||||
$app_icon_size: 96px;
 | 
			
		||||
$app_icon_padding: 24px;
 | 
			
		||||
 | 
			
		||||
// app icons
 | 
			
		||||
.icon-grid {
 | 
			
		||||
  -shell-grid-horizontal-item-size: $app_icon_size + $app_icon_padding * 2;
 | 
			
		||||
  -shell-grid-vertical-item-size: $app_icon_size + $app_icon_padding * 2;
 | 
			
		||||
  spacing: $base_spacing * 4;
 | 
			
		||||
 | 
			
		||||
  .overview-icon {
 | 
			
		||||
    icon-size: $app_icon_size;
 | 
			
		||||
  }
 | 
			
		||||
  row-spacing: $base_spacing * 6;
 | 
			
		||||
  column-spacing: $base_spacing * 6;
 | 
			
		||||
  max-row-spacing: $base_spacing * 12;
 | 
			
		||||
  max-column-spacing: $base_spacing * 12;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//.app-display { spacing: 20px; }
 | 
			
		||||
 | 
			
		||||
/* App Icons */
 | 
			
		||||
 | 
			
		||||
$app_grid_fg_color: #fff;
 | 
			
		||||
@@ -44,8 +38,8 @@ $app_grid_fg_color: #fff;
 | 
			
		||||
.app-folder-dialog {
 | 
			
		||||
  border-radius: $modal_radius * 1.5;
 | 
			
		||||
  border: 1px solid $osd_outer_borders_color;
 | 
			
		||||
  spacing: 12px;
 | 
			
		||||
  background-color: transparentize(darken($osd_bg_color,10%), 0.05);
 | 
			
		||||
  padding: 12px;
 | 
			
		||||
 | 
			
		||||
  & .folder-name-container {
 | 
			
		||||
    padding: 24px 36px 0;
 | 
			
		||||
@@ -54,7 +48,7 @@ $app_grid_fg_color: #fff;
 | 
			
		||||
    & .folder-name-label,
 | 
			
		||||
    & .folder-name-entry {
 | 
			
		||||
      font-size: 18pt;
 | 
			
		||||
      font-weight: bold;
 | 
			
		||||
      font-weight: 800;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & .folder-name-entry { width: 300px }
 | 
			
		||||
@@ -73,11 +67,24 @@ $app_grid_fg_color: #fff;
 | 
			
		||||
      & > StIcon { icon-size: 16px }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  & .icon-grid {
 | 
			
		||||
    row-spacing: $base_spacing * 2;
 | 
			
		||||
    column-spacing: $base_spacing * 5;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  & .page-indicators {
 | 
			
		||||
    margin-bottom: 18px;
 | 
			
		||||
 | 
			
		||||
    .page-indicator {
 | 
			
		||||
      padding: 15px 12px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.app-folder-dialog-container {
 | 
			
		||||
  padding: 12px;
 | 
			
		||||
  width: 800px;
 | 
			
		||||
  height: 600px;
 | 
			
		||||
  width: 620px;
 | 
			
		||||
  height: 620px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.app-folder-icon {
 | 
			
		||||
@@ -123,15 +130,11 @@ $app_grid_fg_color: #fff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Some hacks I don't even know
 | 
			
		||||
.all-apps,
 | 
			
		||||
.frequent-apps > StBoxLayout {
 | 
			
		||||
.all-apps {
 | 
			
		||||
  // horizontal padding to make sure scrollbars or dash don't overlap content
 | 
			
		||||
  padding: 0px 88px 10px 88px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Label when no frequent apps
 | 
			
		||||
.no-frequent-applications-label { @extend %status_text; }
 | 
			
		||||
 | 
			
		||||
// shutdown and other actions in the grid
 | 
			
		||||
.system-action-icon {
 | 
			
		||||
  background-color: rgba(0,0,0,0.8);
 | 
			
		||||
@@ -139,44 +142,3 @@ $app_grid_fg_color: #fff;
 | 
			
		||||
  border-radius: 99px;
 | 
			
		||||
  icon-size: $app_icon_size * 0.5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Frequent | All toggle */
 | 
			
		||||
 | 
			
		||||
// container
 | 
			
		||||
.app-view-controls { 
 | 
			
		||||
  padding-bottom: 32px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// buttons
 | 
			
		||||
.app-view-control {
 | 
			
		||||
  padding: 4px 32px;
 | 
			
		||||
  margin: 0 4px;
 | 
			
		||||
 | 
			
		||||
  &, &:hover, &:checked {
 | 
			
		||||
    @include button(undecorated);
 | 
			
		||||
    color: darken($osd_fg_color, 25%);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &:hover {
 | 
			
		||||
    color: $osd_fg_color;
 | 
			
		||||
    box-shadow: inset 0 -2px darken($osd_fg_color, 25%);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &:active {
 | 
			
		||||
    box-shadow: inset 0 -2px $osd_fg_color;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &:checked {
 | 
			
		||||
    color: $osd_fg_color;
 | 
			
		||||
    box-shadow: inset 0 -2px $selected_bg_color;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &:first-child {
 | 
			
		||||
    border-right-width: 0;
 | 
			
		||||
    border-radius: 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &:last-child {
 | 
			
		||||
    border-radius: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -177,6 +177,32 @@
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Events */
 | 
			
		||||
.events-button {
 | 
			
		||||
  @include notification_bubble;
 | 
			
		||||
  padding: $base_padding * 2;
 | 
			
		||||
 | 
			
		||||
  .events-box {
 | 
			
		||||
    spacing: $base_spacing;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .events-list {
 | 
			
		||||
    spacing: 2 * $base_spacing;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .events-title {
 | 
			
		||||
    color: desaturate(darken($fg_color,40%), 10%);
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    margin-bottom: $base_margin;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .event-time {
 | 
			
		||||
    color: darken($fg_color,20%);
 | 
			
		||||
    font-feature-settings: "tnum";
 | 
			
		||||
    @include fontsize($base_font_size - 1);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* World clocks */
 | 
			
		||||
.world-clocks-button {
 | 
			
		||||
  @include notification_bubble;
 | 
			
		||||
@@ -206,9 +232,7 @@
 | 
			
		||||
    color: $fg_color;
 | 
			
		||||
    font-feature-settings: "tnum";
 | 
			
		||||
    @include fontsize($base_font_size);
 | 
			
		||||
 | 
			
		||||
    &:ltr { text-align: right; }
 | 
			
		||||
    &:rtl { text-align: left; }
 | 
			
		||||
    text-align: right;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // timezone offset label
 | 
			
		||||
 
 | 
			
		||||
@@ -138,10 +138,11 @@
 | 
			
		||||
.user-widget.horizontal .user-widget-label {
 | 
			
		||||
  @include fontsize($base_font_size + 2);
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  text-align: left;
 | 
			
		||||
  padding-left: 15px;
 | 
			
		||||
 | 
			
		||||
  &:ltr { padding-left: 14px; text-align: left; }
 | 
			
		||||
  &:rtl { padding-right: 14px; text-align: right; }
 | 
			
		||||
  &:ltr { padding-left: 14px; }
 | 
			
		||||
  &:rtl { padding-right: 14px; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-widget.vertical .user-widget-label {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
/* Looking Glass */
 | 
			
		||||
 | 
			
		||||
$text_fg_color: #ccc;
 | 
			
		||||
 | 
			
		||||
// Dialog
 | 
			
		||||
#LookingGlassDialog {
 | 
			
		||||
  background-color: $osd_bg_color;
 | 
			
		||||
@@ -52,6 +54,11 @@
 | 
			
		||||
    &:hover { color: lighten($link_color, 10%); }
 | 
			
		||||
    &:active { color: darken($link_color, 10%); }
 | 
			
		||||
   }
 | 
			
		||||
  .actor-link {
 | 
			
		||||
    color: $text_fg_color;
 | 
			
		||||
    &:hover { color: lighten($text_fg_color, 20%); }
 | 
			
		||||
    &:active { color: darken($text_fg_color, 20%); }
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.lg-completions-text {
 | 
			
		||||
 
 | 
			
		||||
@@ -71,11 +71,9 @@
 | 
			
		||||
    > .event-time {
 | 
			
		||||
      color: transparentize($fg_color, 0.5);
 | 
			
		||||
      @include fontsize($base_font_size - 2);
 | 
			
		||||
      text-align: right;
 | 
			
		||||
      /* HACK: the label should be baseline-aligned with a 1em label, fake this with some bottom padding */
 | 
			
		||||
      padding-bottom: 0.13em;
 | 
			
		||||
 | 
			
		||||
      &:ltr { text-align: right };
 | 
			
		||||
      &:rtl { text-align: left };
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -76,10 +76,8 @@ $popover_arrow_height: 12px;
 | 
			
		||||
 | 
			
		||||
// container for radio and check boxes
 | 
			
		||||
.popup-menu-ornament {
 | 
			
		||||
  text-align: right;
 | 
			
		||||
  width: 1.2em;
 | 
			
		||||
 | 
			
		||||
  &:ltr { text-align: right };
 | 
			
		||||
  &:rtl { text-align: left };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// separator
 | 
			
		||||
 
 | 
			
		||||
@@ -54,6 +54,10 @@
 | 
			
		||||
  @extend %status_text;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grid-search-results {
 | 
			
		||||
  spacing: $base_spacing * 6;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Search results with icons
 | 
			
		||||
.grid-search-result {
 | 
			
		||||
  @extend %app-well-app;
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ $window_thumbnail_border_color:transparentize($selected_fg_color, 0.65);
 | 
			
		||||
$window_close_button_size: 24px;
 | 
			
		||||
$window_close_button_padding: 3px;
 | 
			
		||||
 | 
			
		||||
$window_clone_border_size: 6px;
 | 
			
		||||
 | 
			
		||||
// Window picker
 | 
			
		||||
.window-picker {
 | 
			
		||||
@@ -22,7 +23,7 @@ $window_close_button_padding: 3px;
 | 
			
		||||
 | 
			
		||||
// Borders on window thumbnails
 | 
			
		||||
.window-clone-border {
 | 
			
		||||
  border-width: 6px;
 | 
			
		||||
  border-width: $window_clone_border_size;
 | 
			
		||||
  border-style: solid;
 | 
			
		||||
  border-color: $window_thumbnail_border_color;
 | 
			
		||||
  border-radius: $base_border_radius + 2;
 | 
			
		||||
@@ -54,8 +55,6 @@ $window_close_button_padding: 3px;
 | 
			
		||||
  width: $window_close_button_size;
 | 
			
		||||
  box-shadow: -1px 1px 5px 0px rgba(0,0,0,0.5);
 | 
			
		||||
 | 
			
		||||
  -shell-close-overlap: $window_close_button_size * 0.5;
 | 
			
		||||
 | 
			
		||||
  &:hover {
 | 
			
		||||
    background-color: lighten($selected_bg_color, 5%);
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -589,8 +589,8 @@ var LoginDialog = GObject.registerClass({
 | 
			
		||||
        return actorBox;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(dialogBox, flags) {
 | 
			
		||||
        this.set_allocation(dialogBox, flags);
 | 
			
		||||
    vfunc_allocate(dialogBox) {
 | 
			
		||||
        this.set_allocation(dialogBox);
 | 
			
		||||
 | 
			
		||||
        let themeNode = this.get_theme_node();
 | 
			
		||||
        dialogBox = themeNode.get_content_box(dialogBox);
 | 
			
		||||
@@ -719,19 +719,19 @@ var LoginDialog = GObject.registerClass({
 | 
			
		||||
 | 
			
		||||
        // Finally hand out the allocations
 | 
			
		||||
        if (bannerAllocation)
 | 
			
		||||
            this._bannerView.allocate(bannerAllocation, flags);
 | 
			
		||||
            this._bannerView.allocate(bannerAllocation);
 | 
			
		||||
 | 
			
		||||
        if (authPromptAllocation)
 | 
			
		||||
            this._authPrompt.allocate(authPromptAllocation, flags);
 | 
			
		||||
            this._authPrompt.allocate(authPromptAllocation);
 | 
			
		||||
 | 
			
		||||
        if (userSelectionAllocation)
 | 
			
		||||
            this._userSelectionBox.allocate(userSelectionAllocation, flags);
 | 
			
		||||
            this._userSelectionBox.allocate(userSelectionAllocation);
 | 
			
		||||
 | 
			
		||||
        if (logoAllocation)
 | 
			
		||||
            this._logoBin.allocate(logoAllocation, flags);
 | 
			
		||||
            this._logoBin.allocate(logoAllocation);
 | 
			
		||||
 | 
			
		||||
        if (sessionMenuButtonAllocation)
 | 
			
		||||
            this._sessionMenuButton.allocate(sessionMenuButtonAllocation, flags);
 | 
			
		||||
            this._sessionMenuButton.allocate(sessionMenuButtonAllocation);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _ensureUserListLoaded() {
 | 
			
		||||
@@ -810,12 +810,13 @@ var LoginDialog = GObject.registerClass({
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._logoBin.destroy_all_children();
 | 
			
		||||
        if (this._logoFile && this._logoBin.resource_scale > 0) {
 | 
			
		||||
        const [valid, resourceScale] = this._logoBin.get_resource_scale();
 | 
			
		||||
        if (this._logoFile && valid) {
 | 
			
		||||
            let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
 | 
			
		||||
            this._logoBin.add_child(this._textureCache.load_file_async(this._logoFile,
 | 
			
		||||
                                                                       -1, -1,
 | 
			
		||||
                                                                       scaleFactor,
 | 
			
		||||
                                                                       this._logoBin.resource_scale));
 | 
			
		||||
                                                                       resourceScale));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -952,15 +953,16 @@ var LoginDialog = GObject.registerClass({
 | 
			
		||||
        if (this.opacity == 255 && this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (this._authPrompt.verificationStatus !== AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
 | 
			
		||||
            this._authPrompt.reset();
 | 
			
		||||
 | 
			
		||||
        this._bindOpacity();
 | 
			
		||||
        this.ease({
 | 
			
		||||
            opacity: 255,
 | 
			
		||||
            duration: _FADE_ANIMATION_TIME,
 | 
			
		||||
            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
            onComplete: () => this._unbindOpacity(),
 | 
			
		||||
            onComplete: () => {
 | 
			
		||||
                if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
 | 
			
		||||
                    this._authPrompt.reset();
 | 
			
		||||
                this._unbindOpacity();
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
/* exported BANNER_MESSAGE_KEY, BANNER_MESSAGE_TEXT_KEY, LOGO_KEY,
 | 
			
		||||
            DISABLE_USER_LIST_KEY, fadeInActor, fadeOutActor, cloneAndFadeOutActor */
 | 
			
		||||
 | 
			
		||||
const { Clutter, Gio, GLib } = imports.gi;
 | 
			
		||||
const { Clutter, Gdm, Gio, GLib } = imports.gi;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const Batch = imports.gdm.batch;
 | 
			
		||||
@@ -12,6 +12,15 @@ const Main = imports.ui.main;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const SmartcardManager = imports.misc.smartcardManager;
 | 
			
		||||
 | 
			
		||||
Gio._promisify(Gdm.Client.prototype,
 | 
			
		||||
    'open_reauthentication_channel', 'open_reauthentication_channel_finish');
 | 
			
		||||
Gio._promisify(Gdm.Client.prototype,
 | 
			
		||||
    'get_user_verifier', 'get_user_verifier_finish');
 | 
			
		||||
Gio._promisify(Gdm.UserVerifierProxy.prototype,
 | 
			
		||||
    'call_begin_verification_for_user', 'call_begin_verification_for_user_finish');
 | 
			
		||||
Gio._promisify(Gdm.UserVerifierProxy.prototype,
 | 
			
		||||
    'call_begin_verification', 'call_begin_verification_finish');
 | 
			
		||||
 | 
			
		||||
var PASSWORD_SERVICE_NAME = 'gdm-password';
 | 
			
		||||
var FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
 | 
			
		||||
var SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
 | 
			
		||||
@@ -168,14 +177,12 @@ var ShellUserVerifier = class {
 | 
			
		||||
 | 
			
		||||
        this._checkForFingerprintReader();
 | 
			
		||||
 | 
			
		||||
        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,
 | 
			
		||||
                                                       this._reauthenticationChannelOpened.bind(this));
 | 
			
		||||
        } else {
 | 
			
		||||
            this._client.get_user_verifier(this._cancellable, this._userVerifierGot.bind(this));
 | 
			
		||||
        }
 | 
			
		||||
        // If possible, reauthenticate an already running session,
 | 
			
		||||
        // so any session specific credentials get updated appropriately
 | 
			
		||||
        if (userName)
 | 
			
		||||
            this._openReauthenticationChannel(userName);
 | 
			
		||||
        else
 | 
			
		||||
            this._getUserVerifier();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cancel() {
 | 
			
		||||
@@ -339,10 +346,11 @@ var ShellUserVerifier = class {
 | 
			
		||||
        this._verificationFailed(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _reauthenticationChannelOpened(client, result) {
 | 
			
		||||
    async _openReauthenticationChannel(userName) {
 | 
			
		||||
        try {
 | 
			
		||||
            this._clearUserVerifier();
 | 
			
		||||
            this._userVerifier = client.open_reauthentication_channel_finish(result);
 | 
			
		||||
            this._userVerifier = await this._client.open_reauthentication_channel(
 | 
			
		||||
                userName, this._cancellable);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
 | 
			
		||||
                return;
 | 
			
		||||
@@ -351,8 +359,7 @@ var ShellUserVerifier = class {
 | 
			
		||||
                // Gdm emits org.freedesktop.DBus.Error.AccessDenied when there
 | 
			
		||||
                // is no session to reauthenticate. Fall back to performing
 | 
			
		||||
                // verification from this login session
 | 
			
		||||
                client.get_user_verifier(this._cancellable,
 | 
			
		||||
                                         this._userVerifierGot.bind(this));
 | 
			
		||||
                this._getUserVerifier();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -366,10 +373,11 @@ var ShellUserVerifier = class {
 | 
			
		||||
        this._hold.release();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _userVerifierGot(client, result) {
 | 
			
		||||
    async _getUserVerifier() {
 | 
			
		||||
        try {
 | 
			
		||||
            this._clearUserVerifier();
 | 
			
		||||
            this._userVerifier = client.get_user_verifier_finish(result);
 | 
			
		||||
            this._userVerifier =
 | 
			
		||||
                await this._client.get_user_verifier(this._cancellable);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
 | 
			
		||||
                return;
 | 
			
		||||
@@ -421,35 +429,25 @@ var ShellUserVerifier = class {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _startService(serviceName) {
 | 
			
		||||
    async _startService(serviceName) {
 | 
			
		||||
        this._hold.acquire();
 | 
			
		||||
        if (this._userName) {
 | 
			
		||||
            this._userVerifier.call_begin_verification_for_user(serviceName, this._userName, this._cancellable, (obj, result) => {
 | 
			
		||||
                try {
 | 
			
		||||
                    obj.call_begin_verification_for_user_finish(result);
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
                    if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
 | 
			
		||||
                        return;
 | 
			
		||||
                    this._reportInitError('Failed to start verification for user', e);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this._hold.release();
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            this._userVerifier.call_begin_verification(serviceName, this._cancellable, (obj, result) => {
 | 
			
		||||
                try {
 | 
			
		||||
                    obj.call_begin_verification_finish(result);
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
                    if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
 | 
			
		||||
                        return;
 | 
			
		||||
                    this._reportInitError('Failed to start verification', e);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this._hold.release();
 | 
			
		||||
            });
 | 
			
		||||
        try {
 | 
			
		||||
            if (this._userName) {
 | 
			
		||||
                await this._userVerifier.call_begin_verification_for_user(
 | 
			
		||||
                    serviceName, this._userName, this._cancellable);
 | 
			
		||||
            } else {
 | 
			
		||||
                await this._userVerifier.call_begin_verification(
 | 
			
		||||
                    serviceName, this._cancellable);
 | 
			
		||||
            }
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
 | 
			
		||||
                return;
 | 
			
		||||
            this._reportInitError(this._userName
 | 
			
		||||
                ? 'Failed to start verification for user'
 | 
			
		||||
                : 'Failed to start verification', e);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        this._hold.release();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _beginVerification() {
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@
 | 
			
		||||
    <file>misc/modemManager.js</file>
 | 
			
		||||
    <file>misc/objectManager.js</file>
 | 
			
		||||
    <file>misc/params.js</file>
 | 
			
		||||
    <file>misc/parentalControlsManager.js</file>
 | 
			
		||||
    <file>misc/permissionStore.js</file>
 | 
			
		||||
    <file>misc/smartcardManager.js</file>
 | 
			
		||||
    <file>misc/systemActions.js</file>
 | 
			
		||||
@@ -101,13 +102,13 @@
 | 
			
		||||
    <file>ui/swipeTracker.js</file>
 | 
			
		||||
    <file>ui/switcherPopup.js</file>
 | 
			
		||||
    <file>ui/switchMonitor.js</file>
 | 
			
		||||
    <file>ui/tweener.js</file>
 | 
			
		||||
    <file>ui/unlockDialog.js</file>
 | 
			
		||||
    <file>ui/userWidget.js</file>
 | 
			
		||||
    <file>ui/viewSelector.js</file>
 | 
			
		||||
    <file>ui/windowAttentionHandler.js</file>
 | 
			
		||||
    <file>ui/windowMenu.js</file>
 | 
			
		||||
    <file>ui/windowManager.js</file>
 | 
			
		||||
    <file>ui/windowPreview.js</file>
 | 
			
		||||
    <file>ui/workspace.js</file>
 | 
			
		||||
    <file>ui/workspaceSwitcherPopup.js</file>
 | 
			
		||||
    <file>ui/workspaceThumbnail.js</file>
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,15 @@ const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const IBusCandidatePopup = imports.ui.ibusCandidatePopup;
 | 
			
		||||
 | 
			
		||||
Gio._promisify(IBus.Bus.prototype,
 | 
			
		||||
    'list_engines_async', 'list_engines_async_finish');
 | 
			
		||||
Gio._promisify(IBus.Bus.prototype,
 | 
			
		||||
    'request_name_async', 'request_name_async_finish');
 | 
			
		||||
Gio._promisify(IBus.Bus.prototype,
 | 
			
		||||
    'get_global_engine_async', 'get_global_engine_async_finish');
 | 
			
		||||
Gio._promisify(IBus.Bus.prototype,
 | 
			
		||||
    'set_global_engine_async', 'set_global_engine_async_finish');
 | 
			
		||||
 | 
			
		||||
// Ensure runtime version matches
 | 
			
		||||
_checkIBusVersion(1, 5, 2);
 | 
			
		||||
 | 
			
		||||
@@ -102,16 +111,14 @@ var IBusManager = class {
 | 
			
		||||
 | 
			
		||||
    _onConnected() {
 | 
			
		||||
        this._cancellable = new Gio.Cancellable();
 | 
			
		||||
        this._ibus.list_engines_async(-1, this._cancellable,
 | 
			
		||||
            this._initEngines.bind(this));
 | 
			
		||||
        this._ibus.request_name_async(IBus.SERVICE_PANEL,
 | 
			
		||||
            IBus.BusNameFlag.REPLACE_EXISTING, -1, this._cancellable,
 | 
			
		||||
            this._initPanelService.bind(this));
 | 
			
		||||
        this._initEngines();
 | 
			
		||||
        this._initPanelService();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _initEngines(ibus, result) {
 | 
			
		||||
    async _initEngines() {
 | 
			
		||||
        try {
 | 
			
		||||
            let enginesList = this._ibus.list_engines_async_finish(result);
 | 
			
		||||
            const enginesList =
 | 
			
		||||
                await this._ibus.list_engines_async(-1, this._cancellable);
 | 
			
		||||
            for (let i = 0; i < enginesList.length; ++i) {
 | 
			
		||||
                let name = enginesList[i].get_name();
 | 
			
		||||
                this._engines.set(name, enginesList[i]);
 | 
			
		||||
@@ -126,9 +133,10 @@ var IBusManager = class {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _initPanelService(ibus, result) {
 | 
			
		||||
    async _initPanelService() {
 | 
			
		||||
        try {
 | 
			
		||||
            this._ibus.request_name_async_finish(result);
 | 
			
		||||
            await this._ibus.request_name_async(IBus.SERVICE_PANEL,
 | 
			
		||||
                IBus.BusNameFlag.REPLACE_EXISTING, -1, this._cancellable);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
 | 
			
		||||
                logError(e);
 | 
			
		||||
@@ -163,19 +171,15 @@ var IBusManager = class {
 | 
			
		||||
            this._panelService.connect('set-content-type', this._setContentType.bind(this));
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
        }
 | 
			
		||||
        // If an engine is already active we need to get its properties
 | 
			
		||||
        this._ibus.get_global_engine_async(-1, this._cancellable, (_bus, res) => {
 | 
			
		||||
            let engine;
 | 
			
		||||
            try {
 | 
			
		||||
                engine = this._ibus.get_global_engine_async_finish(res);
 | 
			
		||||
                if (!engine)
 | 
			
		||||
                    return;
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            this._engineChanged(this._ibus, engine.get_name());
 | 
			
		||||
        });
 | 
			
		||||
        this._updateReadiness();
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            // If an engine is already active we need to get its properties
 | 
			
		||||
            const engine =
 | 
			
		||||
                await this._ibus.get_global_engine_async(-1, this._cancellable);
 | 
			
		||||
            this._engineChanged(this._ibus, engine.get_name());
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateReadiness() {
 | 
			
		||||
@@ -223,7 +227,7 @@ var IBusManager = class {
 | 
			
		||||
        return this._engines.get(id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setEngine(id, callback) {
 | 
			
		||||
    async setEngine(id, callback) {
 | 
			
		||||
        // Send id even if id == this._currentEngineName
 | 
			
		||||
        // because 'properties-registered' signal can be emitted
 | 
			
		||||
        // while this._ibusSources == null on a lock screen.
 | 
			
		||||
@@ -233,18 +237,16 @@ var IBusManager = class {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._ibus.set_global_engine_async(id,
 | 
			
		||||
            this._MAX_INPUT_SOURCE_ACTIVATION_TIME,
 | 
			
		||||
            this._cancellable, (_bus, res) => {
 | 
			
		||||
                try {
 | 
			
		||||
                    this._ibus.set_global_engine_async_finish(res);
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
                    if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
 | 
			
		||||
                        logError(e);
 | 
			
		||||
                }
 | 
			
		||||
                if (callback)
 | 
			
		||||
                    callback();
 | 
			
		||||
            });
 | 
			
		||||
        try {
 | 
			
		||||
            await this._ibus.set_global_engine_async(id,
 | 
			
		||||
                this._MAX_INPUT_SOURCE_ACTIVATION_TIME,
 | 
			
		||||
                this._cancellable);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
 | 
			
		||||
                logError(e);
 | 
			
		||||
        }
 | 
			
		||||
        if (callback)
 | 
			
		||||
            callback();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    preloadEngines(ids) {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,9 @@ const { Clutter, GLib, Gio, GObject, IBus } = imports.gi;
 | 
			
		||||
 | 
			
		||||
const Keyboard = imports.ui.status.keyboard;
 | 
			
		||||
 | 
			
		||||
Gio._promisify(IBus.Bus.prototype,
 | 
			
		||||
    'create_input_context_async', 'create_input_context_async_finish');
 | 
			
		||||
 | 
			
		||||
var HIDE_PANEL_TIME = 50;
 | 
			
		||||
 | 
			
		||||
var InputMethod = GObject.registerClass(
 | 
			
		||||
@@ -46,15 +49,11 @@ class InputMethod extends Clutter.InputMethod {
 | 
			
		||||
        this._currentSource = this._inputSourceManager.currentSource;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onConnected() {
 | 
			
		||||
    async _onConnected() {
 | 
			
		||||
        this._cancellable = new Gio.Cancellable();
 | 
			
		||||
        this._ibus.create_input_context_async('gnome-shell', -1,
 | 
			
		||||
            this._cancellable, this._setContext.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _setContext(bus, res) {
 | 
			
		||||
        try {
 | 
			
		||||
            this._context = this._ibus.create_input_context_async_finish(res);
 | 
			
		||||
            this._context = await this._ibus.create_input_context_async(
 | 
			
		||||
                'gnome-shell', -1, this._cancellable);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
 | 
			
		||||
                logError(e);
 | 
			
		||||
 
 | 
			
		||||
@@ -24,8 +24,7 @@ function getCompletions(text, commandHeader, globalCompletionList) {
 | 
			
		||||
            [expr_, base, attrHead] = matches;
 | 
			
		||||
 | 
			
		||||
            methods = getPropertyNamesFromExpression(base, commandHeader).filter(
 | 
			
		||||
                attr => attr.slice(0, attrHead.length) == attrHead
 | 
			
		||||
            );
 | 
			
		||||
                attr => attr.slice(0, attrHead.length) === attrHead);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Look for the empty expression or partially entered words
 | 
			
		||||
@@ -34,8 +33,7 @@ function getCompletions(text, commandHeader, globalCompletionList) {
 | 
			
		||||
        if (text == '' || matches) {
 | 
			
		||||
            [expr_, attrHead] = matches;
 | 
			
		||||
            methods = globalCompletionList.filter(
 | 
			
		||||
                attr => attr.slice(0, attrHead.length) == attrHead
 | 
			
		||||
            );
 | 
			
		||||
                attr => attr.slice(0, attrHead.length) === attrHead);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/* exported getKeyboardManager, holdKeyboard, releaseKeyboard */
 | 
			
		||||
 | 
			
		||||
const { GLib, GnomeDesktop, Meta } = imports.gi;
 | 
			
		||||
const { GLib, GnomeDesktop } = imports.gi;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
 | 
			
		||||
@@ -62,11 +62,11 @@ var KeyboardManager = class {
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._currentKeymap = { layouts, variants, options };
 | 
			
		||||
        Meta.get_backend().set_keymap(layouts, variants, options);
 | 
			
		||||
        global.backend.set_keymap(layouts, variants, options);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _applyLayoutGroupIndex(idx) {
 | 
			
		||||
        Meta.get_backend().lock_layout_group(idx);
 | 
			
		||||
        global.backend.lock_layout_group(idx);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    apply(id) {
 | 
			
		||||
 
 | 
			
		||||
@@ -50,25 +50,22 @@ function canLock() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function registerSessionWithGDM() {
 | 
			
		||||
async function registerSessionWithGDM() {
 | 
			
		||||
    log("Registering session with GDM");
 | 
			
		||||
    Gio.DBus.system.call('org.gnome.DisplayManager',
 | 
			
		||||
                         '/org/gnome/DisplayManager/Manager',
 | 
			
		||||
                         'org.gnome.DisplayManager.Manager',
 | 
			
		||||
                         'RegisterSession',
 | 
			
		||||
                         GLib.Variant.new('(a{sv})', [{}]), null,
 | 
			
		||||
                         Gio.DBusCallFlags.NONE, -1, null,
 | 
			
		||||
        (source, result) => {
 | 
			
		||||
            try {
 | 
			
		||||
                source.call_finish(result);
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                if (!e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_METHOD))
 | 
			
		||||
                    log(`Error registering session with GDM: ${e.message}`);
 | 
			
		||||
                else
 | 
			
		||||
                    log("Not calling RegisterSession(): method not exported, GDM too old?");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    );
 | 
			
		||||
    try {
 | 
			
		||||
        await Gio.DBus.system.call(
 | 
			
		||||
            'org.gnome.DisplayManager',
 | 
			
		||||
            '/org/gnome/DisplayManager/Manager',
 | 
			
		||||
            'org.gnome.DisplayManager.Manager',
 | 
			
		||||
            'RegisterSession',
 | 
			
		||||
            GLib.Variant.new('(a{sv})', [{}]), null,
 | 
			
		||||
            Gio.DBusCallFlags.NONE, -1, null);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        if (!e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_METHOD))
 | 
			
		||||
            log(`Error registering session with GDM: ${e.message}`);
 | 
			
		||||
        else
 | 
			
		||||
            log('Not calling RegisterSession(): method not exported, GDM too old?');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let _loginManager = null;
 | 
			
		||||
@@ -174,24 +171,19 @@ var LoginManagerSystemd = class {
 | 
			
		||||
        this._proxy.SuspendRemote(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inhibit(reason, callback) {
 | 
			
		||||
        let inVariant = GLib.Variant.new('(ssss)',
 | 
			
		||||
                                         ['sleep',
 | 
			
		||||
                                          'GNOME Shell',
 | 
			
		||||
                                          reason,
 | 
			
		||||
                                          'delay']);
 | 
			
		||||
        this._proxy.call_with_unix_fd_list('Inhibit', inVariant, 0, -1, null, null,
 | 
			
		||||
            (proxy, result) => {
 | 
			
		||||
                let fd = -1;
 | 
			
		||||
                try {
 | 
			
		||||
                    let [outVariant_, fdList] = proxy.call_with_unix_fd_list_finish(result);
 | 
			
		||||
                    fd = fdList.steal_fds()[0];
 | 
			
		||||
                    callback(new Gio.UnixInputStream({ fd }));
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
                    logError(e, "Error getting systemd inhibitor");
 | 
			
		||||
                    callback(null);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
    async inhibit(reason, callback) {
 | 
			
		||||
        try {
 | 
			
		||||
            const inVariant = new GLib.Variant('(ssss)',
 | 
			
		||||
                ['sleep', 'GNOME Shell', reason, 'delay']);
 | 
			
		||||
            const [outVariant_, fdList] =
 | 
			
		||||
                await this._proxy.call_with_unix_fd_list('Inhibit',
 | 
			
		||||
                    inVariant, 0, -1, null, null);
 | 
			
		||||
            const [fd] = fdList.steal_fds();
 | 
			
		||||
            callback(new Gio.UnixInputStream({ fd }));
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            logError(e, 'Error getting systemd inhibitor');
 | 
			
		||||
            callback(null);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _prepareForSleep(proxy, sender, [aboutToSuspend]) {
 | 
			
		||||
 
 | 
			
		||||
@@ -57,9 +57,7 @@ var ObjectManager = class {
 | 
			
		||||
        // Start out inhibiting load until at least the proxy
 | 
			
		||||
        // manager is loaded and the remote objects are fetched
 | 
			
		||||
        this._numLoadInhibitors = 1;
 | 
			
		||||
        this._managerProxy.init_async(GLib.PRIORITY_DEFAULT,
 | 
			
		||||
                                      this._cancellable,
 | 
			
		||||
                                      this._onManagerProxyLoaded.bind(this));
 | 
			
		||||
        this._initManagerProxy();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _tryToCompleteLoad() {
 | 
			
		||||
@@ -73,7 +71,7 @@ var ObjectManager = class {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _addInterface(objectPath, interfaceName, onFinished) {
 | 
			
		||||
    async _addInterface(objectPath, interfaceName, onFinished) {
 | 
			
		||||
        let info = this._interfaceInfos[interfaceName];
 | 
			
		||||
 | 
			
		||||
        if (!info) {
 | 
			
		||||
@@ -89,40 +87,38 @@ var ObjectManager = class {
 | 
			
		||||
                                        g_interface_info: info,
 | 
			
		||||
                                        g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START });
 | 
			
		||||
 | 
			
		||||
        proxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable, (initable, result) => {
 | 
			
		||||
            try {
 | 
			
		||||
                initable.init_finish(result);
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                logError(e, `could not initialize proxy for interface ${interfaceName}`);
 | 
			
		||||
 | 
			
		||||
                if (onFinished)
 | 
			
		||||
                    onFinished();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let isNewObject;
 | 
			
		||||
            if (!this._objects[objectPath]) {
 | 
			
		||||
                this._objects[objectPath] = {};
 | 
			
		||||
                isNewObject = true;
 | 
			
		||||
            } else {
 | 
			
		||||
                isNewObject = false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this._objects[objectPath][interfaceName] = proxy;
 | 
			
		||||
 | 
			
		||||
            if (!this._interfaces[interfaceName])
 | 
			
		||||
                this._interfaces[interfaceName] = [];
 | 
			
		||||
 | 
			
		||||
            this._interfaces[interfaceName].push(proxy);
 | 
			
		||||
 | 
			
		||||
            if (isNewObject)
 | 
			
		||||
                this.emit('object-added', objectPath);
 | 
			
		||||
 | 
			
		||||
            this.emit('interface-added', interfaceName, proxy);
 | 
			
		||||
        try {
 | 
			
		||||
            await proxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            logError(e, `could not initialize proxy for interface ${interfaceName}`);
 | 
			
		||||
 | 
			
		||||
            if (onFinished)
 | 
			
		||||
                onFinished();
 | 
			
		||||
        });
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let isNewObject;
 | 
			
		||||
        if (!this._objects[objectPath]) {
 | 
			
		||||
            this._objects[objectPath] = {};
 | 
			
		||||
            isNewObject = true;
 | 
			
		||||
        } else {
 | 
			
		||||
            isNewObject = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._objects[objectPath][interfaceName] = proxy;
 | 
			
		||||
 | 
			
		||||
        if (!this._interfaces[interfaceName])
 | 
			
		||||
            this._interfaces[interfaceName] = [];
 | 
			
		||||
 | 
			
		||||
        this._interfaces[interfaceName].push(proxy);
 | 
			
		||||
 | 
			
		||||
        if (isNewObject)
 | 
			
		||||
            this.emit('object-added', objectPath);
 | 
			
		||||
 | 
			
		||||
        this.emit('interface-added', interfaceName, proxy);
 | 
			
		||||
 | 
			
		||||
        if (onFinished)
 | 
			
		||||
            onFinished();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _removeInterface(objectPath, interfaceName) {
 | 
			
		||||
@@ -151,9 +147,10 @@ var ObjectManager = class {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onManagerProxyLoaded(initable, result) {
 | 
			
		||||
    async _initManagerProxy() {
 | 
			
		||||
        try {
 | 
			
		||||
            initable.init_finish(result);
 | 
			
		||||
            await this._managerProxy.init_async(
 | 
			
		||||
                GLib.PRIORITY_DEFAULT, this._cancellable);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            logError(e, `could not initialize object manager for object ${this._serviceName}`);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										146
									
								
								js/misc/parentalControlsManager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								js/misc/parentalControlsManager.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,146 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
//
 | 
			
		||||
// Copyright (C) 2018, 2019, 2020 Endless Mobile, Inc.
 | 
			
		||||
//
 | 
			
		||||
// This is a GNOME Shell component to wrap the interactions over
 | 
			
		||||
// D-Bus with the malcontent library.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the GNU General Public License Version 2
 | 
			
		||||
//
 | 
			
		||||
// This program is free software; you can redistribute it and/or
 | 
			
		||||
// modify it under the terms of the GNU General Public License
 | 
			
		||||
// as published by the Free Software Foundation; either version 2
 | 
			
		||||
// of the License, or (at your option) any later version.
 | 
			
		||||
//
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
//
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program; if not, write to the Free Software
 | 
			
		||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 | 
			
		||||
 | 
			
		||||
/* exported getDefault */
 | 
			
		||||
 | 
			
		||||
const { Gio, GObject, Shell } = imports.gi;
 | 
			
		||||
 | 
			
		||||
// We require libmalcontent ≥ 0.6.0
 | 
			
		||||
const HAVE_MALCONTENT = imports.package.checkSymbol(
 | 
			
		||||
    'Malcontent', '0', 'ManagerGetValueFlags');
 | 
			
		||||
 | 
			
		||||
var Malcontent = null;
 | 
			
		||||
if (HAVE_MALCONTENT) {
 | 
			
		||||
    Malcontent = imports.gi.Malcontent;
 | 
			
		||||
    Gio._promisify(Malcontent.Manager.prototype, 'get_app_filter_async', 'get_app_filter_finish');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let _singleton = null;
 | 
			
		||||
 | 
			
		||||
function getDefault() {
 | 
			
		||||
    if (_singleton === null)
 | 
			
		||||
        _singleton = new ParentalControlsManager();
 | 
			
		||||
 | 
			
		||||
    return _singleton;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A manager class which provides cached access to the constructing user’s
 | 
			
		||||
// parental controls settings. It’s possible for the user’s parental controls
 | 
			
		||||
// to change at runtime if the Parental Controls application is used by an
 | 
			
		||||
// administrator from within the user’s session.
 | 
			
		||||
var ParentalControlsManager = GObject.registerClass({
 | 
			
		||||
    Signals: {
 | 
			
		||||
        'app-filter-changed': {},
 | 
			
		||||
    },
 | 
			
		||||
}, class ParentalControlsManager extends GObject.Object {
 | 
			
		||||
    _init() {
 | 
			
		||||
        super._init();
 | 
			
		||||
 | 
			
		||||
        this._initialized = false;
 | 
			
		||||
        this._disabled = false;
 | 
			
		||||
        this._appFilter = null;
 | 
			
		||||
 | 
			
		||||
        this._initializeManager();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async _initializeManager() {
 | 
			
		||||
        if (!HAVE_MALCONTENT) {
 | 
			
		||||
            log('Skipping parental controls support as it’s disabled');
 | 
			
		||||
            this._initialized = true;
 | 
			
		||||
            this.emit('app-filter-changed');
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        log(`Getting parental controls for user ${Shell.util_get_uid()}`);
 | 
			
		||||
        try {
 | 
			
		||||
            const connection = await Gio.DBus.get(Gio.BusType.SYSTEM, null);
 | 
			
		||||
            this._manager = new Malcontent.Manager({ connection });
 | 
			
		||||
            this._appFilter = await this._manager.get_app_filter_async(
 | 
			
		||||
                Shell.util_get_uid(),
 | 
			
		||||
                Malcontent.ManagerGetValueFlags.NONE,
 | 
			
		||||
                null);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            if (e.matches(Malcontent.ManagerError, Malcontent.ManagerError.DISABLED)) {
 | 
			
		||||
                log('Parental controls globally disabled');
 | 
			
		||||
                this._disabled = true;
 | 
			
		||||
            } else {
 | 
			
		||||
                logError(e, 'Failed to get parental controls settings');
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._manager.connect('app-filter-changed', this._onAppFilterChanged.bind(this));
 | 
			
		||||
 | 
			
		||||
        // Signal initialisation is complete.
 | 
			
		||||
        this._initialized = true;
 | 
			
		||||
        this.emit('app-filter-changed');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async _onAppFilterChanged(manager, uid) {
 | 
			
		||||
        // Emit 'changed' signal only if app-filter is changed for currently logged-in user.
 | 
			
		||||
        let currentUid = Shell.util_get_uid();
 | 
			
		||||
        if (currentUid !== uid)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            this._appFilter = await this._manager.get_app_filter_async(
 | 
			
		||||
                currentUid,
 | 
			
		||||
                Malcontent.ManagerGetValueFlags.NONE,
 | 
			
		||||
                null);
 | 
			
		||||
            this.emit('app-filter-changed');
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            // Log an error and keep the old app filter.
 | 
			
		||||
            logError(e, `Failed to get new MctAppFilter for uid ${Shell.util_get_uid()} on app-filter-changed`);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get initialized() {
 | 
			
		||||
        return this._initialized;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Calculate whether the given app (a Gio.DesktopAppInfo) should be shown
 | 
			
		||||
    // on the desktop, in search results, etc. The app should be shown if:
 | 
			
		||||
    //  - The .desktop file doesn’t say it should be hidden.
 | 
			
		||||
    //  - The executable from the .desktop file’s Exec line isn’t blacklisted in
 | 
			
		||||
    //    the user’s parental controls.
 | 
			
		||||
    //  - None of the flatpak app IDs from the X-Flatpak and the
 | 
			
		||||
    //    X-Flatpak-RenamedFrom lines are blacklisted in the user’s parental
 | 
			
		||||
    //    controls.
 | 
			
		||||
    shouldShowApp(appInfo) {
 | 
			
		||||
        // Quick decision?
 | 
			
		||||
        if (!appInfo.should_show())
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        // Are parental controls enabled (at configure time or runtime)?
 | 
			
		||||
        if (!HAVE_MALCONTENT || this._disabled)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        // Have we finished initialising yet?
 | 
			
		||||
        if (!this.initialized) {
 | 
			
		||||
            log(`Warning: Hiding app because parental controls not yet initialised: ${appInfo.get_id()}`);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this._appFilter.is_appinfo_allowed(appInfo);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine,
 | 
			
		||||
            formatTime, formatTimeSpan, createTimeLabel, insertSorted,
 | 
			
		||||
            makeCloseButton, ensureActorVisibleInScrollView, wiggle */
 | 
			
		||||
            ensureActorVisibleInScrollView, wiggle */
 | 
			
		||||
 | 
			
		||||
const { Clutter, Gio, GLib, GObject, Shell, St, GnomeDesktop } = imports.gi;
 | 
			
		||||
const { Clutter, Gio, GLib, Shell, St, GnomeDesktop } = imports.gi;
 | 
			
		||||
const Gettext = imports.gettext;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
@@ -363,51 +363,6 @@ function insertSorted(array, val, cmp) {
 | 
			
		||||
    return pos;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var CloseButton = GObject.registerClass(
 | 
			
		||||
class CloseButton extends St.Button {
 | 
			
		||||
    _init(boxpointer) {
 | 
			
		||||
        super._init({
 | 
			
		||||
            style_class: 'notification-close',
 | 
			
		||||
            x_expand: true,
 | 
			
		||||
            y_expand: true,
 | 
			
		||||
            x_align: Clutter.ActorAlign.END,
 | 
			
		||||
            y_align: Clutter.ActorAlign.START,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._boxPointer = boxpointer;
 | 
			
		||||
        if (boxpointer)
 | 
			
		||||
            this._boxPointer.connect('arrow-side-changed', this._sync.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _computeBoxPointerOffset() {
 | 
			
		||||
        if (!this._boxPointer || !this._boxPointer.get_stage())
 | 
			
		||||
            return 0;
 | 
			
		||||
 | 
			
		||||
        let side = this._boxPointer.arrowSide;
 | 
			
		||||
        if (side == St.Side.TOP)
 | 
			
		||||
            return this._boxPointer.getArrowHeight();
 | 
			
		||||
        else
 | 
			
		||||
            return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _sync() {
 | 
			
		||||
        let themeNode = this.get_theme_node();
 | 
			
		||||
 | 
			
		||||
        let offY = this._computeBoxPointerOffset();
 | 
			
		||||
        this.translation_x = themeNode.get_length('-shell-close-overlap-x');
 | 
			
		||||
        this.translation_y = themeNode.get_length('-shell-close-overlap-y') + offY;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_style_changed() {
 | 
			
		||||
        this._sync();
 | 
			
		||||
        super.vfunc_style_changed();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function makeCloseButton(boxpointer) {
 | 
			
		||||
    return new CloseButton(boxpointer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ensureActorVisibleInScrollView(scrollView, actor) {
 | 
			
		||||
    let adjustment = scrollView.vscroll.adjustment;
 | 
			
		||||
    let [value, lower_, upper, stepIncrement_, pageIncrement_, pageSize] = adjustment.get_values();
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,8 @@ const PermissionStore = imports.misc.permissionStore;
 | 
			
		||||
 | 
			
		||||
const { loadInterfaceXML } = imports.misc.fileUtils;
 | 
			
		||||
 | 
			
		||||
Gio._promisify(Geoclue.Simple, 'new', 'new_finish');
 | 
			
		||||
 | 
			
		||||
const WeatherIntegrationIface = loadInterfaceXML('org.gnome.Shell.WeatherIntegration');
 | 
			
		||||
 | 
			
		||||
const WEATHER_BUS_NAME = 'org.gnome.Weather';
 | 
			
		||||
@@ -79,16 +81,7 @@ var WeatherClient = class {
 | 
			
		||||
        this._weatherApp = null;
 | 
			
		||||
        this._weatherProxy = null;
 | 
			
		||||
 | 
			
		||||
        let nodeInfo = Gio.DBusNodeInfo.new_for_xml(WeatherIntegrationIface);
 | 
			
		||||
        Gio.DBusProxy.new(
 | 
			
		||||
            Gio.DBus.session,
 | 
			
		||||
            Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES,
 | 
			
		||||
            nodeInfo.lookup_interface(WEATHER_INTEGRATION_IFACE),
 | 
			
		||||
            WEATHER_BUS_NAME,
 | 
			
		||||
            WEATHER_OBJECT_PATH,
 | 
			
		||||
            WEATHER_INTEGRATION_IFACE,
 | 
			
		||||
            null,
 | 
			
		||||
            this._onWeatherProxyReady.bind(this));
 | 
			
		||||
        this._createWeatherProxy();
 | 
			
		||||
 | 
			
		||||
        this._settings = new Gio.Settings({
 | 
			
		||||
            schema_id: 'org.gnome.shell.weather',
 | 
			
		||||
@@ -146,9 +139,17 @@ var WeatherClient = class {
 | 
			
		||||
               (!this._needsAuth || this._weatherAuthorized);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onWeatherProxyReady(o, res) {
 | 
			
		||||
    async _createWeatherProxy() {
 | 
			
		||||
        const nodeInfo = Gio.DBusNodeInfo.new_for_xml(WeatherIntegrationIface);
 | 
			
		||||
        try {
 | 
			
		||||
            this._weatherProxy = Gio.DBusProxy.new_finish(res);
 | 
			
		||||
            this._weatherProxy = await Gio.DBusProxy.new(
 | 
			
		||||
                Gio.DBus.session,
 | 
			
		||||
                Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES,
 | 
			
		||||
                nodeInfo.lookup_interface(WEATHER_INTEGRATION_IFACE),
 | 
			
		||||
                WEATHER_BUS_NAME,
 | 
			
		||||
                WEATHER_OBJECT_PATH,
 | 
			
		||||
                WEATHER_INTEGRATION_IFACE,
 | 
			
		||||
                null);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            log(`Failed to create GNOME Weather proxy: ${e}`);
 | 
			
		||||
            return;
 | 
			
		||||
@@ -239,25 +240,23 @@ var WeatherClient = class {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _startGClueService() {
 | 
			
		||||
    async _startGClueService() {
 | 
			
		||||
        if (this._gclueStarting)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._gclueStarting = true;
 | 
			
		||||
 | 
			
		||||
        Geoclue.Simple.new('org.gnome.Shell', Geoclue.AccuracyLevel.CITY, null,
 | 
			
		||||
            (o, res) => {
 | 
			
		||||
                try {
 | 
			
		||||
                    this._gclueService = Geoclue.Simple.new_finish(res);
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
                    log(`Failed to connect to Geoclue2 service: ${e.message}`);
 | 
			
		||||
                    this._setLocation(this._mostRecentLocation);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                this._gclueStarted = true;
 | 
			
		||||
                this._gclueService.get_client().distance_threshold = 100;
 | 
			
		||||
                this._updateLocationMonitoring();
 | 
			
		||||
            });
 | 
			
		||||
        try {
 | 
			
		||||
            this._gclueService = await Geoclue.Simple.new(
 | 
			
		||||
                'org.gnome.Shell', Geoclue.AccuracyLevel.CITY, null);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            log(`Failed to connect to Geoclue2 service: ${e.message}`);
 | 
			
		||||
            this._setLocation(this._mostRecentLocation);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        this._gclueStarted = true;
 | 
			
		||||
        this._gclueService.get_client().distance_threshold = 100;
 | 
			
		||||
        this._updateLocationMonitoring();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onGClueLocationChanged() {
 | 
			
		||||
 
 | 
			
		||||
@@ -68,8 +68,8 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
 | 
			
		||||
        this._items = this._switcherList.icons;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
        super.vfunc_allocate(box, flags);
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        super.vfunc_allocate(box);
 | 
			
		||||
 | 
			
		||||
        // Allocate the thumbnails
 | 
			
		||||
        // We try to avoid overflowing the screen so we base the resulting size on
 | 
			
		||||
@@ -102,7 +102,7 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
 | 
			
		||||
            this._thumbnails.addClones(primary.y + primary.height - bottomPadding - childBox.y1);
 | 
			
		||||
            let [, childNaturalHeight] = this._thumbnails.get_preferred_height(-1);
 | 
			
		||||
            childBox.y2 = childBox.y1 + childNaturalHeight;
 | 
			
		||||
            this._thumbnails.allocate(childBox, flags);
 | 
			
		||||
            this._thumbnails.allocate(childBox);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -681,8 +681,7 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
 | 
			
		||||
            // Cache the window list now; we don't handle dynamic changes here,
 | 
			
		||||
            // and we don't want to be continually retrieving it
 | 
			
		||||
            appIcon.cachedWindows = allWindows.filter(
 | 
			
		||||
                w => windowTracker.get_window_app(w) == appIcon.app
 | 
			
		||||
            );
 | 
			
		||||
                w => windowTracker.get_window_app(w) === appIcon.app);
 | 
			
		||||
            if (appIcon.cachedWindows.length > 0)
 | 
			
		||||
                this._addIcon(appIcon);
 | 
			
		||||
        }
 | 
			
		||||
@@ -750,9 +749,9 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
 | 
			
		||||
        return super.vfunc_get_preferred_height(forWidth);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        // Allocate the main list items
 | 
			
		||||
        super.vfunc_allocate(box, flags);
 | 
			
		||||
        super.vfunc_allocate(box);
 | 
			
		||||
 | 
			
		||||
        let contentBox = this.get_theme_node().get_content_box(box);
 | 
			
		||||
 | 
			
		||||
@@ -767,7 +766,7 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
 | 
			
		||||
            childBox.x2 = childBox.x1 + arrowWidth;
 | 
			
		||||
            childBox.y1 = contentBox.y1 + itemBox.y2 + arrowHeight;
 | 
			
		||||
            childBox.y2 = childBox.y1 + arrowHeight;
 | 
			
		||||
            this._arrows[i].allocate(childBox, flags);
 | 
			
		||||
            this._arrows[i].allocate(childBox);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -853,9 +852,6 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
 | 
			
		||||
        if (index === -1)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._arrows[index].destroy();
 | 
			
		||||
        this._arrows.splice(index, 1);
 | 
			
		||||
 | 
			
		||||
        this.icons.splice(index, 1);
 | 
			
		||||
        this.removeItem(index);
 | 
			
		||||
    }
 | 
			
		||||
@@ -1060,7 +1056,7 @@ class WindowSwitcher extends SwitcherPopup.SwitcherList {
 | 
			
		||||
        return [minHeight, natHeight];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        let themeNode = this.get_theme_node();
 | 
			
		||||
        let contentBox = themeNode.get_content_box(box);
 | 
			
		||||
        const labelHeight = this._label.height;
 | 
			
		||||
@@ -1068,20 +1064,20 @@ class WindowSwitcher extends SwitcherPopup.SwitcherList {
 | 
			
		||||
            labelHeight + themeNode.get_padding(St.Side.BOTTOM);
 | 
			
		||||
 | 
			
		||||
        box.y2 -= totalLabelHeight;
 | 
			
		||||
        super.vfunc_allocate(box, flags);
 | 
			
		||||
        super.vfunc_allocate(box);
 | 
			
		||||
 | 
			
		||||
        // Hooking up the parent vfunc will call this.set_allocation() with
 | 
			
		||||
        // the height without the label height, so call it again with the
 | 
			
		||||
        // correct size here.
 | 
			
		||||
        box.y2 += totalLabelHeight;
 | 
			
		||||
        this.set_allocation(box, flags);
 | 
			
		||||
        this.set_allocation(box);
 | 
			
		||||
 | 
			
		||||
        const childBox = new Clutter.ActorBox();
 | 
			
		||||
        childBox.x1 = contentBox.x1;
 | 
			
		||||
        childBox.x2 = contentBox.x2;
 | 
			
		||||
        childBox.y2 = contentBox.y2;
 | 
			
		||||
        childBox.y1 = childBox.y2 - labelHeight;
 | 
			
		||||
        this._label.allocate(childBox, flags);
 | 
			
		||||
        this._label.allocate(childBox);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    highlight(index, justOutline) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1257
									
								
								js/ui/appDisplay.js
									
									
									
									
									
								
							
							
						
						
									
										1257
									
								
								js/ui/appDisplay.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -2,6 +2,7 @@
 | 
			
		||||
/* exported getAppFavorites */
 | 
			
		||||
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const ParentalControlsManager = imports.misc.parentalControlsManager;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
@@ -65,6 +66,13 @@ const RENAMED_DESKTOP_IDS = {
 | 
			
		||||
 | 
			
		||||
class AppFavorites {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        // Filter the apps through the user’s parental controls.
 | 
			
		||||
        this._parentalControlsManager = ParentalControlsManager.getDefault();
 | 
			
		||||
        this._parentalControlsManager.connect('app-filter-changed', () => {
 | 
			
		||||
            this.reload();
 | 
			
		||||
            this.emit('changed');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.FAVORITE_APPS_KEY = 'favorite-apps';
 | 
			
		||||
        this._favorites = {};
 | 
			
		||||
        global.settings.connect('changed::%s'.format(this.FAVORITE_APPS_KEY), this._onFavsChanged.bind(this));
 | 
			
		||||
@@ -96,7 +104,7 @@ class AppFavorites {
 | 
			
		||||
            global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
 | 
			
		||||
 | 
			
		||||
        let apps = ids.map(id => appSys.lookup_app(id))
 | 
			
		||||
                      .filter(app => app != null);
 | 
			
		||||
                      .filter(app => app !== null && this._parentalControlsManager.shouldShowApp(app.app_info));
 | 
			
		||||
        this._favorites = {};
 | 
			
		||||
        for (let i = 0; i < apps.length; i++) {
 | 
			
		||||
            let app = apps[i];
 | 
			
		||||
@@ -135,6 +143,9 @@ class AppFavorites {
 | 
			
		||||
        if (!app)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (!this._parentalControlsManager.shouldShowApp(app.app_info))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        let ids = this._getIds();
 | 
			
		||||
        if (pos == -1)
 | 
			
		||||
            ids.push(appId);
 | 
			
		||||
 
 | 
			
		||||
@@ -147,9 +147,8 @@ var AudioDeviceSelectionDBus = class AudioDeviceSelectionDBus {
 | 
			
		||||
    _onDeviceSelected(dialog, device) {
 | 
			
		||||
        let connection = this._dbusImpl.get_connection();
 | 
			
		||||
        let info = this._dbusImpl.get_info();
 | 
			
		||||
        let deviceName = Object.keys(AudioDevice).filter(
 | 
			
		||||
            dev => AudioDevice[dev] == device
 | 
			
		||||
        )[0].toLowerCase();
 | 
			
		||||
        const deviceName = Object.keys(AudioDevice)
 | 
			
		||||
            .filter(dev => AudioDevice[dev] === device)[0].toLowerCase();
 | 
			
		||||
        connection.emit_signal(this._audioSelectionDialog._sender,
 | 
			
		||||
                               this._dbusImpl.get_object_path(),
 | 
			
		||||
                               info ? info.name : null,
 | 
			
		||||
 
 | 
			
		||||
@@ -347,8 +347,6 @@ var Background = GObject.registerClass({
 | 
			
		||||
            this.set_color(color);
 | 
			
		||||
        else
 | 
			
		||||
            this.set_gradient(shadingType, color, secondColor);
 | 
			
		||||
 | 
			
		||||
        this._setLoaded();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _watchFile(file) {
 | 
			
		||||
@@ -514,8 +512,8 @@ var SystemBackground = GObject.registerClass({
 | 
			
		||||
        super._init({
 | 
			
		||||
            meta_display: global.display,
 | 
			
		||||
            monitor: 0,
 | 
			
		||||
            background: _systemBackground,
 | 
			
		||||
        });
 | 
			
		||||
        this.content.background = _systemBackground;
 | 
			
		||||
 | 
			
		||||
        let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
 | 
			
		||||
            this.emit('loaded');
 | 
			
		||||
@@ -740,6 +738,8 @@ var BackgroundManager = class BackgroundManager {
 | 
			
		||||
        let backgroundActor = new Meta.BackgroundActor({
 | 
			
		||||
            meta_display: global.display,
 | 
			
		||||
            monitor: this._monitorIndex,
 | 
			
		||||
        });
 | 
			
		||||
        backgroundActor.content.set({
 | 
			
		||||
            background,
 | 
			
		||||
            vignette: this._vignette,
 | 
			
		||||
            vignette_sharpness: 0.5,
 | 
			
		||||
@@ -760,27 +760,10 @@ var BackgroundManager = class BackgroundManager {
 | 
			
		||||
            this._updateBackgroundActor();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let loadedSignalId;
 | 
			
		||||
        if (background.isLoaded) {
 | 
			
		||||
            GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
 | 
			
		||||
                this.emit('loaded');
 | 
			
		||||
                return GLib.SOURCE_REMOVE;
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            loadedSignalId = background.connect('loaded', () => {
 | 
			
		||||
                background.disconnect(loadedSignalId);
 | 
			
		||||
                loadedSignalId = null;
 | 
			
		||||
                this.emit('loaded');
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        backgroundActor.connect('destroy', () => {
 | 
			
		||||
            if (changeSignalId)
 | 
			
		||||
                background.disconnect(changeSignalId);
 | 
			
		||||
 | 
			
		||||
            if (loadedSignalId)
 | 
			
		||||
                background.disconnect(loadedSignalId);
 | 
			
		||||
 | 
			
		||||
            if (backgroundActor.loadedSignalId)
 | 
			
		||||
                background.disconnect(backgroundActor.loadedSignalId);
 | 
			
		||||
        });
 | 
			
		||||
 
 | 
			
		||||
@@ -30,8 +30,8 @@ var BarLevel = GObject.registerClass({
 | 
			
		||||
            accessible_role: Atk.Role.LEVEL_BAR,
 | 
			
		||||
        };
 | 
			
		||||
        super._init(Object.assign(defaultParams, params));
 | 
			
		||||
        this.connect('allocation-changed', (actor, box) => {
 | 
			
		||||
            this._barLevelWidth = box.get_width();
 | 
			
		||||
        this.connect('notify::allocation', () => {
 | 
			
		||||
            this._barLevelWidth = this.allocation.get_width();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._customAccessible = St.GenericAccessible.new_for_actor(this);
 | 
			
		||||
 
 | 
			
		||||
@@ -196,13 +196,13 @@ var BoxPointer = GObject.registerClass({
 | 
			
		||||
        return themeNode.adjust_preferred_height(...height);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        if (this._sourceActor && this._sourceActor.mapped) {
 | 
			
		||||
            this._reposition(box);
 | 
			
		||||
            this._updateFlip(box);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.set_allocation(box, flags);
 | 
			
		||||
        this.set_allocation(box);
 | 
			
		||||
 | 
			
		||||
        let themeNode = this.get_theme_node();
 | 
			
		||||
        let borderWidth = themeNode.get_length('-arrow-border-width');
 | 
			
		||||
@@ -214,7 +214,7 @@ var BoxPointer = GObject.registerClass({
 | 
			
		||||
        childBox.y1 = 0;
 | 
			
		||||
        childBox.x2 = availWidth;
 | 
			
		||||
        childBox.y2 = availHeight;
 | 
			
		||||
        this._border.allocate(childBox, flags);
 | 
			
		||||
        this._border.allocate(childBox);
 | 
			
		||||
 | 
			
		||||
        childBox.x1 = borderWidth;
 | 
			
		||||
        childBox.y1 = borderWidth;
 | 
			
		||||
@@ -234,7 +234,7 @@ var BoxPointer = GObject.registerClass({
 | 
			
		||||
            childBox.x2 -= rise;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        this.bin.allocate(childBox, flags);
 | 
			
		||||
        this.bin.allocate(childBox);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _drawBorder(area) {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,6 @@ const { loadInterfaceXML } = imports.misc.fileUtils;
 | 
			
		||||
 | 
			
		||||
var MSECS_IN_DAY = 24 * 60 * 60 * 1000;
 | 
			
		||||
var SHOW_WEEKDATE_KEY = 'show-weekdate';
 | 
			
		||||
var ELLIPSIS_CHAR = '\u2026';
 | 
			
		||||
 | 
			
		||||
var MESSAGE_ICON_SIZE = -1; // pick up from CSS
 | 
			
		||||
 | 
			
		||||
@@ -32,10 +31,6 @@ function sameDay(dateA, dateB) {
 | 
			
		||||
    return sameMonth(dateA, dateB) && (dateA.getDate() == dateB.getDate());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isToday(date) {
 | 
			
		||||
    return sameDay(new Date(), date);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _isWorkDay(date) {
 | 
			
		||||
    /* Translators: Enter 0-6 (Sunday-Saturday) for non-work days. Examples: "0" (Sunday) "6" (Saturday) "06" (Sunday and Saturday). */
 | 
			
		||||
    let days = C_('calendar-no-work', "06");
 | 
			
		||||
@@ -199,51 +194,52 @@ class DBusEventSource extends EventSourceBase {
 | 
			
		||||
 | 
			
		||||
        this._initialized = false;
 | 
			
		||||
        this._dbusProxy = new CalendarServer();
 | 
			
		||||
        this._dbusProxy.init_async(GLib.PRIORITY_DEFAULT, null, (object, result) => {
 | 
			
		||||
            let loaded = false;
 | 
			
		||||
        this._initProxy();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                this._dbusProxy.init_finish(result);
 | 
			
		||||
                loaded = true;
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                if (e.matches(Gio.DBusError, Gio.DBusError.TIMED_OUT)) {
 | 
			
		||||
                    // Ignore timeouts and install signals as normal, because with high
 | 
			
		||||
                    // probability the service will appear later on, and we will get a
 | 
			
		||||
                    // NameOwnerChanged which will finish loading
 | 
			
		||||
                    //
 | 
			
		||||
                    // (But still _initialized to false, because the proxy does not know
 | 
			
		||||
                    // about the HasCalendars property and would cause an exception trying
 | 
			
		||||
                    // to read it)
 | 
			
		||||
                } else {
 | 
			
		||||
                    log('Error loading calendars: %s'.format(e.message));
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
    async _initProxy() {
 | 
			
		||||
        let loaded = false;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            await this._dbusProxy.init_async(GLib.PRIORITY_DEFAULT, null);
 | 
			
		||||
            loaded = true;
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            // Ignore timeouts and install signals as normal, because with high
 | 
			
		||||
            // probability the service will appear later on, and we will get a
 | 
			
		||||
            // NameOwnerChanged which will finish loading
 | 
			
		||||
            //
 | 
			
		||||
            // (But still _initialized to false, because the proxy does not know
 | 
			
		||||
            // about the HasCalendars property and would cause an exception trying
 | 
			
		||||
            // to read it)
 | 
			
		||||
            if (!e.matches(Gio.DBusError, Gio.DBusError.TIMED_OUT)) {
 | 
			
		||||
                log('Error loading calendars: %s'.format(e.message));
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            this._dbusProxy.connectSignal('EventsAddedOrUpdated',
 | 
			
		||||
                this._onEventsAddedOrUpdated.bind(this));
 | 
			
		||||
            this._dbusProxy.connectSignal('EventsRemoved',
 | 
			
		||||
                this._onEventsRemoved.bind(this));
 | 
			
		||||
            this._dbusProxy.connectSignal('ClientDisappeared',
 | 
			
		||||
                this._onClientDisappeared.bind(this));
 | 
			
		||||
        this._dbusProxy.connectSignal('EventsAddedOrUpdated',
 | 
			
		||||
            this._onEventsAddedOrUpdated.bind(this));
 | 
			
		||||
        this._dbusProxy.connectSignal('EventsRemoved',
 | 
			
		||||
            this._onEventsRemoved.bind(this));
 | 
			
		||||
        this._dbusProxy.connectSignal('ClientDisappeared',
 | 
			
		||||
            this._onClientDisappeared.bind(this));
 | 
			
		||||
 | 
			
		||||
            this._dbusProxy.connect('notify::g-name-owner', () => {
 | 
			
		||||
                if (this._dbusProxy.g_name_owner)
 | 
			
		||||
                    this._onNameAppeared();
 | 
			
		||||
                else
 | 
			
		||||
                    this._onNameVanished();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this._dbusProxy.connect('g-properties-changed', () => {
 | 
			
		||||
                this.notify('has-calendars');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this._initialized = loaded;
 | 
			
		||||
            if (loaded) {
 | 
			
		||||
                this.notify('has-calendars');
 | 
			
		||||
        this._dbusProxy.connect('notify::g-name-owner', () => {
 | 
			
		||||
            if (this._dbusProxy.g_name_owner)
 | 
			
		||||
                this._onNameAppeared();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                this._onNameVanished();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._dbusProxy.connect('g-properties-changed', () => {
 | 
			
		||||
            this.notify('has-calendars');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._initialized = loaded;
 | 
			
		||||
        if (loaded) {
 | 
			
		||||
            this.notify('has-calendars');
 | 
			
		||||
            this._onNameAppeared();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    destroy() {
 | 
			
		||||
@@ -722,67 +718,6 @@ var Calendar = GObject.registerClass({
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var EventMessage = GObject.registerClass(
 | 
			
		||||
class EventMessage extends MessageList.Message {
 | 
			
		||||
    _init(event, date) {
 | 
			
		||||
        super._init('', '');
 | 
			
		||||
 | 
			
		||||
        this._date = date;
 | 
			
		||||
 | 
			
		||||
        this.update(event);
 | 
			
		||||
 | 
			
		||||
        this._icon = new St.Icon({ icon_name: 'x-office-calendar-symbolic' });
 | 
			
		||||
        this.setIcon(this._icon);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_style_changed() {
 | 
			
		||||
        let iconVisible = this.get_parent().has_style_pseudo_class('first-child');
 | 
			
		||||
        this._icon.opacity = iconVisible ? 255 : 0;
 | 
			
		||||
        super.vfunc_style_changed();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    update(event) {
 | 
			
		||||
        this._event = event;
 | 
			
		||||
 | 
			
		||||
        this.setTitle(this._formatEventTime());
 | 
			
		||||
        this.setBody(event.summary);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _formatEventTime() {
 | 
			
		||||
        let periodBegin = _getBeginningOfDay(this._date);
 | 
			
		||||
        let periodEnd = _getEndOfDay(this._date);
 | 
			
		||||
        let allDay = this._event.allDay || (this._event.date <= periodBegin &&
 | 
			
		||||
                                             this._event.end >= periodEnd);
 | 
			
		||||
        let title;
 | 
			
		||||
        if (allDay) {
 | 
			
		||||
            /* Translators: Shown in calendar event list for all day events
 | 
			
		||||
             * Keep it short, best if you can use less then 10 characters
 | 
			
		||||
             */
 | 
			
		||||
            title = C_("event list time", "All Day");
 | 
			
		||||
        } else {
 | 
			
		||||
            let date = this._event.date >= periodBegin
 | 
			
		||||
                ? this._event.date
 | 
			
		||||
                : this._event.end;
 | 
			
		||||
            title = Util.formatTime(date, { timeOnly: true });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
 | 
			
		||||
        if (this._event.date < periodBegin && !this._event.allDay) {
 | 
			
		||||
            if (rtl)
 | 
			
		||||
                title = '%s%s'.format(title, ELLIPSIS_CHAR);
 | 
			
		||||
            else
 | 
			
		||||
                title = '%s%s'.format(ELLIPSIS_CHAR, title);
 | 
			
		||||
        }
 | 
			
		||||
        if (this._event.end > periodEnd && !this._event.allDay) {
 | 
			
		||||
            if (rtl)
 | 
			
		||||
                title = '%s%s'.format(ELLIPSIS_CHAR, title);
 | 
			
		||||
            else
 | 
			
		||||
                title = '%s%s'.format(title, ELLIPSIS_CHAR);
 | 
			
		||||
        }
 | 
			
		||||
        return title;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var NotificationMessage = GObject.registerClass(
 | 
			
		||||
class NotificationMessage extends MessageList.Message {
 | 
			
		||||
    _init(notification) {
 | 
			
		||||
@@ -848,149 +783,6 @@ class NotificationMessage extends MessageList.Message {
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var EventsSection = GObject.registerClass(
 | 
			
		||||
class EventsSection extends MessageList.MessageListSection {
 | 
			
		||||
    _init() {
 | 
			
		||||
        super._init();
 | 
			
		||||
 | 
			
		||||
        this._desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
 | 
			
		||||
        this._desktopSettings.connect('changed', this._reloadEvents.bind(this));
 | 
			
		||||
        this._eventSource = new EmptyEventSource();
 | 
			
		||||
 | 
			
		||||
        this._messageById = new Map();
 | 
			
		||||
 | 
			
		||||
        this._title = new St.Button({ style_class: 'events-section-title',
 | 
			
		||||
                                      label: '',
 | 
			
		||||
                                      can_focus: true });
 | 
			
		||||
        this._title.child.x_align = Clutter.ActorAlign.START;
 | 
			
		||||
        this.insert_child_below(this._title, null);
 | 
			
		||||
 | 
			
		||||
        this._title.connect('clicked', this._onTitleClicked.bind(this));
 | 
			
		||||
        this._title.connect('key-focus-in', this._onKeyFocusIn.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._appSys = Shell.AppSystem.get_default();
 | 
			
		||||
        this._appSys.connect('installed-changed',
 | 
			
		||||
            this._appInstalledChanged.bind(this));
 | 
			
		||||
        this._appInstalledChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setEventSource(eventSource) {
 | 
			
		||||
        if (!(eventSource instanceof EventSourceBase))
 | 
			
		||||
            throw new Error('Event source is not valid type');
 | 
			
		||||
 | 
			
		||||
        this._eventSource = eventSource;
 | 
			
		||||
        this._eventSource.connect('changed', this._reloadEvents.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get allowed() {
 | 
			
		||||
        return Main.sessionMode.showCalendarEvents;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateTitle() {
 | 
			
		||||
        this._title.visible = !isToday(this._date);
 | 
			
		||||
 | 
			
		||||
        if (!this._title.visible)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let dayFormat;
 | 
			
		||||
        let now = new Date();
 | 
			
		||||
        if (sameYear(this._date, now)) {
 | 
			
		||||
            /* Translators: Shown on calendar heading when selected day occurs on current year */
 | 
			
		||||
            dayFormat = Shell.util_translate_time_string(NC_("calendar heading", "%A, %B %-d"));
 | 
			
		||||
        } else {
 | 
			
		||||
            /* Translators: Shown on calendar heading when selected day occurs on different year */
 | 
			
		||||
            dayFormat = Shell.util_translate_time_string(NC_("calendar heading", "%A, %B %-d, %Y"));
 | 
			
		||||
        }
 | 
			
		||||
        this._title.label = this._date.toLocaleFormat(dayFormat);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _reloadEvents() {
 | 
			
		||||
        if (this._eventSource.isLoading || this._reloading)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._reloading = true;
 | 
			
		||||
 | 
			
		||||
        let periodBegin = _getBeginningOfDay(this._date);
 | 
			
		||||
        let periodEnd = _getEndOfDay(this._date);
 | 
			
		||||
        let events = this._eventSource.getEvents(periodBegin, periodEnd);
 | 
			
		||||
 | 
			
		||||
        let ids = events.map(e => e.id);
 | 
			
		||||
        this._messageById.forEach((message, id) => {
 | 
			
		||||
            if (ids.includes(id))
 | 
			
		||||
                return;
 | 
			
		||||
            this._messageById.delete(id);
 | 
			
		||||
            this.removeMessage(message);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < events.length; i++) {
 | 
			
		||||
            let event = events[i];
 | 
			
		||||
 | 
			
		||||
            let message = this._messageById.get(event.id);
 | 
			
		||||
            if (!message) {
 | 
			
		||||
                message = new EventMessage(event, this._date);
 | 
			
		||||
                this._messageById.set(event.id, message);
 | 
			
		||||
                this.addMessage(message, false);
 | 
			
		||||
            } else {
 | 
			
		||||
                message.update(event);
 | 
			
		||||
                this.moveMessage(message, i, false);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._reloading = false;
 | 
			
		||||
        this._sync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _appInstalledChanged() {
 | 
			
		||||
        this._calendarApp = undefined;
 | 
			
		||||
        this._title.reactive = this._getCalendarApp() != null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _getCalendarApp() {
 | 
			
		||||
        if (this._calendarApp !== undefined)
 | 
			
		||||
            return this._calendarApp;
 | 
			
		||||
 | 
			
		||||
        let apps = Gio.AppInfo.get_recommended_for_type('text/calendar');
 | 
			
		||||
        if (apps && (apps.length > 0)) {
 | 
			
		||||
            let app = Gio.AppInfo.get_default_for_type('text/calendar', false);
 | 
			
		||||
            let defaultInRecommended = apps.some(a => a.equal(app));
 | 
			
		||||
            this._calendarApp = defaultInRecommended ? app : apps[0];
 | 
			
		||||
        } else {
 | 
			
		||||
            this._calendarApp = null;
 | 
			
		||||
        }
 | 
			
		||||
        return this._calendarApp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onTitleClicked() {
 | 
			
		||||
        Main.overview.hide();
 | 
			
		||||
        Main.panel.closeCalendar();
 | 
			
		||||
 | 
			
		||||
        let appInfo = this._getCalendarApp();
 | 
			
		||||
        if (appInfo.get_id() === 'org.gnome.Evolution.desktop') {
 | 
			
		||||
            let app = this._appSys.lookup_app('evolution-calendar.desktop');
 | 
			
		||||
            if (app)
 | 
			
		||||
                appInfo = app.app_info;
 | 
			
		||||
        }
 | 
			
		||||
        appInfo.launch([], global.create_app_launch_context(0, -1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setDate(date) {
 | 
			
		||||
        super.setDate(date);
 | 
			
		||||
        this._updateTitle();
 | 
			
		||||
        this._reloadEvents();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _shouldShow() {
 | 
			
		||||
        return !this.empty || !isToday(this._date);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _sync() {
 | 
			
		||||
        if (this._reloading)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        super._sync();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var TimeLabel = GObject.registerClass(
 | 
			
		||||
class NotificationTimeLabel extends St.Label {
 | 
			
		||||
    _init(datetime) {
 | 
			
		||||
@@ -1087,10 +879,6 @@ class NotificationSection extends MessageList.MessageListSection {
 | 
			
		||||
        });
 | 
			
		||||
        super.vfunc_map();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _shouldShow() {
 | 
			
		||||
        return !this.empty && isToday(this._date);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var Placeholder = GObject.registerClass(
 | 
			
		||||
@@ -1099,41 +887,13 @@ class Placeholder extends St.BoxLayout {
 | 
			
		||||
        super._init({ style_class: 'message-list-placeholder', vertical: true });
 | 
			
		||||
        this._date = new Date();
 | 
			
		||||
 | 
			
		||||
        let todayFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/no-notifications.svg');
 | 
			
		||||
        let otherFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/no-events.svg');
 | 
			
		||||
        this._todayIcon = new Gio.FileIcon({ file: todayFile });
 | 
			
		||||
        this._otherIcon = new Gio.FileIcon({ file: otherFile });
 | 
			
		||||
 | 
			
		||||
        this._icon = new St.Icon();
 | 
			
		||||
        const file = Gio.File.new_for_uri(
 | 
			
		||||
            'resource:///org/gnome/shell/theme/no-notifications.svg');
 | 
			
		||||
        this._icon = new St.Icon({ gicon: new Gio.FileIcon({ file }) });
 | 
			
		||||
        this.add_actor(this._icon);
 | 
			
		||||
 | 
			
		||||
        this._label = new St.Label();
 | 
			
		||||
        this._label = new St.Label({ text: _('No Notifications') });
 | 
			
		||||
        this.add_actor(this._label);
 | 
			
		||||
 | 
			
		||||
        this._sync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setDate(date) {
 | 
			
		||||
        if (sameDay(this._date, date))
 | 
			
		||||
            return;
 | 
			
		||||
        this._date = date;
 | 
			
		||||
        this._sync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _sync() {
 | 
			
		||||
        let today = isToday(this._date);
 | 
			
		||||
        if (today && this._icon.gicon == this._todayIcon)
 | 
			
		||||
            return;
 | 
			
		||||
        if (!today && this._icon.gicon == this._otherIcon)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (today) {
 | 
			
		||||
            this._icon.gicon = this._todayIcon;
 | 
			
		||||
            this._label.text = _("No Notifications");
 | 
			
		||||
        } else {
 | 
			
		||||
            this._icon.gicon = this._otherIcon;
 | 
			
		||||
            this._label.text = _("No Events");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -1234,9 +994,6 @@ class CalendarMessageList extends St.Widget {
 | 
			
		||||
        this._notificationSection = new NotificationSection();
 | 
			
		||||
        this._addSection(this._notificationSection);
 | 
			
		||||
 | 
			
		||||
        this._eventsSection = new EventsSection();
 | 
			
		||||
        this._addSection(this._eventsSection);
 | 
			
		||||
 | 
			
		||||
        Main.sessionMode.connect('updated', this._sync.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1272,13 +1029,4 @@ class CalendarMessageList extends St.Widget {
 | 
			
		||||
        let canClear = sections.some(s => s.canClear && s.visible);
 | 
			
		||||
        this._clearButton.reactive = canClear;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setEventSource(eventSource) {
 | 
			
		||||
        this._eventsSection.setEventSource(eventSource);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setDate(date) {
 | 
			
		||||
        this._sectionList.get_children().forEach(s => s.setDate(date));
 | 
			
		||||
        this._placeholder.setDate(date);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -13,17 +13,13 @@ var ComponentManager = class {
 | 
			
		||||
    _sessionUpdated() {
 | 
			
		||||
        let newEnabledComponents = Main.sessionMode.components;
 | 
			
		||||
 | 
			
		||||
        newEnabledComponents.filter(
 | 
			
		||||
            name => !this._enabledComponents.includes(name)
 | 
			
		||||
        ).forEach(name => {
 | 
			
		||||
            this._enableComponent(name);
 | 
			
		||||
        });
 | 
			
		||||
        newEnabledComponents
 | 
			
		||||
            .filter(name => !this._enabledComponents.includes(name))
 | 
			
		||||
            .forEach(name => this._enableComponent(name));
 | 
			
		||||
 | 
			
		||||
        this._enabledComponents.filter(
 | 
			
		||||
            name => !newEnabledComponents.includes(name)
 | 
			
		||||
        ).forEach(name => {
 | 
			
		||||
            this._disableComponent(name);
 | 
			
		||||
        });
 | 
			
		||||
        this._enabledComponents
 | 
			
		||||
            .filter(name => !newEnabledComponents.includes(name))
 | 
			
		||||
            .forEach(name => this._disableComponent(name));
 | 
			
		||||
 | 
			
		||||
        this._enabledComponents = newEnabledComponents;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -125,8 +125,7 @@ var ContentTypeDiscoverer = class {
 | 
			
		||||
    _emitCallback(mount, contentTypes = []) {
 | 
			
		||||
        // we're not interested in win32 software content types here
 | 
			
		||||
        contentTypes = contentTypes.filter(
 | 
			
		||||
            type => type != 'x-content/win32-software'
 | 
			
		||||
        );
 | 
			
		||||
            type => type !== 'x-content/win32-software');
 | 
			
		||||
 | 
			
		||||
        let apps = [];
 | 
			
		||||
        contentTypes.forEach(type => {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ const MessageTray = imports.ui.messageTray;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const ShellEntry = imports.ui.shellEntry;
 | 
			
		||||
 | 
			
		||||
Gio._promisify(Shell.NetworkAgent.prototype, 'init_async', 'init_finish');
 | 
			
		||||
Gio._promisify(Shell.NetworkAgent.prototype,
 | 
			
		||||
    'search_vpn_plugin', 'search_vpn_plugin_finish');
 | 
			
		||||
 | 
			
		||||
@@ -482,39 +483,37 @@ var VPNRequestHandler = class {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _readStdoutOldStyle() {
 | 
			
		||||
        this._dataStdout.read_line_async(GLib.PRIORITY_DEFAULT, null, (stream, result) => {
 | 
			
		||||
            let [line, len_] = this._dataStdout.read_line_finish_utf8(result);
 | 
			
		||||
    async _readStdoutOldStyle() {
 | 
			
		||||
        const [line, len_] =
 | 
			
		||||
            await this._dataStdout.read_line_async(GLib.PRIORITY_DEFAULT, null);
 | 
			
		||||
 | 
			
		||||
            if (line == null) {
 | 
			
		||||
                // end of file
 | 
			
		||||
                this._stdout.close(null);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        if (line === null) {
 | 
			
		||||
            // end of file
 | 
			
		||||
            this._stdout.close(null);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            this._vpnChildProcessLineOldStyle(line);
 | 
			
		||||
        this._vpnChildProcessLineOldStyle(line);
 | 
			
		||||
 | 
			
		||||
            // try to read more!
 | 
			
		||||
            this._readStdoutOldStyle();
 | 
			
		||||
        });
 | 
			
		||||
        // try to read more!
 | 
			
		||||
        this._readStdoutOldStyle();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _readStdoutNewStyle() {
 | 
			
		||||
        this._dataStdout.fill_async(-1, GLib.PRIORITY_DEFAULT, null, (stream, result) => {
 | 
			
		||||
            let cnt = this._dataStdout.fill_finish(result);
 | 
			
		||||
    async _readStdoutNewStyle() {
 | 
			
		||||
        const cnt =
 | 
			
		||||
            await this._dataStdout.fill_async(-1, GLib.PRIORITY_DEFAULT, null);
 | 
			
		||||
 | 
			
		||||
            if (cnt == 0) {
 | 
			
		||||
                // end of file
 | 
			
		||||
                this._showNewStyleDialog();
 | 
			
		||||
        if (cnt === 0) {
 | 
			
		||||
            // end of file
 | 
			
		||||
            this._showNewStyleDialog();
 | 
			
		||||
 | 
			
		||||
                this._stdout.close(null);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            this._stdout.close(null);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            // Try to read more
 | 
			
		||||
            this._dataStdout.set_buffer_size(2 * this._dataStdout.get_buffer_size());
 | 
			
		||||
            this._readStdoutNewStyle();
 | 
			
		||||
        });
 | 
			
		||||
        // Try to read more
 | 
			
		||||
        this._dataStdout.set_buffer_size(2 * this._dataStdout.get_buffer_size());
 | 
			
		||||
        this._readStdoutNewStyle();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _showNewStyleDialog() {
 | 
			
		||||
@@ -621,15 +620,17 @@ var NetworkAgent = class {
 | 
			
		||||
        this._native.connect('cancel-request', this._cancelRequest.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._initialized = false;
 | 
			
		||||
        this._native.init_async(GLib.PRIORITY_DEFAULT, null, (o, res) => {
 | 
			
		||||
            try {
 | 
			
		||||
                this._native.init_finish(res);
 | 
			
		||||
                this._initialized = true;
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                this._native = null;
 | 
			
		||||
                logError(e, 'error initializing the NetworkManager Agent');
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        this._initNative();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async _initNative() {
 | 
			
		||||
        try {
 | 
			
		||||
            await this._native.init_async(GLib.PRIORITY_DEFAULT, null);
 | 
			
		||||
            this._initialized = true;
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            this._native = null;
 | 
			
		||||
            logError(e, 'error initializing the NetworkManager Agent');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enable() {
 | 
			
		||||
 
 | 
			
		||||
@@ -330,11 +330,13 @@ var AuthenticationDialog = GObject.registerClass({
 | 
			
		||||
            this._sessionRequestTimeoutId = 0;
 | 
			
		||||
 | 
			
		||||
            if (this.state != ModalDialog.State.OPENED)
 | 
			
		||||
                return;
 | 
			
		||||
                return GLib.SOURCE_REMOVE;
 | 
			
		||||
 | 
			
		||||
            this._passwordEntry.hide();
 | 
			
		||||
            this._cancelButton.grab_key_focus();
 | 
			
		||||
            this._okButton.reactive = false;
 | 
			
		||||
 | 
			
		||||
            return GLib.SOURCE_REMOVE;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if (delay) {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,14 @@ var Tpl = null;
 | 
			
		||||
var Tp = null;
 | 
			
		||||
try {
 | 
			
		||||
    ({ TelepathyGLib: Tp, TelepathyLogger: Tpl } = imports.gi);
 | 
			
		||||
 | 
			
		||||
    Gio._promisify(Tp.Channel.prototype, 'close_async', 'close_finish');
 | 
			
		||||
    Gio._promisify(Tp.Channel.prototype,
 | 
			
		||||
        'send_message_async', 'send_message_finish');
 | 
			
		||||
    Gio._promisify(Tp.ChannelDispatchOperation.prototype,
 | 
			
		||||
        'claim_with_async', 'claim_with_finish');
 | 
			
		||||
    Gio._promisify(Tpl.LogManager.prototype,
 | 
			
		||||
        'get_filtered_events_async', 'get_filtered_events_finish');
 | 
			
		||||
} catch (e) {
 | 
			
		||||
    log('Telepathy is not available, chat integration will be disabled.');
 | 
			
		||||
}
 | 
			
		||||
@@ -215,7 +223,7 @@ class TelepathyClient extends Tp.BaseClient {
 | 
			
		||||
 | 
			
		||||
            // We can only handle text channel, so close any other channel
 | 
			
		||||
            if (!(channel instanceof Tp.TextChannel)) {
 | 
			
		||||
                channel.close_async(null);
 | 
			
		||||
                channel.close_async();
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -261,7 +269,7 @@ class TelepathyClient extends Tp.BaseClient {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _approveTextChannel(account, conn, channel, dispatchOp, context) {
 | 
			
		||||
    async _approveTextChannel(account, conn, channel, dispatchOp, context) {
 | 
			
		||||
        let [targetHandle_, targetHandleType] = channel.get_handle();
 | 
			
		||||
 | 
			
		||||
        if (targetHandleType != Tp.HandleType.CONTACT) {
 | 
			
		||||
@@ -270,17 +278,15 @@ class TelepathyClient extends Tp.BaseClient {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Approve private text channels right away as we are going to handle it
 | 
			
		||||
        dispatchOp.claim_with_async(this, (o, result) => {
 | 
			
		||||
            try {
 | 
			
		||||
                dispatchOp.claim_with_finish(result);
 | 
			
		||||
                this._handlingChannels(account, conn, [channel], false);
 | 
			
		||||
            } catch (err) {
 | 
			
		||||
                log('Failed to Claim channel: %s'.format(err.toString()));
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        context.accept();
 | 
			
		||||
 | 
			
		||||
        // Approve private text channels right away as we are going to handle it
 | 
			
		||||
        try {
 | 
			
		||||
            await dispatchOp.claim_with_async(this);
 | 
			
		||||
            this._handlingChannels(account, conn, [channel], false);
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
            log('Failed to Claim channel: %s'.format(err.toString()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _delegatedChannelsCb(_client, _channels) {
 | 
			
		||||
@@ -441,17 +447,14 @@ class ChatSource extends MessageTray.Source {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _getLogMessages() {
 | 
			
		||||
    async _getLogMessages() {
 | 
			
		||||
        let logManager = Tpl.LogManager.dup_singleton();
 | 
			
		||||
        let entity = Tpl.Entity.new_from_tp_contact(this._contact, Tpl.EntityType.CONTACT);
 | 
			
		||||
 | 
			
		||||
        logManager.get_filtered_events_async(this._account, entity,
 | 
			
		||||
                                             Tpl.EventTypeMask.TEXT, SCROLLBACK_HISTORY_LINES,
 | 
			
		||||
                                             null, this._displayPendingMessages.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _displayPendingMessages(logManager, result) {
 | 
			
		||||
        let [success_, events] = logManager.get_filtered_events_finish(result);
 | 
			
		||||
        const [events] = await logManager.get_filtered_events_async(
 | 
			
		||||
            this._account, entity,
 | 
			
		||||
            Tpl.EventTypeMask.TEXT, SCROLLBACK_HISTORY_LINES,
 | 
			
		||||
            null);
 | 
			
		||||
 | 
			
		||||
        let logMessages = events.map(e => ChatMessage.newFromTplTextEvent(e));
 | 
			
		||||
        this._ensureNotification();
 | 
			
		||||
@@ -509,9 +512,7 @@ class ChatSource extends MessageTray.Source {
 | 
			
		||||
            this._ackMessages();
 | 
			
		||||
            // The chat box has been destroyed so it can't
 | 
			
		||||
            // handle the channel any more.
 | 
			
		||||
            this._channel.close_async((channel, result) => {
 | 
			
		||||
                channel.close_finish(result);
 | 
			
		||||
            });
 | 
			
		||||
            this._channel.close_async();
 | 
			
		||||
        } else {
 | 
			
		||||
            // Don't indicate any unread messages when the notification
 | 
			
		||||
            // that represents them has been destroyed.
 | 
			
		||||
@@ -609,9 +610,7 @@ class ChatSource extends MessageTray.Source {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let msg = Tp.ClientMessage.new_text(type, text);
 | 
			
		||||
        this._channel.send_message_async(msg, 0, (src, result) => {
 | 
			
		||||
            this._channel.send_message_finish(result);
 | 
			
		||||
        });
 | 
			
		||||
        this._channel.send_message_async(msg, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setChatState(state) {
 | 
			
		||||
 
 | 
			
		||||
@@ -292,11 +292,11 @@ class DashActor extends St.Widget {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        let contentBox = this.get_theme_node().get_content_box(box);
 | 
			
		||||
        let availWidth = contentBox.x2 - contentBox.x1;
 | 
			
		||||
 | 
			
		||||
        this.set_allocation(box, flags);
 | 
			
		||||
        this.set_allocation(box);
 | 
			
		||||
 | 
			
		||||
        let [appIcons, showAppsButton] = this.get_children();
 | 
			
		||||
        let [, showAppsNatHeight] = showAppsButton.get_preferred_height(availWidth);
 | 
			
		||||
@@ -306,11 +306,11 @@ class DashActor extends St.Widget {
 | 
			
		||||
        childBox.y1 = contentBox.y1;
 | 
			
		||||
        childBox.x2 = contentBox.x2;
 | 
			
		||||
        childBox.y2 = contentBox.y2 - showAppsNatHeight;
 | 
			
		||||
        appIcons.allocate(childBox, flags);
 | 
			
		||||
        appIcons.allocate(childBox);
 | 
			
		||||
 | 
			
		||||
        childBox.y1 = contentBox.y2 - showAppsNatHeight;
 | 
			
		||||
        childBox.y2 = contentBox.y2;
 | 
			
		||||
        showAppsButton.allocate(childBox, flags);
 | 
			
		||||
        showAppsButton.allocate(childBox);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_height(forWidth) {
 | 
			
		||||
@@ -815,7 +815,12 @@ var Dash = GObject.registerClass({
 | 
			
		||||
        else
 | 
			
		||||
            pos = 0; // always insert at the top when dash is empty
 | 
			
		||||
 | 
			
		||||
        if (pos != this._dragPlaceholderPos && pos <= numFavorites && this._animatingPlaceholdersCount == 0) {
 | 
			
		||||
        // Put the placeholder after the last favorite if we are not
 | 
			
		||||
        // in the favorites zone
 | 
			
		||||
        if (pos > numFavorites)
 | 
			
		||||
            pos = numFavorites;
 | 
			
		||||
 | 
			
		||||
        if (pos !== this._dragPlaceholderPos && this._animatingPlaceholdersCount === 0) {
 | 
			
		||||
            this._dragPlaceholderPos = pos;
 | 
			
		||||
 | 
			
		||||
            // Don't allow positioning before or after self
 | 
			
		||||
@@ -843,11 +848,6 @@ var Dash = GObject.registerClass({
 | 
			
		||||
            this._dragPlaceholder.show(fadeIn);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Remove the drag placeholder if we are not in the
 | 
			
		||||
        // "favorites zone"
 | 
			
		||||
        if (pos > numFavorites)
 | 
			
		||||
            this._clearDragPlaceholder();
 | 
			
		||||
 | 
			
		||||
        if (!this._dragPlaceholder)
 | 
			
		||||
            return DND.DragMotionResult.NO_DROP;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,11 @@ const System = imports.system;
 | 
			
		||||
 | 
			
		||||
const { loadInterfaceXML } = imports.misc.fileUtils;
 | 
			
		||||
 | 
			
		||||
const NC_ = (context, str) => '%s\u0004%s'.format(context, str);
 | 
			
		||||
const T_ = Shell.util_translate_time_string;
 | 
			
		||||
 | 
			
		||||
const MAX_FORECASTS = 5;
 | 
			
		||||
const ELLIPSIS_CHAR = '\u2026';
 | 
			
		||||
 | 
			
		||||
const ClocksIntegrationIface = loadInterfaceXML('org.gnome.Shell.ClocksIntegration');
 | 
			
		||||
const ClocksProxy = Gio.DBusProxy.makeProxyWrapper(ClocksIntegrationIface);
 | 
			
		||||
@@ -84,6 +88,188 @@ class TodayButton extends St.Button {
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var EventsSection = GObject.registerClass(
 | 
			
		||||
class EventsSection extends St.Button {
 | 
			
		||||
    _init() {
 | 
			
		||||
        super._init({
 | 
			
		||||
            style_class: 'events-button',
 | 
			
		||||
            can_focus: true,
 | 
			
		||||
            x_expand: true,
 | 
			
		||||
            child: new St.BoxLayout({
 | 
			
		||||
                style_class: 'events-box',
 | 
			
		||||
                vertical: true,
 | 
			
		||||
                x_expand: true,
 | 
			
		||||
            }),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._startDate = null;
 | 
			
		||||
        this._endDate = null;
 | 
			
		||||
 | 
			
		||||
        this._eventSource = null;
 | 
			
		||||
        this._calendarApp = null;
 | 
			
		||||
 | 
			
		||||
        this._title = new St.Label({
 | 
			
		||||
            style_class: 'events-title',
 | 
			
		||||
        });
 | 
			
		||||
        this.child.add_child(this._title);
 | 
			
		||||
 | 
			
		||||
        this._eventsList = new St.BoxLayout({
 | 
			
		||||
            style_class: 'events-list',
 | 
			
		||||
            vertical: true,
 | 
			
		||||
            x_expand: true,
 | 
			
		||||
        });
 | 
			
		||||
        this.child.add_child(this._eventsList);
 | 
			
		||||
 | 
			
		||||
        this._appSys = Shell.AppSystem.get_default();
 | 
			
		||||
        this._appSys.connect('installed-changed',
 | 
			
		||||
            this._appInstalledChanged.bind(this));
 | 
			
		||||
        this._appInstalledChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setDate(date) {
 | 
			
		||||
        const day = [date.getFullYear(), date.getMonth(), date.getDate()];
 | 
			
		||||
        this._startDate = new Date(...day);
 | 
			
		||||
        this._endDate = new Date(...day, 23, 59, 59, 999);
 | 
			
		||||
 | 
			
		||||
        this._updateTitle();
 | 
			
		||||
        this._reloadEvents();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setEventSource(eventSource) {
 | 
			
		||||
        if (!(eventSource instanceof Calendar.EventSourceBase))
 | 
			
		||||
            throw new Error('Event source is not valid type');
 | 
			
		||||
 | 
			
		||||
        this._eventSource = eventSource;
 | 
			
		||||
        this._eventSource.connect('changed', this._reloadEvents.bind(this));
 | 
			
		||||
        this._eventSource.connect('notify::has-calendars',
 | 
			
		||||
            this._sync.bind(this));
 | 
			
		||||
        this._sync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateTitle() {
 | 
			
		||||
        /* Translators: Shown on calendar heading when selected day occurs on current year */
 | 
			
		||||
        const sameYearFormat = T_(NC_('calendar heading', '%B %-d'));
 | 
			
		||||
 | 
			
		||||
        /* Translators: Shown on calendar heading when selected day occurs on different year */
 | 
			
		||||
        const otherYearFormat = T_(NC_('calendar heading', '%B %-d %Y'));
 | 
			
		||||
 | 
			
		||||
        const timeSpanDay = GLib.TIME_SPAN_DAY / 1000;
 | 
			
		||||
        const now = new Date();
 | 
			
		||||
 | 
			
		||||
        if (this._startDate <= now && now <= this._endDate)
 | 
			
		||||
            this._title.text = _('Today');
 | 
			
		||||
        else if (this._endDate < now && now - this._endDate < timeSpanDay)
 | 
			
		||||
            this._title.text = _('Yesterday');
 | 
			
		||||
        else if (this._startDate > now && this._startDate - now < timeSpanDay)
 | 
			
		||||
            this._title.text = _('Tomorrow');
 | 
			
		||||
        else if (this._startDate.getFullYear() === now.getFullYear())
 | 
			
		||||
            this._title.text = this._startDate.toLocaleFormat(sameYearFormat);
 | 
			
		||||
        else
 | 
			
		||||
            this._title.text = this._startDate.toLocaleFormat(otherYearFormat);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _formatEventTime(event) {
 | 
			
		||||
        const allDay = event.allDay ||
 | 
			
		||||
            (event.date <= this._startDate && event.end >= this._endDate);
 | 
			
		||||
 | 
			
		||||
        let title;
 | 
			
		||||
        if (allDay) {
 | 
			
		||||
            /* Translators: Shown in calendar event list for all day events
 | 
			
		||||
             * Keep it short, best if you can use less then 10 characters
 | 
			
		||||
             */
 | 
			
		||||
            title = C_('event list time', 'All Day');
 | 
			
		||||
        } else {
 | 
			
		||||
            let date = event.date >= this._startDate ? event.date : event.end;
 | 
			
		||||
            title = Util.formatTime(date, { timeOnly: true });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const rtl = Clutter.get_default_text_direction() === Clutter.TextDirection.RTL;
 | 
			
		||||
        if (event.date < this._startDate && !event.allDay) {
 | 
			
		||||
            if (rtl)
 | 
			
		||||
                title = '%s%s'.format(title, ELLIPSIS_CHAR);
 | 
			
		||||
            else
 | 
			
		||||
                title = '%s%s'.format(ELLIPSIS_CHAR, title);
 | 
			
		||||
        }
 | 
			
		||||
        if (event.end > this._endDate && !event.allDay) {
 | 
			
		||||
            if (rtl)
 | 
			
		||||
                title = '%s%s'.format(ELLIPSIS_CHAR, title);
 | 
			
		||||
            else
 | 
			
		||||
                title = '%s%s'.format(title, ELLIPSIS_CHAR);
 | 
			
		||||
        }
 | 
			
		||||
        return title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _reloadEvents() {
 | 
			
		||||
        if (this._eventSource.isLoading || this._reloading)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._reloading = true;
 | 
			
		||||
 | 
			
		||||
        [...this._eventsList].forEach(c => c.destroy());
 | 
			
		||||
 | 
			
		||||
        const events =
 | 
			
		||||
            this._eventSource.getEvents(this._startDate, this._endDate);
 | 
			
		||||
 | 
			
		||||
        for (let event of events) {
 | 
			
		||||
            const box = new St.BoxLayout({
 | 
			
		||||
                style_class: 'event-box',
 | 
			
		||||
                vertical: true,
 | 
			
		||||
            });
 | 
			
		||||
            box.add(new St.Label({
 | 
			
		||||
                text: event.summary,
 | 
			
		||||
                style_class: 'event-summary',
 | 
			
		||||
            }));
 | 
			
		||||
            box.add(new St.Label({
 | 
			
		||||
                text: this._formatEventTime(event),
 | 
			
		||||
                style_class: 'event-time',
 | 
			
		||||
            }));
 | 
			
		||||
            this._eventsList.add_child(box);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._eventsList.get_n_children() === 0) {
 | 
			
		||||
            const placeholder = new St.Label({
 | 
			
		||||
                text: _('No Events'),
 | 
			
		||||
                style_class: 'event-placeholder',
 | 
			
		||||
            });
 | 
			
		||||
            this._eventsList.add_child(placeholder);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._reloading = false;
 | 
			
		||||
        this._sync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_clicked() {
 | 
			
		||||
        Main.overview.hide();
 | 
			
		||||
        Main.panel.closeCalendar();
 | 
			
		||||
 | 
			
		||||
        let appInfo = this._calendarApp;
 | 
			
		||||
        if (appInfo.get_id() === 'org.gnome.Evolution.desktop') {
 | 
			
		||||
            const app = this._appSys.lookup_app('evolution-calendar.desktop');
 | 
			
		||||
            if (app)
 | 
			
		||||
                appInfo = app.app_info;
 | 
			
		||||
        }
 | 
			
		||||
        appInfo.launch([], global.create_app_launch_context(0, -1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _appInstalledChanged() {
 | 
			
		||||
        const apps = Gio.AppInfo.get_recommended_for_type('text/calendar');
 | 
			
		||||
        if (apps && (apps.length > 0)) {
 | 
			
		||||
            const app = Gio.AppInfo.get_default_for_type('text/calendar', false);
 | 
			
		||||
            const defaultInRecommended = apps.some(a => a.equal(app));
 | 
			
		||||
            this._calendarApp = defaultInRecommended ? app : apps[0];
 | 
			
		||||
        } else {
 | 
			
		||||
            this._calendarApp = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this._sync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _sync() {
 | 
			
		||||
        this.visible = this._eventSource && this._eventSource.hasCalendars;
 | 
			
		||||
        this.reactive = this._calendarApp !== null;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var WorldClocksSection = GObject.registerClass(
 | 
			
		||||
class WorldClocksSection extends St.Button {
 | 
			
		||||
    _init() {
 | 
			
		||||
@@ -300,13 +486,13 @@ class WeatherSection extends St.Button {
 | 
			
		||||
        this.child = box;
 | 
			
		||||
 | 
			
		||||
        let titleBox = new St.BoxLayout({ style_class: 'weather-header-box' });
 | 
			
		||||
        titleBox.add_child(new St.Label({
 | 
			
		||||
        this._titleLabel = new St.Label({
 | 
			
		||||
            style_class: 'weather-header',
 | 
			
		||||
            x_align: Clutter.ActorAlign.START,
 | 
			
		||||
            x_expand: true,
 | 
			
		||||
            y_align: Clutter.ActorAlign.END,
 | 
			
		||||
            text: _('Weather'),
 | 
			
		||||
        }));
 | 
			
		||||
        });
 | 
			
		||||
        titleBox.add_child(this._titleLabel);
 | 
			
		||||
        box.add_child(titleBox);
 | 
			
		||||
 | 
			
		||||
        this._titleLocation = new St.Label({
 | 
			
		||||
@@ -433,10 +619,8 @@ class WeatherSection extends St.Button {
 | 
			
		||||
    _updateForecasts() {
 | 
			
		||||
        this._forecastGrid.destroy_all_children();
 | 
			
		||||
 | 
			
		||||
        if (!this._weatherClient.hasLocation) {
 | 
			
		||||
            this._setStatusLabel(_("Select a location…"));
 | 
			
		||||
        if (!this._weatherClient.hasLocation)
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const { info } = this._weatherClient;
 | 
			
		||||
        this._titleLocation.text = this._findBestLocationName(info.location);
 | 
			
		||||
@@ -463,6 +647,12 @@ class WeatherSection extends St.Button {
 | 
			
		||||
        if (!this.visible)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (this._weatherClient.hasLocation)
 | 
			
		||||
            this._titleLabel.text = _('Weather');
 | 
			
		||||
        else
 | 
			
		||||
            this._titleLabel.text = _('Select weather location…');
 | 
			
		||||
 | 
			
		||||
        this._forecastGrid.visible = this._weatherClient.hasLocation;
 | 
			
		||||
        this._titleLocation.visible = this._weatherClient.hasLocation;
 | 
			
		||||
 | 
			
		||||
        this._updateForecasts();
 | 
			
		||||
@@ -561,8 +751,8 @@ class FreezableBinLayout extends Clutter.BinLayout {
 | 
			
		||||
        return this._savedHeight;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(container, allocation, flags) {
 | 
			
		||||
        super.vfunc_allocate(container, allocation, flags);
 | 
			
		||||
    vfunc_allocate(container, allocation) {
 | 
			
		||||
        super.vfunc_allocate(container, allocation);
 | 
			
		||||
 | 
			
		||||
        let [width, height] = allocation.get_size();
 | 
			
		||||
        this._savedWidth = [width, width];
 | 
			
		||||
@@ -594,7 +784,6 @@ class DateMenuButton extends PanelMenu.Button {
 | 
			
		||||
 | 
			
		||||
        this._clockDisplay = new St.Label({ style_class: 'clock' });
 | 
			
		||||
        this._clockDisplay.clutter_text.y_align = Clutter.ActorAlign.CENTER;
 | 
			
		||||
        this._clockDisplay.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
 | 
			
		||||
 | 
			
		||||
        this._indicator = new MessagesIndicator();
 | 
			
		||||
 | 
			
		||||
@@ -629,7 +818,7 @@ class DateMenuButton extends PanelMenu.Button {
 | 
			
		||||
        this._calendar.connect('selected-date-changed', (_calendar, datetime) => {
 | 
			
		||||
            let date = _gDateTimeToDate(datetime);
 | 
			
		||||
            layout.frozen = !_isToday(date);
 | 
			
		||||
            this._messageList.setDate(date);
 | 
			
		||||
            this._eventsItem.setDate(date);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.menu.connect('open-state-changed', (menu, isOpen) => {
 | 
			
		||||
@@ -638,7 +827,7 @@ class DateMenuButton extends PanelMenu.Button {
 | 
			
		||||
                let now = new Date();
 | 
			
		||||
                this._calendar.setDate(now);
 | 
			
		||||
                this._date.setDate(now);
 | 
			
		||||
                this._messageList.setDate(now);
 | 
			
		||||
                this._eventsItem.setDate(now);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@@ -669,6 +858,9 @@ class DateMenuButton extends PanelMenu.Button {
 | 
			
		||||
                                             style_class: 'datemenu-displays-box' });
 | 
			
		||||
        this._displaysSection.add_actor(displaysBox);
 | 
			
		||||
 | 
			
		||||
        this._eventsItem = new EventsSection();
 | 
			
		||||
        displaysBox.add_child(this._eventsItem);
 | 
			
		||||
 | 
			
		||||
        this._clocksItem = new WorldClocksSection();
 | 
			
		||||
        displaysBox.add_child(this._clocksItem);
 | 
			
		||||
 | 
			
		||||
@@ -694,7 +886,7 @@ class DateMenuButton extends PanelMenu.Button {
 | 
			
		||||
            this._eventSource.destroy();
 | 
			
		||||
 | 
			
		||||
        this._calendar.setEventSource(eventSource);
 | 
			
		||||
        this._messageList.setEventSource(eventSource);
 | 
			
		||||
        this._eventsItem.setEventSource(eventSource);
 | 
			
		||||
 | 
			
		||||
        this._eventSource = eventSource;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/* exported Dialog, MessageDialogContent, ListSection, ListSectionItem */
 | 
			
		||||
 | 
			
		||||
const { Clutter, GLib, GObject, Meta, Pango, St } = imports.gi;
 | 
			
		||||
const { Clutter, GObject, Meta, Pango, St } = imports.gi;
 | 
			
		||||
 | 
			
		||||
function _setLabel(label, value) {
 | 
			
		||||
    label.set({
 | 
			
		||||
@@ -221,16 +221,13 @@ var MessageDialogContent = GObject.registerClass({
 | 
			
		||||
            this._updateTitleStyleLater = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
 | 
			
		||||
                this._updateTitleStyleLater = 0;
 | 
			
		||||
                this._title.add_style_class_name('leightweight');
 | 
			
		||||
                return GLib.SOURCE_REMOVE;
 | 
			
		||||
                return false;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set title(title) {
 | 
			
		||||
        if (this._title.text === title)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        _setLabel(this._title, title);
 | 
			
		||||
 | 
			
		||||
        this._title.remove_style_class_name('leightweight');
 | 
			
		||||
@@ -240,9 +237,6 @@ var MessageDialogContent = GObject.registerClass({
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set description(description) {
 | 
			
		||||
        if (this._description.text === description)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        _setLabel(this._description, description);
 | 
			
		||||
        this.notify('description');
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										44
									
								
								js/ui/dnd.js
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								js/ui/dnd.js
									
									
									
									
									
								
							@@ -375,19 +375,30 @@ var _Draggable = class _Draggable {
 | 
			
		||||
 | 
			
		||||
            this._dragActorSource = undefined;
 | 
			
		||||
            this._dragOrigParent = this.actor.get_parent();
 | 
			
		||||
            this._dragOrigX = this._dragActor.x;
 | 
			
		||||
            this._dragOrigY = this._dragActor.y;
 | 
			
		||||
            this._dragActorHadFixedPos = this._dragActor.fixed_position_set;
 | 
			
		||||
            this._dragOrigX = this._dragActor.allocation.x1;
 | 
			
		||||
            this._dragOrigY = this._dragActor.allocation.y1;
 | 
			
		||||
            this._dragOrigWidth = this._dragActor.allocation.get_width();
 | 
			
		||||
            this._dragOrigHeight = this._dragActor.allocation.get_height();
 | 
			
		||||
            this._dragOrigScale = this._dragActor.scale_x;
 | 
			
		||||
 | 
			
		||||
            // When the actor gets reparented to the uiGroup, it will be
 | 
			
		||||
            // allocated its preferred size, so use that size instead of the
 | 
			
		||||
            // current allocation size.
 | 
			
		||||
            const [, newAllocatedWidth] = this._dragActor.get_preferred_width(-1);
 | 
			
		||||
            const [, newAllocatedHeight] = this._dragActor.get_preferred_height(-1);
 | 
			
		||||
 | 
			
		||||
            const transformedAllocation =
 | 
			
		||||
                Shell.util_get_transformed_allocation(this._dragActor);
 | 
			
		||||
 | 
			
		||||
            // Set the actor's scale such that it will keep the same
 | 
			
		||||
            // transformed size when it's reparented to the uiGroup
 | 
			
		||||
            let [scaledWidth, scaledHeight] = this.actor.get_transformed_size();
 | 
			
		||||
            this._dragActor.set_scale(scaledWidth / this.actor.width,
 | 
			
		||||
                                      scaledHeight / this.actor.height);
 | 
			
		||||
            this._dragActor.set_scale(
 | 
			
		||||
                transformedAllocation.get_width() / newAllocatedWidth,
 | 
			
		||||
                transformedAllocation.get_height() / newAllocatedHeight);
 | 
			
		||||
 | 
			
		||||
            let [actorStageX, actorStageY] = this.actor.get_transformed_position();
 | 
			
		||||
            this._dragOffsetX = actorStageX - this._dragStartX;
 | 
			
		||||
            this._dragOffsetY = actorStageY - this._dragStartY;
 | 
			
		||||
            this._dragOffsetX = transformedAllocation.x1 - this._dragStartX;
 | 
			
		||||
            this._dragOffsetY = transformedAllocation.y1 - this._dragStartY;
 | 
			
		||||
 | 
			
		||||
            this._dragOrigParent.remove_actor(this._dragActor);
 | 
			
		||||
            Main.uiGroup.add_child(this._dragActor);
 | 
			
		||||
@@ -417,6 +428,10 @@ var _Draggable = class _Draggable {
 | 
			
		||||
        this._dragOffsetX -= transX;
 | 
			
		||||
        this._dragOffsetY -= transY;
 | 
			
		||||
 | 
			
		||||
        this._dragActor.set_position(
 | 
			
		||||
            this._dragX + this._dragOffsetX,
 | 
			
		||||
            this._dragY + this._dragOffsetY);
 | 
			
		||||
 | 
			
		||||
        if (this._dragActorMaxSize != undefined) {
 | 
			
		||||
            let [scaledWidth, scaledHeight] = this._dragActor.get_transformed_size();
 | 
			
		||||
            let currentSize = Math.max(scaledWidth, scaledHeight);
 | 
			
		||||
@@ -635,9 +650,15 @@ var _Draggable = class _Draggable {
 | 
			
		||||
            if (parentWidth != 0)
 | 
			
		||||
                parentScale = parentScaledWidth / parentWidth;
 | 
			
		||||
 | 
			
		||||
            // Also adjust for the difference in the original actor width
 | 
			
		||||
            // and the width it is now (children of uiGroup always get
 | 
			
		||||
            // allocated their preferred size)
 | 
			
		||||
            const childScaleX =
 | 
			
		||||
                this._dragOrigWidth / this._dragActor.allocation.get_width();
 | 
			
		||||
 | 
			
		||||
            x = parentX + parentScale * this._dragOrigX;
 | 
			
		||||
            y = parentY + parentScale * this._dragOrigY;
 | 
			
		||||
            scale = this._dragOrigScale * parentScale;
 | 
			
		||||
            scale = this._dragOrigScale * parentScale * childScaleX;
 | 
			
		||||
        } else {
 | 
			
		||||
            // Snap back actor to its original stage position
 | 
			
		||||
            x = this._snapBackX;
 | 
			
		||||
@@ -718,7 +739,10 @@ var _Draggable = class _Draggable {
 | 
			
		||||
            Main.uiGroup.remove_child(this._dragActor);
 | 
			
		||||
            this._dragOrigParent.add_actor(this._dragActor);
 | 
			
		||||
            dragActor.set_scale(this._dragOrigScale, this._dragOrigScale);
 | 
			
		||||
            dragActor.set_position(this._dragOrigX, this._dragOrigY);
 | 
			
		||||
            if (this._dragActorHadFixedPos)
 | 
			
		||||
                dragActor.set_position(this._dragOrigX, this._dragOrigY);
 | 
			
		||||
            else
 | 
			
		||||
                dragActor.fixed_position_set = false;
 | 
			
		||||
        } else {
 | 
			
		||||
            dragActor.destroy();
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -278,7 +278,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
 | 
			
		||||
        this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onPkOfflineProxyCreated(proxy, error) {
 | 
			
		||||
    async _onPkOfflineProxyCreated(proxy, error) {
 | 
			
		||||
        if (error) {
 | 
			
		||||
            log(error.message);
 | 
			
		||||
            return;
 | 
			
		||||
@@ -293,15 +293,12 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // It only makes sense to check for this permission if PackageKit is available.
 | 
			
		||||
        Polkit.Permission.new(
 | 
			
		||||
            'org.freedesktop.packagekit.trigger-offline-update', null, null,
 | 
			
		||||
            (source, res) => {
 | 
			
		||||
                try {
 | 
			
		||||
                    this._updatesPermission = Polkit.Permission.new_finish(res);
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
                    log('No permission to trigger offline updates: %s'.format(e.toString()));
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        try {
 | 
			
		||||
            this._updatesPermission = await Polkit.Permission.new(
 | 
			
		||||
                'org.freedesktop.packagekit.trigger-offline-update', null, null);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            log('No permission to trigger offline updates: %s'.format(e.toString()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDestroy() {
 | 
			
		||||
@@ -680,7 +677,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
 | 
			
		||||
 | 
			
		||||
        _setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText || '');
 | 
			
		||||
        this._checkBox.visible = dialogContent.checkBoxText && updatePrepared && updatesAllowed;
 | 
			
		||||
        this._checkBox.checked = updatePrepared && updateTriggered;
 | 
			
		||||
        this._checkBox.checked = this._checkBox.visible;
 | 
			
		||||
 | 
			
		||||
        // We show the warning either together with the checkbox, or when
 | 
			
		||||
        // updates have already been triggered, but the user doesn't have
 | 
			
		||||
 
 | 
			
		||||
@@ -10,11 +10,20 @@ imports.gi.versions.Gtk = '3.0';
 | 
			
		||||
imports.gi.versions.TelepathyGLib = '0.12';
 | 
			
		||||
imports.gi.versions.TelepathyLogger = '0.2';
 | 
			
		||||
 | 
			
		||||
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
 | 
			
		||||
const { Clutter, Gio, GLib, GObject, Meta, Polkit, Shell, St } = imports.gi;
 | 
			
		||||
const Gettext = imports.gettext;
 | 
			
		||||
const System = imports.system;
 | 
			
		||||
 | 
			
		||||
Gio._promisify(Gio.DataInputStream.prototype, 'fill_async', 'fill_finish');
 | 
			
		||||
Gio._promisify(Gio.DataInputStream.prototype,
 | 
			
		||||
    'read_line_async', 'read_line_finish');
 | 
			
		||||
Gio._promisify(Gio.DBus, 'get', 'get_finish');
 | 
			
		||||
Gio._promisify(Gio.DBusConnection.prototype, 'call', 'call_finish');
 | 
			
		||||
Gio._promisify(Gio.DBusProxy, 'new', 'new_finish');
 | 
			
		||||
Gio._promisify(Gio.DBusProxy.prototype, 'init_async', 'init_finish');
 | 
			
		||||
Gio._promisify(Gio.DBusProxy.prototype,
 | 
			
		||||
    'call_with_unix_fd_list', 'call_with_unix_fd_list_finish');
 | 
			
		||||
Gio._promisify(Polkit.Permission, 'new', 'new_finish');
 | 
			
		||||
 | 
			
		||||
let _localTimeZone = null;
 | 
			
		||||
 | 
			
		||||
@@ -236,16 +245,15 @@ function _loggingFunc(...args) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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();
 | 
			
		||||
    // Add some bindings to the global JS namespace
 | 
			
		||||
    globalThis.global = Shell.Global.get();
 | 
			
		||||
 | 
			
		||||
    window.log = _loggingFunc;
 | 
			
		||||
    globalThis.log = _loggingFunc;
 | 
			
		||||
 | 
			
		||||
    window._ = Gettext.gettext;
 | 
			
		||||
    window.C_ = Gettext.pgettext;
 | 
			
		||||
    window.ngettext = Gettext.ngettext;
 | 
			
		||||
    window.N_ = s => s;
 | 
			
		||||
    globalThis._ = Gettext.gettext;
 | 
			
		||||
    globalThis.C_ = Gettext.pgettext;
 | 
			
		||||
    globalThis.ngettext = Gettext.ngettext;
 | 
			
		||||
    globalThis.N_ = s => s;
 | 
			
		||||
 | 
			
		||||
    GObject.gtypeNameBasedOnJSPath = true;
 | 
			
		||||
 | 
			
		||||
@@ -277,6 +285,11 @@ function init() {
 | 
			
		||||
        _easeActorProperty(this, 'value', target, params);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Clutter.Actor.prototype[Symbol.iterator] = function* () {
 | 
			
		||||
        for (let c = this.get_first_child(); c; c = c.get_next_sibling())
 | 
			
		||||
            yield c;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Clutter.Actor.prototype.toString = function () {
 | 
			
		||||
        return St.describe_actor(this);
 | 
			
		||||
    };
 | 
			
		||||
@@ -347,10 +360,12 @@ function init() {
 | 
			
		||||
 | 
			
		||||
    // OK, now things are initialized enough that we can import shell JS
 | 
			
		||||
    const Format = imports.format;
 | 
			
		||||
    const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
    Tweener.init();
 | 
			
		||||
    String.prototype.format = Format.format;
 | 
			
		||||
 | 
			
		||||
    Math.clamp = function (x, lower, upper) {
 | 
			
		||||
        return Math.min(Math.max(x, lower), upper);
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// adjustAnimationTime:
 | 
			
		||||
 
 | 
			
		||||
@@ -139,9 +139,7 @@ function checkForUpdates() {
 | 
			
		||||
            return;
 | 
			
		||||
        if (extension.hasUpdate)
 | 
			
		||||
            return;
 | 
			
		||||
        metadatas[uuid] = {
 | 
			
		||||
            version: extension.metadata.version,
 | 
			
		||||
        };
 | 
			
		||||
        metadatas[uuid] = extension.metadata;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (Object.keys(metadatas).length === 0)
 | 
			
		||||
 
 | 
			
		||||
@@ -230,8 +230,7 @@ var ExtensionManager = class {
 | 
			
		||||
            null,
 | 
			
		||||
            Gio.DBusCallFlags.NONE,
 | 
			
		||||
            -1,
 | 
			
		||||
            null,
 | 
			
		||||
            (conn, res) => conn.call_finish(res));
 | 
			
		||||
            null);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -261,7 +260,8 @@ var ExtensionManager = class {
 | 
			
		||||
        if (!extension)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let message = error.toString();
 | 
			
		||||
        const message = error instanceof Error
 | 
			
		||||
            ? error.message : error.toString();
 | 
			
		||||
 | 
			
		||||
        extension.error = message;
 | 
			
		||||
        extension.state = ExtensionState.ERROR;
 | 
			
		||||
@@ -486,19 +486,15 @@ var ExtensionManager = class {
 | 
			
		||||
 | 
			
		||||
        // Find and enable all the newly enabled extensions: UUIDs found in the
 | 
			
		||||
        // new setting, but not in the old one.
 | 
			
		||||
        newEnabledExtensions.filter(
 | 
			
		||||
            uuid => !this._enabledExtensions.includes(uuid)
 | 
			
		||||
        ).forEach(uuid => {
 | 
			
		||||
            this._callExtensionEnable(uuid);
 | 
			
		||||
        });
 | 
			
		||||
        newEnabledExtensions
 | 
			
		||||
            .filter(uuid => !this._enabledExtensions.includes(uuid))
 | 
			
		||||
            .forEach(uuid => this._callExtensionEnable(uuid));
 | 
			
		||||
 | 
			
		||||
        // Find and disable all the newly disabled extensions: UUIDs found in the
 | 
			
		||||
        // old setting, but not in the new one.
 | 
			
		||||
        this._extensionOrder.filter(
 | 
			
		||||
            uuid => !newEnabledExtensions.includes(uuid)
 | 
			
		||||
        ).reverse().forEach(uuid => {
 | 
			
		||||
            this._callExtensionDisable(uuid);
 | 
			
		||||
        });
 | 
			
		||||
        this._extensionOrder
 | 
			
		||||
            .filter(uuid => !newEnabledExtensions.includes(uuid))
 | 
			
		||||
            .reverse().forEach(uuid => this._callExtensionDisable(uuid));
 | 
			
		||||
 | 
			
		||||
        this._enabledExtensions = newEnabledExtensions;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1802
									
								
								js/ui/iconGrid.js
									
									
									
									
									
								
							
							
						
						
									
										1802
									
								
								js/ui/iconGrid.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,5 +1,5 @@
 | 
			
		||||
/* exported InhibitShortcutsDialog */
 | 
			
		||||
const { Clutter, Gio, GLib, GObject, Gtk, Meta, Pango, Shell, St } = imports.gi;
 | 
			
		||||
const { Clutter, Gio, GLib, GObject, Gtk, Meta, Shell, St } = imports.gi;
 | 
			
		||||
 | 
			
		||||
const Dialog = imports.ui.dialog;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
@@ -90,8 +90,6 @@ var InhibitShortcutsDialog = GObject.registerClass({
 | 
			
		||||
                text: _('You can restore shortcuts by pressing %s.').format(restoreAccel),
 | 
			
		||||
                style_class: 'message-dialog-description',
 | 
			
		||||
            });
 | 
			
		||||
            restoreLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
 | 
			
		||||
            restoreLabel.clutter_text.line_wrap = true;
 | 
			
		||||
            content.add_child(restoreLabel);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,7 @@ const defaultKeysPost = [
 | 
			
		||||
    [[{ width: 1.5, keyval: Clutter.KEY_BackSpace, icon: 'edit-clear-symbolic' }],
 | 
			
		||||
     [{ width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key', icon: 'keyboard-enter-symbolic' }],
 | 
			
		||||
     [{ label: '=/<', width: 3, level: 3, right: true }],
 | 
			
		||||
     [{ action: 'emoji', icon: 'face-smile-symbolic' }, { action: 'languageMenu', extraClassName: 'layout-key', icon: 'keyboard-layout-filled-symbolic' }, { action: 'hide', extraClassName: 'hide-key', icon: 'go-down-symbolic' }]],
 | 
			
		||||
     [{ action: 'emoji', icon: 'face-smile-symbolic' }, { action: 'languageMenu', extraClassName: 'layout-key' }, { action: 'hide', extraClassName: 'hide-key' }]],
 | 
			
		||||
    [[{ width: 1.5, keyval: Clutter.KEY_BackSpace, icon: 'edit-clear-symbolic' }],
 | 
			
		||||
     [{ width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key', icon: 'keyboard-enter-symbolic' }],
 | 
			
		||||
     [{ label: '?123', width: 3, level: 2, right: true }],
 | 
			
		||||
@@ -61,25 +61,7 @@ class AspectContainer extends St.Widget {
 | 
			
		||||
        this.queue_relayout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_width(forHeight) {
 | 
			
		||||
        let [min, nat] = super.vfunc_get_preferred_width(forHeight);
 | 
			
		||||
 | 
			
		||||
        if (forHeight > 0)
 | 
			
		||||
            nat = forHeight * this._ratio;
 | 
			
		||||
 | 
			
		||||
        return [min, nat];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_height(forWidth) {
 | 
			
		||||
        let [min, nat] = super.vfunc_get_preferred_height(forWidth);
 | 
			
		||||
 | 
			
		||||
        if (forWidth > 0)
 | 
			
		||||
            nat = forWidth / this._ratio;
 | 
			
		||||
 | 
			
		||||
        return [min, nat];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        if (box.get_width() > 0 && box.get_height() > 0) {
 | 
			
		||||
            let sizeRatio = box.get_width() / box.get_height();
 | 
			
		||||
 | 
			
		||||
@@ -97,7 +79,7 @@ class AspectContainer extends St.Widget {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        super.vfunc_allocate(box, flags);
 | 
			
		||||
        super.vfunc_allocate(box);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -740,7 +722,7 @@ var EmojiPager = GObject.registerClass({
 | 
			
		||||
 | 
			
		||||
    _onPan(action) {
 | 
			
		||||
        let [dist_, dx, dy_] = action.get_motion_delta(0);
 | 
			
		||||
        this.delta = this.delta + dx;
 | 
			
		||||
        this.delta += dx;
 | 
			
		||||
 | 
			
		||||
        if (this._currentKey != null) {
 | 
			
		||||
            this._currentKey.cancel();
 | 
			
		||||
@@ -953,8 +935,7 @@ var EmojiSelection = GObject.registerClass({
 | 
			
		||||
        this.add_child(this._emojiPager);
 | 
			
		||||
 | 
			
		||||
        this._pageIndicator = new PageIndicators.PageIndicators(
 | 
			
		||||
            Clutter.Orientation.HORIZONTAL
 | 
			
		||||
        );
 | 
			
		||||
            Clutter.Orientation.HORIZONTAL);
 | 
			
		||||
        this.add_child(this._pageIndicator);
 | 
			
		||||
        this._pageIndicator.setReactive(false);
 | 
			
		||||
 | 
			
		||||
@@ -1092,8 +1073,8 @@ var Keypad = GObject.registerClass({
 | 
			
		||||
            { label: '8', keyval: Clutter.KEY_8, left: 1, top: 2 },
 | 
			
		||||
            { label: '9', keyval: Clutter.KEY_9, left: 2, top: 2 },
 | 
			
		||||
            { label: '0', keyval: Clutter.KEY_0, left: 1, top: 3 },
 | 
			
		||||
            { keyval: Clutter.KEY_BackSpace, icon: 'edit-clear-symbolic', left: 3, top: 0 },
 | 
			
		||||
            { keyval: Clutter.KEY_Return, extraClassName: 'enter-key', icon: 'keyboard-enter-symbolic', left: 3, top: 1, height: 2 },
 | 
			
		||||
            { label: '⌫', keyval: Clutter.KEY_BackSpace, left: 3, top: 0 },
 | 
			
		||||
            { keyval: Clutter.KEY_Return, extraClassName: 'enter-key', left: 3, top: 1, height: 2 },
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        super._init({
 | 
			
		||||
@@ -1110,7 +1091,7 @@ var Keypad = GObject.registerClass({
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < keys.length; i++) {
 | 
			
		||||
            let cur = keys[i];
 | 
			
		||||
            let key = new Key(cur.label || "", [], cur.icon);
 | 
			
		||||
            let key = new Key(cur.label || "", []);
 | 
			
		||||
 | 
			
		||||
            if (keys[i].extraClassName)
 | 
			
		||||
                key.keyButton.add_style_class_name(cur.extraClassName);
 | 
			
		||||
@@ -1137,7 +1118,7 @@ var KeyboardManager = class KeyBoardManager {
 | 
			
		||||
        this._seat.connect('notify::touch-mode', this._syncEnabled.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._lastDevice = null;
 | 
			
		||||
        Meta.get_backend().connect('last-device-changed', (backend, device) => {
 | 
			
		||||
        global.backend.connect('last-device-changed', (backend, device) => {
 | 
			
		||||
            if (device.device_type === Clutter.InputDeviceType.KEYBOARD_DEVICE)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
@@ -1627,9 +1608,7 @@ class Keyboard extends St.BoxLayout {
 | 
			
		||||
             * we allow the OSK being smaller than 1/3rd of the monitor height
 | 
			
		||||
             * there.
 | 
			
		||||
             */
 | 
			
		||||
            const forWidth = this.get_theme_node().adjust_for_width(monitor.width);
 | 
			
		||||
            const [, natHeight] = this.get_preferred_height(forWidth);
 | 
			
		||||
            this.height = Math.min(maxHeight, natHeight);
 | 
			
		||||
            this.height = Math.min(maxHeight, this.get_preferred_height(monitor.width));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -246,7 +246,7 @@ var LayoutManager = GObject.registerClass({
 | 
			
		||||
                                           vertical: true });
 | 
			
		||||
        this.addChrome(this.panelBox, { affectsStruts: true,
 | 
			
		||||
                                        trackFullscreen: true });
 | 
			
		||||
        this.panelBox.connect('allocation-changed',
 | 
			
		||||
        this.panelBox.connect('notify::allocation',
 | 
			
		||||
                              this._panelBoxChanged.bind(this));
 | 
			
		||||
 | 
			
		||||
        this.modalDialogGroup = new St.Widget({ name: 'modalDialogGroup',
 | 
			
		||||
@@ -470,15 +470,6 @@ var LayoutManager = GObject.registerClass({
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _waitLoaded(bgManager) {
 | 
			
		||||
        return new Promise(resolve => {
 | 
			
		||||
            const id = bgManager.connect('loaded', () => {
 | 
			
		||||
                bgManager.disconnect(id);
 | 
			
		||||
                resolve();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateBackgrounds() {
 | 
			
		||||
        for (let i = 0; i < this._bgManagers.length; i++)
 | 
			
		||||
            this._bgManagers[i].destroy();
 | 
			
		||||
@@ -486,7 +477,7 @@ var LayoutManager = GObject.registerClass({
 | 
			
		||||
        this._bgManagers = [];
 | 
			
		||||
 | 
			
		||||
        if (Main.sessionMode.isGreeter)
 | 
			
		||||
            return Promise.resolve();
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this.monitors.length; i++) {
 | 
			
		||||
            let bgManager = this._createBackgroundManager(i);
 | 
			
		||||
@@ -495,8 +486,6 @@ var LayoutManager = GObject.registerClass({
 | 
			
		||||
            if (i != this.primaryIndex && this._startingUp)
 | 
			
		||||
                bgManager.backgroundActor.hide();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return Promise.all(this._bgManagers.map(this._waitLoaded));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateKeyboardBox() {
 | 
			
		||||
@@ -655,7 +644,7 @@ var LayoutManager = GObject.registerClass({
 | 
			
		||||
    // When starting a normal user session, we want to grow it out of the middle
 | 
			
		||||
    // of the screen.
 | 
			
		||||
 | 
			
		||||
    async _prepareStartupAnimation() {
 | 
			
		||||
    _prepareStartupAnimation() {
 | 
			
		||||
        // During the initial transition, add a simple actor to block all events,
 | 
			
		||||
        // so they don't get delivered to X11 windows that have been transformed.
 | 
			
		||||
        this._coverPane = new Clutter.Actor({ opacity: 0,
 | 
			
		||||
@@ -672,6 +661,8 @@ var LayoutManager = GObject.registerClass({
 | 
			
		||||
        } else if (Main.sessionMode.isGreeter) {
 | 
			
		||||
            this.panelBox.translation_y = -this.panelBox.height;
 | 
			
		||||
        } else {
 | 
			
		||||
            this._updateBackgrounds();
 | 
			
		||||
 | 
			
		||||
            // We need to force an update of the regions now before we scale
 | 
			
		||||
            // the UI group to get the correct allocation for the struts.
 | 
			
		||||
            this._updateRegions();
 | 
			
		||||
@@ -687,8 +678,6 @@ var LayoutManager = GObject.registerClass({
 | 
			
		||||
            this.uiGroup.scale_x = this.uiGroup.scale_y = 0.75;
 | 
			
		||||
            this.uiGroup.opacity = 0;
 | 
			
		||||
            global.window_group.set_clip(monitor.x, monitor.y, monitor.width, monitor.height);
 | 
			
		||||
 | 
			
		||||
            await this._updateBackgrounds();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.emit('startup-prepared');
 | 
			
		||||
@@ -1240,9 +1229,8 @@ class HotCorner extends Clutter.Actor {
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (Main.overview.shouldToggleByCornerOrButton()) {
 | 
			
		||||
            this._ripples.playAnimation(this._x, this._y);
 | 
			
		||||
            Main.overview.toggle();
 | 
			
		||||
            if (Main.overview.animationInProgress)
 | 
			
		||||
                this._ripples.playAnimation(this._x, this._y);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -27,13 +27,11 @@ var RadialShaderEffect = GObject.registerClass({
 | 
			
		||||
        'brightness': GObject.ParamSpec.float(
 | 
			
		||||
            'brightness', 'brightness', 'brightness',
 | 
			
		||||
            GObject.ParamFlags.READWRITE,
 | 
			
		||||
            0, 1, 1
 | 
			
		||||
        ),
 | 
			
		||||
            0, 1, 1),
 | 
			
		||||
        'sharpness': GObject.ParamSpec.float(
 | 
			
		||||
            'sharpness', 'sharpness', 'sharpness',
 | 
			
		||||
            GObject.ParamFlags.READWRITE,
 | 
			
		||||
            0, 1, 0
 | 
			
		||||
        ),
 | 
			
		||||
            0, 1, 0),
 | 
			
		||||
    },
 | 
			
		||||
}, class RadialShaderEffect extends Shell.GLSLEffect {
 | 
			
		||||
    _init(params) {
 | 
			
		||||
 
 | 
			
		||||
@@ -37,10 +37,9 @@ const LG_ANIMATION_TIME = 500;
 | 
			
		||||
 | 
			
		||||
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(
 | 
			
		||||
        a => a.charAt(0) != '_'
 | 
			
		||||
    );
 | 
			
		||||
    // Don't add the private properties of globalThis (i.e., ones starting with '_')
 | 
			
		||||
    const windowProperties = Object.getOwnPropertyNames(globalThis).filter(
 | 
			
		||||
        a => a.charAt(0) !== '_');
 | 
			
		||||
    const headerProperties = JsParse.getDeclaredConstants(commandHeader);
 | 
			
		||||
 | 
			
		||||
    return keywords.concat(windowProperties).concat(headerProperties);
 | 
			
		||||
@@ -555,8 +554,8 @@ var Inspector = GObject.registerClass({
 | 
			
		||||
        this._lookingGlass = lookingGlass;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
        this.set_allocation(box, flags);
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        this.set_allocation(box);
 | 
			
		||||
 | 
			
		||||
        if (!this._eventHandler)
 | 
			
		||||
            return;
 | 
			
		||||
@@ -571,7 +570,7 @@ var Inspector = GObject.registerClass({
 | 
			
		||||
        childBox.x2 = childBox.x1 + natWidth;
 | 
			
		||||
        childBox.y1 = primary.y + Math.floor((primary.height - natHeight) / 2);
 | 
			
		||||
        childBox.y2 = childBox.y1 + natHeight;
 | 
			
		||||
        this._eventHandler.allocate(childBox, flags);
 | 
			
		||||
        this._eventHandler.allocate(childBox);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _close() {
 | 
			
		||||
@@ -803,6 +802,191 @@ var Extensions = GObject.registerClass({
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var ActorLink = GObject.registerClass({
 | 
			
		||||
    Signals: {
 | 
			
		||||
        'inspect-actor': {},
 | 
			
		||||
    },
 | 
			
		||||
}, class ActorLink extends St.Button {
 | 
			
		||||
    _init(actor) {
 | 
			
		||||
        this._arrow = new St.Icon({
 | 
			
		||||
            icon_name: 'pan-end-symbolic',
 | 
			
		||||
            icon_size: 8,
 | 
			
		||||
            x_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
            y_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
            pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        const label = new St.Label({
 | 
			
		||||
            text: actor.toString(),
 | 
			
		||||
            x_align: Clutter.ActorAlign.START,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        const inspectButton = new St.Button({
 | 
			
		||||
            child: new St.Icon({
 | 
			
		||||
                icon_name: 'insert-object-symbolic',
 | 
			
		||||
                icon_size: 12,
 | 
			
		||||
                y_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
            }),
 | 
			
		||||
            reactive: true,
 | 
			
		||||
            x_expand: true,
 | 
			
		||||
            x_align: Clutter.ActorAlign.START,
 | 
			
		||||
            y_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
        });
 | 
			
		||||
        inspectButton.connect('clicked', () => this.emit('inspect-actor'));
 | 
			
		||||
 | 
			
		||||
        const box = new St.BoxLayout();
 | 
			
		||||
        box.add_child(this._arrow);
 | 
			
		||||
        box.add_child(label);
 | 
			
		||||
        box.add_child(inspectButton);
 | 
			
		||||
 | 
			
		||||
        super._init({
 | 
			
		||||
            reactive: true,
 | 
			
		||||
            track_hover: true,
 | 
			
		||||
            toggle_mode: true,
 | 
			
		||||
            style_class: 'actor-link',
 | 
			
		||||
            child: box,
 | 
			
		||||
            x_align: Clutter.ActorAlign.START,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._actor = actor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_clicked() {
 | 
			
		||||
        this._arrow.ease({
 | 
			
		||||
            rotation_angle_z: this.checked ? 90 : 0,
 | 
			
		||||
            duration: 250,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var ActorTreeViewer = GObject.registerClass(
 | 
			
		||||
class ActorTreeViewer extends St.BoxLayout {
 | 
			
		||||
    _init(lookingGlass) {
 | 
			
		||||
        super._init();
 | 
			
		||||
 | 
			
		||||
        this._lookingGlass = lookingGlass;
 | 
			
		||||
        this._actorData = new Map();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _showActorChildren(actor) {
 | 
			
		||||
        const data = this._actorData.get(actor);
 | 
			
		||||
        if (!data || data.visible)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        data.visible = true;
 | 
			
		||||
        data.actorAddedId = actor.connect('actor-added', (container, child) => {
 | 
			
		||||
            this._addActor(data.children, child);
 | 
			
		||||
        });
 | 
			
		||||
        data.actorRemovedId = actor.connect('actor-removed', (container, child) => {
 | 
			
		||||
            this._removeActor(child);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        for (let child of actor)
 | 
			
		||||
            this._addActor(data.children, child);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _hideActorChildren(actor) {
 | 
			
		||||
        const data = this._actorData.get(actor);
 | 
			
		||||
        if (!data || !data.visible)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        for (let child of actor)
 | 
			
		||||
            this._removeActor(child);
 | 
			
		||||
 | 
			
		||||
        data.visible = false;
 | 
			
		||||
        if (data.actorAddedId > 0) {
 | 
			
		||||
            actor.disconnect(data.actorAddedId);
 | 
			
		||||
            data.actorAddedId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (data.actorRemovedId > 0) {
 | 
			
		||||
            actor.disconnect(data.actorRemovedId);
 | 
			
		||||
            data.actorRemovedId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        data.children.remove_all_children();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _addActor(container, actor) {
 | 
			
		||||
        if (this._actorData.has(actor))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (actor === this._lookingGlass)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        const button = new ActorLink(actor);
 | 
			
		||||
        button.connect('notify::checked', () => {
 | 
			
		||||
            this._lookingGlass.setBorderPaintTarget(actor);
 | 
			
		||||
            if (button.checked)
 | 
			
		||||
                this._showActorChildren(actor);
 | 
			
		||||
            else
 | 
			
		||||
                this._hideActorChildren(actor);
 | 
			
		||||
        });
 | 
			
		||||
        button.connect('inspect-actor', () => {
 | 
			
		||||
            this._lookingGlass.inspectObject(actor, button);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        const mainContainer = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        const childrenContainer = new St.BoxLayout({
 | 
			
		||||
            vertical: true,
 | 
			
		||||
            style: 'padding: 0 0 0 18px',
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        mainContainer.add_child(button);
 | 
			
		||||
        mainContainer.add_child(childrenContainer);
 | 
			
		||||
 | 
			
		||||
        this._actorData.set(actor, {
 | 
			
		||||
            button,
 | 
			
		||||
            container: mainContainer,
 | 
			
		||||
            children: childrenContainer,
 | 
			
		||||
            visible: false,
 | 
			
		||||
            actorAddedId: 0,
 | 
			
		||||
            actorRemovedId: 0,
 | 
			
		||||
            actorDestroyedId: actor.connect('destroy', () => this._removeActor(actor)),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let belowChild = null;
 | 
			
		||||
        const nextSibling = actor.get_next_sibling();
 | 
			
		||||
        if (nextSibling && this._actorData.has(nextSibling))
 | 
			
		||||
            belowChild = this._actorData.get(nextSibling).container;
 | 
			
		||||
 | 
			
		||||
        container.insert_child_above(mainContainer, belowChild);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _removeActor(actor) {
 | 
			
		||||
        const data = this._actorData.get(actor);
 | 
			
		||||
        if (!data)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        for (let child of actor)
 | 
			
		||||
            this._removeActor(child);
 | 
			
		||||
 | 
			
		||||
        if (data.actorAddedId > 0) {
 | 
			
		||||
            actor.disconnect(data.actorAddedId);
 | 
			
		||||
            data.actorAddedId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (data.actorRemovedId > 0) {
 | 
			
		||||
            actor.disconnect(data.actorRemovedId);
 | 
			
		||||
            data.actorRemovedId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (data.actorDestroyedId > 0) {
 | 
			
		||||
            actor.disconnect(data.actorDestroyedId);
 | 
			
		||||
            data.actorDestroyedId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        data.container.destroy();
 | 
			
		||||
        this._actorData.delete(actor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_map() {
 | 
			
		||||
        super.vfunc_map();
 | 
			
		||||
        this._addActor(this, global.stage);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_unmap() {
 | 
			
		||||
        super.vfunc_unmap();
 | 
			
		||||
        this._removeActor(global.stage);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var LookingGlass = GObject.registerClass(
 | 
			
		||||
class LookingGlass extends St.BoxLayout {
 | 
			
		||||
    _init() {
 | 
			
		||||
@@ -834,9 +1018,9 @@ class LookingGlass extends St.BoxLayout {
 | 
			
		||||
        Main.uiGroup.add_actor(this);
 | 
			
		||||
        Main.uiGroup.set_child_below_sibling(this,
 | 
			
		||||
                                             Main.layoutManager.panelBox);
 | 
			
		||||
        Main.layoutManager.panelBox.connect('allocation-changed',
 | 
			
		||||
        Main.layoutManager.panelBox.connect('notify::allocation',
 | 
			
		||||
                                            this._queueResize.bind(this));
 | 
			
		||||
        Main.layoutManager.keyboardBox.connect('allocation-changed',
 | 
			
		||||
        Main.layoutManager.keyboardBox.connect('notify::allocation',
 | 
			
		||||
                                               this._queueResize.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._objInspector = new ObjInspector(this);
 | 
			
		||||
@@ -918,6 +1102,9 @@ class LookingGlass extends St.BoxLayout {
 | 
			
		||||
        this._extensions = new Extensions(this);
 | 
			
		||||
        notebook.appendPage('Extensions', this._extensions);
 | 
			
		||||
 | 
			
		||||
        this._actorTreeViewer = new ActorTreeViewer(this);
 | 
			
		||||
        notebook.appendPage('Actors', this._actorTreeViewer);
 | 
			
		||||
 | 
			
		||||
        this._entry.clutter_text.connect('activate', (o, _e) => {
 | 
			
		||||
            // Hide any completions we are currently showing
 | 
			
		||||
            this._hideCompletions();
 | 
			
		||||
 
 | 
			
		||||
@@ -643,8 +643,7 @@ var Magnifier = class Magnifier {
 | 
			
		||||
        // Applies only to the first zoom region.
 | 
			
		||||
        if (this._zoomRegions.length) {
 | 
			
		||||
            this._zoomRegions[0].setClampScrollingAtEdges(
 | 
			
		||||
                !this._settings.get_boolean(CLAMP_MODE_KEY)
 | 
			
		||||
            );
 | 
			
		||||
                !this._settings.get_boolean(CLAMP_MODE_KEY));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -652,8 +651,7 @@ var Magnifier = class Magnifier {
 | 
			
		||||
        // Applies only to the first zoom region.
 | 
			
		||||
        if (this._zoomRegions.length) {
 | 
			
		||||
            this._zoomRegions[0].setMouseTrackingMode(
 | 
			
		||||
                this._settings.get_enum(MOUSE_TRACKING_KEY)
 | 
			
		||||
            );
 | 
			
		||||
                this._settings.get_enum(MOUSE_TRACKING_KEY));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -661,8 +659,7 @@ var Magnifier = class Magnifier {
 | 
			
		||||
        // Applies only to the first zoom region.
 | 
			
		||||
        if (this._zoomRegions.length) {
 | 
			
		||||
            this._zoomRegions[0].setFocusTrackingMode(
 | 
			
		||||
                this._settings.get_enum(FOCUS_TRACKING_KEY)
 | 
			
		||||
            );
 | 
			
		||||
                this._settings.get_enum(FOCUS_TRACKING_KEY));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -670,8 +667,7 @@ var Magnifier = class Magnifier {
 | 
			
		||||
        // Applies only to the first zoom region.
 | 
			
		||||
        if (this._zoomRegions.length) {
 | 
			
		||||
            this._zoomRegions[0].setCaretTrackingMode(
 | 
			
		||||
                this._settings.get_enum(CARET_TRACKING_KEY)
 | 
			
		||||
            );
 | 
			
		||||
                this._settings.get_enum(CARET_TRACKING_KEY));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -679,8 +675,7 @@ var Magnifier = class Magnifier {
 | 
			
		||||
        // Applies only to the first zoom region.
 | 
			
		||||
        if (this._zoomRegions.length) {
 | 
			
		||||
            this._zoomRegions[0].setInvertLightness(
 | 
			
		||||
                this._settings.get_boolean(INVERT_LIGHTNESS_KEY)
 | 
			
		||||
            );
 | 
			
		||||
                this._settings.get_boolean(INVERT_LIGHTNESS_KEY));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -688,8 +683,7 @@ var Magnifier = class Magnifier {
 | 
			
		||||
        // Applies only to the first zoom region.
 | 
			
		||||
        if (this._zoomRegions.length) {
 | 
			
		||||
            this._zoomRegions[0].setColorSaturation(
 | 
			
		||||
                this._settings.get_double(COLOR_SATURATION_KEY)
 | 
			
		||||
            );
 | 
			
		||||
                this._settings.get_double(COLOR_SATURATION_KEY));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1941,9 +1935,8 @@ var MagShaderEffects = class MagShaderEffects {
 | 
			
		||||
        // 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
 | 
			
		||||
        );
 | 
			
		||||
            bRed !== NO_CHANGE || bGreen !== NO_CHANGE || bBlue !== NO_CHANGE ||
 | 
			
		||||
            cRed !== NO_CHANGE || cGreen !== NO_CHANGE || cBlue !== NO_CHANGE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -1970,8 +1963,7 @@ var MagShaderEffects = class MagShaderEffects {
 | 
			
		||||
        // 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
 | 
			
		||||
        );
 | 
			
		||||
            cRed !== NO_CHANGE || cGreen !== NO_CHANGE || cBlue !== NO_CHANGE ||
 | 
			
		||||
            bRed !== NO_CHANGE || bGreen !== NO_CHANGE || bBlue !== NO_CHANGE);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,7 @@ const XdndHandler = imports.ui.xdndHandler;
 | 
			
		||||
const KbdA11yDialog = imports.ui.kbdA11yDialog;
 | 
			
		||||
const LocatePointer = imports.ui.locatePointer;
 | 
			
		||||
const PointerA11yTimeout = imports.ui.pointerA11yTimeout;
 | 
			
		||||
const ParentalControlsManager = imports.misc.parentalControlsManager;
 | 
			
		||||
 | 
			
		||||
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
 | 
			
		||||
const STICKY_KEYS_ENABLE = 'stickykeys-enable';
 | 
			
		||||
@@ -96,6 +97,8 @@ let _oskResource = null;
 | 
			
		||||
Gio._promisify(Gio._LocalFilePrototype, 'delete_async', 'delete_finish');
 | 
			
		||||
Gio._promisify(Gio._LocalFilePrototype, 'touch_async', 'touch_finish');
 | 
			
		||||
 | 
			
		||||
let _remoteAccessInhibited = false;
 | 
			
		||||
 | 
			
		||||
function _sessionUpdated() {
 | 
			
		||||
    if (sessionMode.isPrimary)
 | 
			
		||||
        _loadDefaultStylesheet();
 | 
			
		||||
@@ -120,12 +123,23 @@ function _sessionUpdated() {
 | 
			
		||||
        if (lookingGlass)
 | 
			
		||||
            lookingGlass.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let remoteAccessController = global.backend.get_remote_access_controller();
 | 
			
		||||
    if (remoteAccessController) {
 | 
			
		||||
        if (sessionMode.allowScreencast && _remoteAccessInhibited) {
 | 
			
		||||
            remoteAccessController.uninhibit_remote_access();
 | 
			
		||||
            _remoteAccessInhibited = false;
 | 
			
		||||
        } else if (!sessionMode.allowScreencast && !_remoteAccessInhibited) {
 | 
			
		||||
            remoteAccessController.inhibit_remote_access();
 | 
			
		||||
            _remoteAccessInhibited = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function start() {
 | 
			
		||||
    // These are here so we don't break compatibility.
 | 
			
		||||
    global.logError = window.log;
 | 
			
		||||
    global.log = window.log;
 | 
			
		||||
    global.logError = globalThis.log;
 | 
			
		||||
    global.log = globalThis.log;
 | 
			
		||||
 | 
			
		||||
    // Chain up async errors reported from C
 | 
			
		||||
    global.connect('notify-error', (global, msg, detail) => {
 | 
			
		||||
@@ -140,6 +154,10 @@ function start() {
 | 
			
		||||
    sessionMode.connect('updated', _sessionUpdated);
 | 
			
		||||
 | 
			
		||||
    St.Settings.get().connect('notify::gtk-theme', _loadDefaultStylesheet);
 | 
			
		||||
 | 
			
		||||
    // Initialize ParentalControlsManager before the UI
 | 
			
		||||
    ParentalControlsManager.getDefault();
 | 
			
		||||
 | 
			
		||||
    _initializeUI();
 | 
			
		||||
 | 
			
		||||
    shellAccessDialogDBusService = new AccessDialog.AccessDialogDBus();
 | 
			
		||||
@@ -799,7 +817,7 @@ function showRestartMessage(message) {
 | 
			
		||||
 | 
			
		||||
var AnimationsSettings = class {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        let backend = Meta.get_backend();
 | 
			
		||||
        let backend = global.backend;
 | 
			
		||||
        if (!backend.is_rendering_hardware_accelerated()) {
 | 
			
		||||
            St.Settings.get().inhibit_animations();
 | 
			
		||||
            return;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@ const { Atk, Clutter, Gio, GLib,
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
 | 
			
		||||
const Calendar = imports.ui.calendar;
 | 
			
		||||
const Util = imports.misc.util;
 | 
			
		||||
 | 
			
		||||
var MESSAGE_ANIMATION_TIME = 100;
 | 
			
		||||
@@ -285,12 +284,12 @@ var LabelExpanderLayout = GObject.registerClass({
 | 
			
		||||
        return [min, nat];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(container, box, flags) {
 | 
			
		||||
    vfunc_allocate(container, box) {
 | 
			
		||||
        for (let i = 0; i < container.get_n_children(); i++) {
 | 
			
		||||
            let child = container.get_child_at_index(i);
 | 
			
		||||
 | 
			
		||||
            if (child.visible)
 | 
			
		||||
                child.allocate(box, flags);
 | 
			
		||||
                child.allocate(box);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
@@ -572,7 +571,6 @@ var MessageListSection = GObject.registerClass({
 | 
			
		||||
            Main.sessionMode.disconnect(id);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._date = new Date();
 | 
			
		||||
        this._empty = true;
 | 
			
		||||
        this._canClear = false;
 | 
			
		||||
        this._sync();
 | 
			
		||||
@@ -598,13 +596,6 @@ var MessageListSection = GObject.registerClass({
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setDate(date) {
 | 
			
		||||
        if (Calendar.sameDay(date, this._date))
 | 
			
		||||
            return;
 | 
			
		||||
        this._date = date;
 | 
			
		||||
        this._sync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    addMessage(message, animate) {
 | 
			
		||||
        this.addMessageAtIndex(message, -1, animate);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -686,8 +686,8 @@ class SourceActorWithLabel extends SourceActor {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
        super.vfunc_allocate(box, flags);
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        super.vfunc_allocate(box);
 | 
			
		||||
 | 
			
		||||
        let childBox = new Clutter.ActorBox();
 | 
			
		||||
 | 
			
		||||
@@ -707,7 +707,7 @@ class SourceActorWithLabel extends SourceActor {
 | 
			
		||||
        childBox.y1 = box.y2 - naturalHeight;
 | 
			
		||||
        childBox.y2 = box.y2;
 | 
			
		||||
 | 
			
		||||
        this._counterBin.allocate(childBox, flags);
 | 
			
		||||
        this._counterBin.allocate(childBox);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateCount() {
 | 
			
		||||
@@ -1164,8 +1164,7 @@ var MessageTray = GObject.registerClass({
 | 
			
		||||
                                     this._onNotificationDestroy.bind(this));
 | 
			
		||||
                this._notificationQueue.push(notification);
 | 
			
		||||
                this._notificationQueue.sort(
 | 
			
		||||
                    (n1, n2) => n2.urgency - n1.urgency
 | 
			
		||||
                );
 | 
			
		||||
                    (n1, n2) => n2.urgency - n1.urgency);
 | 
			
		||||
                this.emit('queue-changed');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@
 | 
			
		||||
const { Gio, GObject, Shell, St } = imports.gi;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const Calendar = imports.ui.calendar;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageList = imports.ui.messageList;
 | 
			
		||||
 | 
			
		||||
@@ -252,10 +251,6 @@ class MediaSection extends MessageList.MessageListSection {
 | 
			
		||||
                                    this._onProxyReady.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _shouldShow() {
 | 
			
		||||
        return !this.empty && Calendar.isToday(this._date);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get allowed() {
 | 
			
		||||
        return !Main.sessionMode.isGreeter;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -4,10 +4,6 @@
 | 
			
		||||
const { Clutter, GLib, GObject, Meta, Shell, St } = imports.gi;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
// Time for initial animation going into Overview mode;
 | 
			
		||||
// this is defined here to make it available in imports.
 | 
			
		||||
var ANIMATION_TIME = 250;
 | 
			
		||||
 | 
			
		||||
const Background = imports.ui.background;
 | 
			
		||||
const DND = imports.ui.dnd;
 | 
			
		||||
const LayoutManager = imports.ui.layout;
 | 
			
		||||
@@ -18,6 +14,9 @@ const OverviewControls = imports.ui.overviewControls;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
 | 
			
		||||
 | 
			
		||||
// Time for initial animation going into Overview mode
 | 
			
		||||
var ANIMATION_TIME = 250;
 | 
			
		||||
 | 
			
		||||
// Must be less than ANIMATION_TIME, since we switch to
 | 
			
		||||
// or from the overview completely after ANIMATION_TIME,
 | 
			
		||||
// and don't want the shading animation to get cut off
 | 
			
		||||
@@ -245,11 +244,11 @@ var Overview = class {
 | 
			
		||||
    _unshadeBackgrounds() {
 | 
			
		||||
        let backgrounds = this._backgroundGroup.get_children();
 | 
			
		||||
        for (let i = 0; i < backgrounds.length; i++) {
 | 
			
		||||
            backgrounds[i].ease_property('brightness', 1.0, {
 | 
			
		||||
            backgrounds[i].ease_property('@content.brightness', 1.0, {
 | 
			
		||||
                duration: SHADE_ANIMATION_TIME,
 | 
			
		||||
                mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
            });
 | 
			
		||||
            backgrounds[i].ease_property('vignette-sharpness', 0.0, {
 | 
			
		||||
            backgrounds[i].ease_property('@content.vignette-sharpness', 0.0, {
 | 
			
		||||
                duration: SHADE_ANIMATION_TIME,
 | 
			
		||||
                mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
            });
 | 
			
		||||
@@ -259,14 +258,16 @@ var Overview = class {
 | 
			
		||||
    _shadeBackgrounds() {
 | 
			
		||||
        let backgrounds = this._backgroundGroup.get_children();
 | 
			
		||||
        for (let i = 0; i < backgrounds.length; i++) {
 | 
			
		||||
            backgrounds[i].ease_property('brightness', Lightbox.VIGNETTE_BRIGHTNESS, {
 | 
			
		||||
                duration: SHADE_ANIMATION_TIME,
 | 
			
		||||
                mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
            });
 | 
			
		||||
            backgrounds[i].ease_property('vignette-sharpness', Lightbox.VIGNETTE_SHARPNESS, {
 | 
			
		||||
                duration: SHADE_ANIMATION_TIME,
 | 
			
		||||
                mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
            });
 | 
			
		||||
            backgrounds[i].ease_property('@content.brightness',
 | 
			
		||||
                Lightbox.VIGNETTE_BRIGHTNESS, {
 | 
			
		||||
                    duration: SHADE_ANIMATION_TIME,
 | 
			
		||||
                    mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
                });
 | 
			
		||||
            backgrounds[i].ease_property('@content.vignette-sharpness',
 | 
			
		||||
                Lightbox.VIGNETTE_SHARPNESS, {
 | 
			
		||||
                    duration: SHADE_ANIMATION_TIME,
 | 
			
		||||
                    mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -401,8 +402,7 @@ var Overview = class {
 | 
			
		||||
 | 
			
		||||
    _getDesktopClone() {
 | 
			
		||||
        let windows = global.get_window_actors().filter(
 | 
			
		||||
            w => w.meta_window.get_window_type() == Meta.WindowType.DESKTOP
 | 
			
		||||
        );
 | 
			
		||||
            w => w.meta_window.get_window_type() === Meta.WindowType.DESKTOP);
 | 
			
		||||
        if (windows.length == 0)
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
@@ -577,7 +577,7 @@ var Overview = class {
 | 
			
		||||
        this._activationTime = GLib.get_monotonic_time() / GLib.USEC_PER_SEC;
 | 
			
		||||
 | 
			
		||||
        Meta.disable_unredirect_for_display(global.display);
 | 
			
		||||
        this.viewSelector.show();
 | 
			
		||||
        this.viewSelector.animateToOverview();
 | 
			
		||||
 | 
			
		||||
        this._overview.opacity = 0;
 | 
			
		||||
        this._overview.ease({
 | 
			
		||||
 
 | 
			
		||||
@@ -8,9 +8,8 @@ const Main = imports.ui.main;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const ViewSelector = imports.ui.viewSelector;
 | 
			
		||||
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
 | 
			
		||||
const Overview = imports.ui.overview;
 | 
			
		||||
 | 
			
		||||
var SIDE_CONTROLS_ANIMATION_TIME = Overview.ANIMATION_TIME;
 | 
			
		||||
var SIDE_CONTROLS_ANIMATION_TIME = 160;
 | 
			
		||||
 | 
			
		||||
function getRtlSlideDirection(direction, actor) {
 | 
			
		||||
    let rtl = actor.text_direction == Clutter.TextDirection.RTL;
 | 
			
		||||
@@ -52,7 +51,7 @@ var SlideLayout = GObject.registerClass({
 | 
			
		||||
        return [minWidth, natWidth];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(container, box, flags) {
 | 
			
		||||
    vfunc_allocate(container, box) {
 | 
			
		||||
        let child = container.get_first_child();
 | 
			
		||||
 | 
			
		||||
        let availWidth = Math.round(box.x2 - box.x1);
 | 
			
		||||
@@ -73,7 +72,7 @@ var SlideLayout = GObject.registerClass({
 | 
			
		||||
        actorBox.y1 = box.y1;
 | 
			
		||||
        actorBox.y2 = actorBox.y1 + availHeight;
 | 
			
		||||
 | 
			
		||||
        child.allocate(actorBox, flags);
 | 
			
		||||
        child.allocate(actorBox);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // eslint-disable-next-line camelcase
 | 
			
		||||
@@ -395,10 +394,10 @@ class DashSpacer extends St.Widget {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var ControlsLayout = GObject.registerClass({
 | 
			
		||||
    Signals: { 'allocation-changed': { flags: GObject.SignalFlags.RUN_LAST } },
 | 
			
		||||
    Signals: { 'allocation-changed': {} },
 | 
			
		||||
}, class ControlsLayout extends Clutter.BinLayout {
 | 
			
		||||
    vfunc_allocate(container, box, flags) {
 | 
			
		||||
        super.vfunc_allocate(container, box, flags);
 | 
			
		||||
    vfunc_allocate(container, box) {
 | 
			
		||||
        super.vfunc_allocate(container, box);
 | 
			
		||||
        this.emit('allocation-changed');
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -436,11 +436,11 @@ var PadDiagram = GObject.registerClass({
 | 
			
		||||
 | 
			
		||||
        childBox.y1 = y - natHeight / 2;
 | 
			
		||||
        childBox.y2 = y + natHeight / 2;
 | 
			
		||||
        child.allocate(childBox, 0);
 | 
			
		||||
        child.allocate(childBox);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
        super.vfunc_allocate(box, flags);
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        super.vfunc_allocate(box);
 | 
			
		||||
        if (this._handle === null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -120,6 +120,10 @@ var PageIndicators = GObject.registerClass({
 | 
			
		||||
        for (let i = 0; i < children.length; i++)
 | 
			
		||||
            this._updateIndicator(children[i], i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get nPages() {
 | 
			
		||||
        return this._nPages;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var AnimatedPageIndicators = GObject.registerClass(
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										102
									
								
								js/ui/panel.js
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								js/ui/panel.js
									
									
									
									
									
								
							@@ -5,6 +5,7 @@ const { Atk, Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
 | 
			
		||||
const Cairo = imports.cairo;
 | 
			
		||||
 | 
			
		||||
const Animation = imports.ui.animation;
 | 
			
		||||
const AppDisplay = imports.ui.appDisplay;
 | 
			
		||||
const Config = imports.misc.config;
 | 
			
		||||
const CtrlAltTab = imports.ui.ctrlAltTab;
 | 
			
		||||
const DND = imports.ui.dnd;
 | 
			
		||||
@@ -60,71 +61,20 @@ function _unpremultiply(color) {
 | 
			
		||||
    return new Clutter.Color({ red, green, blue, alpha: color.alpha });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class AppMenu extends PopupMenu.PopupMenu {
 | 
			
		||||
class AppMenu extends AppDisplay.BaseAppMenu {
 | 
			
		||||
    constructor(sourceActor) {
 | 
			
		||||
        super(sourceActor, 0.5, St.Side.TOP);
 | 
			
		||||
        super(sourceActor, St.Side.TOP);
 | 
			
		||||
 | 
			
		||||
        this.actor.add_style_class_name('app-menu');
 | 
			
		||||
 | 
			
		||||
        this._app = null;
 | 
			
		||||
        this._appSystem = Shell.AppSystem.get_default();
 | 
			
		||||
 | 
			
		||||
        this._windowsChangedId = 0;
 | 
			
		||||
 | 
			
		||||
        /* Translators: This is the heading of a list of open windows */
 | 
			
		||||
        this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem(_("Open Windows")));
 | 
			
		||||
 | 
			
		||||
        this._windowSection = new PopupMenu.PopupMenuSection();
 | 
			
		||||
        this.addMenuItem(this._windowSection);
 | 
			
		||||
 | 
			
		||||
        this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
 | 
			
		||||
 | 
			
		||||
        this._newWindowItem = this.addAction(_("New Window"), () => {
 | 
			
		||||
            this._app.open_new_window(-1);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
 | 
			
		||||
 | 
			
		||||
        this._actionSection = new PopupMenu.PopupMenuSection();
 | 
			
		||||
        this.addMenuItem(this._actionSection);
 | 
			
		||||
 | 
			
		||||
        this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
 | 
			
		||||
 | 
			
		||||
        this._detailsItem = this.addAction(_("Show Details"), () => {
 | 
			
		||||
            let id = this._app.get_id();
 | 
			
		||||
            let args = GLib.Variant.new('(ss)', [id, '']);
 | 
			
		||||
            Gio.DBus.get(Gio.BusType.SESSION, null, (o, res) => {
 | 
			
		||||
                let bus = Gio.DBus.get_finish(res);
 | 
			
		||||
                bus.call('org.gnome.Software',
 | 
			
		||||
                         '/org/gnome/Software',
 | 
			
		||||
                         'org.gtk.Actions', 'Activate',
 | 
			
		||||
                         GLib.Variant.new('(sava{sv})',
 | 
			
		||||
                                          ['details', [args], null]),
 | 
			
		||||
                         null, 0, -1, null);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
 | 
			
		||||
 | 
			
		||||
        this.addAction(_("Quit"), () => {
 | 
			
		||||
            this._app.request_quit();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._appSystem.connect('installed-changed', () => {
 | 
			
		||||
            this._updateDetailsVisibility();
 | 
			
		||||
        });
 | 
			
		||||
        this._updateDetailsVisibility();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateDetailsVisibility() {
 | 
			
		||||
        let sw = this._appSystem.lookup_app('org.gnome.Software.desktop');
 | 
			
		||||
        this._detailsItem.visible = sw != null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    isEmpty() {
 | 
			
		||||
        if (!this._app)
 | 
			
		||||
            return true;
 | 
			
		||||
        return super.isEmpty();
 | 
			
		||||
    get app() {
 | 
			
		||||
        return this._app;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setApp(app) {
 | 
			
		||||
@@ -159,25 +109,6 @@ class AppMenu extends PopupMenu.PopupMenu {
 | 
			
		||||
        this._newWindowItem.visible =
 | 
			
		||||
            app && app.can_open_new_window() && !actions.includes('new-window');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateWindowsSection() {
 | 
			
		||||
        this._windowSection.removeAll();
 | 
			
		||||
 | 
			
		||||
        if (!this._app)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let windows = this._app.get_windows();
 | 
			
		||||
        windows.forEach(window => {
 | 
			
		||||
            let title = window.title || this._app.get_name();
 | 
			
		||||
            let item = this._windowSection.addAction(title, event => {
 | 
			
		||||
                Main.activateWindow(window, event.get_time());
 | 
			
		||||
            });
 | 
			
		||||
            let id = window.connect('notify::title', () => {
 | 
			
		||||
                item.label.text = window.title || this._app.get_name();
 | 
			
		||||
            });
 | 
			
		||||
            item.connect('destroy', () => window.disconnect(id));
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -286,7 +217,7 @@ var AppMenuButton = GObject.registerClass({
 | 
			
		||||
        this.remove_all_transitions();
 | 
			
		||||
        this.ease({
 | 
			
		||||
            opacity: 0,
 | 
			
		||||
            mode: Clutter.Animation.EASE_OUT_QUAD,
 | 
			
		||||
            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
            duration: Overview.ANIMATION_TIME,
 | 
			
		||||
            onComplete: () => this.hide(),
 | 
			
		||||
        });
 | 
			
		||||
@@ -844,8 +775,8 @@ class Panel extends St.Widget {
 | 
			
		||||
        return [0,  0];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
        this.set_allocation(box, flags);
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        this.set_allocation(box);
 | 
			
		||||
 | 
			
		||||
        let allocWidth = box.x2 - box.x1;
 | 
			
		||||
        let allocHeight = box.y2 - box.y1;
 | 
			
		||||
@@ -881,13 +812,13 @@ class Panel extends St.Widget {
 | 
			
		||||
            childBox.x2 = Math.min(Math.floor(sideWidth),
 | 
			
		||||
                                   leftNaturalWidth);
 | 
			
		||||
        }
 | 
			
		||||
        this._leftBox.allocate(childBox, flags);
 | 
			
		||||
        this._leftBox.allocate(childBox);
 | 
			
		||||
 | 
			
		||||
        childBox.x1 = Math.ceil(sideWidth);
 | 
			
		||||
        childBox.y1 = 0;
 | 
			
		||||
        childBox.x2 = childBox.x1 + centerWidth;
 | 
			
		||||
        childBox.y2 = allocHeight;
 | 
			
		||||
        this._centerBox.allocate(childBox, flags);
 | 
			
		||||
        this._centerBox.allocate(childBox);
 | 
			
		||||
 | 
			
		||||
        childBox.y1 = 0;
 | 
			
		||||
        childBox.y2 = allocHeight;
 | 
			
		||||
@@ -901,7 +832,7 @@ class Panel extends St.Widget {
 | 
			
		||||
                                   0);
 | 
			
		||||
            childBox.x2 = allocWidth;
 | 
			
		||||
        }
 | 
			
		||||
        this._rightBox.allocate(childBox, flags);
 | 
			
		||||
        this._rightBox.allocate(childBox);
 | 
			
		||||
 | 
			
		||||
        let cornerWidth, cornerHeight;
 | 
			
		||||
 | 
			
		||||
@@ -911,7 +842,7 @@ class Panel extends St.Widget {
 | 
			
		||||
        childBox.x2 = cornerWidth;
 | 
			
		||||
        childBox.y1 = allocHeight;
 | 
			
		||||
        childBox.y2 = allocHeight + cornerHeight;
 | 
			
		||||
        this._leftCorner.allocate(childBox, flags);
 | 
			
		||||
        this._leftCorner.allocate(childBox);
 | 
			
		||||
 | 
			
		||||
        [, cornerWidth] = this._rightCorner.get_preferred_width(-1);
 | 
			
		||||
        [, cornerHeight] = this._rightCorner.get_preferred_height(-1);
 | 
			
		||||
@@ -919,7 +850,7 @@ class Panel extends St.Widget {
 | 
			
		||||
        childBox.x2 = allocWidth;
 | 
			
		||||
        childBox.y1 = allocHeight;
 | 
			
		||||
        childBox.y2 = allocHeight + cornerHeight;
 | 
			
		||||
        this._rightCorner.allocate(childBox, flags);
 | 
			
		||||
        this._rightCorner.allocate(childBox);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _tryDragWindow(event) {
 | 
			
		||||
@@ -1158,10 +1089,9 @@ class Panel extends St.Widget {
 | 
			
		||||
 | 
			
		||||
    _getDraggableWindowForPosition(stageX) {
 | 
			
		||||
        let workspaceManager = global.workspace_manager;
 | 
			
		||||
        let workspace = workspaceManager.get_active_workspace();
 | 
			
		||||
        let allWindowsByStacking = global.display.sort_windows_by_stacking(
 | 
			
		||||
            workspace.list_windows()
 | 
			
		||||
        ).reverse();
 | 
			
		||||
        const windows = workspaceManager.get_active_workspace().list_windows();
 | 
			
		||||
        const allWindowsByStacking =
 | 
			
		||||
            global.display.sort_windows_by_stacking(windows).reverse();
 | 
			
		||||
 | 
			
		||||
        return allWindowsByStacking.find(metaWindow => {
 | 
			
		||||
            let rect = metaWindow.get_frame_rect();
 | 
			
		||||
 
 | 
			
		||||
@@ -59,8 +59,8 @@ class ButtonBox extends St.Widget {
 | 
			
		||||
        return [0, 0];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
        this.set_allocation(box, flags);
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        this.set_allocation(box);
 | 
			
		||||
 | 
			
		||||
        let child = this.get_first_child();
 | 
			
		||||
        if (!child)
 | 
			
		||||
@@ -83,7 +83,7 @@ class ButtonBox extends St.Widget {
 | 
			
		||||
        childBox.y1 = 0;
 | 
			
		||||
        childBox.y2 = availHeight;
 | 
			
		||||
 | 
			
		||||
        child.allocate(childBox, flags);
 | 
			
		||||
        child.allocate(childBox);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDestroy() {
 | 
			
		||||
@@ -183,9 +183,10 @@ var Button = GObject.registerClass({
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDestroy() {
 | 
			
		||||
        super._onDestroy();
 | 
			
		||||
 | 
			
		||||
        if (this.menu)
 | 
			
		||||
            this.menu.destroy();
 | 
			
		||||
        super._onDestroy();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -881,10 +881,9 @@ var PopupMenu = class extends PopupMenuBase {
 | 
			
		||||
 | 
			
		||||
        let state = event.get_state();
 | 
			
		||||
 | 
			
		||||
        // if user has a modifier down (except capslock and numlock)
 | 
			
		||||
        // if user has a modifier down (except capslock)
 | 
			
		||||
        // then don't handle the key press here
 | 
			
		||||
        state &= ~Clutter.ModifierType.LOCK_MASK;
 | 
			
		||||
        state &= ~Clutter.ModifierType.MOD2_MASK;
 | 
			
		||||
        state &= Clutter.ModifierType.MODIFIER_MASK;
 | 
			
		||||
 | 
			
		||||
        if (state)
 | 
			
		||||
@@ -1325,7 +1324,7 @@ var PopupMenuManager = class {
 | 
			
		||||
 | 
			
		||||
    removeMenu(menu) {
 | 
			
		||||
        if (menu == this.activeMenu)
 | 
			
		||||
            this._grabHelper.ungrab({ actor: menu.actor });
 | 
			
		||||
            this._closeMenu(false, menu);
 | 
			
		||||
 | 
			
		||||
        let position = this._findMenu(menu);
 | 
			
		||||
        if (position == -1) // not a menu we manage
 | 
			
		||||
 
 | 
			
		||||
@@ -204,7 +204,7 @@ var RemoteSearchProvider = class {
 | 
			
		||||
                                         g_interface_info: proxyInfo,
 | 
			
		||||
                                         g_interface_name: proxyInfo.name,
 | 
			
		||||
                                         gFlags });
 | 
			
		||||
        this.proxy.init_async(GLib.PRIORITY_DEFAULT, null, null);
 | 
			
		||||
        this.proxy.init_async(GLib.PRIORITY_DEFAULT, null);
 | 
			
		||||
 | 
			
		||||
        this.appInfo = appInfo;
 | 
			
		||||
        this.id = appInfo.get_id();
 | 
			
		||||
 
 | 
			
		||||
@@ -198,7 +198,7 @@ var ScreenShield = class {
 | 
			
		||||
        let lockEnabled = this._settings.get_boolean(LOCK_ENABLED_KEY);
 | 
			
		||||
        let lockLocked = this._lockSettings.get_boolean(DISABLE_LOCK_KEY);
 | 
			
		||||
        let inhibit = this._loginSession && this._loginSession.Active &&
 | 
			
		||||
                       !this._isActive && lockEnabled && !lockLocked;
 | 
			
		||||
                       !this._isActive && lockEnabled && !lockLocked && Main.sessionMode.unlockDialog;
 | 
			
		||||
        if (inhibit) {
 | 
			
		||||
            this._loginManager.inhibit(_("GNOME needs to lock the screen"),
 | 
			
		||||
                inhibitor => {
 | 
			
		||||
@@ -345,7 +345,7 @@ var ScreenShield = class {
 | 
			
		||||
        this._lockDialogGroup.remove_all_transitions();
 | 
			
		||||
 | 
			
		||||
        if (animate) {
 | 
			
		||||
            // Tween the lock screen out of screen
 | 
			
		||||
            // Animate the lock screen out of screen
 | 
			
		||||
            // if velocity is not specified (i.e. we come here from pressing ESC),
 | 
			
		||||
            // use the same speed regardless of original position
 | 
			
		||||
            // if velocity is specified, it's in pixels per milliseconds
 | 
			
		||||
@@ -561,7 +561,8 @@ var ScreenShield = class {
 | 
			
		||||
        if (this._activationTime == 0)
 | 
			
		||||
            this._activationTime = GLib.get_monotonic_time();
 | 
			
		||||
 | 
			
		||||
        this._ensureUnlockDialog(true);
 | 
			
		||||
        if (!this._ensureUnlockDialog(true))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,19 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/* exported ScreenshotService */
 | 
			
		||||
 | 
			
		||||
const { Clutter, Graphene, Gio, GObject, GLib, Meta, Shell, St } = imports.gi;
 | 
			
		||||
const { Clutter, Gio, GObject, GLib, Meta, Shell, St } = imports.gi;
 | 
			
		||||
 | 
			
		||||
const GrabHelper = imports.ui.grabHelper;
 | 
			
		||||
const Lightbox = imports.ui.lightbox;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
 | 
			
		||||
Gio._promisify(Shell.Screenshot.prototype, 'pick_color', 'pick_color_finish');
 | 
			
		||||
Gio._promisify(Shell.Screenshot.prototype, 'screenshot', 'screenshot_finish');
 | 
			
		||||
Gio._promisify(Shell.Screenshot.prototype,
 | 
			
		||||
    'screenshot_window', 'screenshot_window_finish');
 | 
			
		||||
Gio._promisify(Shell.Screenshot.prototype,
 | 
			
		||||
    'screenshot_area', 'screenshot_area_finish');
 | 
			
		||||
 | 
			
		||||
const { loadInterfaceXML } = imports.misc.fileUtils;
 | 
			
		||||
 | 
			
		||||
const ScreenshotIface = loadInterfaceXML('org.gnome.Shell.Screenshot');
 | 
			
		||||
@@ -158,7 +165,7 @@ var ScreenshotService = class {
 | 
			
		||||
        return [x, y, width, height];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ScreenshotAreaAsync(params, invocation) {
 | 
			
		||||
    async ScreenshotAreaAsync(params, invocation) {
 | 
			
		||||
        let [x, y, width, height, flash, filename] = params;
 | 
			
		||||
        [x, y, width, height] = this._scaleArea(x, y, width, height);
 | 
			
		||||
        if (!this._checkArea(x, y, width, height)) {
 | 
			
		||||
@@ -175,21 +182,17 @@ var ScreenshotService = class {
 | 
			
		||||
        if (!stream)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        screenshot.screenshot_area(x, y, width, height, stream,
 | 
			
		||||
            (o, res) => {
 | 
			
		||||
                try {
 | 
			
		||||
                    let [success_, area] =
 | 
			
		||||
                        screenshot.screenshot_area_finish(res);
 | 
			
		||||
                    this._onScreenshotComplete(
 | 
			
		||||
                        area, stream, file, flash, invocation);
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
                    this._removeShooterForSender(invocation.get_sender());
 | 
			
		||||
                    invocation.return_value(new GLib.Variant('(bs)', [false, '']));
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        try {
 | 
			
		||||
            let [area] =
 | 
			
		||||
                await screenshot.screenshot_area(x, y, width, height, stream);
 | 
			
		||||
            this._onScreenshotComplete(area, stream, file, flash, invocation);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            this._removeShooterForSender(invocation.get_sender());
 | 
			
		||||
            invocation.return_value(new GLib.Variant('(bs)', [false, '']));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ScreenshotWindowAsync(params, invocation) {
 | 
			
		||||
    async ScreenshotWindowAsync(params, invocation) {
 | 
			
		||||
        let [includeFrame, includeCursor, flash, filename] = params;
 | 
			
		||||
        let screenshot = this._createScreenshot(invocation);
 | 
			
		||||
        if (!screenshot)
 | 
			
		||||
@@ -199,21 +202,17 @@ var ScreenshotService = class {
 | 
			
		||||
        if (!stream)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        screenshot.screenshot_window(includeFrame, includeCursor, stream,
 | 
			
		||||
            (o, res) => {
 | 
			
		||||
                try {
 | 
			
		||||
                    let [success_, area] =
 | 
			
		||||
                        screenshot.screenshot_window_finish(res);
 | 
			
		||||
                    this._onScreenshotComplete(
 | 
			
		||||
                        area, stream, file, flash, invocation);
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
                    this._removeShooterForSender(invocation.get_sender());
 | 
			
		||||
                    invocation.return_value(new GLib.Variant('(bs)', [false, '']));
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        try {
 | 
			
		||||
            let [area] =
 | 
			
		||||
                await screenshot.screenshot_window(includeFrame, includeCursor, stream);
 | 
			
		||||
            this._onScreenshotComplete(area, stream, file, flash, invocation);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            this._removeShooterForSender(invocation.get_sender());
 | 
			
		||||
            invocation.return_value(new GLib.Variant('(bs)', [false, '']));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ScreenshotAsync(params, invocation) {
 | 
			
		||||
    async ScreenshotAsync(params, invocation) {
 | 
			
		||||
        let [includeCursor, flash, filename] = params;
 | 
			
		||||
        let screenshot = this._createScreenshot(invocation);
 | 
			
		||||
        if (!screenshot)
 | 
			
		||||
@@ -223,18 +222,13 @@ var ScreenshotService = class {
 | 
			
		||||
        if (!stream)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        screenshot.screenshot(includeCursor, stream,
 | 
			
		||||
            (o, res) => {
 | 
			
		||||
                try {
 | 
			
		||||
                    let [success_, area] =
 | 
			
		||||
                        screenshot.screenshot_finish(res);
 | 
			
		||||
                    this._onScreenshotComplete(
 | 
			
		||||
                        area, stream, file, flash, invocation);
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
                    this._removeShooterForSender(invocation.get_sender());
 | 
			
		||||
                    invocation.return_value(new GLib.Variant('(bs)', [false, '']));
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        try {
 | 
			
		||||
            let [area] = await screenshot.screenshot(includeCursor, stream);
 | 
			
		||||
            this._onScreenshotComplete(area, stream, file, flash, invocation);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            this._removeShooterForSender(invocation.get_sender());
 | 
			
		||||
            invocation.return_value(new GLib.Variant('(bs)', [false, '']));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async SelectAreaAsync(params, invocation) {
 | 
			
		||||
@@ -267,27 +261,22 @@ var ScreenshotService = class {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async PickColorAsync(params, invocation) {
 | 
			
		||||
        let pickPixel = new PickPixel();
 | 
			
		||||
        const screenshot = this._createScreenshot(invocation, false);
 | 
			
		||||
        if (!screenshot)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        const pickPixel = new PickPixel(screenshot);
 | 
			
		||||
        try {
 | 
			
		||||
            const coords = await pickPixel.pickAsync();
 | 
			
		||||
 | 
			
		||||
            let screenshot = this._createScreenshot(invocation, false);
 | 
			
		||||
            if (!screenshot)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            screenshot.pick_color(coords.x, coords.y, (_o, res) => {
 | 
			
		||||
                let [success_, color] = screenshot.pick_color_finish(res);
 | 
			
		||||
                let { red, green, blue } = color;
 | 
			
		||||
                let retval = GLib.Variant.new('(a{sv})', [{
 | 
			
		||||
                    color: GLib.Variant.new('(ddd)', [
 | 
			
		||||
                        red / 255.0,
 | 
			
		||||
                        green / 255.0,
 | 
			
		||||
                        blue / 255.0,
 | 
			
		||||
                    ]),
 | 
			
		||||
                }]);
 | 
			
		||||
                this._removeShooterForSender(invocation.get_sender());
 | 
			
		||||
                invocation.return_value(retval);
 | 
			
		||||
            });
 | 
			
		||||
            const color = await pickPixel.pickAsync();
 | 
			
		||||
            const { red, green, blue } = color;
 | 
			
		||||
            const retval = GLib.Variant.new('(a{sv})', [{
 | 
			
		||||
                color: GLib.Variant.new('(ddd)', [
 | 
			
		||||
                    red / 255.0,
 | 
			
		||||
                    green / 255.0,
 | 
			
		||||
                    blue / 255.0,
 | 
			
		||||
                ]),
 | 
			
		||||
            }]);
 | 
			
		||||
            invocation.return_value(retval);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            invocation.return_error_literal(
 | 
			
		||||
                Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
 | 
			
		||||
@@ -391,12 +380,145 @@ class SelectArea extends St.Widget {
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var RecolorEffect = GObject.registerClass({
 | 
			
		||||
    Properties: {
 | 
			
		||||
        color: GObject.ParamSpec.boxed(
 | 
			
		||||
            'color', 'color', 'replacement color',
 | 
			
		||||
            GObject.ParamFlags.WRITABLE,
 | 
			
		||||
            Clutter.Color.$gtype),
 | 
			
		||||
        chroma: GObject.ParamSpec.boxed(
 | 
			
		||||
            'chroma', 'chroma', 'color to replace',
 | 
			
		||||
            GObject.ParamFlags.WRITABLE,
 | 
			
		||||
            Clutter.Color.$gtype),
 | 
			
		||||
        threshold: GObject.ParamSpec.float(
 | 
			
		||||
            'threshold', 'threshold', 'threshold',
 | 
			
		||||
            GObject.ParamFlags.WRITABLE,
 | 
			
		||||
            0.0, 1.0, 0.0),
 | 
			
		||||
        smoothing: GObject.ParamSpec.float(
 | 
			
		||||
            'smoothing', 'smoothing', 'smoothing',
 | 
			
		||||
            GObject.ParamFlags.WRITABLE,
 | 
			
		||||
            0.0, 1.0, 0.0),
 | 
			
		||||
    },
 | 
			
		||||
}, class RecolorEffect extends Shell.GLSLEffect {
 | 
			
		||||
    _init(params) {
 | 
			
		||||
        this._color = new Clutter.Color();
 | 
			
		||||
        this._chroma = new Clutter.Color();
 | 
			
		||||
        this._threshold = 0;
 | 
			
		||||
        this._smoothing = 0;
 | 
			
		||||
 | 
			
		||||
        this._colorLocation = null;
 | 
			
		||||
        this._chromaLocation = null;
 | 
			
		||||
        this._thresholdLocation = null;
 | 
			
		||||
        this._smoothingLocation = null;
 | 
			
		||||
 | 
			
		||||
        super._init(params);
 | 
			
		||||
 | 
			
		||||
        this._colorLocation = this.get_uniform_location('recolor_color');
 | 
			
		||||
        this._chromaLocation = this.get_uniform_location('chroma_color');
 | 
			
		||||
        this._thresholdLocation = this.get_uniform_location('threshold');
 | 
			
		||||
        this._smoothingLocation = this.get_uniform_location('smoothing');
 | 
			
		||||
 | 
			
		||||
        this._updateColorUniform(this._colorLocation, this._color);
 | 
			
		||||
        this._updateColorUniform(this._chromaLocation, this._chroma);
 | 
			
		||||
        this._updateFloatUniform(this._thresholdLocation, this._threshold);
 | 
			
		||||
        this._updateFloatUniform(this._smoothingLocation, this._smoothing);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateColorUniform(location, color) {
 | 
			
		||||
        if (!location)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.set_uniform_float(location,
 | 
			
		||||
            3, [color.red / 255, color.green / 255, color.blue / 255]);
 | 
			
		||||
        this.queue_repaint();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateFloatUniform(location, value) {
 | 
			
		||||
        if (!location)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.set_uniform_float(location, 1, [value]);
 | 
			
		||||
        this.queue_repaint();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set color(c) {
 | 
			
		||||
        if (this._color.equal(c))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._color = c;
 | 
			
		||||
        this.notify('color');
 | 
			
		||||
 | 
			
		||||
        this._updateColorUniform(this._colorLocation, this._color);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set chroma(c) {
 | 
			
		||||
        if (this._chroma.equal(c))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._chroma = c;
 | 
			
		||||
        this.notify('chroma');
 | 
			
		||||
 | 
			
		||||
        this._updateColorUniform(this._chromaLocation, this._chroma);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set threshold(value) {
 | 
			
		||||
        if (this._threshold === value)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._threshold = value;
 | 
			
		||||
        this.notify('threshold');
 | 
			
		||||
 | 
			
		||||
        this._updateFloatUniform(this._thresholdLocation, this._threshold);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set smoothing(value) {
 | 
			
		||||
        if (this._smoothing === value)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._smoothing = value;
 | 
			
		||||
        this.notify('smoothing');
 | 
			
		||||
 | 
			
		||||
        this._updateFloatUniform(this._smoothingLocation, this._smoothing);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_build_pipeline() {
 | 
			
		||||
        // Conversion parameters from https://en.wikipedia.org/wiki/YCbCr
 | 
			
		||||
        const decl = `
 | 
			
		||||
            vec3 rgb2yCrCb(vec3 c) {                                \n
 | 
			
		||||
                float y = 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;  \n
 | 
			
		||||
                float cr = 0.7133 * (c.r - y);                      \n
 | 
			
		||||
                float cb = 0.5643 * (c.b - y);                      \n
 | 
			
		||||
                return vec3(y, cr, cb);                             \n
 | 
			
		||||
            }                                                       \n
 | 
			
		||||
                                                                    \n
 | 
			
		||||
            uniform vec3 chroma_color;                              \n
 | 
			
		||||
            uniform vec3 recolor_color;                             \n
 | 
			
		||||
            uniform float threshold;                                \n
 | 
			
		||||
            uniform float smoothing;                                \n`;
 | 
			
		||||
        const src = `
 | 
			
		||||
            vec3 mask = rgb2yCrCb(chroma_color.rgb);                \n
 | 
			
		||||
            vec3 yCrCb = rgb2yCrCb(cogl_color_out.rgb);             \n
 | 
			
		||||
            float blend =                                           \n
 | 
			
		||||
              smoothstep(threshold,                                 \n
 | 
			
		||||
                         threshold + smoothing,                     \n
 | 
			
		||||
                         distance(yCrCb.gb, mask.gb));              \n
 | 
			
		||||
            cogl_color_out.rgb =                                    \n
 | 
			
		||||
              mix(recolor_color, cogl_color_out.rgb, blend);        \n`;
 | 
			
		||||
 | 
			
		||||
        this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, decl, src, false);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var PickPixel = GObject.registerClass(
 | 
			
		||||
class PickPixel extends St.Widget {
 | 
			
		||||
    _init() {
 | 
			
		||||
    _init(screenshot) {
 | 
			
		||||
        super._init({ visible: false, reactive: true });
 | 
			
		||||
 | 
			
		||||
        this._screenshot = screenshot;
 | 
			
		||||
 | 
			
		||||
        this._result = null;
 | 
			
		||||
        this._color = null;
 | 
			
		||||
        this._inPick = false;
 | 
			
		||||
 | 
			
		||||
        Main.uiGroup.add_actor(this);
 | 
			
		||||
 | 
			
		||||
@@ -405,16 +527,44 @@ class PickPixel extends St.Widget {
 | 
			
		||||
        let constraint = new Clutter.BindConstraint({ source: global.stage,
 | 
			
		||||
                                                      coordinate: Clutter.BindCoordinate.ALL });
 | 
			
		||||
        this.add_constraint(constraint);
 | 
			
		||||
 | 
			
		||||
        const action = new Clutter.ClickAction();
 | 
			
		||||
        action.connect('clicked', async () => {
 | 
			
		||||
            await this._pickColor(...action.get_coords());
 | 
			
		||||
            this._result = this._color;
 | 
			
		||||
            this._grabHelper.ungrab();
 | 
			
		||||
        });
 | 
			
		||||
        this.add_action(action);
 | 
			
		||||
 | 
			
		||||
        this._recolorEffect = new RecolorEffect({
 | 
			
		||||
            chroma: new Clutter.Color({
 | 
			
		||||
                red: 80,
 | 
			
		||||
                green: 219,
 | 
			
		||||
                blue: 181,
 | 
			
		||||
            }),
 | 
			
		||||
            threshold: 0.04,
 | 
			
		||||
            smoothing: 0.07,
 | 
			
		||||
        });
 | 
			
		||||
        this._previewCursor = new St.Icon({
 | 
			
		||||
            icon_name: 'color-pick',
 | 
			
		||||
            icon_size: Meta.prefs_get_cursor_size(),
 | 
			
		||||
            effect: this._recolorEffect,
 | 
			
		||||
            visible: false,
 | 
			
		||||
        });
 | 
			
		||||
        Main.uiGroup.add_actor(this._previewCursor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async pickAsync() {
 | 
			
		||||
        global.display.set_cursor(Meta.Cursor.CROSSHAIR);
 | 
			
		||||
        global.display.set_cursor(Meta.Cursor.BLANK);
 | 
			
		||||
        Main.uiGroup.set_child_above_sibling(this, null);
 | 
			
		||||
        this.show();
 | 
			
		||||
 | 
			
		||||
        this._pickColor(...global.get_pointer());
 | 
			
		||||
 | 
			
		||||
        await this._grabHelper.grabAsync({ actor: this });
 | 
			
		||||
 | 
			
		||||
        global.display.set_cursor(Meta.Cursor.DEFAULT);
 | 
			
		||||
        this._previewCursor.destroy();
 | 
			
		||||
 | 
			
		||||
        GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
 | 
			
		||||
            this.destroy();
 | 
			
		||||
@@ -424,10 +574,25 @@ class PickPixel extends St.Widget {
 | 
			
		||||
        return this._result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_button_release_event(buttonEvent) {
 | 
			
		||||
        let { x, y } = buttonEvent;
 | 
			
		||||
        this._result = new Graphene.Point({ x, y });
 | 
			
		||||
        this._grabHelper.ungrab();
 | 
			
		||||
    async _pickColor(x, y) {
 | 
			
		||||
        if (this._inPick)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._inPick = true;
 | 
			
		||||
        this._previewCursor.set_position(x, y);
 | 
			
		||||
        [this._color] = await this._screenshot.pick_color(x, y);
 | 
			
		||||
        this._inPick = false;
 | 
			
		||||
 | 
			
		||||
        if (!this._color)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._recolorEffect.color = this._color;
 | 
			
		||||
        this._previewCursor.show();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_motion_event(motionEvent) {
 | 
			
		||||
        const { x, y } = motionEvent;
 | 
			
		||||
        this._pickColor(x, y);
 | 
			
		||||
        return Clutter.EVENT_PROPAGATE;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										165
									
								
								js/ui/search.js
									
									
									
									
									
								
							
							
						
						
									
										165
									
								
								js/ui/search.js
									
									
									
									
									
								
							@@ -6,17 +6,17 @@ const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
 | 
			
		||||
const AppDisplay = imports.ui.appDisplay;
 | 
			
		||||
const IconGrid = imports.ui.iconGrid;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const ParentalControlsManager = imports.misc.parentalControlsManager;
 | 
			
		||||
const RemoteSearch = imports.ui.remoteSearch;
 | 
			
		||||
const Util = imports.misc.util;
 | 
			
		||||
 | 
			
		||||
const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers';
 | 
			
		||||
 | 
			
		||||
var MAX_LIST_SEARCH_RESULTS_ROWS = 5;
 | 
			
		||||
var MAX_GRID_SEARCH_RESULTS_ROWS = 1;
 | 
			
		||||
 | 
			
		||||
var MaxWidthBox = GObject.registerClass(
 | 
			
		||||
class MaxWidthBox extends St.BoxLayout {
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        let themeNode = this.get_theme_node();
 | 
			
		||||
        let maxWidth = themeNode.get_max_width();
 | 
			
		||||
        let availWidth = box.x2 - box.x1;
 | 
			
		||||
@@ -28,7 +28,7 @@ class MaxWidthBox extends St.BoxLayout {
 | 
			
		||||
            adjustedBox.x2 -= Math.floor(excessWidth / 2);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        super.vfunc_allocate(adjustedBox, flags);
 | 
			
		||||
        super.vfunc_allocate(adjustedBox);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -219,8 +219,7 @@ var SearchResultsBase = GObject.registerClass({
 | 
			
		||||
 | 
			
		||||
    _ensureResultActors(results, callback) {
 | 
			
		||||
        let metasNeeded = results.filter(
 | 
			
		||||
            resultId => this._resultDisplays[resultId] === undefined
 | 
			
		||||
        );
 | 
			
		||||
            resultId => this._resultDisplays[resultId] === undefined);
 | 
			
		||||
 | 
			
		||||
        if (metasNeeded.length === 0) {
 | 
			
		||||
            callback(true);
 | 
			
		||||
@@ -349,18 +348,140 @@ class ListSearchResults extends SearchResultsBase {
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var GridSearchResultsLayout = GObject.registerClass({
 | 
			
		||||
    Properties: {
 | 
			
		||||
        'spacing': GObject.ParamSpec.int('spacing', 'Spacing', 'Spacing',
 | 
			
		||||
            GObject.ParamFlags.READWRITE, 0, GLib.MAXINT32, 0),
 | 
			
		||||
    },
 | 
			
		||||
}, class GridSearchResultsLayout extends Clutter.LayoutManager {
 | 
			
		||||
    _init() {
 | 
			
		||||
        super._init();
 | 
			
		||||
        this._spacing = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_set_container(container) {
 | 
			
		||||
        this._container = container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_width(container, forHeight) {
 | 
			
		||||
        let minWidth = 0;
 | 
			
		||||
        let natWidth = 0;
 | 
			
		||||
        let first = true;
 | 
			
		||||
 | 
			
		||||
        for (let child of container) {
 | 
			
		||||
            if (!child.visible)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            const [childMinWidth, childNatWidth] = child.get_preferred_width(forHeight);
 | 
			
		||||
 | 
			
		||||
            minWidth = Math.max(minWidth, childMinWidth);
 | 
			
		||||
            natWidth += childNatWidth;
 | 
			
		||||
 | 
			
		||||
            if (first)
 | 
			
		||||
                first = false;
 | 
			
		||||
            else
 | 
			
		||||
                natWidth += this._spacing;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return [minWidth, natWidth];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_height(container, forWidth) {
 | 
			
		||||
        let minHeight = 0;
 | 
			
		||||
        let natHeight = 0;
 | 
			
		||||
 | 
			
		||||
        for (let child of container) {
 | 
			
		||||
            if (!child.visible)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            const [childMinHeight, childNatHeight] = child.get_preferred_height(forWidth);
 | 
			
		||||
 | 
			
		||||
            minHeight = Math.max(minHeight, childMinHeight);
 | 
			
		||||
            natHeight = Math.max(natHeight, childNatHeight);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return [minHeight, natHeight];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(container, box) {
 | 
			
		||||
        const width = box.get_width();
 | 
			
		||||
 | 
			
		||||
        const childBox = new Clutter.ActorBox();
 | 
			
		||||
        childBox.x1 = 0;
 | 
			
		||||
        childBox.y1 = 0;
 | 
			
		||||
 | 
			
		||||
        let first = true;
 | 
			
		||||
        for (let child of container) {
 | 
			
		||||
            if (!child.visible)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (first)
 | 
			
		||||
                first = false;
 | 
			
		||||
            else
 | 
			
		||||
                childBox.x1 += this._spacing;
 | 
			
		||||
 | 
			
		||||
            const [childWidth] = child.get_preferred_width(-1);
 | 
			
		||||
            const [childHeight] = child.get_preferred_height(-1);
 | 
			
		||||
            childBox.set_size(childWidth, childHeight);
 | 
			
		||||
 | 
			
		||||
            if (childBox.x1 + childWidth > width)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            child.allocate(childBox);
 | 
			
		||||
 | 
			
		||||
            childBox.x1 += childWidth;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    columnsForWidth(width) {
 | 
			
		||||
        if (!this._container)
 | 
			
		||||
            return -1;
 | 
			
		||||
 | 
			
		||||
        const [minWidth] = this.get_preferred_width(this._container, -1);
 | 
			
		||||
 | 
			
		||||
        if (minWidth === 0)
 | 
			
		||||
            return -1;
 | 
			
		||||
 | 
			
		||||
        let nCols = 0;
 | 
			
		||||
        while (width > minWidth) {
 | 
			
		||||
            width -= minWidth;
 | 
			
		||||
            if (nCols > 0)
 | 
			
		||||
                width -= this._spacing;
 | 
			
		||||
            nCols++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return nCols;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get spacing() {
 | 
			
		||||
        return this._spacing;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set spacing(v) {
 | 
			
		||||
        if (this._spacing === v)
 | 
			
		||||
            return;
 | 
			
		||||
        this._spacing = v;
 | 
			
		||||
        this.layout_changed();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var GridSearchResults = GObject.registerClass(
 | 
			
		||||
class GridSearchResults extends SearchResultsBase {
 | 
			
		||||
    _init(provider, resultsView) {
 | 
			
		||||
        super._init(provider, resultsView);
 | 
			
		||||
 | 
			
		||||
        this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
 | 
			
		||||
                                             xAlign: St.Align.START });
 | 
			
		||||
        this._grid = new St.Widget({ style_class: 'grid-search-results' });
 | 
			
		||||
        this._grid.layout_manager = new GridSearchResultsLayout();
 | 
			
		||||
 | 
			
		||||
        this._bin = new St.Bin({ x_align: Clutter.ActorAlign.CENTER });
 | 
			
		||||
        this._bin.set_child(this._grid);
 | 
			
		||||
        this._grid.connect('style-changed', () => {
 | 
			
		||||
            const node = this._grid.get_theme_node();
 | 
			
		||||
            this._grid.layout_manager.spacing = node.get_length('spacing');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._resultDisplayBin.set_child(this._bin);
 | 
			
		||||
        this._resultDisplayBin.set_child(new St.Bin({
 | 
			
		||||
            child: this._grid,
 | 
			
		||||
            x_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDestroy() {
 | 
			
		||||
@@ -400,12 +521,11 @@ class GridSearchResults extends SearchResultsBase {
 | 
			
		||||
        if (width == 0)
 | 
			
		||||
            return -1;
 | 
			
		||||
 | 
			
		||||
        let nCols = this._grid.columnsForWidth(width);
 | 
			
		||||
        return nCols * this._grid.getRowLimit();
 | 
			
		||||
        return this._grid.layout_manager.columnsForWidth(width);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _clearResultDisplay() {
 | 
			
		||||
        this._grid.removeAll();
 | 
			
		||||
        this._grid.remove_all_children();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _createResultDisplay(meta) {
 | 
			
		||||
@@ -414,14 +534,15 @@ class GridSearchResults extends SearchResultsBase {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _addItem(display) {
 | 
			
		||||
        this._grid.addItem(display);
 | 
			
		||||
        this._grid.add_child(display);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getFirstResult() {
 | 
			
		||||
        if (this._grid.visibleItemsCount() > 0)
 | 
			
		||||
            return this._grid.getItemAtIndex(0);
 | 
			
		||||
        else
 | 
			
		||||
            return null;
 | 
			
		||||
        for (let child of this._grid) {
 | 
			
		||||
            if (child.visible)
 | 
			
		||||
                return child;
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -431,6 +552,9 @@ var SearchResultsView = GObject.registerClass({
 | 
			
		||||
    _init() {
 | 
			
		||||
        super._init({ name: 'searchResults', vertical: true });
 | 
			
		||||
 | 
			
		||||
        this._parentalControlsManager = ParentalControlsManager.getDefault();
 | 
			
		||||
        this._parentalControlsManager.connect('app-filter-changed', this._reloadRemoteProviders.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._content = new MaxWidthBox({
 | 
			
		||||
            name: 'searchResultsContent',
 | 
			
		||||
            vertical: true,
 | 
			
		||||
@@ -505,6 +629,11 @@ var SearchResultsView = GObject.registerClass({
 | 
			
		||||
 | 
			
		||||
    _registerProvider(provider) {
 | 
			
		||||
        provider.searchInProgress = false;
 | 
			
		||||
 | 
			
		||||
        // Filter out unwanted providers.
 | 
			
		||||
        if (provider.appInfo && !this._parentalControlsManager.shouldShowApp(provider.appInfo))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._providers.push(provider);
 | 
			
		||||
        this._ensureProviderDisplay(provider);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -295,8 +295,8 @@ var ShellMountPasswordDialog = GObject.registerClass({
 | 
			
		||||
            this._keyfilesLabel = new St.Label({ visible: false });
 | 
			
		||||
            this._keyfilesLabel.clutter_text.set_markup(
 | 
			
		||||
                /* Translators: %s is the Disks application */
 | 
			
		||||
                _("To unlock a volume that uses keyfiles, use the <i>%s</i> utility instead.").format(disksApp.get_name())
 | 
			
		||||
            );
 | 
			
		||||
                _('To unlock a volume that uses keyfiles, use the <i>%s</i> utility instead.')
 | 
			
		||||
               .format(disksApp.get_name()));
 | 
			
		||||
            this._keyfilesLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
 | 
			
		||||
            this._keyfilesLabel.clutter_text.line_wrap = true;
 | 
			
		||||
            content.add_child(this._keyfilesLabel);
 | 
			
		||||
@@ -464,8 +464,7 @@ var ShellMountPasswordDialog = GObject.registerClass({
 | 
			
		||||
                /* Translators: %s is the Disks application */
 | 
			
		||||
                _("Unable to start %s").format(app.get_name()),
 | 
			
		||||
                /* Translators: %s is the Disks application */
 | 
			
		||||
                _("Couldn’t find the %s application").format(app.get_name())
 | 
			
		||||
            );
 | 
			
		||||
                _('Couldn’t find the %s application').format(app.get_name()));
 | 
			
		||||
        }
 | 
			
		||||
        this._onCancelButton();
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/* exported Indicator */
 | 
			
		||||
 | 
			
		||||
const { Gio, GnomeBluetooth, GObject } = imports.gi;
 | 
			
		||||
const { Gio, GLib, GnomeBluetooth, GObject } = imports.gi;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const PanelMenu = imports.ui.panelMenu;
 | 
			
		||||
@@ -35,7 +35,7 @@ class Indicator extends PanelMenu.SystemIndicator {
 | 
			
		||||
 | 
			
		||||
                                                 this._sync();
 | 
			
		||||
                                             });
 | 
			
		||||
        this._proxy.connect('g-properties-changed', this._sync.bind(this));
 | 
			
		||||
        this._proxy.connect('g-properties-changed', this._queueSync.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._item = new PopupMenu.PopupSubMenuMenuItem(_("Bluetooth"), true);
 | 
			
		||||
        this._item.icon.icon_name = 'bluetooth-active-symbolic';
 | 
			
		||||
@@ -49,15 +49,27 @@ class Indicator extends PanelMenu.SystemIndicator {
 | 
			
		||||
        this._item.menu.addSettingsAction(_("Bluetooth Settings"), 'gnome-bluetooth-panel.desktop');
 | 
			
		||||
        this.menu.addMenuItem(this._item);
 | 
			
		||||
 | 
			
		||||
        this._syncId = 0;
 | 
			
		||||
        this._adapter = null;
 | 
			
		||||
 | 
			
		||||
        this._client = new GnomeBluetooth.Client();
 | 
			
		||||
        this._model = this._client.get_model();
 | 
			
		||||
        this._model.connect('row-changed', this._sync.bind(this));
 | 
			
		||||
        this._model.connect('row-deleted', this._sync.bind(this));
 | 
			
		||||
        this._model.connect('row-deleted', this._queueSync.bind(this));
 | 
			
		||||
        this._model.connect('row-changed', this._queueSync.bind(this));
 | 
			
		||||
        this._model.connect('row-inserted', this._sync.bind(this));
 | 
			
		||||
        Main.sessionMode.connect('updated', this._sync.bind(this));
 | 
			
		||||
        this._sync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _setHadSetupDevices(value) {
 | 
			
		||||
        if (this._hadSetupDevices === value)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._hadSetupDevices = value;
 | 
			
		||||
        global.settings.set_boolean(
 | 
			
		||||
            HAD_BLUETOOTH_DEVICES_SETUP, this._hadSetupDevices);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _getDefaultAdapter() {
 | 
			
		||||
        let [ret, iter] = this._model.get_iter_first();
 | 
			
		||||
        while (ret) {
 | 
			
		||||
@@ -72,46 +84,53 @@ class Indicator extends PanelMenu.SystemIndicator {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // nDevices is the number of devices setup for the current default
 | 
			
		||||
    // adapter if one exists and is powered. If unpowered or unavailable,
 | 
			
		||||
    // nDevice is "1" if it had setup devices associated to it the last
 | 
			
		||||
    // time it was seen, and "-1" if not.
 | 
			
		||||
    //
 | 
			
		||||
    // nConnectedDevices is the number of devices connected to the default
 | 
			
		||||
    // adapter if one exists and is powered, or -1 if it's not available.
 | 
			
		||||
    _getNDevices() {
 | 
			
		||||
        let adapter = this._getDefaultAdapter();
 | 
			
		||||
    _getDeviceInfos(adapter) {
 | 
			
		||||
        if (!adapter)
 | 
			
		||||
            return [this._hadSetupDevices ? 1 : -1, -1];
 | 
			
		||||
            return [];
 | 
			
		||||
 | 
			
		||||
        let nConnectedDevices = 0;
 | 
			
		||||
        let nDevices = 0;
 | 
			
		||||
        let deviceInfos = [];
 | 
			
		||||
        let [ret, iter] = this._model.iter_children(adapter);
 | 
			
		||||
        while (ret) {
 | 
			
		||||
            let isConnected = this._model.get_value(iter,
 | 
			
		||||
                                                    GnomeBluetooth.Column.CONNECTED);
 | 
			
		||||
            if (isConnected)
 | 
			
		||||
                nConnectedDevices++;
 | 
			
		||||
            const isPaired = this._model.get_value(iter,
 | 
			
		||||
                GnomeBluetooth.Column.PAIRED);
 | 
			
		||||
            const isTrusted = this._model.get_value(iter,
 | 
			
		||||
                GnomeBluetooth.Column.TRUSTED);
 | 
			
		||||
 | 
			
		||||
            if (isPaired || isTrusted) {
 | 
			
		||||
                deviceInfos.push({
 | 
			
		||||
                    connected: this._model.get_value(iter,
 | 
			
		||||
                        GnomeBluetooth.Column.CONNECTED),
 | 
			
		||||
                    name: this._model.get_value(iter,
 | 
			
		||||
                        GnomeBluetooth.Column.ALIAS),
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let isPaired = this._model.get_value(iter,
 | 
			
		||||
                                                 GnomeBluetooth.Column.PAIRED);
 | 
			
		||||
            let isTrusted = this._model.get_value(iter,
 | 
			
		||||
                                                  GnomeBluetooth.Column.TRUSTED);
 | 
			
		||||
            if (isPaired || isTrusted)
 | 
			
		||||
                nDevices++;
 | 
			
		||||
            ret = this._model.iter_next(iter);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._hadSetupDevices != (nDevices > 0)) {
 | 
			
		||||
            this._hadSetupDevices = !this._hadSetupDevices;
 | 
			
		||||
            global.settings.set_boolean(HAD_BLUETOOTH_DEVICES_SETUP, this._hadSetupDevices);
 | 
			
		||||
        }
 | 
			
		||||
        return deviceInfos;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        return [nDevices, nConnectedDevices];
 | 
			
		||||
    _queueSync() {
 | 
			
		||||
        if (this._syncId)
 | 
			
		||||
            return;
 | 
			
		||||
        this._syncId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
 | 
			
		||||
            this._syncId = 0;
 | 
			
		||||
            this._sync();
 | 
			
		||||
            return GLib.SOURCE_REMOVE;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _sync() {
 | 
			
		||||
        let [nDevices, nConnectedDevices] = this._getNDevices();
 | 
			
		||||
        let adapter = this._getDefaultAdapter();
 | 
			
		||||
        let devices = this._getDeviceInfos(adapter);
 | 
			
		||||
        const connectedDevices = devices.filter(dev => dev.connected);
 | 
			
		||||
        const nConnectedDevices = connectedDevices.length;
 | 
			
		||||
 | 
			
		||||
        if (adapter && this._adapter)
 | 
			
		||||
            this._setHadSetupDevices(devices.length > 0);
 | 
			
		||||
        this._adapter = adapter;
 | 
			
		||||
 | 
			
		||||
        let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
 | 
			
		||||
 | 
			
		||||
        this.menu.setSensitive(sensitive);
 | 
			
		||||
@@ -119,19 +138,21 @@ class Indicator extends PanelMenu.SystemIndicator {
 | 
			
		||||
 | 
			
		||||
        // Remember if there were setup devices and show the menu
 | 
			
		||||
        // if we've seen setup devices and we're not hard blocked
 | 
			
		||||
        if (nDevices > 0)
 | 
			
		||||
        if (this._hadSetupDevices)
 | 
			
		||||
            this._item.visible = !this._proxy.BluetoothHardwareAirplaneMode;
 | 
			
		||||
        else
 | 
			
		||||
            this._item.visible = this._proxy.BluetoothHasAirplaneMode && !this._proxy.BluetoothAirplaneMode;
 | 
			
		||||
 | 
			
		||||
        if (nConnectedDevices > 0)
 | 
			
		||||
        if (nConnectedDevices > 1)
 | 
			
		||||
            /* Translators: this is the number of connected bluetooth devices */
 | 
			
		||||
            this._item.label.text = ngettext("%d Connected", "%d Connected", nConnectedDevices).format(nConnectedDevices);
 | 
			
		||||
        else if (nConnectedDevices == -1)
 | 
			
		||||
            this._item.label.text = _("Off");
 | 
			
		||||
            this._item.label.text = ngettext('%d Connected", "%d Connected', nConnectedDevices).format(nConnectedDevices);
 | 
			
		||||
        else if (nConnectedDevices === 1)
 | 
			
		||||
            this._item.label.text = connectedDevices[0].name;
 | 
			
		||||
        else if (adapter === null)
 | 
			
		||||
            this._item.label.text = _('Bluetooth Off');
 | 
			
		||||
        else
 | 
			
		||||
            this._item.label.text = _("On");
 | 
			
		||||
            this._item.label.text = _('Bluetooth On');
 | 
			
		||||
 | 
			
		||||
        this._toggleItem.label.text = this._proxy.BluetoothAirplaneMode ? _("Turn On") : _("Turn Off");
 | 
			
		||||
        this._toggleItem.label.text = this._proxy.BluetoothAirplaneMode ? _('Turn On') : _('Turn Off');
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -199,36 +199,36 @@ var InputSourceSystemSettings = class extends InputSourceSettings {
 | 
			
		||||
                                         this._reload.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _reload() {
 | 
			
		||||
        Gio.DBus.system.call(this._BUS_NAME,
 | 
			
		||||
                             this._BUS_PATH,
 | 
			
		||||
                             this._BUS_PROPS_IFACE,
 | 
			
		||||
                             'GetAll',
 | 
			
		||||
                             new GLib.Variant('(s)', [this._BUS_IFACE]),
 | 
			
		||||
                             null, Gio.DBusCallFlags.NONE, -1, null,
 | 
			
		||||
                             (conn, result) => {
 | 
			
		||||
                                 let props;
 | 
			
		||||
                                 try {
 | 
			
		||||
                                     props = conn.call_finish(result).deep_unpack()[0];
 | 
			
		||||
                                 } catch (e) {
 | 
			
		||||
                                     log('Could not get properties from %s'.format(this._BUS_NAME));
 | 
			
		||||
                                     return;
 | 
			
		||||
                                 }
 | 
			
		||||
                                 let layouts = props['X11Layout'].unpack();
 | 
			
		||||
                                 let variants = props['X11Variant'].unpack();
 | 
			
		||||
                                 let options = props['X11Options'].unpack();
 | 
			
		||||
    async _reload() {
 | 
			
		||||
        let props;
 | 
			
		||||
        try {
 | 
			
		||||
            const result = await Gio.DBus.system.call(
 | 
			
		||||
                this._BUS_NAME,
 | 
			
		||||
                this._BUS_PATH,
 | 
			
		||||
                this._BUS_PROPS_IFACE,
 | 
			
		||||
                'GetAll',
 | 
			
		||||
                new GLib.Variant('(s)', [this._BUS_IFACE]),
 | 
			
		||||
                null, Gio.DBusCallFlags.NONE, -1, null);
 | 
			
		||||
            [props] = result.deep_unpack();
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            log('Could not get properties from %s'.format(this._BUS_NAME));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
                                 if (layouts != this._layouts ||
 | 
			
		||||
                                     variants != this._variants) {
 | 
			
		||||
                                     this._layouts = layouts;
 | 
			
		||||
                                     this._variants = variants;
 | 
			
		||||
                                     this._emitInputSourcesChanged();
 | 
			
		||||
                                 }
 | 
			
		||||
                                 if (options != this._options) {
 | 
			
		||||
                                     this._options = options;
 | 
			
		||||
                                     this._emitKeyboardOptionsChanged();
 | 
			
		||||
                                 }
 | 
			
		||||
                             });
 | 
			
		||||
        const layouts = props['X11Layout'].unpack();
 | 
			
		||||
        const variants = props['X11Variant'].unpack();
 | 
			
		||||
        const options = props['X11Options'].unpack();
 | 
			
		||||
 | 
			
		||||
        if (layouts !== this._layouts ||
 | 
			
		||||
            variants !== this._variants) {
 | 
			
		||||
            this._layouts = layouts;
 | 
			
		||||
            this._variants = variants;
 | 
			
		||||
            this._emitInputSourcesChanged();
 | 
			
		||||
        }
 | 
			
		||||
        if (options !== this._options) {
 | 
			
		||||
            this._options = options;
 | 
			
		||||
            this._emitKeyboardOptionsChanged();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get inputSources() {
 | 
			
		||||
@@ -805,8 +805,8 @@ class InputSourceIndicatorContainer extends St.Widget {
 | 
			
		||||
        }, [0, 0]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
        this.set_allocation(box, flags);
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        this.set_allocation(box);
 | 
			
		||||
 | 
			
		||||
        // translate box to (0, 0)
 | 
			
		||||
        box.x2 -= box.x1;
 | 
			
		||||
@@ -815,7 +815,7 @@ class InputSourceIndicatorContainer extends St.Widget {
 | 
			
		||||
        box.y1 = 0;
 | 
			
		||||
 | 
			
		||||
        this.get_children().forEach(c => {
 | 
			
		||||
            c.allocate_align_fill(box, 0.5, 0.5, false, false, flags);
 | 
			
		||||
            c.allocate_align_fill(box, 0.5, 0.5, false, false);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -225,10 +225,6 @@ class Indicator extends PanelMenu.SystemIndicator {
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function clamp(value, min, max) {
 | 
			
		||||
    return Math.max(min, Math.min(max, value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var AppAuthorizer = class {
 | 
			
		||||
    constructor(desktopId, reqAccuracyLevel, permStoreProxy, maxAccuracyLevel) {
 | 
			
		||||
        this.desktopId = desktopId;
 | 
			
		||||
@@ -313,9 +309,8 @@ var AppAuthorizer = class {
 | 
			
		||||
 | 
			
		||||
    _completeAuth() {
 | 
			
		||||
        if (this._accuracyLevel != GeoclueAccuracyLevel.NONE) {
 | 
			
		||||
            this._accuracyLevel = clamp(this._accuracyLevel,
 | 
			
		||||
                                        0,
 | 
			
		||||
                                        this._maxAccuracyLevel);
 | 
			
		||||
            this._accuracyLevel = Math.clamp(this._accuracyLevel,
 | 
			
		||||
                0, this._maxAccuracyLevel);
 | 
			
		||||
        }
 | 
			
		||||
        this._saveToPermissionStore();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,10 @@ const Util = imports.misc.util;
 | 
			
		||||
 | 
			
		||||
const { loadInterfaceXML } = imports.misc.fileUtils;
 | 
			
		||||
 | 
			
		||||
Gio._promisify(NM.Client, 'new_async', 'new_finish');
 | 
			
		||||
Gio._promisify(NM.Client.prototype,
 | 
			
		||||
    'check_connectivity_async', 'check_connectivity_finish');
 | 
			
		||||
 | 
			
		||||
const NMConnectionCategory = {
 | 
			
		||||
    INVALID: 'invalid',
 | 
			
		||||
    WIRED: 'wired',
 | 
			
		||||
@@ -712,8 +716,7 @@ class NMWirelessDialog extends ModalDialog.ModalDialog {
 | 
			
		||||
 | 
			
		||||
        let connections = client.get_connections();
 | 
			
		||||
        this._connections = connections.filter(
 | 
			
		||||
            connection => device.connection_valid(connection)
 | 
			
		||||
        );
 | 
			
		||||
            connection => device.connection_valid(connection));
 | 
			
		||||
 | 
			
		||||
        this._apAddedId = device.connect('access-point-added', this._accessPointAdded.bind(this));
 | 
			
		||||
        this._apRemovedId = device.connect('access-point-removed', this._accessPointRemoved.bind(this));
 | 
			
		||||
@@ -1627,11 +1630,11 @@ class Indicator extends PanelMenu.SystemIndicator {
 | 
			
		||||
        this._ctypes[NM.SETTING_GSM_SETTING_NAME] = NMConnectionCategory.WWAN;
 | 
			
		||||
        this._ctypes[NM.SETTING_VPN_SETTING_NAME] = NMConnectionCategory.VPN;
 | 
			
		||||
 | 
			
		||||
        NM.Client.new_async(null, this._clientGot.bind(this));
 | 
			
		||||
        this._getClient();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _clientGot(obj, result) {
 | 
			
		||||
        this._client = NM.Client.new_finish(result);
 | 
			
		||||
    async _getClient() {
 | 
			
		||||
        this._client = await NM.Client.new_async(null);
 | 
			
		||||
 | 
			
		||||
        this._activeConnections = [];
 | 
			
		||||
        this._connections = [];
 | 
			
		||||
@@ -1859,8 +1862,7 @@ class Indicator extends PanelMenu.SystemIndicator {
 | 
			
		||||
    _syncVpnConnections() {
 | 
			
		||||
        let activeConnections = this._client.get_active_connections() || [];
 | 
			
		||||
        let vpnConnections = activeConnections.filter(
 | 
			
		||||
            a => a instanceof NM.VpnConnection
 | 
			
		||||
        );
 | 
			
		||||
            a => a instanceof NM.VpnConnection);
 | 
			
		||||
        vpnConnections.forEach(a => {
 | 
			
		||||
            ensureActiveConnectionProps(a);
 | 
			
		||||
        });
 | 
			
		||||
@@ -1982,7 +1984,7 @@ class Indicator extends PanelMenu.SystemIndicator {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _portalHelperDone(proxy, emitter, parameters) {
 | 
			
		||||
    async _portalHelperDone(proxy, emitter, parameters) {
 | 
			
		||||
        let [path, result] = parameters;
 | 
			
		||||
 | 
			
		||||
        if (result == PortalHelperResult.CANCELLED) {
 | 
			
		||||
@@ -1993,13 +1995,11 @@ class Indicator extends PanelMenu.SystemIndicator {
 | 
			
		||||
        } else if (result == PortalHelperResult.COMPLETED) {
 | 
			
		||||
            this._closeConnectivityCheck(path);
 | 
			
		||||
        } else if (result == PortalHelperResult.RECHECK) {
 | 
			
		||||
            this._client.check_connectivity_async(null, (client, res) => {
 | 
			
		||||
                try {
 | 
			
		||||
                    let state = client.check_connectivity_finish(res);
 | 
			
		||||
                    if (state >= NM.ConnectivityState.FULL)
 | 
			
		||||
                        this._closeConnectivityCheck(path);
 | 
			
		||||
                } catch (e) { }
 | 
			
		||||
            });
 | 
			
		||||
            try {
 | 
			
		||||
                const state = await this._client.check_connectivity_async(null);
 | 
			
		||||
                if (state >= NM.ConnectivityState.FULL)
 | 
			
		||||
                    this._closeConnectivityCheck(path);
 | 
			
		||||
            } catch (e) { }
 | 
			
		||||
        } else {
 | 
			
		||||
            log('Invalid result from portal helper: %s'.format(result));
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -139,7 +139,7 @@ class Indicator extends PanelMenu.SystemIndicator {
 | 
			
		||||
            label = _("%d\u2009%%").format(100);
 | 
			
		||||
        else
 | 
			
		||||
            label = _("%d\u2009%%").format(this._proxy.Percentage);
 | 
			
		||||
        this._percentageLabel.clutter_text.set_markup('<span size="smaller">' + label + '</span>');
 | 
			
		||||
        this._percentageLabel.text = label;
 | 
			
		||||
 | 
			
		||||
        // The status label
 | 
			
		||||
        this._item.label.text = this._getStatus();
 | 
			
		||||
 
 | 
			
		||||
@@ -11,8 +11,7 @@ class RemoteAccessApplet extends PanelMenu.SystemIndicator {
 | 
			
		||||
    _init() {
 | 
			
		||||
        super._init();
 | 
			
		||||
 | 
			
		||||
        let backend = Meta.get_backend();
 | 
			
		||||
        let controller = backend.get_remote_access_controller();
 | 
			
		||||
        let controller = global.backend.get_remote_access_controller();
 | 
			
		||||
 | 
			
		||||
        if (!controller)
 | 
			
		||||
            return;
 | 
			
		||||
 
 | 
			
		||||
@@ -86,8 +86,6 @@ class Indicator extends PanelMenu.SystemIndicator {
 | 
			
		||||
 | 
			
		||||
        Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
 | 
			
		||||
        this._sessionUpdated();
 | 
			
		||||
 | 
			
		||||
        this._sync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _sessionUpdated() {
 | 
			
		||||
 
 | 
			
		||||
@@ -82,8 +82,7 @@ class Indicator extends PanelMenu.SystemIndicator {
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let app = this._settingsApp = Shell.AppSystem.get_default().lookup_app(
 | 
			
		||||
            'gnome-control-center.desktop'
 | 
			
		||||
        );
 | 
			
		||||
            'gnome-control-center.desktop');
 | 
			
		||||
        if (app) {
 | 
			
		||||
            let [icon, name] = [app.app_info.get_icon().names[0],
 | 
			
		||||
                                app.get_name()];
 | 
			
		||||
 
 | 
			
		||||
@@ -52,22 +52,21 @@ const BOLT_DBUS_PATH = '/org/freedesktop/bolt';
 | 
			
		||||
var Client = class {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this._proxy = null;
 | 
			
		||||
        let nodeInfo = Gio.DBusNodeInfo.new_for_xml(BoltClientInterface);
 | 
			
		||||
        Gio.DBusProxy.new(Gio.DBus.system,
 | 
			
		||||
                          Gio.DBusProxyFlags.DO_NOT_AUTO_START,
 | 
			
		||||
                          nodeInfo.lookup_interface(BOLT_DBUS_CLIENT_IFACE),
 | 
			
		||||
                          BOLT_DBUS_NAME,
 | 
			
		||||
                          BOLT_DBUS_PATH,
 | 
			
		||||
                          BOLT_DBUS_CLIENT_IFACE,
 | 
			
		||||
                          null,
 | 
			
		||||
                          this._onProxyReady.bind(this));
 | 
			
		||||
 | 
			
		||||
        this.probing = false;
 | 
			
		||||
        this._getProxy();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onProxyReady(o, res) {
 | 
			
		||||
    async _getProxy() {
 | 
			
		||||
        let nodeInfo = Gio.DBusNodeInfo.new_for_xml(BoltClientInterface);
 | 
			
		||||
        try {
 | 
			
		||||
            this._proxy = Gio.DBusProxy.new_finish(res);
 | 
			
		||||
            this._proxy = await Gio.DBusProxy.new(
 | 
			
		||||
                Gio.DBus.system,
 | 
			
		||||
                Gio.DBusProxyFlags.DO_NOT_AUTO_START,
 | 
			
		||||
                nodeInfo.lookup_interface(BOLT_DBUS_CLIENT_IFACE),
 | 
			
		||||
                BOLT_DBUS_NAME,
 | 
			
		||||
                BOLT_DBUS_PATH,
 | 
			
		||||
                BOLT_DBUS_CLIENT_IFACE,
 | 
			
		||||
                null);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            log('error creating bolt proxy: %s'.format(e.message));
 | 
			
		||||
            return;
 | 
			
		||||
@@ -243,14 +242,15 @@ class Indicator extends PanelMenu.SystemIndicator {
 | 
			
		||||
 | 
			
		||||
        this._source = null;
 | 
			
		||||
        this._perm = null;
 | 
			
		||||
        this._createPermission();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        Polkit.Permission.new('org.freedesktop.bolt.enroll', null, null, (source, res) => {
 | 
			
		||||
            try {
 | 
			
		||||
                this._perm = Polkit.Permission.new_finish(res);
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                log('Failed to get PolKit permission: %s'.format(e.toString()));
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    async _createPermission() {
 | 
			
		||||
        try {
 | 
			
		||||
            this._perm = await Polkit.Permission.new('org.freedesktop.bolt.enroll', null, null);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            log('Failed to get PolKit permission: %s'.format(e.toString()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDestroy() {
 | 
			
		||||
 
 | 
			
		||||
@@ -28,10 +28,6 @@ const State = {
 | 
			
		||||
    SCROLLING: 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function clamp(value, min, max) {
 | 
			
		||||
    return Math.max(min, Math.min(max, value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const TouchpadSwipeGesture = GObject.registerClass({
 | 
			
		||||
    Properties: {
 | 
			
		||||
        'enabled': GObject.ParamSpec.boolean(
 | 
			
		||||
@@ -558,8 +554,8 @@ var SwipeTracker = GObject.registerClass({
 | 
			
		||||
 | 
			
		||||
        let firstPoint = this._snapPoints[0];
 | 
			
		||||
        let lastPoint = this._snapPoints[this._snapPoints.length - 1];
 | 
			
		||||
        this._progress = clamp(this._progress, firstPoint, lastPoint);
 | 
			
		||||
        this._progress = clamp(this._progress,
 | 
			
		||||
        this._progress = Math.clamp(this._progress, firstPoint, lastPoint);
 | 
			
		||||
        this._progress = Math.clamp(this._progress,
 | 
			
		||||
            this._initialProgress - 1, this._initialProgress + 1);
 | 
			
		||||
 | 
			
		||||
        this.emit('update', this._progress);
 | 
			
		||||
@@ -606,7 +602,7 @@ var SwipeTracker = GObject.registerClass({
 | 
			
		||||
 | 
			
		||||
        let duration = Math.abs((this._progress - endProgress) / velocity * DURATION_MULTIPLIER);
 | 
			
		||||
        if (duration > 0) {
 | 
			
		||||
            duration = clamp(duration,
 | 
			
		||||
            duration = Math.clamp(duration,
 | 
			
		||||
                MIN_ANIMATION_DURATION, MAX_ANIMATION_DURATION);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -66,8 +66,8 @@ var SwitcherPopup = GObject.registerClass({
 | 
			
		||||
        this._disableHover();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
        this.set_allocation(box, flags);
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        this.set_allocation(box);
 | 
			
		||||
 | 
			
		||||
        let childBox = new Clutter.ActorBox();
 | 
			
		||||
        let primary = Main.layoutManager.primaryMonitor;
 | 
			
		||||
@@ -84,7 +84,7 @@ var SwitcherPopup = GObject.registerClass({
 | 
			
		||||
        childBox.x2 = Math.min(primary.x + primary.width - rightPadding, childBox.x1 + childNaturalWidth);
 | 
			
		||||
        childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
 | 
			
		||||
        childBox.y2 = childBox.y1 + childNaturalHeight;
 | 
			
		||||
        this._switcherList.allocate(childBox, flags);
 | 
			
		||||
        this._switcherList.allocate(childBox);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _initialSelection(backward, _binding) {
 | 
			
		||||
@@ -317,7 +317,7 @@ var SwitcherPopup = GObject.registerClass({
 | 
			
		||||
            this.ease({
 | 
			
		||||
                opacity: 0,
 | 
			
		||||
                duration: POPUP_FADE_OUT_TIME,
 | 
			
		||||
                mode: Clutter.Animation.EASE_OUT_QUAD,
 | 
			
		||||
                mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
                onComplete: () => this.destroy(),
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -591,8 +591,8 @@ var SwitcherList = GObject.registerClass({
 | 
			
		||||
        return themeNode.adjust_preferred_height(maxChildMin, maxChildNat);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
        this.set_allocation(box, flags);
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        this.set_allocation(box);
 | 
			
		||||
 | 
			
		||||
        let contentBox = this.get_theme_node().get_content_box(box);
 | 
			
		||||
        let width = contentBox.x2 - contentBox.x1;
 | 
			
		||||
@@ -606,7 +606,7 @@ var SwitcherList = GObject.registerClass({
 | 
			
		||||
        let childBox = new Clutter.ActorBox();
 | 
			
		||||
        let scrollable = minListWidth > width;
 | 
			
		||||
 | 
			
		||||
        this._scrollView.allocate(contentBox, flags);
 | 
			
		||||
        this._scrollView.allocate(contentBox);
 | 
			
		||||
 | 
			
		||||
        let arrowWidth = Math.floor(leftPadding / 3);
 | 
			
		||||
        let arrowHeight = arrowWidth * 2;
 | 
			
		||||
@@ -614,7 +614,7 @@ var SwitcherList = GObject.registerClass({
 | 
			
		||||
        childBox.y1 = this.height / 2 - arrowWidth;
 | 
			
		||||
        childBox.x2 = childBox.x1 + arrowWidth;
 | 
			
		||||
        childBox.y2 = childBox.y1 + arrowHeight;
 | 
			
		||||
        this._leftArrow.allocate(childBox, flags);
 | 
			
		||||
        this._leftArrow.allocate(childBox);
 | 
			
		||||
        this._leftArrow.opacity = this._scrollableLeft && scrollable ? 255 : 0;
 | 
			
		||||
 | 
			
		||||
        arrowWidth = Math.floor(rightPadding / 3);
 | 
			
		||||
@@ -623,7 +623,7 @@ var SwitcherList = GObject.registerClass({
 | 
			
		||||
        childBox.y1 = this.height / 2 - arrowWidth;
 | 
			
		||||
        childBox.x2 = childBox.x1 + arrowWidth;
 | 
			
		||||
        childBox.y2 = childBox.y1 + arrowHeight;
 | 
			
		||||
        this._rightArrow.allocate(childBox, flags);
 | 
			
		||||
        this._rightArrow.allocate(childBox);
 | 
			
		||||
        this._rightArrow.opacity = this._scrollableRight && scrollable ? 255 : 0;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										228
									
								
								js/ui/tweener.js
									
									
									
									
									
								
							
							
						
						
									
										228
									
								
								js/ui/tweener.js
									
									
									
									
									
								
							@@ -1,228 +0,0 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/* exported init, addCaller, addTween, getTweenCount, removeTweens,
 | 
			
		||||
            pauseTweens, resumeTweens, registerSpecialProperty,
 | 
			
		||||
            registerSpecialPropertyModifier, registerSpecialPropertySplitter */
 | 
			
		||||
 | 
			
		||||
const { Clutter, GLib, Shell } = imports.gi;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Tweener = imports.tweener.tweener;
 | 
			
		||||
 | 
			
		||||
const { adjustAnimationTime } = imports.ui.environment;
 | 
			
		||||
 | 
			
		||||
// This is a wrapper around imports.tweener.tweener that adds a bit of
 | 
			
		||||
// Clutter integration. If the tweening target is a Clutter.Actor, then
 | 
			
		||||
// the tweenings will automatically be removed if the actor is destroyed.
 | 
			
		||||
 | 
			
		||||
// ActionScript Tweener methods that imports.tweener.tweener doesn't
 | 
			
		||||
// currently implement: getTweens, getVersion, registerTransition,
 | 
			
		||||
// setTimeScale, updateTime.
 | 
			
		||||
 | 
			
		||||
// imports.tweener.tweener methods that we don't re-export:
 | 
			
		||||
// pauseAllTweens, removeAllTweens, resumeAllTweens. (It would be hard
 | 
			
		||||
// to clean up properly after removeAllTweens, and also, any code that
 | 
			
		||||
// calls any of these is almost certainly wrong anyway, because they
 | 
			
		||||
// affect the entire application.)
 | 
			
		||||
 | 
			
		||||
// Called from Main.start
 | 
			
		||||
function init() {
 | 
			
		||||
    Tweener.setFrameTicker(new ClutterFrameTicker());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function addCaller(target, tweeningParameters) {
 | 
			
		||||
    _wrapTweening(target, tweeningParameters);
 | 
			
		||||
    Tweener.addCaller(target, tweeningParameters);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function addTween(target, tweeningParameters) {
 | 
			
		||||
    _wrapTweening(target, tweeningParameters);
 | 
			
		||||
    Tweener.addTween(target, tweeningParameters);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _wrapTweening(target, tweeningParameters) {
 | 
			
		||||
    let state = _getTweenState(target);
 | 
			
		||||
 | 
			
		||||
    if (!state.destroyedId) {
 | 
			
		||||
        if (target instanceof Clutter.Actor) {
 | 
			
		||||
            state.actor = target;
 | 
			
		||||
            state.destroyedId = target.connect('destroy', _actorDestroyed);
 | 
			
		||||
        } else if (target.actor && target.actor instanceof Clutter.Actor) {
 | 
			
		||||
            state.actor = target.actor;
 | 
			
		||||
            state.destroyedId = target.actor.connect('destroy', () => _actorDestroyed(target));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let { time, delay } = tweeningParameters;
 | 
			
		||||
    if (!isNaN(time))
 | 
			
		||||
        tweeningParameters['time'] = adjustAnimationTime(1000 * time) / 1000;
 | 
			
		||||
    if (!isNaN(delay))
 | 
			
		||||
        tweeningParameters['delay'] = adjustAnimationTime(1000 * delay) / 1000;
 | 
			
		||||
 | 
			
		||||
    _addHandler(target, tweeningParameters, 'onComplete', _tweenCompleted);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _getTweenState(target) {
 | 
			
		||||
    // If we were paranoid, we could keep a plist mapping targets to
 | 
			
		||||
    // states... but we're not that paranoid.
 | 
			
		||||
    if (!target.__ShellTweenerState)
 | 
			
		||||
        target.__ShellTweenerState = {};
 | 
			
		||||
    return target.__ShellTweenerState;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _resetTweenState(target) {
 | 
			
		||||
    let state = target.__ShellTweenerState;
 | 
			
		||||
 | 
			
		||||
    if (state) {
 | 
			
		||||
        if (state.destroyedId)
 | 
			
		||||
            state.actor.disconnect(state.destroyedId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    target.__ShellTweenerState = {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _addHandler(target, params, name, handler) {
 | 
			
		||||
    if (params[name]) {
 | 
			
		||||
        let oldHandler = params[name];
 | 
			
		||||
        let oldScope = params[`${name}Scope`];
 | 
			
		||||
        let oldParams = params[`${name}Params`];
 | 
			
		||||
        let eventScope = oldScope ? oldScope : target;
 | 
			
		||||
 | 
			
		||||
        params[name] = () => {
 | 
			
		||||
            oldHandler.apply(eventScope, oldParams);
 | 
			
		||||
            handler(target);
 | 
			
		||||
        };
 | 
			
		||||
    } else {
 | 
			
		||||
        params[name] = () => handler(target);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _actorDestroyed(target) {
 | 
			
		||||
    _resetTweenState(target);
 | 
			
		||||
    Tweener.removeTweens(target);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _tweenCompleted(target) {
 | 
			
		||||
    if (!isTweening(target))
 | 
			
		||||
        _resetTweenState(target);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getTweenCount(scope) {
 | 
			
		||||
    return Tweener.getTweenCount(scope);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// imports.tweener.tweener doesn't provide this method (which exists
 | 
			
		||||
// in the ActionScript version) but it's easy to implement.
 | 
			
		||||
function isTweening(scope) {
 | 
			
		||||
    return Tweener.getTweenCount(scope) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function removeTweens(...args) {
 | 
			
		||||
    if (Tweener.removeTweens(args)) {
 | 
			
		||||
        let [scope] = args;
 | 
			
		||||
        // If we just removed the last active tween, clean up
 | 
			
		||||
        if (Tweener.getTweenCount(scope) == 0)
 | 
			
		||||
            _tweenCompleted(scope);
 | 
			
		||||
        return true;
 | 
			
		||||
    } else {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function pauseTweens(...args) {
 | 
			
		||||
    return Tweener.pauseTweens(...args);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function resumeTweens(...args) {
 | 
			
		||||
    return Tweener.resumeTweens(...args);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function registerSpecialProperty(...args) {
 | 
			
		||||
    Tweener.registerSpecialProperty(...args);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function registerSpecialPropertyModifier(name, modifyFunction, getFunction) {
 | 
			
		||||
    Tweener.registerSpecialPropertyModifier(name, modifyFunction, getFunction);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function registerSpecialPropertySplitter(name, splitFunction, parameters) {
 | 
			
		||||
    Tweener.registerSpecialPropertySplitter(name, splitFunction, parameters);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// The 'FrameTicker' object is an object used to feed new frames to
 | 
			
		||||
// Tweener so it can update values and redraw. The default frame
 | 
			
		||||
// ticker for Tweener just uses a simple timeout at a fixed frame rate
 | 
			
		||||
// and has no idea of "catching up" by dropping frames.
 | 
			
		||||
//
 | 
			
		||||
// We substitute it with custom frame ticker here that connects
 | 
			
		||||
// Tweener to a Clutter.TimeLine. Now, Clutter.Timeline itself isn't a
 | 
			
		||||
// whole lot more sophisticated than a simple timeout at a fixed frame
 | 
			
		||||
// rate, but at least it knows how to drop frames. (See
 | 
			
		||||
// HippoAnimationManager for a more sophisticated view of continuous
 | 
			
		||||
// time updates; even better is to pay attention to the vertical
 | 
			
		||||
// vblank and sync to that when possible.)
 | 
			
		||||
//
 | 
			
		||||
var ClutterFrameTicker = class {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        // We don't have a finite duration; tweener will tell us to stop
 | 
			
		||||
        // when we need to stop, so use 1000 seconds as "infinity", and
 | 
			
		||||
        // set the timeline to loop. Doing this means we have to track
 | 
			
		||||
        // time ourselves, since clutter timeline's time will cycle
 | 
			
		||||
        // instead of strictly increase.
 | 
			
		||||
        this._timeline = new Clutter.Timeline({ duration: 1000 * 1000 });
 | 
			
		||||
        this._timeline.set_loop(true);
 | 
			
		||||
        this._startTime = -1;
 | 
			
		||||
        this._currentTime = -1;
 | 
			
		||||
 | 
			
		||||
        this._timeline.connect('new-frame', () => {
 | 
			
		||||
            this._onNewFrame();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let perfLog = Shell.PerfLog.get_default();
 | 
			
		||||
        perfLog.define_event("tweener.framePrepareStart",
 | 
			
		||||
                             "Start of a new animation frame",
 | 
			
		||||
                             "");
 | 
			
		||||
        perfLog.define_event("tweener.framePrepareDone",
 | 
			
		||||
                             "Finished preparing frame",
 | 
			
		||||
                             "");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get FRAME_RATE() {
 | 
			
		||||
        return 60;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onNewFrame() {
 | 
			
		||||
        // If there is a lot of setup to start the animation, then
 | 
			
		||||
        // first frame number we get from clutter might be a long ways
 | 
			
		||||
        // into the animation (or the animation might even be done).
 | 
			
		||||
        // That looks bad, so we always start at the first frame of the
 | 
			
		||||
        // animation then only do frame dropping from there.
 | 
			
		||||
        if (this._startTime < 0)
 | 
			
		||||
            this._startTime = GLib.get_monotonic_time() / 1000.0;
 | 
			
		||||
 | 
			
		||||
        // currentTime is in milliseconds
 | 
			
		||||
        let perfLog = Shell.PerfLog.get_default();
 | 
			
		||||
        this._currentTime = GLib.get_monotonic_time() / 1000.0 - this._startTime;
 | 
			
		||||
        perfLog.event("tweener.framePrepareStart");
 | 
			
		||||
        this.emit('prepare-frame');
 | 
			
		||||
        perfLog.event("tweener.framePrepareDone");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getTime() {
 | 
			
		||||
        return this._currentTime;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    start() {
 | 
			
		||||
        this._timeline.start();
 | 
			
		||||
        global.begin_work();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    stop() {
 | 
			
		||||
        this._timeline.stop();
 | 
			
		||||
        this._startTime = -1;
 | 
			
		||||
        this._currentTime = -1;
 | 
			
		||||
        global.end_work();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
Signals.addSignalMethods(ClutterFrameTicker.prototype);
 | 
			
		||||
@@ -405,7 +405,7 @@ class UnlockDialogLayout extends Clutter.LayoutManager {
 | 
			
		||||
        return this._stack.get_preferred_height(forWidth);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(container, box, flags) {
 | 
			
		||||
    vfunc_allocate(container, box) {
 | 
			
		||||
        let [width, height] = box.get_size();
 | 
			
		||||
 | 
			
		||||
        let tenthOfHeight = height / 10.0;
 | 
			
		||||
@@ -432,7 +432,7 @@ class UnlockDialogLayout extends Clutter.LayoutManager {
 | 
			
		||||
        actorBox.x2 = columnX1 + columnWidth;
 | 
			
		||||
        actorBox.y2 = actorBox.y1 + maxNotificationsHeight;
 | 
			
		||||
 | 
			
		||||
        this._notifications.allocate(actorBox, flags);
 | 
			
		||||
        this._notifications.allocate(actorBox);
 | 
			
		||||
 | 
			
		||||
        // Authentication Box
 | 
			
		||||
        let stackY = Math.min(
 | 
			
		||||
@@ -444,7 +444,7 @@ class UnlockDialogLayout extends Clutter.LayoutManager {
 | 
			
		||||
        actorBox.x2 = columnX1 + columnWidth;
 | 
			
		||||
        actorBox.y2 = stackY + stackHeight;
 | 
			
		||||
 | 
			
		||||
        this._stack.allocate(actorBox, flags);
 | 
			
		||||
        this._stack.allocate(actorBox);
 | 
			
		||||
 | 
			
		||||
        // Switch User button
 | 
			
		||||
        if (this._switchUserButton.visible) {
 | 
			
		||||
@@ -461,7 +461,7 @@ class UnlockDialogLayout extends Clutter.LayoutManager {
 | 
			
		||||
            actorBox.x2 = actorBox.x1 + natWidth;
 | 
			
		||||
            actorBox.y2 = actorBox.y1 + natHeight;
 | 
			
		||||
 | 
			
		||||
            this._switchUserButton.allocate(actorBox, flags);
 | 
			
		||||
            this._switchUserButton.allocate(actorBox);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
@@ -524,10 +524,6 @@ var UnlockDialog = GObject.registerClass({
 | 
			
		||||
 | 
			
		||||
        this._bgManagers = [];
 | 
			
		||||
 | 
			
		||||
        const themeContext = St.ThemeContext.get_for_stage(global.stage);
 | 
			
		||||
        this._scaleChangedId = themeContext.connect('notify::scale-factor',
 | 
			
		||||
            () => this._updateBackgroundEffects());
 | 
			
		||||
 | 
			
		||||
        this._updateBackgrounds();
 | 
			
		||||
        this._monitorsChangedId =
 | 
			
		||||
            Main.layoutManager.connect('monitors-changed', this._updateBackgrounds.bind(this));
 | 
			
		||||
@@ -630,7 +626,6 @@ var UnlockDialog = GObject.registerClass({
 | 
			
		||||
            y: monitor.y,
 | 
			
		||||
            width: monitor.width,
 | 
			
		||||
            height: monitor.height,
 | 
			
		||||
            effect: new Shell.BlurEffect({ name: 'blur' }),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let bgManager = new Background.BackgroundManager({
 | 
			
		||||
@@ -642,21 +637,19 @@ var UnlockDialog = GObject.registerClass({
 | 
			
		||||
        this._bgManagers.push(bgManager);
 | 
			
		||||
 | 
			
		||||
        this._backgroundGroup.add_child(widget);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateBackgroundEffects() {
 | 
			
		||||
        const themeContext = St.ThemeContext.get_for_stage(global.stage);
 | 
			
		||||
 | 
			
		||||
        for (const widget of this._backgroundGroup.get_children()) {
 | 
			
		||||
            const effect = widget.get_effect('blur');
 | 
			
		||||
        let effect = new Shell.BlurEffect({
 | 
			
		||||
            brightness: BLUR_BRIGHTNESS,
 | 
			
		||||
            sigma: BLUR_SIGMA * themeContext.scale_factor,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
            if (effect) {
 | 
			
		||||
                effect.set({
 | 
			
		||||
                    brightness: BLUR_BRIGHTNESS,
 | 
			
		||||
                    sigma: BLUR_SIGMA * themeContext.scale_factor,
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        this._scaleChangedId = themeContext.connect('notify::scale-factor', () => {
 | 
			
		||||
            effect.sigma = BLUR_SIGMA * themeContext.scale_factor;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        widget.add_effect(effect);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateBackgrounds() {
 | 
			
		||||
@@ -668,7 +661,6 @@ var UnlockDialog = GObject.registerClass({
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < Main.layoutManager.monitors.length; i++)
 | 
			
		||||
            this._createBackground(i);
 | 
			
		||||
        this._updateBackgroundEffects();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _ensureAuthPrompt() {
 | 
			
		||||
 
 | 
			
		||||
@@ -144,8 +144,8 @@ class UserWidgetLabel extends St.Widget {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
        this.set_allocation(box, flags);
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        this.set_allocation(box);
 | 
			
		||||
 | 
			
		||||
        let availWidth = box.x2 - box.x1;
 | 
			
		||||
        let availHeight = box.y2 - box.y1;
 | 
			
		||||
@@ -164,7 +164,7 @@ class UserWidgetLabel extends St.Widget {
 | 
			
		||||
        childBox.x2 = availWidth;
 | 
			
		||||
        childBox.y2 = availHeight;
 | 
			
		||||
 | 
			
		||||
        this._currentLabel.allocate(childBox, flags);
 | 
			
		||||
        this._currentLabel.allocate(childBox);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_paint(paintContext) {
 | 
			
		||||
 
 | 
			
		||||
@@ -132,6 +132,7 @@ var ViewSelector = GObject.registerClass({
 | 
			
		||||
        super._init({
 | 
			
		||||
            name: 'viewSelector',
 | 
			
		||||
            x_expand: true,
 | 
			
		||||
            visible: false,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._showAppsButton = showAppsButton;
 | 
			
		||||
@@ -271,9 +272,10 @@ var ViewSelector = GObject.registerClass({
 | 
			
		||||
        Main.overview.show();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    show() {
 | 
			
		||||
    animateToOverview() {
 | 
			
		||||
        this.show();
 | 
			
		||||
        this.reset();
 | 
			
		||||
        this._workspacesDisplay.show(this._showAppsButton.checked);
 | 
			
		||||
        this._workspacesDisplay.animateToOverview(this._showAppsButton.checked);
 | 
			
		||||
        this._activePage = null;
 | 
			
		||||
        if (this._showAppsButton.checked)
 | 
			
		||||
            this._showPage(this._appsPage);
 | 
			
		||||
@@ -301,9 +303,11 @@ var ViewSelector = GObject.registerClass({
 | 
			
		||||
        this._workspacesDisplay.setWorkspacesFullGeometry(geom);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hide() {
 | 
			
		||||
    vfunc_hide() {
 | 
			
		||||
        this.reset();
 | 
			
		||||
        this._workspacesDisplay.hide();
 | 
			
		||||
 | 
			
		||||
        super.vfunc_hide();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _addPage(actor, name, a11yIcon, params) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1278,13 +1278,13 @@ var WindowManager = class {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _sizeChangeWindow(shellwm, actor, whichChange, oldFrameRect, _oldBufferRect) {
 | 
			
		||||
        let types = [Meta.WindowType.NORMAL];
 | 
			
		||||
        if (!this._shouldAnimateActor(actor, types)) {
 | 
			
		||||
            shellwm.completed_size_change(actor);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        const types = [Meta.WindowType.NORMAL];
 | 
			
		||||
        const shouldAnimate =
 | 
			
		||||
            this._shouldAnimateActor(actor, types) &&
 | 
			
		||||
            oldFrameRect.width > 0 &&
 | 
			
		||||
            oldFrameRect.height > 0;
 | 
			
		||||
 | 
			
		||||
        if (oldFrameRect.width > 0 && oldFrameRect.height > 0)
 | 
			
		||||
        if (shouldAnimate)
 | 
			
		||||
            this._prepareAnimationInfo(shellwm, actor, oldFrameRect, whichChange);
 | 
			
		||||
        else
 | 
			
		||||
            shellwm.completed_size_change(actor);
 | 
			
		||||
@@ -1299,17 +1299,24 @@ var WindowManager = class {
 | 
			
		||||
        actorClone.set_position(oldFrameRect.x, oldFrameRect.y);
 | 
			
		||||
        actorClone.set_size(oldFrameRect.width, oldFrameRect.height);
 | 
			
		||||
 | 
			
		||||
        if (this._clearAnimationInfo(actor))
 | 
			
		||||
        actor.freeze();
 | 
			
		||||
 | 
			
		||||
        if (this._clearAnimationInfo(actor)) {
 | 
			
		||||
            log('Old animationInfo removed from actor %s'.format(actor));
 | 
			
		||||
            this._shellwm.completed_size_change(actor);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let destroyId = actor.connect('destroy', () => {
 | 
			
		||||
            this._clearAnimationInfo(actor);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._resizePending.add(actor);
 | 
			
		||||
        actor.__animationInfo = { clone: actorClone,
 | 
			
		||||
                                  oldRect: oldFrameRect,
 | 
			
		||||
                                  destroyId };
 | 
			
		||||
        actor.__animationInfo = {
 | 
			
		||||
            clone: actorClone,
 | 
			
		||||
            oldRect: oldFrameRect,
 | 
			
		||||
            frozen: true,
 | 
			
		||||
            destroyId,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _sizeChangedWindow(shellwm, actor) {
 | 
			
		||||
@@ -1362,13 +1369,17 @@ var WindowManager = class {
 | 
			
		||||
        // Now unfreeze actor updates, to get it to the new size.
 | 
			
		||||
        // It's important that we don't wait until the animation is completed to
 | 
			
		||||
        // do this, otherwise our scale will be applied to the old texture size.
 | 
			
		||||
        shellwm.completed_size_change(actor);
 | 
			
		||||
        actor.thaw();
 | 
			
		||||
        actor.__animationInfo.frozen = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _clearAnimationInfo(actor) {
 | 
			
		||||
        if (actor.__animationInfo) {
 | 
			
		||||
            actor.__animationInfo.clone.destroy();
 | 
			
		||||
            actor.disconnect(actor.__animationInfo.destroyId);
 | 
			
		||||
            if (actor.__animationInfo.frozen)
 | 
			
		||||
                actor.thaw();
 | 
			
		||||
 | 
			
		||||
            delete actor.__animationInfo;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
@@ -1383,10 +1394,13 @@ var WindowManager = class {
 | 
			
		||||
            actor.translation_x = 0;
 | 
			
		||||
            actor.translation_y = 0;
 | 
			
		||||
            this._clearAnimationInfo(actor);
 | 
			
		||||
            this._shellwm.completed_size_change(actor);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._resizePending.delete(actor))
 | 
			
		||||
        if (this._resizePending.delete(actor)) {
 | 
			
		||||
            this._clearAnimationInfo(actor);
 | 
			
		||||
            this._shellwm.completed_size_change(actor);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _hasAttachedDialogs(window, ignoreWindow) {
 | 
			
		||||
@@ -2101,8 +2115,16 @@ var WindowManager = class {
 | 
			
		||||
            newWs = workspaceManager.get_workspace_by_index(workspaceManager.n_workspaces - 1);
 | 
			
		||||
        } else if (isNaN(target)) {
 | 
			
		||||
            // Prepend a new workspace dynamically
 | 
			
		||||
            if (workspaceManager.get_active_workspace_index() == 0 &&
 | 
			
		||||
                action == 'move' && target == 'up' && this._isWorkspacePrepended == false) {
 | 
			
		||||
            let prependTarget;
 | 
			
		||||
            if (vertical)
 | 
			
		||||
                prependTarget = 'up';
 | 
			
		||||
            else if (rtl)
 | 
			
		||||
                prependTarget = 'right';
 | 
			
		||||
            else
 | 
			
		||||
                prependTarget = 'left';
 | 
			
		||||
            if (workspaceManager.get_active_workspace_index() === 0 &&
 | 
			
		||||
                action === 'move' && target === prependTarget &&
 | 
			
		||||
                this._isWorkspacePrepended === false) {
 | 
			
		||||
                this.insertWorkspace(0);
 | 
			
		||||
                this._isWorkspacePrepended = true;
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										736
									
								
								js/ui/windowPreview.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										736
									
								
								js/ui/windowPreview.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,736 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/* exported WindowPreview */
 | 
			
		||||
 | 
			
		||||
const { Atk, Clutter, GLib, GObject,
 | 
			
		||||
        Graphene, Meta, Pango, Shell, St } = imports.gi;
 | 
			
		||||
 | 
			
		||||
const DND = imports.ui.dnd;
 | 
			
		||||
 | 
			
		||||
var WINDOW_DND_SIZE = 256;
 | 
			
		||||
 | 
			
		||||
var WINDOW_OVERLAY_IDLE_HIDE_TIMEOUT = 750;
 | 
			
		||||
var WINDOW_OVERLAY_FADE_TIME = 200;
 | 
			
		||||
 | 
			
		||||
var DRAGGING_WINDOW_OPACITY = 100;
 | 
			
		||||
 | 
			
		||||
var WindowPreviewLayout = GObject.registerClass({
 | 
			
		||||
    Properties: {
 | 
			
		||||
        'bounding-box': GObject.ParamSpec.boxed(
 | 
			
		||||
            'bounding-box', 'Bounding box', 'Bounding box',
 | 
			
		||||
            GObject.ParamFlags.READABLE,
 | 
			
		||||
            Clutter.ActorBox.$gtype),
 | 
			
		||||
    },
 | 
			
		||||
}, class WindowPreviewLayout extends Clutter.LayoutManager {
 | 
			
		||||
    _init() {
 | 
			
		||||
        super._init();
 | 
			
		||||
 | 
			
		||||
        this._container = null;
 | 
			
		||||
        this._boundingBox = new Clutter.ActorBox();
 | 
			
		||||
        this._windows = new Map();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _layoutChanged() {
 | 
			
		||||
        let frameRect;
 | 
			
		||||
 | 
			
		||||
        for (const windowInfo of this._windows.values()) {
 | 
			
		||||
            const frame = windowInfo.metaWindow.get_frame_rect();
 | 
			
		||||
            frameRect = frameRect ? frameRect.union(frame) : frame;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!frameRect)
 | 
			
		||||
            frameRect = new Meta.Rectangle();
 | 
			
		||||
 | 
			
		||||
        const oldBox = this._boundingBox.copy();
 | 
			
		||||
        this._boundingBox.set_origin(frameRect.x, frameRect.y);
 | 
			
		||||
        this._boundingBox.set_size(frameRect.width, frameRect.height);
 | 
			
		||||
 | 
			
		||||
        if (!this._boundingBox.equal(oldBox))
 | 
			
		||||
            this.notify('bounding-box');
 | 
			
		||||
 | 
			
		||||
        // Always call layout_changed(), a size or position change of an
 | 
			
		||||
        // attached dialog might not affect the boundingBox
 | 
			
		||||
        this.layout_changed();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_set_container(container) {
 | 
			
		||||
        this._container = container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_height(_container, _forWidth) {
 | 
			
		||||
        return [0, this._boundingBox.get_height()];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_width(_container, _forHeight) {
 | 
			
		||||
        return [0, this._boundingBox.get_width()];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(container, box) {
 | 
			
		||||
        // If the scale isn't 1, we weren't allocated our preferred size
 | 
			
		||||
        // and have to scale the children allocations accordingly.
 | 
			
		||||
        const scaleX = box.get_width() / this._boundingBox.get_width();
 | 
			
		||||
        const scaleY = box.get_height() / this._boundingBox.get_height();
 | 
			
		||||
 | 
			
		||||
        const childBox = new Clutter.ActorBox();
 | 
			
		||||
 | 
			
		||||
        for (const child of container) {
 | 
			
		||||
            if (!child.visible)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            const windowInfo = this._windows.get(child);
 | 
			
		||||
            if (windowInfo) {
 | 
			
		||||
                const bufferRect = windowInfo.metaWindow.get_buffer_rect();
 | 
			
		||||
                childBox.set_origin(
 | 
			
		||||
                    bufferRect.x - this._boundingBox.x1,
 | 
			
		||||
                    bufferRect.y - this._boundingBox.y1);
 | 
			
		||||
 | 
			
		||||
                const [, , natWidth, natHeight] = child.get_preferred_size();
 | 
			
		||||
                childBox.set_size(natWidth, natHeight);
 | 
			
		||||
 | 
			
		||||
                childBox.x1 *= scaleX;
 | 
			
		||||
                childBox.x2 *= scaleX;
 | 
			
		||||
                childBox.y1 *= scaleY;
 | 
			
		||||
                childBox.y2 *= scaleY;
 | 
			
		||||
 | 
			
		||||
                child.allocate(childBox);
 | 
			
		||||
            } else {
 | 
			
		||||
                child.allocate_preferred_size();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * addWindow:
 | 
			
		||||
     * @param {Meta.Window} window: the MetaWindow instance
 | 
			
		||||
     *
 | 
			
		||||
     * Creates a ClutterActor drawing the texture of @window and adds it
 | 
			
		||||
     * to the container. If @window is already part of the preview, this
 | 
			
		||||
     * function will do nothing.
 | 
			
		||||
     *
 | 
			
		||||
     * @returns {Clutter.Actor} The newly created actor drawing @window
 | 
			
		||||
     */
 | 
			
		||||
    addWindow(window) {
 | 
			
		||||
        const index = [...this._windows.values()].findIndex(info =>
 | 
			
		||||
            info.metaWindow === window);
 | 
			
		||||
 | 
			
		||||
        if (index !== -1)
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
        const windowActor = window.get_compositor_private();
 | 
			
		||||
        const actor = new Clutter.Clone({ source: windowActor });
 | 
			
		||||
 | 
			
		||||
        this._windows.set(actor, {
 | 
			
		||||
            metaWindow: window,
 | 
			
		||||
            windowActor,
 | 
			
		||||
            sizeChangedId: window.connect('size-changed', () =>
 | 
			
		||||
                this._layoutChanged()),
 | 
			
		||||
            positionChangedId: window.connect('position-changed', () =>
 | 
			
		||||
                this._layoutChanged()),
 | 
			
		||||
            windowActorDestroyId: windowActor.connect('destroy', () =>
 | 
			
		||||
                actor.destroy()),
 | 
			
		||||
            destroyId: actor.connect('destroy', () =>
 | 
			
		||||
                this.removeWindow(window)),
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._container.add_child(actor);
 | 
			
		||||
 | 
			
		||||
        this._layoutChanged();
 | 
			
		||||
 | 
			
		||||
        return actor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * removeWindow:
 | 
			
		||||
     * @param {Meta.Window} window: the window to remove from the preview
 | 
			
		||||
     *
 | 
			
		||||
     * Removes a MetaWindow @window from the preview which has been added
 | 
			
		||||
     * previously using addWindow(). If @window is not part of preview,
 | 
			
		||||
     * this function will do nothing.
 | 
			
		||||
     */
 | 
			
		||||
    removeWindow(window) {
 | 
			
		||||
        const entry = [...this._windows].find(
 | 
			
		||||
            ([, i]) => i.metaWindow === window);
 | 
			
		||||
 | 
			
		||||
        if (!entry)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        const [actor, windowInfo] = entry;
 | 
			
		||||
 | 
			
		||||
        windowInfo.metaWindow.disconnect(windowInfo.sizeChangedId);
 | 
			
		||||
        windowInfo.metaWindow.disconnect(windowInfo.positionChangedId);
 | 
			
		||||
        windowInfo.windowActor.disconnect(windowInfo.windowActorDestroyId);
 | 
			
		||||
        actor.disconnect(windowInfo.destroyId);
 | 
			
		||||
 | 
			
		||||
        this._windows.delete(actor);
 | 
			
		||||
        this._container.remove_child(actor);
 | 
			
		||||
 | 
			
		||||
        this._layoutChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * getWindows:
 | 
			
		||||
     *
 | 
			
		||||
     * Gets an array of all MetaWindows that were added to the layout
 | 
			
		||||
     * using addWindow(), ordered by the insertion order.
 | 
			
		||||
     *
 | 
			
		||||
     * @returns {Array} An array including all windows
 | 
			
		||||
     */
 | 
			
		||||
    getWindows() {
 | 
			
		||||
        return [...this._windows.values()].map(i => i.metaWindow);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // eslint-disable-next-line camelcase
 | 
			
		||||
    get bounding_box() {
 | 
			
		||||
        return this._boundingBox;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var WindowPreview = GObject.registerClass({
 | 
			
		||||
    Signals: {
 | 
			
		||||
        'drag-begin': {},
 | 
			
		||||
        'drag-cancelled': {},
 | 
			
		||||
        'drag-end': {},
 | 
			
		||||
        'selected': { param_types: [GObject.TYPE_UINT] },
 | 
			
		||||
        'show-chrome': {},
 | 
			
		||||
        'size-changed': {},
 | 
			
		||||
    },
 | 
			
		||||
}, class WindowPreview extends St.Widget {
 | 
			
		||||
    _init(metaWindow, workspace) {
 | 
			
		||||
        this.metaWindow = metaWindow;
 | 
			
		||||
        this.metaWindow._delegate = this;
 | 
			
		||||
        this._windowActor = metaWindow.get_compositor_private();
 | 
			
		||||
        this._workspace = workspace;
 | 
			
		||||
 | 
			
		||||
        super._init({
 | 
			
		||||
            reactive: true,
 | 
			
		||||
            can_focus: true,
 | 
			
		||||
            accessible_role: Atk.Role.PUSH_BUTTON,
 | 
			
		||||
            offscreen_redirect: Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._windowContainer = new Clutter.Actor();
 | 
			
		||||
        // gjs currently can't handle setting an actors layout manager during
 | 
			
		||||
        // the initialization of the actor if that layout manager keeps track
 | 
			
		||||
        // of its container, so set the layout manager after creating the
 | 
			
		||||
        // container
 | 
			
		||||
        this._windowContainer.layout_manager = new WindowPreviewLayout();
 | 
			
		||||
        this.add_child(this._windowContainer);
 | 
			
		||||
 | 
			
		||||
        this._addWindow(metaWindow);
 | 
			
		||||
 | 
			
		||||
        this._delegate = this;
 | 
			
		||||
 | 
			
		||||
        this.slotId = 0;
 | 
			
		||||
        this._stackAbove = null;
 | 
			
		||||
 | 
			
		||||
        this._windowContainer.layout_manager.connect(
 | 
			
		||||
            'notify::bounding-box', layout => {
 | 
			
		||||
                // A bounding box of 0x0 means all windows were removed
 | 
			
		||||
                if (layout.bounding_box.get_area() > 0)
 | 
			
		||||
                    this.emit('size-changed');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        this._windowDestroyId =
 | 
			
		||||
            this._windowActor.connect('destroy', () => this.destroy());
 | 
			
		||||
 | 
			
		||||
        this._updateAttachedDialogs();
 | 
			
		||||
        this.x = this.boundingBox.x;
 | 
			
		||||
        this.y = this.boundingBox.y;
 | 
			
		||||
 | 
			
		||||
        let clickAction = new Clutter.ClickAction();
 | 
			
		||||
        clickAction.connect('clicked', () => this._activate());
 | 
			
		||||
        clickAction.connect('long-press', this._onLongPress.bind(this));
 | 
			
		||||
        this.add_action(clickAction);
 | 
			
		||||
        this.connect('destroy', this._onDestroy.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._draggable = DND.makeDraggable(this,
 | 
			
		||||
                                            { restoreOnSuccess: true,
 | 
			
		||||
                                              manualMode: true,
 | 
			
		||||
                                              dragActorMaxSize: WINDOW_DND_SIZE,
 | 
			
		||||
                                              dragActorOpacity: DRAGGING_WINDOW_OPACITY });
 | 
			
		||||
        this._draggable.connect('drag-begin', this._onDragBegin.bind(this));
 | 
			
		||||
        this._draggable.connect('drag-cancelled', this._onDragCancelled.bind(this));
 | 
			
		||||
        this._draggable.connect('drag-end', this._onDragEnd.bind(this));
 | 
			
		||||
        this.inDrag = false;
 | 
			
		||||
 | 
			
		||||
        this._selected = false;
 | 
			
		||||
        this._closeRequested = false;
 | 
			
		||||
        this._idleHideOverlayId = 0;
 | 
			
		||||
 | 
			
		||||
        this._border = new St.Widget({
 | 
			
		||||
            visible: false,
 | 
			
		||||
            style_class: 'window-clone-border',
 | 
			
		||||
        });
 | 
			
		||||
        this._borderConstraint = new Clutter.BindConstraint({
 | 
			
		||||
            source: this._windowContainer,
 | 
			
		||||
            coordinate: Clutter.BindCoordinate.SIZE,
 | 
			
		||||
        });
 | 
			
		||||
        this._border.add_constraint(this._borderConstraint);
 | 
			
		||||
        this._border.add_constraint(new Clutter.AlignConstraint({
 | 
			
		||||
            source: this._windowContainer,
 | 
			
		||||
            align_axis: Clutter.AlignAxis.BOTH,
 | 
			
		||||
            factor: 0.5,
 | 
			
		||||
        }));
 | 
			
		||||
        this._borderCenter = new Clutter.Actor();
 | 
			
		||||
        this._border.bind_property('visible', this._borderCenter, 'visible',
 | 
			
		||||
            GObject.BindingFlags.SYNC_CREATE);
 | 
			
		||||
        this._borderCenterConstraint = new Clutter.BindConstraint({
 | 
			
		||||
            source: this._windowContainer,
 | 
			
		||||
            coordinate: Clutter.BindCoordinate.SIZE,
 | 
			
		||||
        });
 | 
			
		||||
        this._borderCenter.add_constraint(this._borderCenterConstraint);
 | 
			
		||||
        this._borderCenter.add_constraint(new Clutter.AlignConstraint({
 | 
			
		||||
            source: this._windowContainer,
 | 
			
		||||
            align_axis: Clutter.AlignAxis.BOTH,
 | 
			
		||||
            factor: 0.5,
 | 
			
		||||
        }));
 | 
			
		||||
        this._border.connect('style-changed',
 | 
			
		||||
            this._onBorderStyleChanged.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._title = new St.Label({
 | 
			
		||||
            visible: false,
 | 
			
		||||
            style_class: 'window-caption',
 | 
			
		||||
            text: this._getCaption(),
 | 
			
		||||
            reactive: true,
 | 
			
		||||
        });
 | 
			
		||||
        this._title.add_constraint(new Clutter.BindConstraint({
 | 
			
		||||
            source: this._borderCenter,
 | 
			
		||||
            coordinate: Clutter.BindCoordinate.POSITION,
 | 
			
		||||
        }));
 | 
			
		||||
        this._title.add_constraint(new Clutter.AlignConstraint({
 | 
			
		||||
            source: this._borderCenter,
 | 
			
		||||
            align_axis: Clutter.AlignAxis.X_AXIS,
 | 
			
		||||
            factor: 0.5,
 | 
			
		||||
        }));
 | 
			
		||||
        this._title.add_constraint(new Clutter.AlignConstraint({
 | 
			
		||||
            source: this._borderCenter,
 | 
			
		||||
            align_axis: Clutter.AlignAxis.Y_AXIS,
 | 
			
		||||
            pivot_point: new Graphene.Point({ x: -1, y: 0.5 }),
 | 
			
		||||
            factor: 1,
 | 
			
		||||
        }));
 | 
			
		||||
        this._title.clutter_text.ellipsize = Pango.EllipsizeMode.END;
 | 
			
		||||
        this.label_actor = this._title;
 | 
			
		||||
        this._updateCaptionId = this.metaWindow.connect('notify::title', () => {
 | 
			
		||||
            this._title.text = this._getCaption();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        const layout = Meta.prefs_get_button_layout();
 | 
			
		||||
        this._closeButtonSide =
 | 
			
		||||
            layout.left_buttons.includes(Meta.ButtonFunction.CLOSE)
 | 
			
		||||
                ? St.Side.LEFT : St.Side.RIGHT;
 | 
			
		||||
 | 
			
		||||
        this._closeButton = new St.Button({
 | 
			
		||||
            visible: false,
 | 
			
		||||
            style_class: 'window-close',
 | 
			
		||||
            child: new St.Icon({ icon_name: 'window-close-symbolic' }),
 | 
			
		||||
        });
 | 
			
		||||
        this._closeButton.add_constraint(new Clutter.BindConstraint({
 | 
			
		||||
            source: this._borderCenter,
 | 
			
		||||
            coordinate: Clutter.BindCoordinate.POSITION,
 | 
			
		||||
        }));
 | 
			
		||||
        this._closeButton.add_constraint(new Clutter.AlignConstraint({
 | 
			
		||||
            source: this._borderCenter,
 | 
			
		||||
            align_axis: Clutter.AlignAxis.X_AXIS,
 | 
			
		||||
            pivot_point: new Graphene.Point({ x: 0.5, y: -1 }),
 | 
			
		||||
            factor: this._closeButtonSide === St.Side.LEFT ? 0 : 1,
 | 
			
		||||
        }));
 | 
			
		||||
        this._closeButton.add_constraint(new Clutter.AlignConstraint({
 | 
			
		||||
            source: this._borderCenter,
 | 
			
		||||
            align_axis: Clutter.AlignAxis.Y_AXIS,
 | 
			
		||||
            pivot_point: new Graphene.Point({ x: -1, y: 0.5 }),
 | 
			
		||||
            factor: 0,
 | 
			
		||||
        }));
 | 
			
		||||
        this._closeButton.connect('clicked', () => this._deleteAll());
 | 
			
		||||
 | 
			
		||||
        this.add_child(this._borderCenter);
 | 
			
		||||
        this.add_child(this._border);
 | 
			
		||||
        this.add_child(this._title);
 | 
			
		||||
        this.add_child(this._closeButton);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_width(forHeight) {
 | 
			
		||||
        const themeNode = this.get_theme_node();
 | 
			
		||||
 | 
			
		||||
        // Only include window previews in size request, not chrome
 | 
			
		||||
        const [minWidth, natWidth] =
 | 
			
		||||
            this._windowContainer.get_preferred_width(
 | 
			
		||||
                themeNode.adjust_for_height(forHeight));
 | 
			
		||||
 | 
			
		||||
        return themeNode.adjust_preferred_width(minWidth, natWidth);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_get_preferred_height(forWidth) {
 | 
			
		||||
        const themeNode = this.get_theme_node();
 | 
			
		||||
        const [minHeight, natHeight] =
 | 
			
		||||
            this._windowContainer.get_preferred_height(
 | 
			
		||||
                themeNode.adjust_for_width(forWidth));
 | 
			
		||||
 | 
			
		||||
        return themeNode.adjust_preferred_height(minHeight, natHeight);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        this.set_allocation(box);
 | 
			
		||||
 | 
			
		||||
        for (const child of this)
 | 
			
		||||
            child.allocate_available_size(0, 0, box.get_width(), box.get_height());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onBorderStyleChanged() {
 | 
			
		||||
        let borderNode = this._border.get_theme_node();
 | 
			
		||||
        this._borderSize = borderNode.get_border_width(St.Side.TOP);
 | 
			
		||||
 | 
			
		||||
        // Increase the size of the border actor so the border outlines
 | 
			
		||||
        // the bounding box
 | 
			
		||||
        this._borderConstraint.offset = this._borderSize * 2;
 | 
			
		||||
        this._borderCenterConstraint.offset = this._borderSize;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _windowCanClose() {
 | 
			
		||||
        return this.metaWindow.can_close() &&
 | 
			
		||||
               !this._hasAttachedDialogs();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _getCaption() {
 | 
			
		||||
        if (this.metaWindow.title)
 | 
			
		||||
            return this.metaWindow.title;
 | 
			
		||||
 | 
			
		||||
        let tracker = Shell.WindowTracker.get_default();
 | 
			
		||||
        let app = tracker.get_window_app(this.metaWindow);
 | 
			
		||||
        return app.get_name();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    chromeHeights() {
 | 
			
		||||
        this._border.ensure_style();
 | 
			
		||||
        this._title.ensure_style();
 | 
			
		||||
        const [, closeButtonHeight] = this._closeButton.get_preferred_height(-1);
 | 
			
		||||
        const [, titleHeight] = this._title.get_preferred_height(-1);
 | 
			
		||||
 | 
			
		||||
        const topOversize = (this._borderSize / 2) + (closeButtonHeight / 2);
 | 
			
		||||
        const bottomOversize = Math.max(
 | 
			
		||||
            this._borderSize,
 | 
			
		||||
            (titleHeight / 2) + (this._borderSize / 2));
 | 
			
		||||
 | 
			
		||||
        return [topOversize, bottomOversize];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    chromeWidths() {
 | 
			
		||||
        this._border.ensure_style();
 | 
			
		||||
        const [, closeButtonWidth] = this._closeButton.get_preferred_width(-1);
 | 
			
		||||
 | 
			
		||||
        const leftOversize = this._closeButtonSide === St.Side.LEFT
 | 
			
		||||
            ? (this._borderSize / 2) + (closeButtonWidth / 2)
 | 
			
		||||
            : this._borderSize;
 | 
			
		||||
        const rightOversize = this._closeButtonSide === St.Side.LEFT
 | 
			
		||||
            ? this._borderSize
 | 
			
		||||
            : (this._borderSize / 2) + (closeButtonWidth / 2);
 | 
			
		||||
 | 
			
		||||
        return [leftOversize, rightOversize];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    showOverlay(animate) {
 | 
			
		||||
        const ongoingTransition = this._border.get_transition('opacity');
 | 
			
		||||
 | 
			
		||||
        // Don't do anything if we're fully visible already
 | 
			
		||||
        if (this._border.visible && !ongoingTransition)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // If we're supposed to animate and an animation in our direction
 | 
			
		||||
        // is already happening, let that one continue
 | 
			
		||||
        if (animate &&
 | 
			
		||||
            ongoingTransition &&
 | 
			
		||||
            ongoingTransition.get_interval().peek_final_value() === 255)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        const toShow = this._windowCanClose()
 | 
			
		||||
            ? [this._border, this._title, this._closeButton]
 | 
			
		||||
            : [this._border, this._title];
 | 
			
		||||
 | 
			
		||||
        toShow.forEach(a => {
 | 
			
		||||
            a.opacity = 0;
 | 
			
		||||
            a.show();
 | 
			
		||||
            a.ease({
 | 
			
		||||
                opacity: 255,
 | 
			
		||||
                duration: animate ? WINDOW_OVERLAY_FADE_TIME : 0,
 | 
			
		||||
                mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.emit('show-chrome');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hideOverlay(animate) {
 | 
			
		||||
        const ongoingTransition = this._border.get_transition('opacity');
 | 
			
		||||
 | 
			
		||||
        // Don't do anything if we're fully hidden already
 | 
			
		||||
        if (!this._border.visible && !ongoingTransition)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // If we're supposed to animate and an animation in our direction
 | 
			
		||||
        // is already happening, let that one continue
 | 
			
		||||
        if (animate &&
 | 
			
		||||
            ongoingTransition &&
 | 
			
		||||
            ongoingTransition.get_interval().peek_final_value() === 0)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        [this._border, this._title, this._closeButton].forEach(a => {
 | 
			
		||||
            a.opacity = 255;
 | 
			
		||||
            a.ease({
 | 
			
		||||
                opacity: 0,
 | 
			
		||||
                duration: animate ? WINDOW_OVERLAY_FADE_TIME : 0,
 | 
			
		||||
                mode: Clutter.AnimationMode.EASE_OUT_QUAD,
 | 
			
		||||
                onComplete: () => a.hide(),
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _addWindow(metaWindow) {
 | 
			
		||||
        const clone = this._windowContainer.layout_manager.addWindow(metaWindow);
 | 
			
		||||
 | 
			
		||||
        // We expect this to be used for all interaction rather than
 | 
			
		||||
        // the ClutterClone; as the former is reactive and the latter
 | 
			
		||||
        // is not, this just works for most cases. However, for DND all
 | 
			
		||||
        // actors are picked, so DND operations would operate on the clone.
 | 
			
		||||
        // To avoid this, we hide it from pick.
 | 
			
		||||
        Shell.util_set_hidden_from_pick(clone, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_has_overlaps() {
 | 
			
		||||
        return this._hasAttachedDialogs();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _deleteAll() {
 | 
			
		||||
        const windows = this._windowContainer.layout_manager.getWindows();
 | 
			
		||||
 | 
			
		||||
        // Delete all windows, starting from the bottom-most (most-modal) one
 | 
			
		||||
        for (const window of windows.reverse())
 | 
			
		||||
            window.delete(global.get_current_time());
 | 
			
		||||
 | 
			
		||||
        this._closeRequested = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    addDialog(win) {
 | 
			
		||||
        let parent = win.get_transient_for();
 | 
			
		||||
        while (parent.is_attached_dialog())
 | 
			
		||||
            parent = parent.get_transient_for();
 | 
			
		||||
 | 
			
		||||
        // Display dialog if it is attached to our metaWindow
 | 
			
		||||
        if (win.is_attached_dialog() && parent == this.metaWindow)
 | 
			
		||||
            this._addWindow(win);
 | 
			
		||||
 | 
			
		||||
        // The dialog popped up after the user tried to close the window,
 | 
			
		||||
        // assume it's a close confirmation and leave the overview
 | 
			
		||||
        if (this._closeRequested)
 | 
			
		||||
            this._activate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _hasAttachedDialogs() {
 | 
			
		||||
        return this._windowContainer.layout_manager.getWindows().length > 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateAttachedDialogs() {
 | 
			
		||||
        let iter = win => {
 | 
			
		||||
            let actor = win.get_compositor_private();
 | 
			
		||||
 | 
			
		||||
            if (!actor)
 | 
			
		||||
                return false;
 | 
			
		||||
            if (!win.is_attached_dialog())
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            this._addWindow(win);
 | 
			
		||||
            win.foreach_transient(iter);
 | 
			
		||||
            return true;
 | 
			
		||||
        };
 | 
			
		||||
        this.metaWindow.foreach_transient(iter);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get boundingBox() {
 | 
			
		||||
        const box = this._windowContainer.layout_manager.bounding_box;
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            x: box.x1,
 | 
			
		||||
            y: box.y1,
 | 
			
		||||
            width: box.get_width(),
 | 
			
		||||
            height: box.get_height(),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get windowCenter() {
 | 
			
		||||
        const box = this._windowContainer.layout_manager.bounding_box;
 | 
			
		||||
 | 
			
		||||
        return new Graphene.Point({
 | 
			
		||||
            x: box.get_x() + box.get_width() / 2,
 | 
			
		||||
            y: box.get_y() + box.get_height() / 2,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Find the actor just below us, respecting reparenting done by DND code
 | 
			
		||||
    _getActualStackAbove() {
 | 
			
		||||
        if (this._stackAbove == null)
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
        if (this.inDrag) {
 | 
			
		||||
            if (this._stackAbove._delegate)
 | 
			
		||||
                return this._stackAbove._delegate._getActualStackAbove();
 | 
			
		||||
            else
 | 
			
		||||
                return null;
 | 
			
		||||
        } else {
 | 
			
		||||
            return this._stackAbove;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setStackAbove(actor) {
 | 
			
		||||
        this._stackAbove = actor;
 | 
			
		||||
        if (this.inDrag)
 | 
			
		||||
            // We'll fix up the stack after the drag
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let parent = this.get_parent();
 | 
			
		||||
        let actualAbove = this._getActualStackAbove();
 | 
			
		||||
        if (actualAbove == null)
 | 
			
		||||
            parent.set_child_below_sibling(this, null);
 | 
			
		||||
        else
 | 
			
		||||
            parent.set_child_above_sibling(this, actualAbove);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDestroy() {
 | 
			
		||||
        this._windowActor.disconnect(this._windowDestroyId);
 | 
			
		||||
 | 
			
		||||
        this.metaWindow._delegate = null;
 | 
			
		||||
        this._delegate = null;
 | 
			
		||||
 | 
			
		||||
        this.metaWindow.disconnect(this._updateCaptionId);
 | 
			
		||||
 | 
			
		||||
        if (this._longPressLater) {
 | 
			
		||||
            Meta.later_remove(this._longPressLater);
 | 
			
		||||
            delete this._longPressLater;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._idleHideOverlayId > 0) {
 | 
			
		||||
            GLib.source_remove(this._idleHideOverlayId);
 | 
			
		||||
            this._idleHideOverlayId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.inDrag) {
 | 
			
		||||
            this.emit('drag-end');
 | 
			
		||||
            this.inDrag = false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _activate() {
 | 
			
		||||
        this._selected = true;
 | 
			
		||||
        this.emit('selected', global.get_current_time());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_enter_event(crossingEvent) {
 | 
			
		||||
        this.showOverlay(true);
 | 
			
		||||
        return super.vfunc_enter_event(crossingEvent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_leave_event(crossingEvent) {
 | 
			
		||||
        if (this._idleHideOverlayId > 0)
 | 
			
		||||
            GLib.source_remove(this._idleHideOverlayId);
 | 
			
		||||
 | 
			
		||||
        this._idleHideOverlayId = GLib.timeout_add(
 | 
			
		||||
            GLib.PRIORITY_DEFAULT,
 | 
			
		||||
            WINDOW_OVERLAY_IDLE_HIDE_TIMEOUT, () => {
 | 
			
		||||
                if (this._closeButton['has-pointer'] ||
 | 
			
		||||
                    this._title['has-pointer'])
 | 
			
		||||
                    return GLib.SOURCE_CONTINUE;
 | 
			
		||||
 | 
			
		||||
                if (!this['has-pointer'])
 | 
			
		||||
                    this.hideOverlay(true);
 | 
			
		||||
 | 
			
		||||
                this._idleHideOverlayId = 0;
 | 
			
		||||
                return GLib.SOURCE_REMOVE;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        GLib.Source.set_name_by_id(this._idleHideOverlayId, '[gnome-shell] this._idleHideOverlayId');
 | 
			
		||||
 | 
			
		||||
        return super.vfunc_leave_event(crossingEvent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_key_focus_in() {
 | 
			
		||||
        super.vfunc_key_focus_in();
 | 
			
		||||
        this.showOverlay(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_key_focus_out() {
 | 
			
		||||
        super.vfunc_key_focus_out();
 | 
			
		||||
        this.hideOverlay(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_key_press_event(keyEvent) {
 | 
			
		||||
        let symbol = keyEvent.keyval;
 | 
			
		||||
        let isEnter = symbol == Clutter.KEY_Return || symbol == Clutter.KEY_KP_Enter;
 | 
			
		||||
        if (isEnter) {
 | 
			
		||||
            this._activate();
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return super.vfunc_key_press_event(keyEvent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onLongPress(action, actor, state) {
 | 
			
		||||
        // Take advantage of the Clutter policy to consider
 | 
			
		||||
        // a long-press canceled when the pointer movement
 | 
			
		||||
        // exceeds dnd-drag-threshold to manually start the drag
 | 
			
		||||
        if (state == Clutter.LongPressState.CANCEL) {
 | 
			
		||||
            let event = Clutter.get_current_event();
 | 
			
		||||
            this._dragTouchSequence = event.get_event_sequence();
 | 
			
		||||
 | 
			
		||||
            if (this._longPressLater)
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
            // A click cancels a long-press before any click handler is
 | 
			
		||||
            // run - make sure to not start a drag in that case
 | 
			
		||||
            this._longPressLater = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
 | 
			
		||||
                delete this._longPressLater;
 | 
			
		||||
                if (this._selected)
 | 
			
		||||
                    return;
 | 
			
		||||
                let [x, y] = action.get_coords();
 | 
			
		||||
                action.release();
 | 
			
		||||
                this._draggable.startDrag(x, y, global.get_current_time(), this._dragTouchSequence, event.get_device());
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            this.showOverlay(true);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDragBegin(_draggable, _time) {
 | 
			
		||||
        this.inDrag = true;
 | 
			
		||||
        this.hideOverlay(false);
 | 
			
		||||
        this.emit('drag-begin');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    handleDragOver(source, actor, x, y, time) {
 | 
			
		||||
        return this._workspace.handleDragOver(source, actor, x, y, time);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    acceptDrop(source, actor, x, y, time) {
 | 
			
		||||
        return this._workspace.acceptDrop(source, actor, x, y, time);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDragCancelled(_draggable, _time) {
 | 
			
		||||
        this.emit('drag-cancelled');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDragEnd(_draggable, _time, _snapback) {
 | 
			
		||||
        this.inDrag = false;
 | 
			
		||||
 | 
			
		||||
        // We may not have a parent if DnD completed successfully, in
 | 
			
		||||
        // which case our clone will shortly be destroyed and replaced
 | 
			
		||||
        // with a new one on the target workspace.
 | 
			
		||||
        let parent = this.get_parent();
 | 
			
		||||
        if (parent !== null) {
 | 
			
		||||
            if (this._stackAbove == null)
 | 
			
		||||
                parent.set_child_below_sibling(this, null);
 | 
			
		||||
            else
 | 
			
		||||
                parent.set_child_above_sibling(this, this._stackAbove);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this['has-pointer'])
 | 
			
		||||
            this.showOverlay(true);
 | 
			
		||||
 | 
			
		||||
        this.emit('drag-end');
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -86,8 +86,8 @@ class WorkspaceSwitcherPopupList extends St.Widget {
 | 
			
		||||
            return this._getSizeForOppositeOrientation();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
        this.set_allocation(box, flags);
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        this.set_allocation(box);
 | 
			
		||||
 | 
			
		||||
        let themeNode = this.get_theme_node();
 | 
			
		||||
        box = themeNode.get_content_box(box);
 | 
			
		||||
@@ -111,7 +111,7 @@ class WorkspaceSwitcherPopupList extends St.Widget {
 | 
			
		||||
            } else {
 | 
			
		||||
                y += this._childHeight + this._itemSpacing;
 | 
			
		||||
            }
 | 
			
		||||
            child.allocate(childBox, flags);
 | 
			
		||||
            child.allocate(childBox);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -567,7 +567,8 @@ var WorkspaceThumbnail = GObject.registerClass({
 | 
			
		||||
        if (this.state > ThumbnailState.NORMAL)
 | 
			
		||||
            return DND.DragMotionResult.CONTINUE;
 | 
			
		||||
 | 
			
		||||
        if (source.realWindow && !this._isMyWindow(source.realWindow))
 | 
			
		||||
        if (source.metaWindow &&
 | 
			
		||||
            !this._isMyWindow(source.metaWindow.get_compositor_private()))
 | 
			
		||||
            return DND.DragMotionResult.MOVE_DROP;
 | 
			
		||||
        if (source.app && source.app.can_open_new_window())
 | 
			
		||||
            return DND.DragMotionResult.COPY_DROP;
 | 
			
		||||
@@ -581,8 +582,8 @@ var WorkspaceThumbnail = GObject.registerClass({
 | 
			
		||||
        if (this.state > ThumbnailState.NORMAL)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (source.realWindow) {
 | 
			
		||||
            let win = source.realWindow;
 | 
			
		||||
        if (source.metaWindow) {
 | 
			
		||||
            let win = source.metaWindow.get_compositor_private();
 | 
			
		||||
            if (this._isMyWindow(win))
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
@@ -795,7 +796,7 @@ var ThumbnailsBox = GObject.registerClass({
 | 
			
		||||
 | 
			
		||||
    // Draggable target interface
 | 
			
		||||
    handleDragOver(source, actor, x, y, time) {
 | 
			
		||||
        if (!source.realWindow &&
 | 
			
		||||
        if (!source.metaWindow &&
 | 
			
		||||
            (!source.app || !source.app.can_open_new_window()) &&
 | 
			
		||||
            (source.app || !source.shellWorkspaceLaunch) &&
 | 
			
		||||
            source != Main.xdndHandler)
 | 
			
		||||
@@ -846,7 +847,7 @@ var ThumbnailsBox = GObject.registerClass({
 | 
			
		||||
        if (this._dropWorkspace != -1)
 | 
			
		||||
            return this._thumbnails[this._dropWorkspace].handleDragOverInternal(source, actor, time);
 | 
			
		||||
        else if (this._dropPlaceholderPos != -1)
 | 
			
		||||
            return source.realWindow ? DND.DragMotionResult.MOVE_DROP : DND.DragMotionResult.COPY_DROP;
 | 
			
		||||
            return source.metaWindow ? DND.DragMotionResult.MOVE_DROP : DND.DragMotionResult.COPY_DROP;
 | 
			
		||||
        else
 | 
			
		||||
            return DND.DragMotionResult.CONTINUE;
 | 
			
		||||
    }
 | 
			
		||||
@@ -855,12 +856,12 @@ var ThumbnailsBox = GObject.registerClass({
 | 
			
		||||
        if (this._dropWorkspace != -1) {
 | 
			
		||||
            return this._thumbnails[this._dropWorkspace].acceptDropInternal(source, actor, time);
 | 
			
		||||
        } else if (this._dropPlaceholderPos != -1) {
 | 
			
		||||
            if (!source.realWindow &&
 | 
			
		||||
            if (!source.metaWindow &&
 | 
			
		||||
                (!source.app || !source.app.can_open_new_window()) &&
 | 
			
		||||
                (source.app || !source.shellWorkspaceLaunch))
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            let isWindow = !!source.realWindow;
 | 
			
		||||
            let isWindow = !!source.metaWindow;
 | 
			
		||||
 | 
			
		||||
            let newWorkspaceIndex;
 | 
			
		||||
            [newWorkspaceIndex, this._dropPlaceholderPos] = [this._dropPlaceholderPos, -1];
 | 
			
		||||
@@ -1204,8 +1205,8 @@ var ThumbnailsBox = GObject.registerClass({
 | 
			
		||||
        this.queue_relayout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vfunc_allocate(box, flags) {
 | 
			
		||||
        this.set_allocation(box, flags);
 | 
			
		||||
    vfunc_allocate(box) {
 | 
			
		||||
        this.set_allocation(box);
 | 
			
		||||
 | 
			
		||||
        let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
 | 
			
		||||
 | 
			
		||||
@@ -1299,7 +1300,7 @@ var ThumbnailsBox = GObject.registerClass({
 | 
			
		||||
                childBox.x2 = x2;
 | 
			
		||||
                childBox.y1 = Math.round(y);
 | 
			
		||||
                childBox.y2 = Math.round(y + placeholderHeight);
 | 
			
		||||
                this._dropPlaceholder.allocate(childBox, flags);
 | 
			
		||||
                this._dropPlaceholder.allocate(childBox);
 | 
			
		||||
                Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
 | 
			
		||||
                    this._dropPlaceholder.show();
 | 
			
		||||
                });
 | 
			
		||||
@@ -1331,7 +1332,7 @@ var ThumbnailsBox = GObject.registerClass({
 | 
			
		||||
            childBox.y2 = y1 + portholeHeight;
 | 
			
		||||
 | 
			
		||||
            thumbnail.set_scale(roundedHScale, roundedVScale);
 | 
			
		||||
            thumbnail.allocate(childBox, flags);
 | 
			
		||||
            thumbnail.allocate(childBox);
 | 
			
		||||
 | 
			
		||||
            // We round the collapsing portion so that we don't get thumbnails resizing
 | 
			
		||||
            // during an animation due to differences in rounded, but leave the uncollapsed
 | 
			
		||||
@@ -1355,6 +1356,6 @@ var ThumbnailsBox = GObject.registerClass({
 | 
			
		||||
        childBox.x2 += indicatorRightFullBorder;
 | 
			
		||||
        childBox.y1 = indicatorY1 - indicatorTopFullBorder;
 | 
			
		||||
        childBox.y2 = indicatorY2 + indicatorBottomFullBorder;
 | 
			
		||||
        this._indicator.allocate(childBox, flags);
 | 
			
		||||
        this._indicator.allocate(childBox);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -393,7 +393,10 @@ class ExtraWorkspaceView extends WorkspacesViewBase {
 | 
			
		||||
var WorkspacesDisplay = GObject.registerClass(
 | 
			
		||||
class WorkspacesDisplay extends St.Widget {
 | 
			
		||||
    _init(scrollAdjustment) {
 | 
			
		||||
        super._init({ clip_to_allocation: true });
 | 
			
		||||
        super._init({
 | 
			
		||||
            visible: false,
 | 
			
		||||
            clip_to_allocation: true,
 | 
			
		||||
        });
 | 
			
		||||
        this.connect('notify::allocation', this._updateWorkspacesActualGeometry.bind(this));
 | 
			
		||||
 | 
			
		||||
        let workspaceManager = global.workspace_manager;
 | 
			
		||||
@@ -450,6 +453,7 @@ class WorkspacesDisplay extends St.Widget {
 | 
			
		||||
        this._keyPressEventId = 0;
 | 
			
		||||
        this._scrollTimeoutId = 0;
 | 
			
		||||
 | 
			
		||||
        this._actualGeometry = null;
 | 
			
		||||
        this._fullGeometry = null;
 | 
			
		||||
        this._inWindowDrag = false;
 | 
			
		||||
 | 
			
		||||
@@ -608,15 +612,19 @@ class WorkspacesDisplay extends St.Widget {
 | 
			
		||||
        return this._getPrimaryView().navigate_focus(from, direction, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    show(fadeOnPrimary) {
 | 
			
		||||
    animateToOverview(fadeOnPrimary) {
 | 
			
		||||
        this.show();
 | 
			
		||||
        this._updateWorkspacesViews();
 | 
			
		||||
        for (let i = 0; i < this._workspacesViews.length; i++) {
 | 
			
		||||
            let animationType;
 | 
			
		||||
            if (fadeOnPrimary && i == this._primaryIndex)
 | 
			
		||||
                animationType = AnimationType.FADE;
 | 
			
		||||
            else
 | 
			
		||||
                animationType = AnimationType.ZOOM;
 | 
			
		||||
            this._workspacesViews[i].animateToOverview(animationType);
 | 
			
		||||
 | 
			
		||||
        if (this._actualGeometry && this._fullGeometry) {
 | 
			
		||||
            for (let i = 0; i < this._workspacesViews.length; i++) {
 | 
			
		||||
                let animationType;
 | 
			
		||||
                if (fadeOnPrimary && i == this._primaryIndex)
 | 
			
		||||
                    animationType = AnimationType.FADE;
 | 
			
		||||
                else
 | 
			
		||||
                    animationType = AnimationType.ZOOM;
 | 
			
		||||
                this._workspacesViews[i].animateToOverview(animationType);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._restackedNotifyId =
 | 
			
		||||
@@ -640,7 +648,7 @@ class WorkspacesDisplay extends St.Widget {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hide() {
 | 
			
		||||
    vfunc_hide() {
 | 
			
		||||
        if (this._restackedNotifyId > 0) {
 | 
			
		||||
            Main.overview.disconnect(this._restackedNotifyId);
 | 
			
		||||
            this._restackedNotifyId = 0;
 | 
			
		||||
@@ -656,6 +664,8 @@ class WorkspacesDisplay extends St.Widget {
 | 
			
		||||
        for (let i = 0; i < this._workspacesViews.length; i++)
 | 
			
		||||
            this._workspacesViews[i].destroy();
 | 
			
		||||
        this._workspacesViews = [];
 | 
			
		||||
 | 
			
		||||
        super.vfunc_hide();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _workspacesOnlyOnPrimaryChanged() {
 | 
			
		||||
@@ -690,8 +700,10 @@ class WorkspacesDisplay extends St.Widget {
 | 
			
		||||
 | 
			
		||||
        this._workspacesViews.forEach(v => v.show());
 | 
			
		||||
 | 
			
		||||
        this._updateWorkspacesFullGeometry();
 | 
			
		||||
        this._updateWorkspacesActualGeometry();
 | 
			
		||||
        if (this._fullGeometry)
 | 
			
		||||
            this._syncWorkspacesFullGeometry();
 | 
			
		||||
        if (this._actualGeometry)
 | 
			
		||||
            this._syncWorkspacesActualGeometry();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _getMonitorIndexForEvent(event) {
 | 
			
		||||
@@ -743,10 +755,10 @@ class WorkspacesDisplay extends St.Widget {
 | 
			
		||||
    // the sliding controls were never slid in at all.
 | 
			
		||||
    setWorkspacesFullGeometry(geom) {
 | 
			
		||||
        this._fullGeometry = geom;
 | 
			
		||||
        this._updateWorkspacesFullGeometry();
 | 
			
		||||
        this._syncWorkspacesFullGeometry();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateWorkspacesFullGeometry() {
 | 
			
		||||
    _syncWorkspacesFullGeometry() {
 | 
			
		||||
        if (!this._workspacesViews.length)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
@@ -758,18 +770,21 @@ class WorkspacesDisplay extends St.Widget {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateWorkspacesActualGeometry() {
 | 
			
		||||
        const [x, y] = this.get_transformed_position();
 | 
			
		||||
        const width = this.allocation.get_width();
 | 
			
		||||
        const height = this.allocation.get_height();
 | 
			
		||||
 | 
			
		||||
        this._actualGeometry = { x, y, width, height };
 | 
			
		||||
        this._syncWorkspacesActualGeometry();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _syncWorkspacesActualGeometry() {
 | 
			
		||||
        if (!this._workspacesViews.length)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let [x, y] = this.get_transformed_position();
 | 
			
		||||
        let allocation = this.allocation;
 | 
			
		||||
        let width = allocation.x2 - allocation.x1;
 | 
			
		||||
        let height = allocation.y2 - allocation.y1;
 | 
			
		||||
        let primaryGeometry = { x, y, width, height };
 | 
			
		||||
 | 
			
		||||
        let monitors = Main.layoutManager.monitors;
 | 
			
		||||
        for (let i = 0; i < monitors.length; i++) {
 | 
			
		||||
            let geometry = i == this._primaryIndex ? primaryGeometry : monitors[i];
 | 
			
		||||
            let geometry = i === this._primaryIndex ? this._actualGeometry : monitors[i];
 | 
			
		||||
            this._workspacesViews[i].setActualGeometry(geometry);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -820,8 +835,7 @@ class WorkspacesDisplay extends St.Widget {
 | 
			
		||||
                this._canScroll = true;
 | 
			
		||||
                this._scrollTimeoutId = 0;
 | 
			
		||||
                return GLib.SOURCE_REMOVE;
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        return Clutter.EVENT_STOP;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const { Clutter, Meta } = imports.gi;
 | 
			
		||||
const { Clutter } = imports.gi;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const DND = imports.ui.dnd;
 | 
			
		||||
@@ -17,7 +17,7 @@ var XdndHandler = class {
 | 
			
		||||
        Main.uiGroup.add_actor(this._dummy);
 | 
			
		||||
        this._dummy.hide();
 | 
			
		||||
 | 
			
		||||
        var dnd = Meta.get_backend().get_dnd();
 | 
			
		||||
        var dnd = global.backend.get_dnd();
 | 
			
		||||
        dnd.connect('dnd-enter', this._onEnter.bind(this));
 | 
			
		||||
        dnd.connect('dnd-position-change', this._onPositionChanged.bind(this));
 | 
			
		||||
        dnd.connect('dnd-leave', this._onLeave.bind(this));
 | 
			
		||||
 
 | 
			
		||||
@@ -218,12 +218,12 @@ globals:
 | 
			
		||||
  ARGV: readonly
 | 
			
		||||
  Debugger: readonly
 | 
			
		||||
  GIRepositoryGType: readonly
 | 
			
		||||
  globalThis: readonly
 | 
			
		||||
  imports: readonly
 | 
			
		||||
  Intl: readonly
 | 
			
		||||
  log: readonly
 | 
			
		||||
  logError: readonly
 | 
			
		||||
  print: readonly
 | 
			
		||||
  printerr: readonly
 | 
			
		||||
  window: readonly
 | 
			
		||||
parserOptions:
 | 
			
		||||
  ecmaVersion: 2019
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								meson.build
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								meson.build
									
									
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
project('gnome-shell', 'c',
 | 
			
		||||
  version: '3.36.5',
 | 
			
		||||
  meson_version: '>= 0.47.0',
 | 
			
		||||
  version: '3.37.2',
 | 
			
		||||
  meson_version: '>= 0.53.0',
 | 
			
		||||
  license: 'GPLv2+'
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -23,9 +23,9 @@ eds_req = '>= 3.33.1'
 | 
			
		||||
gcr_req = '>= 3.7.5'
 | 
			
		||||
gio_req = '>= 2.56.0'
 | 
			
		||||
gi_req = '>= 1.49.1'
 | 
			
		||||
gjs_req = '>= 1.63.2'
 | 
			
		||||
gjs_req = '>= 1.65.1'
 | 
			
		||||
gtk_req = '>= 3.15.0'
 | 
			
		||||
mutter_req = '>= 3.36.0'
 | 
			
		||||
mutter_req = '>= 3.37.2'
 | 
			
		||||
polkit_req = '>= 0.100'
 | 
			
		||||
schemas_req = '>= 3.33.1'
 | 
			
		||||
startup_req = '>= 0.11'
 | 
			
		||||
@@ -63,16 +63,9 @@ portaldir = join_paths(datadir, 'xdg-desktop-portal', 'portals')
 | 
			
		||||
schemadir = join_paths(datadir, 'glib-2.0', 'schemas')
 | 
			
		||||
servicedir = join_paths(datadir, 'dbus-1', 'services')
 | 
			
		||||
 | 
			
		||||
# XXX: Once https://github.com/systemd/systemd/issues/9595 is fixed and we can
 | 
			
		||||
# depend on this version, replace with something like:
 | 
			
		||||
# systemduserunitdir = systemd_dep.get_pkgconfig_variable('systemduserunitdir',
 | 
			
		||||
#                                                         define_variable: ['prefix', prefix])
 | 
			
		||||
# and uncomment systemd_dep below
 | 
			
		||||
systemduserunitdir = join_paths(prefix, 'lib', 'systemd', 'user')
 | 
			
		||||
 | 
			
		||||
keybindings_dep = dependency('gnome-keybindings', required: false)
 | 
			
		||||
if keybindings_dep.found()
 | 
			
		||||
  keysdir = keybindings_dep.get_pkgconfig_variable('keysdir')
 | 
			
		||||
  keysdir = keybindings_dep.get_pkgconfig_variable('keysdir', define_variable: ['datadir', datadir])
 | 
			
		||||
else
 | 
			
		||||
  keysdir = join_paths(datadir, 'gnome-control-center', 'keybindings')
 | 
			
		||||
endif
 | 
			
		||||
@@ -122,8 +115,9 @@ endif
 | 
			
		||||
 | 
			
		||||
if get_option('systemd')
 | 
			
		||||
  libsystemd_dep = dependency('libsystemd')
 | 
			
		||||
  # XXX: see systemduserunitdir
 | 
			
		||||
  # systemd_dep = dependency('systemd')
 | 
			
		||||
  systemd_dep = dependency('systemd')
 | 
			
		||||
  systemduserunitdir = systemd_dep.get_pkgconfig_variable('systemduserunitdir',
 | 
			
		||||
                                                          define_variable: ['prefix', prefix])
 | 
			
		||||
  have_systemd = true
 | 
			
		||||
else
 | 
			
		||||
  libsystemd_dep = []
 | 
			
		||||
@@ -321,8 +315,6 @@ if get_option('man')
 | 
			
		||||
  summary_dirs += { 'mandir': get_option('mandir') }
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if meson.version().version_compare('>= 0.53.0')
 | 
			
		||||
  summary(summary_dirs, section: 'Directories')
 | 
			
		||||
  summary(summary_build, section: 'Build Configuration')
 | 
			
		||||
  summary(summary_options, section: 'Build Options')
 | 
			
		||||
endif
 | 
			
		||||
summary(summary_dirs, section: 'Directories')
 | 
			
		||||
summary(summary_build, section: 'Build Configuration')
 | 
			
		||||
summary(summary_options, section: 'Build Options')
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								mutter
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								mutter
									
									
									
									
									
										Submodule
									
								
							 Submodule mutter added at 1551b6d386
									
								
							@@ -56,6 +56,7 @@ nl
 | 
			
		||||
nn
 | 
			
		||||
oc
 | 
			
		||||
or
 | 
			
		||||
os
 | 
			
		||||
pa
 | 
			
		||||
pl
 | 
			
		||||
pt
 | 
			
		||||
 
 | 
			
		||||
@@ -94,5 +94,7 @@ subprojects/extensions-tool/src/command-prefs.c
 | 
			
		||||
subprojects/extensions-tool/src/command-reset.c
 | 
			
		||||
subprojects/extensions-tool/src/command-uninstall.c
 | 
			
		||||
subprojects/extensions-tool/src/main.c
 | 
			
		||||
subprojects/extensions-tool/src/templates/00-plain.desktop.in
 | 
			
		||||
subprojects/extensions-tool/src/templates/indicator.desktop.in
 | 
			
		||||
# Please do not remove this file from POTFILES.in. Run "git submodule init && git submodule update" to get it.
 | 
			
		||||
subprojects/gvc/gvc-mixer-control.c
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user