Compare commits
	
		
			265 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					d985477a9d | ||
| 
						 | 
					b188d57609 | ||
| 
						 | 
					412af26e4e | ||
| 
						 | 
					7b440f3864 | ||
| 
						 | 
					2d98903c90 | ||
| 
						 | 
					9a0d0d2fd3 | ||
| 
						 | 
					9451c04a09 | ||
| 
						 | 
					ca9099997c | ||
| 
						 | 
					4de18f2d4b | ||
| 
						 | 
					73d8f6c993 | ||
| 
						 | 
					2141138a6f | ||
| 
						 | 
					4f135be89a | ||
| 
						 | 
					026ec2d4c2 | ||
| 
						 | 
					a82fae3a2f | ||
| 
						 | 
					892d224cd7 | ||
| 
						 | 
					63e6d11892 | ||
| 
						 | 
					0509bb9bb4 | ||
| 
						 | 
					5c78908a5f | ||
| 
						 | 
					5a2269c6c6 | ||
| 
						 | 
					a7e9655e32 | ||
| 
						 | 
					1ec82d2ddd | ||
| 
						 | 
					98eaef621a | ||
| 
						 | 
					74a6ca58ef | ||
| 
						 | 
					747faa43ae | ||
| 
						 | 
					32a53f7412 | ||
| 
						 | 
					9c94e9813c | ||
| 
						 | 
					19749bb37f | ||
| 
						 | 
					5ab4c484a5 | ||
| 
						 | 
					e602199bfb | ||
| 
						 | 
					62e1c08dd6 | ||
| 
						 | 
					37e2b60cd3 | ||
| 
						 | 
					f299078585 | ||
| 
						 | 
					bf0a0d5bad | ||
| 
						 | 
					365cda386c | ||
| 
						 | 
					5de5b7a66a | ||
| 
						 | 
					d6de0a64ed | ||
| 
						 | 
					26f8441f73 | ||
| 
						 | 
					51bca08386 | ||
| 
						 | 
					1579aad362 | ||
| 
						 | 
					a2a580954a | ||
| 
						 | 
					944c28f3b3 | ||
| 
						 | 
					c13a597fe0 | ||
| 
						 | 
					86e0ae0b93 | ||
| 
						 | 
					f71ffed3c7 | ||
| 
						 | 
					cae96d9023 | ||
| 
						 | 
					676b649731 | ||
| 
						 | 
					634ce34e00 | ||
| 
						 | 
					6c3096f71f | ||
| 
						 | 
					991ed2da72 | ||
| 
						 | 
					907f02cd28 | ||
| 
						 | 
					9ba78ce04a | ||
| 
						 | 
					14a3d9f7fb | ||
| 
						 | 
					f73a01295c | ||
| 
						 | 
					ccfa3d3be1 | ||
| 
						 | 
					727e4c0b37 | ||
| 
						 | 
					6ce470b9b2 | ||
| 
						 | 
					4b7e230531 | ||
| 
						 | 
					aefe0d3ddd | ||
| 
						 | 
					bbb23b515f | ||
| 
						 | 
					976166a04a | ||
| 
						 | 
					b20129c37e | ||
| 
						 | 
					4fe1360b2c | ||
| 
						 | 
					f0113c5ff5 | ||
| 
						 | 
					a259016436 | ||
| 
						 | 
					9a79c71e88 | ||
| 
						 | 
					e62d22a50e | ||
| 
						 | 
					402f2d939c | ||
| 
						 | 
					374aee75d8 | ||
| 
						 | 
					88ce65266e | ||
| 
						 | 
					e0a6a623d2 | ||
| 
						 | 
					d0310bd745 | ||
| 
						 | 
					35c665156b | ||
| 
						 | 
					3754a76f10 | ||
| 
						 | 
					db2e6e5b95 | ||
| 
						 | 
					d5f95db68d | ||
| 
						 | 
					d96726c392 | ||
| 
						 | 
					d1c54f55e6 | ||
| 
						 | 
					176a73f4e9 | ||
| 
						 | 
					54a9592e19 | ||
| 
						 | 
					b2aa29e221 | ||
| 
						 | 
					0eba0f8dd3 | ||
| 
						 | 
					d8d0afff0b | ||
| 
						 | 
					b799e8c0a6 | ||
| 
						 | 
					583255e1a8 | ||
| 
						 | 
					c68ccbf263 | ||
| 
						 | 
					d658ec8de2 | ||
| 
						 | 
					8727661c1c | ||
| 
						 | 
					731e8bfe2b | ||
| 
						 | 
					f88d9c06f5 | ||
| 
						 | 
					248a0c1b6c | ||
| 
						 | 
					434f1edb25 | ||
| 
						 | 
					2a550e6466 | ||
| 
						 | 
					4f4132943d | ||
| 
						 | 
					62760d5b2d | ||
| 
						 | 
					34aa501637 | ||
| 
						 | 
					6330379f77 | ||
| 
						 | 
					30c64baa7f | ||
| 
						 | 
					cdbed0c615 | ||
| 
						 | 
					f6e7034172 | ||
| 
						 | 
					cd9c5b9c5d | ||
| 
						 | 
					7833e21b01 | ||
| 
						 | 
					12ba2b222f | ||
| 
						 | 
					8583ca73e4 | ||
| 
						 | 
					b588ae4e0e | ||
| 
						 | 
					28abc15c00 | ||
| 
						 | 
					4d663680d8 | ||
| 
						 | 
					6505f8e94a | ||
| 
						 | 
					ff3c20dda2 | ||
| 
						 | 
					c698dee071 | ||
| 
						 | 
					8891a41793 | ||
| 
						 | 
					026f61f5aa | ||
| 
						 | 
					af063dc2f2 | ||
| 
						 | 
					3075f3cfe4 | ||
| 
						 | 
					419f2dca15 | ||
| 
						 | 
					5803f69605 | ||
| 
						 | 
					bfd1cc99a0 | ||
| 
						 | 
					a6a2cea414 | ||
| 
						 | 
					10e857cebe | ||
| 
						 | 
					ed76b54511 | ||
| 
						 | 
					9659d056b7 | ||
| 
						 | 
					b79b0952b4 | ||
| 
						 | 
					fa44dc7d16 | ||
| 
						 | 
					b0dc841e00 | ||
| 
						 | 
					c72ae375c8 | ||
| 
						 | 
					0fd6ae5330 | ||
| 
						 | 
					c8792ccfa6 | ||
| 
						 | 
					b689972e67 | ||
| 
						 | 
					ae6d7bbfa3 | ||
| 
						 | 
					2591bc90ac | ||
| 
						 | 
					61fe000daa | ||
| 
						 | 
					c864ebeabb | ||
| 
						 | 
					24c530611f | ||
| 
						 | 
					d44d00f0f4 | ||
| 
						 | 
					dc3082e66d | ||
| 
						 | 
					c61573a8b7 | ||
| 
						 | 
					3b95560d32 | ||
| 
						 | 
					990f68375e | ||
| 
						 | 
					1290c98c9b | ||
| 
						 | 
					08599afdd4 | ||
| 
						 | 
					bb040918e3 | ||
| 
						 | 
					6fac33ea7d | ||
| 
						 | 
					e16c16b3ef | ||
| 
						 | 
					1eeeead78f | ||
| 
						 | 
					046a1a7af8 | ||
| 
						 | 
					db89648f62 | ||
| 
						 | 
					9c839cdc70 | ||
| 
						 | 
					938b1ff06a | ||
| 
						 | 
					ecd838bf01 | ||
| 
						 | 
					855a31ff25 | ||
| 
						 | 
					7464add904 | ||
| 
						 | 
					7514607129 | ||
| 
						 | 
					12a1d7b38d | ||
| 
						 | 
					d6fe008b2c | ||
| 
						 | 
					d920da6624 | ||
| 
						 | 
					e2c86cef47 | ||
| 
						 | 
					8e270dc246 | ||
| 
						 | 
					22b6a25408 | ||
| 
						 | 
					cde695d903 | ||
| 
						 | 
					e98eb57e3e | ||
| 
						 | 
					11d997c42b | ||
| 
						 | 
					eab1ab0fac | ||
| 
						 | 
					660b801775 | ||
| 
						 | 
					eb80503bcc | ||
| 
						 | 
					14ceb10555 | ||
| 
						 | 
					d9a4688e98 | ||
| 
						 | 
					092586c931 | ||
| 
						 | 
					31478e9fb4 | ||
| 
						 | 
					cc7630c236 | ||
| 
						 | 
					c29810b2f6 | ||
| 
						 | 
					c1240d3f2c | ||
| 
						 | 
					654f1dd055 | ||
| 
						 | 
					53c609c278 | ||
| 
						 | 
					a2fcbb7e65 | ||
| 
						 | 
					db14dc973a | ||
| 
						 | 
					c29aaa047d | ||
| 
						 | 
					49064ed56d | ||
| 
						 | 
					72bc46d339 | ||
| 
						 | 
					40b895d16b | ||
| 
						 | 
					33cad9a824 | ||
| 
						 | 
					e96d9e0ea1 | ||
| 
						 | 
					ed63bda932 | ||
| 
						 | 
					18107d567d | ||
| 
						 | 
					608818fa9f | ||
| 
						 | 
					9ae2440ec1 | ||
| 
						 | 
					ef9c50e63a | ||
| 
						 | 
					5d50b08351 | ||
| 
						 | 
					123fc19c4e | ||
| 
						 | 
					a9058e471c | ||
| 
						 | 
					bd1f48d9fe | ||
| 
						 | 
					66ab4d217d | ||
| 
						 | 
					7a8b392607 | ||
| 
						 | 
					bfdf069d2d | ||
| 
						 | 
					b4b00a48d9 | ||
| 
						 | 
					e5f226612e | ||
| 
						 | 
					20619ad3c1 | ||
| 
						 | 
					37dce7d4c3 | ||
| 
						 | 
					a67b82e730 | ||
| 
						 | 
					e0b8ad7911 | ||
| 
						 | 
					dbb39d366e | ||
| 
						 | 
					e1de36398d | ||
| 
						 | 
					871c28aeeb | ||
| 
						 | 
					c84dc6254d | ||
| 
						 | 
					60cb1ad7c5 | ||
| 
						 | 
					4a5ff5dcfb | ||
| 
						 | 
					5c40307745 | ||
| 
						 | 
					39426f03e6 | ||
| 
						 | 
					92e5d2b8f5 | ||
| 
						 | 
					09aa59f98b | ||
| 
						 | 
					c9c1c89a27 | ||
| 
						 | 
					96b76709e9 | ||
| 
						 | 
					ca3107e21b | ||
| 
						 | 
					2e4f223207 | ||
| 
						 | 
					17df668186 | ||
| 
						 | 
					aef70152de | ||
| 
						 | 
					e0252f35be | ||
| 
						 | 
					0f47534766 | ||
| 
						 | 
					54feaa67e8 | ||
| 
						 | 
					64ecfa49eb | ||
| 
						 | 
					fdae613b14 | ||
| 
						 | 
					c57c08b2c6 | ||
| 
						 | 
					d2103995cb | ||
| 
						 | 
					196fb0f16e | ||
| 
						 | 
					c0afe7260a | ||
| 
						 | 
					099c8703ae | ||
| 
						 | 
					b03e480dbf | ||
| 
						 | 
					8430353389 | ||
| 
						 | 
					a123ec94ef | ||
| 
						 | 
					4a2f54f6ff | ||
| 
						 | 
					b5c85eaeca | ||
| 
						 | 
					8b3b91d78d | ||
| 
						 | 
					e1de3973fe | ||
| 
						 | 
					c1993a6ffc | ||
| 
						 | 
					ab26fc438a | ||
| 
						 | 
					c37259b01d | ||
| 
						 | 
					bde8cc3285 | ||
| 
						 | 
					59ba5504d0 | ||
| 
						 | 
					65eb5a3d05 | ||
| 
						 | 
					b925322e9e | ||
| 
						 | 
					f0c2ad00f8 | ||
| 
						 | 
					fc53a25a4c | ||
| 
						 | 
					58872d162b | ||
| 
						 | 
					30f1b8f02a | ||
| 
						 | 
					ee4f199a9f | ||
| 
						 | 
					e3957f3bac | ||
| 
						 | 
					2506673514 | ||
| 
						 | 
					7cb12015fd | ||
| 
						 | 
					caaac9b9ec | ||
| 
						 | 
					1dac4d00c4 | ||
| 
						 | 
					b41902f4df | ||
| 
						 | 
					ada70dd683 | ||
| 
						 | 
					7e5d8a8d54 | ||
| 
						 | 
					e981cae27c | ||
| 
						 | 
					d7c377c229 | ||
| 
						 | 
					8772edcd33 | ||
| 
						 | 
					254740cf68 | ||
| 
						 | 
					c3775c0f56 | ||
| 
						 | 
					5ecf40e967 | ||
| 
						 | 
					45026df4bd | ||
| 
						 | 
					b8830f4a09 | ||
| 
						 | 
					811ee1d989 | ||
| 
						 | 
					8c32102e99 | ||
| 
						 | 
					1b135095c7 | ||
| 
						 | 
					becf4396c9 | ||
| 
						 | 
					929e066506 | ||
| 
						 | 
					355ad9ac2c | 
							
								
								
									
										77
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								NEWS
									
									
									
									
									
								
							@@ -1,3 +1,80 @@
 | 
			
		||||
3.9.2
 | 
			
		||||
=====
 | 
			
		||||
* Use a symbolic icon for DESKTOP windows [Matthias; #697914]
 | 
			
		||||
* Move paint state cache into StWidget [Jasper; #697274]
 | 
			
		||||
* gdm: Fix regression where domain login hint not shown [Stef; #698200]
 | 
			
		||||
* Make calendar keyboard navigable [Tanner; #667434]
 | 
			
		||||
* Hide "Open Calendar" item when no calendar app is installed [Lionel; #697725]
 | 
			
		||||
* Update how branding appears on login screen [Florian; #694912, #699877]
 | 
			
		||||
* Allow OSD popups to grow if necessary [Marta; #696523]
 | 
			
		||||
* Fix offset of shadow offscreen rendering [Lionel; #698301]
 | 
			
		||||
* Fix insensitive button preventing empty keyring password [Stef; #696304]
 | 
			
		||||
* Allow cancelling keyring dialog between prompts [Stef; #682830]
 | 
			
		||||
* modalDialog: Show spinner while working [Stef; #684438]
 | 
			
		||||
* overview: Only show close buttons for windows that may close [Jasper; #699269]
 | 
			
		||||
* Add input purpose and hints to StEntry and StIMText [Daiki; #691392]
 | 
			
		||||
* Set input-purpose property for password entries [Rui; #700043]
 | 
			
		||||
* Provide a DBus API for screencasting [Florian; #696247]
 | 
			
		||||
* overview: Disable hotcorner during DND [Jasper; #698484]
 | 
			
		||||
* polkitAgent: Allow retrying after mistyped passwords [Stef; #684431]
 | 
			
		||||
* Add a way to get backtraces from criticals and warnings [Giovanni; #700262]
 | 
			
		||||
* Allow switch-to-workspace-n keybindings in overview [Florian; #649977]
 | 
			
		||||
* Update man page [Matthias; #700339]
 | 
			
		||||
* Add FocusSearch DBus method [Florian; #700536]
 | 
			
		||||
* Hide frequent view when app monitoring is disabled [Florian; #699714]
 | 
			
		||||
* Show switcher popup for switch-to-workspace-n keybindings [Elad; #659288]
 | 
			
		||||
* gdm: Update the session chooser style [Allan; #695742]
 | 
			
		||||
* Fix some app folders getting truncated at the top [Florian; #694371]
 | 
			
		||||
* Don't block the message tray while a notification is showing [Jasper; #700639]
 | 
			
		||||
* popupMenu: Allow for an optional border for slider handle [Florian; #697917]
 | 
			
		||||
* Re-lock screen when restarted after a crash [Colin; #691987]
 | 
			
		||||
* Synchronize input source switching with key events [Rui; #697007]
 | 
			
		||||
* Switch input source on modifiers-only accelerator [Rui; #697008]
 | 
			
		||||
* Allow input source switching in message tray [Rui; #697009]
 | 
			
		||||
* Misc bug fixes and cleanups [Alban, Jasper, Giovanni, Florian, Rui, Tomeu,
 | 
			
		||||
  Stef, Gustavo; #698863, #699799, #699800, #676285, #699975, #700097, #698812,
 | 
			
		||||
  #698486, #700194, #695314, #700257, #699678, #700356, #700322, #700394,
 | 
			
		||||
  #700409, #700595, #700625, #691746, #700620, #700807, #659288, #700784,
 | 
			
		||||
  #700842, #700847, #700488, #700735, #696159, #700900, #700853, #700923,
 | 
			
		||||
  #700944, #697661, #700854, #700190, #699189, #701097]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Elad Alfassa, Alban Browaeys, Giovanni Campagna, Matthias Clasen, Allan Day,
 | 
			
		||||
  Tanner Doshier, Lionel Landwerlin, Rui Matos, Simon McVittie,
 | 
			
		||||
  Marta Milakovic, Florian Müllner, Gustavo Padovan, Jasper St. Pierre,
 | 
			
		||||
  Daiki Ueno, Tomeu Vizoso, Stef Walter, Colin Walters
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Matej Urbančič [sl], Kjartan Maraas [nb], Victor Ibragimov [tg],
 | 
			
		||||
  Dušan Kazik [sk], Gil Forcada [ca], Daniel Mustieles [es]
 | 
			
		||||
 | 
			
		||||
3.9.1
 | 
			
		||||
=====
 | 
			
		||||
* Add additional toggle-overview keybinding [Matthias; #698251]
 | 
			
		||||
* Disable <super> shortcut when sticky keys are enabled [Matthias; #685974]
 | 
			
		||||
* Disable tray context menu while a notification displays [Jasper; #695800]
 | 
			
		||||
* Watch GApplication busy state [Cosimo; #697207]
 | 
			
		||||
* Disable style transitions if animations are disabled [Jasper; #698391]
 | 
			
		||||
* Filter out hidden applications from "Frequent" view [Giovanni; #696949]
 | 
			
		||||
* Fix window previews swapping place randomly [Jasper; #694469, #698776]
 | 
			
		||||
* Add support for serialized GIcons in remote search providers [Cosimo; #698761]
 | 
			
		||||
* Fix hotcorner regression in RTL locales [Jasper; #698884]
 | 
			
		||||
* Allow some keybindings to work while a top bar menu is open [Florian; #698938]
 | 
			
		||||
* Make open-app-menu keybinding a toggle action [Florian; #686756]
 | 
			
		||||
* Only recognize common URL schemes in notification messages [Monica; #661225]
 | 
			
		||||
* Misc fixes and cleanups [Tim, Jasper, Florian, Giovanni, Owen; #698531,
 | 
			
		||||
  #698622, #698427, #698483, #698513, #697203, #698959, #698918, #699029,
 | 
			
		||||
  #699075, #696720, #649748]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Giovanni Campagna, Cosimo Cecchi, Monica Chelliah, Matthias Clasen, Tim Lunn,
 | 
			
		||||
  Florian Müllner, Jasper St. Pierre, Michael Wood, Owen W. Taylor
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Fran Diéguez [gl], Muhammet Kara [tr], Daniel Mustieles [es],
 | 
			
		||||
  Gil Forcada [ia], Anish A [ml], Dimitris Spingos [el], Marek Černocký [cs],
 | 
			
		||||
  Žygimantas Beručka [lt]
 | 
			
		||||
 | 
			
		||||
3.8.1
 | 
			
		||||
=====
 | 
			
		||||
* Clip window group during startup animation [Jasper; #696323]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								configure.ac
									
									
									
									
									
								
							@@ -1,5 +1,5 @@
 | 
			
		||||
AC_PREREQ(2.63)
 | 
			
		||||
AC_INIT([gnome-shell],[3.8.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
 | 
			
		||||
AC_INIT([gnome-shell],[3.9.2],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
 | 
			
		||||
 | 
			
		||||
AC_CONFIG_HEADERS([config.h])
 | 
			
		||||
AC_CONFIG_SRCDIR([src/shell-global.c])
 | 
			
		||||
@@ -63,9 +63,9 @@ AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
 | 
			
		||||
CLUTTER_MIN_VERSION=1.13.4
 | 
			
		||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
 | 
			
		||||
GJS_MIN_VERSION=1.35.4
 | 
			
		||||
MUTTER_MIN_VERSION=3.8.1
 | 
			
		||||
MUTTER_MIN_VERSION=3.9.2
 | 
			
		||||
GTK_MIN_VERSION=3.7.9
 | 
			
		||||
GIO_MIN_VERSION=2.35.0
 | 
			
		||||
GIO_MIN_VERSION=2.37.0
 | 
			
		||||
LIBECAL_MIN_VERSION=3.5.3
 | 
			
		||||
LIBEDATASERVER_MIN_VERSION=3.5.3
 | 
			
		||||
TELEPATHY_GLIB_MIN_VERSION=0.17.5
 | 
			
		||||
@@ -74,7 +74,7 @@ STARTUP_NOTIFICATION_MIN_VERSION=0.11
 | 
			
		||||
GCR_MIN_VERSION=3.3.90
 | 
			
		||||
GNOME_DESKTOP_REQUIRED_VERSION=3.7.90
 | 
			
		||||
GNOME_MENUS_REQUIRED_VERSION=3.5.3
 | 
			
		||||
NETWORKMANAGER_MIN_VERSION=0.9.6
 | 
			
		||||
NETWORKMANAGER_MIN_VERSION=0.9.8
 | 
			
		||||
PULSE_MIN_VERS=2.0
 | 
			
		||||
 | 
			
		||||
# Collect more than 20 libraries for a prize!
 | 
			
		||||
@@ -96,7 +96,7 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
 | 
			
		||||
                               polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes
 | 
			
		||||
                               libnm-glib libnm-util >= $NETWORKMANAGER_MIN_VERSION
 | 
			
		||||
                               libnm-gtk >= $NETWORKMANAGER_MIN_VERSION
 | 
			
		||||
                               libsecret-unstable gcr-3 >= $GCR_MIN_VERSION)
 | 
			
		||||
                               libsecret-unstable gcr-base-3 >= $GCR_MIN_VERSION)
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(GNOME_SHELL_JS, gio-2.0 gjs-internals-1.0 >= $GJS_MIN_VERSION)
 | 
			
		||||
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.8 x11)
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,9 @@
 | 
			
		||||
	<KeyListEntry name="focus-active-notification"
 | 
			
		||||
                      _description="Focus the active notification"/>
 | 
			
		||||
 | 
			
		||||
	<KeyListEntry name="toggle-overview"
 | 
			
		||||
                      _description="Show the overview"/>
 | 
			
		||||
 | 
			
		||||
	<KeyListEntry name="toggle-application-view"
 | 
			
		||||
                      _description="Show all applications"/>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@ desktop_DATA = gnome-shell.desktop gnome-shell-extension-prefs.desktop
 | 
			
		||||
 | 
			
		||||
introspectiondir = $(datadir)/dbus-1/interfaces
 | 
			
		||||
introspection_DATA =				\
 | 
			
		||||
	org.gnome.Shell.Screencast.xml		\
 | 
			
		||||
	org.gnome.Shell.Screenshot.xml		\
 | 
			
		||||
	org.gnome.ShellSearchProvider.xml	\
 | 
			
		||||
	org.gnome.ShellSearchProvider2.xml
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										96
									
								
								data/org.gnome.Shell.Screencast.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								data/org.gnome.Shell.Screencast.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
<!DOCTYPE node PUBLIC
 | 
			
		||||
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
 | 
			
		||||
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
 | 
			
		||||
<node>
 | 
			
		||||
 | 
			
		||||
  <!--
 | 
			
		||||
      org.gnome.Shell.Screencast:
 | 
			
		||||
      @short_description: Screencast interface
 | 
			
		||||
 | 
			
		||||
      The interface used to record screen contents.
 | 
			
		||||
  -->
 | 
			
		||||
  <interface name="org.gnome.Shell.Screencast">
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
        Screencast:
 | 
			
		||||
        @file_template: the template for the filename to use
 | 
			
		||||
        @options: a dictionary of optional parameters
 | 
			
		||||
        @success: whether the screencast was started successfully
 | 
			
		||||
        @filename_used: the file where the screencast is being saved
 | 
			
		||||
 | 
			
		||||
        Records a screencast of the whole screen and saves it
 | 
			
		||||
        (by default) as webm video under a filename derived from
 | 
			
		||||
        @file_template. The template is either a relative or absolute
 | 
			
		||||
        filename which may contain some escape sequences - %d and %t
 | 
			
		||||
        will be replaced by the start date and time of the recording.
 | 
			
		||||
        If a relative name is used, the screencast will be saved in the
 | 
			
		||||
        $XDG_VIDEOS_DIR if it exists, or the home directory otherwise.
 | 
			
		||||
        The actual filename of the saved video is returned in @filename_used.
 | 
			
		||||
        The set of optional parameters in @options currently consists of:
 | 
			
		||||
            'draw-cursor'(b): whether the cursor should be included in the
 | 
			
		||||
                              recording (true)
 | 
			
		||||
            'framerate'(i): the number of frames per second that should be
 | 
			
		||||
                            recorded if possible (30)
 | 
			
		||||
            'pipeline'(s): the GStreamer pipeline used to encode recordings
 | 
			
		||||
                           in gst-launch format; if not specified, the
 | 
			
		||||
                           recorder will produce vp8 (webm) video (unset)
 | 
			
		||||
    -->
 | 
			
		||||
    <method name="Screencast">
 | 
			
		||||
      <arg type="s" direction="in" name="file_template"/>
 | 
			
		||||
      <arg type="a{sv}" direction="in" name="options"/>
 | 
			
		||||
      <arg type="b" direction="in" name="flash"/>
 | 
			
		||||
      <arg type="b" direction="out" name="success"/>
 | 
			
		||||
      <arg type="s" direction="out" name="filename_used"/>
 | 
			
		||||
    </method>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
        ScreencastArea:
 | 
			
		||||
        @x: the X coordinate of the area to capture
 | 
			
		||||
        @y: the Y coordinate of the area to capture
 | 
			
		||||
        @width: the width of the area to capture
 | 
			
		||||
        @height: the height of the area to capture
 | 
			
		||||
        @file_template: the template for the filename to use
 | 
			
		||||
        @options: a dictionary of optional parameters
 | 
			
		||||
        @success: whether the screencast was started successfully
 | 
			
		||||
        @filename_used: the file where the screencast is being saved
 | 
			
		||||
 | 
			
		||||
        Records a screencast of the passed in area and saves it
 | 
			
		||||
        (by default) as webm video under a filename derived from
 | 
			
		||||
        @file_template. The template is either a relative or absolute
 | 
			
		||||
        filename which may contain some escape sequences - %d and %t
 | 
			
		||||
        will be replaced by the start date and time of the recording.
 | 
			
		||||
        If a relative name is used, the screencast will be saved in the
 | 
			
		||||
        $XDG_VIDEOS_DIR if it exists, or the home directory otherwise.
 | 
			
		||||
        The actual filename of the saved video is returned in @filename_used.
 | 
			
		||||
        The set of optional parameters in @options currently consists of:
 | 
			
		||||
            'draw-cursor'(b): whether the cursor should be included in the
 | 
			
		||||
                              recording (true)
 | 
			
		||||
            'framerate'(i): the number of frames per second that should be
 | 
			
		||||
                            recorded if possible (30)
 | 
			
		||||
            'pipeline'(s): the GStreamer pipeline used to encode recordings
 | 
			
		||||
                           in gst-launch format; if not specified, the
 | 
			
		||||
                           recorder will produce vp8 (webm) video (unset)
 | 
			
		||||
    -->
 | 
			
		||||
    <method name="ScreencastArea">
 | 
			
		||||
      <arg type="i" direction="in" name="x"/>
 | 
			
		||||
      <arg type="i" direction="in" name="y"/>
 | 
			
		||||
      <arg type="i" direction="in" name="width"/>
 | 
			
		||||
      <arg type="i" direction="in" name="height"/>
 | 
			
		||||
      <arg type="s" direction="in" name="file_template"/>
 | 
			
		||||
      <arg type="a{sv}" direction="in" name="options"/>
 | 
			
		||||
      <arg type="b" direction="out" name="success"/>
 | 
			
		||||
      <arg type="s" direction="out" name="filename_used"/>
 | 
			
		||||
    </method>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
        StopScreencast:
 | 
			
		||||
        @success: whether stopping the recording was successful
 | 
			
		||||
 | 
			
		||||
        Stop the recording started by either Screencast or ScreencastArea.
 | 
			
		||||
    -->
 | 
			
		||||
    <method name="StopScreencast">
 | 
			
		||||
      <arg type="b" direction="out" name="success"/>
 | 
			
		||||
    </method>
 | 
			
		||||
 | 
			
		||||
  </interface>
 | 
			
		||||
</node>
 | 
			
		||||
@@ -46,7 +46,7 @@
 | 
			
		||||
    <!--
 | 
			
		||||
        GetResultMetas:
 | 
			
		||||
        @identifiers: An array of result identifiers as returned by GetInitialResultSet() or GetSubsearchResultSet()
 | 
			
		||||
        @metas: A dictionary describing the given search result, containing a human-readable 'name' (string), along with the result identifier this meta is for, 'id' (string). Optionally, either 'gicon' (a serialized GIcon) or 'icon-data' (raw image data as (iiibiiay) - width, height, rowstride, has-alpha, bits per sample, channels, data) can be specified if the result can be better served with a thumbnail of the content (such as with images). A 'description' field (string) may also be specified if more context would help the user find the desired result.
 | 
			
		||||
        @metas: A dictionary describing the given search result, containing a human-readable 'name' (string), along with the result identifier this meta is for, 'id' (string). Optionally, 'icon' (a serialized GIcon as obtained by g_icon_serialize) can be specified if the result can be better served with a thumbnail of the content (such as with images). 'gicon' (a serialized GIcon as obtained by g_icon_to_string) or 'icon-data' (raw image data as (iiibiiay) - width, height, rowstride, has-alpha, bits per sample, channels, data) are deprecated values that can also be used for that purpose. A 'description' field (string) may also be specified if more context would help the user find the desired result.
 | 
			
		||||
 | 
			
		||||
        Return an array of meta data used to display each given result
 | 
			
		||||
    -->
 | 
			
		||||
 
 | 
			
		||||
@@ -21,16 +21,6 @@
 | 
			
		||||
        EnableExtension and DisableExtension DBus methods on org.gnome.Shell.
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="enable-app-monitoring" type="b">
 | 
			
		||||
      <default>true</default>
 | 
			
		||||
      <_summary>Whether to collect stats about applications usage</_summary>
 | 
			
		||||
      <_description>
 | 
			
		||||
        The shell normally monitors active applications in order to present
 | 
			
		||||
        the most used ones (e.g. in launchers). While this data will be
 | 
			
		||||
        kept private, you may want to disable this for privacy reasons.
 | 
			
		||||
        Please note that doing so won't remove already saved data.
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="favorite-apps" type="as">
 | 
			
		||||
      <default>[ 'epiphany.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'libreoffice-writer.desktop', 'nautilus.desktop', 'gnome-documents.desktop' ]</default>
 | 
			
		||||
      <_summary>List of desktop file IDs for favorite applications</_summary>
 | 
			
		||||
@@ -117,6 +107,13 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
 | 
			
		||||
        Overview.
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="toggle-overview" type="as">
 | 
			
		||||
      <default>["<Super>s"]</default>
 | 
			
		||||
      <_summary>Keybinding to open the overview</_summary>
 | 
			
		||||
      <_description>
 | 
			
		||||
        Keybinding to open the Activities Overview.
 | 
			
		||||
      </_description>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="toggle-message-tray" type="as">
 | 
			
		||||
      <default>["<Super>m"]</default>
 | 
			
		||||
      <_summary>Keybinding to toggle the visibility of the message tray</_summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -125,6 +125,10 @@ StScrollBar StButton#vhandle:active {
 | 
			
		||||
 | 
			
		||||
/* PopupMenu */
 | 
			
		||||
 | 
			
		||||
.popup-menu-ornament {
 | 
			
		||||
    text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-menu-boxpointer,
 | 
			
		||||
.candidate-popup-boxpointer {
 | 
			
		||||
    -arrow-border-radius: 8px;
 | 
			
		||||
@@ -377,6 +381,7 @@ StScrollBar StButton#vhandle:active {
 | 
			
		||||
/* Entries */
 | 
			
		||||
 | 
			
		||||
#searchEntry,
 | 
			
		||||
.login-dialog StEntry,
 | 
			
		||||
.notification StEntry,
 | 
			
		||||
.modal-dialog StEntry {
 | 
			
		||||
    color: rgb(64, 64, 64);
 | 
			
		||||
@@ -388,6 +393,7 @@ StScrollBar StButton#vhandle:active {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#searchEntry,
 | 
			
		||||
.login-dialog StEntry,
 | 
			
		||||
.run-dialog-entry,
 | 
			
		||||
.notification StEntry {
 | 
			
		||||
    border: 2px solid rgba(245,245,245,0.2);
 | 
			
		||||
@@ -400,6 +406,7 @@ StScrollBar StButton#vhandle:active {
 | 
			
		||||
 | 
			
		||||
#searchEntry:focus,
 | 
			
		||||
#searchEntry:hover,
 | 
			
		||||
.login-dialog StEntry:focus,
 | 
			
		||||
.notification StEntry:focus,
 | 
			
		||||
.modal-dialog StEntry {
 | 
			
		||||
    border: 2px solid rgb(136,138,133);
 | 
			
		||||
@@ -409,6 +416,7 @@ StScrollBar StButton#vhandle:active {
 | 
			
		||||
    box-shadow: inset 0px 2px 4px rgba(0,0,0,0.6);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog StEntry:focus,
 | 
			
		||||
.notification StEntry:focus,
 | 
			
		||||
.modal-dialog StEntry:focus {
 | 
			
		||||
    border: 2px solid #3465a4;
 | 
			
		||||
@@ -432,6 +440,7 @@ StScrollBar StButton#vhandle:active {
 | 
			
		||||
    transition-duration: 0ms;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog StEntry,
 | 
			
		||||
.notification StEntry,
 | 
			
		||||
.modal-dialog StEntry {
 | 
			
		||||
    border-radius: 5px;
 | 
			
		||||
@@ -445,6 +454,7 @@ StScrollBar StButton#vhandle:active {
 | 
			
		||||
    padding: 0 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog StEntry:insensitive,
 | 
			
		||||
.modal-dialog StEntry:insensitive {
 | 
			
		||||
    border-color: #666666;
 | 
			
		||||
    color: #9f9f9f;
 | 
			
		||||
@@ -1184,7 +1194,8 @@ StScrollBar StButton#vhandle:active {
 | 
			
		||||
    background-image: url("calendar-arrow-right.svg");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.calendar-change-month-back:hover {
 | 
			
		||||
.calendar-change-month-back:hover,
 | 
			
		||||
.calendar-change-month-back:focus {
 | 
			
		||||
    background-color: #999999;
 | 
			
		||||
}
 | 
			
		||||
.calendar-change-month-back:active {
 | 
			
		||||
@@ -1202,7 +1213,8 @@ StScrollBar StButton#vhandle:active {
 | 
			
		||||
    background-image: url("calendar-arrow-left.svg");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.calendar-change-month-forward:hover {
 | 
			
		||||
.calendar-change-month-forward:hover,
 | 
			
		||||
.calendar-change-month-forward:focus {
 | 
			
		||||
    background-color: #999999;
 | 
			
		||||
}
 | 
			
		||||
.calendar-change-month-forward:active {
 | 
			
		||||
@@ -1223,7 +1235,8 @@ StScrollBar StButton#vhandle:active {
 | 
			
		||||
    height: 2.4em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.calendar-day-base:hover {
 | 
			
		||||
.calendar-day-base:hover,
 | 
			
		||||
.calendar-day-base:focus {
 | 
			
		||||
    background-color: #777777;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2227,8 +2240,13 @@ StScrollBar StButton#vhandle:active {
 | 
			
		||||
    min-width: 350px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-button-box {
 | 
			
		||||
    spacing: 21px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-prompt-login-hint-message {
 | 
			
		||||
    font-size: 10.5pt;
 | 
			
		||||
    min-width: 480px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-user-list-view {
 | 
			
		||||
@@ -2335,55 +2353,50 @@ StScrollBar StButton#vhandle:active {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-prompt-entry {
 | 
			
		||||
    width: 15em;
 | 
			
		||||
    width: 480px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list {
 | 
			
		||||
    color: #ffffff;
 | 
			
		||||
    font-size: 10.5pt;
 | 
			
		||||
.login-dialog-session-list,
 | 
			
		||||
.login-dialog-session-list-item {
 | 
			
		||||
    color: #babdb6;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-button:focus,
 | 
			
		||||
.login-dialog-session-list-button:active,
 | 
			
		||||
.login-dialog-session-list-button:hover,
 | 
			
		||||
.login-dialog-session-list-item:focus,
 | 
			
		||||
.login-dialog-session-list-item:hover {
 | 
			
		||||
    color: white;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-button {
 | 
			
		||||
    padding: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-button:focus {
 | 
			
		||||
    background-color: #4c4c4c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-button:active {
 | 
			
		||||
    background-color: #4c4c4c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-button:hover {
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-scroll-view {
 | 
			
		||||
    background-gradient-start: rgba(80,80,80,0.3);
 | 
			
		||||
    background-gradient-end: rgba(80,80,80,0.7);
 | 
			
		||||
    background-gradient-direction: vertical;
 | 
			
		||||
    box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9);
 | 
			
		||||
    border-radius: 8px;
 | 
			
		||||
    border: 1px solid rgba(80,80,80,1.0);
 | 
			
		||||
    padding: .5em;
 | 
			
		||||
    padding: 6px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-item:focus {
 | 
			
		||||
    background-color: #666666;
 | 
			
		||||
.login-dialog-session-list-item {
 | 
			
		||||
    padding-bottom: 6px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-triangle {
 | 
			
		||||
    padding-right: .5em;
 | 
			
		||||
    padding-right: 6px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-item-box {
 | 
			
		||||
    spacing: .25em;
 | 
			
		||||
    padding-left: 6px;
 | 
			
		||||
    spacing: 6px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-session-list-item-dot {
 | 
			
		||||
    width: .75em;
 | 
			
		||||
    height: .75em;
 | 
			
		||||
    width: 10px;
 | 
			
		||||
    height: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog-logo-bin {
 | 
			
		||||
    padding: 24px 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.login-dialog .modal-dialog-button-box {
 | 
			
		||||
@@ -2448,6 +2461,7 @@ StScrollBar StButton#vhandle:active {
 | 
			
		||||
 | 
			
		||||
.screen-shield-background {
 | 
			
		||||
    background: black;
 | 
			
		||||
    box-shadow: 0px 4px 8px rgba(0,0,0,0.9);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#lockDialogGroup {
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,7 @@
 | 
			
		||||
    <xi:include href="doc-gen-org.gnome.Shell.SearchProvider.xml"/>
 | 
			
		||||
    <xi:include href="doc-gen-org.gnome.Shell.SearchProvider2.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-global.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-keybinding-modes.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-wm.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-xfixes-cursor.xml"/>
 | 
			
		||||
    <xi:include href="xml/shell-util.xml"/>
 | 
			
		||||
 
 | 
			
		||||
@@ -17,13 +17,8 @@ misc/config.js: misc/config.js.in Makefile
 | 
			
		||||
jsdir = $(pkgdatadir)/js
 | 
			
		||||
 | 
			
		||||
nobase_dist_js_DATA = 	\
 | 
			
		||||
	gdm/batch.js		\
 | 
			
		||||
	gdm/fingerprint.js	\
 | 
			
		||||
	gdm/loginDialog.js	\
 | 
			
		||||
	gdm/powerMenu.js	\
 | 
			
		||||
	gdm/realmd.js		\
 | 
			
		||||
	gdm/util.js		\
 | 
			
		||||
	extensionPrefs/main.js	\
 | 
			
		||||
	misc/batch.js		\
 | 
			
		||||
	misc/config.js		\
 | 
			
		||||
	misc/extensionUtils.js	\
 | 
			
		||||
	misc/fileUtils.js	\
 | 
			
		||||
@@ -37,6 +32,7 @@ nobase_dist_js_DATA = 	\
 | 
			
		||||
	misc/util.js		\
 | 
			
		||||
	perf/core.js		\
 | 
			
		||||
	ui/altTab.js		\
 | 
			
		||||
	ui/animation.js		\
 | 
			
		||||
	ui/appDisplay.js	\
 | 
			
		||||
	ui/appFavorites.js	\
 | 
			
		||||
	ui/backgroundMenu.js	\
 | 
			
		||||
@@ -77,7 +73,9 @@ nobase_dist_js_DATA = 	\
 | 
			
		||||
	ui/pointerWatcher.js    \
 | 
			
		||||
	ui/popupMenu.js		\
 | 
			
		||||
	ui/remoteSearch.js	\
 | 
			
		||||
	ui/remoteMenu.js	\
 | 
			
		||||
	ui/runDialog.js		\
 | 
			
		||||
	ui/screencast.js	\
 | 
			
		||||
	ui/screenshot.js	\
 | 
			
		||||
        ui/screenShield.js	\
 | 
			
		||||
	ui/scripting.js		\
 | 
			
		||||
@@ -93,7 +91,7 @@ nobase_dist_js_DATA = 	\
 | 
			
		||||
	ui/status/bluetooth.js	\
 | 
			
		||||
	ui/switcherPopup.js	\
 | 
			
		||||
	ui/tweener.js		\
 | 
			
		||||
	ui/unlockDialog.js	\
 | 
			
		||||
	ui/userAvatar.js	\
 | 
			
		||||
	ui/userMenu.js		\
 | 
			
		||||
	ui/userWidget.js	\
 | 
			
		||||
	ui/viewSelector.js	\
 | 
			
		||||
@@ -105,6 +103,14 @@ nobase_dist_js_DATA = 	\
 | 
			
		||||
	ui/workspacesView.js	\
 | 
			
		||||
	ui/workspaceSwitcherPopup.js    \
 | 
			
		||||
	ui/xdndHandler.js	\
 | 
			
		||||
	ui/auth/fingerprint.js	\
 | 
			
		||||
	ui/auth/loginDialog.js	\
 | 
			
		||||
	ui/auth/powerMenu.js	\
 | 
			
		||||
	ui/auth/realmd.js	\
 | 
			
		||||
	ui/auth/sessionList.js	\
 | 
			
		||||
	ui/auth/unlockDialog.js	\
 | 
			
		||||
	ui/auth/userList.js	\
 | 
			
		||||
	ui/auth/util.js		\
 | 
			
		||||
	ui/components/__init__.js		\
 | 
			
		||||
	ui/components/autorunManager.js		\
 | 
			
		||||
	ui/components/automountManager.js	\
 | 
			
		||||
 
 | 
			
		||||
@@ -58,6 +58,7 @@ const Map = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _init: function(iterable) {
 | 
			
		||||
        this._pool = { };
 | 
			
		||||
        this._size = 0;
 | 
			
		||||
 | 
			
		||||
        if (iterable) {
 | 
			
		||||
            for (let i = 0; i < iterable.length; i++) {
 | 
			
		||||
@@ -99,6 +100,7 @@ const Map = new Lang.Class({
 | 
			
		||||
            node.value = value;
 | 
			
		||||
        } else {
 | 
			
		||||
            this._pool[hash] = { key: key, value: value };
 | 
			
		||||
            this._size++;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -108,6 +110,7 @@ const Map = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        if (node && _sameValue(node.key, key)) {
 | 
			
		||||
            delete this._pool[hash];
 | 
			
		||||
            this._size--;
 | 
			
		||||
            return [node.key, node.value];
 | 
			
		||||
        } else {
 | 
			
		||||
            return [null, null];
 | 
			
		||||
@@ -136,6 +139,6 @@ const Map = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    size: function() {
 | 
			
		||||
        return Object.getOwnPropertyNames(this._pool).length;
 | 
			
		||||
        return this._size;
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ const _urlRegexp = new RegExp(
 | 
			
		||||
    '(^|' + _leadingJunk + ')' +
 | 
			
		||||
    '(' +
 | 
			
		||||
        '(?:' +
 | 
			
		||||
            '[a-z][\\w-]+://' +                   // scheme://
 | 
			
		||||
            '(?:http|https|ftp)://' +             // scheme://
 | 
			
		||||
            '|' +
 | 
			
		||||
            'www\\d{0,3}[.]' +                    // www.
 | 
			
		||||
            '|' +
 | 
			
		||||
 
 | 
			
		||||
@@ -234,7 +234,7 @@ const AppSwitcherPopup = new Lang.Class({
 | 
			
		||||
    _finish : function(timestamp) {
 | 
			
		||||
        let appIcon = this._items[this._selectedIndex];
 | 
			
		||||
        if (this._currentWindow < 0)
 | 
			
		||||
            appIcon.app.activate_full(-1, timestamp);
 | 
			
		||||
            appIcon.app.activate_window(appIcon.cachedWindows[0], timestamp);
 | 
			
		||||
        else
 | 
			
		||||
            Main.activateWindow(appIcon.cachedWindows[this._currentWindow], timestamp);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										84
									
								
								js/ui/animation.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								js/ui/animation.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Atk = imports.gi.Atk;
 | 
			
		||||
 | 
			
		||||
const ANIMATED_ICON_UPDATE_TIMEOUT = 100;
 | 
			
		||||
 | 
			
		||||
const Animation = new Lang.Class({
 | 
			
		||||
    Name: 'Animation',
 | 
			
		||||
 | 
			
		||||
    _init: function(filename, width, height, speed) {
 | 
			
		||||
        this.actor = new St.Bin();
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 | 
			
		||||
        this._speed = speed;
 | 
			
		||||
 | 
			
		||||
        this._isLoaded = false;
 | 
			
		||||
        this._isPlaying = false;
 | 
			
		||||
        this._timeoutId = 0;
 | 
			
		||||
        this._frame = 0;
 | 
			
		||||
        this._animations = St.TextureCache.get_default().load_sliced_image (filename, width, height,
 | 
			
		||||
                                                                            Lang.bind(this, this._animationsLoaded));
 | 
			
		||||
        this.actor.set_child(this._animations);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    play: function() {
 | 
			
		||||
        if (this._isLoaded && this._timeoutId == 0) {
 | 
			
		||||
            if (this._frame == 0)
 | 
			
		||||
                this._showFrame(0);
 | 
			
		||||
 | 
			
		||||
            this._timeoutId = Mainloop.timeout_add(this._speed, Lang.bind(this, this._update));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._isPlaying = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    stop: function() {
 | 
			
		||||
        if (this._timeoutId > 0) {
 | 
			
		||||
            Mainloop.source_remove(this._timeoutId);
 | 
			
		||||
            this._timeoutId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._isPlaying = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showFrame: function(frame) {
 | 
			
		||||
        let oldFrameActor = this._animations.get_child_at_index(this._frame);
 | 
			
		||||
        if (oldFrameActor)
 | 
			
		||||
            oldFrameActor.hide();
 | 
			
		||||
 | 
			
		||||
        this._frame = (frame % this._animations.get_n_children());
 | 
			
		||||
 | 
			
		||||
        let newFrameActor = this._animations.get_child_at_index(this._frame);
 | 
			
		||||
        if (newFrameActor)
 | 
			
		||||
            newFrameActor.show();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _update: function() {
 | 
			
		||||
        this._showFrame(this._frame + 1);
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _animationsLoaded: function() {
 | 
			
		||||
        this._isLoaded = true;
 | 
			
		||||
 | 
			
		||||
        if (this._isPlaying)
 | 
			
		||||
            this.play();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDestroy: function() {
 | 
			
		||||
        this.stop();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AnimatedIcon = new Lang.Class({
 | 
			
		||||
    Name: 'AnimatedIcon',
 | 
			
		||||
    Extends: Animation,
 | 
			
		||||
 | 
			
		||||
    _init: function(filename, size) {
 | 
			
		||||
        this.parent(filename, size, size, ANIMATED_ICON_UPDATE_TIMEOUT);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
@@ -187,6 +187,9 @@ const AllView = new Lang.Class({
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.parent();
 | 
			
		||||
 | 
			
		||||
        this._grid.actor.y_align = Clutter.ActorAlign.START;
 | 
			
		||||
        this._grid.actor.y_expand = true;
 | 
			
		||||
 | 
			
		||||
        let box = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        this._stack = new St.Widget({ layout_manager: new AllViewLayout() });
 | 
			
		||||
        this._stack.add_actor(this._grid.actor);
 | 
			
		||||
@@ -276,8 +279,12 @@ const AllView = new Lang.Class({
 | 
			
		||||
                this._eventBlocker.reactive = isOpen;
 | 
			
		||||
                this._currentPopup = isOpen ? popup : null;
 | 
			
		||||
                this._updateIconOpacities(isOpen);
 | 
			
		||||
                if (isOpen)
 | 
			
		||||
                if (isOpen) {
 | 
			
		||||
                    this._ensureIconVisible(popup.actor);
 | 
			
		||||
                    this._grid.actor.y = popup.parentOffset;
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._grid.actor.y = 0;
 | 
			
		||||
                }
 | 
			
		||||
            }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -316,6 +323,8 @@ const FrequentView = new Lang.Class({
 | 
			
		||||
    loadApps: function() {
 | 
			
		||||
        let mostUsed = this._usage.get_most_used ("");
 | 
			
		||||
        for (let i = 0; i < mostUsed.length; i++) {
 | 
			
		||||
            if (!mostUsed[i].get_app_info().should_show())
 | 
			
		||||
                continue;
 | 
			
		||||
            let appIcon = new AppIcon(mostUsed[i]);
 | 
			
		||||
            this._grid.addItem(appIcon.actor, -1);
 | 
			
		||||
        }
 | 
			
		||||
@@ -341,6 +350,9 @@ const AppDisplay = new Lang.Class({
 | 
			
		||||
        global.settings.connect('changed::app-folder-categories', Lang.bind(this, function() {
 | 
			
		||||
            Main.queueDeferredWork(this._allAppsWorkId);
 | 
			
		||||
        }));
 | 
			
		||||
        this._privacySettings = new Gio.Settings({ schema: 'org.gnome.desktop.privacy' });
 | 
			
		||||
        this._privacySettings.connect('changed::remember-app-usage',
 | 
			
		||||
                                      Lang.bind(this, this._updateFrequentVisibility));
 | 
			
		||||
 | 
			
		||||
        this._views = [];
 | 
			
		||||
 | 
			
		||||
@@ -384,6 +396,7 @@ const AppDisplay = new Lang.Class({
 | 
			
		||||
                }));
 | 
			
		||||
        }
 | 
			
		||||
        this._showView(Views.FREQUENT);
 | 
			
		||||
        this._updateFrequentVisibility();
 | 
			
		||||
 | 
			
		||||
        // We need a dummy actor to catch the keyboard focus if the
 | 
			
		||||
        // user Ctrl-Alt-Tabs here before the deferred work creates
 | 
			
		||||
@@ -413,6 +426,19 @@ const AppDisplay = new Lang.Class({
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateFrequentVisibility: function() {
 | 
			
		||||
        let enabled = this._privacySettings.get_boolean('remember-app-usage');
 | 
			
		||||
        this._views[Views.FREQUENT].control.visible = enabled;
 | 
			
		||||
 | 
			
		||||
        let visibleViews = this._views.filter(function(v) {
 | 
			
		||||
            return v.control.visible;
 | 
			
		||||
        });
 | 
			
		||||
        this._controls.visible = visibleViews.length > 1;
 | 
			
		||||
 | 
			
		||||
        if (!enabled && this._views[Views.FREQUENT].view.actor.visible)
 | 
			
		||||
            this._showView(Views.ALL);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _redisplay: function() {
 | 
			
		||||
        this._redisplayFrequentApps();
 | 
			
		||||
        this._redisplayAllApps();
 | 
			
		||||
@@ -483,11 +509,11 @@ const AppSearchProvider = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getInitialResultSet: function(terms) {
 | 
			
		||||
        this.searchSystem.pushResults(this, this._appSys.initial_search(terms));
 | 
			
		||||
        this.searchSystem.setResults(this, this._appSys.initial_search(terms));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getSubsearchResultSet: function(previousResults, terms) {
 | 
			
		||||
        this.searchSystem.pushResults(this, this._appSys.subsearch(previousResults, terms));
 | 
			
		||||
        this.searchSystem.setResults(this, this._appSys.subsearch(previousResults, terms));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activateResult: function(app) {
 | 
			
		||||
@@ -572,7 +598,11 @@ const FolderIcon = new Lang.Class({
 | 
			
		||||
        // Position the popup above or below the source icon
 | 
			
		||||
        if (side == St.Side.BOTTOM) {
 | 
			
		||||
            this._popup.actor.show();
 | 
			
		||||
            this._popup.actor.y = this.actor.y - this._popup.actor.height;
 | 
			
		||||
            let closeButtonOffset = -this._popup.closeButton.translation_y;
 | 
			
		||||
            let y = this.actor.y - this._popup.actor.height;
 | 
			
		||||
            let yWithButton = y - closeButtonOffset;
 | 
			
		||||
            this._popup.parentOffset = yWithButton < 0 ? -yWithButton : 0;
 | 
			
		||||
            this._popup.actor.y = Math.max(y, closeButtonOffset);
 | 
			
		||||
            this._popup.actor.hide();
 | 
			
		||||
        } else {
 | 
			
		||||
            this._popup.actor.y = this.actor.y + this.actor.height;
 | 
			
		||||
@@ -595,6 +625,7 @@ const AppFolderPopup = new Lang.Class({
 | 
			
		||||
        this._arrowSide = side;
 | 
			
		||||
 | 
			
		||||
        this._isOpen = false;
 | 
			
		||||
        this.parentOffset = 0;
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.Widget({ layout_manager: new Clutter.BinLayout(),
 | 
			
		||||
                                     visible: false,
 | 
			
		||||
@@ -618,17 +649,31 @@ const AppFolderPopup = new Lang.Class({
 | 
			
		||||
        this.actor.add_actor(this._boxPointer.actor);
 | 
			
		||||
        this._boxPointer.bin.set_child(this._view.actor);
 | 
			
		||||
 | 
			
		||||
        let closeButton = Util.makeCloseButton();
 | 
			
		||||
        closeButton.connect('clicked', Lang.bind(this, this.popdown));
 | 
			
		||||
        this.actor.add_actor(closeButton);
 | 
			
		||||
        this.closeButton = Util.makeCloseButton();
 | 
			
		||||
        this.closeButton.connect('clicked', Lang.bind(this, this.popdown));
 | 
			
		||||
        this.actor.add_actor(this.closeButton);
 | 
			
		||||
 | 
			
		||||
        this._boxPointer.actor.bind_property('opacity', closeButton, 'opacity',
 | 
			
		||||
        this._boxPointer.actor.bind_property('opacity', this.closeButton, 'opacity',
 | 
			
		||||
                                             GObject.BindingFlags.SYNC_CREATE);
 | 
			
		||||
 | 
			
		||||
        global.focus_manager.add_group(this.actor);
 | 
			
		||||
 | 
			
		||||
        source.actor.connect('destroy', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
                this.actor.destroy();
 | 
			
		||||
            }));
 | 
			
		||||
        this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPress));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeyPress: function(actor, event) {
 | 
			
		||||
        if (!this._isOpen)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (event.get_key_symbol() != Clutter.KEY_Escape)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        this.popdown();
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    toggle: function() {
 | 
			
		||||
@@ -643,6 +688,7 @@ const AppFolderPopup = new Lang.Class({
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
        this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
 | 
			
		||||
 | 
			
		||||
        this._boxPointer.setArrowActor(this._source.actor);
 | 
			
		||||
        this._boxPointer.show(BoxPointer.PopupAnimation.FADE |
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -23,7 +23,7 @@ const Lang = imports.lang;
 | 
			
		||||
 | 
			
		||||
const LoginManager = imports.misc.loginManager;
 | 
			
		||||
 | 
			
		||||
const GdmUtil = imports.gdm.util;
 | 
			
		||||
const AuthUtil = imports.ui.auth.util;
 | 
			
		||||
const PanelMenu = imports.ui.panelMenu;
 | 
			
		||||
const PopupMenu = imports.ui.popupMenu;
 | 
			
		||||
 | 
			
		||||
@@ -37,7 +37,7 @@ const PowerMenuButton = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._loginManager = LoginManager.getLoginManager();
 | 
			
		||||
 | 
			
		||||
        this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
 | 
			
		||||
        this._settings = new Gio.Settings({ schema: AuthUtil.LOGIN_SCREEN_SCHEMA });
 | 
			
		||||
        this._settings.connect('changed::disable-restart-buttons',
 | 
			
		||||
                               Lang.bind(this, this._updateVisibility));
 | 
			
		||||
 | 
			
		||||
@@ -63,7 +63,7 @@ const Manager = new Lang.Class({
 | 
			
		||||
                                           Lang.bind(this, this._reloadRealms))
 | 
			
		||||
        this._realms = {};
 | 
			
		||||
 | 
			
		||||
        this._aggregateProvider.connect('g-properties-changed',
 | 
			
		||||
        this._signalId = this._aggregateProvider.connect('g-properties-changed',
 | 
			
		||||
                                        Lang.bind(this, function(proxy, properties) {
 | 
			
		||||
                                            if ('Realms' in properties.deep_unpack())
 | 
			
		||||
                                                this._reloadRealms();
 | 
			
		||||
@@ -106,7 +106,7 @@ const Manager = new Lang.Class({
 | 
			
		||||
        realm.connect('g-properties-changed',
 | 
			
		||||
                      Lang.bind(this, function(proxy, properties) {
 | 
			
		||||
                                if ('Configured' in properties.deep_unpack())
 | 
			
		||||
                                    this._reloadRealm();
 | 
			
		||||
                                    this._reloadRealm(realm);
 | 
			
		||||
                                }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -134,6 +134,18 @@ const Manager = new Lang.Class({
 | 
			
		||||
        this._updateLoginFormat();
 | 
			
		||||
 | 
			
		||||
        return this._loginFormat;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    release: function() {
 | 
			
		||||
        Service(Gio.DBus.system,
 | 
			
		||||
                'org.freedesktop.realmd',
 | 
			
		||||
                '/org/freedesktop/realmd',
 | 
			
		||||
                function(service) {
 | 
			
		||||
                    service.ReleaseRemote();
 | 
			
		||||
                });
 | 
			
		||||
        this._aggregateProvider.disconnect(this._signalId);
 | 
			
		||||
        this._realms = { };
 | 
			
		||||
        this._updateLoginFormat();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(Manager.prototype)
 | 
			
		||||
							
								
								
									
										230
									
								
								js/ui/auth/sessionList.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										230
									
								
								js/ui/auth/sessionList.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,230 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2011 Red Hat, Inc
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2, or (at your option)
 | 
			
		||||
 * any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 | 
			
		||||
 * 02111-1307, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Gdm = imports.gi.Gdm;
 | 
			
		||||
 | 
			
		||||
const SessionListItem = new Lang.Class({
 | 
			
		||||
    Name: 'SessionListItem',
 | 
			
		||||
 | 
			
		||||
    _init: function(id, name) {
 | 
			
		||||
        this.id = id;
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.Button({ style_class: 'login-dialog-session-list-item',
 | 
			
		||||
                                     button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
 | 
			
		||||
                                     can_focus: true,
 | 
			
		||||
                                     reactive: true,
 | 
			
		||||
                                     x_fill: true,
 | 
			
		||||
                                     x_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        this._box = new St.BoxLayout({ style_class: 'login-dialog-session-list-item-box' });
 | 
			
		||||
 | 
			
		||||
        this.actor.add_actor(this._box);
 | 
			
		||||
        this.actor.connect('clicked', Lang.bind(this, this._onClicked));
 | 
			
		||||
 | 
			
		||||
        this._dot = new St.DrawingArea({ style_class: 'login-dialog-session-list-item-dot' });
 | 
			
		||||
        this._dot.connect('repaint', Lang.bind(this, this._onRepaintDot));
 | 
			
		||||
        this._box.add_actor(this._dot);
 | 
			
		||||
        this.setShowDot(false);
 | 
			
		||||
 | 
			
		||||
        let label = new St.Label({ style_class: 'login-dialog-session-list-item-label',
 | 
			
		||||
                                   text: name });
 | 
			
		||||
        this.actor.label_actor = label;
 | 
			
		||||
 | 
			
		||||
        this._box.add_actor(label);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setShowDot: function(show) {
 | 
			
		||||
        if (show)
 | 
			
		||||
            this._dot.opacity = 255;
 | 
			
		||||
        else
 | 
			
		||||
            this._dot.opacity = 0;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onRepaintDot: function(area) {
 | 
			
		||||
        let cr = area.get_context();
 | 
			
		||||
        let [width, height] = area.get_surface_size();
 | 
			
		||||
        let color = area.get_theme_node().get_foreground_color();
 | 
			
		||||
 | 
			
		||||
        cr.setSourceRGBA (color.red / 255,
 | 
			
		||||
                          color.green / 255,
 | 
			
		||||
                          color.blue / 255,
 | 
			
		||||
                          color.alpha / 255);
 | 
			
		||||
        cr.arc(width / 2, height / 2, width / 3, 0, 2 * Math.PI);
 | 
			
		||||
        cr.fill();
 | 
			
		||||
        cr.$dispose();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onClicked: function() {
 | 
			
		||||
        this.emit('activate');
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(SessionListItem.prototype);
 | 
			
		||||
 | 
			
		||||
const SessionList = new Lang.Class({
 | 
			
		||||
    Name: 'SessionList',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.actor = new St.Bin();
 | 
			
		||||
 | 
			
		||||
        this._box = new St.BoxLayout({ style_class: 'login-dialog-session-list',
 | 
			
		||||
                                       vertical: true});
 | 
			
		||||
        this.actor.child = this._box;
 | 
			
		||||
 | 
			
		||||
        this._button = new St.Button({ style_class: 'login-dialog-session-list-button',
 | 
			
		||||
                                       button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
 | 
			
		||||
                                       can_focus: true,
 | 
			
		||||
                                       x_fill: true,
 | 
			
		||||
                                       y_fill: true });
 | 
			
		||||
        let box = new St.BoxLayout();
 | 
			
		||||
        this._button.add_actor(box);
 | 
			
		||||
 | 
			
		||||
        this._triangle = new St.Label({ style_class: 'login-dialog-session-list-triangle',
 | 
			
		||||
                                        text: '\u25B8' });
 | 
			
		||||
        box.add_actor(this._triangle);
 | 
			
		||||
 | 
			
		||||
        let label = new St.Label({ style_class: 'login-dialog-session-list-label',
 | 
			
		||||
                                   text: _("Session…") });
 | 
			
		||||
        box.add_actor(label);
 | 
			
		||||
 | 
			
		||||
        this._button.connect('clicked',
 | 
			
		||||
                             Lang.bind(this, this._onClicked));
 | 
			
		||||
        this._box.add_actor(this._button);
 | 
			
		||||
        this._scrollView = new St.ScrollView({ style_class: 'login-dialog-session-list-scroll-view'});
 | 
			
		||||
        this._scrollView.set_policy(Gtk.PolicyType.NEVER,
 | 
			
		||||
                                    Gtk.PolicyType.AUTOMATIC);
 | 
			
		||||
        this._box.add_actor(this._scrollView);
 | 
			
		||||
        this._itemList = new St.BoxLayout({ style_class: 'login-dialog-session-item-list',
 | 
			
		||||
                                            vertical: true });
 | 
			
		||||
        this._scrollView.add_actor(this._itemList);
 | 
			
		||||
        this._hideSessions();
 | 
			
		||||
        this.isOpen = false;
 | 
			
		||||
        this._populate();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _hideSessions: function() {
 | 
			
		||||
        this._itemList.can_focus = false;
 | 
			
		||||
        this._itemList.reactive = false;
 | 
			
		||||
        this._scrollView.opacity = 0;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showSessions: function() {
 | 
			
		||||
        this._scrollView.opacity = 255;
 | 
			
		||||
        this._itemList.reactive = true;
 | 
			
		||||
        this._itemList.can_focus = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    open: function() {
 | 
			
		||||
        if (this.isOpen)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._button.add_style_pseudo_class('open');
 | 
			
		||||
        this._showSessions();
 | 
			
		||||
        this._triangle.set_text('\u25BE');
 | 
			
		||||
 | 
			
		||||
        this.isOpen = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    close: function() {
 | 
			
		||||
        if (!this.isOpen)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._button.remove_style_pseudo_class('open');
 | 
			
		||||
        this._hideSessions();
 | 
			
		||||
        this._triangle.set_text('\u25B8');
 | 
			
		||||
 | 
			
		||||
        this.isOpen = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onClicked: function() {
 | 
			
		||||
        if (!this.isOpen)
 | 
			
		||||
            this.open();
 | 
			
		||||
        else
 | 
			
		||||
            this.close();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    updateSensitivity: function(sensitive) {
 | 
			
		||||
        this._button.reactive = sensitive;
 | 
			
		||||
        this._button.can_focus = sensitive;
 | 
			
		||||
 | 
			
		||||
        for (let id in this._items)
 | 
			
		||||
            this._items[id].actor.reactive = sensitive;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setActiveSession: function(sessionId) {
 | 
			
		||||
         if (sessionId == this._activeSessionId)
 | 
			
		||||
             return;
 | 
			
		||||
 | 
			
		||||
         if (this._activeSessionId)
 | 
			
		||||
             this._items[this._activeSessionId].setShowDot(false);
 | 
			
		||||
 | 
			
		||||
         this._items[sessionId].setShowDot(true);
 | 
			
		||||
         this._activeSessionId = sessionId;
 | 
			
		||||
 | 
			
		||||
         this.emit('session-activated', this._activeSessionId);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _populate: function() {
 | 
			
		||||
        this._itemList.destroy_all_children();
 | 
			
		||||
        this._activeSessionId = null;
 | 
			
		||||
        this._items = {};
 | 
			
		||||
 | 
			
		||||
        let ids = Gdm.get_session_ids();
 | 
			
		||||
        ids.sort();
 | 
			
		||||
 | 
			
		||||
        if (ids.length <= 1) {
 | 
			
		||||
            this._box.hide();
 | 
			
		||||
            this._button.hide();
 | 
			
		||||
        } else {
 | 
			
		||||
            this._button.show();
 | 
			
		||||
            this._box.show();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < ids.length; i++) {
 | 
			
		||||
            let [sessionName, sessionDescription] = Gdm.get_session_name_and_description(ids[i]);
 | 
			
		||||
 | 
			
		||||
            let item = new SessionListItem(ids[i], sessionName);
 | 
			
		||||
            this._itemList.add_actor(item.actor);
 | 
			
		||||
            this._items[ids[i]] = item;
 | 
			
		||||
 | 
			
		||||
            if (!this._activeSessionId)
 | 
			
		||||
                this.setActiveSession(ids[i]);
 | 
			
		||||
 | 
			
		||||
            item.connect('activate',
 | 
			
		||||
                         Lang.bind(this, function() {
 | 
			
		||||
                             this.setActiveSession(item.id);
 | 
			
		||||
                         }));
 | 
			
		||||
 | 
			
		||||
            item.actor.can_focus = this._itemList.can_focus;
 | 
			
		||||
            let signalId = this._itemList.connect('notify::can-focus',
 | 
			
		||||
                                                  Lang.bind(this, function() {
 | 
			
		||||
                                                      item.actor.can_focus = this._itemList.can_focus;
 | 
			
		||||
                                                  }));
 | 
			
		||||
            item.actor.connect('destroy',
 | 
			
		||||
                               Lang.bind(this, function() {
 | 
			
		||||
                                   this._itemList.disconnect(signalId);
 | 
			
		||||
                               }));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(SessionList.prototype);
 | 
			
		||||
@@ -6,23 +6,17 @@ const Gdm  = imports.gi.Gdm;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const GnomeDesktop = imports.gi.GnomeDesktop;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const Panel = imports.ui.panel;
 | 
			
		||||
const ShellEntry = imports.ui.shellEntry;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const UserMenu = imports.ui.userMenu;
 | 
			
		||||
const UserWidget = imports.ui.userWidget;
 | 
			
		||||
 | 
			
		||||
const Batch = imports.gdm.batch;
 | 
			
		||||
const GdmUtil = imports.gdm.util;
 | 
			
		||||
const LoginDialog = imports.gdm.loginDialog;
 | 
			
		||||
const AuthUtil = imports.ui.auth.util;
 | 
			
		||||
const Batch = imports.misc.batch;
 | 
			
		||||
 | 
			
		||||
// The timeout before going back automatically to the lock screen (in seconds)
 | 
			
		||||
const IDLE_TIMEOUT = 2 * 60;
 | 
			
		||||
@@ -46,7 +40,7 @@ const UnlockDialog = new Lang.Class({
 | 
			
		||||
        this._firstQuestion = true;
 | 
			
		||||
 | 
			
		||||
        this._greeterClient = new Gdm.Client();
 | 
			
		||||
        this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true });
 | 
			
		||||
        this._userVerifier = new AuthUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true });
 | 
			
		||||
        this._userVerified = false;
 | 
			
		||||
 | 
			
		||||
        this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion));
 | 
			
		||||
@@ -91,10 +85,6 @@ const UnlockDialog = new Lang.Class({
 | 
			
		||||
        this._promptLoginHint.hide();
 | 
			
		||||
        this.contentLayout.add_actor(this._promptLoginHint);
 | 
			
		||||
 | 
			
		||||
        let spinnerIcon = global.datadir + '/theme/process-working.svg';
 | 
			
		||||
        this._workSpinner = new Panel.AnimatedIcon(spinnerIcon, LoginDialog.WORK_SPINNER_ICON_SIZE);
 | 
			
		||||
        this._workSpinner.actor.opacity = 0;
 | 
			
		||||
 | 
			
		||||
        this.allowCancel = false;
 | 
			
		||||
        this.buttonLayout.visible = true;
 | 
			
		||||
        this.addButton({ label: _("Cancel"),
 | 
			
		||||
@@ -105,12 +95,11 @@ const UnlockDialog = new Lang.Class({
 | 
			
		||||
                         y_fill: false,
 | 
			
		||||
                         x_align: St.Align.START,
 | 
			
		||||
                         y_align: St.Align.MIDDLE });
 | 
			
		||||
        this.buttonLayout.add(this._workSpinner.actor,
 | 
			
		||||
                              { expand: false,
 | 
			
		||||
                                x_fill: false,
 | 
			
		||||
                                y_fill: false,
 | 
			
		||||
                                x_align: St.Align.END,
 | 
			
		||||
                                y_align: St.Align.MIDDLE });
 | 
			
		||||
        this.placeSpinner({ expand: false,
 | 
			
		||||
                            x_fill: false,
 | 
			
		||||
                            y_fill: false,
 | 
			
		||||
                            x_align: St.Align.END,
 | 
			
		||||
                            y_align: St.Align.MIDDLE });
 | 
			
		||||
        this._okButton = this.addButton({ label: _("Unlock"),
 | 
			
		||||
                                          action: Lang.bind(this, this._doUnlock),
 | 
			
		||||
                                          default: true },
 | 
			
		||||
@@ -164,35 +153,13 @@ const UnlockDialog = new Lang.Class({
 | 
			
		||||
        this._okButton.can_focus = sensitive;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setWorking: function(working) {
 | 
			
		||||
        if (working) {
 | 
			
		||||
            this._workSpinner.play();
 | 
			
		||||
            Tweener.addTween(this._workSpinner.actor,
 | 
			
		||||
                             { opacity: 255,
 | 
			
		||||
                               delay: LoginDialog.WORK_SPINNER_ANIMATION_DELAY,
 | 
			
		||||
                               time: LoginDialog.WORK_SPINNER_ANIMATION_TIME,
 | 
			
		||||
                               transition: 'linear'
 | 
			
		||||
                             });
 | 
			
		||||
        } else {
 | 
			
		||||
            Tweener.addTween(this._workSpinner.actor,
 | 
			
		||||
                             { opacity: 0,
 | 
			
		||||
                               time: LoginDialog.WORK_SPINNER_ANIMATION_TIME,
 | 
			
		||||
                               transition: 'linear',
 | 
			
		||||
                               onCompleteScope: this,
 | 
			
		||||
                               onComplete: function() {
 | 
			
		||||
                                   this._workSpinner.stop();
 | 
			
		||||
                               }
 | 
			
		||||
                             });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showMessage: function(userVerifier, message, styleClass) {
 | 
			
		||||
        if (message) {
 | 
			
		||||
            this._promptMessage.text = message;
 | 
			
		||||
            this._promptMessage.styleClass = styleClass;
 | 
			
		||||
            GdmUtil.fadeInActor(this._promptMessage);
 | 
			
		||||
            AuthUtil.fadeInActor(this._promptMessage);
 | 
			
		||||
        } else {
 | 
			
		||||
            GdmUtil.fadeOutActor(this._promptMessage);
 | 
			
		||||
            AuthUtil.fadeOutActor(this._promptMessage);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -216,16 +183,16 @@ const UnlockDialog = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._currentQuery = serviceName;
 | 
			
		||||
        this._updateSensitivity(true);
 | 
			
		||||
        this._setWorking(false);
 | 
			
		||||
        this.setWorking(false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showLoginHint: function(verifier, message) {
 | 
			
		||||
        this._promptLoginHint.set_text(message)
 | 
			
		||||
        GdmUtil.fadeInActor(this._promptLoginHint);
 | 
			
		||||
        AuthUtil.fadeInActor(this._promptLoginHint);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _hideLoginHint: function() {
 | 
			
		||||
        GdmUtil.fadeOutActor(this._promptLoginHint);
 | 
			
		||||
        AuthUtil.fadeOutActor(this._promptLoginHint);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _doUnlock: function() {
 | 
			
		||||
@@ -235,7 +202,7 @@ const UnlockDialog = new Lang.Class({
 | 
			
		||||
            // the actual reply to GDM will be sent as soon as asked
 | 
			
		||||
            this._firstQuestionAnswer = this._promptEntry.text;
 | 
			
		||||
            this._updateSensitivity(false);
 | 
			
		||||
            this._setWorking(true);
 | 
			
		||||
            this.setWorking(true);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -246,7 +213,7 @@ const UnlockDialog = new Lang.Class({
 | 
			
		||||
        this._currentQuery = null;
 | 
			
		||||
 | 
			
		||||
        this._updateSensitivity(false);
 | 
			
		||||
        this._setWorking(true);
 | 
			
		||||
        this.setWorking(true);
 | 
			
		||||
 | 
			
		||||
        this._userVerifier.answerQuery(query, this._promptEntry.text);
 | 
			
		||||
    },
 | 
			
		||||
@@ -286,7 +253,7 @@ const UnlockDialog = new Lang.Class({
 | 
			
		||||
        this._promptEntry.menu.isPassword = true;
 | 
			
		||||
 | 
			
		||||
        this._updateSensitivity(false);
 | 
			
		||||
        this._setWorking(false);
 | 
			
		||||
        this.setWorking(false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _escape: function() {
 | 
			
		||||
							
								
								
									
										251
									
								
								js/ui/auth/userList.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								js/ui/auth/userList.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,251 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const AccountsService = imports.gi.AccountsService;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Gdm = imports.gi.Gdm;
 | 
			
		||||
 | 
			
		||||
const Batch = imports.misc.batch;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const UserAvatar = imports.ui.userAvatar;
 | 
			
		||||
 | 
			
		||||
const _SCROLL_ANIMATION_TIME = 0.5;
 | 
			
		||||
 | 
			
		||||
const UserListItem = new Lang.Class({
 | 
			
		||||
    Name: 'UserListItem',
 | 
			
		||||
 | 
			
		||||
    _init: function(user) {
 | 
			
		||||
        this.user = user;
 | 
			
		||||
        this._userChangedId = this.user.connect('changed',
 | 
			
		||||
                                                 Lang.bind(this, this._onUserChanged));
 | 
			
		||||
 | 
			
		||||
        let layout = new St.BoxLayout({ vertical: false });
 | 
			
		||||
        this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
 | 
			
		||||
                                     button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
 | 
			
		||||
                                     can_focus: true,
 | 
			
		||||
                                     child: layout,
 | 
			
		||||
                                     reactive: true,
 | 
			
		||||
                                     x_align: St.Align.START,
 | 
			
		||||
                                     x_fill: true });
 | 
			
		||||
 | 
			
		||||
        this._userAvatar = new UserAvatar.UserAvatar(this.user,
 | 
			
		||||
                                                     { styleClass: 'login-dialog-user-list-item-icon' });
 | 
			
		||||
        layout.add(this._userAvatar.actor);
 | 
			
		||||
        let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
 | 
			
		||||
                                            vertical:    true });
 | 
			
		||||
        layout.add(textLayout, { expand: true });
 | 
			
		||||
 | 
			
		||||
        this._nameLabel = new St.Label({ style_class: 'login-dialog-user-list-item-name' });
 | 
			
		||||
        this.actor.label_actor = this._nameLabel;
 | 
			
		||||
        textLayout.add(this._nameLabel,
 | 
			
		||||
                       { y_fill: false,
 | 
			
		||||
                         y_align: St.Align.MIDDLE,
 | 
			
		||||
                         expand: true });
 | 
			
		||||
 | 
			
		||||
        this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator',
 | 
			
		||||
                                                 scale_x: 0 });
 | 
			
		||||
        textLayout.add(this._timedLoginIndicator,
 | 
			
		||||
                       { x_fill: true,
 | 
			
		||||
                         x_align: St.Align.MIDDLE,
 | 
			
		||||
                         y_fill: false,
 | 
			
		||||
                         y_align: St.Align.END });
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('clicked', Lang.bind(this, this._onClicked));
 | 
			
		||||
        this._onUserChanged();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onUserChanged: function() {
 | 
			
		||||
        this._nameLabel.set_text(this.user.get_real_name());
 | 
			
		||||
        this._userAvatar.update();
 | 
			
		||||
        this._updateLoggedIn();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    syncStyleClasses: function() {
 | 
			
		||||
        this._updateLoggedIn();
 | 
			
		||||
 | 
			
		||||
        if (global.stage.get_key_focus() == this.actor)
 | 
			
		||||
            this.actor.add_style_pseudo_class('focus');
 | 
			
		||||
        else
 | 
			
		||||
            this.actor.remove_style_pseudo_class('focus');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateLoggedIn: function() {
 | 
			
		||||
        if (this.user.is_logged_in())
 | 
			
		||||
            this.actor.add_style_pseudo_class('logged-in');
 | 
			
		||||
        else
 | 
			
		||||
            this.actor.remove_style_pseudo_class('logged-in');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onClicked: function() {
 | 
			
		||||
        this.emit('activate');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    showTimedLoginIndicator: function(time) {
 | 
			
		||||
        let hold = new Batch.Hold();
 | 
			
		||||
 | 
			
		||||
        this.hideTimedLoginIndicator();
 | 
			
		||||
        Tweener.addTween(this._timedLoginIndicator,
 | 
			
		||||
                         { scale_x: 1.,
 | 
			
		||||
                           time: time,
 | 
			
		||||
                           transition: 'linear',
 | 
			
		||||
                           onComplete: function() {
 | 
			
		||||
                               hold.release();
 | 
			
		||||
                           },
 | 
			
		||||
                           onCompleteScope: this
 | 
			
		||||
                         });
 | 
			
		||||
        return hold;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hideTimedLoginIndicator: function() {
 | 
			
		||||
        Tweener.removeTweens(this._timedLoginIndicator);
 | 
			
		||||
        this._timedLoginIndicator.scale_x = 0.;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(UserListItem.prototype);
 | 
			
		||||
 | 
			
		||||
const UserList = new Lang.Class({
 | 
			
		||||
    Name: 'UserList',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.actor = new St.ScrollView({ style_class: 'login-dialog-user-list-view'});
 | 
			
		||||
        this.actor.set_policy(Gtk.PolicyType.NEVER,
 | 
			
		||||
                              Gtk.PolicyType.AUTOMATIC);
 | 
			
		||||
 | 
			
		||||
        this._box = new St.BoxLayout({ vertical: true,
 | 
			
		||||
                                       style_class: 'login-dialog-user-list',
 | 
			
		||||
                                       pseudo_class: 'expanded' });
 | 
			
		||||
 | 
			
		||||
        this.actor.add_actor(this._box);
 | 
			
		||||
        this._items = {};
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('key-focus-in', Lang.bind(this, this._moveFocusToItems));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _moveFocusToItems: function() {
 | 
			
		||||
        let hasItems = Object.keys(this._items).length > 0;
 | 
			
		||||
 | 
			
		||||
        if (!hasItems)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (global.stage.get_key_focus() != this.actor)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let focusSet = this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
 | 
			
		||||
        if (!focusSet) {
 | 
			
		||||
            Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
 | 
			
		||||
                this._moveFocusToItems();
 | 
			
		||||
                return false;
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onItemActivated: function(activatedItem) {
 | 
			
		||||
        this.emit('activate', activatedItem);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    updateStyle: function(isExpanded) {
 | 
			
		||||
        let tasks = [];
 | 
			
		||||
 | 
			
		||||
        if (isExpanded)
 | 
			
		||||
            this._box.add_style_pseudo_class('expanded');
 | 
			
		||||
        else
 | 
			
		||||
            this._box.remove_style_pseudo_class('expanded');
 | 
			
		||||
 | 
			
		||||
        for (let userName in this._items) {
 | 
			
		||||
            let item = this._items[userName];
 | 
			
		||||
            item.actor.sync_hover();
 | 
			
		||||
            item.syncStyleClasses();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    scrollToItem: function(item) {
 | 
			
		||||
        let box = item.actor.get_allocation_box();
 | 
			
		||||
 | 
			
		||||
        let adjustment = this.actor.get_vscroll_bar().get_adjustment();
 | 
			
		||||
 | 
			
		||||
        let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
 | 
			
		||||
        Tweener.removeTweens(adjustment);
 | 
			
		||||
        Tweener.addTween (adjustment,
 | 
			
		||||
                          { value: value,
 | 
			
		||||
                            time: _SCROLL_ANIMATION_TIME,
 | 
			
		||||
                            transition: 'easeOutQuad' });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    jumpToItem: function(item) {
 | 
			
		||||
        let box = item.actor.get_allocation_box();
 | 
			
		||||
 | 
			
		||||
        let adjustment = this.actor.get_vscroll_bar().get_adjustment();
 | 
			
		||||
 | 
			
		||||
        let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
 | 
			
		||||
 | 
			
		||||
        adjustment.set_value(value);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getItemFromUserName: function(userName) {
 | 
			
		||||
        let item = this._items[userName];
 | 
			
		||||
 | 
			
		||||
        if (!item)
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
        return item;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addUser: function(user) {
 | 
			
		||||
        if (!user.is_loaded)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (user.is_system_account())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (user.locked)
 | 
			
		||||
           return;
 | 
			
		||||
 | 
			
		||||
        let userName = user.get_user_name();
 | 
			
		||||
 | 
			
		||||
        if (!userName)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.removeUser(user);
 | 
			
		||||
 | 
			
		||||
        let item = new UserListItem(user);
 | 
			
		||||
        this._box.add(item.actor, { x_fill: true });
 | 
			
		||||
 | 
			
		||||
        this._items[userName] = item;
 | 
			
		||||
 | 
			
		||||
        item.connect('activate',
 | 
			
		||||
                     Lang.bind(this, this._onItemActivated));
 | 
			
		||||
 | 
			
		||||
        // Try to keep the focused item front-and-center
 | 
			
		||||
        item.actor.connect('key-focus-in',
 | 
			
		||||
                           Lang.bind(this,
 | 
			
		||||
                                     function() {
 | 
			
		||||
                                         this.scrollToItem(item);
 | 
			
		||||
                                     }));
 | 
			
		||||
 | 
			
		||||
        this._moveFocusToItems();
 | 
			
		||||
 | 
			
		||||
        this.emit('item-added', item);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    removeUser: function(user) {
 | 
			
		||||
        if (!user.is_loaded)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let userName = user.get_user_name();
 | 
			
		||||
 | 
			
		||||
        if (!userName)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let item = this._items[userName];
 | 
			
		||||
 | 
			
		||||
        if (!item)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        item.actor.destroy();
 | 
			
		||||
        delete this._items[userName];
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(UserList.prototype);
 | 
			
		||||
@@ -7,9 +7,8 @@ const Lang = imports.lang;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const Batch = imports.gdm.batch;
 | 
			
		||||
const Fprint = imports.gdm.fingerprint;
 | 
			
		||||
const Realmd = imports.gdm.realmd;
 | 
			
		||||
const Batch = imports.misc.batch;
 | 
			
		||||
const Fprint = imports.ui.auth.fingerprint;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
@@ -117,7 +116,6 @@ const ShellUserVerifier = new Lang.Class({
 | 
			
		||||
        this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
 | 
			
		||||
 | 
			
		||||
        this._fprintManager = new Fprint.FprintManager();
 | 
			
		||||
        this._realmManager = new Realmd.Manager();
 | 
			
		||||
        this._messageQueue = [];
 | 
			
		||||
        this._messageQueueTimeoutId = 0;
 | 
			
		||||
        this.hasPendingMessages = false;
 | 
			
		||||
@@ -377,30 +375,11 @@ const ShellUserVerifier = new Lang.Class({
 | 
			
		||||
        this._queueMessage(problem, 'login-dialog-message-warning');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showRealmLoginHint: function() {
 | 
			
		||||
        if (this._realmManager.loginFormat) {
 | 
			
		||||
            let hint = this._realmManager.loginFormat;
 | 
			
		||||
 | 
			
		||||
            hint = hint.replace(/%U/g, 'user');
 | 
			
		||||
            hint = hint.replace(/%D/g, 'DOMAIN');
 | 
			
		||||
            hint = hint.replace(/%[^UD]/g, '');
 | 
			
		||||
 | 
			
		||||
            // Translators: this message is shown below the username entry field
 | 
			
		||||
            // to clue the user in on how to login to the local network realm
 | 
			
		||||
            this.emit('show-login-hint',
 | 
			
		||||
                      _("(e.g., user or %s)").format(hint));
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onInfoQuery: function(client, serviceName, question) {
 | 
			
		||||
        // We only expect questions to come from the main auth service
 | 
			
		||||
        if (serviceName != PASSWORD_SERVICE_NAME)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._showRealmLoginHint();
 | 
			
		||||
        this._realmLoginHintSignalId = this._realmManager.connect('login-format-changed',
 | 
			
		||||
                                                                  Lang.bind(this, this._showRealmLoginHint));
 | 
			
		||||
 | 
			
		||||
        this.emit('ask-question', serviceName, question, '');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -476,11 +455,6 @@ const ShellUserVerifier = new Lang.Class({
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.emit('hide-login-hint');
 | 
			
		||||
 | 
			
		||||
        if (this._realmLoginHintSignalId) {
 | 
			
		||||
            this._realmManager.disconnect(this._realmLoginHintSignalId);
 | 
			
		||||
            this._realmLoginHintSignalId = 0;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ShellUserVerifier.prototype);
 | 
			
		||||
@@ -46,8 +46,10 @@ function addBackgroundMenu(actor) {
 | 
			
		||||
    clickAction.connect('long-press', function(action, actor, state) {
 | 
			
		||||
        if (state == Clutter.LongPressState.QUERY)
 | 
			
		||||
            return action.get_button() == 1 && !actor._backgroundMenu.isOpen;
 | 
			
		||||
        if (state == Clutter.LongPressState.ACTIVATE)
 | 
			
		||||
        if (state == Clutter.LongPressState.ACTIVATE) {
 | 
			
		||||
            openMenu();
 | 
			
		||||
            actor._backgroundManager.ignoreRelease();
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
    clickAction.connect('clicked', function(action) {
 | 
			
		||||
 
 | 
			
		||||
@@ -443,16 +443,18 @@ const Calendar = new Lang.Class({
 | 
			
		||||
        this.actor.add(this._topBox,
 | 
			
		||||
                       { row: 0, col: 0, col_span: offsetCols + 7 });
 | 
			
		||||
 | 
			
		||||
        let back = new St.Button({ style_class: 'calendar-change-month-back' });
 | 
			
		||||
        this._topBox.add(back);
 | 
			
		||||
        back.connect('clicked', Lang.bind(this, this._onPrevMonthButtonClicked));
 | 
			
		||||
        this._backButton = new St.Button({ style_class: 'calendar-change-month-back',
 | 
			
		||||
                                           can_focus: true });
 | 
			
		||||
        this._topBox.add(this._backButton);
 | 
			
		||||
        this._backButton.connect('clicked', Lang.bind(this, this._onPrevMonthButtonClicked));
 | 
			
		||||
 | 
			
		||||
        this._monthLabel = new St.Label({style_class: 'calendar-month-label'});
 | 
			
		||||
        this._topBox.add(this._monthLabel, { expand: true, x_fill: false, x_align: St.Align.MIDDLE });
 | 
			
		||||
 | 
			
		||||
        let forward = new St.Button({ style_class: 'calendar-change-month-forward' });
 | 
			
		||||
        this._topBox.add(forward);
 | 
			
		||||
        forward.connect('clicked', Lang.bind(this, this._onNextMonthButtonClicked));
 | 
			
		||||
        this._forwardButton = new St.Button({ style_class: 'calendar-change-month-forward',
 | 
			
		||||
                                              can_focus: true });
 | 
			
		||||
        this._topBox.add(this._forwardButton);
 | 
			
		||||
        this._forwardButton.connect('clicked', Lang.bind(this, this._onNextMonthButtonClicked));
 | 
			
		||||
 | 
			
		||||
        // Add weekday labels...
 | 
			
		||||
        //
 | 
			
		||||
@@ -511,10 +513,12 @@ const Calendar = new Lang.Class({
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.setDate(newDate, false);
 | 
			
		||||
   },
 | 
			
		||||
        this._backButton.grab_key_focus();
 | 
			
		||||
 | 
			
		||||
   _onNextMonthButtonClicked: function() {
 | 
			
		||||
        this.setDate(newDate, false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onNextMonthButtonClicked: function() {
 | 
			
		||||
        let newDate = new Date(this._selectedDate);
 | 
			
		||||
        let oldMonth = newDate.getMonth();
 | 
			
		||||
        if (oldMonth == 11) {
 | 
			
		||||
@@ -533,7 +537,9 @@ const Calendar = new Lang.Class({
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
       this.setDate(newDate, false);
 | 
			
		||||
        this._forwardButton.grab_key_focus();
 | 
			
		||||
 | 
			
		||||
        this.setDate(newDate, false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onSettingsChange: function() {
 | 
			
		||||
@@ -590,7 +596,8 @@ const Calendar = new Lang.Class({
 | 
			
		||||
        // nRows here means 6 weeks + one header + one navbar
 | 
			
		||||
        let nRows = 8;
 | 
			
		||||
        while (row < 8) {
 | 
			
		||||
            let button = new St.Button({ label: iter.getDate().toString() });
 | 
			
		||||
            let button = new St.Button({ label: iter.getDate().toString(),
 | 
			
		||||
                                         can_focus: true });
 | 
			
		||||
            let rtl = button.get_text_direction() == Clutter.TextDirection.RTL;
 | 
			
		||||
 | 
			
		||||
            if (this._eventSource.isDummy)
 | 
			
		||||
@@ -598,8 +605,12 @@ const Calendar = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
            let iterStr = iter.toUTCString();
 | 
			
		||||
            button.connect('clicked', Lang.bind(this, function() {
 | 
			
		||||
                this._shouldDateGrabFocus = true;
 | 
			
		||||
 | 
			
		||||
                let newlySelectedDate = new Date(iterStr);
 | 
			
		||||
                this.setDate(newlySelectedDate, false);
 | 
			
		||||
 | 
			
		||||
                this._shouldDateGrabFocus = false;
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            let hasEvents = this._eventSource.hasEvents(iter);
 | 
			
		||||
@@ -624,9 +635,6 @@ const Calendar = new Lang.Class({
 | 
			
		||||
            else if (iter.getMonth() != this._selectedDate.getMonth())
 | 
			
		||||
                styleClass += ' calendar-other-month-day';
 | 
			
		||||
 | 
			
		||||
            if (_sameDay(this._selectedDate, iter))
 | 
			
		||||
                button.add_style_pseudo_class('active');
 | 
			
		||||
 | 
			
		||||
            if (hasEvents)
 | 
			
		||||
                styleClass += ' calendar-day-with-events'
 | 
			
		||||
 | 
			
		||||
@@ -636,6 +644,13 @@ const Calendar = new Lang.Class({
 | 
			
		||||
            this.actor.add(button,
 | 
			
		||||
                           { row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7 });
 | 
			
		||||
 | 
			
		||||
            if (_sameDay(this._selectedDate, iter)) {
 | 
			
		||||
                button.add_style_pseudo_class('active');
 | 
			
		||||
 | 
			
		||||
                if (this._shouldDateGrabFocus)
 | 
			
		||||
                    button.grab_key_focus();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (this._useWeekdate && iter.getDay() == 4) {
 | 
			
		||||
                let label = new St.Label({ text: _getCalendarWeekForDate(iter).toString(),
 | 
			
		||||
                                           style_class: 'calendar-day-base calendar-week-number'});
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ const KeyringDialog = new Lang.Class({
 | 
			
		||||
        this.prompt = new Shell.KeyringPrompt();
 | 
			
		||||
        this.prompt.connect('show-password', Lang.bind(this, this._onShowPassword));
 | 
			
		||||
        this.prompt.connect('show-confirm', Lang.bind(this, this._onShowConfirm));
 | 
			
		||||
        this.prompt.connect('hide-prompt', Lang.bind(this, this._onHidePrompt));
 | 
			
		||||
        this.prompt.connect('prompt-close', Lang.bind(this, this._onHidePrompt));
 | 
			
		||||
 | 
			
		||||
        let mainContentBox = new St.BoxLayout({ style_class: 'prompt-dialog-main-layout',
 | 
			
		||||
                                                vertical: false });
 | 
			
		||||
@@ -63,11 +63,17 @@ const KeyringDialog = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._cancelButton = this.addButton({ label: '',
 | 
			
		||||
                                              action: Lang.bind(this, this._onCancelButton),
 | 
			
		||||
                                              key: Clutter.Escape });
 | 
			
		||||
                                              key: Clutter.Escape },
 | 
			
		||||
                                            { expand: true, x_fill: false, x_align: St.Align.START });
 | 
			
		||||
        this.placeSpinner({ expand: false,
 | 
			
		||||
                            x_fill: false,
 | 
			
		||||
                            y_fill: false,
 | 
			
		||||
                            x_align: St.Align.END,
 | 
			
		||||
                            y_align: St.Align.MIDDLE });
 | 
			
		||||
        this._continueButton = this.addButton({ label: '',
 | 
			
		||||
                                                action: Lang.bind(this, this._onContinueButton),
 | 
			
		||||
                                                default: true },
 | 
			
		||||
                                              { expand: true, x_fill: false, x_align: St.Align.END });
 | 
			
		||||
                                              { expand: false, x_fill: false, x_align: St.Align.END });
 | 
			
		||||
 | 
			
		||||
        this.prompt.bind_property('cancel-label', this._cancelButton, 'label', GObject.BindingFlags.SYNC_CREATE);
 | 
			
		||||
        this.prompt.bind_property('continue-label', this._continueButton, 'label', GObject.BindingFlags.SYNC_CREATE);
 | 
			
		||||
@@ -143,11 +149,19 @@ const KeyringDialog = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateSensitivity: function(sensitive) {
 | 
			
		||||
        this._passwordEntry.reactive = sensitive;
 | 
			
		||||
        this._passwordEntry.clutter_text.editable = sensitive;
 | 
			
		||||
        if (this._passwordEntry) {
 | 
			
		||||
            this._passwordEntry.reactive = sensitive;
 | 
			
		||||
            this._passwordEntry.clutter_text.editable = sensitive;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._confirmEntry) {
 | 
			
		||||
            this._confirmEntry.reactive = sensitive;
 | 
			
		||||
            this._confirmEntry.clutter_text.editable = sensitive;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._continueButton.can_focus = sensitive;
 | 
			
		||||
        this._continueButton.reactive = sensitive;
 | 
			
		||||
        this.setWorking(!sensitive);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _ensureOpen: function() {
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ const PolkitAgent = imports.gi.PolkitAgent;
 | 
			
		||||
const Components = imports.ui.components;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const ShellEntry = imports.ui.shellEntry;
 | 
			
		||||
const UserMenu = imports.ui.userMenu;
 | 
			
		||||
const UserAvatar = imports.ui.userAvatar;
 | 
			
		||||
 | 
			
		||||
const DIALOG_ICON_SIZE = 48;
 | 
			
		||||
 | 
			
		||||
@@ -31,7 +31,6 @@ const AuthenticationDialog = new Lang.Class({
 | 
			
		||||
        this.message = message;
 | 
			
		||||
        this.userNames = userNames;
 | 
			
		||||
        this._wasDismissed = false;
 | 
			
		||||
        this._completed = false;
 | 
			
		||||
 | 
			
		||||
        let mainContentBox = new St.BoxLayout({ style_class: 'prompt-dialog-main-layout',
 | 
			
		||||
                                                vertical: false });
 | 
			
		||||
@@ -101,9 +100,9 @@ const AuthenticationDialog = new Lang.Class({
 | 
			
		||||
            let userBox = new St.BoxLayout({ style_class: 'polkit-dialog-user-layout',
 | 
			
		||||
                                             vertical: false });
 | 
			
		||||
            messageBox.add(userBox);
 | 
			
		||||
            this._userAvatar = new UserMenu.UserAvatarWidget(this._user,
 | 
			
		||||
                                                             { iconSize: DIALOG_ICON_SIZE,
 | 
			
		||||
                                                               styleClass: 'polkit-dialog-user-icon' });
 | 
			
		||||
            this._userAvatar = new UserAvatar.UserAvatar(this._user,
 | 
			
		||||
                                                         { iconSize: DIALOG_ICON_SIZE,
 | 
			
		||||
                                                           styleClass: 'polkit-dialog-user-icon' });
 | 
			
		||||
            this._userAvatar.actor.hide();
 | 
			
		||||
            userBox.add(this._userAvatar.actor,
 | 
			
		||||
                        { x_fill:  true,
 | 
			
		||||
@@ -161,26 +160,32 @@ const AuthenticationDialog = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._cancelButton = this.addButton({ label: _("Cancel"),
 | 
			
		||||
                                              action: Lang.bind(this, this.cancel),
 | 
			
		||||
                                              key: Clutter.Escape });
 | 
			
		||||
                                              key: Clutter.Escape },
 | 
			
		||||
                                            { expand: true, x_fill: false, x_align: St.Align.START });
 | 
			
		||||
        this.placeSpinner({ expand: false,
 | 
			
		||||
                            x_fill: false,
 | 
			
		||||
                            y_fill: false,
 | 
			
		||||
                            x_align: St.Align.END,
 | 
			
		||||
                            y_align: St.Align.MIDDLE });
 | 
			
		||||
        this._okButton = this.addButton({ label:  _("Authenticate"),
 | 
			
		||||
                                          action: Lang.bind(this, this._onAuthenticateButtonPressed),
 | 
			
		||||
                                          default: true },
 | 
			
		||||
                                        { expand: true, x_fill: false, x_align: St.Align.END });
 | 
			
		||||
                                        { expand: false, x_fill: false, x_align: St.Align.END });
 | 
			
		||||
 | 
			
		||||
        this._doneEmitted = false;
 | 
			
		||||
 | 
			
		||||
        this._identityToAuth = Polkit.UnixUser.new_for_name(userName);
 | 
			
		||||
        this._cookie = cookie;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    performAuthentication: function() {
 | 
			
		||||
        this.destroySession();
 | 
			
		||||
        this._session = new PolkitAgent.Session({ identity: this._identityToAuth,
 | 
			
		||||
                                                  cookie: this._cookie });
 | 
			
		||||
        this._session.connect('completed', Lang.bind(this, this._onSessionCompleted));
 | 
			
		||||
        this._session.connect('request', Lang.bind(this, this._onSessionRequest));
 | 
			
		||||
        this._session.connect('show-error', Lang.bind(this, this._onSessionShowError));
 | 
			
		||||
        this._session.connect('show-info', Lang.bind(this, this._onSessionShowInfo));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    startAuthentication: function() {
 | 
			
		||||
        this._session.initiate();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -202,14 +207,14 @@ const AuthenticationDialog = new Lang.Class({
 | 
			
		||||
            log('polkitAuthenticationAgent: Failed to show modal dialog.' +
 | 
			
		||||
                ' Dismissing authentication request for action-id ' + this.actionId +
 | 
			
		||||
                ' cookie ' + this._cookie);
 | 
			
		||||
            this._emitDone(false, true);
 | 
			
		||||
            this._emitDone(true);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _emitDone: function(keepVisible, dismissed) {
 | 
			
		||||
    _emitDone: function(dismissed) {
 | 
			
		||||
        if (!this._doneEmitted) {
 | 
			
		||||
            this._doneEmitted = true;
 | 
			
		||||
            this.emit('done', keepVisible, dismissed);
 | 
			
		||||
            this.emit('done', dismissed);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -219,6 +224,7 @@ const AuthenticationDialog = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._okButton.can_focus = sensitive;
 | 
			
		||||
        this._okButton.reactive = sensitive;
 | 
			
		||||
        this.setWorking(!sensitive);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onEntryActivate: function() {
 | 
			
		||||
@@ -237,12 +243,16 @@ const AuthenticationDialog = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onSessionCompleted: function(session, gainedAuthorization) {
 | 
			
		||||
        if (this._completed)
 | 
			
		||||
        if (this._completed || this._doneEmitted)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._completed = true;
 | 
			
		||||
 | 
			
		||||
        if (!gainedAuthorization) {
 | 
			
		||||
        /* Yay, all done */
 | 
			
		||||
        if (gainedAuthorization) {
 | 
			
		||||
            this._emitDone(false);
 | 
			
		||||
 | 
			
		||||
        } else {
 | 
			
		||||
            /* Unless we are showing an existing error message from the PAM
 | 
			
		||||
             * module (the PAM module could be reporting the authentication
 | 
			
		||||
             * error providing authentication-method specific information),
 | 
			
		||||
@@ -258,8 +268,10 @@ const AuthenticationDialog = new Lang.Class({
 | 
			
		||||
                this._infoMessageLabel.hide();
 | 
			
		||||
                this._nullMessageLabel.hide();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* Try and authenticate again */
 | 
			
		||||
            this.performAuthentication();
 | 
			
		||||
        }
 | 
			
		||||
        this._emitDone(!gainedAuthorization, false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onSessionRequest: function(session, request, echo_on) {
 | 
			
		||||
@@ -303,6 +315,7 @@ const AuthenticationDialog = new Lang.Class({
 | 
			
		||||
        if (this._session) {
 | 
			
		||||
            if (!this._completed)
 | 
			
		||||
                this._session.cancel();
 | 
			
		||||
            this._completed = false;
 | 
			
		||||
            this._session = null;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
@@ -317,7 +330,7 @@ const AuthenticationDialog = new Lang.Class({
 | 
			
		||||
    cancel: function() {
 | 
			
		||||
        this._wasDismissed = true;
 | 
			
		||||
        this.close(global.get_current_time());
 | 
			
		||||
        this._emitDone(false, true);
 | 
			
		||||
        this._emitDone(true);
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(AuthenticationDialog.prototype);
 | 
			
		||||
@@ -327,7 +340,6 @@ const AuthenticationAgent = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._currentDialog = null;
 | 
			
		||||
        this._isCompleting = false;
 | 
			
		||||
        this._handle = null;
 | 
			
		||||
        this._native = new Shell.PolkitAuthenticationAgent();
 | 
			
		||||
        this._native.connect('initiate', Lang.bind(this, this._onInitiate));
 | 
			
		||||
@@ -364,45 +376,24 @@ const AuthenticationAgent = new Lang.Class({
 | 
			
		||||
        // discussion.
 | 
			
		||||
 | 
			
		||||
        this._currentDialog.connect('done', Lang.bind(this, this._onDialogDone));
 | 
			
		||||
        this._currentDialog.startAuthentication();
 | 
			
		||||
        this._currentDialog.performAuthentication();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onCancel: function(nativeAgent) {
 | 
			
		||||
        this._completeRequest(false, false);
 | 
			
		||||
        this._completeRequest(false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDialogDone: function(dialog, keepVisible, dismissed) {
 | 
			
		||||
        this._completeRequest(keepVisible, dismissed);
 | 
			
		||||
    _onDialogDone: function(dialog, dismissed) {
 | 
			
		||||
        this._completeRequest(dismissed);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _reallyCompleteRequest: function(dismissed) {
 | 
			
		||||
    _completeRequest: function(dismissed) {
 | 
			
		||||
        this._currentDialog.close();
 | 
			
		||||
        this._currentDialog.destroySession();
 | 
			
		||||
        this._currentDialog = null;
 | 
			
		||||
        this._isCompleting = false;
 | 
			
		||||
 | 
			
		||||
        this._native.complete(dismissed)
 | 
			
		||||
        this._native.complete(dismissed);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _completeRequest: function(keepVisible, wasDismissed) {
 | 
			
		||||
        if (this._isCompleting)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._isCompleting = true;
 | 
			
		||||
 | 
			
		||||
        if (keepVisible) {
 | 
			
		||||
            // Give the user 2 seconds to read 'Authentication Failure' before
 | 
			
		||||
            // dismissing the dialog
 | 
			
		||||
            Mainloop.timeout_add(2000,
 | 
			
		||||
                                 Lang.bind(this,
 | 
			
		||||
                                           function() {
 | 
			
		||||
                                               this._reallyCompleteRequest(wasDismissed);
 | 
			
		||||
                                               return false;
 | 
			
		||||
                                           }));
 | 
			
		||||
        } else {
 | 
			
		||||
            this._reallyCompleteRequest(wasDismissed);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const Component = AuthenticationAgent;
 | 
			
		||||
 
 | 
			
		||||
@@ -61,8 +61,7 @@ const CtrlAltTabManager = new Lang.Class({
 | 
			
		||||
        if (item.focusCallback) {
 | 
			
		||||
            item.focusCallback(timestamp);
 | 
			
		||||
        } else {
 | 
			
		||||
            if (global.stage_input_mode == Shell.StageInputMode.NONREACTIVE ||
 | 
			
		||||
                global.stage_input_mode == Shell.StageInputMode.NORMAL)
 | 
			
		||||
            if (global.stage_input_mode == Shell.StageInputMode.NORMAL)
 | 
			
		||||
                global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
 | 
			
		||||
 | 
			
		||||
            item.root.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
 | 
			
		||||
@@ -89,19 +88,25 @@ const CtrlAltTabManager = new Lang.Class({
 | 
			
		||||
        let items = this._items.filter(function (item) { return item.proxy.mapped; });
 | 
			
		||||
 | 
			
		||||
        // And add the windows metacity would show in its Ctrl-Alt-Tab list
 | 
			
		||||
        if (!Main.overview.visible) {
 | 
			
		||||
        if (Main.sessionMode.hasWindows && !Main.overview.visible) {
 | 
			
		||||
            let screen = global.screen;
 | 
			
		||||
            let display = screen.get_display();
 | 
			
		||||
            let windows = display.get_tab_list(Meta.TabList.DOCKS, screen, screen.get_active_workspace ());
 | 
			
		||||
            let windowTracker = Shell.WindowTracker.get_default();
 | 
			
		||||
            let textureCache = St.TextureCache.get_default();
 | 
			
		||||
            for (let i = 0; i < windows.length; i++) {
 | 
			
		||||
                let icon;
 | 
			
		||||
                let app = windowTracker.get_window_app(windows[i]);
 | 
			
		||||
                if (app)
 | 
			
		||||
                    icon = app.create_icon_texture(POPUP_APPICON_SIZE);
 | 
			
		||||
                else
 | 
			
		||||
                    icon = textureCache.bind_pixbuf_property(windows[i], 'icon');
 | 
			
		||||
                let icon = null;
 | 
			
		||||
                let iconName = null;
 | 
			
		||||
                if (windows[i].get_window_type () == Meta.WindowType.DESKTOP) {
 | 
			
		||||
                    iconName = 'video-display-symbolic';
 | 
			
		||||
                } else {
 | 
			
		||||
                    let app = windowTracker.get_window_app(windows[i]);
 | 
			
		||||
                    if (app)
 | 
			
		||||
                        icon = app.create_icon_texture(POPUP_APPICON_SIZE);
 | 
			
		||||
                    else
 | 
			
		||||
                        icon = textureCache.bind_pixbuf_property(windows[i], 'icon');
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                items.push({ name: windows[i].title,
 | 
			
		||||
                             proxy: windows[i].get_compositor_private(),
 | 
			
		||||
                             focusCallback: Lang.bind(windows[i],
 | 
			
		||||
@@ -109,6 +114,7 @@ const CtrlAltTabManager = new Lang.Class({
 | 
			
		||||
                                     Main.activateWindow(this, timestamp);
 | 
			
		||||
                                 }),
 | 
			
		||||
                             iconActor: icon,
 | 
			
		||||
                             iconName: iconName,
 | 
			
		||||
                             sortGroup: SortGroup.MIDDLE });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -49,11 +49,6 @@ const DateMenuButton = new Lang.Class({
 | 
			
		||||
            menuAlignment = 1.0 - menuAlignment;
 | 
			
		||||
        this.parent(menuAlignment);
 | 
			
		||||
 | 
			
		||||
        // At this moment calendar menu is not keyboard navigable at
 | 
			
		||||
        // all (so not accessible), so it doesn't make sense to set as
 | 
			
		||||
        // role ATK_ROLE_MENU like other elements of the panel.
 | 
			
		||||
        this.actor.accessible_role = Atk.Role.LABEL;
 | 
			
		||||
 | 
			
		||||
        this._clockDisplay = new St.Label();
 | 
			
		||||
        this.actor.add_actor(this._clockDisplay);
 | 
			
		||||
 | 
			
		||||
@@ -90,22 +85,18 @@ const DateMenuButton = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._openCalendarItem = new PopupMenu.PopupMenuItem(_("Open Calendar"));
 | 
			
		||||
        this._openCalendarItem.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
 | 
			
		||||
        this._openCalendarItem.actor.can_focus = false;
 | 
			
		||||
        vbox.add(this._openCalendarItem.actor, {y_align: St.Align.END, expand: true, y_fill: false});
 | 
			
		||||
 | 
			
		||||
        this._openClocksItem = new PopupMenu.PopupMenuItem(_("Open Clocks"));
 | 
			
		||||
        this._openClocksItem.connect('activate', Lang.bind(this, this._onOpenClocksActivate));
 | 
			
		||||
        this._openClocksItem.actor.can_focus = false;
 | 
			
		||||
        vbox.add(this._openClocksItem.actor, {y_align: St.Align.END, expand: true, y_fill: false});
 | 
			
		||||
 | 
			
		||||
        Shell.AppSystem.get_default().connect('installed-changed',
 | 
			
		||||
                                              Lang.bind(this, this._appInstalledChanged));
 | 
			
		||||
        this._appInstalledChanged();
 | 
			
		||||
 | 
			
		||||
        item = this.menu.addSettingsAction(_("Date & Time Settings"), 'gnome-datetime-panel.desktop');
 | 
			
		||||
        if (item) {
 | 
			
		||||
            item.actor.show_on_set_parent = false;
 | 
			
		||||
            item.actor.can_focus = false;
 | 
			
		||||
            item.actor.reparent(vbox);
 | 
			
		||||
            this._dateAndTimeSeparator = separator;
 | 
			
		||||
        }
 | 
			
		||||
@@ -157,14 +148,16 @@ const DateMenuButton = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _appInstalledChanged: function() {
 | 
			
		||||
        let app = Shell.AppSystem.get_default().lookup_app('gnome-clocks.desktop');
 | 
			
		||||
        this._openClocksItem.actor.visible = app !== null;
 | 
			
		||||
        this._calendarApp = undefined;
 | 
			
		||||
        this._updateEventsVisibility();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateEventsVisibility: function() {
 | 
			
		||||
        let visible = this._eventSource.hasCalendars;
 | 
			
		||||
        this._openCalendarItem.actor.visible = visible;
 | 
			
		||||
        this._openClocksItem.actor.visible = visible;
 | 
			
		||||
        this._openCalendarItem.actor.visible = visible &&
 | 
			
		||||
            (this._getCalendarApp() != null);
 | 
			
		||||
        this._openClocksItem.actor.visible = visible &&
 | 
			
		||||
            (this._getClockApp() != null);
 | 
			
		||||
        this._separator.visible = visible;
 | 
			
		||||
        if (visible) {
 | 
			
		||||
          let alignment = 0.25;
 | 
			
		||||
@@ -217,18 +210,34 @@ const DateMenuButton = new Lang.Class({
 | 
			
		||||
        this._date.set_text(displayDate.toLocaleFormat(dateFormat));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getCalendarApp: function() {
 | 
			
		||||
        if (this._calendarApp !== undefined)
 | 
			
		||||
            return this._calendarApp;
 | 
			
		||||
 | 
			
		||||
        let apps = Gio.AppInfo.get_recommended_for_type('text/calendar');
 | 
			
		||||
        if (apps && (apps.length > 0))
 | 
			
		||||
            this._calendarApp = apps[0];
 | 
			
		||||
        else
 | 
			
		||||
            this._calendarApp = null;
 | 
			
		||||
        return this._calendarApp;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getClockApp: function() {
 | 
			
		||||
        return Shell.AppSystem.get_default().lookup_app('gnome-clocks.desktop');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onOpenCalendarActivate: function() {
 | 
			
		||||
        this.menu.close();
 | 
			
		||||
 | 
			
		||||
        let app = Gio.AppInfo.get_default_for_type('text/calendar', false);
 | 
			
		||||
        if (app.get_id() == 'evolution')
 | 
			
		||||
            app = Gio.DesktopAppInfo.new('evolution-calendar');
 | 
			
		||||
        let app = this._getCalendarApp();
 | 
			
		||||
        if (app.get_id() == 'evolution.desktop')
 | 
			
		||||
            app = Gio.DesktopAppInfo.new('evolution-calendar.desktop');
 | 
			
		||||
        app.launch([], global.create_app_launch_context());
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onOpenClocksActivate: function() {
 | 
			
		||||
        this.menu.close();
 | 
			
		||||
        let app = Shell.AppSystem.get_default().lookup_app('gnome-clocks.desktop');
 | 
			
		||||
        let app = this._getClockApp();
 | 
			
		||||
        app.activate();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -43,9 +43,7 @@ let dragMonitors = [];
 | 
			
		||||
 | 
			
		||||
function _getEventHandlerActor() {
 | 
			
		||||
    if (!eventHandlerActor) {
 | 
			
		||||
        eventHandlerActor = new Clutter.Rectangle();
 | 
			
		||||
        eventHandlerActor.width = 0;
 | 
			
		||||
        eventHandlerActor.height = 0;
 | 
			
		||||
        eventHandlerActor = new Clutter.Actor({ width: 0, height: 0 });
 | 
			
		||||
        Main.uiGroup.add_actor(eventHandlerActor);
 | 
			
		||||
        // We connect to 'event' rather than 'captured-event' because the capturing phase doesn't happen
 | 
			
		||||
        // when you've grabbed the pointer.
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ const GnomeSession = imports.misc.gnomeSession;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const UserMenu = imports.ui.userMenu;
 | 
			
		||||
const UserAvatar = imports.ui.userAvatar;
 | 
			
		||||
 | 
			
		||||
let _endSessionDialog = null;
 | 
			
		||||
 | 
			
		||||
@@ -360,9 +360,9 @@ const EndSessionDialog = new Lang.Class({
 | 
			
		||||
                                                icon_size: _DIALOG_ICON_SIZE,
 | 
			
		||||
                                                style_class: dialogContent.iconStyleClass });
 | 
			
		||||
        } else {
 | 
			
		||||
            let avatarWidget = new UserMenu.UserAvatarWidget(this._user,
 | 
			
		||||
                                                             { iconSize: _DIALOG_ICON_SIZE,
 | 
			
		||||
                                                               styleClass: dialogContent.iconStyleClass });
 | 
			
		||||
            let avatarWidget = new UserAvatar.UserAvatar(this._user,
 | 
			
		||||
                                                         { iconSize: _DIALOG_ICON_SIZE,
 | 
			
		||||
                                                           styleClass: dialogContent.iconStyleClass });
 | 
			
		||||
            this._iconBin.child = avatarWidget.actor;
 | 
			
		||||
            avatarWidget.update();
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -292,7 +292,7 @@ function disableAllExtensions() {
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (initted) {
 | 
			
		||||
        enabledExtensions.forEach(function(uuid) {
 | 
			
		||||
        extensionOrder.slice().reverse().forEach(function(uuid) {
 | 
			
		||||
            disableExtension(uuid);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -211,10 +211,8 @@ const GrabHelper = new Lang.Class({
 | 
			
		||||
            this._grabbedFromKeynav = hadFocus;
 | 
			
		||||
            this._preGrabInputMode = global.stage_input_mode;
 | 
			
		||||
 | 
			
		||||
            if (this._preGrabInputMode == Shell.StageInputMode.NONREACTIVE ||
 | 
			
		||||
                this._preGrabInputMode == Shell.StageInputMode.NORMAL) {
 | 
			
		||||
            if (this._preGrabInputMode == Shell.StageInputMode.NORMAL)
 | 
			
		||||
                global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this._keyFocusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
 | 
			
		||||
            this._focusWindowChangedId = metaDisplay.connect('notify::focus-window', Lang.bind(this, this._focusWindowChanged));
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										182
									
								
								js/ui/layout.js
									
									
									
									
									
								
							
							
						
						
									
										182
									
								
								js/ui/layout.js
									
									
									
									
									
								
							@@ -118,10 +118,25 @@ const MonitorConstraint = new Lang.Class({
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const Monitor = new Lang.Class({
 | 
			
		||||
    Name: 'Monitor',
 | 
			
		||||
 | 
			
		||||
    _init: function(index, geometry) {
 | 
			
		||||
        this.index = index;
 | 
			
		||||
        this.x = geometry.x;
 | 
			
		||||
        this.y = geometry.y;
 | 
			
		||||
        this.width = geometry.width;
 | 
			
		||||
        this.height = geometry.height;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get inFullscreen() {
 | 
			
		||||
        return global.screen.get_monitor_in_fullscreen(this.index);
 | 
			
		||||
    }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const defaultParams = {
 | 
			
		||||
    trackFullscreen: false,
 | 
			
		||||
    affectsStruts: false,
 | 
			
		||||
    affectsInputRegion: true
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const LayoutManager = new Lang.Class({
 | 
			
		||||
@@ -173,10 +188,12 @@ const LayoutManager = new Lang.Class({
 | 
			
		||||
        global.stage.remove_actor(global.window_group);
 | 
			
		||||
        this.uiGroup.add_actor(global.window_group);
 | 
			
		||||
 | 
			
		||||
        global.stage.remove_actor(global.overlay_group);
 | 
			
		||||
        this.uiGroup.add_actor(global.overlay_group);
 | 
			
		||||
        global.stage.add_child(this.uiGroup);
 | 
			
		||||
 | 
			
		||||
        this.overviewGroup = new St.Widget({ name: 'overviewGroup',
 | 
			
		||||
                                             visible: false });
 | 
			
		||||
        this.addChrome(this.overviewGroup);
 | 
			
		||||
 | 
			
		||||
        this.screenShieldGroup = new St.Widget({ name: 'screenShieldGroup',
 | 
			
		||||
                                                 visible: false,
 | 
			
		||||
                                                 clip_to_allocation: true,
 | 
			
		||||
@@ -227,24 +244,24 @@ const LayoutManager = new Lang.Class({
 | 
			
		||||
        this._monitorsChanged();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // This is called by Main after everything else is constructed;
 | 
			
		||||
    // it needs access to Main.overview, which didn't exist
 | 
			
		||||
    // yet when the LayoutManager was constructed.
 | 
			
		||||
    // This is called by Main after everything else is constructed
 | 
			
		||||
    init: function() {
 | 
			
		||||
        Main.overview.connect('showing', Lang.bind(this, this._overviewShowing));
 | 
			
		||||
        Main.overview.connect('hidden', Lang.bind(this, this._overviewHidden));
 | 
			
		||||
        Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
 | 
			
		||||
 | 
			
		||||
        this._prepareStartupAnimation();
 | 
			
		||||
        this._loadBackground();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _overviewShowing: function() {
 | 
			
		||||
    showOverview: function() {
 | 
			
		||||
        this.overviewGroup.show();
 | 
			
		||||
 | 
			
		||||
        this._inOverview = true;
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _overviewHidden: function() {
 | 
			
		||||
    hideOverview: function() {
 | 
			
		||||
        this.overviewGroup.hide();
 | 
			
		||||
 | 
			
		||||
        this._inOverview = false;
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
@@ -261,7 +278,7 @@ const LayoutManager = new Lang.Class({
 | 
			
		||||
        this.monitors = [];
 | 
			
		||||
        let nMonitors = screen.get_n_monitors();
 | 
			
		||||
        for (let i = 0; i < nMonitors; i++)
 | 
			
		||||
            this.monitors.push(screen.get_monitor_geometry(i));
 | 
			
		||||
            this.monitors.push(new Monitor(i, screen.get_monitor_geometry(i)));
 | 
			
		||||
 | 
			
		||||
        if (nMonitors == 1) {
 | 
			
		||||
            this.primaryIndex = this.bottomIndex = 0;
 | 
			
		||||
@@ -283,8 +300,10 @@ const LayoutManager = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _updateHotCorners: function() {
 | 
			
		||||
        // destroy old hot corners
 | 
			
		||||
        for (let i = 0; i < this.hotCorners.length; i++)
 | 
			
		||||
            this.hotCorners[i].destroy();
 | 
			
		||||
        this.hotCorners.forEach(function(corner) {
 | 
			
		||||
            if (corner)
 | 
			
		||||
                corner.destroy();
 | 
			
		||||
        });
 | 
			
		||||
        this.hotCorners = [];
 | 
			
		||||
 | 
			
		||||
        let size = this.panelBox.height;
 | 
			
		||||
@@ -295,9 +314,9 @@ const LayoutManager = new Lang.Class({
 | 
			
		||||
            let cornerX = this._rtl ? monitor.x + monitor.width : monitor.x;
 | 
			
		||||
            let cornerY = monitor.y;
 | 
			
		||||
 | 
			
		||||
            if (i != this.primaryIndex) {
 | 
			
		||||
                let haveTopLeftCorner = true;
 | 
			
		||||
            let haveTopLeftCorner = true;
 | 
			
		||||
 | 
			
		||||
            if (i != this.primaryIndex) {
 | 
			
		||||
                // Check if we have a top left (right for RTL) corner.
 | 
			
		||||
                // I.e. if there is no monitor directly above or to the left(right)
 | 
			
		||||
                let besideX = this._rtl ? monitor.x + 1 : cornerX - 1;
 | 
			
		||||
@@ -324,14 +343,15 @@ const LayoutManager = new Lang.Class({
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (!haveTopLeftCorner)
 | 
			
		||||
                    continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let corner = new HotCorner(this, monitor, cornerX, cornerY);
 | 
			
		||||
            corner.setBarrierSize(size);
 | 
			
		||||
            this.hotCorners.push(corner);
 | 
			
		||||
            if (haveTopLeftCorner) {
 | 
			
		||||
                let corner = new HotCorner(this, monitor, cornerX, cornerY);
 | 
			
		||||
                corner.setBarrierSize(size);
 | 
			
		||||
                this.hotCorners.push(corner);
 | 
			
		||||
            } else {
 | 
			
		||||
                this.hotCorners.push(null);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.emit('hot-corners-changed');
 | 
			
		||||
@@ -408,7 +428,8 @@ const LayoutManager = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        let size = this.panelBox.height;
 | 
			
		||||
        this.hotCorners.forEach(function(corner) {
 | 
			
		||||
            corner.setBarrierSize(size);
 | 
			
		||||
            if (corner)
 | 
			
		||||
                corner.setBarrierSize(size);
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -536,6 +557,25 @@ const LayoutManager = new Lang.Class({
 | 
			
		||||
        return this._keyboardIndex;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _loadBackground: function() {
 | 
			
		||||
        this._systemBackground = new Background.SystemBackground();
 | 
			
		||||
        this._systemBackground.actor.hide();
 | 
			
		||||
 | 
			
		||||
        global.stage.insert_child_below(this._systemBackground.actor, null);
 | 
			
		||||
 | 
			
		||||
        let constraint = new Clutter.BindConstraint({ source: global.stage,
 | 
			
		||||
                                                      coordinate: Clutter.BindCoordinate.ALL });
 | 
			
		||||
        this._systemBackground.actor.add_constraint(constraint);
 | 
			
		||||
 | 
			
		||||
        let signalId = this._systemBackground.connect('loaded', Lang.bind(this, function() {
 | 
			
		||||
            this._systemBackground.disconnect(signalId);
 | 
			
		||||
            this._systemBackground.actor.show();
 | 
			
		||||
            global.stage.show();
 | 
			
		||||
 | 
			
		||||
            this._prepareStartupAnimation();
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Startup Animations
 | 
			
		||||
    //
 | 
			
		||||
    // We have two different animations, depending on whether we're a greeter
 | 
			
		||||
@@ -581,35 +621,18 @@ const LayoutManager = new Lang.Class({
 | 
			
		||||
            global.window_group.set_clip(monitor.x, monitor.y, monitor.width, monitor.height);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._systemBackground = new Background.SystemBackground();
 | 
			
		||||
        this._systemBackground.actor.hide();
 | 
			
		||||
        this.emit('startup-prepared');
 | 
			
		||||
 | 
			
		||||
        global.stage.insert_child_below(this._systemBackground.actor, null);
 | 
			
		||||
 | 
			
		||||
        let constraint = new Clutter.BindConstraint({ source: global.stage,
 | 
			
		||||
                                                      coordinate: Clutter.BindCoordinate.ALL });
 | 
			
		||||
        this._systemBackground.actor.add_constraint(constraint);
 | 
			
		||||
 | 
			
		||||
        let signalId = this._systemBackground.connect('loaded',
 | 
			
		||||
                                                      Lang.bind(this, function() {
 | 
			
		||||
                                                          this._systemBackground.disconnect(signalId);
 | 
			
		||||
                                                          this._systemBackground.actor.show();
 | 
			
		||||
                                                          global.stage.show();
 | 
			
		||||
 | 
			
		||||
                                                          this.emit('startup-prepared');
 | 
			
		||||
 | 
			
		||||
                                                          // We're mostly prepared for the startup animation
 | 
			
		||||
                                                          // now, but since a lot is going on asynchronously
 | 
			
		||||
                                                          // during startup, let's defer the startup animation
 | 
			
		||||
                                                          // until the event loop is uncontended and idle.
 | 
			
		||||
                                                          // This helps to prevent us from running the animation
 | 
			
		||||
                                                          // when the system is bogged down
 | 
			
		||||
                                                          GLib.idle_add(GLib.PRIORITY_LOW,
 | 
			
		||||
                                                                        Lang.bind(this, function() {
 | 
			
		||||
                                                                            this._startupAnimation();
 | 
			
		||||
                                                                            return false;
 | 
			
		||||
                                                                        }));
 | 
			
		||||
                                                      }));
 | 
			
		||||
        // We're mostly prepared for the startup animation
 | 
			
		||||
        // now, but since a lot is going on asynchronously
 | 
			
		||||
        // during startup, let's defer the startup animation
 | 
			
		||||
        // until the event loop is uncontended and idle.
 | 
			
		||||
        // This helps to prevent us from running the animation
 | 
			
		||||
        // when the system is bogged down
 | 
			
		||||
        GLib.idle_add(GLib.PRIORITY_LOW, Lang.bind(this, function() {
 | 
			
		||||
            this._startupAnimation();
 | 
			
		||||
            return false;
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _startupAnimation: function() {
 | 
			
		||||
@@ -666,7 +689,6 @@ const LayoutManager = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    showKeyboard: function () {
 | 
			
		||||
        this.keyboardBox.raise_top();
 | 
			
		||||
        Tweener.addTween(this.keyboardBox,
 | 
			
		||||
                         { anchor_y: this.keyboardBox.height,
 | 
			
		||||
                           time: KEYBOARD_ANIMATION_TIME,
 | 
			
		||||
@@ -711,11 +733,10 @@ const LayoutManager = new Lang.Class({
 | 
			
		||||
    // @actor: an actor to add to the chrome
 | 
			
		||||
    // @params: (optional) additional params
 | 
			
		||||
    //
 | 
			
		||||
    // Adds @actor to the chrome, and (unless %affectsInputRegion in
 | 
			
		||||
    // @params is %false) extends the input region to include it.
 | 
			
		||||
    // Changes in @actor's size, position, and visibility will
 | 
			
		||||
    // automatically result in appropriate changes to the input
 | 
			
		||||
    // region.
 | 
			
		||||
    // Adds @actor to the chrome, and extends the input region
 | 
			
		||||
    // to include it. Changes in @actor's size, position, and
 | 
			
		||||
    // visibility will automatically result in appropriate changes
 | 
			
		||||
    // to the input region.
 | 
			
		||||
    //
 | 
			
		||||
    // If %affectsStruts in @params is %true (and @actor is along a
 | 
			
		||||
    // screen edge), then @actor's size and position will also affect
 | 
			
		||||
@@ -900,13 +921,8 @@ const LayoutManager = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateFullscreen: function() {
 | 
			
		||||
        for (let i = 0; i < this.monitors.length; i++)
 | 
			
		||||
            this.monitors[i].inFullscreen = global.screen.get_monitor_in_fullscreen (i);
 | 
			
		||||
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
        this._queueUpdateRegions();
 | 
			
		||||
 | 
			
		||||
        this.emit('fullscreen-changed');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _windowsRestacked: function() {
 | 
			
		||||
@@ -934,7 +950,7 @@ const LayoutManager = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        for (i = 0; i < this._trackedActors.length; i++) {
 | 
			
		||||
            let actorData = this._trackedActors[i];
 | 
			
		||||
            if (!(actorData.affectsInputRegion && wantsInputRegion) && !actorData.affectsStruts)
 | 
			
		||||
            if (!wantsInputRegion && !actorData.affectsStruts)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            let [x, y] = actorData.actor.get_transformed_position();
 | 
			
		||||
@@ -944,13 +960,8 @@ const LayoutManager = new Lang.Class({
 | 
			
		||||
            w = Math.round(w);
 | 
			
		||||
            h = Math.round(h);
 | 
			
		||||
 | 
			
		||||
            if (actorData.affectsInputRegion && wantsInputRegion) {
 | 
			
		||||
                let rect = new Meta.Rectangle({ x: x, y: y, width: w, height: h});
 | 
			
		||||
 | 
			
		||||
                if (actorData.actor.get_paint_visibility() &&
 | 
			
		||||
                    !this.uiGroup.get_skip_paint(actorData.actor))
 | 
			
		||||
                    rects.push(rect);
 | 
			
		||||
            }
 | 
			
		||||
            if (wantsInputRegion && actorData.actor.get_paint_visibility())
 | 
			
		||||
                rects.push(new Meta.Rectangle({ x: x, y: y, width: w, height: h }));
 | 
			
		||||
 | 
			
		||||
            if (actorData.affectsStruts) {
 | 
			
		||||
                // Limit struts to the size of the screen
 | 
			
		||||
@@ -1092,12 +1103,21 @@ const HotCorner = new Lang.Class({
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (size > 0) {
 | 
			
		||||
            this._verticalBarrier = new Meta.Barrier({ display: global.display,
 | 
			
		||||
                                                       x1: this._x, x2: this._x, y1: this._y, y2: this._y + size,
 | 
			
		||||
                                                       directions: Meta.BarrierDirection.POSITIVE_X });
 | 
			
		||||
            this._horizontalBarrier = new Meta.Barrier({ display: global.display,
 | 
			
		||||
                                                         x1: this._x, x2: this._x + size, y1: this._y, y2: this._y,
 | 
			
		||||
                                                         directions: Meta.BarrierDirection.POSITIVE_Y });
 | 
			
		||||
            if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
 | 
			
		||||
                this._verticalBarrier = new Meta.Barrier({ display: global.display,
 | 
			
		||||
                                                           x1: this._x, x2: this._x, y1: this._y, y2: this._y + size,
 | 
			
		||||
                                                           directions: Meta.BarrierDirection.NEGATIVE_X });
 | 
			
		||||
                this._horizontalBarrier = new Meta.Barrier({ display: global.display,
 | 
			
		||||
                                                             x1: this._x - size, x2: this._x, y1: this._y, y2: this._y,
 | 
			
		||||
                                                             directions: Meta.BarrierDirection.POSITIVE_Y });
 | 
			
		||||
            } else {
 | 
			
		||||
                this._verticalBarrier = new Meta.Barrier({ display: global.display,
 | 
			
		||||
                                                           x1: this._x, x2: this._x, y1: this._y, y2: this._y + size,
 | 
			
		||||
                                                           directions: Meta.BarrierDirection.POSITIVE_X });
 | 
			
		||||
                this._horizontalBarrier = new Meta.Barrier({ display: global.display,
 | 
			
		||||
                                                             x1: this._x, x2: this._x + size, y1: this._y, y2: this._y,
 | 
			
		||||
                                                             directions: Meta.BarrierDirection.POSITIVE_Y });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this._pressureBarrier.addBarrier(this._verticalBarrier);
 | 
			
		||||
            this._pressureBarrier.addBarrier(this._horizontalBarrier);
 | 
			
		||||
@@ -1112,11 +1132,11 @@ const HotCorner = new Lang.Class({
 | 
			
		||||
                                             height: 3,
 | 
			
		||||
                                             reactive: true });
 | 
			
		||||
 | 
			
		||||
            this._corner = new Clutter.Rectangle({ name: 'hot-corner',
 | 
			
		||||
                                                   width: 1,
 | 
			
		||||
                                                   height: 1,
 | 
			
		||||
                                                   opacity: 0,
 | 
			
		||||
                                                   reactive: true });
 | 
			
		||||
            this._corner = new Clutter.Actor({ name: 'hot-corner',
 | 
			
		||||
                                               width: 1,
 | 
			
		||||
                                               height: 1,
 | 
			
		||||
                                               opacity: 0,
 | 
			
		||||
                                               reactive: true });
 | 
			
		||||
            this._corner._delegate = this;
 | 
			
		||||
 | 
			
		||||
            this.actor.add_child(this._corner);
 | 
			
		||||
 
 | 
			
		||||
@@ -308,10 +308,6 @@ const Result = new Lang.Class({
 | 
			
		||||
        box.add(resultTxt);
 | 
			
		||||
        let objLink = new ObjLink(this._lookingGlass, o);
 | 
			
		||||
        box.add(objLink.actor);
 | 
			
		||||
        let line = new Clutter.Rectangle({ name: 'Separator' });
 | 
			
		||||
        let padBin = new St.Bin({ name: 'Separator', x_fill: true, y_fill: true });
 | 
			
		||||
        padBin.add_actor(line);
 | 
			
		||||
        this.actor.add(padBin);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -989,28 +985,18 @@ const LookingGlass = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _showCompletions: function(completions) {
 | 
			
		||||
        if (!this._completionActor) {
 | 
			
		||||
            let actor = new St.BoxLayout({ vertical: true });
 | 
			
		||||
 | 
			
		||||
            this._completionText = new St.Label({ name: 'LookingGlassAutoCompletionText', style_class: 'lg-completions-text' });
 | 
			
		||||
            this._completionText.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
 | 
			
		||||
            this._completionText.clutter_text.line_wrap = true;
 | 
			
		||||
            actor.add(this._completionText);
 | 
			
		||||
 | 
			
		||||
            let line = new Clutter.Rectangle();
 | 
			
		||||
            let padBin = new St.Bin({ x_fill: true, y_fill: true });
 | 
			
		||||
            padBin.add_actor(line);
 | 
			
		||||
            actor.add(padBin);
 | 
			
		||||
 | 
			
		||||
            this._completionActor = actor;
 | 
			
		||||
            this._completionActor = new St.Label({ name: 'LookingGlassAutoCompletionText', style_class: 'lg-completions-text' });
 | 
			
		||||
            this._completionActor.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
 | 
			
		||||
            this._completionActor.clutter_text.line_wrap = true;
 | 
			
		||||
            this._evalBox.insert_child_below(this._completionActor, this._entryArea);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._completionText.set_text(completions.join(', '));
 | 
			
		||||
        this._completionActor.set_text(completions.join(', '));
 | 
			
		||||
 | 
			
		||||
        // Setting the height to -1 allows us to get its actual preferred height rather than
 | 
			
		||||
        // whatever was last given in set_height by Tweener.
 | 
			
		||||
        this._completionActor.set_height(-1);
 | 
			
		||||
        let [minHeight, naturalHeight] = this._completionText.get_preferred_height(this._resultsArea.get_width());
 | 
			
		||||
        let [minHeight, naturalHeight] = this._completionActor.get_preferred_height(this._resultsArea.get_width());
 | 
			
		||||
 | 
			
		||||
        // Don't reanimate if we are already visible
 | 
			
		||||
        if (this._completionActor.visible) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										217
									
								
								js/ui/main.js
									
									
									
									
									
								
							
							
						
						
									
										217
									
								
								js/ui/main.js
									
									
									
									
									
								
							@@ -38,9 +38,11 @@ const Magnifier = imports.ui.magnifier;
 | 
			
		||||
const XdndHandler = imports.ui.xdndHandler;
 | 
			
		||||
const Util = imports.misc.util;
 | 
			
		||||
 | 
			
		||||
const OVERRIDES_SCHEMA = 'org.gnome.shell.overrides';
 | 
			
		||||
const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
 | 
			
		||||
 | 
			
		||||
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
 | 
			
		||||
const STICKY_KEYS_ENABLE = 'stickykeys-enable';
 | 
			
		||||
 | 
			
		||||
let componentManager = null;
 | 
			
		||||
let panel = null;
 | 
			
		||||
let overview = null;
 | 
			
		||||
@@ -68,7 +70,7 @@ let layoutManager = null;
 | 
			
		||||
let _startDate;
 | 
			
		||||
let _defaultCssStylesheet = null;
 | 
			
		||||
let _cssStylesheet = null;
 | 
			
		||||
let _overridesSettings = null;
 | 
			
		||||
let _a11ySettings = null;
 | 
			
		||||
 | 
			
		||||
function _sessionUpdated() {
 | 
			
		||||
    _loadDefaultStylesheet();
 | 
			
		||||
@@ -123,11 +125,9 @@ function _initializeUI() {
 | 
			
		||||
    // and recalculate application associations, so to avoid
 | 
			
		||||
    // races for now we initialize it here.  It's better to
 | 
			
		||||
    // be predictable anyways.
 | 
			
		||||
    let tracker = Shell.WindowTracker.get_default();
 | 
			
		||||
    Shell.WindowTracker.get_default();
 | 
			
		||||
    Shell.AppUsage.get_default();
 | 
			
		||||
 | 
			
		||||
    tracker.connect('startup-sequence-changed', _queueCheckWorkspaces);
 | 
			
		||||
 | 
			
		||||
    _loadDefaultStylesheet();
 | 
			
		||||
 | 
			
		||||
    // Setup the stage hierarchy early
 | 
			
		||||
@@ -157,9 +157,12 @@ function _initializeUI() {
 | 
			
		||||
    layoutManager.init();
 | 
			
		||||
    overview.init();
 | 
			
		||||
 | 
			
		||||
    global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
 | 
			
		||||
                                            false, -1, 1);
 | 
			
		||||
    global.display.connect('overlay-key', Lang.bind(overview, overview.toggle));
 | 
			
		||||
    _a11ySettings = new Gio.Settings({ schema: A11Y_SCHEMA });
 | 
			
		||||
 | 
			
		||||
    global.display.connect('overlay-key', Lang.bind(overview, function () {
 | 
			
		||||
        if (!_a11ySettings.get_boolean (STICKY_KEYS_ENABLE))
 | 
			
		||||
            overview.toggle();
 | 
			
		||||
    }));
 | 
			
		||||
 | 
			
		||||
    // Provide the bus object for gnome-session to
 | 
			
		||||
    // initiate logouts.
 | 
			
		||||
@@ -179,17 +182,6 @@ function _initializeUI() {
 | 
			
		||||
        Scripting.runPerfScript(module, perfOutput);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _overridesSettings = new Gio.Settings({ schema: OVERRIDES_SCHEMA });
 | 
			
		||||
    _overridesSettings.connect('changed::dynamic-workspaces', _queueCheckWorkspaces);
 | 
			
		||||
 | 
			
		||||
    global.screen.connect('notify::n-workspaces', _nWorkspacesChanged);
 | 
			
		||||
 | 
			
		||||
    global.screen.connect('window-entered-monitor', _windowEnteredMonitor);
 | 
			
		||||
    global.screen.connect('window-left-monitor', _windowLeftMonitor);
 | 
			
		||||
    global.screen.connect('restacked', _windowsRestacked);
 | 
			
		||||
 | 
			
		||||
    _nWorkspacesChanged();
 | 
			
		||||
 | 
			
		||||
    ExtensionDownloader.init();
 | 
			
		||||
    ExtensionSystem.init();
 | 
			
		||||
 | 
			
		||||
@@ -203,190 +195,12 @@ function _initializeUI() {
 | 
			
		||||
                              if (keybindingMode == Shell.KeyBindingMode.NONE) {
 | 
			
		||||
                                  keybindingMode = Shell.KeyBindingMode.NORMAL;
 | 
			
		||||
                              }
 | 
			
		||||
                              if (screenShield) {
 | 
			
		||||
                                  screenShield.lockIfWasLocked();
 | 
			
		||||
                              }
 | 
			
		||||
                          });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let _workspaces = [];
 | 
			
		||||
let _checkWorkspacesId = 0;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * When the last window closed on a workspace is a dialog or splash
 | 
			
		||||
 * screen, we assume that it might be an initial window shown before
 | 
			
		||||
 * the main window of an application, and give the app a grace period
 | 
			
		||||
 * where it can map another window before we remove the workspace.
 | 
			
		||||
 */
 | 
			
		||||
const LAST_WINDOW_GRACE_TIME = 1000;
 | 
			
		||||
 | 
			
		||||
function _checkWorkspaces() {
 | 
			
		||||
    let i;
 | 
			
		||||
    let emptyWorkspaces = [];
 | 
			
		||||
 | 
			
		||||
    if (!Meta.prefs_get_dynamic_workspaces()) {
 | 
			
		||||
        _checkWorkspacesId = 0;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < _workspaces.length; i++) {
 | 
			
		||||
        let lastRemoved = _workspaces[i]._lastRemovedWindow;
 | 
			
		||||
        if ((lastRemoved &&
 | 
			
		||||
             (lastRemoved.get_window_type() == Meta.WindowType.SPLASHSCREEN ||
 | 
			
		||||
              lastRemoved.get_window_type() == Meta.WindowType.DIALOG ||
 | 
			
		||||
              lastRemoved.get_window_type() == Meta.WindowType.MODAL_DIALOG)) ||
 | 
			
		||||
            _workspaces[i]._keepAliveId)
 | 
			
		||||
                emptyWorkspaces[i] = false;
 | 
			
		||||
        else
 | 
			
		||||
            emptyWorkspaces[i] = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let sequences = Shell.WindowTracker.get_default().get_startup_sequences();
 | 
			
		||||
    for (i = 0; i < sequences.length; i++) {
 | 
			
		||||
        let index = sequences[i].get_workspace();
 | 
			
		||||
        if (index >= 0 && index <= global.screen.n_workspaces)
 | 
			
		||||
            emptyWorkspaces[index] = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let windows = global.get_window_actors();
 | 
			
		||||
    for (i = 0; i < windows.length; i++) {
 | 
			
		||||
        let win = windows[i];
 | 
			
		||||
 | 
			
		||||
        if (win.get_meta_window().is_on_all_workspaces())
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        let workspaceIndex = win.get_workspace();
 | 
			
		||||
        emptyWorkspaces[workspaceIndex] = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // If we don't have an empty workspace at the end, add one
 | 
			
		||||
    if (!emptyWorkspaces[emptyWorkspaces.length -1]) {
 | 
			
		||||
        global.screen.append_new_workspace(false, global.get_current_time());
 | 
			
		||||
        emptyWorkspaces.push(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let activeWorkspaceIndex = global.screen.get_active_workspace_index();
 | 
			
		||||
    let removingCurrentWorkspace = (emptyWorkspaces[activeWorkspaceIndex] &&
 | 
			
		||||
                                    activeWorkspaceIndex < emptyWorkspaces.length - 1);
 | 
			
		||||
    // Don't enter the overview when removing multiple empty workspaces at startup
 | 
			
		||||
    let showOverview  = (removingCurrentWorkspace &&
 | 
			
		||||
                         !emptyWorkspaces.every(function(x) { return x; }));
 | 
			
		||||
 | 
			
		||||
    if (removingCurrentWorkspace) {
 | 
			
		||||
        // "Merge" the empty workspace we are removing with the one at the end
 | 
			
		||||
        wm.blockAnimations();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Delete other empty workspaces; do it from the end to avoid index changes
 | 
			
		||||
    for (i = emptyWorkspaces.length - 2; i >= 0; i--) {
 | 
			
		||||
        if (emptyWorkspaces[i])
 | 
			
		||||
            global.screen.remove_workspace(_workspaces[i], global.get_current_time());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (removingCurrentWorkspace) {
 | 
			
		||||
        global.screen.get_workspace_by_index(global.screen.n_workspaces - 1).activate(global.get_current_time());
 | 
			
		||||
        wm.unblockAnimations();
 | 
			
		||||
 | 
			
		||||
        if (!overview.visible && showOverview)
 | 
			
		||||
            overview.show();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _checkWorkspacesId = 0;
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function keepWorkspaceAlive(workspace, duration) {
 | 
			
		||||
    if (workspace._keepAliveId)
 | 
			
		||||
        Mainloop.source_remove(workspace._keepAliveId);
 | 
			
		||||
 | 
			
		||||
    workspace._keepAliveId = Mainloop.timeout_add(duration, function() {
 | 
			
		||||
        workspace._keepAliveId = 0;
 | 
			
		||||
        _queueCheckWorkspaces();
 | 
			
		||||
        return false;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _windowRemoved(workspace, window) {
 | 
			
		||||
    workspace._lastRemovedWindow = window;
 | 
			
		||||
    _queueCheckWorkspaces();
 | 
			
		||||
    Mainloop.timeout_add(LAST_WINDOW_GRACE_TIME, function() {
 | 
			
		||||
        if (workspace._lastRemovedWindow == window) {
 | 
			
		||||
            workspace._lastRemovedWindow = null;
 | 
			
		||||
            _queueCheckWorkspaces();
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _windowLeftMonitor(metaScreen, monitorIndex, metaWin) {
 | 
			
		||||
    // If the window left the primary monitor, that
 | 
			
		||||
    // might make that workspace empty
 | 
			
		||||
    if (monitorIndex == layoutManager.primaryIndex)
 | 
			
		||||
        _queueCheckWorkspaces();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _windowEnteredMonitor(metaScreen, monitorIndex, metaWin) {
 | 
			
		||||
    // If the window entered the primary monitor, that
 | 
			
		||||
    // might make that workspace non-empty
 | 
			
		||||
    if (monitorIndex == layoutManager.primaryIndex)
 | 
			
		||||
        _queueCheckWorkspaces();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _windowsRestacked() {
 | 
			
		||||
    // Figure out where the pointer is in case we lost track of
 | 
			
		||||
    // it during a grab. (In particular, if a trayicon popup menu
 | 
			
		||||
    // is dismissed, see if we need to close the message tray.)
 | 
			
		||||
    global.sync_pointer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _queueCheckWorkspaces() {
 | 
			
		||||
    if (_checkWorkspacesId == 0)
 | 
			
		||||
        _checkWorkspacesId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, _checkWorkspaces);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _nWorkspacesChanged() {
 | 
			
		||||
    let oldNumWorkspaces = _workspaces.length;
 | 
			
		||||
    let newNumWorkspaces = global.screen.n_workspaces;
 | 
			
		||||
 | 
			
		||||
    if (oldNumWorkspaces == newNumWorkspaces)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    let lostWorkspaces = [];
 | 
			
		||||
    if (newNumWorkspaces > oldNumWorkspaces) {
 | 
			
		||||
        let w;
 | 
			
		||||
 | 
			
		||||
        // Assume workspaces are only added at the end
 | 
			
		||||
        for (w = oldNumWorkspaces; w < newNumWorkspaces; w++)
 | 
			
		||||
            _workspaces[w] = global.screen.get_workspace_by_index(w);
 | 
			
		||||
 | 
			
		||||
        for (w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
 | 
			
		||||
            let workspace = _workspaces[w];
 | 
			
		||||
            workspace._windowAddedId = workspace.connect('window-added', _queueCheckWorkspaces);
 | 
			
		||||
            workspace._windowRemovedId = workspace.connect('window-removed', _windowRemoved);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
        // Assume workspaces are only removed sequentially
 | 
			
		||||
        // (e.g. 2,3,4 - not 2,4,7)
 | 
			
		||||
        let removedIndex;
 | 
			
		||||
        let removedNum = oldNumWorkspaces - newNumWorkspaces;
 | 
			
		||||
        for (let w = 0; w < oldNumWorkspaces; w++) {
 | 
			
		||||
            let workspace = global.screen.get_workspace_by_index(w);
 | 
			
		||||
            if (_workspaces[w] != workspace) {
 | 
			
		||||
                removedIndex = w;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let lostWorkspaces = _workspaces.splice(removedIndex, removedNum);
 | 
			
		||||
        lostWorkspaces.forEach(function(workspace) {
 | 
			
		||||
                                   workspace.disconnect(workspace._windowAddedId);
 | 
			
		||||
                                   workspace.disconnect(workspace._windowRemovedId);
 | 
			
		||||
                               });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _queueCheckWorkspaces();
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _loadDefaultStylesheet() {
 | 
			
		||||
    if (!sessionMode.isPrimary)
 | 
			
		||||
        return;
 | 
			
		||||
@@ -437,7 +251,8 @@ function loadTheme() {
 | 
			
		||||
    if (_cssStylesheet != null)
 | 
			
		||||
        cssStylesheet = _cssStylesheet;
 | 
			
		||||
 | 
			
		||||
    let theme = new St.Theme ({ application_stylesheet: cssStylesheet });
 | 
			
		||||
    let theme = new St.Theme ({ application_stylesheet: cssStylesheet,
 | 
			
		||||
                                default_stylesheet: _defaultCssStylesheet });
 | 
			
		||||
 | 
			
		||||
    if (previousTheme) {
 | 
			
		||||
        let customStylesheets = previousTheme.get_custom_stylesheets();
 | 
			
		||||
 
 | 
			
		||||
@@ -1530,11 +1530,7 @@ const MessageTrayContextMenu = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateClearSensitivity: function() {
 | 
			
		||||
        let sources = this._tray.getSources();
 | 
			
		||||
        sources = sources.filter(function(source) {
 | 
			
		||||
            return !source.trayIcon && !source.isChat && !source.resident;
 | 
			
		||||
        });
 | 
			
		||||
        this._clearItem.setSensitive(sources.length > 0);
 | 
			
		||||
        this._clearItem.setSensitive(this._tray.clearableCount > 0);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setPosition: function(x, y) {
 | 
			
		||||
@@ -1557,23 +1553,22 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.Widget({ name: 'message-tray',
 | 
			
		||||
                                     reactive: true,
 | 
			
		||||
                                     track_hover: true,
 | 
			
		||||
                                     layout_manager: new Clutter.BinLayout(),
 | 
			
		||||
                                     x_expand: true,
 | 
			
		||||
                                     y_expand: true,
 | 
			
		||||
                                     y_align: Clutter.ActorAlign.START,
 | 
			
		||||
                                   });
 | 
			
		||||
        this.actor.connect('notify::hover', Lang.bind(this, this._onTrayHoverChanged));
 | 
			
		||||
 | 
			
		||||
        this._notificationWidget = new St.Widget({ name: 'notification-container',
 | 
			
		||||
                                                   reactive: true,
 | 
			
		||||
                                                   track_hover: true,
 | 
			
		||||
                                                   y_align: Clutter.ActorAlign.START,
 | 
			
		||||
                                                   x_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
                                                   y_expand: true,
 | 
			
		||||
                                                   x_expand: true,
 | 
			
		||||
                                                   layout_manager: new Clutter.BinLayout() });
 | 
			
		||||
        this._notificationWidget.connect('key-release-event', Lang.bind(this, this._onNotificationKeyRelease));
 | 
			
		||||
 | 
			
		||||
        this.actor.add_actor(this._notificationWidget);
 | 
			
		||||
        this._notificationWidget.connect('notify::hover', Lang.bind(this, this._onNotificationHoverChanged));
 | 
			
		||||
 | 
			
		||||
        this._notificationBin = new St.Bin({ y_expand: true });
 | 
			
		||||
        this._notificationBin.set_y_align(Clutter.ActorAlign.START);
 | 
			
		||||
@@ -1628,24 +1623,25 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
                                                     { keybindingMode: Shell.KeyBindingMode.MESSAGE_TRAY });
 | 
			
		||||
        this._grabHelper.addActor(this._summaryBoxPointer.actor);
 | 
			
		||||
        this._grabHelper.addActor(this.actor);
 | 
			
		||||
        this._grabHelper.addActor(this._notificationWidget);
 | 
			
		||||
 | 
			
		||||
        Main.layoutManager.connect('keyboard-visible-changed', Lang.bind(this, this._onKeyboardVisibleChanged));
 | 
			
		||||
 | 
			
		||||
        this._trayState = State.HIDDEN;
 | 
			
		||||
        this._traySummoned = false;
 | 
			
		||||
        this._useLongerTrayLeftTimeout = false;
 | 
			
		||||
        this._useLongerNotificationLeftTimeout = false;
 | 
			
		||||
        this._trayLeftTimeoutId = 0;
 | 
			
		||||
 | 
			
		||||
        // pointerInTray is sort of a misnomer -- it tracks whether
 | 
			
		||||
        // pointerInNotification is sort of a misnomer -- it tracks whether
 | 
			
		||||
        // a message tray notification should expand. The value is
 | 
			
		||||
        // partially driven by the hover state of the tray, but has
 | 
			
		||||
        // partially driven by the hover state of the notification, but has
 | 
			
		||||
        // a lot of complex state related to timeouts and the current
 | 
			
		||||
        // state of the pointer when a notification pops up.
 | 
			
		||||
        this._pointerInTray = false;
 | 
			
		||||
        this._pointerInNotification = false;
 | 
			
		||||
 | 
			
		||||
        // This tracks this.actor.hover and is used to fizzle
 | 
			
		||||
        // out non-changing hover notifications in onTrayHoverChanged.
 | 
			
		||||
        this._trayHovered = false;
 | 
			
		||||
        // This tracks this._notificationWidget.hover and is used to fizzle
 | 
			
		||||
        // out non-changing hover notifications in onNotificationHoverChanged.
 | 
			
		||||
        this._notificationHovered = false;
 | 
			
		||||
 | 
			
		||||
        this._keyboardVisible = false;
 | 
			
		||||
        this._notificationClosed = false;
 | 
			
		||||
@@ -1657,23 +1653,29 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
        this._desktopCloneState = State.HIDDEN;
 | 
			
		||||
        this._notificationRemoved = false;
 | 
			
		||||
        this._reNotifyAfterHideNotification = null;
 | 
			
		||||
        this._inFullscreen = false;
 | 
			
		||||
        this._desktopClone = null;
 | 
			
		||||
        this._inCtrlAltTab = false;
 | 
			
		||||
 | 
			
		||||
        this._lightbox = new Lightbox.Lightbox(global.overlay_group,
 | 
			
		||||
                                               { inhibitEvents: true,
 | 
			
		||||
                                                 fadeInTime: ANIMATION_TIME,
 | 
			
		||||
                                                 fadeOutTime: ANIMATION_TIME,
 | 
			
		||||
                                                 fadeFactor: 0.2
 | 
			
		||||
                                               });
 | 
			
		||||
        this.clearableCount = 0;
 | 
			
		||||
 | 
			
		||||
        this._lightboxes = [];
 | 
			
		||||
        let lightboxContainers = [global.window_group,
 | 
			
		||||
                                  Main.layoutManager.overviewGroup];
 | 
			
		||||
        for (let i = 0; i < lightboxContainers.length; i++)
 | 
			
		||||
            this._lightboxes.push(new Lightbox.Lightbox(lightboxContainers[i],
 | 
			
		||||
                                                        { inhibitEvents: true,
 | 
			
		||||
                                                          fadeInTime: ANIMATION_TIME,
 | 
			
		||||
                                                          fadeOutTime: ANIMATION_TIME,
 | 
			
		||||
                                                          fadeFactor: 0.2
 | 
			
		||||
                                                        }));
 | 
			
		||||
 | 
			
		||||
        Main.layoutManager.trayBox.add_actor(this.actor);
 | 
			
		||||
        Main.layoutManager.trayBox.add_actor(this._notificationWidget);
 | 
			
		||||
        Main.layoutManager.trackChrome(this.actor);
 | 
			
		||||
        Main.layoutManager.trackChrome(this._notificationWidget);
 | 
			
		||||
        Main.layoutManager.trackChrome(this._closeButton);
 | 
			
		||||
 | 
			
		||||
        Main.layoutManager.connect('fullscreen-changed', Lang.bind(this, this._updateState));
 | 
			
		||||
        global.screen.connect('in-fullscreen-changed', Lang.bind(this, this._updateState));
 | 
			
		||||
        Main.layoutManager.connect('hot-corners-changed', Lang.bind(this, this._hotCornersChanged));
 | 
			
		||||
 | 
			
		||||
        // If the overview shows or hides while we're in
 | 
			
		||||
@@ -1721,9 +1723,6 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
        this.actor.add_action(clickAction);
 | 
			
		||||
 | 
			
		||||
        clickAction.connect('clicked', Lang.bind(this, function(action) {
 | 
			
		||||
            if (this._trayState != State.SHOWN)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            let button = action.get_button();
 | 
			
		||||
            if (button == 3)
 | 
			
		||||
                this._openContextMenu();
 | 
			
		||||
@@ -1734,7 +1733,7 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
        clickAction.connect('long-press', Lang.bind(this, function(action, actor, state) {
 | 
			
		||||
            switch (state) {
 | 
			
		||||
            case Clutter.LongPressState.QUERY:
 | 
			
		||||
                return this._trayState == State.SHOWN;
 | 
			
		||||
                return true;
 | 
			
		||||
            case Clutter.LongPressState.ACTIVATE:
 | 
			
		||||
                this._openContextMenu();
 | 
			
		||||
            }
 | 
			
		||||
@@ -1750,7 +1749,7 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
        let [x, y, mask] = global.get_pointer();
 | 
			
		||||
        this._contextMenu.setPosition(Math.round(x), Math.round(y));
 | 
			
		||||
        this._grabHelper.grab({ actor: this._contextMenu.actor,
 | 
			
		||||
                                grabFocus: true,
 | 
			
		||||
                                modal: true,
 | 
			
		||||
                                onUngrab: Lang.bind(this, function () {
 | 
			
		||||
                                    this._contextMenu.close(BoxPointer.PopupAnimation.FULL);
 | 
			
		||||
                                })
 | 
			
		||||
@@ -1796,12 +1795,12 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
                           y == monitor.y + monitor.height - 1);
 | 
			
		||||
        if (shouldDwell) {
 | 
			
		||||
            // We only set up dwell timeout when the user is not hovering over the tray
 | 
			
		||||
            // (!this.actor.hover). This avoids bringing up the message tray after the
 | 
			
		||||
            // (!this._notificationHovered). This avoids bringing up the message tray after the
 | 
			
		||||
            // user clicks on a notification with the pointer on the bottom pixel
 | 
			
		||||
            // of the monitor. The _trayDwelling variable is used so that we only try to
 | 
			
		||||
            // fire off one tray dwell - if it fails (because, say, the user has the mouse down),
 | 
			
		||||
            // we don't try again until the user moves the mouse up and down again.
 | 
			
		||||
            if (!this._trayDwelling && !this.actor.hover && this._trayDwellTimeoutId == 0) {
 | 
			
		||||
            if (!this._trayDwelling && !this._notificationHovered && this._trayDwellTimeoutId == 0) {
 | 
			
		||||
                // Save the interaction timestamp so we can detect user input
 | 
			
		||||
                let focusWindow = global.display.focus_window;
 | 
			
		||||
                this._trayDwellUserTime = focusWindow ? focusWindow.user_time : 0;
 | 
			
		||||
@@ -1899,6 +1898,9 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
            this._summary.insert_child_at_index(summaryItem.actor, this._chatSummaryItemsCount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!source.trayIcon && !source.isChat && !source.resident)
 | 
			
		||||
            this.clearableCount++;
 | 
			
		||||
 | 
			
		||||
        this._sources.set(source, obj);
 | 
			
		||||
 | 
			
		||||
        obj.notifyId = source.connect('notify', Lang.bind(this, this._onNotify));
 | 
			
		||||
@@ -1940,6 +1942,9 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
        if (source.isChat)
 | 
			
		||||
            this._chatSummaryItemsCount--;
 | 
			
		||||
 | 
			
		||||
        if (!source.trayIcon && !source.isChat && !source.resident)
 | 
			
		||||
            this.clearableCount--;
 | 
			
		||||
 | 
			
		||||
        source.disconnect(obj.notifyId);
 | 
			
		||||
        source.disconnect(obj.destroyId);
 | 
			
		||||
        source.disconnect(obj.mutedChangedId);
 | 
			
		||||
@@ -1995,7 +2000,6 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let index = this._notificationQueue.indexOf(notification);
 | 
			
		||||
        notification.destroy();
 | 
			
		||||
        if (index != -1)
 | 
			
		||||
            this._notificationQueue.splice(index, 1);
 | 
			
		||||
    },
 | 
			
		||||
@@ -2024,7 +2028,6 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    hide: function() {
 | 
			
		||||
        this._traySummoned = false;
 | 
			
		||||
        this.actor.set_hover(false);
 | 
			
		||||
        this._updateState();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -2091,25 +2094,21 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
            this._grabHelper.addActor(corner.actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onTrayHoverChanged: function() {
 | 
			
		||||
        if (this.actor.hover == this._trayHovered)
 | 
			
		||||
    _onNotificationHoverChanged: function() {
 | 
			
		||||
        if (this._notificationWidget.hover == this._notificationHovered)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._trayHovered = this.actor.hover;
 | 
			
		||||
        if (this._trayHovered) {
 | 
			
		||||
        this._notificationHovered = this._notificationWidget.hover;
 | 
			
		||||
        if (this._notificationHovered) {
 | 
			
		||||
            // No dwell inside notifications at the bottom of the screen
 | 
			
		||||
            this._cancelTrayDwell();
 | 
			
		||||
 | 
			
		||||
            // Don't do anything if the one pixel area at the bottom is hovered over while the tray is hidden.
 | 
			
		||||
            if (this._trayState == State.HIDDEN && this._notificationState == State.HIDDEN)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            this._useLongerTrayLeftTimeout = false;
 | 
			
		||||
            if (this._trayLeftTimeoutId) {
 | 
			
		||||
                Mainloop.source_remove(this._trayLeftTimeoutId);
 | 
			
		||||
                this._trayLeftTimeoutId = 0;
 | 
			
		||||
                this._trayLeftMouseX = -1;
 | 
			
		||||
                this._trayLeftMouseY = -1;
 | 
			
		||||
            this._useLongerNotificationLeftTimeout = false;
 | 
			
		||||
            if (this._notificationLeftTimeoutId) {
 | 
			
		||||
                Mainloop.source_remove(this._notificationLeftTimeoutId);
 | 
			
		||||
                this._notificationLeftTimeoutId = 0;
 | 
			
		||||
                this._notificationLeftMouseX = -1;
 | 
			
		||||
                this._notificationLeftMouseY = -1;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -2118,32 +2117,32 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
                    global.stage.get_actor_at_pos(Clutter.PickMode.ALL, this._showNotificationMouseX, this._showNotificationMouseY);
 | 
			
		||||
                this._showNotificationMouseX = -1;
 | 
			
		||||
                this._showNotificationMouseY = -1;
 | 
			
		||||
                // Don't set this._pointerInTray to true if the pointer was initially in the area where the notification
 | 
			
		||||
                // Don't set this._pointerInNotification to true if the pointer was initially in the area where the notification
 | 
			
		||||
                // popped up. That way we will not be expanding notifications that happen to pop up over the pointer
 | 
			
		||||
                // automatically. Instead, the user is able to expand the notification by mousing away from it and then
 | 
			
		||||
                // mousing back in. Because this is an expected action, we set the boolean flag that indicates that a longer
 | 
			
		||||
                // timeout should be used before popping down the notification.
 | 
			
		||||
                if (this.actor.contains(actorAtShowNotificationPosition)) {
 | 
			
		||||
                    this._useLongerTrayLeftTimeout = true;
 | 
			
		||||
                    this._useLongerNotificationLeftTimeout = true;
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            this._pointerInTray = true;
 | 
			
		||||
            this._pointerInNotification = true;
 | 
			
		||||
            this._updateState();
 | 
			
		||||
        } else {
 | 
			
		||||
            // We record the position of the mouse the moment it leaves the tray. These coordinates are used in
 | 
			
		||||
            // this._onTrayLeftTimeout() to determine if the mouse has moved far enough during the initial timeout for us
 | 
			
		||||
            // this._onNotificationLeftTimeout() to determine if the mouse has moved far enough during the initial timeout for us
 | 
			
		||||
            // to consider that the user intended to leave the tray and therefore hide the tray. If the mouse is still
 | 
			
		||||
            // close to its previous position, we extend the timeout once.
 | 
			
		||||
            let [x, y, mods] = global.get_pointer();
 | 
			
		||||
            this._trayLeftMouseX = x;
 | 
			
		||||
            this._trayLeftMouseY = y;
 | 
			
		||||
            this._notificationLeftMouseX = x;
 | 
			
		||||
            this._notificationLeftMouseY = y;
 | 
			
		||||
 | 
			
		||||
            // We wait just a little before hiding the message tray in case the user quickly moves the mouse back into it.
 | 
			
		||||
            // We wait for a longer period if the notification popped up where the mouse pointer was already positioned.
 | 
			
		||||
            // That gives the user more time to mouse away from the notification and mouse back in in order to expand it.
 | 
			
		||||
            let timeout = this._useLongerTrayLeftTimeout ? LONGER_HIDE_TIMEOUT * 1000 : HIDE_TIMEOUT * 1000;
 | 
			
		||||
            this._trayLeftTimeoutId = Mainloop.timeout_add(timeout, Lang.bind(this, this._onTrayLeftTimeout));
 | 
			
		||||
            let timeout = this._useLongerNotificationLeftTimeout ? LONGER_HIDE_TIMEOUT * 1000 : HIDE_TIMEOUT * 1000;
 | 
			
		||||
            this._notificationLeftTimeoutId = Mainloop.timeout_add(timeout, Lang.bind(this, this._onNotificationLeftTimeout));
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -2167,22 +2166,22 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
        this._updateState();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onTrayLeftTimeout: function() {
 | 
			
		||||
    _onNotificationLeftTimeout: function() {
 | 
			
		||||
        let [x, y, mods] = global.get_pointer();
 | 
			
		||||
        // We extend the timeout once if the mouse moved no further than MOUSE_LEFT_ACTOR_THRESHOLD to either side or up.
 | 
			
		||||
        // We don't check how far down the mouse moved because any point above the tray, but below the exit coordinate,
 | 
			
		||||
        // is close to the tray.
 | 
			
		||||
        if (this._trayLeftMouseX > -1 &&
 | 
			
		||||
            y > this._trayLeftMouseY - MOUSE_LEFT_ACTOR_THRESHOLD &&
 | 
			
		||||
            x < this._trayLeftMouseX + MOUSE_LEFT_ACTOR_THRESHOLD &&
 | 
			
		||||
            x > this._trayLeftMouseX - MOUSE_LEFT_ACTOR_THRESHOLD) {
 | 
			
		||||
            this._trayLeftMouseX = -1;
 | 
			
		||||
            this._trayLeftTimeoutId = Mainloop.timeout_add(LONGER_HIDE_TIMEOUT * 1000,
 | 
			
		||||
                                                             Lang.bind(this, this._onTrayLeftTimeout));
 | 
			
		||||
        if (this._notificationLeftMouseX > -1 &&
 | 
			
		||||
            y > this._notificationLeftMouseY - MOUSE_LEFT_ACTOR_THRESHOLD &&
 | 
			
		||||
            x < this._notificationLeftMouseX + MOUSE_LEFT_ACTOR_THRESHOLD &&
 | 
			
		||||
            x > this._notificationLeftMouseX - MOUSE_LEFT_ACTOR_THRESHOLD) {
 | 
			
		||||
            this._notificationLeftMouseX = -1;
 | 
			
		||||
            this._notificationLeftTimeoutId = Mainloop.timeout_add(LONGER_HIDE_TIMEOUT * 1000,
 | 
			
		||||
                                                             Lang.bind(this, this._onNotificationLeftTimeout));
 | 
			
		||||
        } else {
 | 
			
		||||
            this._trayLeftTimeoutId = 0;
 | 
			
		||||
            this._useLongerTrayLeftTimeout = false;
 | 
			
		||||
            this._pointerInTray = false;
 | 
			
		||||
            this._notificationLeftTimeoutId = 0;
 | 
			
		||||
            this._useLongerNotificationLeftTimeout = false;
 | 
			
		||||
            this._pointerInNotification = false;
 | 
			
		||||
            this._updateNotificationTimeout(0);
 | 
			
		||||
            this._updateState();
 | 
			
		||||
        }
 | 
			
		||||
@@ -2190,7 +2189,7 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _escapeTray: function() {
 | 
			
		||||
        this._pointerInTray = false;
 | 
			
		||||
        this._pointerInNotification = false;
 | 
			
		||||
        this._traySummoned = false;
 | 
			
		||||
        this._setClickedSummaryItem(null);
 | 
			
		||||
        this._updateNotificationTimeout(0);
 | 
			
		||||
@@ -2199,26 +2198,33 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    // All of the logic for what happens when occurs here; the various
 | 
			
		||||
    // event handlers merely update variables such as
 | 
			
		||||
    // 'this._pointerInTray', 'this._traySummoned', etc, and
 | 
			
		||||
    // 'this._pointerInNotification', 'this._traySummoned', etc, and
 | 
			
		||||
    // _updateState() figures out what (if anything) needs to be done
 | 
			
		||||
    // at the present time.
 | 
			
		||||
    _updateState: function() {
 | 
			
		||||
        // Notifications
 | 
			
		||||
        let notificationQueue = this._notificationQueue;
 | 
			
		||||
        let notificationQueue = this._notificationQueue.filter(function(n) {
 | 
			
		||||
            return !n.acknowledged;
 | 
			
		||||
        });
 | 
			
		||||
        let hasNotifications = Main.sessionMode.hasNotifications;
 | 
			
		||||
 | 
			
		||||
        this._notificationQueue = notificationQueue;
 | 
			
		||||
        let notificationUrgent = notificationQueue.length > 0 && notificationQueue[0].urgency == Urgency.CRITICAL;
 | 
			
		||||
        let notificationForFeedback = notificationQueue.length > 0 && notificationQueue[0].forFeedback;
 | 
			
		||||
        let notificationsLimited = this._busy || Main.layoutManager.bottomMonitor.inFullscreen;
 | 
			
		||||
        let notificationsPending = notificationQueue.length > 0 && (!notificationsLimited || notificationUrgent || notificationForFeedback) && Main.sessionMode.hasNotifications;
 | 
			
		||||
        let notificationsPending = notificationQueue.length > 0 && (!notificationsLimited || notificationUrgent || notificationForFeedback) && hasNotifications;
 | 
			
		||||
        let nextNotification = notificationQueue.length > 0 ? notificationQueue[0] : null;
 | 
			
		||||
        let notificationPinned = this._pointerInTray && !this._notificationRemoved;
 | 
			
		||||
        let notificationPinned = this._pointerInNotification && !this._notificationRemoved;
 | 
			
		||||
        let notificationExpanded = this._notification && this._notification.expanded;
 | 
			
		||||
        let notificationExpired = this._notificationTimeoutId == 0 &&
 | 
			
		||||
                                  !(this._notification && this._notification.urgency == Urgency.CRITICAL) &&
 | 
			
		||||
                                  !(this._notification && this._notification.focused) &&
 | 
			
		||||
                                  !this._pointerInTray;
 | 
			
		||||
        let notificationLockedOut = !Main.sessionMode.hasNotifications && this._notification;
 | 
			
		||||
        let notificationMustClose = this._notificationRemoved || notificationLockedOut || (notificationExpired && this._userActiveWhileNotificationShown) || this._notificationClosed;
 | 
			
		||||
        let canShowNotification = notificationsPending && this._trayState == State.HIDDEN;
 | 
			
		||||
                                  !this._pointerInNotification;
 | 
			
		||||
        let notificationLockedOut = !hasNotifications && this._notification;
 | 
			
		||||
        let notificationMustClose = (this._notificationRemoved || notificationLockedOut ||
 | 
			
		||||
                                     (notificationExpired && this._userActiveWhileNotificationShown) ||
 | 
			
		||||
                                     this._notificationClosed || this._traySummoned);
 | 
			
		||||
        let canShowNotification = notificationsPending && this._trayState == State.HIDDEN && !this._traySummoned;
 | 
			
		||||
 | 
			
		||||
        if (this._notificationState == State.HIDDEN) {
 | 
			
		||||
            if (canShowNotification)
 | 
			
		||||
@@ -2232,12 +2238,6 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
                this._ensureNotificationFocused();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let notificationsVisible = this._notificationState != State.HIDDEN;
 | 
			
		||||
        let notificationsDone = !notificationsVisible && !notificationsPending;
 | 
			
		||||
 | 
			
		||||
        let mustHideTray = ((notificationsPending && notificationUrgent)
 | 
			
		||||
                           || notificationsVisible || !Main.sessionMode.hasNotifications);
 | 
			
		||||
 | 
			
		||||
        // Summary notification
 | 
			
		||||
        let haveClickedSummaryItem = this._clickedSummaryItem != null;
 | 
			
		||||
        let summarySourceIsMainNotificationSource = (haveClickedSummaryItem && this._notification &&
 | 
			
		||||
@@ -2245,10 +2245,15 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
        let canShowSummaryBoxPointer = this._trayState == State.SHOWN;
 | 
			
		||||
        // We only have sources with empty notification stacks for legacy tray icons. Currently, we never attempt
 | 
			
		||||
        // to show notifications for legacy tray icons, but this would be necessary if we did.
 | 
			
		||||
        let requestedNotificationStackIsEmpty = (this._clickedSummaryItemMouseButton == 1 && this._clickedSummaryItem.source.notifications.length == 0);
 | 
			
		||||
        let wrongSummaryNotificationStack = (this._clickedSummaryItemMouseButton == 1 &&
 | 
			
		||||
        let requestedNotificationStackIsEmpty = (haveClickedSummaryItem &&
 | 
			
		||||
                                                 this._clickedSummaryItemMouseButton == 1 &&
 | 
			
		||||
                                                 this._clickedSummaryItem.source.notifications.length == 0);
 | 
			
		||||
        let wrongSummaryNotificationStack = (haveClickedSummaryItem &&
 | 
			
		||||
                                             this._clickedSummaryItemMouseButton == 1 &&
 | 
			
		||||
                                             this._summaryBoxPointer.bin.child != this._clickedSummaryItem.notificationStackWidget);
 | 
			
		||||
        let wrongSummaryRightClickMenu = (this._clickedSummaryItemMouseButton == 3 &&
 | 
			
		||||
        let wrongSummaryRightClickMenu = (haveClickedSummaryItem &&
 | 
			
		||||
                                          this._clickedSummaryItemMouseButton == 3 &&
 | 
			
		||||
                                          this._clickedSummaryItem.rightClickMenu != null &&
 | 
			
		||||
                                          this._summaryBoxPointer.bin.child != this._clickedSummaryItem.rightClickMenu);
 | 
			
		||||
        let wrongSummaryBoxPointer = (haveClickedSummaryItem &&
 | 
			
		||||
                                      (wrongSummaryNotificationStack || wrongSummaryRightClickMenu));
 | 
			
		||||
@@ -2257,7 +2262,7 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
            if (haveClickedSummaryItem && !summarySourceIsMainNotificationSource && canShowSummaryBoxPointer && !requestedNotificationStackIsEmpty)
 | 
			
		||||
                this._showSummaryBoxPointer();
 | 
			
		||||
        } else if (this._summaryBoxPointerState == State.SHOWN) {
 | 
			
		||||
            if (!haveClickedSummaryItem || !canShowSummaryBoxPointer || wrongSummaryBoxPointer || mustHideTray) {
 | 
			
		||||
            if (!haveClickedSummaryItem || !canShowSummaryBoxPointer || wrongSummaryBoxPointer || !hasNotifications) {
 | 
			
		||||
                this._hideSummaryBoxPointer();
 | 
			
		||||
                if (wrongSummaryBoxPointer)
 | 
			
		||||
                    this._showSummaryBoxPointer();
 | 
			
		||||
@@ -2267,7 +2272,7 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
        // Tray itself
 | 
			
		||||
        let trayIsVisible = (this._trayState == State.SHOWING ||
 | 
			
		||||
                             this._trayState == State.SHOWN);
 | 
			
		||||
        let trayShouldBeVisible = this._traySummoned && !this._keyboardVisible && !mustHideTray;
 | 
			
		||||
        let trayShouldBeVisible = this._traySummoned && !this._keyboardVisible && hasNotifications;
 | 
			
		||||
        if (!trayIsVisible && trayShouldBeVisible)
 | 
			
		||||
            trayShouldBeVisible = this._showTray();
 | 
			
		||||
        else if (trayIsVisible && !trayShouldBeVisible)
 | 
			
		||||
@@ -2324,7 +2329,8 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
                      transition: 'easeOutQuad'
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
        this._lightbox.show();
 | 
			
		||||
        for (let i = 0; i < this._lightboxes.length; i++)
 | 
			
		||||
            this._lightboxes[i].show();
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
@@ -2347,7 +2353,7 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        if (this._desktopClone)
 | 
			
		||||
            this._desktopClone.destroy();
 | 
			
		||||
        let cloneSource = Main.overview.visible ? global.overlay_group : global.window_group;
 | 
			
		||||
        let cloneSource = Main.overview.visible ? Main.layoutManager.overviewGroup : global.window_group;
 | 
			
		||||
        this._desktopClone = new Clutter.Clone({ source: cloneSource,
 | 
			
		||||
                                                 clip: new Clutter.Geometry(this._bottomMonitorGeometry) });
 | 
			
		||||
        Main.uiGroup.insert_child_above(this._desktopClone, cloneSource);
 | 
			
		||||
@@ -2379,7 +2385,8 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
        // which would happen if GrabHelper ungrabbed for us.
 | 
			
		||||
        // This is a no-op in that case.
 | 
			
		||||
        this._grabHelper.ungrab({ actor: this.actor });
 | 
			
		||||
        this._lightbox.hide();
 | 
			
		||||
        for (let i = 0; i < this._lightboxes.length; i++)
 | 
			
		||||
            this._lightboxes[i].hide();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _hideDesktopClone: function() {
 | 
			
		||||
@@ -2428,7 +2435,7 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
        let [x, y, mods] = global.get_pointer();
 | 
			
		||||
        // We save the position of the mouse at the time when we started showing the notification
 | 
			
		||||
        // in order to determine if the notification popped up under it. We make that check if
 | 
			
		||||
        // the user starts moving the mouse and _onTrayHoverChanged() gets called. We don't
 | 
			
		||||
        // the user starts moving the mouse and _onNotificationHoverChanged() gets called. We don't
 | 
			
		||||
        // expand the notification if it just happened to pop up under the mouse unless the user
 | 
			
		||||
        // explicitly mouses away from it and then mouses back in.
 | 
			
		||||
        this._showNotificationMouseX = x;
 | 
			
		||||
@@ -2490,13 +2497,13 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _notificationTimeout: function() {
 | 
			
		||||
        let [x, y, mods] = global.get_pointer();
 | 
			
		||||
        if (y > this._lastSeenMouseY + 10 && !this.actor.hover) {
 | 
			
		||||
        if (y > this._lastSeenMouseY + 10 && !this._notificationHovered) {
 | 
			
		||||
            // The mouse is moving towards the notification, so don't
 | 
			
		||||
            // hide it yet. (We just create a new timeout (and destroy
 | 
			
		||||
            // the old one) each time because the bookkeeping is
 | 
			
		||||
            // simpler.)
 | 
			
		||||
            this._updateNotificationTimeout(1000);
 | 
			
		||||
        } else if (this._useLongerTrayLeftTimeout && !this._trayLeftTimeoutId &&
 | 
			
		||||
        } else if (this._useLongerNotificationLeftTimeout && !this._notificationLeftTimeoutId &&
 | 
			
		||||
                  (x != this._lastSeenMouseX || y != this._lastSeenMouseY)) {
 | 
			
		||||
            // Refresh the timeout if the notification originally
 | 
			
		||||
            // popped up under the pointer, and the pointer is hovering
 | 
			
		||||
@@ -2540,12 +2547,12 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
            this._notificationUnfocusedId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._useLongerTrayLeftTimeout = false;
 | 
			
		||||
        if (this._trayLeftTimeoutId) {
 | 
			
		||||
            Mainloop.source_remove(this._trayLeftTimeoutId);
 | 
			
		||||
            this._trayLeftTimeoutId = 0;
 | 
			
		||||
            this._trayLeftMouseX = -1;
 | 
			
		||||
            this._trayLeftMouseY = -1;
 | 
			
		||||
        this._useLongerNotificationLeftTimeout = false;
 | 
			
		||||
        if (this._notificationLeftTimeoutId) {
 | 
			
		||||
            Mainloop.source_remove(this._notificationLeftTimeoutId);
 | 
			
		||||
            this._notificationLeftTimeoutId = 0;
 | 
			
		||||
            this._notificationLeftMouseX = -1;
 | 
			
		||||
            this._notificationLeftMouseY = -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._notificationRemoved) {
 | 
			
		||||
@@ -2575,14 +2582,9 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
        if (notification.isTransient)
 | 
			
		||||
            notification.destroy(NotificationDestroyedReason.EXPIRED);
 | 
			
		||||
 | 
			
		||||
        this._notificationRemoved = false;
 | 
			
		||||
        this._closeButton.hide();
 | 
			
		||||
        this._pointerInTray = false;
 | 
			
		||||
 | 
			
		||||
        // Clutter will send a leave-event the next time the mouse
 | 
			
		||||
        // moves, but we need to set this here now to update the
 | 
			
		||||
        // state machine.
 | 
			
		||||
        this.actor.hover = false;
 | 
			
		||||
        this._pointerInNotification = false;
 | 
			
		||||
        this._notificationRemoved = false;
 | 
			
		||||
        this._notificationBin.child = null;
 | 
			
		||||
        this._notificationWidget.hide();
 | 
			
		||||
    },
 | 
			
		||||
@@ -2642,38 +2644,37 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showSummaryBoxPointer: function() {
 | 
			
		||||
        this._summaryBoxPointerItem = this._clickedSummaryItem;
 | 
			
		||||
        let child;
 | 
			
		||||
        let summaryItem = this._clickedSummaryItem;
 | 
			
		||||
        if (this._clickedSummaryItemMouseButton == 1) {
 | 
			
		||||
            // Acknowledge all our notifications
 | 
			
		||||
            summaryItem.source.notifications.forEach(function(n) { n.acknowledged = true; });
 | 
			
		||||
 | 
			
		||||
            child = summaryItem.notificationStackWidget;
 | 
			
		||||
 | 
			
		||||
            let closeButton = summaryItem.closeButton;
 | 
			
		||||
            closeButton.show();
 | 
			
		||||
            this._summaryBoxPointerCloseClickedId = closeButton.connect('clicked', Lang.bind(this, this._hideSummaryBoxPointer));
 | 
			
		||||
            summaryItem.prepareNotificationStackForShowing();
 | 
			
		||||
        } else if (this._clickedSummaryItemMouseButton == 3) {
 | 
			
		||||
            child = summaryItem.rightClickMenu;
 | 
			
		||||
            this._summaryBoxPointerCloseClickedId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If the user clicked the middle mouse button, or the item
 | 
			
		||||
        // doesn't have a right-click menu, do nothing.
 | 
			
		||||
        if (!child)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._summaryBoxPointerItem = summaryItem;
 | 
			
		||||
        this._summaryBoxPointerContentUpdatedId = this._summaryBoxPointerItem.connect('content-updated',
 | 
			
		||||
                                                                                      Lang.bind(this, this._onSummaryBoxPointerContentUpdated));
 | 
			
		||||
        this._sourceDoneDisplayingId = this._summaryBoxPointerItem.source.connect('done-displaying-content',
 | 
			
		||||
                                                                                  Lang.bind(this, this._onSourceDoneDisplayingContent));
 | 
			
		||||
 | 
			
		||||
        let hasRightClickMenu = this._summaryBoxPointerItem.rightClickMenu != null;
 | 
			
		||||
        if (this._clickedSummaryItemMouseButton == 1 || !hasRightClickMenu) {
 | 
			
		||||
            let newQueue = [];
 | 
			
		||||
            for (let i = 0; i < this._notificationQueue.length; i++) {
 | 
			
		||||
                let notification = this._notificationQueue[i];
 | 
			
		||||
                let sameSource = this._summaryBoxPointerItem.source == notification.source;
 | 
			
		||||
                if (sameSource)
 | 
			
		||||
                    notification.acknowledged = true;
 | 
			
		||||
                else
 | 
			
		||||
                    newQueue.push(notification);
 | 
			
		||||
            }
 | 
			
		||||
            this._notificationQueue = newQueue;
 | 
			
		||||
 | 
			
		||||
            this._summaryBoxPointer.bin.child = this._summaryBoxPointerItem.notificationStackWidget;
 | 
			
		||||
 | 
			
		||||
            let closeButton = this._summaryBoxPointerItem.closeButton;
 | 
			
		||||
            closeButton.show();
 | 
			
		||||
            this._summaryBoxPointerCloseClickedId = closeButton.connect('clicked', Lang.bind(this, this._hideSummaryBoxPointer));
 | 
			
		||||
            this._summaryBoxPointerItem.prepareNotificationStackForShowing();
 | 
			
		||||
        } else if (this._clickedSummaryItemMouseButton == 3) {
 | 
			
		||||
            this._summaryBoxPointer.bin.child = this._clickedSummaryItem.rightClickMenu;
 | 
			
		||||
            this._summaryBoxPointerCloseClickedId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._summaryBoxPointer.bin.child = child;
 | 
			
		||||
        this._grabHelper.grab({ actor: this._summaryBoxPointer.bin.child,
 | 
			
		||||
                                grabFocus: true,
 | 
			
		||||
                                modal: true,
 | 
			
		||||
                                onUngrab: Lang.bind(this, this._onSummaryBoxPointerUngrabbed) });
 | 
			
		||||
 | 
			
		||||
        this._summaryBoxPointer.actor.opacity = 0;
 | 
			
		||||
@@ -2782,17 +2783,14 @@ const MessageTray = new Lang.Class({
 | 
			
		||||
        this._summaryBoxPointerState = State.HIDDEN;
 | 
			
		||||
        this._summaryBoxPointer.bin.child = null;
 | 
			
		||||
 | 
			
		||||
        let sourceNotificationStackDoneShowing = null;
 | 
			
		||||
        if (doneShowingNotificationStack) {
 | 
			
		||||
            let source = this._summaryBoxPointerItem.source;
 | 
			
		||||
 | 
			
		||||
            this._summaryBoxPointerItem.doneShowingNotificationStack();
 | 
			
		||||
            sourceNotificationStackDoneShowing = this._summaryBoxPointerItem.source;
 | 
			
		||||
        }
 | 
			
		||||
            this._summaryBoxPointerItem = null;
 | 
			
		||||
 | 
			
		||||
        this._summaryBoxPointerItem = null;
 | 
			
		||||
 | 
			
		||||
        if (sourceNotificationStackDoneShowing) {
 | 
			
		||||
            if (sourceNotificationStackDoneShowing.isTransient && !this._reNotifyAfterHideNotification)
 | 
			
		||||
                sourceNotificationStackDoneShowing.destroy(NotificationDestroyedReason.EXPIRED);
 | 
			
		||||
            if (source.isTransient && !this._reNotifyAfterHideNotification)
 | 
			
		||||
                source.destroy(NotificationDestroyedReason.EXPIRED);
 | 
			
		||||
            if (this._reNotifyAfterHideNotification) {
 | 
			
		||||
                this._onNotify(this._reNotifyAfterHideNotification.source, this._reNotifyAfterHideNotification);
 | 
			
		||||
                this._reNotifyAfterHideNotification = null;
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@ const Atk = imports.gi.Atk;
 | 
			
		||||
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
 | 
			
		||||
const Animation = imports.ui.animation;
 | 
			
		||||
const Layout = imports.ui.layout;
 | 
			
		||||
const Lightbox = imports.ui.lightbox;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
@@ -22,6 +23,10 @@ const Tweener = imports.ui.tweener;
 | 
			
		||||
const OPEN_AND_CLOSE_TIME = 0.1;
 | 
			
		||||
const FADE_OUT_DIALOG_TIME = 1.0;
 | 
			
		||||
 | 
			
		||||
const WORK_SPINNER_ICON_SIZE = 24;
 | 
			
		||||
const WORK_SPINNER_ANIMATION_DELAY = 1.0;
 | 
			
		||||
const WORK_SPINNER_ANIMATION_TIME = 0.3;
 | 
			
		||||
 | 
			
		||||
const State = {
 | 
			
		||||
    OPENED: 0,
 | 
			
		||||
    CLOSED: 1,
 | 
			
		||||
@@ -65,7 +70,9 @@ const ModalDialog = new Lang.Class({
 | 
			
		||||
        this._group.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
 | 
			
		||||
        this._group.connect('key-release-event', Lang.bind(this, this._onKeyReleaseEvent));
 | 
			
		||||
 | 
			
		||||
        this._backgroundBin = new St.Bin();
 | 
			
		||||
        this.backgroundStack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
 | 
			
		||||
        this._backgroundBin = new St.Bin({ child: this.backgroundStack,
 | 
			
		||||
                                           x_fill: true, y_fill: true });
 | 
			
		||||
        this._monitorConstraint = new Layout.MonitorConstraint();
 | 
			
		||||
        this._backgroundBin.add_constraint(this._monitorConstraint);
 | 
			
		||||
        this._group.add_actor(this._backgroundBin);
 | 
			
		||||
@@ -81,15 +88,10 @@ const ModalDialog = new Lang.Class({
 | 
			
		||||
                                                   { inhibitEvents: true });
 | 
			
		||||
            this._lightbox.highlight(this._backgroundBin);
 | 
			
		||||
 | 
			
		||||
            let stack = new Shell.Stack();
 | 
			
		||||
            this._backgroundBin.child = stack;
 | 
			
		||||
 | 
			
		||||
            this._eventBlocker = new Clutter.Actor({ reactive: true });
 | 
			
		||||
            stack.add_actor(this._eventBlocker);
 | 
			
		||||
            stack.add_actor(this.dialogLayout);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._backgroundBin.child = this.dialogLayout;
 | 
			
		||||
            this.backgroundStack.add_actor(this._eventBlocker);
 | 
			
		||||
        }
 | 
			
		||||
        this.backgroundStack.add_actor(this.dialogLayout);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        this.contentLayout = new St.BoxLayout({ vertical: true });
 | 
			
		||||
@@ -110,6 +112,8 @@ const ModalDialog = new Lang.Class({
 | 
			
		||||
        this._initialKeyFocus = this.dialogLayout;
 | 
			
		||||
        this._initialKeyFocusDestroyId = 0;
 | 
			
		||||
        this._savedKeyFocus = null;
 | 
			
		||||
 | 
			
		||||
        this._workSpinner = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
@@ -183,6 +187,42 @@ const ModalDialog = new Lang.Class({
 | 
			
		||||
        return button;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    placeSpinner: function(layoutInfo) {
 | 
			
		||||
        let spinnerIcon = global.datadir + '/theme/process-working.svg';
 | 
			
		||||
        this._workSpinner = new Animation.AnimatedIcon(spinnerIcon, WORK_SPINNER_ICON_SIZE);
 | 
			
		||||
        this._workSpinner.actor.opacity = 0;
 | 
			
		||||
        this._workSpinner.actor.show();
 | 
			
		||||
 | 
			
		||||
        this.buttonLayout.add(this._workSpinner.actor, layoutInfo);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setWorking: function(working) {
 | 
			
		||||
        if (!this._workSpinner)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Tweener.removeTweens(this._workSpinner.actor);
 | 
			
		||||
        if (working) {
 | 
			
		||||
            this._workSpinner.play();
 | 
			
		||||
            Tweener.addTween(this._workSpinner.actor,
 | 
			
		||||
                             { opacity: 255,
 | 
			
		||||
                               delay: WORK_SPINNER_ANIMATION_DELAY,
 | 
			
		||||
                               time: WORK_SPINNER_ANIMATION_TIME,
 | 
			
		||||
                               transition: 'linear'
 | 
			
		||||
                             });
 | 
			
		||||
        } else {
 | 
			
		||||
            Tweener.addTween(this._workSpinner.actor,
 | 
			
		||||
                             { opacity: 0,
 | 
			
		||||
                               time: WORK_SPINNER_ANIMATION_TIME,
 | 
			
		||||
                               transition: 'linear',
 | 
			
		||||
                               onCompleteScope: this,
 | 
			
		||||
                               onComplete: function() {
 | 
			
		||||
                                   if (this._workSpinner)
 | 
			
		||||
                                       this._workSpinner.stop();
 | 
			
		||||
                               }
 | 
			
		||||
                             });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeyPressEvent: function(object, event) {
 | 
			
		||||
        this._pressedKey = event.get_key_symbol();
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ const Layout = imports.ui.layout;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
 | 
			
		||||
const HIDE_TIMEOUT = 1500;
 | 
			
		||||
const FADE_TIME = 0.1;
 | 
			
		||||
@@ -71,6 +72,7 @@ const OsdWindow = new Lang.Class({
 | 
			
		||||
    Name: 'OsdWindow',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._popupSize = 0;
 | 
			
		||||
        this.actor = new St.Widget({ x_expand: true,
 | 
			
		||||
                                     y_expand: true,
 | 
			
		||||
                                     x_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
@@ -80,6 +82,15 @@ const OsdWindow = new Lang.Class({
 | 
			
		||||
                                       vertical: true });
 | 
			
		||||
        this.actor.add_actor(this._box);
 | 
			
		||||
 | 
			
		||||
        this._box.connect('style-changed', Lang.bind(this, this._onStyleChanged));
 | 
			
		||||
        this._box.connect('notify::height', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
                Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
 | 
			
		||||
                    function() {
 | 
			
		||||
                        this._box.width = this._box.height;
 | 
			
		||||
                    }));
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        this._icon = new St.Icon();
 | 
			
		||||
        this._box.add(this._icon, { expand: true });
 | 
			
		||||
 | 
			
		||||
@@ -96,7 +107,7 @@ const OsdWindow = new Lang.Class({
 | 
			
		||||
                                   Lang.bind(this, this._monitorsChanged));
 | 
			
		||||
        this._monitorsChanged();
 | 
			
		||||
 | 
			
		||||
        Main.layoutManager.addChrome(this.actor, { affectsInputRegion: false });
 | 
			
		||||
        Main.uiGroup.add_child(this.actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setIcon: function(icon) {
 | 
			
		||||
@@ -169,11 +180,25 @@ const OsdWindow = new Lang.Class({
 | 
			
		||||
        let scalew = monitor.width / 640.0;
 | 
			
		||||
        let scaleh = monitor.height / 480.0;
 | 
			
		||||
        let scale = Math.min(scalew, scaleh);
 | 
			
		||||
        let size = 110 * Math.max(1, scale);
 | 
			
		||||
        this._popupSize = 110 * Math.max(1, scale);
 | 
			
		||||
 | 
			
		||||
        this._box.set_size(size, size);
 | 
			
		||||
        this._box.translation_y = monitor.height / 4;
 | 
			
		||||
        this._icon.icon_size = this._popupSize / 2;
 | 
			
		||||
        this._box.style_changed();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
        this._icon.icon_size = size / 2;
 | 
			
		||||
    _onStyleChanged: function() {
 | 
			
		||||
        let themeNode = this._box.get_theme_node();
 | 
			
		||||
        let horizontalPadding = themeNode.get_horizontal_padding();
 | 
			
		||||
        let verticalPadding = themeNode.get_vertical_padding();
 | 
			
		||||
        let topBorder = themeNode.get_border_width(St.Side.TOP);
 | 
			
		||||
        let bottomBorder = themeNode.get_border_width(St.Side.BOTTOM);
 | 
			
		||||
        let leftBorder = themeNode.get_border_width(St.Side.LEFT);
 | 
			
		||||
        let rightBorder = themeNode.get_border_width(St.Side.RIGHT);
 | 
			
		||||
 | 
			
		||||
        let minWidth = this._popupSize - verticalPadding - leftBorder - rightBorder;
 | 
			
		||||
        let minHeight = this._popupSize - horizontalPadding - topBorder - bottomBorder;
 | 
			
		||||
 | 
			
		||||
        this._box.style = 'min-height: %dpx;'.format(Math.max(minWidth, minHeight));
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,6 @@ const Shell = imports.gi.Shell;
 | 
			
		||||
const Gdk = imports.gi.Gdk;
 | 
			
		||||
 | 
			
		||||
const Background = imports.ui.background;
 | 
			
		||||
const Dash = imports.ui.dash;
 | 
			
		||||
const DND = imports.ui.dnd;
 | 
			
		||||
const LayoutManager = imports.ui.layout;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
@@ -20,7 +19,6 @@ const OverviewControls = imports.ui.overviewControls;
 | 
			
		||||
const Panel = imports.ui.panel;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const ViewSelector = imports.ui.viewSelector;
 | 
			
		||||
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
 | 
			
		||||
 | 
			
		||||
// Time for initial animation going into Overview mode
 | 
			
		||||
@@ -31,7 +29,7 @@ const ANIMATION_TIME = 0.25;
 | 
			
		||||
// and don't want the shading animation to get cut off
 | 
			
		||||
const SHADE_ANIMATION_TIME = .20;
 | 
			
		||||
 | 
			
		||||
const DND_WINDOW_SWITCH_TIMEOUT = 1250;
 | 
			
		||||
const DND_WINDOW_SWITCH_TIMEOUT = 750;
 | 
			
		||||
 | 
			
		||||
const OVERVIEW_ACTIVATION_TIMEOUT = 0.5;
 | 
			
		||||
 | 
			
		||||
@@ -117,7 +115,7 @@ const Overview = new Lang.Class({
 | 
			
		||||
        let monitor = Main.layoutManager.primaryMonitor;
 | 
			
		||||
 | 
			
		||||
        this._desktopFade = new St.Bin();
 | 
			
		||||
        global.overlay_group.add_actor(this._desktopFade);
 | 
			
		||||
        Main.layoutManager.overviewGroup.add_child(this._desktopFade);
 | 
			
		||||
 | 
			
		||||
        let layout = new Clutter.BinLayout();
 | 
			
		||||
        this._stack = new Clutter.Actor({ layout_manager: layout });
 | 
			
		||||
@@ -133,17 +131,8 @@ const Overview = new Lang.Class({
 | 
			
		||||
                                            y_expand: true });
 | 
			
		||||
        this._overview._delegate = this;
 | 
			
		||||
 | 
			
		||||
        this._groupStack = new St.Widget({ layout_manager: new Clutter.BinLayout(),
 | 
			
		||||
                                           x_expand: true, y_expand: true,
 | 
			
		||||
                                           clip_to_allocation: true });
 | 
			
		||||
        this._group = new St.BoxLayout({ name: 'overview-group',
 | 
			
		||||
                                         reactive: true,
 | 
			
		||||
                                         x_expand: true, y_expand: true });
 | 
			
		||||
        this._groupStack.add_actor(this._group);
 | 
			
		||||
 | 
			
		||||
        this._backgroundGroup = new Meta.BackgroundGroup();
 | 
			
		||||
        global.overlay_group.add_child(this._backgroundGroup);
 | 
			
		||||
        this._backgroundGroup.hide();
 | 
			
		||||
        Main.layoutManager.overviewGroup.add_child(this._backgroundGroup);
 | 
			
		||||
        this._bgManagers = [];
 | 
			
		||||
 | 
			
		||||
        this._activationTime = 0;
 | 
			
		||||
@@ -157,14 +146,13 @@ const Overview = new Lang.Class({
 | 
			
		||||
        // During transitions, we raise this to the top to avoid having the overview
 | 
			
		||||
        // area be reactive; it causes too many issues such as double clicks on
 | 
			
		||||
        // Dash elements, or mouseover handlers in the workspaces.
 | 
			
		||||
        this._coverPane = new Clutter.Rectangle({ opacity: 0,
 | 
			
		||||
                                                  reactive: true });
 | 
			
		||||
        this._coverPane = new Clutter.Actor({ opacity: 0,
 | 
			
		||||
                                              reactive: true });
 | 
			
		||||
        this._overview.add_actor(this._coverPane);
 | 
			
		||||
        this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return true; }));
 | 
			
		||||
 | 
			
		||||
        this._stack.hide();
 | 
			
		||||
        this._stack.add_actor(this._overview);
 | 
			
		||||
        global.overlay_group.add_actor(this._stack);
 | 
			
		||||
        Main.layoutManager.overviewGroup.add_child(this._stack);
 | 
			
		||||
 | 
			
		||||
        this._coverPane.hide();
 | 
			
		||||
 | 
			
		||||
@@ -177,7 +165,6 @@ const Overview = new Lang.Class({
 | 
			
		||||
        Main.xdndHandler.connect('drag-end', Lang.bind(this, this._onDragEnd));
 | 
			
		||||
 | 
			
		||||
        global.screen.connect('restacked', Lang.bind(this, this._onRestacked));
 | 
			
		||||
        this._group.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
 | 
			
		||||
 | 
			
		||||
        this._windowSwitchTimeoutId = 0;
 | 
			
		||||
        this._windowSwitchTimestamp = 0;
 | 
			
		||||
@@ -276,28 +263,13 @@ const Overview = new Lang.Class({
 | 
			
		||||
        this._overview.add_actor(this._searchEntryBin);
 | 
			
		||||
 | 
			
		||||
        // Create controls
 | 
			
		||||
        this._dash = new Dash.Dash();
 | 
			
		||||
        this._viewSelector = new ViewSelector.ViewSelector(this._searchEntry,
 | 
			
		||||
                                                           this._dash.showAppsButton);
 | 
			
		||||
        this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
 | 
			
		||||
        this._controls = new OverviewControls.ControlsManager(this._dash,
 | 
			
		||||
                                                              this._thumbnailsBox,
 | 
			
		||||
                                                              this._viewSelector);
 | 
			
		||||
 | 
			
		||||
        this._controls.dashActor.x_align = Clutter.ActorAlign.START;
 | 
			
		||||
        this._controls.dashActor.y_expand = true;
 | 
			
		||||
 | 
			
		||||
        // Put the dash in a separate layer to allow content to be centered
 | 
			
		||||
        this._groupStack.add_actor(this._controls.dashActor);
 | 
			
		||||
 | 
			
		||||
        // Pack all the actors into the group
 | 
			
		||||
        this._group.add_actor(this._controls.dashSpacer);
 | 
			
		||||
        this._group.add(this._viewSelector.actor, { x_fill: true,
 | 
			
		||||
                                                    expand: true });
 | 
			
		||||
        this._group.add_actor(this._controls.thumbnailsActor);
 | 
			
		||||
        this._controls = new OverviewControls.ControlsManager(this._searchEntry);
 | 
			
		||||
        this._dash = this._controls.dash;
 | 
			
		||||
        this._viewSelector = this._controls.viewSelector;
 | 
			
		||||
 | 
			
		||||
        // Add our same-line elements after the search entry
 | 
			
		||||
        this._overview.add(this._groupStack, { y_fill: true, expand: true });
 | 
			
		||||
        this._overview.add(this._controls.actor, { y_fill: true, expand: true });
 | 
			
		||||
        this._controls.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
 | 
			
		||||
 | 
			
		||||
        this._stack.add_actor(this._controls.indicatorActor);
 | 
			
		||||
 | 
			
		||||
@@ -461,6 +433,7 @@ const Overview = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    beginItemDrag: function(source) {
 | 
			
		||||
        this.emit('item-drag-begin');
 | 
			
		||||
        this._inDrag = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    cancelledItemDrag: function(source) {
 | 
			
		||||
@@ -469,10 +442,12 @@ const Overview = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    endItemDrag: function(source) {
 | 
			
		||||
        this.emit('item-drag-end');
 | 
			
		||||
        this._inDrag = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    beginWindowDrag: function(source) {
 | 
			
		||||
        this.emit('window-drag-begin');
 | 
			
		||||
        this._inDrag = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    cancelledWindowDrag: function(source) {
 | 
			
		||||
@@ -481,24 +456,31 @@ const Overview = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    endWindowDrag: function(source) {
 | 
			
		||||
        this.emit('window-drag-end');
 | 
			
		||||
        this._inDrag = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // show:
 | 
			
		||||
    //
 | 
			
		||||
    // Animates the overview visible and grabs mouse and keyboard input
 | 
			
		||||
    show : function() {
 | 
			
		||||
    show: function() {
 | 
			
		||||
        if (this.isDummy)
 | 
			
		||||
            return;
 | 
			
		||||
        if (this._shown)
 | 
			
		||||
            return;
 | 
			
		||||
        this._shown = true;
 | 
			
		||||
 | 
			
		||||
        if (!this._syncInputMode())
 | 
			
		||||
        if (!this._syncGrab())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Main.layoutManager.showOverview();
 | 
			
		||||
        this._animateVisible();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    focusSearch: function() {
 | 
			
		||||
        this.show();
 | 
			
		||||
        this._searchEntry.grab_key_focus();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    fadeInDesktop: function() {
 | 
			
		||||
            this._desktopFade.opacity = 0;
 | 
			
		||||
            this._desktopFade.show();
 | 
			
		||||
@@ -540,8 +522,6 @@ const Overview = new Lang.Class({
 | 
			
		||||
        //
 | 
			
		||||
        // Disable unredirection while in the overview
 | 
			
		||||
        Meta.disable_unredirect_for_screen(global.screen);
 | 
			
		||||
        this._stack.show();
 | 
			
		||||
        this._backgroundGroup.show();
 | 
			
		||||
        this._viewSelector.show();
 | 
			
		||||
 | 
			
		||||
        this._stack.opacity = 0;
 | 
			
		||||
@@ -582,7 +562,7 @@ const Overview = new Lang.Class({
 | 
			
		||||
        this._animateNotVisible();
 | 
			
		||||
 | 
			
		||||
        this._shown = false;
 | 
			
		||||
        this._syncInputMode();
 | 
			
		||||
        this._syncGrab();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    toggle: function() {
 | 
			
		||||
@@ -604,6 +584,8 @@ const Overview = new Lang.Class({
 | 
			
		||||
    shouldToggleByCornerOrButton: function() {
 | 
			
		||||
        if (this.animationInProgress)
 | 
			
		||||
            return false;
 | 
			
		||||
        if (this._inDrag)
 | 
			
		||||
            return false;
 | 
			
		||||
        if (this._activationTime == 0 || Date.now() / 1000 - this._activationTime > OVERVIEW_ACTIVATION_TIMEOUT)
 | 
			
		||||
            return true;
 | 
			
		||||
        return false;
 | 
			
		||||
@@ -611,8 +593,8 @@ const Overview = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    //// Private methods ////
 | 
			
		||||
 | 
			
		||||
    _syncInputMode: function() {
 | 
			
		||||
        // We delay input mode changes during animation so that when removing the
 | 
			
		||||
    _syncGrab: function() {
 | 
			
		||||
        // We delay grab changes during animation so that when removing the
 | 
			
		||||
        // overview we don't have a problem with the release of a press/release
 | 
			
		||||
        // going to an application.
 | 
			
		||||
        if (this.animationInProgress)
 | 
			
		||||
@@ -630,16 +612,12 @@ const Overview = new Lang.Class({
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if (this._modal) {
 | 
			
		||||
                Main.popModal(this._overview);
 | 
			
		||||
                this._modal = false;
 | 
			
		||||
            }
 | 
			
		||||
            else if (global.stage_input_mode == Shell.StageInputMode.FULLSCREEN)
 | 
			
		||||
                global.stage_input_mode = Shell.StageInputMode.NORMAL;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
@@ -678,7 +656,7 @@ const Overview = new Lang.Class({
 | 
			
		||||
        if (!this._shown)
 | 
			
		||||
            this._animateNotVisible();
 | 
			
		||||
 | 
			
		||||
        this._syncInputMode();
 | 
			
		||||
        this._syncGrab();
 | 
			
		||||
        global.sync_pointer();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -688,20 +666,19 @@ const Overview = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._viewSelector.hide();
 | 
			
		||||
        this._desktopFade.hide();
 | 
			
		||||
        this._backgroundGroup.hide();
 | 
			
		||||
        this._stack.hide();
 | 
			
		||||
        this._coverPane.hide();
 | 
			
		||||
 | 
			
		||||
        this.visible = false;
 | 
			
		||||
        this.animationInProgress = false;
 | 
			
		||||
 | 
			
		||||
        this._coverPane.hide();
 | 
			
		||||
 | 
			
		||||
        this.emit('hidden');
 | 
			
		||||
        // Handle any calls to show* while we were hiding
 | 
			
		||||
        if (this._shown)
 | 
			
		||||
            this._animateVisible();
 | 
			
		||||
        else
 | 
			
		||||
            Main.layoutManager.hideOverview();
 | 
			
		||||
 | 
			
		||||
        this._syncInputMode();
 | 
			
		||||
        this._syncGrab();
 | 
			
		||||
 | 
			
		||||
        // Fake a pointer event if requested
 | 
			
		||||
        if (this._needsFakePointerEvent) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,18 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const GObject = imports.gi.GObject;
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
 | 
			
		||||
const Dash = imports.ui.dash;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const ViewSelector = imports.ui.viewSelector;
 | 
			
		||||
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
 | 
			
		||||
 | 
			
		||||
const SIDE_CONTROLS_ANIMATION_TIME = 0.16;
 | 
			
		||||
 | 
			
		||||
@@ -244,6 +247,7 @@ const ThumbnailsSlider = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        Main.layoutManager.connect('monitors-changed', Lang.bind(this, this.updateSlide));
 | 
			
		||||
        this.actor.connect('notify::hover', Lang.bind(this, this.updateSlide));
 | 
			
		||||
        this._thumbnailsBox.actor.bind_property('visible', this.actor, 'visible', GObject.BindingFlags.SYNC_CREATE);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getAlwaysZoomOut: function() {
 | 
			
		||||
@@ -269,6 +273,11 @@ const ThumbnailsSlider = new Lang.Class({
 | 
			
		||||
        return alwaysZoomOut;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getNonExpandedWidth: function() {
 | 
			
		||||
        let child = this.actor.get_first_child();
 | 
			
		||||
        return child.get_theme_node().get_length('visible-width');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getSlide: function() {
 | 
			
		||||
        if (!this.visible)
 | 
			
		||||
            return 0;
 | 
			
		||||
@@ -280,18 +289,16 @@ const ThumbnailsSlider = new Lang.Class({
 | 
			
		||||
        let child = this.actor.get_first_child();
 | 
			
		||||
        let preferredHeight = child.get_preferred_height(-1)[1];
 | 
			
		||||
        let expandedWidth = child.get_preferred_width(preferredHeight)[1];
 | 
			
		||||
        let visibleWidth = child.get_theme_node().get_length('visible-width');
 | 
			
		||||
 | 
			
		||||
        return visibleWidth / expandedWidth;
 | 
			
		||||
        return this.getNonExpandedWidth() / expandedWidth;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getVisibleWidth: function() {
 | 
			
		||||
        let alwaysZoomOut = this._getAlwaysZoomOut();
 | 
			
		||||
        if (alwaysZoomOut)
 | 
			
		||||
            return this.parent();
 | 
			
		||||
 | 
			
		||||
        let child = this.actor.get_first_child();
 | 
			
		||||
        return child.get_theme_node().get_length('visible-width');
 | 
			
		||||
        else
 | 
			
		||||
            return this.getNonExpandedWidth();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -309,6 +316,10 @@ const DashSlider = new Lang.Class({
 | 
			
		||||
        // available allocation
 | 
			
		||||
        this._dash.actor.x_expand = true;
 | 
			
		||||
        this._dash.actor.y_expand = true;
 | 
			
		||||
 | 
			
		||||
        this.actor.x_align = Clutter.ActorAlign.START;
 | 
			
		||||
        this.actor.y_expand = true;
 | 
			
		||||
 | 
			
		||||
        this.actor.add_actor(this._dash.actor);
 | 
			
		||||
 | 
			
		||||
        this._dash.connect('icon-size-changed', Lang.bind(this, this.updateSlide));
 | 
			
		||||
@@ -479,39 +490,77 @@ const MessagesIndicator = new Lang.Class({
 | 
			
		||||
const ControlsManager = new Lang.Class({
 | 
			
		||||
    Name: 'ControlsManager',
 | 
			
		||||
 | 
			
		||||
    _init: function(dash, thumbnails, viewSelector) {
 | 
			
		||||
        this._dashSlider = new DashSlider(dash);
 | 
			
		||||
        this.dashActor = this._dashSlider.actor;
 | 
			
		||||
        this.dashSpacer = new DashSpacer();
 | 
			
		||||
        this.dashSpacer.setDashActor(this.dashActor);
 | 
			
		||||
    _init: function(searchEntry) {
 | 
			
		||||
        this.dash = new Dash.Dash();
 | 
			
		||||
        this._dashSlider = new DashSlider(this.dash);
 | 
			
		||||
        this._dashSpacer = new DashSpacer();
 | 
			
		||||
        this._dashSpacer.setDashActor(this._dashSlider.actor);
 | 
			
		||||
 | 
			
		||||
        this._thumbnailsSlider = new ThumbnailsSlider(thumbnails);
 | 
			
		||||
        this.thumbnailsActor = this._thumbnailsSlider.actor;
 | 
			
		||||
        this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
 | 
			
		||||
        this._thumbnailsSlider = new ThumbnailsSlider(this._thumbnailsBox);
 | 
			
		||||
 | 
			
		||||
        this._indicator = new MessagesIndicator(viewSelector);
 | 
			
		||||
        this.viewSelector = new ViewSelector.ViewSelector(searchEntry,
 | 
			
		||||
                                                          this.dash.showAppsButton);
 | 
			
		||||
        this.viewSelector.connect('page-changed', Lang.bind(this, this._setVisibility));
 | 
			
		||||
        this.viewSelector.connect('page-empty', Lang.bind(this, this._onPageEmpty));
 | 
			
		||||
 | 
			
		||||
        this._indicator = new MessagesIndicator(this.viewSelector);
 | 
			
		||||
        this.indicatorActor = this._indicator.actor;
 | 
			
		||||
 | 
			
		||||
        this._viewSelector = viewSelector;
 | 
			
		||||
        this._viewSelector.connect('page-changed', Lang.bind(this, this._setVisibility));
 | 
			
		||||
        this._viewSelector.connect('page-empty', Lang.bind(this, this._onPageEmpty));
 | 
			
		||||
        this.actor = new St.Widget({ layout_manager: new Clutter.BinLayout(),
 | 
			
		||||
                                     reactive: true,
 | 
			
		||||
                                     x_expand: true, y_expand: true,
 | 
			
		||||
                                     clip_to_allocation: true });
 | 
			
		||||
        this._group = new St.BoxLayout({ name: 'overview-group',
 | 
			
		||||
                                        x_expand: true, y_expand: true });
 | 
			
		||||
        this.actor.add_actor(this._group);
 | 
			
		||||
 | 
			
		||||
        this.actor.add_actor(this._dashSlider.actor);
 | 
			
		||||
 | 
			
		||||
        this._group.add_actor(this._dashSpacer);
 | 
			
		||||
        this._group.add(this.viewSelector.actor, { x_fill: true,
 | 
			
		||||
                                                   expand: true });
 | 
			
		||||
        this._group.add_actor(this._thumbnailsSlider.actor);
 | 
			
		||||
 | 
			
		||||
        this._group.connect('notify::allocation', Lang.bind(this, this._updateWorkspacesGeometry));
 | 
			
		||||
 | 
			
		||||
        Main.overview.connect('showing', Lang.bind(this, this._updateSpacerVisibility));
 | 
			
		||||
        Main.overview.connect('item-drag-begin', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
                let activePage = this._viewSelector.getActivePage();
 | 
			
		||||
                let activePage = this.viewSelector.getActivePage();
 | 
			
		||||
                if (activePage != ViewSelector.ViewPage.WINDOWS)
 | 
			
		||||
                    this._viewSelector.fadeHalf();
 | 
			
		||||
                    this.viewSelector.fadeHalf();
 | 
			
		||||
            }));
 | 
			
		||||
        Main.overview.connect('item-drag-end', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
                this._viewSelector.fadeIn();
 | 
			
		||||
                this.viewSelector.fadeIn();
 | 
			
		||||
            }));
 | 
			
		||||
        Main.overview.connect('item-drag-cancelled', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
                this._viewSelector.fadeIn();
 | 
			
		||||
                this.viewSelector.fadeIn();
 | 
			
		||||
            }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateWorkspacesGeometry: function() {
 | 
			
		||||
        let [x, y] = this.actor.get_transformed_position();
 | 
			
		||||
        let [width, height] = this.actor.get_transformed_size();
 | 
			
		||||
        let geometry = { x: x, y: y, width: width, height: height };
 | 
			
		||||
 | 
			
		||||
        let spacing = this.actor.get_theme_node().get_length('spacing');
 | 
			
		||||
        let dashWidth = this._dashSlider.getVisibleWidth() + spacing;
 | 
			
		||||
        let thumbnailsWidth = this._thumbnailsSlider.getNonExpandedWidth() + spacing;
 | 
			
		||||
 | 
			
		||||
        geometry.width -= dashWidth;
 | 
			
		||||
        geometry.width -= thumbnailsWidth;
 | 
			
		||||
 | 
			
		||||
        if (this.actor.get_text_direction() == Clutter.TextDirection.LTR)
 | 
			
		||||
            geometry.x += dashWidth;
 | 
			
		||||
        else
 | 
			
		||||
            geometry.x += thumbnailsWidth;
 | 
			
		||||
 | 
			
		||||
        this.viewSelector.setWorkspacesFullGeometry(geometry);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setVisibility: function() {
 | 
			
		||||
        // Ignore the case when we're leaving the overview, since
 | 
			
		||||
        // actors will be made visible again when entering the overview
 | 
			
		||||
@@ -521,7 +570,7 @@ const ControlsManager = new Lang.Class({
 | 
			
		||||
            (Main.overview.animationInProgress && !Main.overview.visibleTarget))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let activePage = this._viewSelector.getActivePage();
 | 
			
		||||
        let activePage = this.viewSelector.getActivePage();
 | 
			
		||||
        let dashVisible = (activePage == ViewSelector.ViewPage.WINDOWS ||
 | 
			
		||||
                           activePage == ViewSelector.ViewPage.APPS);
 | 
			
		||||
        let thumbnailsVisible = (activePage == ViewSelector.ViewPage.WINDOWS);
 | 
			
		||||
@@ -541,8 +590,8 @@ const ControlsManager = new Lang.Class({
 | 
			
		||||
        if (Main.overview.animationInProgress && !Main.overview.visibleTarget)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let activePage = this._viewSelector.getActivePage();
 | 
			
		||||
        this.dashSpacer.visible = (activePage == ViewSelector.ViewPage.WINDOWS);
 | 
			
		||||
        let activePage = this.viewSelector.getActivePage();
 | 
			
		||||
        this._dashSpacer.visible = (activePage == ViewSelector.ViewPage.WINDOWS);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onPageEmpty: function() {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										149
									
								
								js/ui/panel.js
									
									
									
									
									
								
							
							
						
						
									
										149
									
								
								js/ui/panel.js
									
									
									
									
									
								
							@@ -15,12 +15,14 @@ const Signals = imports.signals;
 | 
			
		||||
const Atk = imports.gi.Atk;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const Animation = imports.ui.animation;
 | 
			
		||||
const Config = imports.misc.config;
 | 
			
		||||
const CtrlAltTab = imports.ui.ctrlAltTab;
 | 
			
		||||
const DND = imports.ui.dnd;
 | 
			
		||||
const Overview = imports.ui.overview;
 | 
			
		||||
const PopupMenu = imports.ui.popupMenu;
 | 
			
		||||
const PanelMenu = imports.ui.panelMenu;
 | 
			
		||||
const RemoteMenu = imports.ui.remoteMenu;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
@@ -28,7 +30,6 @@ const PANEL_ICON_SIZE = 24;
 | 
			
		||||
 | 
			
		||||
const BUTTON_DND_ACTIVATION_TIMEOUT = 250;
 | 
			
		||||
 | 
			
		||||
const ANIMATED_ICON_UPDATE_TIMEOUT = 100;
 | 
			
		||||
const SPINNER_ANIMATION_TIME = 0.2;
 | 
			
		||||
 | 
			
		||||
// To make sure the panel corners blend nicely with the panel,
 | 
			
		||||
@@ -74,81 +75,6 @@ function _unpremultiply(color) {
 | 
			
		||||
                               blue: blue, alpha: color.alpha });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const Animation = new Lang.Class({
 | 
			
		||||
    Name: 'Animation',
 | 
			
		||||
 | 
			
		||||
    _init: function(filename, width, height, speed) {
 | 
			
		||||
        this.actor = new St.Bin();
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 | 
			
		||||
        this._speed = speed;
 | 
			
		||||
 | 
			
		||||
        this._isLoaded = false;
 | 
			
		||||
        this._isPlaying = false;
 | 
			
		||||
        this._timeoutId = 0;
 | 
			
		||||
        this._frame = 0;
 | 
			
		||||
        this._animations = St.TextureCache.get_default().load_sliced_image (filename, width, height,
 | 
			
		||||
                                                                            Lang.bind(this, this._animationsLoaded));
 | 
			
		||||
        this.actor.set_child(this._animations);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    play: function() {
 | 
			
		||||
        if (this._isLoaded && this._timeoutId == 0) {
 | 
			
		||||
            if (this._frame == 0)
 | 
			
		||||
                this._showFrame(0);
 | 
			
		||||
 | 
			
		||||
            this._timeoutId = Mainloop.timeout_add(this._speed, Lang.bind(this, this._update));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._isPlaying = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    stop: function() {
 | 
			
		||||
        if (this._timeoutId > 0) {
 | 
			
		||||
            Mainloop.source_remove(this._timeoutId);
 | 
			
		||||
            this._timeoutId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._isPlaying = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showFrame: function(frame) {
 | 
			
		||||
        let oldFrameActor = this._animations.get_child_at_index(this._frame);
 | 
			
		||||
        if (oldFrameActor)
 | 
			
		||||
            oldFrameActor.hide();
 | 
			
		||||
 | 
			
		||||
        this._frame = (frame % this._animations.get_n_children());
 | 
			
		||||
 | 
			
		||||
        let newFrameActor = this._animations.get_child_at_index(this._frame);
 | 
			
		||||
        if (newFrameActor)
 | 
			
		||||
            newFrameActor.show();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _update: function() {
 | 
			
		||||
        this._showFrame(this._frame + 1);
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _animationsLoaded: function() {
 | 
			
		||||
        this._isLoaded = true;
 | 
			
		||||
 | 
			
		||||
        if (this._isPlaying)
 | 
			
		||||
            this.play();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDestroy: function() {
 | 
			
		||||
        this.stop();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const AnimatedIcon = new Lang.Class({
 | 
			
		||||
    Name: 'AnimatedIcon',
 | 
			
		||||
    Extends: Animation,
 | 
			
		||||
 | 
			
		||||
    _init: function(filename, size) {
 | 
			
		||||
        this.parent(filename, size, size, ANIMATED_ICON_UPDATE_TIMEOUT);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const TextShadower = new Lang.Class({
 | 
			
		||||
    Name: 'TextShadower',
 | 
			
		||||
 | 
			
		||||
@@ -289,10 +215,10 @@ const AppMenuButton = new Lang.Class({
 | 
			
		||||
        this._visible = !Main.overview.visible;
 | 
			
		||||
        if (!this._visible)
 | 
			
		||||
            this.actor.hide();
 | 
			
		||||
        Main.overview.connect('hiding', Lang.bind(this, function () {
 | 
			
		||||
        this._overviewHidingId = Main.overview.connect('hiding', Lang.bind(this, function () {
 | 
			
		||||
            this.show();
 | 
			
		||||
        }));
 | 
			
		||||
        Main.overview.connect('showing', Lang.bind(this, function () {
 | 
			
		||||
        this._overviewShowingId = Main.overview.connect('showing', Lang.bind(this, function () {
 | 
			
		||||
            this.hide();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
@@ -302,10 +228,12 @@ const AppMenuButton = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        let tracker = Shell.WindowTracker.get_default();
 | 
			
		||||
        let appSys = Shell.AppSystem.get_default();
 | 
			
		||||
        tracker.connect('notify::focus-app', Lang.bind(this, this._focusAppChanged));
 | 
			
		||||
        appSys.connect('app-state-changed', Lang.bind(this, this._onAppStateChanged));
 | 
			
		||||
 | 
			
		||||
        global.window_manager.connect('switch-workspace', Lang.bind(this, this._sync));
 | 
			
		||||
        this._focusAppNotifyId =
 | 
			
		||||
            tracker.connect('notify::focus-app', Lang.bind(this, this._focusAppChanged));
 | 
			
		||||
        this._appStateChangedSignalId =
 | 
			
		||||
            appSys.connect('app-state-changed', Lang.bind(this, this._onAppStateChanged));
 | 
			
		||||
        this._switchWorkspaceNotifyId =
 | 
			
		||||
            global.window_manager.connect('switch-workspace', Lang.bind(this, this._sync));
 | 
			
		||||
 | 
			
		||||
        this._sync();
 | 
			
		||||
    },
 | 
			
		||||
@@ -357,7 +285,7 @@ const AppMenuButton = new Lang.Class({
 | 
			
		||||
        if (!success || this._spinnerIcon == icon)
 | 
			
		||||
            return;
 | 
			
		||||
        this._spinnerIcon = icon;
 | 
			
		||||
        this._spinner = new AnimatedIcon(this._spinnerIcon, PANEL_ICON_SIZE);
 | 
			
		||||
        this._spinner = new Animation.AnimatedIcon(this._spinnerIcon, PANEL_ICON_SIZE);
 | 
			
		||||
        this._container.add_actor(this._spinner.actor);
 | 
			
		||||
        this._spinner.actor.hide();
 | 
			
		||||
        this._spinner.actor.lower_bottom();
 | 
			
		||||
@@ -566,9 +494,14 @@ const AppMenuButton = new Lang.Class({
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (targetApp == this._targetApp) {
 | 
			
		||||
            if (targetApp && targetApp.get_state() != Shell.AppState.STARTING) {
 | 
			
		||||
            if (targetApp &&
 | 
			
		||||
                targetApp.get_state() != Shell.AppState.STARTING &&
 | 
			
		||||
                targetApp.get_state() != Shell.AppState.BUSY) {
 | 
			
		||||
                this.stopAnimation();
 | 
			
		||||
                this._maybeSetMenu();
 | 
			
		||||
            } else if (targetApp &&
 | 
			
		||||
                       targetApp.get_state() == Shell.AppState.BUSY) {
 | 
			
		||||
                this.startAnimation();
 | 
			
		||||
            }
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -601,7 +534,8 @@ const AppMenuButton = new Lang.Class({
 | 
			
		||||
        this._iconBox.set_child(icon);
 | 
			
		||||
        this._iconBox.show();
 | 
			
		||||
 | 
			
		||||
        if (targetApp.get_state() == Shell.AppState.STARTING)
 | 
			
		||||
        if (targetApp.get_state() == Shell.AppState.STARTING ||
 | 
			
		||||
            targetApp.get_state() == Shell.AppState.BUSY)
 | 
			
		||||
            this.startAnimation();
 | 
			
		||||
        else
 | 
			
		||||
            this._maybeSetMenu();
 | 
			
		||||
@@ -613,11 +547,11 @@ const AppMenuButton = new Lang.Class({
 | 
			
		||||
        let menu;
 | 
			
		||||
 | 
			
		||||
        if (this._targetApp.action_group && this._targetApp.menu) {
 | 
			
		||||
            if (this.menu instanceof PopupMenu.RemoteMenu &&
 | 
			
		||||
            if (this.menu instanceof RemoteMenu.RemoteMenu &&
 | 
			
		||||
                this.menu.actionGroup == this._targetApp.action_group)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            menu = new PopupMenu.RemoteMenu(this.actor, this._targetApp.menu, this._targetApp.action_group);
 | 
			
		||||
            menu = new RemoteMenu.RemoteMenu(this.actor, this._targetApp.menu, this._targetApp.action_group);
 | 
			
		||||
            menu.connect('activate', Lang.bind(this, function() {
 | 
			
		||||
                let win = this._targetApp.get_windows()[0];
 | 
			
		||||
                win.check_alive(global.get_current_time());
 | 
			
		||||
@@ -637,6 +571,33 @@ const AppMenuButton = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this.setMenu(menu);
 | 
			
		||||
        this._menuManager.addMenu(menu);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
        if (this._appStateChangedSignalId > 0) {
 | 
			
		||||
            let appSys = Shell.AppSystem.get_default();
 | 
			
		||||
            appSys.disconnect(this._appStateChangedSignalId);
 | 
			
		||||
            this._appStateChangedSignalId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (this._focusAppNotifyId > 0) {
 | 
			
		||||
            let tracker = Shell.WindowTracker.get_default();
 | 
			
		||||
            tracker.disconnect(this._focusAppNotifyId);
 | 
			
		||||
            this._focusAppNotifyId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (this._overviewHidingId > 0) {
 | 
			
		||||
            Main.overview.disconnect(this._overviewHidingId);
 | 
			
		||||
            this._overviewHidingId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (this._overviewShowingId > 0) {
 | 
			
		||||
            Main.overview.disconnect(this._overviewShowingId);
 | 
			
		||||
            this._overviewShowingId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (this._switchWorkspaceNotifyId > 0) {
 | 
			
		||||
            global.window_manager.disconnect(this._switchWorkspaceNotifyId);
 | 
			
		||||
            this._switchWorkspaceNotifyId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.parent();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -894,9 +855,8 @@ const PANEL_ITEM_IMPLEMENTATIONS = {
 | 
			
		||||
    'volume': imports.ui.status.volume.Indicator,
 | 
			
		||||
    'battery': imports.ui.status.power.Indicator,
 | 
			
		||||
    'lockScreen': imports.ui.status.lockScreenMenu.Indicator,
 | 
			
		||||
    'logo': imports.gdm.loginDialog.LogoMenuButton,
 | 
			
		||||
    'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
 | 
			
		||||
    'powerMenu': imports.gdm.powerMenu.PowerMenuButton,
 | 
			
		||||
    'powerMenu': imports.ui.auth.powerMenu.PowerMenuButton,
 | 
			
		||||
    'userMenu': imports.ui.userMenu.UserMenuButton
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -923,7 +883,7 @@ const Panel = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this.statusArea = {};
 | 
			
		||||
 | 
			
		||||
        this.menuManager = new PopupMenu.PopupMenuManager(this);
 | 
			
		||||
        this.menuManager = new PopupMenu.PopupMenuManager(this, { keybindingMode: Shell.KeyBindingMode.TOPBAR_POPUP });
 | 
			
		||||
 | 
			
		||||
        this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
 | 
			
		||||
        this.actor.add_actor(this._leftBox);
 | 
			
		||||
@@ -1077,17 +1037,18 @@ const Panel = new Lang.Class({
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    openAppMenu: function() {
 | 
			
		||||
    toggleAppMenu: function() {
 | 
			
		||||
        let indicator = this.statusArea.appMenu;
 | 
			
		||||
        if (!indicator) // appMenu not supported by current session mode
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let menu = indicator.menu;
 | 
			
		||||
        if (!indicator.actor.reactive || menu.isOpen)
 | 
			
		||||
        if (!indicator.actor.reactive)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        menu.open();
 | 
			
		||||
        menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
 | 
			
		||||
        menu.toggle();
 | 
			
		||||
        if (menu.isOpen)
 | 
			
		||||
            menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    set boxOpacity(value) {
 | 
			
		||||
 
 | 
			
		||||
@@ -184,6 +184,9 @@ const Button = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onMenuKeyPress: function(actor, event) {
 | 
			
		||||
        if (global.focus_manager.navigate_from_event(event))
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        let symbol = event.get_key_symbol();
 | 
			
		||||
        if (symbol == Clutter.KEY_Left || symbol == Clutter.KEY_Right) {
 | 
			
		||||
            let group = global.focus_manager.get_group(this.actor);
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,12 @@ const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
const SLIDER_SCROLL_STEP = 0.05; /* Slider scrolling step in % */
 | 
			
		||||
 | 
			
		||||
const Ornament = {
 | 
			
		||||
    NONE: 0,
 | 
			
		||||
    DOT: 1,
 | 
			
		||||
    CHECK: 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function _ensureStyle(actor) {
 | 
			
		||||
    if (actor.get_children) {
 | 
			
		||||
        let children = actor.get_children();
 | 
			
		||||
@@ -53,7 +59,9 @@ const PopupBaseMenuItem = new Lang.Class({
 | 
			
		||||
        this.actor._delegate = this;
 | 
			
		||||
 | 
			
		||||
        this._children = [];
 | 
			
		||||
        this._dot = null;
 | 
			
		||||
        this._ornament = Ornament.NONE;
 | 
			
		||||
        this._ornamentLabel = new St.Label({ style_class: 'popup-menu-ornament' });
 | 
			
		||||
        this.actor.add_actor(this._ornamentLabel);
 | 
			
		||||
        this._columnWidths = null;
 | 
			
		||||
        this._spacing = 0;
 | 
			
		||||
        this.active = false;
 | 
			
		||||
@@ -176,40 +184,24 @@ const PopupBaseMenuItem = new Lang.Class({
 | 
			
		||||
        this._removeChild(child);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setShowDot: function(show) {
 | 
			
		||||
        if (show) {
 | 
			
		||||
            if (this._dot)
 | 
			
		||||
                return;
 | 
			
		||||
    setOrnament: function(ornament) {
 | 
			
		||||
        if (ornament == this._ornament)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
            this._dot = new St.DrawingArea({ style_class: 'popup-menu-item-dot' });
 | 
			
		||||
            this._dot.connect('repaint', Lang.bind(this, this._onRepaintDot));
 | 
			
		||||
            this.actor.add_actor(this._dot);
 | 
			
		||||
            this.actor.add_accessible_state (Atk.StateType.CHECKED);
 | 
			
		||||
        } else {
 | 
			
		||||
            if (!this._dot)
 | 
			
		||||
                return;
 | 
			
		||||
        this._ornament = ornament;
 | 
			
		||||
 | 
			
		||||
            this._dot.destroy();
 | 
			
		||||
            this._dot = null;
 | 
			
		||||
            this.actor.remove_accessible_state (Atk.StateType.CHECKED);
 | 
			
		||||
        if (ornament == Ornament.DOT) {
 | 
			
		||||
            this._ornamentLabel.text = '\u2022';
 | 
			
		||||
            this.actor.add_accessible_state(Atk.StateType.CHECKED);
 | 
			
		||||
        } else if (ornament == Ornament.CHECK) {
 | 
			
		||||
            this._ornamentLabel.text = '\u2713';
 | 
			
		||||
            this.actor.add_accessible_state(Atk.StateType.CHECKED);
 | 
			
		||||
        } else if (ornament == Ornament.NONE) {
 | 
			
		||||
            this._ornamentLabel.text = '';
 | 
			
		||||
            this.actor.remove_accessible_state(Atk.StateType.CHECKED);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onRepaintDot: function(area) {
 | 
			
		||||
        let cr = area.get_context();
 | 
			
		||||
        let [width, height] = area.get_surface_size();
 | 
			
		||||
        let color = area.get_theme_node().get_foreground_color();
 | 
			
		||||
 | 
			
		||||
        cr.setSourceRGBA (
 | 
			
		||||
            color.red / 255,
 | 
			
		||||
            color.green / 255,
 | 
			
		||||
            color.blue / 255,
 | 
			
		||||
            color.alpha / 255);
 | 
			
		||||
        cr.arc(width / 2, height / 2, width / 3, 0, 2 * Math.PI);
 | 
			
		||||
        cr.fill();
 | 
			
		||||
        cr.$dispose();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // This returns column widths in logical order (i.e. from the dot
 | 
			
		||||
    // to the image), not in visual order (left to right)
 | 
			
		||||
    getColumnWidths: function() {
 | 
			
		||||
@@ -280,26 +272,25 @@ const PopupBaseMenuItem = new Lang.Class({
 | 
			
		||||
        let height = box.y2 - box.y1;
 | 
			
		||||
        let direction = this.actor.get_text_direction();
 | 
			
		||||
 | 
			
		||||
        if (this._dot) {
 | 
			
		||||
            // The dot is placed outside box
 | 
			
		||||
            // one quarter of padding from the border of the container
 | 
			
		||||
            // (so 3/4 from the inner border)
 | 
			
		||||
            // (padding is box.x1)
 | 
			
		||||
            let dotBox = new Clutter.ActorBox();
 | 
			
		||||
            let dotWidth = Math.round(box.x1 / 2);
 | 
			
		||||
        // The ornament is placed outside box
 | 
			
		||||
        // one quarter of padding from the border of the container
 | 
			
		||||
        // (so 3/4 from the inner border)
 | 
			
		||||
        // (padding is box.x1)
 | 
			
		||||
        let ornamentBox = new Clutter.ActorBox();
 | 
			
		||||
        let ornamentWidth = box.x1;
 | 
			
		||||
 | 
			
		||||
            if (direction == Clutter.TextDirection.LTR) {
 | 
			
		||||
                dotBox.x1 = Math.round(box.x1 / 4);
 | 
			
		||||
                dotBox.x2 = dotBox.x1 + dotWidth;
 | 
			
		||||
            } else {
 | 
			
		||||
                dotBox.x2 = box.x2 + 3 * Math.round(box.x1 / 4);
 | 
			
		||||
                dotBox.x1 = dotBox.x2 - dotWidth;
 | 
			
		||||
            }
 | 
			
		||||
            dotBox.y1 = Math.round(box.y1 + (height - dotWidth) / 2);
 | 
			
		||||
            dotBox.y2 = dotBox.y1 + dotWidth;
 | 
			
		||||
            this._dot.allocate(dotBox, flags);
 | 
			
		||||
        ornamentBox.x1 = 0;
 | 
			
		||||
        ornamentBox.x2 = ornamentWidth;
 | 
			
		||||
        ornamentBox.y1 = box.y1;
 | 
			
		||||
        ornamentBox.y2 = box.y2;
 | 
			
		||||
 | 
			
		||||
        if (direction == Clutter.TextDirection.RTL) {
 | 
			
		||||
            ornamentBox.x1 += box.x2;
 | 
			
		||||
            ornamentBox.x2 += box.x2;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._ornamentLabel.allocate(ornamentBox, flags);
 | 
			
		||||
 | 
			
		||||
        let x;
 | 
			
		||||
        if (direction == Clutter.TextDirection.LTR)
 | 
			
		||||
            x = box.x1;
 | 
			
		||||
@@ -402,12 +393,19 @@ const PopupSeparatorMenuItem = new Lang.Class({
 | 
			
		||||
    Name: 'PopupSeparatorMenuItem',
 | 
			
		||||
    Extends: PopupBaseMenuItem,
 | 
			
		||||
 | 
			
		||||
    _init: function () {
 | 
			
		||||
    _init: function (text) {
 | 
			
		||||
        this.parent({ reactive: false,
 | 
			
		||||
                      can_focus: false});
 | 
			
		||||
 | 
			
		||||
        this._box = new St.BoxLayout();
 | 
			
		||||
        this.addActor(this._box, { span: -1, expand: true });
 | 
			
		||||
 | 
			
		||||
        this.label = new St.Label({ text: text || '' });
 | 
			
		||||
        this._box.add(this.label);
 | 
			
		||||
        this.actor.label_actor = this.label;
 | 
			
		||||
 | 
			
		||||
        this._separator = new Separator.HorizontalSeparator({ style_class: 'popup-separator-menu-item' });
 | 
			
		||||
        this.addActor(this._separator.actor, { span: -1, expand: true });
 | 
			
		||||
        this._box.add(this._separator.actor, { expand: true });
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -553,6 +551,10 @@ const PopupSliderMenuItem = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        let handleRadius = themeNode.get_length('-slider-handle-radius');
 | 
			
		||||
 | 
			
		||||
        let handleBorderWidth = themeNode.get_length('-slider-handle-border-width');
 | 
			
		||||
        let [hasHandleColor, handleBorderColor] =
 | 
			
		||||
            themeNode.lookup_color('-slider-handle-border-color', false);
 | 
			
		||||
 | 
			
		||||
        let sliderWidth = width - 2 * handleRadius;
 | 
			
		||||
        let sliderHeight = themeNode.get_length('-slider-height');
 | 
			
		||||
 | 
			
		||||
@@ -604,7 +606,16 @@ const PopupSliderMenuItem = new Lang.Class({
 | 
			
		||||
            color.blue / 255,
 | 
			
		||||
            color.alpha / 255);
 | 
			
		||||
        cr.arc(handleX, handleY, handleRadius, 0, 2 * Math.PI);
 | 
			
		||||
        cr.fill();
 | 
			
		||||
        cr.fillPreserve();
 | 
			
		||||
        if (hasHandleColor && handleBorderWidth) {
 | 
			
		||||
          cr.setSourceRGBA(
 | 
			
		||||
              handleBorderColor.red / 255,
 | 
			
		||||
              handleBorderColor.green / 255,
 | 
			
		||||
              handleBorderColor.blue / 255,
 | 
			
		||||
              handleBorderColor.alpha / 255);
 | 
			
		||||
          cr.setLineWidth(handleBorderWidth);
 | 
			
		||||
          cr.stroke();
 | 
			
		||||
        }
 | 
			
		||||
        cr.$dispose();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -992,6 +1003,9 @@ const PopupMenuBase = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateSeparatorVisibility: function(menuItem) {
 | 
			
		||||
        if (menuItem.label.text)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let children = this.box.get_children();
 | 
			
		||||
 | 
			
		||||
        let index = children.indexOf(menuItem.actor);
 | 
			
		||||
@@ -1475,23 +1489,12 @@ const PopupMenuSection = new Lang.Class({
 | 
			
		||||
        this.actor = this.box;
 | 
			
		||||
        this.actor._delegate = this;
 | 
			
		||||
        this.isOpen = true;
 | 
			
		||||
 | 
			
		||||
        // an array of externally managed separators
 | 
			
		||||
        this.separators = [];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // deliberately ignore any attempt to open() or close(), but emit the
 | 
			
		||||
    // corresponding signal so children can still pick it up
 | 
			
		||||
    open: function() { this.emit('open-state-changed', true); },
 | 
			
		||||
    close: function() { this.emit('open-state-changed', false); },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
        for (let i = 0; i < this.separators.length; i++)
 | 
			
		||||
            this.separators[i].destroy();
 | 
			
		||||
        this.separators = [];
 | 
			
		||||
 | 
			
		||||
        this.parent();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const PopupSubMenuMenuItem = new Lang.Class({
 | 
			
		||||
@@ -1526,15 +1529,30 @@ const PopupSubMenuMenuItem = new Lang.Class({
 | 
			
		||||
        this.parent();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setSubmenuShown: function(open) {
 | 
			
		||||
        if (open)
 | 
			
		||||
            this.menu.open(BoxPointer.PopupAnimation.FULL);
 | 
			
		||||
        else
 | 
			
		||||
            this.menu.close(BoxPointer.PopupAnimation.FULL);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setOpenState: function(open) {
 | 
			
		||||
        this.setSubmenuShown(open);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getOpenState: function() {
 | 
			
		||||
        return this.menu.isOpen;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeyPressEvent: function(actor, event) {
 | 
			
		||||
        let symbol = event.get_key_symbol();
 | 
			
		||||
 | 
			
		||||
        if (symbol == Clutter.KEY_Right) {
 | 
			
		||||
            this.menu.open(BoxPointer.PopupAnimation.FULL);
 | 
			
		||||
            this._setOpenState(true);
 | 
			
		||||
            this.menu.actor.navigate_focus(null, Gtk.DirectionType.DOWN, false);
 | 
			
		||||
            return true;
 | 
			
		||||
        } else if (symbol == Clutter.KEY_Left && this.menu.isOpen) {
 | 
			
		||||
            this.menu.close();
 | 
			
		||||
        } else if (symbol == Clutter.KEY_Left && this._getOpenState()) {
 | 
			
		||||
            this._setOpenState(false);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -1542,11 +1560,11 @@ const PopupSubMenuMenuItem = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activate: function(event) {
 | 
			
		||||
        this.menu.open(BoxPointer.PopupAnimation.FULL);
 | 
			
		||||
        this._setOpenState(true);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onButtonReleaseEvent: function(actor) {
 | 
			
		||||
        this.menu.toggle();
 | 
			
		||||
        this._setOpenState(!this._getOpenState());
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -1792,269 +1810,15 @@ const PopupComboBoxMenuItem = new Lang.Class({
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * RemoteMenu:
 | 
			
		||||
 *
 | 
			
		||||
 * A PopupMenu that tracks a GMenuModel and shows its actions
 | 
			
		||||
 * (exposed by GApplication/GActionGroup)
 | 
			
		||||
 */
 | 
			
		||||
const RemoteMenu = new Lang.Class({
 | 
			
		||||
    Name: 'RemoteMenu',
 | 
			
		||||
    Extends: PopupMenu,
 | 
			
		||||
 | 
			
		||||
    _init: function(sourceActor, model, actionGroup) {
 | 
			
		||||
        this.parent(sourceActor, 0.0, St.Side.TOP);
 | 
			
		||||
 | 
			
		||||
        this.model = model;
 | 
			
		||||
        this.actionGroup = actionGroup;
 | 
			
		||||
 | 
			
		||||
        this._actions = { };
 | 
			
		||||
        this._modelChanged(this.model, 0, 0, this.model.get_n_items(), this);
 | 
			
		||||
 | 
			
		||||
        this._actionStateChangeId = this.actionGroup.connect('action-state-changed', Lang.bind(this, this._actionStateChanged));
 | 
			
		||||
        this._actionEnableChangeId = this.actionGroup.connect('action-enabled-changed', Lang.bind(this, this._actionEnabledChanged));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
        if (this._actionStateChangeId) {
 | 
			
		||||
            this.actionGroup.disconnect(this._actionStateChangeId);
 | 
			
		||||
            this._actionStateChangeId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._actionEnableChangeId) {
 | 
			
		||||
            this.actionGroup.disconnect(this._actionEnableChangeId);
 | 
			
		||||
            this._actionEnableChangeId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.parent();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createMenuItem: function(model, index) {
 | 
			
		||||
        let labelValue = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_LABEL, null);
 | 
			
		||||
        let label = labelValue ? labelValue.deep_unpack() : '';
 | 
			
		||||
        // remove all underscores that are not followed by another underscore
 | 
			
		||||
        label = label.replace(/_([^_])/, '$1');
 | 
			
		||||
 | 
			
		||||
        let section_link = model.get_item_link(index, Gio.MENU_LINK_SECTION);
 | 
			
		||||
        if (section_link) {
 | 
			
		||||
            let item = new PopupMenuSection();
 | 
			
		||||
            if (label) {
 | 
			
		||||
                let title = new PopupMenuItem(label, { reactive: false,
 | 
			
		||||
                                                       style_class: 'popup-subtitle-menu-item' });
 | 
			
		||||
                item._titleMenuItem = title;
 | 
			
		||||
                title._ignored = true;
 | 
			
		||||
                item.addMenuItem(title);
 | 
			
		||||
            }
 | 
			
		||||
            this._modelChanged(section_link, 0, 0, section_link.get_n_items(), item);
 | 
			
		||||
            return [item, true, ''];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let submenu_link = model.get_item_link(index, Gio.MENU_LINK_SUBMENU);
 | 
			
		||||
 | 
			
		||||
        if (submenu_link) {
 | 
			
		||||
            let item = new PopupSubMenuMenuItem(label);
 | 
			
		||||
            this._modelChanged(submenu_link, 0, 0, submenu_link.get_n_items(), item.menu);
 | 
			
		||||
            return [item, false, ''];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let action_id = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_ACTION, null).deep_unpack();
 | 
			
		||||
        if (!this.actionGroup.has_action(action_id)) {
 | 
			
		||||
            // the action may not be there yet, wait for action-added
 | 
			
		||||
            return [null, false, 'action-added'];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!this._actions[action_id])
 | 
			
		||||
            this._actions[action_id] = { enabled: this.actionGroup.get_action_enabled(action_id),
 | 
			
		||||
                                         state: this.actionGroup.get_action_state(action_id),
 | 
			
		||||
                                         items: [ ],
 | 
			
		||||
                                       };
 | 
			
		||||
        let action = this._actions[action_id];
 | 
			
		||||
        let item, target, destroyId, specificSignalId;
 | 
			
		||||
 | 
			
		||||
        if (action.state) {
 | 
			
		||||
            // Docs have get_state_hint(), except that the DBus protocol
 | 
			
		||||
            // has no provision for it (so ShellApp does not implement it,
 | 
			
		||||
            // and neither GApplication), and g_action_get_state_hint()
 | 
			
		||||
            // always returns null
 | 
			
		||||
            // Funny :)
 | 
			
		||||
 | 
			
		||||
            switch (String.fromCharCode(action.state.classify())) {
 | 
			
		||||
            case 'b':
 | 
			
		||||
                item = new PopupSwitchMenuItem(label, action.state.get_boolean());
 | 
			
		||||
                action.items.push(item);
 | 
			
		||||
                specificSignalId = item.connect('toggled', Lang.bind(this, function(item) {
 | 
			
		||||
                    this.actionGroup.activate_action(action_id, null);
 | 
			
		||||
                }));
 | 
			
		||||
                break;
 | 
			
		||||
            case 's':
 | 
			
		||||
                item = new PopupMenuItem(label);
 | 
			
		||||
                item._remoteTarget = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_TARGET, null).deep_unpack();
 | 
			
		||||
                action.items.push(item);
 | 
			
		||||
                item.setShowDot(action.state.deep_unpack() == item._remoteTarget);
 | 
			
		||||
                specificSignalId = item.connect('activate', Lang.bind(this, function(item) {
 | 
			
		||||
                    this.actionGroup.activate_action(action_id, GLib.Variant.new_string(item._remoteTarget));
 | 
			
		||||
                }));
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                log('Action "%s" has state of type %s, which is not supported'.format(action_id, action.state.get_type_string()));
 | 
			
		||||
                return [null, false, 'action-state-changed'];
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            target = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_TARGET, null);
 | 
			
		||||
            item = new PopupMenuItem(label);
 | 
			
		||||
            action.items.push(item);
 | 
			
		||||
            specificSignalId = item.connect('activate', Lang.bind(this, function() {
 | 
			
		||||
                this.actionGroup.activate_action(action_id, target);
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        item.actor.reactive = item.actor.can_focus = action.enabled;
 | 
			
		||||
 | 
			
		||||
        destroyId = item.connect('destroy', Lang.bind(this, function() {
 | 
			
		||||
            item.disconnect(destroyId);
 | 
			
		||||
            item.disconnect(specificSignalId);
 | 
			
		||||
 | 
			
		||||
            let pos = action.items.indexOf(item);
 | 
			
		||||
            if (pos != -1)
 | 
			
		||||
                action.items.splice(pos, 1);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return [item, false, ''];
 | 
			
		||||
    }, 
 | 
			
		||||
 | 
			
		||||
    _modelChanged: function(model, position, removed, added, target) {
 | 
			
		||||
        let j, k;
 | 
			
		||||
        let j0, k0;
 | 
			
		||||
 | 
			
		||||
        let currentItems = target._getMenuItems();
 | 
			
		||||
 | 
			
		||||
        k0 = 0;
 | 
			
		||||
        // skip ignored items at the beginning
 | 
			
		||||
        while (k0 < currentItems.length && currentItems[k0]._ignored)
 | 
			
		||||
            k0++;
 | 
			
		||||
        // find the right menu item matching the model item
 | 
			
		||||
        for (j0 = 0; k0 < currentItems.length && j0 < position; j0++, k0++) {
 | 
			
		||||
            if (currentItems[k0]._ignored)
 | 
			
		||||
                k0++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (removed == -1) {
 | 
			
		||||
            // special flag to indicate we should destroy everything
 | 
			
		||||
            for (k = k0; k < currentItems.length; k++)
 | 
			
		||||
                currentItems[k].destroy();
 | 
			
		||||
        } else {
 | 
			
		||||
            for (j = j0, k = k0; k < currentItems.length && j < j0 + removed; j++, k++) {
 | 
			
		||||
                currentItems[k].destroy();
 | 
			
		||||
 | 
			
		||||
                if (currentItems[k]._ignored)
 | 
			
		||||
                    j--;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (j = j0, k = k0; j < j0 + added; j++, k++) {
 | 
			
		||||
            let [item, addSeparator, changeSignal] = this._createMenuItem(model, j);
 | 
			
		||||
 | 
			
		||||
            if (item) {
 | 
			
		||||
                // separators must be added in the parent to make autohiding work
 | 
			
		||||
                if (addSeparator) {
 | 
			
		||||
                    let separator = new PopupSeparatorMenuItem();
 | 
			
		||||
                    item.separators.push(separator);
 | 
			
		||||
                    separator._ignored = true;
 | 
			
		||||
                    target.addMenuItem(separator, k+1);
 | 
			
		||||
                    k++;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                target.addMenuItem(item, k);
 | 
			
		||||
 | 
			
		||||
                if (addSeparator) {
 | 
			
		||||
                    let separator = new PopupSeparatorMenuItem();
 | 
			
		||||
                    item.separators.push(separator);
 | 
			
		||||
                    separator._ignored = true;
 | 
			
		||||
                    target.addMenuItem(separator, k+1);
 | 
			
		||||
                    k++;
 | 
			
		||||
                }
 | 
			
		||||
            } else if (changeSignal) {
 | 
			
		||||
                let signalId = this.actionGroup.connect(changeSignal, Lang.bind(this, function(actionGroup, actionName) {
 | 
			
		||||
                    actionGroup.disconnect(signalId);
 | 
			
		||||
                    if (this._actions[actionName]) return;
 | 
			
		||||
 | 
			
		||||
                    // force a full update
 | 
			
		||||
                    this._modelChanged(model, 0, -1, model.get_n_items(), target);
 | 
			
		||||
                }));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!model._changedId) {
 | 
			
		||||
            model._changedId = model.connect('items-changed', Lang.bind(this, this._modelChanged, target));
 | 
			
		||||
            model._destroyId = target.connect('destroy', function() {
 | 
			
		||||
                if (model._changedId)
 | 
			
		||||
                    model.disconnect(model._changedId);
 | 
			
		||||
                if (model._destroyId)
 | 
			
		||||
                    target.disconnect(model._destroyId);
 | 
			
		||||
                model._changedId = 0;
 | 
			
		||||
                model._destroyId = 0;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (target instanceof PopupMenuSection) {
 | 
			
		||||
            if (target._titleMenuItem)
 | 
			
		||||
                target.actor.visible = target.numMenuItems != 1;
 | 
			
		||||
            else
 | 
			
		||||
                target.actor.visible = target.numMenuItems != 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            let sourceItem = target.sourceActor._delegate;
 | 
			
		||||
            if (sourceItem instanceof PopupSubMenuMenuItem)
 | 
			
		||||
                sourceItem.actor.visible = target.numMenuItems != 0;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _actionStateChanged: function(actionGroup, action_id) {
 | 
			
		||||
        let action = this._actions[action_id];
 | 
			
		||||
        if (!action)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        action.state = actionGroup.get_action_state(action_id);
 | 
			
		||||
        if (action.items.length) {
 | 
			
		||||
            switch (String.fromCharCode(action.state.classify())) {
 | 
			
		||||
            case 'b':
 | 
			
		||||
                for (let i = 0; i < action.items.length; i++)
 | 
			
		||||
                    action.items[i].setToggleState(action.state.get_boolean());
 | 
			
		||||
                break;
 | 
			
		||||
            case 'd':
 | 
			
		||||
                for (let i = 0; i < action.items.length; i++)
 | 
			
		||||
                    action.items[i].setValue(action.state.get_double());
 | 
			
		||||
                break;
 | 
			
		||||
            case 's':
 | 
			
		||||
                for (let i = 0; i < action.items.length; i++)
 | 
			
		||||
                    action.items[i].setShowDot(action.items[i]._remoteTarget == action.state.deep_unpack());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _actionEnabledChanged: function(actionGroup, action_id) {
 | 
			
		||||
        let action = this._actions[action_id];
 | 
			
		||||
        if (!action)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        action.enabled = actionGroup.get_action_enabled(action_id);
 | 
			
		||||
        if (action.items.length) {
 | 
			
		||||
            for (let i = 0; i < action.items.length; i++) {
 | 
			
		||||
                let item = action.items[i];
 | 
			
		||||
                item.actor.reactive = item.actor.can_focus = action.enabled;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Basic implementation of a menu manager.
 | 
			
		||||
 * Call addMenu to add menus
 | 
			
		||||
 */
 | 
			
		||||
const PopupMenuManager = new Lang.Class({
 | 
			
		||||
    Name: 'PopupMenuManager',
 | 
			
		||||
 | 
			
		||||
    _init: function(owner) {
 | 
			
		||||
    _init: function(owner, grabParams) {
 | 
			
		||||
        this._owner = owner;
 | 
			
		||||
        this._grabHelper = new GrabHelper.GrabHelper(owner.actor);
 | 
			
		||||
        this._grabHelper = new GrabHelper.GrabHelper(owner.actor, grabParams);
 | 
			
		||||
        this._menus = [];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -2124,6 +1888,8 @@ const PopupMenuManager = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _onMenuOpenState: function(menu, open) {
 | 
			
		||||
        if (open) {
 | 
			
		||||
            if (this.activeMenu && !this.activeMenu.isChildMenu(menu))
 | 
			
		||||
                this.activeMenu.close(BoxPointer.PopupAnimation.FADE);
 | 
			
		||||
            this._grabHelper.grab({ actor: menu.actor, modal: true, focus: menu.sourceActor,
 | 
			
		||||
                                    onUngrab: Lang.bind(this, this._closeMenu, menu) });
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -2140,13 +1906,8 @@ const PopupMenuManager = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _changeMenu: function(newMenu) {
 | 
			
		||||
        let oldMenu = this.activeMenu;
 | 
			
		||||
        if (oldMenu) {
 | 
			
		||||
            oldMenu.close(BoxPointer.PopupAnimation.FADE);
 | 
			
		||||
            newMenu.open(BoxPointer.PopupAnimation.FADE);
 | 
			
		||||
        } else {
 | 
			
		||||
            newMenu.open(BoxPointer.PopupAnimation.FULL);
 | 
			
		||||
        }
 | 
			
		||||
        newMenu.open(this.activeMenu ? BoxPointer.PopupAnimation.FADE
 | 
			
		||||
                                     : BoxPointer.PopupAnimation.FULL);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onMenuSourceEnter: function(menu) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										199
									
								
								js/ui/remoteMenu.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								js/ui/remoteMenu.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,199 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Atk = imports.gi.Atk;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const GObject = imports.gi.GObject;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const ShellMenu = imports.gi.ShellMenu;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const PopupMenu = imports.ui.popupMenu;
 | 
			
		||||
 | 
			
		||||
function stripMnemonics(label) {
 | 
			
		||||
    if (!label)
 | 
			
		||||
        return '';
 | 
			
		||||
 | 
			
		||||
    // remove all underscores that are not followed by another underscore
 | 
			
		||||
    return label.replace(/_([^_])/, '$1');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _insertItem(menu, trackerItem, position) {
 | 
			
		||||
    let mapper;
 | 
			
		||||
 | 
			
		||||
    if (trackerItem.get_is_separator())
 | 
			
		||||
        mapper = new RemoteMenuSeparatorItemMapper(trackerItem);
 | 
			
		||||
    else if (trackerItem.get_has_submenu())
 | 
			
		||||
        mapper = new RemoteMenuSubmenuItemMapper(trackerItem);
 | 
			
		||||
    else
 | 
			
		||||
        mapper = new RemoteMenuItemMapper(trackerItem);
 | 
			
		||||
 | 
			
		||||
    let item = mapper.menuItem;
 | 
			
		||||
    menu.addMenuItem(item, position);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _removeItem(menu, position) {
 | 
			
		||||
    let items = menu._getMenuItems();
 | 
			
		||||
    items[position].destroy();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const RemoteMenuSeparatorItemMapper = new Lang.Class({
 | 
			
		||||
    Name: 'RemoteMenuSeparatorItemMapper',
 | 
			
		||||
 | 
			
		||||
    _init: function(trackerItem) {
 | 
			
		||||
        this._trackerItem = trackerItem;
 | 
			
		||||
        this.menuItem = new PopupMenu.PopupSeparatorMenuItem();
 | 
			
		||||
        this._trackerItem.connect('notify::label', Lang.bind(this, this._updateLabel));
 | 
			
		||||
        this._updateLabel();
 | 
			
		||||
 | 
			
		||||
        this.menuItem.connect('destroy', function() {
 | 
			
		||||
            trackerItem.run_dispose();
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateLabel: function() {
 | 
			
		||||
        this.menuItem.label.text = stripMnemonics(this._trackerItem.label);
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const RequestSubMenu = new Lang.Class({
 | 
			
		||||
    Name: 'RequestSubMenu',
 | 
			
		||||
    Extends: PopupMenu.PopupSubMenuMenuItem,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.parent('');
 | 
			
		||||
        this._requestOpen = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setOpenState: function(open) {
 | 
			
		||||
        this.emit('request-open', open);
 | 
			
		||||
        this._requestOpen = open;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getOpenState: function() {
 | 
			
		||||
        return this._requestOpen;
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const RemoteMenuSubmenuItemMapper = new Lang.Class({
 | 
			
		||||
    Name: 'RemoteMenuSubmenuItemMapper',
 | 
			
		||||
 | 
			
		||||
    _init: function(trackerItem) {
 | 
			
		||||
        this._trackerItem = trackerItem;
 | 
			
		||||
        this.menuItem = new RequestSubMenu();
 | 
			
		||||
        this._trackerItem.connect('notify::label', Lang.bind(this, this._updateLabel));
 | 
			
		||||
        this._updateLabel();
 | 
			
		||||
 | 
			
		||||
        this._tracker = Shell.MenuTracker.new_for_item_submenu(this._trackerItem,
 | 
			
		||||
                                                               _insertItem.bind(null, this.menuItem.menu),
 | 
			
		||||
                                                               _removeItem.bind(null, this.menuItem.menu));
 | 
			
		||||
 | 
			
		||||
        this.menuItem.connect('request-open', Lang.bind(this, function(menu, open) {
 | 
			
		||||
            this._trackerItem.request_submenu_shown(open);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        this._trackerItem.connect('notify::submenu-shown', Lang.bind(this, function() {
 | 
			
		||||
            this.menuItem.setSubmenuShown(this._trackerItem.get_submenu_shown());
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        this.menuItem.connect('destroy', function() {
 | 
			
		||||
            trackerItem.run_dispose();
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
        this._tracker.destroy();
 | 
			
		||||
        this.parent();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateLabel: function() {
 | 
			
		||||
        this.menuItem.label.text = stripMnemonics(this._trackerItem.label);
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const RemoteMenuItemMapper = new Lang.Class({
 | 
			
		||||
    Name: 'RemoteMenuItemMapper',
 | 
			
		||||
 | 
			
		||||
    _init: function(trackerItem) {
 | 
			
		||||
        this._trackerItem = trackerItem;
 | 
			
		||||
 | 
			
		||||
        this.menuItem = new PopupMenu.PopupBaseMenuItem();
 | 
			
		||||
        this._label = new St.Label();
 | 
			
		||||
        this.menuItem.addActor(this._label);
 | 
			
		||||
        this.menuItem.actor.label_actor = this._label;
 | 
			
		||||
 | 
			
		||||
        this.menuItem.connect('activate', Lang.bind(this, function() {
 | 
			
		||||
            this._trackerItem.activated();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        this._trackerItem.bind_property('visible', this.menuItem.actor, 'visible', GObject.BindingFlags.SYNC_CREATE);
 | 
			
		||||
 | 
			
		||||
        this._trackerItem.connect('notify::label', Lang.bind(this, this._updateLabel));
 | 
			
		||||
        this._trackerItem.connect('notify::sensitive', Lang.bind(this, this._updateSensitivity));
 | 
			
		||||
        this._trackerItem.connect('notify::role', Lang.bind(this, this._updateRole));
 | 
			
		||||
        this._trackerItem.connect('notify::toggled', Lang.bind(this, this._updateDecoration));
 | 
			
		||||
 | 
			
		||||
        this._updateLabel();
 | 
			
		||||
        this._updateSensitivity();
 | 
			
		||||
        this._updateRole();
 | 
			
		||||
 | 
			
		||||
        this.menuItem.connect('destroy', function() {
 | 
			
		||||
            trackerItem.run_dispose();
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateLabel: function() {
 | 
			
		||||
        this._label.text = stripMnemonics(this._trackerItem.label);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateSensitivity: function() {
 | 
			
		||||
        this.menuItem.setSensitive(this._trackerItem.sensitive);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateDecoration: function() {
 | 
			
		||||
        let ornamentForRole = {};
 | 
			
		||||
        ornamentForRole[ShellMenu.MenuTrackerItemRole.RADIO] = PopupMenu.Ornament.DOT;
 | 
			
		||||
        ornamentForRole[ShellMenu.MenuTrackerItemRole.CHECK] = PopupMenu.Ornament.CHECK;
 | 
			
		||||
 | 
			
		||||
        let ornament = PopupMenu.Ornament.NONE;
 | 
			
		||||
        if (this._trackerItem.toggled)
 | 
			
		||||
            ornament = ornamentForRole[this._trackerItem.role];
 | 
			
		||||
 | 
			
		||||
        this.menuItem.setOrnament(ornament);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateRole: function() {
 | 
			
		||||
        let a11yRoles = {};
 | 
			
		||||
        a11yRoles[ShellMenu.MenuTrackerItemRole.NORMAL] = Atk.Role.MENU_ITEM;
 | 
			
		||||
        a11yRoles[ShellMenu.MenuTrackerItemRole.RADIO] = Atk.Role.RADIO_MENU_ITEM;
 | 
			
		||||
        a11yRoles[ShellMenu.MenuTrackerItemRole.CHECK] = Atk.Role.CHECK_MENU_ITEM;
 | 
			
		||||
 | 
			
		||||
        let a11yRole = a11yRoles[this._trackerItem.role];
 | 
			
		||||
        this.menuItem.actor.accessible_role = a11yRole;
 | 
			
		||||
 | 
			
		||||
        this._updateDecoration();
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const RemoteMenu = new Lang.Class({
 | 
			
		||||
    Name: 'RemoteMenu',
 | 
			
		||||
    Extends: PopupMenu.PopupMenu,
 | 
			
		||||
 | 
			
		||||
    _init: function(sourceActor, model, actionGroup) {
 | 
			
		||||
        this.parent(sourceActor, 0.0, St.Side.TOP);
 | 
			
		||||
 | 
			
		||||
        this._model = model;
 | 
			
		||||
        this._actionGroup = actionGroup;
 | 
			
		||||
        this._tracker = Shell.MenuTracker.new(this._actionGroup,
 | 
			
		||||
                                              this._model,
 | 
			
		||||
                                              null, /* action namespace */
 | 
			
		||||
                                              _insertItem.bind(null, this),
 | 
			
		||||
                                              _removeItem.bind(null, this));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
        this._tracker.destroy();
 | 
			
		||||
        this.parent();
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
@@ -187,7 +187,9 @@ const RemoteSearchProvider = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    createIcon: function(size, meta) {
 | 
			
		||||
        let gicon;
 | 
			
		||||
        if (meta['gicon']) {
 | 
			
		||||
        if (meta['icon']) {
 | 
			
		||||
            gicon = Gio.icon_deserialize(meta['icon']);
 | 
			
		||||
        } else if (meta['gicon']) {
 | 
			
		||||
            gicon = Gio.icon_new_for_string(meta['gicon']);
 | 
			
		||||
        } else if (meta['icon-data']) {
 | 
			
		||||
            let [width, height, rowStride, hasAlpha,
 | 
			
		||||
@@ -203,7 +205,7 @@ const RemoteSearchProvider = new Lang.Class({
 | 
			
		||||
    _getResultsFinished: function(results, error) {
 | 
			
		||||
        if (error)
 | 
			
		||||
            return;
 | 
			
		||||
        this.searchSystem.pushResults(this, results[0]);
 | 
			
		||||
        this.searchSystem.setResults(this, results[0]);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getInitialResultSet: function(terms) {
 | 
			
		||||
@@ -215,7 +217,7 @@ const RemoteSearchProvider = new Lang.Class({
 | 
			
		||||
                                                 this._cancellable);
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            log('Error calling GetInitialResultSet for provider %s: %s'.format(this.id, e.toString()));
 | 
			
		||||
            this.searchSystem.pushResults(this, []);
 | 
			
		||||
            this.searchSystem.setResults(this, []);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -228,7 +230,7 @@ const RemoteSearchProvider = new Lang.Class({
 | 
			
		||||
                                                   this._cancellable);
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            log('Error calling GetSubsearchResultSet for provider %s: %s'.format(this.id, e.toString()));
 | 
			
		||||
            this.searchSystem.pushResults(this, []);
 | 
			
		||||
            this.searchSystem.setResults(this, []);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -240,8 +242,12 @@ const RemoteSearchProvider = new Lang.Class({
 | 
			
		||||
        let metas = results[0];
 | 
			
		||||
        let resultMetas = [];
 | 
			
		||||
        for (let i = 0; i < metas.length; i++) {
 | 
			
		||||
            for (let prop in metas[i])
 | 
			
		||||
                metas[i][prop] = metas[i][prop].deep_unpack();
 | 
			
		||||
            for (let prop in metas[i]) {
 | 
			
		||||
                // we can use the serialized icon variant directly
 | 
			
		||||
                if (prop != 'icon')
 | 
			
		||||
                    metas[i][prop] = metas[i][prop].deep_unpack();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            resultMetas.push({ id: metas[i]['id'],
 | 
			
		||||
                               name: metas[i]['name'],
 | 
			
		||||
                               description: metas[i]['description'],
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@ const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
 | 
			
		||||
const LOCK_ENABLED_KEY = 'lock-enabled';
 | 
			
		||||
const LOCK_DELAY_KEY = 'lock-delay';
 | 
			
		||||
 | 
			
		||||
const LOCKED_STATE_STR = 'screenShield.locked';
 | 
			
		||||
// fraction of screen height the arrow must reach before completing
 | 
			
		||||
// the slide up automatically
 | 
			
		||||
const ARROW_DRAG_THRESHOLD = 0.1;
 | 
			
		||||
@@ -214,6 +215,7 @@ const NotificationsBox = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        if (musicNotification != null &&
 | 
			
		||||
            this._musicBin.child == null) {
 | 
			
		||||
            musicNotification.acknowledged = true;
 | 
			
		||||
            if (musicNotification.actor.get_parent() != null)
 | 
			
		||||
                musicNotification.actor.get_parent().remove_actor(musicNotification.actor);
 | 
			
		||||
            this._musicBin.child = musicNotification.actor;
 | 
			
		||||
@@ -246,6 +248,7 @@ const NotificationsBox = new Lang.Class({
 | 
			
		||||
            sourceCountChangedId: 0,
 | 
			
		||||
            sourceTitleChangedId: 0,
 | 
			
		||||
            sourceUpdatedId: 0,
 | 
			
		||||
            sourceNotifyId: 0,
 | 
			
		||||
            musicNotification: null,
 | 
			
		||||
            sourceBox: null,
 | 
			
		||||
            titleLabel: null,
 | 
			
		||||
@@ -256,6 +259,12 @@ const NotificationsBox = new Lang.Class({
 | 
			
		||||
        this._showSource(source, obj, obj.sourceBox);
 | 
			
		||||
        this._notificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        if (obj.musicNotification) {
 | 
			
		||||
            obj.sourceNotifyId = source.connect('notify', Lang.bind(this, function(source, notification) {
 | 
			
		||||
                notification.acknowledged = true;
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        obj.sourceCountChangedId = source.connect('count-updated', Lang.bind(this, function(source) {
 | 
			
		||||
            this._countChanged(source, obj);
 | 
			
		||||
        }));
 | 
			
		||||
@@ -336,6 +345,8 @@ const NotificationsBox = new Lang.Class({
 | 
			
		||||
        if (obj.musicNotification) {
 | 
			
		||||
            this._musicBin.child = null;
 | 
			
		||||
            obj.musicNotification = null;
 | 
			
		||||
 | 
			
		||||
            source.disconnect(obj.sourceNotifyId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        source.disconnect(obj.sourceDestroyId);
 | 
			
		||||
@@ -1115,11 +1126,22 @@ const ScreenShield = new Lang.Class({
 | 
			
		||||
    deactivate: function(animate) {
 | 
			
		||||
        this._hideLockScreen(animate, 0);
 | 
			
		||||
 | 
			
		||||
        if (this._hasLockScreen)
 | 
			
		||||
            this._clearLockScreen();
 | 
			
		||||
 | 
			
		||||
        if (Main.sessionMode.currentMode == 'lock-screen')
 | 
			
		||||
            Main.sessionMode.popMode('lock-screen');
 | 
			
		||||
        if (Main.sessionMode.currentMode == 'unlock-dialog')
 | 
			
		||||
            Main.sessionMode.popMode('unlock-dialog');
 | 
			
		||||
 | 
			
		||||
        if (this._dialog && !this._isGreeter)
 | 
			
		||||
            this._dialog.popModal();
 | 
			
		||||
 | 
			
		||||
        if (this._isModal) {
 | 
			
		||||
            Main.popModal(this.actor);
 | 
			
		||||
            this._isModal = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Tweener.addTween(this._lockDialogGroup, {
 | 
			
		||||
            scale_x: 0,
 | 
			
		||||
            scale_y: 0,
 | 
			
		||||
@@ -1131,21 +1153,12 @@ const ScreenShield = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _completeDeactivate: function() {
 | 
			
		||||
        if (this._hasLockScreen)
 | 
			
		||||
            this._clearLockScreen();
 | 
			
		||||
 | 
			
		||||
        if (this._dialog && !this._isGreeter) {
 | 
			
		||||
            this._dialog.destroy();
 | 
			
		||||
            this._dialog = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._lightbox.hide();
 | 
			
		||||
 | 
			
		||||
        if (this._isModal) {
 | 
			
		||||
            Main.popModal(this.actor);
 | 
			
		||||
            this._isModal = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.actor.hide();
 | 
			
		||||
 | 
			
		||||
        if (this._becameActiveId != 0) {
 | 
			
		||||
@@ -1163,6 +1176,7 @@ const ScreenShield = new Lang.Class({
 | 
			
		||||
        this._isLocked = false;
 | 
			
		||||
        this.emit('active-changed');
 | 
			
		||||
        this.emit('locked-changed');
 | 
			
		||||
        global.set_runtime_state(LOCKED_STATE_STR, null);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activate: function(animate) {
 | 
			
		||||
@@ -1179,6 +1193,7 @@ const ScreenShield = new Lang.Class({
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._resetLockScreen(animate, animate);
 | 
			
		||||
        global.set_runtime_state(LOCKED_STATE_STR, GLib.Variant.new('b', true));
 | 
			
		||||
 | 
			
		||||
        // We used to set isActive and emit active-changed here,
 | 
			
		||||
        // but now we do that from lockScreenShown, which means
 | 
			
		||||
@@ -1205,5 +1220,15 @@ const ScreenShield = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this.emit('locked-changed');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // If the previous shell crashed, and gnome-session restarted us, then re-lock
 | 
			
		||||
    lockIfWasLocked: function() {
 | 
			
		||||
        let wasLocked = global.get_runtime_state('b', LOCKED_STATE_STR);
 | 
			
		||||
        if (wasLocked === null)
 | 
			
		||||
            return;
 | 
			
		||||
        Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
 | 
			
		||||
            this.lock(false);
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(ScreenShield.prototype);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										140
									
								
								js/ui/screencast.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								js/ui/screencast.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,140 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
 | 
			
		||||
const Hash = imports.misc.hash;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
 | 
			
		||||
const ScreencastIface = <interface name="org.gnome.Shell.Screencast">
 | 
			
		||||
<method name="Screencast">
 | 
			
		||||
    <arg type="s" direction="in" name="file_template"/>
 | 
			
		||||
    <arg type="a{sv}" direction="in" name="options"/>
 | 
			
		||||
    <arg type="b" direction="out" name="success"/>
 | 
			
		||||
    <arg type="s" direction="out" name="filename_used"/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name="ScreencastArea">
 | 
			
		||||
    <arg type="i" direction="in" name="x"/>
 | 
			
		||||
    <arg type="i" direction="in" name="y"/>
 | 
			
		||||
    <arg type="i" direction="in" name="width"/>
 | 
			
		||||
    <arg type="i" direction="in" name="height"/>
 | 
			
		||||
    <arg type="s" direction="in" name="file_template"/>
 | 
			
		||||
    <arg type="a{sv}" direction="in" name="options"/>
 | 
			
		||||
    <arg type="b" direction="out" name="success"/>
 | 
			
		||||
    <arg type="s" direction="out" name="filename_used"/>
 | 
			
		||||
</method>
 | 
			
		||||
<method name="StopScreencast">
 | 
			
		||||
    <arg type="b" direction="out" name="success"/>
 | 
			
		||||
</method>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const ScreencastService = new Lang.Class({
 | 
			
		||||
    Name: 'ScreencastService',
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreencastIface, this);
 | 
			
		||||
        this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Screencast');
 | 
			
		||||
 | 
			
		||||
        Gio.DBus.session.own_name('org.gnome.Shell.Screencast', Gio.BusNameOwnerFlags.REPLACE, null, null);
 | 
			
		||||
 | 
			
		||||
        this._recorders = new Hash.Map();
 | 
			
		||||
 | 
			
		||||
        Main.sessionMode.connect('updated',
 | 
			
		||||
                                 Lang.bind(this, this._sessionModeChanged));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _ensureRecorderForSender: function(sender) {
 | 
			
		||||
        let recorder = this._recorders.get(sender);
 | 
			
		||||
        if (!recorder) {
 | 
			
		||||
            recorder = new Shell.Recorder({ stage: global.stage });
 | 
			
		||||
            recorder._watchNameId =
 | 
			
		||||
                Gio.bus_watch_name(Gio.BusType.SESSION, sender, 0, null,
 | 
			
		||||
                                   Lang.bind(this, this._onNameVanished));
 | 
			
		||||
            this._recorders.set(sender, recorder);
 | 
			
		||||
        }
 | 
			
		||||
        return recorder;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _sessionModeChanged: function() {
 | 
			
		||||
        if (Main.sessionMode.allowScreencast)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        for (let sender in this._recorders.keys())
 | 
			
		||||
            this._recorders.delete(sender);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onNameVanished: function(connection, name) {
 | 
			
		||||
        this._stopRecordingForSender(name);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _stopRecordingForSender: function(sender) {
 | 
			
		||||
        let recorder = this._recorders.get(sender);
 | 
			
		||||
        if (!recorder)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        Gio.bus_unwatch_name(recorder._watchNameId);
 | 
			
		||||
        recorder.close();
 | 
			
		||||
        this._recorders.delete(sender);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _applyOptionalParameters: function(recorder, options) {
 | 
			
		||||
        for (let option in options)
 | 
			
		||||
            options[option] = options[option].deep_unpack();
 | 
			
		||||
 | 
			
		||||
        if (options['pipeline'])
 | 
			
		||||
            recorder.set_pipeline(options['pipeline']);
 | 
			
		||||
        if (options['framerate'])
 | 
			
		||||
            recorder.set_framerate(options['framerate']);
 | 
			
		||||
        if (options['draw-cursor'])
 | 
			
		||||
            recorder.set_draw_cursor(options['draw-cursor']);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    ScreencastAsync: function(params, invocation) {
 | 
			
		||||
        let returnValue = [false, ''];
 | 
			
		||||
        if (!Main.sessionMode.allowScreencast)
 | 
			
		||||
            invocation.return_value(GLib.Variant.new('(bs)', returnValue));
 | 
			
		||||
 | 
			
		||||
        let sender = invocation.get_sender();
 | 
			
		||||
        let recorder = this._ensureRecorderForSender(sender);
 | 
			
		||||
        if (!recorder.is_recording()) {
 | 
			
		||||
            let [fileTemplate, options] = params;
 | 
			
		||||
 | 
			
		||||
            recorder.set_file_template(fileTemplate);
 | 
			
		||||
            this._applyOptionalParameters(recorder, options);
 | 
			
		||||
            let [success, fileName] = recorder.record();
 | 
			
		||||
            returnValue = [success, fileName ? fileName : ''];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        invocation.return_value(GLib.Variant.new('(bs)', returnValue));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    ScreencastAreaAsync: function(params, invocation) {
 | 
			
		||||
        let returnValue = [false, ''];
 | 
			
		||||
        if (!Main.sessionMode.allowScreencast)
 | 
			
		||||
            invocation.return_value(GLib.Variant.new('(bs)', returnValue));
 | 
			
		||||
 | 
			
		||||
        let sender = invocation.get_sender();
 | 
			
		||||
        let recorder = this._ensureRecorderForSender(sender);
 | 
			
		||||
 | 
			
		||||
        if (!recorder.is_recording()) {
 | 
			
		||||
            let [x, y, width, height, fileTemplate, options] = params;
 | 
			
		||||
 | 
			
		||||
            recorder.set_file_template(fileTemplate);
 | 
			
		||||
            recorder.set_area(x, y, width, height);
 | 
			
		||||
            this._applyOptionalParameters(recorder, options);
 | 
			
		||||
            let [success, fileName] = recorder.record();
 | 
			
		||||
            returnValue = [success, fileName ? fileName : ''];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        invocation.return_value(GLib.Variant.new('(bs)', returnValue));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    StopScreencastAsync: function(params, invocation) {
 | 
			
		||||
        let success = this._stopRecordingForSender(invocation.get_sender());
 | 
			
		||||
        invocation.return_value(GLib.Variant.new('(b)', [success]));
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
@@ -51,7 +51,7 @@ const SearchSystem = new Lang.Class({
 | 
			
		||||
        this._previousResults = [];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    pushResults: function(provider, results) {
 | 
			
		||||
    setResults: function(provider, results) {
 | 
			
		||||
        let i = this._providers.indexOf(provider);
 | 
			
		||||
        if (i == -1)
 | 
			
		||||
            return;
 | 
			
		||||
 
 | 
			
		||||
@@ -180,13 +180,82 @@ const GridSearchResult = new Lang.Class({
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const ListSearchResults = new Lang.Class({
 | 
			
		||||
    Name: 'ListSearchResults',
 | 
			
		||||
const SearchResultsBase = new Lang.Class({
 | 
			
		||||
    Name: 'SearchResultsBase',
 | 
			
		||||
 | 
			
		||||
    _init: function(provider) {
 | 
			
		||||
        this.provider = provider;
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.BoxLayout({ style_class: 'search-section-content' });
 | 
			
		||||
        this._terms = [];
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.BoxLayout({ style_class: 'search-section',
 | 
			
		||||
                                        vertical: true });
 | 
			
		||||
 | 
			
		||||
        this._resultDisplayBin = new St.Bin({ x_fill: true,
 | 
			
		||||
                                              y_fill: true });
 | 
			
		||||
        this.actor.add(this._resultDisplayBin, { expand: true });
 | 
			
		||||
 | 
			
		||||
        let separator = new Separator.HorizontalSeparator({ style_class: 'search-section-separator' });
 | 
			
		||||
        this.actor.add(separator.actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
        this.actor.destroy();
 | 
			
		||||
        this._terms = [];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _clearResultDisplay: function() {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    clear: function() {
 | 
			
		||||
        this._clearResultDisplay();
 | 
			
		||||
        this.actor.hide();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _keyFocusIn: function(icon) {
 | 
			
		||||
        this.emit('key-focus-in', icon);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _setMoreIconVisible: function(visible) {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    updateSearch: function(providerResults, terms, callback) {
 | 
			
		||||
        this._terms = terms;
 | 
			
		||||
 | 
			
		||||
        if (providerResults.length == 0) {
 | 
			
		||||
            this._clearResultDisplay();
 | 
			
		||||
            this.actor.hide();
 | 
			
		||||
            callback();
 | 
			
		||||
        } else {
 | 
			
		||||
            let maxResults = this._getMaxDisplayedResults();
 | 
			
		||||
            let results = providerResults.slice(0, maxResults);
 | 
			
		||||
            let hasMoreResults = results.length < providerResults.length;
 | 
			
		||||
 | 
			
		||||
            this.provider.getResultMetas(results, Lang.bind(this, function(metas) {
 | 
			
		||||
                this.clear();
 | 
			
		||||
 | 
			
		||||
                // To avoid CSS transitions causing flickering when
 | 
			
		||||
                // the first search result stays the same, we hide the
 | 
			
		||||
                // content while filling in the results.
 | 
			
		||||
                this.actor.hide();
 | 
			
		||||
                this._clearResultDisplay();
 | 
			
		||||
                this._renderResults(metas);
 | 
			
		||||
                this._setMoreIconVisible(hasMoreResults && this.provider.canLaunchSearch);
 | 
			
		||||
                this.actor.show();
 | 
			
		||||
                callback();
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const ListSearchResults = new Lang.Class({
 | 
			
		||||
    Name: 'ListSearchResults',
 | 
			
		||||
    Extends: SearchResultsBase,
 | 
			
		||||
 | 
			
		||||
    _init: function(provider) {
 | 
			
		||||
        this.parent(provider);
 | 
			
		||||
 | 
			
		||||
        this._container = new St.BoxLayout({ style_class: 'search-section-content' });
 | 
			
		||||
        this.providerIcon = new ProviderIcon(provider);
 | 
			
		||||
        this.providerIcon.connect('clicked', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
@@ -194,48 +263,27 @@ const ListSearchResults = new Lang.Class({
 | 
			
		||||
                Main.overview.toggle();
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        this.actor.add(this.providerIcon, { x_fill: false,
 | 
			
		||||
                                            y_fill: false,
 | 
			
		||||
                                            x_align: St.Align.START,
 | 
			
		||||
                                            y_align: St.Align.START });
 | 
			
		||||
        this._container.add(this.providerIcon, { x_fill: false,
 | 
			
		||||
                                                 y_fill: false,
 | 
			
		||||
                                                 x_align: St.Align.START,
 | 
			
		||||
                                                 y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
        this._content = new St.BoxLayout({ style_class: 'list-search-results',
 | 
			
		||||
                                           vertical: true });
 | 
			
		||||
        this.actor.add(this._content, { expand: true });
 | 
			
		||||
        this._container.add(this._content, { expand: true });
 | 
			
		||||
 | 
			
		||||
        this._notDisplayedResult = [];
 | 
			
		||||
        this._terms = [];
 | 
			
		||||
        this._pendingClear = false;
 | 
			
		||||
        this._resultDisplayBin.set_child(this._container);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getResultsForDisplay: function() {
 | 
			
		||||
        let alreadyVisible = this._pendingClear ? 0 : this.getVisibleResultCount();
 | 
			
		||||
        let canDisplay = MAX_LIST_SEARCH_RESULTS_ROWS - alreadyVisible;
 | 
			
		||||
 | 
			
		||||
        let newResults = this._notDisplayedResult.splice(0, canDisplay);
 | 
			
		||||
        return newResults;
 | 
			
		||||
    _setMoreIconVisible: function(visible) {
 | 
			
		||||
        this.providerIcon.moreIcon.visible = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getVisibleResultCount: function() {
 | 
			
		||||
        return this._content.get_n_children();
 | 
			
		||||
    _getMaxDisplayedResults: function() {
 | 
			
		||||
        return MAX_LIST_SEARCH_RESULTS_ROWS;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hasMoreResults: function() {
 | 
			
		||||
        return this._notDisplayedResult.length > 0;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setResults: function(results, terms) {
 | 
			
		||||
        // copy the lists
 | 
			
		||||
        this._notDisplayedResult = results.slice(0);
 | 
			
		||||
        this._terms = terms.slice(0);
 | 
			
		||||
        this._pendingClear = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _keyFocusIn: function(icon) {
 | 
			
		||||
        this.emit('key-focus-in', icon);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    renderResults: function(metas) {
 | 
			
		||||
    _renderResults: function(metas) {
 | 
			
		||||
        for (let i = 0; i < metas.length; i++) {
 | 
			
		||||
            let display = new ListSearchResult(this.provider, metas[i], this._terms);
 | 
			
		||||
            display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
 | 
			
		||||
@@ -243,13 +291,12 @@ const ListSearchResults = new Lang.Class({
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    clear: function () {
 | 
			
		||||
    _clearResultDisplay: function () {
 | 
			
		||||
        this._content.destroy_all_children();
 | 
			
		||||
        this._pendingClear = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getFirstResult: function() {
 | 
			
		||||
        if (this.getVisibleResultCount() > 0)
 | 
			
		||||
        if (this._content.get_n_children() > 0)
 | 
			
		||||
            return this._content.get_child_at_index(0)._delegate;
 | 
			
		||||
        else
 | 
			
		||||
            return null;
 | 
			
		||||
@@ -259,50 +306,24 @@ Signals.addSignalMethods(ListSearchResults.prototype);
 | 
			
		||||
 | 
			
		||||
const GridSearchResults = new Lang.Class({
 | 
			
		||||
    Name: 'GridSearchResults',
 | 
			
		||||
    Extends: SearchResultsBase,
 | 
			
		||||
 | 
			
		||||
    _init: function(provider) {
 | 
			
		||||
        this.provider = provider;
 | 
			
		||||
        this.parent(provider);
 | 
			
		||||
 | 
			
		||||
        this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
 | 
			
		||||
                                             xAlign: St.Align.START });
 | 
			
		||||
        this.actor = new St.Bin({ x_align: St.Align.MIDDLE });
 | 
			
		||||
        this._bin = new St.Bin({ x_align: St.Align.MIDDLE });
 | 
			
		||||
        this._bin.set_child(this._grid.actor);
 | 
			
		||||
 | 
			
		||||
        this.actor.set_child(this._grid.actor);
 | 
			
		||||
 | 
			
		||||
        this._notDisplayedResult = [];
 | 
			
		||||
        this._terms = [];
 | 
			
		||||
        this._pendingClear = false;
 | 
			
		||||
        this._resultDisplayBin.set_child(this._bin);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getResultsForDisplay: function() {
 | 
			
		||||
        let alreadyVisible = this._pendingClear ? 0 : this._grid.visibleItemsCount();
 | 
			
		||||
        let canDisplay = this._grid.childrenInRow(this.actor.width) * this._grid.getRowLimit()
 | 
			
		||||
                         - alreadyVisible;
 | 
			
		||||
 | 
			
		||||
        let newResults = this._notDisplayedResult.splice(0, canDisplay);
 | 
			
		||||
        return newResults;
 | 
			
		||||
    _getMaxDisplayedResults: function() {
 | 
			
		||||
        return this._grid.childrenInRow(this._bin.width) * this._grid.getRowLimit();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getVisibleResultCount: function() {
 | 
			
		||||
        return this._grid.visibleItemsCount();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hasMoreResults: function() {
 | 
			
		||||
        return this._notDisplayedResult.length > 0;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setResults: function(results, terms) {
 | 
			
		||||
        // copy the lists
 | 
			
		||||
        this._notDisplayedResult = results.slice(0);
 | 
			
		||||
        this._terms = terms.slice(0);
 | 
			
		||||
        this._pendingClear = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _keyFocusIn: function(icon) {
 | 
			
		||||
        this.emit('key-focus-in', icon);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    renderResults: function(metas) {
 | 
			
		||||
    _renderResults: function(metas) {
 | 
			
		||||
        for (let i = 0; i < metas.length; i++) {
 | 
			
		||||
            let display = new GridSearchResult(this.provider, metas[i], this._terms);
 | 
			
		||||
            display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
 | 
			
		||||
@@ -310,13 +331,12 @@ const GridSearchResults = new Lang.Class({
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    clear: function () {
 | 
			
		||||
    _clearResultDisplay: function () {
 | 
			
		||||
        this._grid.removeAll();
 | 
			
		||||
        this._pendingClear = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getFirstResult: function() {
 | 
			
		||||
        if (this.getVisibleResultCount() > 0)
 | 
			
		||||
        if (this._grid.visibleItemsCount() > 0)
 | 
			
		||||
            return this._grid.getItemAtIndex(0)._delegate;
 | 
			
		||||
        else
 | 
			
		||||
            return null;
 | 
			
		||||
@@ -366,9 +386,9 @@ const SearchResults = new Lang.Class({
 | 
			
		||||
        this._content.add(this._statusBin, { expand: true });
 | 
			
		||||
        this._statusBin.add_actor(this._statusText);
 | 
			
		||||
        this._providers = this._searchSystem.getProviders();
 | 
			
		||||
        this._providerMeta = [];
 | 
			
		||||
        this._providerDisplays = {};
 | 
			
		||||
        for (let i = 0; i < this._providers.length; i++) {
 | 
			
		||||
            this.createProviderMeta(this._providers[i]);
 | 
			
		||||
            this.createProviderDisplay(this._providers[i]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._highlightDefault = false;
 | 
			
		||||
@@ -386,61 +406,33 @@ const SearchResults = new Lang.Class({
 | 
			
		||||
        Util.ensureActorVisibleInScrollView(this._scrollView, icon);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createProviderMeta: function(provider) {
 | 
			
		||||
        let providerBox = new St.BoxLayout({ style_class: 'search-section',
 | 
			
		||||
                                             vertical: true });
 | 
			
		||||
        let providerIcon = null;
 | 
			
		||||
        let resultDisplay = null;
 | 
			
		||||
    createProviderDisplay: function(provider) {
 | 
			
		||||
        let providerDisplay = null;
 | 
			
		||||
 | 
			
		||||
        if (provider.appInfo) {
 | 
			
		||||
            resultDisplay = new ListSearchResults(provider);
 | 
			
		||||
            providerIcon = resultDisplay.providerIcon;
 | 
			
		||||
            providerDisplay = new ListSearchResults(provider);
 | 
			
		||||
        } else {
 | 
			
		||||
            resultDisplay = new GridSearchResults(provider);
 | 
			
		||||
            providerDisplay = new GridSearchResults(provider);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        resultDisplay.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
 | 
			
		||||
 | 
			
		||||
        let resultDisplayBin = new St.Bin({ child: resultDisplay.actor,
 | 
			
		||||
                                            x_fill: true,
 | 
			
		||||
                                            y_fill: true });
 | 
			
		||||
        providerBox.add(resultDisplayBin, { expand: true });
 | 
			
		||||
 | 
			
		||||
        let separator = new Separator.HorizontalSeparator({ style_class: 'search-section-separator' });
 | 
			
		||||
        providerBox.add(separator.actor);
 | 
			
		||||
 | 
			
		||||
        this._providerMeta.push({ provider: provider,
 | 
			
		||||
                                  actor: providerBox,
 | 
			
		||||
                                  icon: providerIcon,
 | 
			
		||||
                                  resultDisplay: resultDisplay });
 | 
			
		||||
        this._content.add(providerBox);
 | 
			
		||||
        providerDisplay.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
 | 
			
		||||
        this._providerDisplays[provider.id] = providerDisplay;
 | 
			
		||||
        this._content.add(providerDisplay.actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroyProviderMeta: function(provider) {
 | 
			
		||||
        for (let i=0; i < this._providerMeta.length; i++) {
 | 
			
		||||
            let meta = this._providerMeta[i];
 | 
			
		||||
            if (meta.provider == provider) {
 | 
			
		||||
                meta.actor.destroy();
 | 
			
		||||
                this._providerMeta.splice(i, 1);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    destroyProviderDisplay: function(provider) {
 | 
			
		||||
        this._providerDisplays[provider.id].destroy();
 | 
			
		||||
        delete this._providerDisplays[provider.id];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _clearDisplay: function() {
 | 
			
		||||
        for (let i = 0; i < this._providerMeta.length; i++) {
 | 
			
		||||
            let meta = this._providerMeta[i];
 | 
			
		||||
            meta.resultDisplay.clear();
 | 
			
		||||
            meta.actor.hide();
 | 
			
		||||
        for (let i = 0; i < this._providers.length; i++) {
 | 
			
		||||
            let provider = this._providers[i];
 | 
			
		||||
            let providerDisplay = this._providerDisplays[provider.id];
 | 
			
		||||
            providerDisplay.clear();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _clearDisplayForProvider: function(provider) {
 | 
			
		||||
        let meta = this._metaForProvider(provider);
 | 
			
		||||
        meta.resultDisplay.clear();
 | 
			
		||||
        meta.actor.hide();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    reset: function() {
 | 
			
		||||
        this._searchSystem.reset();
 | 
			
		||||
        this._statusBin.hide();
 | 
			
		||||
@@ -454,20 +446,17 @@ const SearchResults = new Lang.Class({
 | 
			
		||||
        this._statusBin.show();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _metaForProvider: function(provider) {
 | 
			
		||||
        return this._providerMeta[this._providers.indexOf(provider)];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _maybeSetInitialSelection: function() {
 | 
			
		||||
        let newDefaultResult = null;
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._providerMeta.length; i++) {
 | 
			
		||||
            let meta = this._providerMeta[i];
 | 
			
		||||
        for (let i = 0; i < this._providers.length; i++) {
 | 
			
		||||
            let provider = this._providers[i];
 | 
			
		||||
            let display = this._providerDisplays[provider.id];
 | 
			
		||||
 | 
			
		||||
            if (!meta.actor.visible)
 | 
			
		||||
            if (!display.actor.visible)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            let firstResult = meta.resultDisplay.getFirstResult();
 | 
			
		||||
            let firstResult = display.getFirstResult();
 | 
			
		||||
            if (firstResult) {
 | 
			
		||||
                newDefaultResult = firstResult;
 | 
			
		||||
                break; // select this one!
 | 
			
		||||
@@ -487,11 +476,14 @@ const SearchResults = new Lang.Class({
 | 
			
		||||
    _updateStatusText: function () {
 | 
			
		||||
        let haveResults = false;
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._providerMeta.length; ++i)
 | 
			
		||||
            if (this._providerMeta[i].resultDisplay.getFirstResult()) {
 | 
			
		||||
        for (let i = 0; i < this._providers.length; i++) {
 | 
			
		||||
            let provider = this._providers[i];
 | 
			
		||||
            let display = this._providerDisplays[provider.id];
 | 
			
		||||
            if (display.getFirstResult()) {
 | 
			
		||||
                haveResults = true;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!haveResults) {
 | 
			
		||||
            this._statusText.set_text(_("No results."));
 | 
			
		||||
@@ -504,42 +496,12 @@ const SearchResults = new Lang.Class({
 | 
			
		||||
    _updateResults: function(searchSystem, results) {
 | 
			
		||||
        let terms = searchSystem.getTerms();
 | 
			
		||||
        let [provider, providerResults] = results;
 | 
			
		||||
        let meta = this._metaForProvider(provider);
 | 
			
		||||
        let display = this._providerDisplays[provider.id];
 | 
			
		||||
 | 
			
		||||
        if (providerResults.length == 0) {
 | 
			
		||||
            this._clearDisplayForProvider(provider);
 | 
			
		||||
            meta.resultDisplay.setResults([], []);
 | 
			
		||||
        display.updateSearch(providerResults, terms, Lang.bind(this, function() {
 | 
			
		||||
            this._maybeSetInitialSelection();
 | 
			
		||||
            this._updateStatusText();
 | 
			
		||||
        } else {
 | 
			
		||||
            meta.resultDisplay.setResults(providerResults, terms);
 | 
			
		||||
            let results = meta.resultDisplay.getResultsForDisplay();
 | 
			
		||||
 | 
			
		||||
            if (meta.icon)
 | 
			
		||||
                meta.icon.moreIcon.visible =
 | 
			
		||||
                    meta.resultDisplay.hasMoreResults() &&
 | 
			
		||||
                    provider.canLaunchSearch;
 | 
			
		||||
 | 
			
		||||
            provider.getResultMetas(results, Lang.bind(this, function(metas) {
 | 
			
		||||
                this._clearDisplayForProvider(provider);
 | 
			
		||||
                meta.actor.show();
 | 
			
		||||
 | 
			
		||||
                // Hiding drops the key focus if we have it
 | 
			
		||||
                let focus = global.stage.get_key_focus();
 | 
			
		||||
                // To avoid CSS transitions causing flickering when
 | 
			
		||||
                // the first search result stays the same, we hide the
 | 
			
		||||
                // content while filling in the results.
 | 
			
		||||
                this._content.hide();
 | 
			
		||||
 | 
			
		||||
                meta.resultDisplay.renderResults(metas);
 | 
			
		||||
                this._maybeSetInitialSelection();
 | 
			
		||||
                this._updateStatusText();
 | 
			
		||||
 | 
			
		||||
                this._content.show();
 | 
			
		||||
                if (this._content.contains(focus))
 | 
			
		||||
                    global.stage.set_key_focus(focus);
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activateDefault: function() {
 | 
			
		||||
 
 | 
			
		||||
@@ -42,10 +42,10 @@ const _modes = {
 | 
			
		||||
        hasNotifications: true,
 | 
			
		||||
        isGreeter: true,
 | 
			
		||||
        isPrimary: true,
 | 
			
		||||
        unlockDialog: imports.gdm.loginDialog.LoginDialog,
 | 
			
		||||
        unlockDialog: imports.ui.auth.loginDialog.LoginDialog,
 | 
			
		||||
        components: ['polkitAgent'],
 | 
			
		||||
        panel: {
 | 
			
		||||
            left: ['logo'],
 | 
			
		||||
            left: [],
 | 
			
		||||
            center: ['dateMenu'],
 | 
			
		||||
            right: ['a11yGreeter', 'display', 'keyboard',
 | 
			
		||||
                    'volume', 'battery', 'powerMenu']
 | 
			
		||||
@@ -78,17 +78,6 @@ const _modes = {
 | 
			
		||||
        panelStyle: 'unlock-screen'
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    'initial-setup': {
 | 
			
		||||
        hasWindows: true,
 | 
			
		||||
        isPrimary: true,
 | 
			
		||||
        components: ['networkAgent', 'keyring'],
 | 
			
		||||
        panel: {
 | 
			
		||||
            left: [],
 | 
			
		||||
            center: ['dateMenu'],
 | 
			
		||||
            right: ['a11yGreeter', 'keyboard', 'volume', 'battery']
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    'user': {
 | 
			
		||||
        hasOverview: true,
 | 
			
		||||
        showCalendarEvents: true,
 | 
			
		||||
@@ -100,7 +89,7 @@ const _modes = {
 | 
			
		||||
        hasNotifications: true,
 | 
			
		||||
        isLocked: false,
 | 
			
		||||
        isPrimary: true,
 | 
			
		||||
        unlockDialog: imports.ui.unlockDialog.UnlockDialog,
 | 
			
		||||
        unlockDialog: imports.ui.auth.unlockDialog.UnlockDialog,
 | 
			
		||||
        components: ['networkAgent', 'polkitAgent', 'telepathyClient',
 | 
			
		||||
                     'keyring', 'recorder', 'autorunManager', 'automountManager'],
 | 
			
		||||
        panel: {
 | 
			
		||||
@@ -195,6 +184,10 @@ const SessionMode = new Lang.Class({
 | 
			
		||||
        return this._modeStack[this._modeStack.length - 1];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get allowScreencast() {
 | 
			
		||||
        return this.components.indexOf('recorder') != -1;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _sync: function() {
 | 
			
		||||
        let params = this._modes[this.currentMode];
 | 
			
		||||
        let defaults;
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ const ExtensionDownloader = imports.ui.extensionDownloader;
 | 
			
		||||
const ExtensionUtils = imports.misc.extensionUtils;
 | 
			
		||||
const Hash = imports.misc.hash;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Screencast = imports.ui.screencast;
 | 
			
		||||
const Screenshot = imports.ui.screenshot;
 | 
			
		||||
 | 
			
		||||
const GnomeShellIface = <interface name="org.gnome.Shell">
 | 
			
		||||
@@ -20,6 +21,7 @@ const GnomeShellIface = <interface name="org.gnome.Shell">
 | 
			
		||||
    <arg type="b" direction="out" name="success" />
 | 
			
		||||
    <arg type="s" direction="out" name="result" />
 | 
			
		||||
</method>
 | 
			
		||||
<method name="FocusSearch"/>
 | 
			
		||||
<method name="ShowOSD">
 | 
			
		||||
    <arg type="a{sv}" direction="in" name="params"/>
 | 
			
		||||
</method>
 | 
			
		||||
@@ -70,6 +72,7 @@ const GnomeShell = new Lang.Class({
 | 
			
		||||
        this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
 | 
			
		||||
 | 
			
		||||
        this._extensionsService = new GnomeShellExtensions();
 | 
			
		||||
        this._screencastService = new Screencast.ScreencastService();
 | 
			
		||||
        this._screenshotService = new Screenshot.ScreenshotService();
 | 
			
		||||
 | 
			
		||||
        this._grabbedAccelerators = new Hash.Map();
 | 
			
		||||
@@ -97,7 +100,7 @@ const GnomeShell = new Lang.Class({
 | 
			
		||||
     */
 | 
			
		||||
    Eval: function(code) {
 | 
			
		||||
        if (!global.settings.get_boolean('development-tools'))
 | 
			
		||||
            return [false, null];
 | 
			
		||||
            return [false, ''];
 | 
			
		||||
 | 
			
		||||
        let returnValue;
 | 
			
		||||
        let success;
 | 
			
		||||
@@ -114,6 +117,10 @@ const GnomeShell = new Lang.Class({
 | 
			
		||||
        return [success, returnValue];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    FocusSearch: function() {
 | 
			
		||||
        Main.overview.focusSearch();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    ShowOSD: function(params) {
 | 
			
		||||
        for (let param in params)
 | 
			
		||||
            params[param] = params[param].deep_unpack();
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,7 @@ const EntryMenu = new Lang.Class({
 | 
			
		||||
    Name: 'ShellEntryMenu',
 | 
			
		||||
    Extends: PopupMenu.PopupMenu,
 | 
			
		||||
 | 
			
		||||
    _init: function(entry, params) {
 | 
			
		||||
        params = Params.parse (params, { isPassword: false });
 | 
			
		||||
 | 
			
		||||
    _init: function(entry) {
 | 
			
		||||
        this.parent(entry, 0, St.Side.TOP);
 | 
			
		||||
 | 
			
		||||
        this.actor.add_style_class_name('entry-context-menu');
 | 
			
		||||
@@ -37,8 +35,6 @@ const EntryMenu = new Lang.Class({
 | 
			
		||||
        this._pasteItem = item;
 | 
			
		||||
 | 
			
		||||
        this._passwordItem = null;
 | 
			
		||||
        if (params.isPassword)
 | 
			
		||||
	    this._makePasswordItem();
 | 
			
		||||
 | 
			
		||||
        Main.uiGroup.add_actor(this.actor);
 | 
			
		||||
        this.actor.hide();
 | 
			
		||||
@@ -53,19 +49,21 @@ const EntryMenu = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get isPassword() {
 | 
			
		||||
	return this._passwordItem != null;
 | 
			
		||||
        return this._passwordItem != null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    set isPassword(v) {
 | 
			
		||||
	if (v == this.isPassword)
 | 
			
		||||
	    return;
 | 
			
		||||
        if (v == this.isPassword)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
	if (v)
 | 
			
		||||
	    this._makePasswordItem();
 | 
			
		||||
	else {
 | 
			
		||||
	    this._passwordItem.destroy();
 | 
			
		||||
	    this._passwordItem = null;
 | 
			
		||||
	}
 | 
			
		||||
        if (v) {
 | 
			
		||||
            this._makePasswordItem();
 | 
			
		||||
            this._entry.input_purpose = Gtk.InputPurpose.PASSWORD;
 | 
			
		||||
        } else {
 | 
			
		||||
            this._passwordItem.destroy();
 | 
			
		||||
            this._passwordItem = null;
 | 
			
		||||
            this._entry.input_purpose = Gtk.InputPurpose.FREE_FORM;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    open: function(animate) {
 | 
			
		||||
@@ -155,7 +153,10 @@ function addContextMenu(entry, params) {
 | 
			
		||||
    if (entry.menu)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    entry.menu = new EntryMenu(entry, params);
 | 
			
		||||
    params = Params.parse (params, { isPassword: false });
 | 
			
		||||
 | 
			
		||||
    entry.menu = new EntryMenu(entry);
 | 
			
		||||
    entry.menu.isPassword = params.isPassword;
 | 
			
		||||
    entry._menuManager = new PopupMenu.PopupMenuManager({ actor: entry });
 | 
			
		||||
    entry._menuManager.addMenu(entry.menu);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -363,7 +363,7 @@ const ConfirmNotification = new Lang.Class({
 | 
			
		||||
        this._applet = applet;
 | 
			
		||||
        this._devicePath = device_path;
 | 
			
		||||
        this.addBody(_("Device %s wants to pair with this computer").format(long_name));
 | 
			
		||||
        this.addBody(_("Please confirm whether the PIN '%06d' matches the one on the device.").format(pin));
 | 
			
		||||
        this.addBody(_("Please confirm whether the Passkey '%06d' matches the one on the device.").format(pin));
 | 
			
		||||
 | 
			
		||||
        /* Translators: this is the verb, not the noun */
 | 
			
		||||
        this.addButton('matches', _("Matches"));
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,33 @@ const KEY_INPUT_SOURCES = 'sources';
 | 
			
		||||
const INPUT_SOURCE_TYPE_XKB = 'xkb';
 | 
			
		||||
const INPUT_SOURCE_TYPE_IBUS = 'ibus';
 | 
			
		||||
 | 
			
		||||
// This is the longest we'll keep the keyboard frozen until an input
 | 
			
		||||
// source is active.
 | 
			
		||||
const MAX_INPUT_SOURCE_ACTIVATION_TIME = 4000; // ms
 | 
			
		||||
 | 
			
		||||
const BUS_NAME = 'org.gnome.SettingsDaemon.Keyboard';
 | 
			
		||||
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Keyboard';
 | 
			
		||||
 | 
			
		||||
const KeyboardManagerInterface =
 | 
			
		||||
<interface name="org.gnome.SettingsDaemon.Keyboard">
 | 
			
		||||
<method name="SetInputSource">
 | 
			
		||||
    <arg type="u" direction="in" />
 | 
			
		||||
</method>
 | 
			
		||||
</interface>;
 | 
			
		||||
 | 
			
		||||
const KeyboardManagerProxy = Gio.DBusProxy.makeProxyWrapper(KeyboardManagerInterface);
 | 
			
		||||
 | 
			
		||||
function releaseKeyboard() {
 | 
			
		||||
    if (Main.modalCount > 0)
 | 
			
		||||
        global.display.unfreeze_keyboard(global.get_current_time());
 | 
			
		||||
    else
 | 
			
		||||
        global.display.ungrab_keyboard(global.get_current_time());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function holdKeyboard() {
 | 
			
		||||
    global.freeze_keyboard(global.get_current_time());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const IBusManager = new Lang.Class({
 | 
			
		||||
    Name: 'IBusManager',
 | 
			
		||||
 | 
			
		||||
@@ -45,26 +72,24 @@ const IBusManager = new Lang.Class({
 | 
			
		||||
        this._readyCallback = readyCallback;
 | 
			
		||||
        this._candidatePopup = new IBusCandidatePopup.CandidatePopup();
 | 
			
		||||
 | 
			
		||||
        this._ibus = null;
 | 
			
		||||
        this._panelService = null;
 | 
			
		||||
        this._engines = {};
 | 
			
		||||
        this._ready = false;
 | 
			
		||||
        this._registerPropertiesId = 0;
 | 
			
		||||
        this._currentEngineName = null;
 | 
			
		||||
 | 
			
		||||
        this._nameWatcherId = Gio.DBus.session.watch_name(IBus.SERVICE_IBUS,
 | 
			
		||||
                                                          Gio.BusNameWatcherFlags.NONE,
 | 
			
		||||
                                                          Lang.bind(this, this._onNameAppeared),
 | 
			
		||||
                                                          Lang.bind(this, this._clear));
 | 
			
		||||
        this._ibus = IBus.Bus.new_async();
 | 
			
		||||
        this._ibus.connect('connected', Lang.bind(this, this._onConnected));
 | 
			
		||||
        this._ibus.connect('disconnected', Lang.bind(this, this._clear));
 | 
			
		||||
        // Need to set this to get 'global-engine-changed' emitions
 | 
			
		||||
        this._ibus.set_watch_ibus_signal(true);
 | 
			
		||||
        this._ibus.connect('global-engine-changed', Lang.bind(this, this._engineChanged));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _clear: function() {
 | 
			
		||||
        if (this._panelService)
 | 
			
		||||
            this._panelService.destroy();
 | 
			
		||||
        if (this._ibus)
 | 
			
		||||
            this._ibus.destroy();
 | 
			
		||||
 | 
			
		||||
        this._ibus = null;
 | 
			
		||||
        this._panelService = null;
 | 
			
		||||
        this._candidatePopup.setPanelService(null);
 | 
			
		||||
        this._engines = {};
 | 
			
		||||
@@ -76,18 +101,12 @@ const IBusManager = new Lang.Class({
 | 
			
		||||
            this._readyCallback(false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onNameAppeared: function() {
 | 
			
		||||
        this._ibus = IBus.Bus.new_async();
 | 
			
		||||
        this._ibus.connect('connected', Lang.bind(this, this._onConnected));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onConnected: function() {
 | 
			
		||||
        this._ibus.list_engines_async(-1, null, Lang.bind(this, this._initEngines));
 | 
			
		||||
        this._ibus.request_name_async(IBus.SERVICE_PANEL,
 | 
			
		||||
                                      IBus.BusNameFlag.REPLACE_EXISTING,
 | 
			
		||||
                                      -1, null,
 | 
			
		||||
                                      Lang.bind(this, this._initPanelService));
 | 
			
		||||
        this._ibus.connect('disconnected', Lang.bind(this, this._clear));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _initEngines: function(ibus, result) {
 | 
			
		||||
@@ -109,9 +128,6 @@ const IBusManager = new Lang.Class({
 | 
			
		||||
            this._panelService = new IBus.PanelService({ connection: this._ibus.get_connection(),
 | 
			
		||||
                                                         object_path: IBus.PATH_PANEL });
 | 
			
		||||
            this._candidatePopup.setPanelService(this._panelService);
 | 
			
		||||
            // Need to set this to get 'global-engine-changed' emitions
 | 
			
		||||
            this._ibus.set_watch_ibus_signal(true);
 | 
			
		||||
            this._ibus.connect('global-engine-changed', Lang.bind(this, this._engineChanged));
 | 
			
		||||
            this._panelService.connect('update-property', Lang.bind(this, this._updateProperty));
 | 
			
		||||
            // If an engine is already active we need to get its properties
 | 
			
		||||
            this._ibus.get_global_engine_async(-1, null, Lang.bind(this, function(i, result) {
 | 
			
		||||
@@ -140,6 +156,9 @@ const IBusManager = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _engineChanged: function(bus, engineName) {
 | 
			
		||||
        if (!this._ready)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._currentEngineName = engineName;
 | 
			
		||||
 | 
			
		||||
        if (this._registerPropertiesId != 0)
 | 
			
		||||
@@ -337,14 +356,14 @@ const InputSourceIndicator = new Lang.Class({
 | 
			
		||||
            Main.wm.addKeybinding('switch-input-source',
 | 
			
		||||
                                  new Gio.Settings({ schema: "org.gnome.desktop.wm.keybindings" }),
 | 
			
		||||
                                  Meta.KeyBindingFlags.REVERSES,
 | 
			
		||||
                                  Shell.KeyBindingMode.ALL & ~Shell.KeyBindingMode.MESSAGE_TRAY,
 | 
			
		||||
                                  Shell.KeyBindingMode.ALL,
 | 
			
		||||
                                  Lang.bind(this, this._switchInputSource));
 | 
			
		||||
        this._keybindingActionBackward =
 | 
			
		||||
            Main.wm.addKeybinding('switch-input-source-backward',
 | 
			
		||||
                                  new Gio.Settings({ schema: "org.gnome.desktop.wm.keybindings" }),
 | 
			
		||||
                                  Meta.KeyBindingFlags.REVERSES |
 | 
			
		||||
                                  Meta.KeyBindingFlags.REVERSED,
 | 
			
		||||
                                  Shell.KeyBindingMode.ALL & ~Shell.KeyBindingMode.MESSAGE_TRAY,
 | 
			
		||||
                                  Shell.KeyBindingMode.ALL,
 | 
			
		||||
                                  Lang.bind(this, this._switchInputSource));
 | 
			
		||||
        this._settings = new Gio.Settings({ schema: DESKTOP_INPUT_SOURCES_SCHEMA });
 | 
			
		||||
        this._settings.connect('changed::' + KEY_CURRENT_INPUT_SOURCE, Lang.bind(this, this._currentInputSourceChanged));
 | 
			
		||||
@@ -364,6 +383,15 @@ const InputSourceIndicator = new Lang.Class({
 | 
			
		||||
        this._ibusManager.connect('property-updated', Lang.bind(this, this._ibusPropertyUpdated));
 | 
			
		||||
        this._inputSourcesChanged();
 | 
			
		||||
 | 
			
		||||
        this._keyboardManager = new KeyboardManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
 | 
			
		||||
                                                         function(proxy, error) {
 | 
			
		||||
                                                             if (error)
 | 
			
		||||
                                                                 log(error.message);
 | 
			
		||||
                                                         });
 | 
			
		||||
        this._keyboardManager.g_default_timeout = MAX_INPUT_SOURCE_ACTIVATION_TIME;
 | 
			
		||||
 | 
			
		||||
        global.display.connect('modifiers-accelerator-activated', Lang.bind(this, this._modifiersSwitcher));
 | 
			
		||||
 | 
			
		||||
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
 | 
			
		||||
        this._showLayoutItem = this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, this._showLayout));
 | 
			
		||||
 | 
			
		||||
@@ -397,10 +425,43 @@ const InputSourceIndicator = new Lang.Class({
 | 
			
		||||
        this._inputSourcesChanged();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _modifiersSwitcher: function() {
 | 
			
		||||
        let sourceIndexes = Object.keys(this._inputSources);
 | 
			
		||||
        if (sourceIndexes.length == 0) {
 | 
			
		||||
            releaseKeyboard();
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let is = this._currentSource;
 | 
			
		||||
        if (!is)
 | 
			
		||||
            is = this._inputSources[sourceIndexes[0]];
 | 
			
		||||
 | 
			
		||||
        let nextIndex = is.index + 1;
 | 
			
		||||
        if (nextIndex > sourceIndexes[sourceIndexes.length - 1])
 | 
			
		||||
            nextIndex = 0;
 | 
			
		||||
 | 
			
		||||
        while (!(is = this._inputSources[nextIndex]))
 | 
			
		||||
            nextIndex += 1;
 | 
			
		||||
 | 
			
		||||
        is.activate();
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _switchInputSource: function(display, screen, window, binding) {
 | 
			
		||||
        if (this._mruSources.length < 2)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // HACK: Fall back on simple input source switching since we
 | 
			
		||||
        // can't show a popup switcher while a GrabHelper grab is in
 | 
			
		||||
        // effect without considerable work to consolidate the usage
 | 
			
		||||
        // of pushModal/popModal and grabHelper. See
 | 
			
		||||
        // https://bugzilla.gnome.org/show_bug.cgi?id=695143 .
 | 
			
		||||
        if (Main.keybindingMode == Shell.KeyBindingMode.MESSAGE_TRAY ||
 | 
			
		||||
            Main.keybindingMode == Shell.KeyBindingMode.TOPBAR_POPUP) {
 | 
			
		||||
            this._modifiersSwitcher();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let popup = new InputSourcePopup(this._mruSources, this._keybindingAction, this._keybindingActionBackward);
 | 
			
		||||
        let modifiers = binding.get_modifiers();
 | 
			
		||||
        let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
 | 
			
		||||
@@ -417,7 +478,7 @@ const InputSourceIndicator = new Lang.Class({
 | 
			
		||||
        [oldSource, this._currentSource] = [this._currentSource, newSource];
 | 
			
		||||
 | 
			
		||||
        if (oldSource) {
 | 
			
		||||
            oldSource.menuItem.setShowDot(false);
 | 
			
		||||
            oldSource.menuItem.setOrnament(PopupMenu.Ornament.NONE);
 | 
			
		||||
            oldSource.indicatorLabel.hide();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -435,7 +496,7 @@ const InputSourceIndicator = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
 | 
			
		||||
        newSource.menuItem.setShowDot(true);
 | 
			
		||||
        newSource.menuItem.setOrnament(PopupMenu.Ornament.DOT);
 | 
			
		||||
        newSource.indicatorLabel.show();
 | 
			
		||||
 | 
			
		||||
        this._buildPropSection(newSource.properties);
 | 
			
		||||
@@ -459,6 +520,7 @@ const InputSourceIndicator = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._inputSources = {};
 | 
			
		||||
        this._ibusSources = {};
 | 
			
		||||
        this._currentSource = null;
 | 
			
		||||
 | 
			
		||||
        let inputSourcesByShortName = {};
 | 
			
		||||
 | 
			
		||||
@@ -487,10 +549,8 @@ const InputSourceIndicator = new Lang.Class({
 | 
			
		||||
            let is = new InputSource(type, id, displayName, shortName, i);
 | 
			
		||||
 | 
			
		||||
            is.connect('activate', Lang.bind(this, function() {
 | 
			
		||||
                if (this._currentSource && this._currentSource.index == is.index)
 | 
			
		||||
                    return;
 | 
			
		||||
                this._settings.set_value(KEY_CURRENT_INPUT_SOURCE,
 | 
			
		||||
                                         GLib.Variant.new_uint32(is.index));
 | 
			
		||||
                holdKeyboard();
 | 
			
		||||
                this._keyboardManager.SetInputSourceRemote(is.index, releaseKeyboard);
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            if (!(is.shortName in inputSourcesByShortName))
 | 
			
		||||
@@ -660,7 +720,8 @@ const InputSourceIndicator = new Lang.Class({
 | 
			
		||||
                item.prop = prop;
 | 
			
		||||
                radioGroup.push(item);
 | 
			
		||||
                item.radioGroup = radioGroup;
 | 
			
		||||
                item.setShowDot(prop.get_state() == IBus.PropState.CHECKED);
 | 
			
		||||
                item.setOrnament(prop.get_state() == IBus.PropState.CHECKED ?
 | 
			
		||||
                                 PopupMenu.Ornament.DOT : PopupMenu.Ornament.NONE);
 | 
			
		||||
                item.connect('activate', Lang.bind(this, function() {
 | 
			
		||||
                    if (item.prop.get_state() == IBus.PropState.CHECKED)
 | 
			
		||||
                        return;
 | 
			
		||||
@@ -668,12 +729,12 @@ const InputSourceIndicator = new Lang.Class({
 | 
			
		||||
                    let group = item.radioGroup;
 | 
			
		||||
                    for (let i = 0; i < group.length; ++i) {
 | 
			
		||||
                        if (group[i] == item) {
 | 
			
		||||
                            item.setShowDot(true);
 | 
			
		||||
                            item.setOrnament(PopupMenu.Ornament.DOT);
 | 
			
		||||
                            item.prop.set_state(IBus.PropState.CHECKED);
 | 
			
		||||
                            this._ibusManager.activateProperty(item.prop.get_key(),
 | 
			
		||||
                                                               IBus.PropState.CHECKED);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            group[i].setShowDot(false);
 | 
			
		||||
                            group[i].setOrnament(PopupMenu.Ornament.NONE);
 | 
			
		||||
                            group[i].prop.set_state(IBus.PropState.UNCHECKED);
 | 
			
		||||
                            this._ibusManager.activateProperty(group[i].prop.get_key(),
 | 
			
		||||
                                                               IBus.PropState.UNCHECKED);
 | 
			
		||||
 
 | 
			
		||||
@@ -5,17 +5,10 @@ const Gio = imports.gi.Gio;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const NetworkManager = imports.gi.NetworkManager;
 | 
			
		||||
const NMClient = imports.gi.NMClient;
 | 
			
		||||
const NMGtk = imports.gi.NMGtk;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
// Some of the new code depends on as-yet-unreleased NM
 | 
			
		||||
var NMGtk;
 | 
			
		||||
try {
 | 
			
		||||
    NMGtk = imports.gi.NMGtk;
 | 
			
		||||
} catch(e) {
 | 
			
		||||
    NMGtk = null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const PanelMenu = imports.ui.panelMenu;
 | 
			
		||||
const PopupMenu = imports.ui.popupMenu;
 | 
			
		||||
@@ -34,7 +27,6 @@ const NMConnectionCategory = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const NMAccessPointSecurity = {
 | 
			
		||||
    UNKNOWN: 0,
 | 
			
		||||
    NONE: 1,
 | 
			
		||||
    WEP: 2,
 | 
			
		||||
    WPA_PSK: 3,
 | 
			
		||||
@@ -52,20 +44,6 @@ const NM80211ApSecurityFlags = NetworkManager['80211ApSecurityFlags'];
 | 
			
		||||
// (the remaining are placed into More…)
 | 
			
		||||
const NUM_VISIBLE_NETWORKS = 5;
 | 
			
		||||
 | 
			
		||||
function macToArray(string) {
 | 
			
		||||
    return string.split(':').map(function(el) {
 | 
			
		||||
        return parseInt(el, 16);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function macCompare(one, two) {
 | 
			
		||||
    for (let i = 0; i < 6; i++) {
 | 
			
		||||
        if (one[i] != two[i])
 | 
			
		||||
            return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ssidCompare(one, two) {
 | 
			
		||||
    if (!one || !two)
 | 
			
		||||
        return false;
 | 
			
		||||
@@ -91,13 +69,6 @@ function signalToIcon(value) {
 | 
			
		||||
    return 'none';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// shared between NMNetworkMenuItem and NMDeviceWireless
 | 
			
		||||
function sortAccessPoints(accessPoints) {
 | 
			
		||||
    return accessPoints.sort(function (one, two) {
 | 
			
		||||
        return two.strength - one.strength;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ssidToLabel(ssid) {
 | 
			
		||||
    let label = NetworkManager.utils_ssid_to_utf8(ssid);
 | 
			
		||||
    if (!label)
 | 
			
		||||
@@ -130,8 +101,7 @@ const NMNetworkMenuItem = new Lang.Class({
 | 
			
		||||
        this._icons.add_actor(this._signalIcon);
 | 
			
		||||
 | 
			
		||||
        this._secureIcon = new St.Icon({ style_class: 'popup-menu-icon' });
 | 
			
		||||
        if (this.bestAP._secType != NMAccessPointSecurity.UNKNOWN &&
 | 
			
		||||
            this.bestAP._secType != NMAccessPointSecurity.NONE)
 | 
			
		||||
        if (this.bestAP._secType != NMAccessPointSecurity.NONE)
 | 
			
		||||
            this._secureIcon.icon_name = 'network-wireless-encrypted-symbolic';
 | 
			
		||||
        this._icons.add_actor(this._secureIcon);
 | 
			
		||||
    },
 | 
			
		||||
@@ -153,18 +123,12 @@ const NMWirelessSectionTitleMenuItem = new Lang.Class({
 | 
			
		||||
    Name: 'NMWirelessSectionTitleMenuItem',
 | 
			
		||||
    Extends: PopupMenu.PopupSwitchMenuItem,
 | 
			
		||||
 | 
			
		||||
    _init: function(client, property, title, params) {
 | 
			
		||||
        params = params || { };
 | 
			
		||||
        params.style_class = 'popup-subtitle-menu-item';
 | 
			
		||||
        this.parent(title, false, params);
 | 
			
		||||
    _init: function(client) {
 | 
			
		||||
        this.parent(_("Wi-Fi"), false, { style_class: 'popup-subtitle-menu-item' });
 | 
			
		||||
 | 
			
		||||
        this._client = client;
 | 
			
		||||
        this._property = property + '_enabled';
 | 
			
		||||
        this._propertyHardware = property + '_hardware_enabled';
 | 
			
		||||
        this._setEnabledFunc = property + '_set_enabled';
 | 
			
		||||
 | 
			
		||||
        this._client.connect('notify::' + property + '-enabled', Lang.bind(this, this._propertyChanged));
 | 
			
		||||
        this._client.connect('notify::' + property + '-hardware-enabled', Lang.bind(this, this._propertyChanged));
 | 
			
		||||
        this._client.connect('notify::wireless-enabled', Lang.bind(this, this._propertyChanged));
 | 
			
		||||
        this._client.connect('notify::wireless-hardware-enabled', Lang.bind(this, this._propertyChanged));
 | 
			
		||||
 | 
			
		||||
        this._propertyChanged();
 | 
			
		||||
    },
 | 
			
		||||
@@ -186,12 +150,12 @@ const NMWirelessSectionTitleMenuItem = new Lang.Class({
 | 
			
		||||
    activate: function(event) {
 | 
			
		||||
        this.parent(event);
 | 
			
		||||
 | 
			
		||||
        this._client[this._setEnabledFunc](this._switch.state);
 | 
			
		||||
        this._client.wireless_set_enabled(this._switch.state);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _propertyChanged: function() {
 | 
			
		||||
        this._softwareEnabled = this._client[this._property];
 | 
			
		||||
        this._hardwareEnabled = this._client[this._propertyHardware];
 | 
			
		||||
        this._softwareEnabled = this._client.wireless_enabled;
 | 
			
		||||
        this._hardwareEnabled = this._client.wireless_hardware_enabled;
 | 
			
		||||
 | 
			
		||||
        let enabled = this._softwareEnabled && this._hardwareEnabled;
 | 
			
		||||
        this.setToggleState(enabled);
 | 
			
		||||
@@ -209,22 +173,7 @@ const NMConnectionBased = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _init: function(connections) {
 | 
			
		||||
        this._connections = [ ];
 | 
			
		||||
        for (let i = 0; i < connections.length; i++) {
 | 
			
		||||
            if (!connections[i].get_uuid())
 | 
			
		||||
                continue;
 | 
			
		||||
            if (!this.connectionValid(connections[i]))
 | 
			
		||||
                continue;
 | 
			
		||||
            // record the connection
 | 
			
		||||
            let obj = {
 | 
			
		||||
                connection: connections[i],
 | 
			
		||||
                name: connections[i].get_id(),
 | 
			
		||||
                uuid: connections[i].get_uuid(),
 | 
			
		||||
                timestamp: connections[i]._timestamp,
 | 
			
		||||
                item: null,
 | 
			
		||||
            };
 | 
			
		||||
            this._connections.push(obj);
 | 
			
		||||
        }
 | 
			
		||||
        this._connections.sort(this._connectionSortFunction);
 | 
			
		||||
        connections.forEach(Lang.bind(this, this.checkConnection));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    checkConnection: function(connection) {
 | 
			
		||||
@@ -315,7 +264,6 @@ const NMDevice = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._activeConnection = null;
 | 
			
		||||
        this._activeConnectionItem = null;
 | 
			
		||||
        this._autoConnectionItem = null;
 | 
			
		||||
        this._overflowItem = null;
 | 
			
		||||
 | 
			
		||||
        this.statusItem = new PopupMenu.PopupSwitchMenuItem('', this.connected, { style_class: 'popup-subtitle-menu-item' });
 | 
			
		||||
@@ -402,13 +350,9 @@ const NMDevice = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _activateAutomaticConnection: function() {
 | 
			
		||||
        let connection = this._createAutomaticConnection();
 | 
			
		||||
        if (connection) {
 | 
			
		||||
            this._client.add_and_activate_connection(connection, this.device, null, null);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
        let connection = new NetworkManager.Connection();
 | 
			
		||||
        this._client.add_and_activate_connection(connection, this.device, null, null);
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get connected() {
 | 
			
		||||
@@ -502,11 +446,6 @@ const NMDevice = new Lang.Class({
 | 
			
		||||
            this.statusItem.label.text = this.device._description;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // protected
 | 
			
		||||
    _createAutomaticConnection: function() {
 | 
			
		||||
        throw new TypeError('Invoking pure virtual function NMDevice.createAutomaticConnection');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _queueCreateSection: function() {
 | 
			
		||||
        if (this._deferredWorkId) {
 | 
			
		||||
            this._clearSection();
 | 
			
		||||
@@ -517,7 +456,6 @@ const NMDevice = new Lang.Class({
 | 
			
		||||
    _clearSection: function() {
 | 
			
		||||
        // Clear everything
 | 
			
		||||
        this.section.removeAll();
 | 
			
		||||
        this._autoConnectionItem = null;
 | 
			
		||||
        this._activeConnectionItem = null;
 | 
			
		||||
        this._overflowItem = null;
 | 
			
		||||
        for (let i = 0; i < this._connections.length; i++) {
 | 
			
		||||
@@ -556,14 +494,6 @@ const NMDevice = new Lang.Class({
 | 
			
		||||
                } else
 | 
			
		||||
                    this.section.addMenuItem(obj.item);
 | 
			
		||||
            }
 | 
			
		||||
        } else if (this._autoConnectionName) {
 | 
			
		||||
            this._autoConnectionItem = new PopupMenu.PopupMenuItem(this._autoConnectionName);
 | 
			
		||||
            this._autoConnectionItem.connect('activate', Lang.bind(this, function() {
 | 
			
		||||
                let connection = this._createAutomaticConnection();
 | 
			
		||||
                if (connection)
 | 
			
		||||
                    this._client.add_and_activate_connection(connection, this.device, null, null);
 | 
			
		||||
            }));
 | 
			
		||||
            this.section.addMenuItem(this._autoConnectionItem);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -588,7 +518,7 @@ const NMDevice = new Lang.Class({
 | 
			
		||||
            title = _("Connected (private)");
 | 
			
		||||
        }
 | 
			
		||||
        this._activeConnectionItem = new PopupMenu.PopupMenuItem(title, { reactive: false });
 | 
			
		||||
        this._activeConnectionItem.setShowDot(true);
 | 
			
		||||
        this._activeConnectionItem.setOrnament(PopupMenu.Ornament.DOT);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _deviceStateChanged: function(device, newstate, oldstate, reason) {
 | 
			
		||||
@@ -665,24 +595,10 @@ const NMDeviceWired = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _init: function(client, device, connections) {
 | 
			
		||||
        device._description = _("Wired");
 | 
			
		||||
        this._autoConnectionName = _("Auto Ethernet");
 | 
			
		||||
        this.category = NMConnectionCategory.WIRED;
 | 
			
		||||
 | 
			
		||||
        this.parent(client, device, connections);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createAutomaticConnection: function() {
 | 
			
		||||
        let connection = new NetworkManager.Connection();
 | 
			
		||||
        let uuid = NetworkManager.utils_uuid_generate();
 | 
			
		||||
        connection.add_setting(new NetworkManager.SettingWired());
 | 
			
		||||
        connection.add_setting(new NetworkManager.SettingConnection({
 | 
			
		||||
            uuid: uuid,
 | 
			
		||||
            id: this._autoConnectionName,
 | 
			
		||||
            type: NetworkManager.SETTING_WIRED_SETTING_NAME,
 | 
			
		||||
            autoconnect: true
 | 
			
		||||
        }));
 | 
			
		||||
        return connection;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const NMDeviceModem = new Lang.Class({
 | 
			
		||||
@@ -723,13 +639,10 @@ const NMDeviceModem = new Lang.Class({
 | 
			
		||||
            this._connectionType = NetworkManager.SETTING_GSM_SETTING_NAME;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (is_wwan) {
 | 
			
		||||
        if (is_wwan)
 | 
			
		||||
            this.category = NMConnectionCategory.WWAN;
 | 
			
		||||
            this._autoConnectionName = _("Auto broadband");
 | 
			
		||||
        } else {
 | 
			
		||||
        else
 | 
			
		||||
            this.category = NMConnectionCategory.WIRED;
 | 
			
		||||
            this._autoConnectionName = _("Auto dial-up");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.mobileDevice) {
 | 
			
		||||
            this._operatorNameId = this.mobileDevice.connect('notify::operator-name', Lang.bind(this, function() {
 | 
			
		||||
@@ -824,50 +737,20 @@ const NMDeviceBluetooth = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _init: function(client, device, connections) {
 | 
			
		||||
        device._description = _("Bluetooth");
 | 
			
		||||
        this._autoConnectionName = this._makeConnectionName(device);
 | 
			
		||||
        device.connect('notify::name', Lang.bind(this, this._updateAutoConnectionName));
 | 
			
		||||
 | 
			
		||||
        this.category = NMConnectionCategory.WWAN;
 | 
			
		||||
 | 
			
		||||
        this.parent(client, device, connections);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createAutomaticConnection: function() {
 | 
			
		||||
        let connection = new NetworkManager.Connection;
 | 
			
		||||
        let uuid = NetworkManager.utils_uuid_generate();
 | 
			
		||||
        connection.add_setting(new NetworkManager.SettingBluetooth);
 | 
			
		||||
        connection.add_setting(new NetworkManager.SettingConnection({
 | 
			
		||||
            uuid: uuid,
 | 
			
		||||
            id: this._autoConnectionName,
 | 
			
		||||
            type: NetworkManager.SETTING_BLUETOOTH_SETTING_NAME,
 | 
			
		||||
            autoconnect: false
 | 
			
		||||
        }));
 | 
			
		||||
        return connection;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _activateAutomaticConnection: function() {
 | 
			
		||||
        // FIXME: DUN devices are configured like modems, so
 | 
			
		||||
        // we need to spawn the mobile wizard
 | 
			
		||||
        // We need to spawn the mobile wizard
 | 
			
		||||
        // but the network panel doesn't support bluetooth at the moment
 | 
			
		||||
        // so we just create an empty connection and hope
 | 
			
		||||
        // that this phone supports PAN
 | 
			
		||||
 | 
			
		||||
        return this.parent();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _makeConnectionName: function(device) {
 | 
			
		||||
        let name = device.name;
 | 
			
		||||
        if (name)
 | 
			
		||||
            return _("Auto %s").format(name);
 | 
			
		||||
        else
 | 
			
		||||
            return _("Auto bluetooth");
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateAutoConnectionName: function() {
 | 
			
		||||
        this._autoConnectionName = this._makeConnectionName(this.device);
 | 
			
		||||
 | 
			
		||||
        this._queueCreateSection();
 | 
			
		||||
        this._updateStatusItem();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -881,76 +764,19 @@ const NMDeviceWireless = new Lang.Class({
 | 
			
		||||
        this._overflowItem = null;
 | 
			
		||||
        this._networks = [ ];
 | 
			
		||||
 | 
			
		||||
        // breaking the layers with this, but cannot call
 | 
			
		||||
        // this.connectionValid until I have a device
 | 
			
		||||
        this.device = device;
 | 
			
		||||
        this.parent(client, device, connections);
 | 
			
		||||
 | 
			
		||||
        let validConnections = connections.filter(Lang.bind(this, function(connection) {
 | 
			
		||||
            return this.connectionValid(connection);
 | 
			
		||||
        }));
 | 
			
		||||
        let accessPoints = device.get_access_points() || [ ];
 | 
			
		||||
        for (let i = 0; i < accessPoints.length; i++) {
 | 
			
		||||
            // Access points are grouped by network
 | 
			
		||||
            let ap = accessPoints[i];
 | 
			
		||||
        accessPoints.forEach(Lang.bind(this, function(ap) {
 | 
			
		||||
            this._accessPointAdded(this.device, ap);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
            if (ap.get_ssid() == null) {
 | 
			
		||||
                // hidden access point cannot be added, we need to know
 | 
			
		||||
                // the SSID and security details to connect
 | 
			
		||||
                // nevertheless, the access point can acquire a SSID when
 | 
			
		||||
                // NetworkManager connects to it (via nmcli or the control-center)
 | 
			
		||||
                ap._notifySsidId = ap.connect('notify::ssid', Lang.bind(this, this._notifySsidCb));
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let pos = this._findNetwork(ap);
 | 
			
		||||
            let obj;
 | 
			
		||||
            if (pos != -1) {
 | 
			
		||||
                obj = this._networks[pos];
 | 
			
		||||
                obj.accessPoints.push(ap);
 | 
			
		||||
            } else {
 | 
			
		||||
                obj = { ssid: ap.get_ssid(),
 | 
			
		||||
                        mode: ap.mode,
 | 
			
		||||
                        security: this._getApSecurityType(ap),
 | 
			
		||||
                        connections: [ ],
 | 
			
		||||
                        item: null,
 | 
			
		||||
                        accessPoints: [ ap ]
 | 
			
		||||
                      };
 | 
			
		||||
                obj.ssidText = ssidToLabel(obj.ssid);
 | 
			
		||||
                this._networks.push(obj);
 | 
			
		||||
            }
 | 
			
		||||
            ap._updateId = ap.connect('notify::strength', Lang.bind(this, this._onApStrengthChanged));
 | 
			
		||||
 | 
			
		||||
            // Check if some connection is valid for this AP
 | 
			
		||||
            for (let j = 0; j < validConnections.length; j++) {
 | 
			
		||||
                let connection = validConnections[j];
 | 
			
		||||
                if (ap.connection_valid(connection) &&
 | 
			
		||||
                    obj.connections.indexOf(connection) == -1) {
 | 
			
		||||
                    obj.connections.push(connection);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Sort APs within each network by strength
 | 
			
		||||
        for (let i = 0; i < this._networks.length; i++)
 | 
			
		||||
            sortAccessPoints(this._networks[i].accessPoints);
 | 
			
		||||
 | 
			
		||||
        if (this.device.active_access_point) {
 | 
			
		||||
            let networkPos = this._findNetwork(this.device.active_access_point);
 | 
			
		||||
 | 
			
		||||
            if (networkPos == -1) // the connected access point is invisible
 | 
			
		||||
                this._activeNetwork = null;
 | 
			
		||||
            else
 | 
			
		||||
                this._activeNetwork = this._networks[networkPos];
 | 
			
		||||
        } else {
 | 
			
		||||
            this._activeNetwork = null;
 | 
			
		||||
        }
 | 
			
		||||
        this._activeApChanged();
 | 
			
		||||
        this._networks.sort(this._networkSortFunction);
 | 
			
		||||
 | 
			
		||||
        this._apChangedId = device.connect('notify::active-access-point', Lang.bind(this, this._activeApChanged));
 | 
			
		||||
        this._apAddedId = device.connect('access-point-added', Lang.bind(this, this._accessPointAdded));
 | 
			
		||||
        this._apRemovedId = device.connect('access-point-removed', Lang.bind(this, this._accessPointRemoved));
 | 
			
		||||
 | 
			
		||||
        this.parent(client, device, validConnections);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
@@ -1090,9 +916,9 @@ const NMDeviceWireless = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _findExistingNetwork: function(accessPoint) {
 | 
			
		||||
        for (let i = 0; i < this._networks.length; i++) {
 | 
			
		||||
            let apObj = this._networks[i];
 | 
			
		||||
            for (let j = 0; j < apObj.accessPoints.length; j++) {
 | 
			
		||||
                if (apObj.accessPoints[j] == accessPoint)
 | 
			
		||||
            let network = this._networks[i];
 | 
			
		||||
            for (let j = 0; j < network.accessPoints.length; j++) {
 | 
			
		||||
                if (network.accessPoints[j] == accessPoint)
 | 
			
		||||
                    return { network: i, ap: j };
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -1140,30 +966,30 @@ const NMDeviceWireless = new Lang.Class({
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let pos = this._findNetwork(accessPoint);
 | 
			
		||||
        let apObj;
 | 
			
		||||
        let network;
 | 
			
		||||
        let needsupdate = false;
 | 
			
		||||
 | 
			
		||||
        if (pos != -1) {
 | 
			
		||||
            apObj = this._networks[pos];
 | 
			
		||||
            if (apObj.accessPoints.indexOf(accessPoint) != -1) {
 | 
			
		||||
            network = this._networks[pos];
 | 
			
		||||
            if (network.accessPoints.indexOf(accessPoint) != -1) {
 | 
			
		||||
                log('Access point was already seen, not adding again');
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Util.insertSorted(apObj.accessPoints, accessPoint, function(one, two) {
 | 
			
		||||
            Util.insertSorted(network.accessPoints, accessPoint, function(one, two) {
 | 
			
		||||
                return two.strength - one.strength;
 | 
			
		||||
            });
 | 
			
		||||
            if (apObj.item)
 | 
			
		||||
                apObj.item.updateBestAP(apObj.accessPoints[0]);
 | 
			
		||||
            if (network.item)
 | 
			
		||||
                network.item.updateBestAP(network.accessPoints[0]);
 | 
			
		||||
        } else {
 | 
			
		||||
            apObj = { ssid: accessPoint.get_ssid(),
 | 
			
		||||
                      mode: accessPoint.mode,
 | 
			
		||||
                      security: this._getApSecurityType(accessPoint),
 | 
			
		||||
                      connections: [ ],
 | 
			
		||||
                      item: null,
 | 
			
		||||
                      accessPoints: [ accessPoint ]
 | 
			
		||||
                    };
 | 
			
		||||
            apObj.ssidText = ssidToLabel(apObj.ssid);
 | 
			
		||||
            network = { ssid: accessPoint.get_ssid(),
 | 
			
		||||
                        mode: accessPoint.mode,
 | 
			
		||||
                        security: this._getApSecurityType(accessPoint),
 | 
			
		||||
                        connections: [ ],
 | 
			
		||||
                        item: null,
 | 
			
		||||
                        accessPoints: [ accessPoint ]
 | 
			
		||||
                      };
 | 
			
		||||
            network.ssidText = ssidToLabel(network.ssid);
 | 
			
		||||
        }
 | 
			
		||||
        accessPoint._updateId = accessPoint.connect('notify::strength', Lang.bind(this, this._onApStrengthChanged));
 | 
			
		||||
 | 
			
		||||
@@ -1171,14 +997,14 @@ const NMDeviceWireless = new Lang.Class({
 | 
			
		||||
        for (let i = 0; i < this._connections.length; i++) {
 | 
			
		||||
            let connection = this._connections[i].connection;
 | 
			
		||||
            if (accessPoint.connection_valid(connection) &&
 | 
			
		||||
                apObj.connections.indexOf(connection) == -1) {
 | 
			
		||||
                apObj.connections.push(connection);
 | 
			
		||||
                network.connections.indexOf(connection) == -1) {
 | 
			
		||||
                network.connections.push(connection);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (pos != -1)
 | 
			
		||||
            this._networks.splice(pos, 1);
 | 
			
		||||
        let newPos = Util.insertSorted(this._networks, apObj, this._networkSortFunction);
 | 
			
		||||
        let newPos = Util.insertSorted(this._networks, network, this._networkSortFunction);
 | 
			
		||||
 | 
			
		||||
        // Queue an update of the UI if we changed the order
 | 
			
		||||
        if (newPos != pos)
 | 
			
		||||
@@ -1198,28 +1024,28 @@ const NMDeviceWireless = new Lang.Class({
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let apObj = this._networks[res.network];
 | 
			
		||||
        apObj.accessPoints.splice(res.ap, 1);
 | 
			
		||||
        let network = this._networks[res.network];
 | 
			
		||||
        network.accessPoints.splice(res.ap, 1);
 | 
			
		||||
 | 
			
		||||
        if (apObj.accessPoints.length == 0) {
 | 
			
		||||
            if (this._activeNetwork == apObj)
 | 
			
		||||
        if (network.accessPoints.length == 0) {
 | 
			
		||||
            if (this._activeNetwork == network)
 | 
			
		||||
                this._activeNetwork = null;
 | 
			
		||||
 | 
			
		||||
            if (apObj.item)
 | 
			
		||||
                apObj.item.destroy();
 | 
			
		||||
            if (network.item)
 | 
			
		||||
                network.item.destroy();
 | 
			
		||||
 | 
			
		||||
            if (this._overflowItem) {
 | 
			
		||||
                if (!apObj.isMore) {
 | 
			
		||||
                if (!network.isMore) {
 | 
			
		||||
                    // we removed an item in the main menu, and we have a more submenu
 | 
			
		||||
                    // we need to extract the first item in more and move it to the submenu
 | 
			
		||||
 | 
			
		||||
                    let item = this._overflowItem.menu.firstMenuItem;
 | 
			
		||||
                    if (item && item._apObj) {
 | 
			
		||||
                    if (item && item._network) {
 | 
			
		||||
                        item.destroy();
 | 
			
		||||
                        // clear the cycle, and allow the construction of the new item
 | 
			
		||||
                        item._apObj.item = null;
 | 
			
		||||
                        item._network.item = null;
 | 
			
		||||
 | 
			
		||||
                        this._createNetworkItem(item._apObj, NUM_VISIBLE_NETWORKS-1);
 | 
			
		||||
                        this._createNetworkItem(item._network, NUM_VISIBLE_NETWORKS-1);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        log('The more... menu was existing and empty! This should not happen');
 | 
			
		||||
                    }
 | 
			
		||||
@@ -1238,14 +1064,14 @@ const NMDeviceWireless = new Lang.Class({
 | 
			
		||||
            let okPrev = true, okNext = true;
 | 
			
		||||
 | 
			
		||||
            if (res.network > 0)
 | 
			
		||||
                okPrev = this._networkSortFunction(this._networks[res.network - 1], apObj) >= 0;
 | 
			
		||||
                okPrev = this._networkSortFunction(this._networks[res.network - 1], network) >= 0;
 | 
			
		||||
            if (res.network < this._networks.length-1)
 | 
			
		||||
                okNext = this._networkSortFunction(this._networks[res.network + 1], apObj) <= 0;
 | 
			
		||||
                okNext = this._networkSortFunction(this._networks[res.network + 1], network) <= 0;
 | 
			
		||||
 | 
			
		||||
            if (!okPrev || !okNext)
 | 
			
		||||
                this._queueCreateSection();
 | 
			
		||||
            else if (apObj.item)
 | 
			
		||||
                apObj.item.updateBestAP(apObj.accessPoints[0]);
 | 
			
		||||
            else if (network.item)
 | 
			
		||||
                network.item.updateBestAP(network.accessPoints[0]);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -1284,20 +1110,20 @@ const NMDeviceWireless = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        let forceupdate = false;
 | 
			
		||||
        for (let i = 0; i < this._networks.length; i++) {
 | 
			
		||||
            let apObj = this._networks[i];
 | 
			
		||||
            let connections = apObj.connections;
 | 
			
		||||
            let network = this._networks[i];
 | 
			
		||||
            let connections = network.connections;
 | 
			
		||||
            for (let k = 0; k < connections.length; k++) {
 | 
			
		||||
                if (connections[k].get_uuid() == connection.get_uuid()) {
 | 
			
		||||
                    // remove the connection from the access point group
 | 
			
		||||
                    connections.splice(k);
 | 
			
		||||
                    connections.splice(k, 1);
 | 
			
		||||
                    forceupdate = forceupdate || connections.length == 0;
 | 
			
		||||
 | 
			
		||||
                    if (forceupdate)
 | 
			
		||||
                        break;
 | 
			
		||||
 | 
			
		||||
                    if (apObj.item) {
 | 
			
		||||
                        if (apObj.item instanceof PopupMenu.PopupSubMenuMenuItem) {
 | 
			
		||||
                            let items = apObj.item.menu._getMenuItems();
 | 
			
		||||
                    if (network.item) {
 | 
			
		||||
                        if (network.item instanceof PopupMenu.PopupSubMenuMenuItem) {
 | 
			
		||||
                            let items = network.item.menu._getMenuItems();
 | 
			
		||||
                            if (items.length == 2) {
 | 
			
		||||
                                // we need to update the connection list to convert this to a normal item
 | 
			
		||||
                                forceupdate = true;
 | 
			
		||||
@@ -1310,8 +1136,8 @@ const NMDeviceWireless = new Lang.Class({
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            apObj.item.destroy();
 | 
			
		||||
                            apObj.item = null;
 | 
			
		||||
                            network.item.destroy();
 | 
			
		||||
                            network.item = null;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
@@ -1337,13 +1163,13 @@ const NMDeviceWireless = new Lang.Class({
 | 
			
		||||
        // find an appropriate access point
 | 
			
		||||
        let forceupdate = false;
 | 
			
		||||
        for (let i = 0; i < this._networks.length; i++) {
 | 
			
		||||
            let apObj = this._networks[i];
 | 
			
		||||
            let network = this._networks[i];
 | 
			
		||||
 | 
			
		||||
            // Check if connection is valid for any of these access points
 | 
			
		||||
            for (let k = 0; k < apObj.accessPoints.length; k++) {
 | 
			
		||||
                let ap = apObj.accessPoints[k];
 | 
			
		||||
            for (let k = 0; k < network.accessPoints.length; k++) {
 | 
			
		||||
                let ap = network.accessPoints[k];
 | 
			
		||||
                if (ap.connection_valid(connection)) {
 | 
			
		||||
                    apObj.connections.push(connection);
 | 
			
		||||
                    network.connections.push(connection);
 | 
			
		||||
                    // this potentially changes the sorting order
 | 
			
		||||
                    forceupdate = true;
 | 
			
		||||
                    break;
 | 
			
		||||
@@ -1364,55 +1190,30 @@ const NMDeviceWireless = new Lang.Class({
 | 
			
		||||
        else
 | 
			
		||||
            title = _("Connected (private)");
 | 
			
		||||
 | 
			
		||||
        if (this._activeNetwork)
 | 
			
		||||
            this._activeConnectionItem = new NMNetworkMenuItem(this.device.active_access_point, undefined,
 | 
			
		||||
                                                               { reactive: false });
 | 
			
		||||
        else
 | 
			
		||||
            this._activeConnectionItem = new PopupMenu.PopupImageMenuItem(title,
 | 
			
		||||
                                                                          'network-wireless-connected-symbolic',
 | 
			
		||||
                                                                          { reactive: false });
 | 
			
		||||
        this._activeConnectionItem.setShowDot(true);
 | 
			
		||||
        this._activeConnectionItem = new NMNetworkMenuItem(this.device.active_access_point, undefined,
 | 
			
		||||
                                                           { reactive: false });
 | 
			
		||||
        this._activeConnectionItem.setOrnament(PopupMenu.Ornament.DOT);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createAutomaticConnection: function(apObj) {
 | 
			
		||||
        let name;
 | 
			
		||||
        let ssid = NetworkManager.utils_ssid_to_utf8(apObj.ssid);
 | 
			
		||||
        if (ssid) {
 | 
			
		||||
            /* TRANSLATORS: this the automatic wireless connection name (including the network name) */
 | 
			
		||||
            name = _("Auto %s").format(ssid);
 | 
			
		||||
        } else
 | 
			
		||||
            name = _("Auto wireless");
 | 
			
		||||
 | 
			
		||||
        let connection = new NetworkManager.Connection();
 | 
			
		||||
        connection.add_setting(new NetworkManager.SettingWireless());
 | 
			
		||||
        connection.add_setting(new NetworkManager.SettingConnection({
 | 
			
		||||
            id: name,
 | 
			
		||||
            autoconnect: true, // NetworkManager will know to ignore this if appropriate
 | 
			
		||||
            uuid: NetworkManager.utils_uuid_generate(),
 | 
			
		||||
            type: NetworkManager.SETTING_WIRELESS_SETTING_NAME
 | 
			
		||||
        }));
 | 
			
		||||
        return connection;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _createNetworkItem: function(apObj, position) {
 | 
			
		||||
        if(!apObj.accessPoints || apObj.accessPoints.length == 0) {
 | 
			
		||||
    _createNetworkItem: function(network, position) {
 | 
			
		||||
        if(!network.accessPoints || network.accessPoints.length == 0) {
 | 
			
		||||
            // this should not happen, but I have no idea why it happens
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(apObj.connections.length > 0) {
 | 
			
		||||
            if (apObj.connections.length == 1) {
 | 
			
		||||
                apObj.item = this._createAPItem(apObj.connections[0], apObj, false);
 | 
			
		||||
        if(network.connections.length > 0) {
 | 
			
		||||
            if (network.connections.length == 1) {
 | 
			
		||||
                network.item = this._createAPItem(network.connections[0], network, false);
 | 
			
		||||
            } else {
 | 
			
		||||
                let title = apObj.ssidText;
 | 
			
		||||
                apObj.item = new PopupMenu.PopupSubMenuMenuItem(title);
 | 
			
		||||
                for (let i = 0; i < apObj.connections.length; i++)
 | 
			
		||||
                    apObj.item.menu.addMenuItem(this._createAPItem(apObj.connections[i], apObj, true));
 | 
			
		||||
                let title = network.ssidText;
 | 
			
		||||
                network.item = new PopupMenu.PopupSubMenuMenuItem(title);
 | 
			
		||||
                for (let i = 0; i < network.connections.length; i++)
 | 
			
		||||
                    network.item.menu.addMenuItem(this._createAPItem(network.connections[i], network, true));
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            apObj.item = new NMNetworkMenuItem(apObj.accessPoints[0]);
 | 
			
		||||
            apObj.item.connect('activate', Lang.bind(this, function() {
 | 
			
		||||
                let accessPoints = apObj.accessPoints;
 | 
			
		||||
            network.item = new NMNetworkMenuItem(network.accessPoints[0]);
 | 
			
		||||
            network.item.connect('activate', Lang.bind(this, function() {
 | 
			
		||||
                let accessPoints = network.accessPoints;
 | 
			
		||||
                if (   (accessPoints[0]._secType == NMAccessPointSecurity.WPA2_ENT)
 | 
			
		||||
                    || (accessPoints[0]._secType == NMAccessPointSecurity.WPA_ENT)) {
 | 
			
		||||
                    // 802.1x-enabled APs require further configuration, so they're
 | 
			
		||||
@@ -1420,23 +1221,23 @@ const NMDeviceWireless = new Lang.Class({
 | 
			
		||||
                    Util.spawn(['gnome-control-center', 'network', 'connect-8021x-wifi',
 | 
			
		||||
                                this.device.get_path(), accessPoints[0].dbus_path]);
 | 
			
		||||
                } else {
 | 
			
		||||
                    let connection = this._createAutomaticConnection(apObj);
 | 
			
		||||
                    let connection = new NetworkManager.Connection();
 | 
			
		||||
                    this._client.add_and_activate_connection(connection, this.device, accessPoints[0].dbus_path, null)
 | 
			
		||||
                }
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
        apObj.item._apObj = apObj;
 | 
			
		||||
        network.item._network = network;
 | 
			
		||||
 | 
			
		||||
        if (position < NUM_VISIBLE_NETWORKS) {
 | 
			
		||||
            apObj.isMore = false;
 | 
			
		||||
            this.section.addMenuItem(apObj.item, position);
 | 
			
		||||
            network.isMore = false;
 | 
			
		||||
            this.section.addMenuItem(network.item, position);
 | 
			
		||||
        } else {
 | 
			
		||||
            if (!this._overflowItem) {
 | 
			
		||||
                this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More…"));
 | 
			
		||||
                this.section.addMenuItem(this._overflowItem);
 | 
			
		||||
            }
 | 
			
		||||
            this._overflowItem.menu.addMenuItem(apObj.item, position - NUM_VISIBLE_NETWORKS);
 | 
			
		||||
            apObj.isMore = true;
 | 
			
		||||
            this._overflowItem.menu.addMenuItem(network.item, position - NUM_VISIBLE_NETWORKS);
 | 
			
		||||
            network.isMore = true;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -1452,13 +1253,13 @@ const NMDeviceWireless = new Lang.Class({
 | 
			
		||||
        let activeOffset = this._activeConnectionItem ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
        for(let j = 0; j < this._networks.length; j++) {
 | 
			
		||||
            let apObj = this._networks[j];
 | 
			
		||||
            if (apObj == this._activeNetwork) {
 | 
			
		||||
            let network = this._networks[j];
 | 
			
		||||
            if (network == this._activeNetwork) {
 | 
			
		||||
                activeOffset--;
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this._createNetworkItem(apObj, j + activeOffset);
 | 
			
		||||
            this._createNetworkItem(network, j + activeOffset);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
@@ -1518,18 +1319,14 @@ const NMVPNSection = new Lang.Class({
 | 
			
		||||
    Extends: NMConnectionBased,
 | 
			
		||||
    category: NMConnectionCategory.VPN,
 | 
			
		||||
 | 
			
		||||
    _init: function(client, connections) {
 | 
			
		||||
        this.parent(connections);
 | 
			
		||||
    _init: function(client) {
 | 
			
		||||
        this.parent([]);
 | 
			
		||||
        this._client = client;
 | 
			
		||||
 | 
			
		||||
        this.section = new PopupMenu.PopupMenuSection();
 | 
			
		||||
        this._deferredWorkId = Main.initializeDeferredWork(this.section.actor, Lang.bind(this, this._createSection));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    get empty() {
 | 
			
		||||
        return this._connections.length == 0;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    connectionValid: function(connection) {
 | 
			
		||||
        // filtering is done by NMApplet code
 | 
			
		||||
        return true;
 | 
			
		||||
@@ -1680,11 +1477,9 @@ const NMApplet = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        // Virtual device types
 | 
			
		||||
        this._vtypes = { };
 | 
			
		||||
        if (NMGtk) {
 | 
			
		||||
            this._vtypes[NetworkManager.SETTING_VLAN_SETTING_NAME] = NMDeviceVirtual;
 | 
			
		||||
            this._vtypes[NetworkManager.SETTING_BOND_SETTING_NAME] = NMDeviceVirtual;
 | 
			
		||||
            this._vtypes[NetworkManager.SETTING_BRIDGE_SETTING_NAME] = NMDeviceVirtual;
 | 
			
		||||
        }
 | 
			
		||||
        this._vtypes[NetworkManager.SETTING_VLAN_SETTING_NAME] = NMDeviceVirtual;
 | 
			
		||||
        this._vtypes[NetworkManager.SETTING_BOND_SETTING_NAME] = NMDeviceVirtual;
 | 
			
		||||
        this._vtypes[NetworkManager.SETTING_BRIDGE_SETTING_NAME] = NMDeviceVirtual;
 | 
			
		||||
 | 
			
		||||
        // Connection types
 | 
			
		||||
        this._ctypes = { };
 | 
			
		||||
@@ -1696,11 +1491,9 @@ const NMApplet = new Lang.Class({
 | 
			
		||||
        this._ctypes[NetworkManager.SETTING_CDMA_SETTING_NAME] = NMConnectionCategory.WWAN;
 | 
			
		||||
        this._ctypes[NetworkManager.SETTING_GSM_SETTING_NAME] = NMConnectionCategory.WWAN;
 | 
			
		||||
        this._ctypes[NetworkManager.SETTING_INFINIBAND_SETTING_NAME] = NMConnectionCategory.WIRED;
 | 
			
		||||
        if (NMGtk) {
 | 
			
		||||
            this._ctypes[NetworkManager.SETTING_VLAN_SETTING_NAME] = NMConnectionCategory.VIRTUAL;
 | 
			
		||||
            this._ctypes[NetworkManager.SETTING_BOND_SETTING_NAME] = NMConnectionCategory.VIRTUAL;
 | 
			
		||||
            this._ctypes[NetworkManager.SETTING_BRIDGE_SETTING_NAME] = NMConnectionCategory.VIRTUAL;
 | 
			
		||||
        }
 | 
			
		||||
        this._ctypes[NetworkManager.SETTING_VLAN_SETTING_NAME] = NMConnectionCategory.VIRTUAL;
 | 
			
		||||
        this._ctypes[NetworkManager.SETTING_BOND_SETTING_NAME] = NMConnectionCategory.VIRTUAL;
 | 
			
		||||
        this._ctypes[NetworkManager.SETTING_BRIDGE_SETTING_NAME] = NMConnectionCategory.VIRTUAL;
 | 
			
		||||
        this._ctypes[NetworkManager.SETTING_VPN_SETTING_NAME] = NMConnectionCategory.VPN;
 | 
			
		||||
 | 
			
		||||
        NMClient.Client.new_async(null, Lang.bind(this, this._clientGot));
 | 
			
		||||
@@ -1768,7 +1561,7 @@ const NMApplet = new Lang.Class({
 | 
			
		||||
        this._devices.wireless = {
 | 
			
		||||
            section: new PopupMenu.PopupMenuSection(),
 | 
			
		||||
            devices: [ ],
 | 
			
		||||
            item: this._makeToggleItem('wireless', _("Wi-Fi"))
 | 
			
		||||
            item: this._makeWirelessToggle()
 | 
			
		||||
        };
 | 
			
		||||
        this._devices.wireless.section.addMenuItem(this._devices.wireless.item);
 | 
			
		||||
        this._devices.wireless.section.actor.hide();
 | 
			
		||||
@@ -1783,7 +1576,7 @@ const NMApplet = new Lang.Class({
 | 
			
		||||
        this.menu.addMenuItem(this._devices.wwan.section);
 | 
			
		||||
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
 | 
			
		||||
 | 
			
		||||
        this._vpnSection = new NMVPNSection(this._client, this._connections);
 | 
			
		||||
        this._vpnSection = new NMVPNSection(this._client);
 | 
			
		||||
        this._vpnSection.connect('activation-failed', Lang.bind(this, this._onActivationFailed));
 | 
			
		||||
        this.menu.addMenuItem(this._vpnSection.section);
 | 
			
		||||
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
 | 
			
		||||
@@ -1815,14 +1608,14 @@ const NMApplet = new Lang.Class({
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _makeToggleItem: function(type, title) {
 | 
			
		||||
        let item = new NMWirelessSectionTitleMenuItem(this._client, type, title);
 | 
			
		||||
    _makeWirelessToggle: function() {
 | 
			
		||||
        let item = new NMWirelessSectionTitleMenuItem(this._client);
 | 
			
		||||
        item.connect('enabled-changed', Lang.bind(this, function(item, enabled) {
 | 
			
		||||
            let devices = this._devices[type].devices;
 | 
			
		||||
            let devices = this._devices.wireless.devices;
 | 
			
		||||
            devices.forEach(function(dev) {
 | 
			
		||||
                dev.setEnabled(enabled);
 | 
			
		||||
            });
 | 
			
		||||
            this._syncSectionTitle(type);
 | 
			
		||||
            this._syncSectionTitle('wireless');
 | 
			
		||||
        }));
 | 
			
		||||
        return item;
 | 
			
		||||
    },
 | 
			
		||||
@@ -1900,19 +1693,12 @@ const NMApplet = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _syncDeviceNames: function() {
 | 
			
		||||
        if (NMGtk) {
 | 
			
		||||
            let names = NMGtk.utils_disambiguate_device_names(this._nmDevices);
 | 
			
		||||
            for (let i = 0; i < this._nmDevices.length; i++) {
 | 
			
		||||
                let device = this._nmDevices[i];
 | 
			
		||||
                device._description = names[i];
 | 
			
		||||
                if (device._delegate)
 | 
			
		||||
                    device._delegate.syncDescription();
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            for (let i = 0; i < this._nmDevices.length; i++) {
 | 
			
		||||
                let device = this._nmDevices[i];
 | 
			
		||||
        let names = NMGtk.utils_disambiguate_device_names(this._nmDevices);
 | 
			
		||||
        for (let i = 0; i < this._nmDevices.length; i++) {
 | 
			
		||||
            let device = this._nmDevices[i];
 | 
			
		||||
            device._description = names[i];
 | 
			
		||||
            if (device._delegate)
 | 
			
		||||
                device._delegate.syncDescription();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -1948,11 +1734,6 @@ const NMApplet = new Lang.Class({
 | 
			
		||||
        wrapper._deviceStateChangedId = wrapper.connect('state-changed', Lang.bind(this, function(dev) {
 | 
			
		||||
            this._syncSectionTitle(dev.category);
 | 
			
		||||
        }));
 | 
			
		||||
        wrapper._destroyId = wrapper.connect('destroy', function(wrapper) {
 | 
			
		||||
            wrapper.disconnect(wrapper._activationFailedId);
 | 
			
		||||
            wrapper.disconnect(wrapper._deviceStateChangedId);
 | 
			
		||||
            wrapper.disconnect(wrapper._destroyId);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let section = this._devices[wrapper.category].section;
 | 
			
		||||
        section.addMenuItem(wrapper.statusItem);
 | 
			
		||||
@@ -1984,6 +1765,8 @@ const NMApplet = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _removeDeviceWrapper: function(wrapper) {
 | 
			
		||||
        wrapper.disconnect(wrapper._activationFailedId);
 | 
			
		||||
        wrapper.disconnect(wrapper._deviceStateChangedId);
 | 
			
		||||
        wrapper.destroy();
 | 
			
		||||
 | 
			
		||||
        let devices = this._devices[wrapper.category].devices;
 | 
			
		||||
@@ -2047,6 +1830,7 @@ const NMApplet = new Lang.Class({
 | 
			
		||||
        let default_ip4 = null;
 | 
			
		||||
        let default_ip6 = null;
 | 
			
		||||
        let active_vpn = null;
 | 
			
		||||
        let active_any = null;
 | 
			
		||||
        for (let i = 0; i < this._activeConnections.length; i++) {
 | 
			
		||||
            let a = this._activeConnections[i];
 | 
			
		||||
 | 
			
		||||
@@ -2077,24 +1861,21 @@ const NMApplet = new Lang.Class({
 | 
			
		||||
            if (a.default6)
 | 
			
		||||
                default_ip6 = a;
 | 
			
		||||
 | 
			
		||||
            if (a._type == 'vpn')
 | 
			
		||||
                active_vpn = a;
 | 
			
		||||
            else if (a.state == NetworkManager.ActiveConnectionState.ACTIVATING)
 | 
			
		||||
            if (a.state == NetworkManager.ActiveConnectionState.ACTIVATING)
 | 
			
		||||
                activating = a;
 | 
			
		||||
            else if (a.state == NetworkManager.ActiveConnectionState.ACTIVATED)
 | 
			
		||||
                active_any = a;
 | 
			
		||||
 | 
			
		||||
            if (a._type == 'vpn' &&
 | 
			
		||||
                (a.state == NetworkManager.ActiveConnectionState.ACTIVATING ||
 | 
			
		||||
                 a.state == NetworkManager.ActiveConnectionState.ACTIVATED))
 | 
			
		||||
                active_vpn = a;
 | 
			
		||||
 | 
			
		||||
            if (!a._primaryDevice) {
 | 
			
		||||
                if (a._type != NetworkManager.SETTING_VPN_SETTING_NAME) {
 | 
			
		||||
                    // find a good device to be considered primary
 | 
			
		||||
                    a._primaryDevice = null;
 | 
			
		||||
                    let devices = a.get_devices() || [];
 | 
			
		||||
                    for (let j = 0; j < devices.length; j++) {
 | 
			
		||||
                        let d = devices[j];
 | 
			
		||||
                        if (d._delegate) {
 | 
			
		||||
                            a._primaryDevice = d._delegate;
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                } else
 | 
			
		||||
                if (a._type != NetworkManager.SETTING_VPN_SETTING_NAME)
 | 
			
		||||
                    // This list is guaranteed to have one device in it.
 | 
			
		||||
                    a._primaryDevice = a.get_devices()[0]._delegate;
 | 
			
		||||
                else
 | 
			
		||||
                    a._primaryDevice = this._vpnSection;
 | 
			
		||||
 | 
			
		||||
                if (a._primaryDevice)
 | 
			
		||||
@@ -2108,7 +1889,7 @@ const NMApplet = new Lang.Class({
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._mainConnection = activating || default_ip4 || default_ip6 || this._activeConnections[0] || null;
 | 
			
		||||
        this._mainConnection = activating || default_ip4 || default_ip6 || active_any || null;
 | 
			
		||||
        this._vpnConnection = active_vpn;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -2134,25 +1915,7 @@ const NMApplet = new Lang.Class({
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _readConnections: function() {
 | 
			
		||||
        let connections = this._settings.list_connections();
 | 
			
		||||
        for (let i = 0; i < connections.length; i++) {
 | 
			
		||||
            let connection = connections[i];
 | 
			
		||||
            if (this._ignoreConnection(connection))
 | 
			
		||||
                continue;
 | 
			
		||||
            if (connection._updatedId) {
 | 
			
		||||
                // connection was already seen (for example because NetworkManager was restarted)
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            connection._removedId = connection.connect('removed', Lang.bind(this, this._connectionRemoved));
 | 
			
		||||
            connection._updatedId = connection.connect('updated', Lang.bind(this, this._updateConnection));
 | 
			
		||||
 | 
			
		||||
            this._updateConnection(connection);
 | 
			
		||||
            this._connections.push(connection);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _newConnection: function(settings, connection) {
 | 
			
		||||
    _addConnection: function(connection) {
 | 
			
		||||
        if (this._ignoreConnection(connection))
 | 
			
		||||
            return;
 | 
			
		||||
        if (connection._updatedId) {
 | 
			
		||||
@@ -2165,14 +1928,22 @@ const NMApplet = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._updateConnection(connection);
 | 
			
		||||
        this._connections.push(connection);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _readConnections: function() {
 | 
			
		||||
        let connections = this._settings.list_connections();
 | 
			
		||||
        connections.forEach(Lang.bind(this, this._addConnection));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _newConnection: function(settings, connection) {
 | 
			
		||||
        this._addConnection(connection);
 | 
			
		||||
        this._updateIcon();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _connectionRemoved: function(connection) {
 | 
			
		||||
        let pos = this._connections.indexOf(connection);
 | 
			
		||||
        if (pos != -1)
 | 
			
		||||
            this._connections.splice(connection);
 | 
			
		||||
            this._connections.splice(connection, 1);
 | 
			
		||||
 | 
			
		||||
        let section = connection._section;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -307,7 +307,7 @@ const Indicator = new Lang.Class({
 | 
			
		||||
            this._headphoneIcon.visible = value;
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        this._headphoneIcon = this.addIcon(new Gio.ThemedIcon({ name: 'headphones-symbolic' }));
 | 
			
		||||
        this._headphoneIcon = this.addIcon(new Gio.ThemedIcon({ name: 'audio-headphones-symbolic' }));
 | 
			
		||||
        this._headphoneIcon.visible = false;
 | 
			
		||||
 | 
			
		||||
        this.menu.addMenuItem(this._volumeMenu);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										52
									
								
								js/ui/userAvatar.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								js/ui/userAvatar.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
 | 
			
		||||
const DIALOG_ICON_SIZE = 64;
 | 
			
		||||
 | 
			
		||||
// Adapted from gdm/gui/user-switch-applet/applet.c
 | 
			
		||||
//
 | 
			
		||||
// Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
 | 
			
		||||
// Copyright (C) 2008,2009 Red Hat, Inc.
 | 
			
		||||
 | 
			
		||||
const UserAvatar = new Lang.Class({
 | 
			
		||||
    Name: 'UserAvatar',
 | 
			
		||||
 | 
			
		||||
    _init: function(user, params) {
 | 
			
		||||
        this._user = user;
 | 
			
		||||
        params = Params.parse(params, { reactive: false,
 | 
			
		||||
                                        iconSize: DIALOG_ICON_SIZE,
 | 
			
		||||
                                        styleClass: 'status-chooser-user-icon' });
 | 
			
		||||
        this._iconSize = params.iconSize;
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.Bin({ style_class: params.styleClass,
 | 
			
		||||
                                  track_hover: params.reactive,
 | 
			
		||||
                                  reactive: params.reactive });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setSensitive: function(sensitive) {
 | 
			
		||||
        this.actor.can_focus = sensitive;
 | 
			
		||||
        this.actor.reactive = sensitive;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    update: function() {
 | 
			
		||||
        let iconFile = this._user.get_icon_file();
 | 
			
		||||
        if (iconFile && !GLib.file_test(iconFile, GLib.FileTest.EXISTS))
 | 
			
		||||
            iconFile = null;
 | 
			
		||||
 | 
			
		||||
        if (iconFile) {
 | 
			
		||||
            let file = Gio.File.new_for_path(iconFile);
 | 
			
		||||
            this.actor.child = null;
 | 
			
		||||
            this.actor.style = 'background-image: url("%s");'.format(iconFile);
 | 
			
		||||
        } else {
 | 
			
		||||
            this.actor.style = null;
 | 
			
		||||
            this.actor.child = new St.Icon({ icon_name: 'avatar-default-symbolic',
 | 
			
		||||
                                             icon_size: this._iconSize });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
@@ -21,6 +21,7 @@ const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const PanelMenu = imports.ui.panelMenu;
 | 
			
		||||
const PopupMenu = imports.ui.popupMenu;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
const UserAvatar = imports.ui.userAvatar;
 | 
			
		||||
const Util = imports.misc.util;
 | 
			
		||||
 | 
			
		||||
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
 | 
			
		||||
@@ -57,48 +58,6 @@ const SystemdLoginSessionIface = <interface name='org.freedesktop.login1.Session
 | 
			
		||||
 | 
			
		||||
const SystemdLoginSession = Gio.DBusProxy.makeProxyWrapper(SystemdLoginSessionIface);
 | 
			
		||||
 | 
			
		||||
// Adapted from gdm/gui/user-switch-applet/applet.c
 | 
			
		||||
//
 | 
			
		||||
// Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
 | 
			
		||||
// Copyright (C) 2008,2009 Red Hat, Inc.
 | 
			
		||||
 | 
			
		||||
const UserAvatarWidget = new Lang.Class({
 | 
			
		||||
    Name: 'UserAvatarWidget',
 | 
			
		||||
 | 
			
		||||
    _init: function(user, params) {
 | 
			
		||||
        this._user = user;
 | 
			
		||||
        params = Params.parse(params, { reactive: false,
 | 
			
		||||
                                        iconSize: DIALOG_ICON_SIZE,
 | 
			
		||||
                                        styleClass: 'status-chooser-user-icon' });
 | 
			
		||||
        this._iconSize = params.iconSize;
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.Bin({ style_class: params.styleClass,
 | 
			
		||||
                                  track_hover: params.reactive,
 | 
			
		||||
                                  reactive: params.reactive });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setSensitive: function(sensitive) {
 | 
			
		||||
        this.actor.can_focus = sensitive;
 | 
			
		||||
        this.actor.reactive = sensitive;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    update: function() {
 | 
			
		||||
        let iconFile = this._user.get_icon_file();
 | 
			
		||||
        if (iconFile && !GLib.file_test(iconFile, GLib.FileTest.EXISTS))
 | 
			
		||||
            iconFile = null;
 | 
			
		||||
 | 
			
		||||
        if (iconFile) {
 | 
			
		||||
            let file = Gio.File.new_for_path(iconFile);
 | 
			
		||||
            this.actor.child = null;
 | 
			
		||||
            this.actor.style = 'background-image: url("%s");'.format(iconFile);
 | 
			
		||||
        } else {
 | 
			
		||||
            this.actor.style = null;
 | 
			
		||||
            this.actor.child = new St.Icon({ icon_name: 'avatar-default-symbolic',
 | 
			
		||||
                                             icon_size: this._iconSize });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const IMStatusItem = new Lang.Class({
 | 
			
		||||
    Name: 'IMStatusItem',
 | 
			
		||||
    Extends: PopupMenu.PopupBaseMenuItem,
 | 
			
		||||
@@ -170,7 +129,7 @@ const IMStatusChooserItem = new Lang.Class({
 | 
			
		||||
        this._userManager = AccountsService.UserManager.get_default();
 | 
			
		||||
        this._user = this._userManager.get_user(GLib.get_user_name());
 | 
			
		||||
 | 
			
		||||
        this._avatar = new UserAvatarWidget(this._user, { reactive: true });
 | 
			
		||||
        this._avatar = new UserAvatar.UserAvatar(this._user, { reactive: true });
 | 
			
		||||
        this._iconBin = new St.Button({ child: this._avatar.actor });
 | 
			
		||||
        this.addActor(this._iconBin);
 | 
			
		||||
 | 
			
		||||
@@ -908,7 +867,7 @@ const UserMenuButton = new Lang.Class({
 | 
			
		||||
            let session = sessions[i];
 | 
			
		||||
            let userEntry = new St.BoxLayout({ style_class: 'login-dialog-user-list-item',
 | 
			
		||||
                                               vertical: false });
 | 
			
		||||
            let avatar = new UserAvatarWidget(session.user);
 | 
			
		||||
            let avatar = new UserAvatar.UserAvatar(session.user);
 | 
			
		||||
            avatar.update();
 | 
			
		||||
            userEntry.add(avatar.actor);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ const AccountsService = imports.gi.AccountsService;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const UserMenu = imports.ui.userMenu;
 | 
			
		||||
const UserAvatar = imports.ui.userAvatar;
 | 
			
		||||
 | 
			
		||||
const UserWidget = new Lang.Class({
 | 
			
		||||
    Name: 'UserWidget',
 | 
			
		||||
@@ -16,8 +16,9 @@ const UserWidget = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.BoxLayout({ style_class: 'user-widget',
 | 
			
		||||
                                        vertical: false });
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 | 
			
		||||
 | 
			
		||||
        this._avatar = new UserMenu.UserAvatarWidget(user);
 | 
			
		||||
        this._avatar = new UserAvatar.UserAvatar(user);
 | 
			
		||||
        this.actor.add(this._avatar.actor,
 | 
			
		||||
                       { x_fill: true, y_fill: true });
 | 
			
		||||
 | 
			
		||||
@@ -36,7 +37,7 @@ const UserWidget = new Lang.Class({
 | 
			
		||||
            this._updateUser();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy: function() {
 | 
			
		||||
    _onDestroy: function() {
 | 
			
		||||
        if (this._userLoadedId != 0) {
 | 
			
		||||
            this._user.disconnect(this._userLoadedId);
 | 
			
		||||
            this._userLoadedId = 0;
 | 
			
		||||
@@ -46,8 +47,6 @@ const UserWidget = new Lang.Class({
 | 
			
		||||
            this._user.disconnect(this._userChangedId);
 | 
			
		||||
            this._userChangedId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.actor.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateUser: function() {
 | 
			
		||||
 
 | 
			
		||||
@@ -150,6 +150,14 @@ const ViewSelector = new Lang.Class({
 | 
			
		||||
                              Shell.KeyBindingMode.NORMAL |
 | 
			
		||||
                              Shell.KeyBindingMode.OVERVIEW,
 | 
			
		||||
                              Lang.bind(this, this._toggleAppsPage));
 | 
			
		||||
 | 
			
		||||
        Main.wm.addKeybinding('toggle-overview',
 | 
			
		||||
                              new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
 | 
			
		||||
                              Meta.KeyBindingFlags.NONE,
 | 
			
		||||
                              Shell.KeyBindingMode.NORMAL |
 | 
			
		||||
                              Shell.KeyBindingMode.OVERVIEW,
 | 
			
		||||
                              Lang.bind(Main.overview, Main.overview.toggle));
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _toggleAppsPage: function() {
 | 
			
		||||
@@ -178,6 +186,10 @@ const ViewSelector = new Lang.Class({
 | 
			
		||||
            Main.overview.fadeInDesktop();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setWorkspacesFullGeometry: function(geom) {
 | 
			
		||||
        this._workspacesDisplay.setWorkspacesFullGeometry(geom);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hide: function() {
 | 
			
		||||
        this._workspacesDisplay.hide();
 | 
			
		||||
    },
 | 
			
		||||
@@ -496,12 +508,12 @@ const ViewSelector = new Lang.Class({
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._searchSystem.registerProvider(provider);
 | 
			
		||||
        this._searchResults.createProviderMeta(provider);
 | 
			
		||||
        this._searchResults.createProviderDisplay(provider);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    removeSearchProvider: function(provider) {
 | 
			
		||||
        this._searchSystem.unregisterProvider(provider);
 | 
			
		||||
        this._searchResults.destroyProviderMeta(provider);
 | 
			
		||||
        this._searchResults.destroyProviderDisplay(provider);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getActivePage: function() {
 | 
			
		||||
 
 | 
			
		||||
@@ -134,9 +134,9 @@ const WandaSearchProvider = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    getInitialResultSet: function(terms) {
 | 
			
		||||
        if (terms.join(' ') == MAGIC_FISH_KEY) {
 | 
			
		||||
            this.searchSystem.pushResults(this, [ FISH_NAME ]);
 | 
			
		||||
            this.searchSystem.setResults(this, [ FISH_NAME ]);
 | 
			
		||||
        } else {
 | 
			
		||||
            this.searchSystem.pushResults(this, []);
 | 
			
		||||
            this.searchSystem.setResults(this, []);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ const Clutter = imports.gi.Clutter;
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
@@ -66,6 +67,209 @@ function getWindowDimmer(actor) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * When the last window closed on a workspace is a dialog or splash
 | 
			
		||||
 * screen, we assume that it might be an initial window shown before
 | 
			
		||||
 * the main window of an application, and give the app a grace period
 | 
			
		||||
 * where it can map another window before we remove the workspace.
 | 
			
		||||
 */
 | 
			
		||||
const LAST_WINDOW_GRACE_TIME = 1000;
 | 
			
		||||
 | 
			
		||||
const WorkspaceTracker = new Lang.Class({
 | 
			
		||||
    Name: 'WorkspaceTracker',
 | 
			
		||||
 | 
			
		||||
    _init: function(wm) {
 | 
			
		||||
        this._wm = wm;
 | 
			
		||||
 | 
			
		||||
        this._workspaces = [];
 | 
			
		||||
        this._checkWorkspacesId = 0;
 | 
			
		||||
 | 
			
		||||
        let tracker = Shell.WindowTracker.get_default();
 | 
			
		||||
        tracker.connect('startup-sequence-changed', Lang.bind(this, this._queueCheckWorkspaces));
 | 
			
		||||
 | 
			
		||||
        global.screen.connect('notify::n-workspaces', Lang.bind(this, this._nWorkspacesChanged));
 | 
			
		||||
 | 
			
		||||
        global.screen.connect('window-entered-monitor', Lang.bind(this, this._windowEnteredMonitor));
 | 
			
		||||
        global.screen.connect('window-left-monitor', Lang.bind(this, this._windowLeftMonitor));
 | 
			
		||||
        global.screen.connect('restacked', Lang.bind(this, this._windowsRestacked));
 | 
			
		||||
 | 
			
		||||
        this._overrideSettings = new Gio.Settings({ schema: 'org.gnome.shell.overrides' });
 | 
			
		||||
        this._overrideSettings.connect('changed::dynamic-workspaces', Lang.bind(this, this._queueCheckWorkspaces));
 | 
			
		||||
 | 
			
		||||
        this._nWorkspacesChanged();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _checkWorkspaces: function() {
 | 
			
		||||
        let i;
 | 
			
		||||
        let emptyWorkspaces = [];
 | 
			
		||||
 | 
			
		||||
        if (!Meta.prefs_get_dynamic_workspaces()) {
 | 
			
		||||
            this._checkWorkspacesId = 0;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (i = 0; i < this._workspaces.length; i++) {
 | 
			
		||||
            let lastRemoved = this._workspaces[i]._lastRemovedWindow;
 | 
			
		||||
            if ((lastRemoved &&
 | 
			
		||||
                 (lastRemoved.get_window_type() == Meta.WindowType.SPLASHSCREEN ||
 | 
			
		||||
                  lastRemoved.get_window_type() == Meta.WindowType.DIALOG ||
 | 
			
		||||
                  lastRemoved.get_window_type() == Meta.WindowType.MODAL_DIALOG)) ||
 | 
			
		||||
                this._workspaces[i]._keepAliveId)
 | 
			
		||||
                emptyWorkspaces[i] = false;
 | 
			
		||||
            else
 | 
			
		||||
                emptyWorkspaces[i] = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let sequences = Shell.WindowTracker.get_default().get_startup_sequences();
 | 
			
		||||
        for (i = 0; i < sequences.length; i++) {
 | 
			
		||||
            let index = sequences[i].get_workspace();
 | 
			
		||||
            if (index >= 0 && index <= global.screen.n_workspaces)
 | 
			
		||||
                emptyWorkspaces[index] = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let windows = global.get_window_actors();
 | 
			
		||||
        for (i = 0; i < windows.length; i++) {
 | 
			
		||||
            let win = windows[i];
 | 
			
		||||
 | 
			
		||||
            if (win.get_meta_window().is_on_all_workspaces())
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            let workspaceIndex = win.get_workspace();
 | 
			
		||||
            emptyWorkspaces[workspaceIndex] = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If we don't have an empty workspace at the end, add one
 | 
			
		||||
        if (!emptyWorkspaces[emptyWorkspaces.length -1]) {
 | 
			
		||||
            global.screen.append_new_workspace(false, global.get_current_time());
 | 
			
		||||
            emptyWorkspaces.push(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let activeWorkspaceIndex = global.screen.get_active_workspace_index();
 | 
			
		||||
        let removingCurrentWorkspace = (emptyWorkspaces[activeWorkspaceIndex] &&
 | 
			
		||||
                                        activeWorkspaceIndex < emptyWorkspaces.length - 1);
 | 
			
		||||
        // Don't enter the overview when removing multiple empty workspaces at startup
 | 
			
		||||
        let showOverview  = (removingCurrentWorkspace &&
 | 
			
		||||
                             !emptyWorkspaces.every(function(x) { return x; }));
 | 
			
		||||
 | 
			
		||||
        if (removingCurrentWorkspace) {
 | 
			
		||||
            // "Merge" the empty workspace we are removing with the one at the end
 | 
			
		||||
            this._wm.blockAnimations();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Delete other empty workspaces; do it from the end to avoid index changes
 | 
			
		||||
        for (i = emptyWorkspaces.length - 2; i >= 0; i--) {
 | 
			
		||||
            if (emptyWorkspaces[i])
 | 
			
		||||
                global.screen.remove_workspace(this._workspaces[i], global.get_current_time());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (removingCurrentWorkspace) {
 | 
			
		||||
            global.screen.get_workspace_by_index(global.screen.n_workspaces - 1).activate(global.get_current_time());
 | 
			
		||||
            this._wm.unblockAnimations();
 | 
			
		||||
 | 
			
		||||
            if (!Main.overview.visible && showOverview)
 | 
			
		||||
                Main.overview.show();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._checkWorkspacesId = 0;
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    keepWorkspaceAlive: function(workspace, duration) {
 | 
			
		||||
        if (workspace._keepAliveId)
 | 
			
		||||
            Mainloop.source_remove(workspace._keepAliveId);
 | 
			
		||||
 | 
			
		||||
        workspace._keepAliveId = Mainloop.timeout_add(duration, Lang.bind(this, function() {
 | 
			
		||||
            workspace._keepAliveId = 0;
 | 
			
		||||
            this._queueCheckWorkspaces();
 | 
			
		||||
            return false;
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _windowRemoved: function(workspace, window) {
 | 
			
		||||
        workspace._lastRemovedWindow = window;
 | 
			
		||||
        this._queueCheckWorkspaces();
 | 
			
		||||
        Mainloop.timeout_add(LAST_WINDOW_GRACE_TIME, Lang.bind(this, function() {
 | 
			
		||||
            if (workspace._lastRemovedWindow == window) {
 | 
			
		||||
                workspace._lastRemovedWindow = null;
 | 
			
		||||
                this._queueCheckWorkspaces();
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _windowLeftMonitor: function(metaScreen, monitorIndex, metaWin) {
 | 
			
		||||
        // If the window left the primary monitor, that
 | 
			
		||||
        // might make that workspace empty
 | 
			
		||||
        if (monitorIndex == Main.layoutManager.primaryIndex)
 | 
			
		||||
            this._queueCheckWorkspaces();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _windowEnteredMonitor: function(metaScreen, monitorIndex, metaWin) {
 | 
			
		||||
        // If the window entered the primary monitor, that
 | 
			
		||||
        // might make that workspace non-empty
 | 
			
		||||
        if (monitorIndex == Main.layoutManager.primaryIndex)
 | 
			
		||||
            this._queueCheckWorkspaces();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _windowsRestacked: function() {
 | 
			
		||||
        // Figure out where the pointer is in case we lost track of
 | 
			
		||||
        // it during a grab. (In particular, if a trayicon popup menu
 | 
			
		||||
        // is dismissed, see if we need to close the message tray.)
 | 
			
		||||
        global.sync_pointer();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _queueCheckWorkspaces: function() {
 | 
			
		||||
        if (this._checkWorkspacesId == 0)
 | 
			
		||||
            this._checkWorkspacesId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, this._checkWorkspaces));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _nWorkspacesChanged: function() {
 | 
			
		||||
        let oldNumWorkspaces = this._workspaces.length;
 | 
			
		||||
        let newNumWorkspaces = global.screen.n_workspaces;
 | 
			
		||||
 | 
			
		||||
        if (oldNumWorkspaces == newNumWorkspaces)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        let lostWorkspaces = [];
 | 
			
		||||
        if (newNumWorkspaces > oldNumWorkspaces) {
 | 
			
		||||
            let w;
 | 
			
		||||
 | 
			
		||||
            // Assume workspaces are only added at the end
 | 
			
		||||
            for (w = oldNumWorkspaces; w < newNumWorkspaces; w++)
 | 
			
		||||
                this._workspaces[w] = global.screen.get_workspace_by_index(w);
 | 
			
		||||
 | 
			
		||||
            for (w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
 | 
			
		||||
                let workspace = this._workspaces[w];
 | 
			
		||||
                workspace._windowAddedId = workspace.connect('window-added', Lang.bind(this, this._queueCheckWorkspaces));
 | 
			
		||||
                workspace._windowRemovedId = workspace.connect('window-removed', Lang.bind(this, this._windowRemoved));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        } else {
 | 
			
		||||
            // Assume workspaces are only removed sequentially
 | 
			
		||||
            // (e.g. 2,3,4 - not 2,4,7)
 | 
			
		||||
            let removedIndex;
 | 
			
		||||
            let removedNum = oldNumWorkspaces - newNumWorkspaces;
 | 
			
		||||
            for (let w = 0; w < oldNumWorkspaces; w++) {
 | 
			
		||||
                let workspace = global.screen.get_workspace_by_index(w);
 | 
			
		||||
                if (this._workspaces[w] != workspace) {
 | 
			
		||||
                    removedIndex = w;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let lostWorkspaces = this._workspaces.splice(removedIndex, removedNum);
 | 
			
		||||
            lostWorkspaces.forEach(function(workspace) {
 | 
			
		||||
                workspace.disconnect(workspace._windowAddedId);
 | 
			
		||||
                workspace.disconnect(workspace._windowRemovedId);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._queueCheckWorkspaces();
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const WindowManager = new Lang.Class({
 | 
			
		||||
    Name: 'WindowManager',
 | 
			
		||||
 | 
			
		||||
@@ -136,6 +340,90 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL |
 | 
			
		||||
                                        Shell.KeyBindingMode.OVERVIEW,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('switch-to-workspace-1',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL |
 | 
			
		||||
                                        Shell.KeyBindingMode.OVERVIEW,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('switch-to-workspace-2',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL |
 | 
			
		||||
                                        Shell.KeyBindingMode.OVERVIEW,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('switch-to-workspace-3',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL |
 | 
			
		||||
                                        Shell.KeyBindingMode.OVERVIEW,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('switch-to-workspace-4',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL |
 | 
			
		||||
                                        Shell.KeyBindingMode.OVERVIEW,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('switch-to-workspace-5',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL |
 | 
			
		||||
                                        Shell.KeyBindingMode.OVERVIEW,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('switch-to-workspace-6',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL |
 | 
			
		||||
                                        Shell.KeyBindingMode.OVERVIEW,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('switch-to-workspace-7',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL |
 | 
			
		||||
                                        Shell.KeyBindingMode.OVERVIEW,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('switch-to-workspace-8',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL |
 | 
			
		||||
                                        Shell.KeyBindingMode.OVERVIEW,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('switch-to-workspace-9',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL |
 | 
			
		||||
                                        Shell.KeyBindingMode.OVERVIEW,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('switch-to-workspace-10',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL |
 | 
			
		||||
                                        Shell.KeyBindingMode.OVERVIEW,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('switch-to-workspace-11',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL |
 | 
			
		||||
                                        Shell.KeyBindingMode.OVERVIEW,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('switch-to-workspace-12',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL |
 | 
			
		||||
                                        Shell.KeyBindingMode.OVERVIEW,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('move-to-workspace-1',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('move-to-workspace-2',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('move-to-workspace-3',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('move-to-workspace-4',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('move-to-workspace-5',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('move-to-workspace-6',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('move-to-workspace-7',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('move-to-workspace-8',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('move-to-workspace-9',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('move-to-workspace-10',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('move-to-workspace-11',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('move-to-workspace-12',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._showWorkspaceSwitcher));
 | 
			
		||||
        this.setCustomKeybindingHandler('switch-applications',
 | 
			
		||||
                                        Shell.KeyBindingMode.NORMAL,
 | 
			
		||||
                                        Lang.bind(this, this._startAppSwitcher));
 | 
			
		||||
@@ -172,8 +460,9 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
        this.addKeybinding('open-application-menu',
 | 
			
		||||
                           new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
 | 
			
		||||
                           Meta.KeyBindingFlags.NONE,
 | 
			
		||||
                           Shell.KeyBindingMode.NORMAL,
 | 
			
		||||
                           Lang.bind(this, this._openAppMenu));
 | 
			
		||||
                           Shell.KeyBindingMode.NORMAL |
 | 
			
		||||
                           Shell.KeyBindingMode.TOPBAR_POPUP,
 | 
			
		||||
                           Lang.bind(this, this._toggleAppMenu));
 | 
			
		||||
 | 
			
		||||
        Main.overview.connect('showing', Lang.bind(this, function() {
 | 
			
		||||
            for (let i = 0; i < this._dimmedWindows.length; i++)
 | 
			
		||||
@@ -183,6 +472,11 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
            for (let i = 0; i < this._dimmedWindows.length; i++)
 | 
			
		||||
                this._dimWindow(this._dimmedWindows[i]);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        this._workspaceTracker = new WorkspaceTracker(this);
 | 
			
		||||
 | 
			
		||||
        global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
 | 
			
		||||
                                                false, -1, 1);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setCustomKeybindingHandler: function(name, modes, handler) {
 | 
			
		||||
@@ -679,27 +973,39 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
        Main.ctrlAltTabManager.popup(backwards, binding.get_name(), binding.get_mask());
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _openAppMenu : function(display, screen, window, event, binding) {
 | 
			
		||||
        Main.panel.openAppMenu();
 | 
			
		||||
    _toggleAppMenu : function(display, screen, window, event, binding) {
 | 
			
		||||
        Main.panel.toggleAppMenu();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showWorkspaceSwitcher : function(display, screen, window, binding) {
 | 
			
		||||
        if (screen.n_workspaces == 1)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let [action,,,direction] = binding.get_name().split('-');
 | 
			
		||||
        let direction = Meta.MotionDirection[direction.toUpperCase()];
 | 
			
		||||
        let [action,,,target] = binding.get_name().split('-');
 | 
			
		||||
        let newWs;
 | 
			
		||||
        let direction;
 | 
			
		||||
 | 
			
		||||
        if (isNaN(target)) {
 | 
			
		||||
            direction = Meta.MotionDirection[target.toUpperCase()];
 | 
			
		||||
            newWs = screen.get_active_workspace().get_neighbor(direction);
 | 
			
		||||
        } else if (target > 0) {
 | 
			
		||||
            target--;
 | 
			
		||||
            newWs = screen.get_workspace_by_index(target);
 | 
			
		||||
 | 
			
		||||
            if (screen.get_active_workspace().index() > target)
 | 
			
		||||
                direction = Meta.MotionDirection.UP;
 | 
			
		||||
            else
 | 
			
		||||
                direction = Meta.MotionDirection.DOWN;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (direction != Meta.MotionDirection.UP &&
 | 
			
		||||
            direction != Meta.MotionDirection.DOWN)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (action == 'switch')
 | 
			
		||||
            newWs = this.actionMoveWorkspace(direction);
 | 
			
		||||
            this.actionMoveWorkspace(newWs);
 | 
			
		||||
        else
 | 
			
		||||
            newWs = this.actionMoveWindow(window, direction);
 | 
			
		||||
            this.actionMoveWindow(window, newWs);
 | 
			
		||||
 | 
			
		||||
        if (!Main.overview.visible) {
 | 
			
		||||
            if (this._workspaceSwitcherPopup == null) {
 | 
			
		||||
@@ -712,31 +1018,27 @@ const WindowManager = new Lang.Class({
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    actionMoveWorkspace: function(direction) {
 | 
			
		||||
    actionMoveWorkspace: function(workspace) {
 | 
			
		||||
        let activeWorkspace = global.screen.get_active_workspace();
 | 
			
		||||
        let toActivate = activeWorkspace.get_neighbor(direction);
 | 
			
		||||
 | 
			
		||||
        if (activeWorkspace != toActivate)
 | 
			
		||||
            toActivate.activate(global.get_current_time());
 | 
			
		||||
        if (activeWorkspace != workspace)
 | 
			
		||||
            workspace.activate(global.get_current_time());
 | 
			
		||||
 | 
			
		||||
        return toActivate;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    actionMoveWindow: function(window, direction) {
 | 
			
		||||
    actionMoveWindow: function(window, workspace) {
 | 
			
		||||
        let activeWorkspace = global.screen.get_active_workspace();
 | 
			
		||||
        let toActivate = activeWorkspace.get_neighbor(direction);
 | 
			
		||||
 | 
			
		||||
        if (activeWorkspace != toActivate) {
 | 
			
		||||
        if (activeWorkspace != workspace) {
 | 
			
		||||
            // This won't have any effect for "always sticky" windows
 | 
			
		||||
            // (like desktop windows or docks)
 | 
			
		||||
 | 
			
		||||
            this._movingWindow = window;
 | 
			
		||||
            window.change_workspace(toActivate);
 | 
			
		||||
            window.change_workspace(workspace);
 | 
			
		||||
 | 
			
		||||
            global.display.clear_mouse_mode();
 | 
			
		||||
            toActivate.activate_with_focus (window, global.get_current_time());
 | 
			
		||||
            workspace.activate_with_focus (window, global.get_current_time());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return toActivate;
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -453,6 +453,10 @@ const WindowOverlay = new Lang.Class({
 | 
			
		||||
        metaWindow.delete(global.get_current_time());
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _windowCanClose: function() {
 | 
			
		||||
        return this._windowClone.metaWindow.can_close();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onWindowAdded: function(workspace, win) {
 | 
			
		||||
        let metaWindow = this._windowClone.metaWindow;
 | 
			
		||||
 | 
			
		||||
@@ -488,12 +492,14 @@ const WindowOverlay = new Lang.Class({
 | 
			
		||||
    _animateVisible: function() {
 | 
			
		||||
        this._parentActor.raise_top();
 | 
			
		||||
 | 
			
		||||
        this.closeButton.show();
 | 
			
		||||
        this.closeButton.opacity = 0;
 | 
			
		||||
        Tweener.addTween(this.closeButton,
 | 
			
		||||
                         { opacity: 255,
 | 
			
		||||
                           time: CLOSE_BUTTON_FADE_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad' });
 | 
			
		||||
        if (this._windowCanClose()) {
 | 
			
		||||
            this.closeButton.show();
 | 
			
		||||
            this.closeButton.opacity = 0;
 | 
			
		||||
            Tweener.addTween(this.closeButton,
 | 
			
		||||
                             { opacity: 255,
 | 
			
		||||
                               time: CLOSE_BUTTON_FADE_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad' });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.border.show();
 | 
			
		||||
        this.border.opacity = 0;
 | 
			
		||||
@@ -753,13 +759,6 @@ const LayoutStrategy = new Lang.Class({
 | 
			
		||||
        layout.space = space;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getDistance: function (row, actor) {
 | 
			
		||||
        let dist_x = actor.x - row.x;
 | 
			
		||||
        let dist_y = actor.y - row.y;
 | 
			
		||||
 | 
			
		||||
        return Math.sqrt(Math.pow(dist_x, 2) + Math.pow(dist_y, 2));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    computeWindowSlots: function(layout, area) {
 | 
			
		||||
        this._computeRowSizes(layout);
 | 
			
		||||
 | 
			
		||||
@@ -767,28 +766,36 @@ const LayoutStrategy = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        let slots = [];
 | 
			
		||||
 | 
			
		||||
        let y = 0;
 | 
			
		||||
        // Do this in three parts.
 | 
			
		||||
        let height = 0;
 | 
			
		||||
        for (let i = 0; i < rows.length; i++) {
 | 
			
		||||
            let row = rows[i];
 | 
			
		||||
            row.x = area.x + (area.width - row.width) / 2;
 | 
			
		||||
            row.y = area.y + y;
 | 
			
		||||
            y += row.height + this._rowSpacing;
 | 
			
		||||
            row.windows.sort(Lang.bind(this, function(a, b) {
 | 
			
		||||
                return this._getDistance(row, a.realWindow) - this._getDistance(row, b.realWindow);
 | 
			
		||||
            }));
 | 
			
		||||
            height += row.height + this._rowSpacing;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let height = y - this._rowSpacing;
 | 
			
		||||
        let baseY = (area.height - height) / 2;
 | 
			
		||||
        height -= this._rowSpacing;
 | 
			
		||||
 | 
			
		||||
        let y = 0;
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < rows.length; i++) {
 | 
			
		||||
            let row = rows[i];
 | 
			
		||||
 | 
			
		||||
            // If this window layout row doesn't fit in the actual
 | 
			
		||||
            // geometry, then apply an additional scale to it.
 | 
			
		||||
            row.additionalScale = Math.min(1, area.width / row.width, area.height / height);
 | 
			
		||||
 | 
			
		||||
            row.x = area.x + (Math.max(area.width - row.width, 0) / 2) * row.additionalScale;
 | 
			
		||||
            row.y = area.y + (y + Math.max(area.height - height, 0) / 2) * row.additionalScale;
 | 
			
		||||
            y += row.height + this._rowSpacing;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < rows.length; i++) {
 | 
			
		||||
            let row = rows[i];
 | 
			
		||||
            row.y += baseY;
 | 
			
		||||
            let x = row.x;
 | 
			
		||||
            for (let j = 0; j < row.windows.length; j++) {
 | 
			
		||||
                let window = row.windows[j];
 | 
			
		||||
 | 
			
		||||
                let s = scale * this._computeWindowScale(window);
 | 
			
		||||
                let s = scale * this._computeWindowScale(window) * row.additionalScale;
 | 
			
		||||
                let cellWidth = window.actor.width * s;
 | 
			
		||||
                let cellHeight = window.actor.height * s;
 | 
			
		||||
 | 
			
		||||
@@ -832,6 +839,13 @@ const UnalignedLayoutStrategy = new Lang.Class({
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _sortRow: function(row) {
 | 
			
		||||
        // Sort windows horizontally to minimize travel distance
 | 
			
		||||
        row.windows.sort(function(a, b) {
 | 
			
		||||
            return a.realWindow.x - b.realWindow.x;
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    computeLayout: function(windows, layout) {
 | 
			
		||||
        let numRows = layout.numRows;
 | 
			
		||||
 | 
			
		||||
@@ -862,6 +876,7 @@ const UnalignedLayoutStrategy = new Lang.Class({
 | 
			
		||||
                    row.windows.push(window);
 | 
			
		||||
                    row.fullWidth += width;
 | 
			
		||||
                } else {
 | 
			
		||||
                    this._sortRow(row);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -883,6 +898,14 @@ const UnalignedLayoutStrategy = new Lang.Class({
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function padArea(area, padding) {
 | 
			
		||||
    return {
 | 
			
		||||
        x: area.x + padding.left,
 | 
			
		||||
        y: area.y + padding.top,
 | 
			
		||||
        width: area.width - padding.left - padding.right,
 | 
			
		||||
        height: area.height - padding.top - padding.bottom,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @metaWorkspace: a #Meta.Workspace, or null
 | 
			
		||||
@@ -894,10 +917,19 @@ const Workspace = new Lang.Class({
 | 
			
		||||
        // When dragging a window, we use this slot for reserve space.
 | 
			
		||||
        this._reservedSlot = null;
 | 
			
		||||
        this.metaWorkspace = metaWorkspace;
 | 
			
		||||
        this._x = 0;
 | 
			
		||||
        this._y = 0;
 | 
			
		||||
        this._width = 0;
 | 
			
		||||
        this._height = 0;
 | 
			
		||||
 | 
			
		||||
        // The full geometry is the geometry we should try and position
 | 
			
		||||
        // windows for. The actual geometry we allocate may be less than
 | 
			
		||||
        // this, like if the workspace switcher is slid out.
 | 
			
		||||
        this._fullGeometry = null;
 | 
			
		||||
 | 
			
		||||
        // The actual geometry is the geometry we need to arrange windows
 | 
			
		||||
        // in. If this is a smaller area than the full geometry, we'll
 | 
			
		||||
        // do some simple aspect ratio like math to fit the layout calculated
 | 
			
		||||
        // for the full geometry into this area.
 | 
			
		||||
        this._actualGeometry = null;
 | 
			
		||||
 | 
			
		||||
        this._currentLayout = null;
 | 
			
		||||
 | 
			
		||||
        this.monitorIndex = monitorIndex;
 | 
			
		||||
        this._monitor = Main.layoutManager.monitors[this.monitorIndex];
 | 
			
		||||
@@ -910,7 +942,7 @@ const Workspace = new Lang.Class({
 | 
			
		||||
            this.actor.add_style_class_name('external-monitor');
 | 
			
		||||
        this.actor.set_size(0, 0);
 | 
			
		||||
 | 
			
		||||
        this._dropRect = new Clutter.Rectangle({ opacity: 0 });
 | 
			
		||||
        this._dropRect = new Clutter.Actor({ opacity: 0 });
 | 
			
		||||
        this._dropRect._delegate = this;
 | 
			
		||||
 | 
			
		||||
        this.actor.add_actor(this._dropRect);
 | 
			
		||||
@@ -947,23 +979,29 @@ const Workspace = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._positionWindowsFlags = 0;
 | 
			
		||||
        this._positionWindowsId = 0;
 | 
			
		||||
 | 
			
		||||
        this._currentLayout = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setGeometry: function(x, y, width, height) {
 | 
			
		||||
        this._x = x;
 | 
			
		||||
        this._y = y;
 | 
			
		||||
        this._width = width;
 | 
			
		||||
        this._height = height;
 | 
			
		||||
    setFullGeometry: function(geom) {
 | 
			
		||||
        this._fullGeometry = geom;
 | 
			
		||||
        this._recalculateWindowPositions(WindowPositionFlags.NONE);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
        Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
 | 
			
		||||
            this._dropRect.set_position(x, y);
 | 
			
		||||
            this._dropRect.set_size(width, height);
 | 
			
		||||
    setActualGeometry: function(geom) {
 | 
			
		||||
        this._actualGeometry = geom;
 | 
			
		||||
 | 
			
		||||
        if (this._actualGeometryLater)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._actualGeometryLater = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
 | 
			
		||||
            let geom = this._actualGeometry;
 | 
			
		||||
 | 
			
		||||
            this._dropRect.set_position(geom.x, geom.y);
 | 
			
		||||
            this._dropRect.set_size(geom.width, geom.height);
 | 
			
		||||
            this._updateWindowPositions(WindowPositionFlags.NONE);
 | 
			
		||||
 | 
			
		||||
            this._actualGeometryLater = 0;
 | 
			
		||||
            return false;
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        this.positionWindows(WindowPositionFlags.NONE);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _lookupIndex: function (metaWindow) {
 | 
			
		||||
@@ -991,37 +1029,32 @@ const Workspace = new Lang.Class({
 | 
			
		||||
            clone = null;
 | 
			
		||||
 | 
			
		||||
        this._reservedSlot = clone;
 | 
			
		||||
        this._currentLayout = null;
 | 
			
		||||
        this.positionWindows(WindowPositionFlags.ANIMATE);
 | 
			
		||||
        this._recalculateWindowPositions(WindowPositionFlags.ANIMATE);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * positionWindows:
 | 
			
		||||
     * @flags:
 | 
			
		||||
     *  INITIAL - this is the initial positioning of the windows.
 | 
			
		||||
     *  ANIMATE - Indicates that we need animate changing position.
 | 
			
		||||
     */
 | 
			
		||||
    positionWindows: function(flags) {
 | 
			
		||||
    _recalculateWindowPositions: function(flags) {
 | 
			
		||||
        this._positionWindowsFlags |= flags;
 | 
			
		||||
 | 
			
		||||
        if (this._positionWindowsId > 0)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._positionWindowsId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
 | 
			
		||||
            this._realPositionWindows(this._positionWindowsFlags);
 | 
			
		||||
            this._realRecalculateWindowPositions(this._positionWindowsFlags);
 | 
			
		||||
            this._positionWindowsFlags = 0;
 | 
			
		||||
            this._positionWindowsId = 0;
 | 
			
		||||
            return false;
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _realPositionWindows : function(flags) {
 | 
			
		||||
    _realRecalculateWindowPositions: function(flags) {
 | 
			
		||||
        if (this._repositionWindowsId > 0) {
 | 
			
		||||
            Mainloop.source_remove(this._repositionWindowsId);
 | 
			
		||||
            this._repositionWindowsId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let clones = this._windows.slice();
 | 
			
		||||
        if (clones.length == 0)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        clones.sort(function(a, b) {
 | 
			
		||||
            return a.metaWindow.get_stable_sequence() - b.metaWindow.get_stable_sequence();
 | 
			
		||||
@@ -1030,11 +1063,25 @@ const Workspace = new Lang.Class({
 | 
			
		||||
        if (this._reservedSlot)
 | 
			
		||||
            clones.push(this._reservedSlot);
 | 
			
		||||
 | 
			
		||||
        this._currentLayout = this._computeLayout(clones);
 | 
			
		||||
        this._updateWindowPositions(flags);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateWindowPositions: function(flags) {
 | 
			
		||||
        if (this._currentLayout == null) {
 | 
			
		||||
            this._recalculateWindowPositions(flags);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let initialPositioning = flags & WindowPositionFlags.INITIAL;
 | 
			
		||||
        let animate = flags & WindowPositionFlags.ANIMATE;
 | 
			
		||||
 | 
			
		||||
        // Start the animations
 | 
			
		||||
        let slots = this._computeAllWindowSlots(clones);
 | 
			
		||||
        let layout = this._currentLayout;
 | 
			
		||||
        let strategy = layout.strategy;
 | 
			
		||||
 | 
			
		||||
        let [, , padding] = this._getSpacingAndPadding();
 | 
			
		||||
        let area = padArea(this._actualGeometry, padding);
 | 
			
		||||
        let slots = strategy.computeWindowSlots(layout, area);
 | 
			
		||||
 | 
			
		||||
        let currentWorkspace = global.screen.get_active_workspace();
 | 
			
		||||
        let isOnCurrentWorkspace = this.metaWorkspace == null || this.metaWorkspace == currentWorkspace;
 | 
			
		||||
@@ -1148,8 +1195,8 @@ const Workspace = new Lang.Class({
 | 
			
		||||
        let [x, y, mask] = global.get_pointer();
 | 
			
		||||
 | 
			
		||||
        let pointerHasMoved = (this._cursorX != x && this._cursorY != y);
 | 
			
		||||
        let inWorkspace = (this._x < x && x < this._x + this._width &&
 | 
			
		||||
                           this._y < y && y < this._y + this._height);
 | 
			
		||||
        let inWorkspace = (this._fullGeometry.x < x && x < this._fullGeometry.x + this._fullGeometry.width &&
 | 
			
		||||
                           this._fullGeometry.y < y && y < this._fullGeometry.y + this._fullGeometry.height);
 | 
			
		||||
 | 
			
		||||
        if (pointerHasMoved && inWorkspace) {
 | 
			
		||||
            // store current cursor position
 | 
			
		||||
@@ -1164,7 +1211,7 @@ const Workspace = new Lang.Class({
 | 
			
		||||
                return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.positionWindows(WindowPositionFlags.ANIMATE);
 | 
			
		||||
        this._recalculateWindowPositions(WindowPositionFlags.ANIMATE);
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -1269,7 +1316,7 @@ const Workspace = new Lang.Class({
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._currentLayout = null;
 | 
			
		||||
        this.positionWindows(WindowPositionFlags.ANIMATE);
 | 
			
		||||
        this._recalculateWindowPositions(WindowPositionFlags.ANIMATE);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _windowAdded : function(metaWorkspace, metaWin) {
 | 
			
		||||
@@ -1306,13 +1353,8 @@ const Workspace = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    // Animate the full-screen to Overview transition.
 | 
			
		||||
    zoomToOverview : function() {
 | 
			
		||||
        this._currentLayout = null;
 | 
			
		||||
 | 
			
		||||
        // Position and scale the windows.
 | 
			
		||||
        if (Main.overview.animationInProgress)
 | 
			
		||||
            this.positionWindows(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
 | 
			
		||||
        else
 | 
			
		||||
            this.positionWindows(WindowPositionFlags.INITIAL);
 | 
			
		||||
        this._recalculateWindowPositions(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Animates the return from Overview mode
 | 
			
		||||
@@ -1436,7 +1478,7 @@ const Workspace = new Lang.Class({
 | 
			
		||||
                      }));
 | 
			
		||||
        clone.connect('size-changed',
 | 
			
		||||
                      Lang.bind(this, function() {
 | 
			
		||||
                          this.positionWindows(0);
 | 
			
		||||
                          this._recalculateWindowPositions(WindowPositionFlags.NONE);
 | 
			
		||||
                      }));
 | 
			
		||||
 | 
			
		||||
        this.actor.add_actor(clone.actor);
 | 
			
		||||
@@ -1485,12 +1527,14 @@ const Workspace = new Lang.Class({
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _computeLayout: function(windows, area, rowSpacing, columnSpacing) {
 | 
			
		||||
    _getBestLayout: function(windows, area, rowSpacing, columnSpacing) {
 | 
			
		||||
        // We look for the largest scale that allows us to fit the
 | 
			
		||||
        // largest row/tallest column on the workspace.
 | 
			
		||||
 | 
			
		||||
        let lastLayout = {};
 | 
			
		||||
 | 
			
		||||
        let strategy = new UnalignedLayoutStrategy(this._monitor, rowSpacing, columnSpacing);
 | 
			
		||||
 | 
			
		||||
        for (let numRows = 1; ; numRows++) {
 | 
			
		||||
            let numColumns = Math.ceil(windows.length / numRows);
 | 
			
		||||
 | 
			
		||||
@@ -1500,8 +1544,6 @@ const Workspace = new Lang.Class({
 | 
			
		||||
            if (numColumns == lastLayout.numColumns)
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            let strategy = new UnalignedLayoutStrategy(this._monitor, rowSpacing, columnSpacing);
 | 
			
		||||
 | 
			
		||||
            let layout = { area: area, strategy: strategy, numRows: numRows, numColumns: numColumns };
 | 
			
		||||
            strategy.computeLayout(windows, layout);
 | 
			
		||||
            strategy.computeScaleAndSpace(layout);
 | 
			
		||||
@@ -1515,18 +1557,7 @@ const Workspace = new Lang.Class({
 | 
			
		||||
        return lastLayout;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _rectEqual: function(one, two) {
 | 
			
		||||
        if (one == two)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        return (one.x == two.x &&
 | 
			
		||||
                one.y == two.y &&
 | 
			
		||||
                one.width == two.width &&
 | 
			
		||||
                one.height == two.height);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _computeAllWindowSlots: function(windows) {
 | 
			
		||||
        let totalWindows = windows.length;
 | 
			
		||||
    _getSpacingAndPadding: function() {
 | 
			
		||||
        let node = this.actor.get_theme_node();
 | 
			
		||||
 | 
			
		||||
        // Window grid spacing
 | 
			
		||||
@@ -1539,21 +1570,14 @@ const Workspace = new Lang.Class({
 | 
			
		||||
            right: node.get_padding(St.Side.RIGHT),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if (!totalWindows)
 | 
			
		||||
            return [];
 | 
			
		||||
 | 
			
		||||
        let closeButtonHeight, captionHeight;
 | 
			
		||||
        let leftBorder, rightBorder;
 | 
			
		||||
        if (this._windowOverlays.length) {
 | 
			
		||||
            // All of the overlays have the same chrome sizes,
 | 
			
		||||
            // so just pick the first one.
 | 
			
		||||
            let overlay = this._windowOverlays[0];
 | 
			
		||||
            [closeButtonHeight, captionHeight] = overlay.chromeHeights();
 | 
			
		||||
            [leftBorder, rightBorder] = overlay.chromeWidths();
 | 
			
		||||
        } else {
 | 
			
		||||
            [closeButtonHeight, captionHeight] = [0, 0];
 | 
			
		||||
            [leftBorder, rightBorder] = [0, 0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // All of the overlays have the same chrome sizes,
 | 
			
		||||
        // so just pick the first one.
 | 
			
		||||
        let overlay = this._windowOverlays[0];
 | 
			
		||||
        [closeButtonHeight, captionHeight] = overlay.chromeHeights();
 | 
			
		||||
        [leftBorder, rightBorder] = overlay.chromeWidths();
 | 
			
		||||
 | 
			
		||||
        rowSpacing += captionHeight;
 | 
			
		||||
        columnSpacing += (rightBorder + leftBorder) / 2;
 | 
			
		||||
@@ -1562,25 +1586,13 @@ const Workspace = new Lang.Class({
 | 
			
		||||
        padding.left += leftBorder;
 | 
			
		||||
        padding.right += rightBorder;
 | 
			
		||||
 | 
			
		||||
        let area = {
 | 
			
		||||
            x: this._x + padding.left,
 | 
			
		||||
            y: this._y + padding.top,
 | 
			
		||||
            width: this._width - padding.left - padding.right,
 | 
			
		||||
            height: this._height - padding.top - padding.bottom,
 | 
			
		||||
        };
 | 
			
		||||
        return [rowSpacing, columnSpacing, padding];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
        if (!this._currentLayout)
 | 
			
		||||
            this._currentLayout = this._computeLayout(windows, area, rowSpacing, columnSpacing);
 | 
			
		||||
 | 
			
		||||
        let layout = this._currentLayout;
 | 
			
		||||
        let strategy = layout.strategy;
 | 
			
		||||
 | 
			
		||||
        if (!this._rectEqual(area, layout.area)) {
 | 
			
		||||
            layout.area = area;
 | 
			
		||||
            strategy.computeScaleAndSpace(layout);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return strategy.computeWindowSlots(layout, area);
 | 
			
		||||
    _computeLayout: function(windows) {
 | 
			
		||||
        let [rowSpacing, columnSpacing, padding] = this._getSpacingAndPadding();
 | 
			
		||||
        let area = padArea(this._fullGeometry, padding);
 | 
			
		||||
        return this._getBestLayout(windows, area, rowSpacing, columnSpacing);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onCloneSelected : function (clone, time) {
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,18 @@ const MAX_WORKSPACES = 16;
 | 
			
		||||
 | 
			
		||||
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
 | 
			
		||||
 | 
			
		||||
function rectEqual(one, two) {
 | 
			
		||||
    if (one == two)
 | 
			
		||||
        return true;
 | 
			
		||||
 | 
			
		||||
    if (!one || !two)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    return (one.x == two.x &&
 | 
			
		||||
            one.y == two.y &&
 | 
			
		||||
            one.width == two.width &&
 | 
			
		||||
            one.height == two.height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const WorkspacesView = new Lang.Class({
 | 
			
		||||
    Name: 'WorkspacesView',
 | 
			
		||||
@@ -43,10 +55,9 @@ const WorkspacesView = new Lang.Class({
 | 
			
		||||
                this._updateWorkspaceActors(false);
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        this._width = 0;
 | 
			
		||||
        this._height = 0;
 | 
			
		||||
        this._x = 0;
 | 
			
		||||
        this._y = 0;
 | 
			
		||||
        this._fullGeometry = null;
 | 
			
		||||
        this._actualGeometry = null;
 | 
			
		||||
 | 
			
		||||
        this._spacing = 0;
 | 
			
		||||
        this._animating = false; // tweening
 | 
			
		||||
        this._scrolling = false; // swipe-scrolling
 | 
			
		||||
@@ -85,8 +96,8 @@ const WorkspacesView = new Lang.Class({
 | 
			
		||||
        this._overviewShownId =
 | 
			
		||||
            Main.overview.connect('shown',
 | 
			
		||||
                                 Lang.bind(this, function() {
 | 
			
		||||
                this.actor.set_clip(this._x, this._y,
 | 
			
		||||
                                    this._width, this._height);
 | 
			
		||||
                this.actor.set_clip(this._fullGeometry.x, this._fullGeometry.y,
 | 
			
		||||
                                    this._fullGeometry.width, this._fullGeometry.height);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        this.scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
 | 
			
		||||
@@ -124,11 +135,9 @@ const WorkspacesView = new Lang.Class({
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            let ws = new Workspace.Workspace(null, i);
 | 
			
		||||
            ws.setGeometry(monitors[i].x,
 | 
			
		||||
                           monitors[i].y,
 | 
			
		||||
                           monitors[i].width,
 | 
			
		||||
                           monitors[i].height);
 | 
			
		||||
            global.overlay_group.add_actor(ws.actor);
 | 
			
		||||
            ws.setFullGeometry(monitors[i]);
 | 
			
		||||
            ws.setActualGeometry(monitors[i]);
 | 
			
		||||
            Main.layoutManager.overviewGroup.add_actor(ws.actor);
 | 
			
		||||
            this._extraWorkspaces.push(ws);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
@@ -139,18 +148,24 @@ const WorkspacesView = new Lang.Class({
 | 
			
		||||
        this._extraWorkspaces = [];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setGeometry: function(x, y, width, height) {
 | 
			
		||||
      if (this._x == x && this._y == y &&
 | 
			
		||||
          this._width == width && this._height == height)
 | 
			
		||||
          return;
 | 
			
		||||
    setFullGeometry: function(geom) {
 | 
			
		||||
        if (rectEqual(this._fullGeometry, geom))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._width = width;
 | 
			
		||||
        this._height = height;
 | 
			
		||||
        this._x = x;
 | 
			
		||||
        this._y = y;
 | 
			
		||||
        this._fullGeometry = geom;
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._workspaces.length; i++)
 | 
			
		||||
            this._workspaces[i].setGeometry(x, y, width, height);
 | 
			
		||||
            this._workspaces[i].setFullGeometry(geom);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setActualGeometry: function(geom) {
 | 
			
		||||
        if (rectEqual(this._actualGeometry, geom))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._actualGeometry = geom;
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._workspaces.length; i++)
 | 
			
		||||
            this._workspaces[i].setActualGeometry(geom);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _lookupWorkspaceForMetaWindow: function (metaWindow) {
 | 
			
		||||
@@ -210,7 +225,7 @@ const WorkspacesView = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
            Tweener.removeTweens(workspace.actor);
 | 
			
		||||
 | 
			
		||||
            let y = (w - active) * (this._height + this._spacing);
 | 
			
		||||
            let y = (w - active) * (this._fullGeometry.height + this._spacing);
 | 
			
		||||
 | 
			
		||||
            if (showAnimation) {
 | 
			
		||||
                let params = { y: y,
 | 
			
		||||
@@ -281,8 +296,9 @@ const WorkspacesView = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        if (newNumWorkspaces > oldNumWorkspaces) {
 | 
			
		||||
            for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
 | 
			
		||||
                this._workspaces[w].setGeometry(this._x, this._y,
 | 
			
		||||
                                                this._width, this._height);
 | 
			
		||||
                this._workspaces[w].setFullGeometry(this._fullGeometry);
 | 
			
		||||
                if (this._actualGeometry)
 | 
			
		||||
                    this._workspaces[w].setActualGeometry(this._actualGeometry);
 | 
			
		||||
                this.actor.add_actor(this._workspaces[w].actor);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -430,7 +446,7 @@ const WorkspacesDisplay = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.actor = new St.Widget({ clip_to_allocation: true });
 | 
			
		||||
        this.actor.connect('notify::allocation', Lang.bind(this, this._updateWorkspacesGeometry));
 | 
			
		||||
        this.actor.connect('notify::allocation', Lang.bind(this, this._updateWorkspacesActualGeometry));
 | 
			
		||||
        this.actor.connect('parent-set', Lang.bind(this, this._parentSet));
 | 
			
		||||
 | 
			
		||||
        let clickAction = new Clutter.ClickAction()
 | 
			
		||||
@@ -484,6 +500,8 @@ const WorkspacesDisplay = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this._notifyOpacityId = 0;
 | 
			
		||||
        this._scrollEventId = 0;
 | 
			
		||||
 | 
			
		||||
        this._fullGeometry = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onPan: function(action) {
 | 
			
		||||
@@ -572,10 +590,11 @@ const WorkspacesDisplay = new Lang.Class({
 | 
			
		||||
            this._workspacesViews.push(view);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._updateWorkspacesGeometry();
 | 
			
		||||
        this._updateWorkspacesFullGeometry();
 | 
			
		||||
        this._updateWorkspacesActualGeometry();
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._workspacesViews.length; i++)
 | 
			
		||||
            global.overlay_group.add_actor(this._workspacesViews[i].actor);
 | 
			
		||||
            Main.layoutManager.overviewGroup.add_actor(this._workspacesViews[i].actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _scrollValueChanged: function() {
 | 
			
		||||
@@ -619,7 +638,7 @@ const WorkspacesDisplay = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
                // This is kinda hackish - we want the primary view to
 | 
			
		||||
                // appear as parent of this.actor, though in reality it
 | 
			
		||||
                // is added directly to overlay_group
 | 
			
		||||
                // is added directly to Main.layoutManager.overviewGroup
 | 
			
		||||
                this._notifyOpacityId = newParent.connect('notify::opacity',
 | 
			
		||||
                    Lang.bind(this, function() {
 | 
			
		||||
                        let opacity = this.actor.get_parent().opacity;
 | 
			
		||||
@@ -632,31 +651,48 @@ const WorkspacesDisplay = new Lang.Class({
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateWorkspacesGeometry: function() {
 | 
			
		||||
    // This geometry should always be the fullest geometry
 | 
			
		||||
    // the workspaces switcher can ever be allocated, as if
 | 
			
		||||
    // the sliding controls were never slid in at all.
 | 
			
		||||
    setWorkspacesFullGeometry: function(geom) {
 | 
			
		||||
        this._fullGeometry = geom;
 | 
			
		||||
        this._updateWorkspacesFullGeometry();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateWorkspacesFullGeometry: function() {
 | 
			
		||||
        if (!this._workspacesViews.length)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let fullWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
 | 
			
		||||
        let fullHeight = this.actor.allocation.y2 - this.actor.allocation.y1;
 | 
			
		||||
 | 
			
		||||
        let width = fullWidth;
 | 
			
		||||
        let height = fullHeight;
 | 
			
		||||
 | 
			
		||||
        let [x, y] = this.actor.get_transformed_position();
 | 
			
		||||
 | 
			
		||||
        let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
 | 
			
		||||
 | 
			
		||||
        let monitors = Main.layoutManager.monitors;
 | 
			
		||||
        let m = 0;
 | 
			
		||||
        for (let i = 0; i < monitors.length; i++) {
 | 
			
		||||
            if (i == this._primaryIndex) {
 | 
			
		||||
                this._workspacesViews[m].setGeometry(x, y, width, height);
 | 
			
		||||
                this._workspacesViews[m].setFullGeometry(this._fullGeometry);
 | 
			
		||||
                m++;
 | 
			
		||||
            } else if (!this._workspacesOnlyOnPrimary) {
 | 
			
		||||
                this._workspacesViews[m].setGeometry(monitors[i].x,
 | 
			
		||||
                                                     monitors[i].y,
 | 
			
		||||
                                                     monitors[i].width,
 | 
			
		||||
                                                     monitors[i].height);
 | 
			
		||||
                this._workspacesViews[m].setFullGeometry(monitors[i]);
 | 
			
		||||
                m++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateWorkspacesActualGeometry: function() {
 | 
			
		||||
        if (!this._workspacesViews.length)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let [x, y] = this.actor.get_transformed_position();
 | 
			
		||||
        let width = this.actor.allocation.x2 - this.actor.allocation.x1;
 | 
			
		||||
        let height = this.actor.allocation.y2 - this.actor.allocation.y1;
 | 
			
		||||
        let geometry = { x: x, y: y, width: width, height: height };
 | 
			
		||||
 | 
			
		||||
        let monitors = Main.layoutManager.monitors;
 | 
			
		||||
        let m = 0;
 | 
			
		||||
        for (let i = 0; i < monitors.length; i++) {
 | 
			
		||||
            if (i == this._primaryIndex) {
 | 
			
		||||
                this._workspacesViews[m].setActualGeometry(geometry);
 | 
			
		||||
                m++;
 | 
			
		||||
            } else if (!this._workspacesOnlyOnPrimary) {
 | 
			
		||||
                this._workspacesViews[m].setActualGeometry(monitors[i]);
 | 
			
		||||
                m++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -724,15 +760,20 @@ const WorkspacesDisplay = new Lang.Class({
 | 
			
		||||
    _onScrollEvent: function(actor, event) {
 | 
			
		||||
        if (!this.actor.mapped)
 | 
			
		||||
            return false;
 | 
			
		||||
        let activeWs = global.screen.get_active_workspace();
 | 
			
		||||
        let ws;
 | 
			
		||||
        switch (event.get_scroll_direction()) {
 | 
			
		||||
        case Clutter.ScrollDirection.UP:
 | 
			
		||||
            Main.wm.actionMoveWorkspace(Meta.MotionDirection.UP);
 | 
			
		||||
            return true;
 | 
			
		||||
            ws = activeWs.get_neighbor(Meta.MotionDirection.UP);
 | 
			
		||||
            break;
 | 
			
		||||
        case Clutter.ScrollDirection.DOWN:
 | 
			
		||||
            Main.wm.actionMoveWorkspace(Meta.MotionDirection.DOWN);
 | 
			
		||||
            return true;
 | 
			
		||||
            ws = activeWs.get_neighbor(Meta.MotionDirection.DOWN);
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
        Main.wm.actionMoveWorkspace(ws);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
Signals.addSignalMethods(WorkspacesDisplay.prototype);
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ const XdndHandler = new Lang.Class({
 | 
			
		||||
        this._cursorWindowClone = null;
 | 
			
		||||
 | 
			
		||||
        // Used as a drag actor in case we don't have a cursor window clone
 | 
			
		||||
        this._dummy = new Clutter.Rectangle({ width: 1, height: 1, opacity: 0 });
 | 
			
		||||
        this._dummy = new Clutter.Actor({ width: 1, height: 1, opacity: 0 });
 | 
			
		||||
        Main.uiGroup.add_actor(this._dummy);
 | 
			
		||||
        Shell.util_set_hidden_from_pick(this._dummy, true);
 | 
			
		||||
        this._dummy.hide();
 | 
			
		||||
 
 | 
			
		||||
@@ -125,6 +125,12 @@
 | 
			
		||||
                                <listitem><para>List possible modes and exit</para></listitem>
 | 
			
		||||
                        </varlistentry>
 | 
			
		||||
 | 
			
		||||
                        <varlistentry>
 | 
			
		||||
                                <term><option>--clutter-display=<replaceable>DISPLAY</replaceable></option></term>
 | 
			
		||||
 | 
			
		||||
                                <listitem><para>Clutter the option display (otherwise ignored)</para></listitem>
 | 
			
		||||
                        </varlistentry>
 | 
			
		||||
 | 
			
		||||
                </variablelist>
 | 
			
		||||
 | 
			
		||||
        </refsect1>
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@ gu
 | 
			
		||||
he
 | 
			
		||||
hi
 | 
			
		||||
hu
 | 
			
		||||
ia
 | 
			
		||||
id
 | 
			
		||||
it
 | 
			
		||||
ja
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								po/ca.po
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								po/ca.po
									
									
									
									
									
								
							@@ -11,7 +11,7 @@ msgstr ""
 | 
			
		||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
 | 
			
		||||
"shell&keywords=I18N+L10N&component=general\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-11 21:29+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-03-11 00:03+0100\n"
 | 
			
		||||
"PO-Revision-Date: 2013-05-26 08:21+0200\n"
 | 
			
		||||
"Last-Translator: Gil Forcada <gilforcada@guifi.net>\n"
 | 
			
		||||
"Language-Team: Catalan <tradgnome@softcatala.org>\n"
 | 
			
		||||
"Language: ca\n"
 | 
			
		||||
@@ -1048,7 +1048,7 @@ msgstr "Obre els rellotges"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/dateMenu.js:105
 | 
			
		||||
msgid "Date & Time Settings"
 | 
			
		||||
msgstr "Configuració de la data i l'hora"
 | 
			
		||||
msgstr "Configuració de la data i de l'hora"
 | 
			
		||||
 | 
			
		||||
#. Translators: This is the date format to use when the calendar popup is
 | 
			
		||||
#. * shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										239
									
								
								po/el.po
									
									
									
									
									
								
							
							
						
						
									
										239
									
								
								po/el.po
									
									
									
									
									
								
							@@ -5,8 +5,8 @@ msgstr ""
 | 
			
		||||
"Project-Id-Version: gnome-shell.po.master\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
 | 
			
		||||
"shell&keywords=I18N+L10N&component=general\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-02 23:02+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-03-03 13:22+0300\n"
 | 
			
		||||
"POT-Creation-Date: 2013-04-19 02:48+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-04-25 08:11+0300\n"
 | 
			
		||||
"Last-Translator: Dimitris Spingos (Δημήτρης Σπίγγος) <dmtrs32@gmail.com>\n"
 | 
			
		||||
"Language-Team: team@gnome.gr\n"
 | 
			
		||||
"Language: el\n"
 | 
			
		||||
@@ -40,10 +40,14 @@ msgid "Focus the active notification"
 | 
			
		||||
msgstr "Εστίαση στην ενεργή ειδοποίηση"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:4
 | 
			
		||||
msgid "Show the overview"
 | 
			
		||||
msgstr "Εμφάνιση της επισκόπησης"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:5
 | 
			
		||||
msgid "Show all applications"
 | 
			
		||||
msgstr "Προβολή όλων των εφαρμογών"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:5
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:6
 | 
			
		||||
msgid "Open the application menu"
 | 
			
		||||
msgstr "Άνοιγμα του μενού εφαρμογών"
 | 
			
		||||
 | 
			
		||||
@@ -223,45 +227,55 @@ msgstr ""
 | 
			
		||||
"επισκόπησης ενεργειών."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
 | 
			
		||||
#| msgid "Keybinding to open the \"Show Applications\" view"
 | 
			
		||||
msgid "Keybinding to open the overview"
 | 
			
		||||
msgstr "Συνδυασμός πλήκτρων για το άνοιγμα της επισκόπησης"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
 | 
			
		||||
#| msgid "Keybinding to open the \"Show Applications\" view"
 | 
			
		||||
msgid "Keybinding to open the Activities Overview."
 | 
			
		||||
msgstr "Συνδυασμός πλήκτρων για το άνοιγμα της προβολής ενέργειες."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
 | 
			
		||||
msgid "Keybinding to toggle the visibility of the message tray"
 | 
			
		||||
msgstr "Συνδυασμός πλήκτρων για την ορατότητα της περιοχής ειδοποιήσεων"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
 | 
			
		||||
msgid "Keybinding to toggle the visibility of the message tray."
 | 
			
		||||
msgstr "Συνδυασμός πλήκτρων για την ορατότητα της περιοχής ειδοποιήσεων."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
 | 
			
		||||
msgid "Keybinding to focus the active notification"
 | 
			
		||||
msgstr "Ο συνδυασμός πλήκτρων για εστίαση της ενεργής ειδοποίησης"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
 | 
			
		||||
msgid "Keybinding to focus the active notification."
 | 
			
		||||
msgstr "Ο συνδυασμός πλήκτρων για εστίαση της ενεργής ειδοποίησης."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
 | 
			
		||||
msgid "Keybinding to toggle the screen recorder"
 | 
			
		||||
msgstr "Συνδυασμός πλήκτρων για την εναλλαγή της μαγνητοσκόπησης οθόνης"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:32
 | 
			
		||||
msgid "Keybinding to start/stop the builtin screen recorder."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Συνδυασμός πλήκτρων για το άνοιγμα/κλείσιμο της ενσωματωμένης "
 | 
			
		||||
"μαγνητοσκόπησης οθόνης."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:33
 | 
			
		||||
msgid "Which keyboard to use"
 | 
			
		||||
msgstr "Ποιο πληκτρολόγιο θα χρησιμοποιηθεί"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:32
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:34
 | 
			
		||||
msgid "The type of keyboard to use."
 | 
			
		||||
msgstr "Ο τύπος του πληκτρολογίου που θα χρησιμοποιηθεί."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:33
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:35
 | 
			
		||||
msgid "Framerate used for recording screencasts."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Ο ρυθμός καρέ που θα χρησιμοποιηθεί για την καταγραφή του βίντεο οθόνης."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:34
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:36
 | 
			
		||||
msgid ""
 | 
			
		||||
"The framerate of the resulting screencast recordered by GNOME Shell's "
 | 
			
		||||
"screencast recorder in frames-per-second."
 | 
			
		||||
@@ -269,13 +283,13 @@ msgstr ""
 | 
			
		||||
"Ο ρυθμός καρέ του στιγμιότυπου που παράγεται από τον εγγραφέα βίντεο οθόνης "
 | 
			
		||||
"του GNOME Shell σε καρέ ανά δευτερόλεπτο."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:35
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:37
 | 
			
		||||
msgid "The gstreamer pipeline used to encode the screencast"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Ο δίαυλος του gstreamer που χρησιμοποιήθηκε για την κωδικοποίηση του βίντεο "
 | 
			
		||||
"οθόνης"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:37
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:39
 | 
			
		||||
#, no-c-format
 | 
			
		||||
msgid ""
 | 
			
		||||
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
 | 
			
		||||
@@ -303,12 +317,12 @@ msgstr ""
 | 
			
		||||
"χρησιμοποιείται ως παράδειγμα για το πιθανό βέλτιστο αριθμό πυρήνων του "
 | 
			
		||||
"συστήματος."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:38
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:40
 | 
			
		||||
msgid "File extension used for storing the screencast"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Επέκταση αρχείου που θα χρησιμοποιηθεί για την αποθήκευση του βίντεο οθόνης"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:39
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:41
 | 
			
		||||
msgid ""
 | 
			
		||||
"The filename for recorded screencasts will be a unique filename based on the "
 | 
			
		||||
"current date, and use this extension. It should be changed when recording to "
 | 
			
		||||
@@ -318,11 +332,11 @@ msgstr ""
 | 
			
		||||
"βασισμένο στην τρέχουσα ημερομηνία και θα χρησιμοποιεί αυτή την επέκταση. Θα "
 | 
			
		||||
"πρέπει να αλλάζει όταν γίνεται εγγραφή σε διαφορετικό πρότυπο περιέκτη."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:40
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:42
 | 
			
		||||
msgid "The application icon mode."
 | 
			
		||||
msgstr "Η κατάσταση εικονιδίου εφαρμογής."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:41
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:43
 | 
			
		||||
msgid ""
 | 
			
		||||
"Configures how the windows are shown in the switcher. Valid possibilities "
 | 
			
		||||
"are 'thumbnail-only' (shows a thumbnail of the window), 'app-icon-"
 | 
			
		||||
@@ -333,22 +347,22 @@ msgstr ""
 | 
			
		||||
"παραθύρου), 'app-icon-only' (εμφανίζει μόνο το εικονίδιο της εφαρμογής) ή "
 | 
			
		||||
"'both' - και τα δύο."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:42
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:44
 | 
			
		||||
msgid "Attach modal dialog to the parent window"
 | 
			
		||||
msgstr "Προσάρτηση αναγκαστικού διαλόγου στο γονικό παράθυρο"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:43
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:45
 | 
			
		||||
msgid ""
 | 
			
		||||
"This key overrides the key in org.gnome.mutter when running GNOME Shell."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Αυτό το κλειδί υπερισχύει του κλειδιού στο org.gnome.mutter όταν εκτελείται "
 | 
			
		||||
"το κέλυφος GNOME."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:44
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:46
 | 
			
		||||
msgid "Arrangement of buttons on the titlebar"
 | 
			
		||||
msgstr "Διάταξη των κουμπιών στη γραμμή τίτλου"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:45
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:47
 | 
			
		||||
msgid ""
 | 
			
		||||
"This key overrides the key in org.gnome.desktop.wm.preferences when running "
 | 
			
		||||
"GNOME Shell."
 | 
			
		||||
@@ -356,17 +370,17 @@ msgstr ""
 | 
			
		||||
"Αυτό το κλειδί υπερισχύει του κλειδιού στο org.gnome.desktop.wm.preferences "
 | 
			
		||||
"όταν εκτελείται το κέλυφος GNOME."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:46
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:48
 | 
			
		||||
msgid "Enable edge tiling when dropping windows on screen edges"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Ενεργοποίηση της παράθεσης άκρων όταν αποθέτετε παράθυρα στις άκρες της "
 | 
			
		||||
"οθόνης"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:47
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:49
 | 
			
		||||
msgid "Workspaces are managed dynamically"
 | 
			
		||||
msgstr "Οι χώροι εργασίας διαχειρίζονται δυναμικά"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:48
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:50
 | 
			
		||||
msgid "Workspaces only on primary monitor"
 | 
			
		||||
msgstr "Χώροι εργασίας μόνο στην κύρια οθόνη"
 | 
			
		||||
 | 
			
		||||
@@ -388,43 +402,42 @@ msgstr ""
 | 
			
		||||
"πολλαπλών επιλογών."
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:405
 | 
			
		||||
#| msgid "Session..."
 | 
			
		||||
msgid "Session…"
 | 
			
		||||
msgstr "Συνεδρία…"
 | 
			
		||||
 | 
			
		||||
#. translators: this message is shown below the user list on the
 | 
			
		||||
#. login screen. It can be activated to reveal an entry for
 | 
			
		||||
#. manually entering the username.
 | 
			
		||||
#: ../js/gdm/loginDialog.js:629
 | 
			
		||||
#: ../js/gdm/loginDialog.js:630
 | 
			
		||||
msgid "Not listed?"
 | 
			
		||||
msgstr "Δεν είστε στη λίστα;"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:783 ../js/ui/components/networkAgent.js:137
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:375
 | 
			
		||||
#: ../js/gdm/loginDialog.js:787 ../js/ui/components/networkAgent.js:137
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:376
 | 
			
		||||
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:399
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:126
 | 
			
		||||
#: ../js/ui/userMenu.js:932
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:100
 | 
			
		||||
#: ../js/ui/userMenu.js:938
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "Ακύρωση"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:799
 | 
			
		||||
#: ../js/gdm/loginDialog.js:803
 | 
			
		||||
msgctxt "button"
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr "Σύνδεση"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:799
 | 
			
		||||
#: ../js/gdm/loginDialog.js:803
 | 
			
		||||
msgid "Next"
 | 
			
		||||
msgstr "Επόμενο"
 | 
			
		||||
 | 
			
		||||
#. TTLS and PEAP are actually much more complicated, but this complication
 | 
			
		||||
#. is not visible here since we only care about phase2 authentication
 | 
			
		||||
#. (and don't even care of which one)
 | 
			
		||||
#: ../js/gdm/loginDialog.js:904 ../js/ui/components/networkAgent.js:260
 | 
			
		||||
#: ../js/gdm/loginDialog.js:918 ../js/ui/components/networkAgent.js:260
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:278
 | 
			
		||||
msgid "Username: "
 | 
			
		||||
msgstr "Όνομα χρήστη: "
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:1157
 | 
			
		||||
#: ../js/gdm/loginDialog.js:1174
 | 
			
		||||
msgid "Login Window"
 | 
			
		||||
msgstr "Παράθυρο σύνδεσης"
 | 
			
		||||
 | 
			
		||||
@@ -433,8 +446,8 @@ msgstr "Παράθυρο σύνδεσης"
 | 
			
		||||
msgid "Power"
 | 
			
		||||
msgstr "Ενέργεια"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:694 ../js/ui/userMenu.js:698
 | 
			
		||||
#: ../js/ui/userMenu.js:814
 | 
			
		||||
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:696 ../js/ui/userMenu.js:700
 | 
			
		||||
#: ../js/ui/userMenu.js:816
 | 
			
		||||
msgid "Suspend"
 | 
			
		||||
msgstr "Αναστολή"
 | 
			
		||||
 | 
			
		||||
@@ -442,58 +455,58 @@ msgstr "Αναστολή"
 | 
			
		||||
msgid "Restart"
 | 
			
		||||
msgstr "Επανεκκίνηση"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:696
 | 
			
		||||
#: ../js/ui/userMenu.js:698 ../js/ui/userMenu.js:813 ../js/ui/userMenu.js:936
 | 
			
		||||
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:698
 | 
			
		||||
#: ../js/ui/userMenu.js:700 ../js/ui/userMenu.js:815 ../js/ui/userMenu.js:942
 | 
			
		||||
msgid "Power Off"
 | 
			
		||||
msgstr "Απενεργοποίηση"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/util.js:182
 | 
			
		||||
#: ../js/gdm/util.js:249
 | 
			
		||||
msgid "Authentication error"
 | 
			
		||||
msgstr "Σφάλμα πιστοποίησης"
 | 
			
		||||
 | 
			
		||||
#. Translators: this message is shown below the password entry field
 | 
			
		||||
#. to indicate the user can swipe their finger instead
 | 
			
		||||
#: ../js/gdm/util.js:299
 | 
			
		||||
#: ../js/gdm/util.js:366
 | 
			
		||||
msgid "(or swipe finger)"
 | 
			
		||||
msgstr "(ή περάστε το δάκτυλο σας)"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/util.js:324
 | 
			
		||||
#: ../js/gdm/util.js:391
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "(e.g., user or %s)"
 | 
			
		||||
msgstr "(π.χ χρήστης ή %s)"
 | 
			
		||||
 | 
			
		||||
#: ../js/misc/util.js:94
 | 
			
		||||
#: ../js/misc/util.js:97
 | 
			
		||||
msgid "Command not found"
 | 
			
		||||
msgstr "Δε βρέθηκε η εντολή"
 | 
			
		||||
 | 
			
		||||
#. Replace "Error invoking GLib.shell_parse_argv: " with
 | 
			
		||||
#. something nicer
 | 
			
		||||
#: ../js/misc/util.js:127
 | 
			
		||||
#: ../js/misc/util.js:130
 | 
			
		||||
msgid "Could not parse command:"
 | 
			
		||||
msgstr "Δεν ήταν δυνατό να επεξεργαστεί η εντολή:"
 | 
			
		||||
 | 
			
		||||
#: ../js/misc/util.js:135
 | 
			
		||||
#: ../js/misc/util.js:138
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Execution of '%s' failed:"
 | 
			
		||||
msgstr "Η εκτέλεση του '%s' απέτυχε:"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:348
 | 
			
		||||
#: ../js/ui/appDisplay.js:349
 | 
			
		||||
msgid "Frequent"
 | 
			
		||||
msgstr "Συχνό"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:355
 | 
			
		||||
#: ../js/ui/appDisplay.js:356
 | 
			
		||||
msgid "All"
 | 
			
		||||
msgstr "Όλα"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:913
 | 
			
		||||
#: ../js/ui/appDisplay.js:914
 | 
			
		||||
msgid "New Window"
 | 
			
		||||
msgstr "Νέο παράθυρο"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:916 ../js/ui/dash.js:284
 | 
			
		||||
#: ../js/ui/appDisplay.js:917 ../js/ui/dash.js:284
 | 
			
		||||
msgid "Remove from Favorites"
 | 
			
		||||
msgstr "Αφαίρεση από τα αγαπημένα"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:917
 | 
			
		||||
#: ../js/ui/appDisplay.js:918
 | 
			
		||||
msgid "Add to Favorites"
 | 
			
		||||
msgstr "Προσθήκη στα αγαπημένα"
 | 
			
		||||
 | 
			
		||||
@@ -507,7 +520,7 @@ msgstr "Tο %s προστέθηκε στα αγαπημένα σας."
 | 
			
		||||
msgid "%s has been removed from your favorites."
 | 
			
		||||
msgstr "Tο %s αφαιρέθηκε από τα αγαπημένα σας."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:787
 | 
			
		||||
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:789
 | 
			
		||||
msgid "Settings"
 | 
			
		||||
msgstr "Ρυθμίσεις"
 | 
			
		||||
 | 
			
		||||
@@ -530,7 +543,7 @@ msgctxt "event list time"
 | 
			
		||||
msgid "%H\\u2236%M"
 | 
			
		||||
msgstr "%Ω\\u2236%Λ"
 | 
			
		||||
 | 
			
		||||
#. Transators: Shown in calendar event list, if 12h format,
 | 
			
		||||
#. Translators: Shown in calendar event list, if 12h format,
 | 
			
		||||
#. \u2236 is a ratio character, similar to : and \u2009 is
 | 
			
		||||
#. a thin space
 | 
			
		||||
#: ../js/ui/calendar.js:77
 | 
			
		||||
@@ -632,35 +645,35 @@ msgid "S"
 | 
			
		||||
msgstr "Σ"
 | 
			
		||||
 | 
			
		||||
#. Translators: Text to show if there are no events
 | 
			
		||||
#: ../js/ui/calendar.js:692
 | 
			
		||||
#: ../js/ui/calendar.js:720
 | 
			
		||||
msgid "Nothing Scheduled"
 | 
			
		||||
msgstr "Τίποτα προγραμματισμένο"
 | 
			
		||||
 | 
			
		||||
#. Translators: Shown on calendar heading when selected day occurs on current year
 | 
			
		||||
#: ../js/ui/calendar.js:708
 | 
			
		||||
#: ../js/ui/calendar.js:736
 | 
			
		||||
msgctxt "calendar heading"
 | 
			
		||||
msgid "%A, %B %d"
 | 
			
		||||
msgstr "%A, %B %d"
 | 
			
		||||
 | 
			
		||||
#. Translators: Shown on calendar heading when selected day occurs on different year
 | 
			
		||||
#: ../js/ui/calendar.js:711
 | 
			
		||||
#: ../js/ui/calendar.js:739
 | 
			
		||||
msgctxt "calendar heading"
 | 
			
		||||
msgid "%A, %B %d, %Y"
 | 
			
		||||
msgstr "%A, %B %d, %Y"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:721
 | 
			
		||||
#: ../js/ui/calendar.js:749
 | 
			
		||||
msgid "Today"
 | 
			
		||||
msgstr "Σήμερα"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:725
 | 
			
		||||
#: ../js/ui/calendar.js:753
 | 
			
		||||
msgid "Tomorrow"
 | 
			
		||||
msgstr "Αύριο"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:736
 | 
			
		||||
#: ../js/ui/calendar.js:764
 | 
			
		||||
msgid "This week"
 | 
			
		||||
msgstr "Αυτή η εβδομάδα"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:744
 | 
			
		||||
#: ../js/ui/calendar.js:772
 | 
			
		||||
msgid "Next week"
 | 
			
		||||
msgstr "Επόμενη εβδομάδα"
 | 
			
		||||
 | 
			
		||||
@@ -676,12 +689,12 @@ msgstr "Αποσυνδέθηκε εξωτερικός δίσκος"
 | 
			
		||||
msgid "Removable Devices"
 | 
			
		||||
msgstr "Αφαιρούμενες συσκευές"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/autorunManager.js:593
 | 
			
		||||
#: ../js/ui/components/autorunManager.js:594
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Open with %s"
 | 
			
		||||
msgstr "Άνοιγμα με %s"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/autorunManager.js:619
 | 
			
		||||
#: ../js/ui/components/autorunManager.js:620
 | 
			
		||||
msgid "Eject"
 | 
			
		||||
msgstr "Εξαγωγή"
 | 
			
		||||
 | 
			
		||||
@@ -790,7 +803,7 @@ msgid "Sorry, that didn't work. Please try again."
 | 
			
		||||
msgstr "Συγνώμη, αυτό δεν λειτούργησε. Παρακαλώ προσπαθήστε ξανά."
 | 
			
		||||
 | 
			
		||||
#. Translators: this is a filename used for screencast recording
 | 
			
		||||
#: ../js/ui/components/recorder.js:48
 | 
			
		||||
#: ../js/ui/components/recorder.js:47
 | 
			
		||||
#, no-c-format
 | 
			
		||||
msgid "Screencast from %d %t"
 | 
			
		||||
msgstr "Βίντεο οθόνης από %d %t"
 | 
			
		||||
@@ -1037,7 +1050,7 @@ msgstr "Προβολή λογαριασμού"
 | 
			
		||||
msgid "Unknown reason"
 | 
			
		||||
msgstr "Άγνωστος λόγος"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/ctrlAltTab.js:29 ../js/ui/viewSelector.js:97
 | 
			
		||||
#: ../js/ui/ctrlAltTab.js:29 ../js/ui/viewSelector.js:96
 | 
			
		||||
msgid "Windows"
 | 
			
		||||
msgstr "Παράθυρα"
 | 
			
		||||
 | 
			
		||||
@@ -1066,7 +1079,7 @@ msgstr "Ρυθμίσεις ημερομηνίας & ώρας"
 | 
			
		||||
#. Translators: This is the date format to use when the calendar popup is
 | 
			
		||||
#. * shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
 | 
			
		||||
#.
 | 
			
		||||
#: ../js/ui/dateMenu.js:205
 | 
			
		||||
#: ../js/ui/dateMenu.js:215
 | 
			
		||||
msgid "%A %B %e, %Y"
 | 
			
		||||
msgstr "%A %B %e, %Y"
 | 
			
		||||
 | 
			
		||||
@@ -1235,7 +1248,6 @@ msgid "Remove"
 | 
			
		||||
msgstr "Αφαίρεση"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:1501
 | 
			
		||||
#| msgid "No Messages"
 | 
			
		||||
msgid "Clear Messages"
 | 
			
		||||
msgstr "Καθαρισμός μηνυμάτων"
 | 
			
		||||
 | 
			
		||||
@@ -1243,15 +1255,15 @@ msgstr "Καθαρισμός μηνυμάτων"
 | 
			
		||||
msgid "Notification Settings"
 | 
			
		||||
msgstr "Ρυθμίσεις ειδοποιήσεων"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:1707
 | 
			
		||||
#: ../js/ui/messageTray.js:1709
 | 
			
		||||
msgid "No Messages"
 | 
			
		||||
msgstr "Κανένα μήνυμα"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:1787
 | 
			
		||||
#: ../js/ui/messageTray.js:1785
 | 
			
		||||
msgid "Message Tray"
 | 
			
		||||
msgstr "Περιοχή ειδοποιήσεων"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:2864
 | 
			
		||||
#: ../js/ui/messageTray.js:2813
 | 
			
		||||
msgid "System Information"
 | 
			
		||||
msgstr "Πληροφορίες συστήματος"
 | 
			
		||||
 | 
			
		||||
@@ -1260,14 +1272,14 @@ msgctxt "program"
 | 
			
		||||
msgid "Unknown"
 | 
			
		||||
msgstr "Άγνωστο"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/overviewControls.js:460 ../js/ui/screenShield.js:153
 | 
			
		||||
#: ../js/ui/overviewControls.js:463 ../js/ui/screenShield.js:149
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%d new message"
 | 
			
		||||
msgid_plural "%d new messages"
 | 
			
		||||
msgstr[0] "%d νέο μήνυμα"
 | 
			
		||||
msgstr[1] "%d νέα μηνύματα"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/overview.js:82
 | 
			
		||||
#: ../js/ui/overview.js:84
 | 
			
		||||
msgid "Undo"
 | 
			
		||||
msgstr "Αναίρεση"
 | 
			
		||||
 | 
			
		||||
@@ -1279,22 +1291,21 @@ msgstr "Επισκόπηση"
 | 
			
		||||
#. in the search entry when no search is
 | 
			
		||||
#. active; it should not exceed ~30
 | 
			
		||||
#. characters.
 | 
			
		||||
#: ../js/ui/overview.js:284
 | 
			
		||||
#| msgid "Type to search..."
 | 
			
		||||
#: ../js/ui/overview.js:271
 | 
			
		||||
msgid "Type to search…"
 | 
			
		||||
msgstr "Πληκτρολογήστε για αναζήτηση…"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/panel.js:613
 | 
			
		||||
#: ../js/ui/panel.js:633
 | 
			
		||||
msgid "Quit"
 | 
			
		||||
msgstr "Έξοδος"
 | 
			
		||||
 | 
			
		||||
#. Translators: If there is no suitable word for "Activities"
 | 
			
		||||
#. in your language, you can use the word for "Overview".
 | 
			
		||||
#: ../js/ui/panel.js:642
 | 
			
		||||
#: ../js/ui/panel.js:657
 | 
			
		||||
msgid "Activities"
 | 
			
		||||
msgstr "Δραστηριότητες"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/panel.js:983
 | 
			
		||||
#: ../js/ui/panel.js:954
 | 
			
		||||
msgid "Top Bar"
 | 
			
		||||
msgstr "Πάνω μπάρα"
 | 
			
		||||
 | 
			
		||||
@@ -1307,32 +1318,32 @@ msgstr "Πάνω μπάρα"
 | 
			
		||||
msgid "toggle-switch-us"
 | 
			
		||||
msgstr "toggle-switch-intl"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/runDialog.js:205
 | 
			
		||||
#: ../js/ui/runDialog.js:74
 | 
			
		||||
msgid "Enter a Command"
 | 
			
		||||
msgstr "Εισαγωγή εντολής"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/runDialog.js:241
 | 
			
		||||
#: ../js/ui/runDialog.js:110
 | 
			
		||||
msgid "Close"
 | 
			
		||||
msgstr "Κλείσιμο"
 | 
			
		||||
 | 
			
		||||
#. Translators: This is a time format for a date in
 | 
			
		||||
#. long format
 | 
			
		||||
#: ../js/ui/screenShield.js:90
 | 
			
		||||
#: ../js/ui/screenShield.js:86
 | 
			
		||||
msgid "%A, %B %d"
 | 
			
		||||
msgstr "%A, %B %d"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:155
 | 
			
		||||
#: ../js/ui/screenShield.js:151
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%d new notification"
 | 
			
		||||
msgid_plural "%d new notifications"
 | 
			
		||||
msgstr[0] "%d νέα ειδοποίηση"
 | 
			
		||||
msgstr[1] "%d νέες ειδοποιήσεις"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:442 ../js/ui/userMenu.js:805
 | 
			
		||||
#: ../js/ui/screenShield.js:438 ../js/ui/userMenu.js:807
 | 
			
		||||
msgid "Lock"
 | 
			
		||||
msgstr "Κλείδωμα"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:639
 | 
			
		||||
#: ../js/ui/screenShield.js:641
 | 
			
		||||
msgid "GNOME needs to lock the screen"
 | 
			
		||||
msgstr "Το GNOME χρειάζεται να κλειδώσει την οθόνη"
 | 
			
		||||
 | 
			
		||||
@@ -1343,21 +1354,19 @@ msgstr "Το GNOME χρειάζεται να κλειδώσει την οθόν
 | 
			
		||||
#.
 | 
			
		||||
#. XXX: another option is to kick the user into the gdm login
 | 
			
		||||
#. screen, where we're not affected by grabs
 | 
			
		||||
#: ../js/ui/screenShield.js:758 ../js/ui/screenShield.js:1169
 | 
			
		||||
#| msgid "Unable to connect to %s"
 | 
			
		||||
#: ../js/ui/screenShield.js:762 ../js/ui/screenShield.js:1198
 | 
			
		||||
msgid "Unable to lock"
 | 
			
		||||
msgstr "Αδυναμία κλειδώματος"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:759 ../js/ui/screenShield.js:1170
 | 
			
		||||
#: ../js/ui/screenShield.js:763 ../js/ui/screenShield.js:1199
 | 
			
		||||
msgid "Lock was blocked by an application"
 | 
			
		||||
msgstr "Το κλείδωμα εμποδίστηκε από μια εφαρμογή"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/searchDisplay.js:431
 | 
			
		||||
#| msgid "Searching..."
 | 
			
		||||
#: ../js/ui/searchDisplay.js:453
 | 
			
		||||
msgid "Searching…"
 | 
			
		||||
msgstr "Αναζήτηση…"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/searchDisplay.js:475
 | 
			
		||||
#: ../js/ui/searchDisplay.js:497
 | 
			
		||||
msgid "No results."
 | 
			
		||||
msgstr "Δε βρέθηκαν αποτελέσματα."
 | 
			
		||||
 | 
			
		||||
@@ -1369,11 +1378,11 @@ msgstr "Αντιγραφή"
 | 
			
		||||
msgid "Paste"
 | 
			
		||||
msgstr "Επικόλληση"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellEntry.js:105
 | 
			
		||||
#: ../js/ui/shellEntry.js:101
 | 
			
		||||
msgid "Show Text"
 | 
			
		||||
msgstr "Εμφάνιση κειμένου"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellEntry.js:107
 | 
			
		||||
#: ../js/ui/shellEntry.js:103
 | 
			
		||||
msgid "Hide Text"
 | 
			
		||||
msgstr "Απόκρυψη κειμένου"
 | 
			
		||||
 | 
			
		||||
@@ -1385,7 +1394,7 @@ msgstr "Κωδικός"
 | 
			
		||||
msgid "Remember Password"
 | 
			
		||||
msgstr "Απομνημόνευση κωδικού"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:140
 | 
			
		||||
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:114
 | 
			
		||||
msgid "Unlock"
 | 
			
		||||
msgstr "Ξεκλείδωμα"
 | 
			
		||||
 | 
			
		||||
@@ -1449,12 +1458,10 @@ msgid "Visibility"
 | 
			
		||||
msgstr "Ορατότητα"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:59
 | 
			
		||||
#| msgid "Send Files to Device..."
 | 
			
		||||
msgid "Send Files to Device…"
 | 
			
		||||
msgstr "Αποστολή αρχείων σε συσκευή…"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:60
 | 
			
		||||
#| msgid "Set Up a New Device..."
 | 
			
		||||
msgid "Set Up a New Device…"
 | 
			
		||||
msgstr "Ρύθμιση νέας συσκευής…"
 | 
			
		||||
 | 
			
		||||
@@ -1481,7 +1488,6 @@ msgid "connecting..."
 | 
			
		||||
msgstr "σύνδεση..."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:239
 | 
			
		||||
#| msgid "Send Files..."
 | 
			
		||||
msgid "Send Files…"
 | 
			
		||||
msgstr "Αποστολή αρχείων…"
 | 
			
		||||
 | 
			
		||||
@@ -1694,7 +1700,6 @@ msgstr "Ρυθμίσεις τροφοδοσίας"
 | 
			
		||||
#. 0 is reported when UPower does not have enough data
 | 
			
		||||
#. to estimate battery life
 | 
			
		||||
#: ../js/ui/status/power.js:99
 | 
			
		||||
#| msgid "Estimating..."
 | 
			
		||||
msgid "Estimating…"
 | 
			
		||||
msgstr "Υπολογισμός…"
 | 
			
		||||
 | 
			
		||||
@@ -1794,59 +1799,59 @@ msgstr "Ένταση ήχου"
 | 
			
		||||
msgid "Microphone"
 | 
			
		||||
msgstr "Μικρόφωνο"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/unlockDialog.js:151
 | 
			
		||||
#: ../js/ui/unlockDialog.js:125
 | 
			
		||||
msgid "Log in as another user"
 | 
			
		||||
msgstr "Είσοδος ως άλλος χρήστης"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/unlockDialog.js:177
 | 
			
		||||
#: ../js/ui/unlockDialog.js:146
 | 
			
		||||
msgid "Unlock Window"
 | 
			
		||||
msgstr "Ξεκλείδωμα παραθύρου"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:192
 | 
			
		||||
#: ../js/ui/userMenu.js:193
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr "Διαθέσιμος-η"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:195
 | 
			
		||||
#: ../js/ui/userMenu.js:196
 | 
			
		||||
msgid "Busy"
 | 
			
		||||
msgstr "Απασχολημένος-η"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:198
 | 
			
		||||
#: ../js/ui/userMenu.js:199
 | 
			
		||||
msgid "Invisible"
 | 
			
		||||
msgstr "Αόρατος-η"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:201
 | 
			
		||||
#: ../js/ui/userMenu.js:202
 | 
			
		||||
msgid "Away"
 | 
			
		||||
msgstr "Απουσιάζει"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:204
 | 
			
		||||
#: ../js/ui/userMenu.js:205
 | 
			
		||||
msgid "Idle"
 | 
			
		||||
msgstr "Αδρανής"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:207
 | 
			
		||||
#: ../js/ui/userMenu.js:208
 | 
			
		||||
msgid "Offline"
 | 
			
		||||
msgstr "Εκτός σύνδεσης"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:779
 | 
			
		||||
#: ../js/ui/userMenu.js:781
 | 
			
		||||
msgid "Notifications"
 | 
			
		||||
msgstr "Ειδοποιήσεις"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:795
 | 
			
		||||
#: ../js/ui/userMenu.js:797
 | 
			
		||||
msgid "Switch User"
 | 
			
		||||
msgstr "Αλλαγή χρήστη"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:800
 | 
			
		||||
#: ../js/ui/userMenu.js:802
 | 
			
		||||
msgid "Log Out"
 | 
			
		||||
msgstr "Αποσύνδεση"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:820
 | 
			
		||||
#: ../js/ui/userMenu.js:822
 | 
			
		||||
msgid "Install Updates & Restart"
 | 
			
		||||
msgstr "Εγκατάσταση ενημερώσεων & επανεκκίνηση"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:838
 | 
			
		||||
#: ../js/ui/userMenu.js:840
 | 
			
		||||
msgid "Your chat status will be set to busy"
 | 
			
		||||
msgstr "Η κατάσταση συνομιλίας σας θα ορισθεί σε απασχολημένος"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:839
 | 
			
		||||
#: ../js/ui/userMenu.js:841
 | 
			
		||||
msgid ""
 | 
			
		||||
"Notifications are now disabled, including chat messages. Your online status "
 | 
			
		||||
"has been adjusted to let others know that you might not see their messages."
 | 
			
		||||
@@ -1855,34 +1860,36 @@ msgstr ""
 | 
			
		||||
"κατάσταση σας έχει ορισθεί έτσι ώστε να γίνεται γνωστό ότι πιθανόν να μην "
 | 
			
		||||
"δείτε τα μηνύματα τους."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:885
 | 
			
		||||
#: ../js/ui/userMenu.js:888
 | 
			
		||||
msgid "Other users are logged in."
 | 
			
		||||
msgstr "Και άλλοι χρήστες είναι συνδεμένοι."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:890
 | 
			
		||||
#: ../js/ui/userMenu.js:893
 | 
			
		||||
msgid "Shutting down might cause them to lose unsaved work."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Κλείνοντας μπορεί να τους προκαλέσετε την απώλεια αναποθήκευτης εργασίας."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:916
 | 
			
		||||
#. Translators: Remote here refers to a remote session, like a ssh login
 | 
			
		||||
#: ../js/ui/userMenu.js:921
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%s (remote)"
 | 
			
		||||
msgstr "%s (απομακρυσμένο)"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:918
 | 
			
		||||
#. Translators: Console here refers to a tty like a VT console
 | 
			
		||||
#: ../js/ui/userMenu.js:924
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%s (console)"
 | 
			
		||||
msgstr "%s (κονσόλα)"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/viewSelector.js:101
 | 
			
		||||
#: ../js/ui/viewSelector.js:100
 | 
			
		||||
msgid "Applications"
 | 
			
		||||
msgstr "Εφαρμογές"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/viewSelector.js:105
 | 
			
		||||
#: ../js/ui/viewSelector.js:104
 | 
			
		||||
msgid "Search"
 | 
			
		||||
msgstr "Αναζήτηση"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/wanda.js:92
 | 
			
		||||
#: ../js/ui/wanda.js:77
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid ""
 | 
			
		||||
"Sorry, no wisdom for you today:\n"
 | 
			
		||||
@@ -1891,7 +1898,7 @@ msgstr ""
 | 
			
		||||
"Συγγνώμη, κανένα απόφθεγμα για εσάς σήμερα:\n"
 | 
			
		||||
"%s"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/wanda.js:96
 | 
			
		||||
#: ../js/ui/wanda.js:81
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%s the Oracle says"
 | 
			
		||||
msgstr "%s ο Προφήτης λέει"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										219
									
								
								po/gl.po
									
									
									
									
									
								
							
							
						
						
									
										219
									
								
								po/gl.po
									
									
									
									
									
								
							@@ -10,10 +10,9 @@
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: gnome-shell master\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
 | 
			
		||||
"shell&keywords=I18N+L10N&component=general\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-02 23:02+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-03-04 12:40+0200\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2013-04-18 01:27+0200\n"
 | 
			
		||||
"PO-Revision-Date: 2013-04-18 01:42+0200\n"
 | 
			
		||||
"Last-Translator: Fran Dieguez <frandieguez@gnome.org>\n"
 | 
			
		||||
"Language-Team: gnome-l10n-gl@gnome.org\n"
 | 
			
		||||
"Language: gl\n"
 | 
			
		||||
@@ -30,7 +29,7 @@ msgstr "Capturas de pantalla"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-gnome-shell-screenshot.xml.in.h:2
 | 
			
		||||
msgid "Record a screencast"
 | 
			
		||||
msgstr "Gravar unha gravación de pantalla"
 | 
			
		||||
msgstr "Facer unha gravación da pantalla"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:1
 | 
			
		||||
msgid "System"
 | 
			
		||||
@@ -63,16 +62,16 @@ msgstr "Xestor de xanelas e inicio de aplicativos"
 | 
			
		||||
#: ../data/gnome-shell-extension-prefs.desktop.in.in.h:1
 | 
			
		||||
#: ../js/extensionPrefs/main.js:153
 | 
			
		||||
msgid "GNOME Shell Extension Preferences"
 | 
			
		||||
msgstr "Preferencias de extensións de GNOME Shell"
 | 
			
		||||
msgstr "Preferencias das extensións de GNOME Shell"
 | 
			
		||||
 | 
			
		||||
#: ../data/gnome-shell-extension-prefs.desktop.in.in.h:2
 | 
			
		||||
msgid "Configure GNOME Shell Extensions"
 | 
			
		||||
msgstr "Configurar as extensións de GNOME Shell"
 | 
			
		||||
msgstr "Configure as extensións de GNOME Shell"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:1
 | 
			
		||||
msgid "Enable internal tools useful for developers and testers from Alt-F2"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Activar as ferramentas internas útiles para os desenvolvedores e probadores, "
 | 
			
		||||
"Activar as ferramentas internas útiles para os desenvolvedores e probadores "
 | 
			
		||||
"usando Alt-F2"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:2
 | 
			
		||||
@@ -85,7 +84,7 @@ msgstr ""
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:3
 | 
			
		||||
msgid "Uuids of extensions to enable"
 | 
			
		||||
msgstr "Uuid das extensións que activar"
 | 
			
		||||
msgstr "UUIDs das extensións a activar"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:4
 | 
			
		||||
msgid ""
 | 
			
		||||
@@ -375,43 +374,42 @@ msgstr ""
 | 
			
		||||
"Seleccione unha extensión que configurar usando a caixa combinada de arriba."
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:405
 | 
			
		||||
#| msgid "Session..."
 | 
			
		||||
msgid "Session…"
 | 
			
		||||
msgstr "Sesión…"
 | 
			
		||||
 | 
			
		||||
#. translators: this message is shown below the user list on the
 | 
			
		||||
#. login screen. It can be activated to reveal an entry for
 | 
			
		||||
#. manually entering the username.
 | 
			
		||||
#: ../js/gdm/loginDialog.js:629
 | 
			
		||||
#: ../js/gdm/loginDialog.js:630
 | 
			
		||||
msgid "Not listed?"
 | 
			
		||||
msgstr "Non está na lista?"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:783 ../js/ui/components/networkAgent.js:137
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:375
 | 
			
		||||
#: ../js/gdm/loginDialog.js:787 ../js/ui/components/networkAgent.js:137
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:376
 | 
			
		||||
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:399
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:126
 | 
			
		||||
#: ../js/ui/userMenu.js:932
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:100
 | 
			
		||||
#: ../js/ui/userMenu.js:938
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "Cancelar"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:799
 | 
			
		||||
#: ../js/gdm/loginDialog.js:803
 | 
			
		||||
msgctxt "button"
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr "Iniciar sesión"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:799
 | 
			
		||||
#: ../js/gdm/loginDialog.js:803
 | 
			
		||||
msgid "Next"
 | 
			
		||||
msgstr "Seguinte"
 | 
			
		||||
 | 
			
		||||
#. TTLS and PEAP are actually much more complicated, but this complication
 | 
			
		||||
#. is not visible here since we only care about phase2 authentication
 | 
			
		||||
#. (and don't even care of which one)
 | 
			
		||||
#: ../js/gdm/loginDialog.js:904 ../js/ui/components/networkAgent.js:260
 | 
			
		||||
#: ../js/gdm/loginDialog.js:918 ../js/ui/components/networkAgent.js:260
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:278
 | 
			
		||||
msgid "Username: "
 | 
			
		||||
msgstr "Nome de usuario: "
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:1157
 | 
			
		||||
#: ../js/gdm/loginDialog.js:1174
 | 
			
		||||
msgid "Login Window"
 | 
			
		||||
msgstr "Xanela de inicio de sesión"
 | 
			
		||||
 | 
			
		||||
@@ -420,8 +418,8 @@ msgstr "Xanela de inicio de sesión"
 | 
			
		||||
msgid "Power"
 | 
			
		||||
msgstr "Apagar"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:694 ../js/ui/userMenu.js:698
 | 
			
		||||
#: ../js/ui/userMenu.js:814
 | 
			
		||||
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:696 ../js/ui/userMenu.js:700
 | 
			
		||||
#: ../js/ui/userMenu.js:816
 | 
			
		||||
msgid "Suspend"
 | 
			
		||||
msgstr "Suspender"
 | 
			
		||||
 | 
			
		||||
@@ -429,58 +427,58 @@ msgstr "Suspender"
 | 
			
		||||
msgid "Restart"
 | 
			
		||||
msgstr "Reiniciar"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:696
 | 
			
		||||
#: ../js/ui/userMenu.js:698 ../js/ui/userMenu.js:813 ../js/ui/userMenu.js:936
 | 
			
		||||
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:698
 | 
			
		||||
#: ../js/ui/userMenu.js:700 ../js/ui/userMenu.js:815 ../js/ui/userMenu.js:942
 | 
			
		||||
msgid "Power Off"
 | 
			
		||||
msgstr "Apagar"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/util.js:182
 | 
			
		||||
#: ../js/gdm/util.js:249
 | 
			
		||||
msgid "Authentication error"
 | 
			
		||||
msgstr "Erro de autenticación"
 | 
			
		||||
 | 
			
		||||
#. Translators: this message is shown below the password entry field
 | 
			
		||||
#. to indicate the user can swipe their finger instead
 | 
			
		||||
#: ../js/gdm/util.js:299
 | 
			
		||||
#: ../js/gdm/util.js:366
 | 
			
		||||
msgid "(or swipe finger)"
 | 
			
		||||
msgstr "(ou pase o dedo)"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/util.js:324
 | 
			
		||||
#: ../js/gdm/util.js:391
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "(e.g., user or %s)"
 | 
			
		||||
msgstr "(p.ex., usuario ou %s)"
 | 
			
		||||
 | 
			
		||||
#: ../js/misc/util.js:94
 | 
			
		||||
#: ../js/misc/util.js:97
 | 
			
		||||
msgid "Command not found"
 | 
			
		||||
msgstr "Orde non atopada"
 | 
			
		||||
 | 
			
		||||
#. Replace "Error invoking GLib.shell_parse_argv: " with
 | 
			
		||||
#. something nicer
 | 
			
		||||
#: ../js/misc/util.js:127
 | 
			
		||||
#: ../js/misc/util.js:130
 | 
			
		||||
msgid "Could not parse command:"
 | 
			
		||||
msgstr "Non foi posíbel analizar a orde:"
 | 
			
		||||
 | 
			
		||||
#: ../js/misc/util.js:135
 | 
			
		||||
#: ../js/misc/util.js:138
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Execution of '%s' failed:"
 | 
			
		||||
msgstr "Produciuse un fallo na execución de «%s»:"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:348
 | 
			
		||||
#: ../js/ui/appDisplay.js:349
 | 
			
		||||
msgid "Frequent"
 | 
			
		||||
msgstr "Frecuentes"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:355
 | 
			
		||||
#: ../js/ui/appDisplay.js:356
 | 
			
		||||
msgid "All"
 | 
			
		||||
msgstr "Todos"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:913
 | 
			
		||||
#: ../js/ui/appDisplay.js:914
 | 
			
		||||
msgid "New Window"
 | 
			
		||||
msgstr "Xanela nova"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:916 ../js/ui/dash.js:284
 | 
			
		||||
#: ../js/ui/appDisplay.js:917 ../js/ui/dash.js:284
 | 
			
		||||
msgid "Remove from Favorites"
 | 
			
		||||
msgstr "Retirar dos marcadores"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:917
 | 
			
		||||
#: ../js/ui/appDisplay.js:918
 | 
			
		||||
msgid "Add to Favorites"
 | 
			
		||||
msgstr "Engadir aos favoritos"
 | 
			
		||||
 | 
			
		||||
@@ -494,7 +492,7 @@ msgstr "%s foi engadido aos seus favoritos."
 | 
			
		||||
msgid "%s has been removed from your favorites."
 | 
			
		||||
msgstr "%s retirouse dos seus marcadores."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:787
 | 
			
		||||
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:789
 | 
			
		||||
msgid "Settings"
 | 
			
		||||
msgstr "Preferencias"
 | 
			
		||||
 | 
			
		||||
@@ -517,7 +515,7 @@ msgctxt "event list time"
 | 
			
		||||
msgid "%H\\u2236%M"
 | 
			
		||||
msgstr "%H\\u2236%M"
 | 
			
		||||
 | 
			
		||||
#. Transators: Shown in calendar event list, if 12h format,
 | 
			
		||||
#. Translators: Shown in calendar event list, if 12h format,
 | 
			
		||||
#. \u2236 is a ratio character, similar to : and \u2009 is
 | 
			
		||||
#. a thin space
 | 
			
		||||
#: ../js/ui/calendar.js:77
 | 
			
		||||
@@ -619,35 +617,35 @@ msgid "S"
 | 
			
		||||
msgstr "S"
 | 
			
		||||
 | 
			
		||||
#. Translators: Text to show if there are no events
 | 
			
		||||
#: ../js/ui/calendar.js:692
 | 
			
		||||
#: ../js/ui/calendar.js:720
 | 
			
		||||
msgid "Nothing Scheduled"
 | 
			
		||||
msgstr "Nada programado"
 | 
			
		||||
 | 
			
		||||
#. Translators: Shown on calendar heading when selected day occurs on current year
 | 
			
		||||
#: ../js/ui/calendar.js:708
 | 
			
		||||
#: ../js/ui/calendar.js:736
 | 
			
		||||
msgctxt "calendar heading"
 | 
			
		||||
msgid "%A, %B %d"
 | 
			
		||||
msgstr "%A, %d de %B"
 | 
			
		||||
 | 
			
		||||
#. Translators: Shown on calendar heading when selected day occurs on different year
 | 
			
		||||
#: ../js/ui/calendar.js:711
 | 
			
		||||
#: ../js/ui/calendar.js:739
 | 
			
		||||
msgctxt "calendar heading"
 | 
			
		||||
msgid "%A, %B %d, %Y"
 | 
			
		||||
msgstr "%A, %d de %B de %Y"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:721
 | 
			
		||||
#: ../js/ui/calendar.js:749
 | 
			
		||||
msgid "Today"
 | 
			
		||||
msgstr "Hoxe"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:725
 | 
			
		||||
#: ../js/ui/calendar.js:753
 | 
			
		||||
msgid "Tomorrow"
 | 
			
		||||
msgstr "Mañá"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:736
 | 
			
		||||
#: ../js/ui/calendar.js:764
 | 
			
		||||
msgid "This week"
 | 
			
		||||
msgstr "Esta semana"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:744
 | 
			
		||||
#: ../js/ui/calendar.js:772
 | 
			
		||||
msgid "Next week"
 | 
			
		||||
msgstr "A vindeira semana"
 | 
			
		||||
 | 
			
		||||
@@ -663,12 +661,12 @@ msgstr "Unidade externa desconectada"
 | 
			
		||||
msgid "Removable Devices"
 | 
			
		||||
msgstr "Dispositivos extraíbeis"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/autorunManager.js:593
 | 
			
		||||
#: ../js/ui/components/autorunManager.js:594
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Open with %s"
 | 
			
		||||
msgstr "Abrir con %s"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/autorunManager.js:619
 | 
			
		||||
#: ../js/ui/components/autorunManager.js:620
 | 
			
		||||
msgid "Eject"
 | 
			
		||||
msgstr "Expulsar"
 | 
			
		||||
 | 
			
		||||
@@ -777,7 +775,7 @@ msgid "Sorry, that didn't work. Please try again."
 | 
			
		||||
msgstr "Desculpe, iso non funcionou. Ténteo de novo."
 | 
			
		||||
 | 
			
		||||
#. Translators: this is a filename used for screencast recording
 | 
			
		||||
#: ../js/ui/components/recorder.js:48
 | 
			
		||||
#: ../js/ui/components/recorder.js:47
 | 
			
		||||
#, no-c-format
 | 
			
		||||
msgid "Screencast from %d %t"
 | 
			
		||||
msgstr "Screencast desde %d %t"
 | 
			
		||||
@@ -1024,7 +1022,7 @@ msgstr "Ver conta"
 | 
			
		||||
msgid "Unknown reason"
 | 
			
		||||
msgstr "Razón descoñecida"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/ctrlAltTab.js:29 ../js/ui/viewSelector.js:97
 | 
			
		||||
#: ../js/ui/ctrlAltTab.js:29 ../js/ui/viewSelector.js:96
 | 
			
		||||
msgid "Windows"
 | 
			
		||||
msgstr "Xanelas"
 | 
			
		||||
 | 
			
		||||
@@ -1040,7 +1038,7 @@ msgstr "Taboleiro"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/dateMenu.js:91
 | 
			
		||||
msgid "Open Calendar"
 | 
			
		||||
msgstr "Abrir o calendario"
 | 
			
		||||
msgstr "Abrir Calendario"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/dateMenu.js:96
 | 
			
		||||
msgid "Open Clocks"
 | 
			
		||||
@@ -1053,7 +1051,7 @@ msgstr "Preferencias de data e hora"
 | 
			
		||||
#. Translators: This is the date format to use when the calendar popup is
 | 
			
		||||
#. * shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
 | 
			
		||||
#.
 | 
			
		||||
#: ../js/ui/dateMenu.js:205
 | 
			
		||||
#: ../js/ui/dateMenu.js:215
 | 
			
		||||
msgid "%A %B %e, %Y"
 | 
			
		||||
msgstr "%a, %e de %B, %Y"
 | 
			
		||||
 | 
			
		||||
@@ -1071,7 +1069,7 @@ msgstr "Saír da sesión"
 | 
			
		||||
#: ../js/ui/endSessionDialog.js:65
 | 
			
		||||
msgid "Click Log Out to quit these applications and log out of the system."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Prema sobre «Saír da sesión» para saír deses aplicativos e saír da sesión do "
 | 
			
		||||
"Prema en «Saír da sesión» para pechar estes aplicativos e saír da sesión do "
 | 
			
		||||
"sistema."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/endSessionDialog.js:67
 | 
			
		||||
@@ -1090,7 +1088,7 @@ msgstr[1] "A súa sesión pecharase automaticamente en %d segundos."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/endSessionDialog.js:76
 | 
			
		||||
msgid "Logging out of the system."
 | 
			
		||||
msgstr "Saíndo da sesión."
 | 
			
		||||
msgstr "Saíndo da sesión do sistema."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/endSessionDialog.js:78
 | 
			
		||||
msgctxt "button"
 | 
			
		||||
@@ -1104,7 +1102,7 @@ msgstr "Apagar"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/endSessionDialog.js:84
 | 
			
		||||
msgid "Click Power Off to quit these applications and power off the system."
 | 
			
		||||
msgstr "Prema sobre «Apagar» para saír deses aplicativos e apagar o sistema."
 | 
			
		||||
msgstr "Prema sobre «Apagar» para pechar estes aplicativos e apagar o sistema."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/endSessionDialog.js:86
 | 
			
		||||
#, c-format
 | 
			
		||||
@@ -1134,7 +1132,7 @@ msgstr "Reiniciar"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/endSessionDialog.js:101
 | 
			
		||||
msgid "Click Restart to quit these applications and restart the system."
 | 
			
		||||
msgstr "Prema «Reiniciar» para saír deses aplicativos e reiniciar o sistema."
 | 
			
		||||
msgstr "Prema «Reiniciar» para pechar estes aplicativos e reiniciar o sistema."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/endSessionDialog.js:103
 | 
			
		||||
#, c-format
 | 
			
		||||
@@ -1169,7 +1167,7 @@ msgstr "Non hai ningunha extensión instalada"
 | 
			
		||||
#: ../js/ui/lookingGlass.js:747
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%s has not emitted any errors."
 | 
			
		||||
msgstr "%s non xerou ningún erro."
 | 
			
		||||
msgstr "%s non emitiu ningún erro."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:753
 | 
			
		||||
msgid "Hide Errors"
 | 
			
		||||
@@ -1195,7 +1193,7 @@ msgstr "Erro"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:773
 | 
			
		||||
msgid "Out of date"
 | 
			
		||||
msgstr "Caducado"
 | 
			
		||||
msgstr "Obsoleto"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:775
 | 
			
		||||
msgid "Downloading"
 | 
			
		||||
@@ -1218,7 +1216,6 @@ msgid "Remove"
 | 
			
		||||
msgstr "Retirar"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:1501
 | 
			
		||||
#| msgid "No Messages"
 | 
			
		||||
msgid "Clear Messages"
 | 
			
		||||
msgstr "Limpar mensaxes"
 | 
			
		||||
 | 
			
		||||
@@ -1226,15 +1223,15 @@ msgstr "Limpar mensaxes"
 | 
			
		||||
msgid "Notification Settings"
 | 
			
		||||
msgstr "Preferencias das notificacións"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:1707
 | 
			
		||||
#: ../js/ui/messageTray.js:1709
 | 
			
		||||
msgid "No Messages"
 | 
			
		||||
msgstr "Non hai mensaxes"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:1787
 | 
			
		||||
#: ../js/ui/messageTray.js:1785
 | 
			
		||||
msgid "Message Tray"
 | 
			
		||||
msgstr "Bandexa de mensaxes"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:2864
 | 
			
		||||
#: ../js/ui/messageTray.js:2813
 | 
			
		||||
msgid "System Information"
 | 
			
		||||
msgstr "Información do sistema"
 | 
			
		||||
 | 
			
		||||
@@ -1243,14 +1240,14 @@ msgctxt "program"
 | 
			
		||||
msgid "Unknown"
 | 
			
		||||
msgstr "Descoñecido"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/overviewControls.js:460 ../js/ui/screenShield.js:153
 | 
			
		||||
#: ../js/ui/overviewControls.js:463 ../js/ui/screenShield.js:149
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%d new message"
 | 
			
		||||
msgid_plural "%d new messages"
 | 
			
		||||
msgstr[0] "%d mensaxe nova"
 | 
			
		||||
msgstr[1] "%d mensaxes novas"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/overview.js:82
 | 
			
		||||
#: ../js/ui/overview.js:84
 | 
			
		||||
msgid "Undo"
 | 
			
		||||
msgstr "Desfacer"
 | 
			
		||||
 | 
			
		||||
@@ -1262,22 +1259,21 @@ msgstr "Vista xeral"
 | 
			
		||||
#. in the search entry when no search is
 | 
			
		||||
#. active; it should not exceed ~30
 | 
			
		||||
#. characters.
 | 
			
		||||
#: ../js/ui/overview.js:284
 | 
			
		||||
#| msgid "Type to search..."
 | 
			
		||||
#: ../js/ui/overview.js:271
 | 
			
		||||
msgid "Type to search…"
 | 
			
		||||
msgstr "Escriba para buscar…"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/panel.js:613
 | 
			
		||||
#: ../js/ui/panel.js:633
 | 
			
		||||
msgid "Quit"
 | 
			
		||||
msgstr "Saír"
 | 
			
		||||
 | 
			
		||||
#. Translators: If there is no suitable word for "Activities"
 | 
			
		||||
#. in your language, you can use the word for "Overview".
 | 
			
		||||
#: ../js/ui/panel.js:642
 | 
			
		||||
#: ../js/ui/panel.js:657
 | 
			
		||||
msgid "Activities"
 | 
			
		||||
msgstr "Actividades"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/panel.js:983
 | 
			
		||||
#: ../js/ui/panel.js:954
 | 
			
		||||
msgid "Top Bar"
 | 
			
		||||
msgstr "Barra superior"
 | 
			
		||||
 | 
			
		||||
@@ -1290,34 +1286,34 @@ msgstr "Barra superior"
 | 
			
		||||
msgid "toggle-switch-us"
 | 
			
		||||
msgstr "toggle-switch-intl"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/runDialog.js:205
 | 
			
		||||
#: ../js/ui/runDialog.js:74
 | 
			
		||||
msgid "Enter a Command"
 | 
			
		||||
msgstr "Escriba unha orde"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/runDialog.js:241
 | 
			
		||||
#: ../js/ui/runDialog.js:110
 | 
			
		||||
msgid "Close"
 | 
			
		||||
msgstr "Pechar"
 | 
			
		||||
 | 
			
		||||
#. Translators: This is a time format for a date in
 | 
			
		||||
#. long format
 | 
			
		||||
#: ../js/ui/screenShield.js:90
 | 
			
		||||
#: ../js/ui/screenShield.js:86
 | 
			
		||||
msgid "%A, %B %d"
 | 
			
		||||
msgstr "%A, %d de %B"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:155
 | 
			
		||||
#: ../js/ui/screenShield.js:151
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%d new notification"
 | 
			
		||||
msgid_plural "%d new notifications"
 | 
			
		||||
msgstr[0] "%d notificación nova"
 | 
			
		||||
msgstr[1] "%d notificacións novas"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:442 ../js/ui/userMenu.js:805
 | 
			
		||||
#: ../js/ui/screenShield.js:438 ../js/ui/userMenu.js:807
 | 
			
		||||
msgid "Lock"
 | 
			
		||||
msgstr "Bloquear"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:639
 | 
			
		||||
#: ../js/ui/screenShield.js:641
 | 
			
		||||
msgid "GNOME needs to lock the screen"
 | 
			
		||||
msgstr "GNOME debe bloquear a pantalla"
 | 
			
		||||
msgstr "GNOME precisa bloquear a pantalla"
 | 
			
		||||
 | 
			
		||||
#. We could not become modal, so we can't activate the
 | 
			
		||||
#. screenshield. The user is probably very upset at this
 | 
			
		||||
@@ -1326,22 +1322,19 @@ msgstr "GNOME debe bloquear a pantalla"
 | 
			
		||||
#.
 | 
			
		||||
#. XXX: another option is to kick the user into the gdm login
 | 
			
		||||
#. screen, where we're not affected by grabs
 | 
			
		||||
#: ../js/ui/screenShield.js:758 ../js/ui/screenShield.js:1169
 | 
			
		||||
#| msgid "Unable to connect to %s"
 | 
			
		||||
#: ../js/ui/screenShield.js:762 ../js/ui/screenShield.js:1198
 | 
			
		||||
msgid "Unable to lock"
 | 
			
		||||
msgstr "Non foi posíbel bloquear"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:759 ../js/ui/screenShield.js:1170
 | 
			
		||||
#| msgid "No such application"
 | 
			
		||||
#: ../js/ui/screenShield.js:763 ../js/ui/screenShield.js:1199
 | 
			
		||||
msgid "Lock was blocked by an application"
 | 
			
		||||
msgstr "O bloqueo foi impedido por un aplicativo"
 | 
			
		||||
msgstr "Un aplicativo impediu o bloqueo"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/searchDisplay.js:431
 | 
			
		||||
#| msgid "Searching..."
 | 
			
		||||
#: ../js/ui/searchDisplay.js:453
 | 
			
		||||
msgid "Searching…"
 | 
			
		||||
msgstr "Buscando…"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/searchDisplay.js:475
 | 
			
		||||
#: ../js/ui/searchDisplay.js:497
 | 
			
		||||
msgid "No results."
 | 
			
		||||
msgstr "Sen resultados."
 | 
			
		||||
 | 
			
		||||
@@ -1353,11 +1346,11 @@ msgstr "Copiar"
 | 
			
		||||
msgid "Paste"
 | 
			
		||||
msgstr "Pegar"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellEntry.js:105
 | 
			
		||||
#: ../js/ui/shellEntry.js:101
 | 
			
		||||
msgid "Show Text"
 | 
			
		||||
msgstr "Mostrar texto"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellEntry.js:107
 | 
			
		||||
#: ../js/ui/shellEntry.js:103
 | 
			
		||||
msgid "Hide Text"
 | 
			
		||||
msgstr "Ocultar texto"
 | 
			
		||||
 | 
			
		||||
@@ -1367,9 +1360,9 @@ msgstr "Contrasinal"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellMountOperation.js:391
 | 
			
		||||
msgid "Remember Password"
 | 
			
		||||
msgstr "Lembrar o contrasinal"
 | 
			
		||||
msgstr "Lembrar contrasinal"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:140
 | 
			
		||||
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:114
 | 
			
		||||
msgid "Unlock"
 | 
			
		||||
msgstr "Desbloquear"
 | 
			
		||||
 | 
			
		||||
@@ -1433,12 +1426,10 @@ msgid "Visibility"
 | 
			
		||||
msgstr "Visibilidade"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:59
 | 
			
		||||
#| msgid "Send Files to Device..."
 | 
			
		||||
msgid "Send Files to Device…"
 | 
			
		||||
msgstr "Enviar ficheiros ao dispositivo…"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:60
 | 
			
		||||
#| msgid "Set Up a New Device..."
 | 
			
		||||
msgid "Set Up a New Device…"
 | 
			
		||||
msgstr "Configurar un dispositivo novo…"
 | 
			
		||||
 | 
			
		||||
@@ -1465,7 +1456,6 @@ msgid "connecting..."
 | 
			
		||||
msgstr "conectando…"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:239
 | 
			
		||||
#| msgid "Send Files..."
 | 
			
		||||
msgid "Send Files…"
 | 
			
		||||
msgstr "Enviar ficheiros…"
 | 
			
		||||
 | 
			
		||||
@@ -1547,7 +1537,7 @@ msgstr "Mostrar a distribución do teclado"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/keyboard.js:373
 | 
			
		||||
msgid "Region & Language Settings"
 | 
			
		||||
msgstr "Configuración rexional e de idioma"
 | 
			
		||||
msgstr "Preferencias de rexión e idioma"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/lockScreenMenu.js:43
 | 
			
		||||
msgid "Volume, network, battery"
 | 
			
		||||
@@ -1592,7 +1582,7 @@ msgstr "non dispoñíbel"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:493 ../js/ui/status/network.js:1551
 | 
			
		||||
msgid "connection failed"
 | 
			
		||||
msgstr "conexión fallida"
 | 
			
		||||
msgstr "conexión fallada"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:552 ../js/ui/status/network.js:1435
 | 
			
		||||
#: ../js/ui/status/network.js:1627
 | 
			
		||||
@@ -1678,7 +1668,6 @@ msgstr "Preferencias de enerxía"
 | 
			
		||||
#. 0 is reported when UPower does not have enough data
 | 
			
		||||
#. to estimate battery life
 | 
			
		||||
#: ../js/ui/status/power.js:99
 | 
			
		||||
#| msgid "Estimating..."
 | 
			
		||||
msgid "Estimating…"
 | 
			
		||||
msgstr "Estimando…"
 | 
			
		||||
 | 
			
		||||
@@ -1778,59 +1767,59 @@ msgstr "Volume"
 | 
			
		||||
msgid "Microphone"
 | 
			
		||||
msgstr "Micrófono"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/unlockDialog.js:151
 | 
			
		||||
#: ../js/ui/unlockDialog.js:125
 | 
			
		||||
msgid "Log in as another user"
 | 
			
		||||
msgstr "Iniciar sesión como outro usuario"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/unlockDialog.js:177
 | 
			
		||||
#: ../js/ui/unlockDialog.js:146
 | 
			
		||||
msgid "Unlock Window"
 | 
			
		||||
msgstr "Desbloquear xanela"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:192
 | 
			
		||||
#: ../js/ui/userMenu.js:193
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr "Dispoñíbel"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:195
 | 
			
		||||
#: ../js/ui/userMenu.js:196
 | 
			
		||||
msgid "Busy"
 | 
			
		||||
msgstr "Ocupado"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:198
 | 
			
		||||
#: ../js/ui/userMenu.js:199
 | 
			
		||||
msgid "Invisible"
 | 
			
		||||
msgstr "Invisíbel"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:201
 | 
			
		||||
#: ../js/ui/userMenu.js:202
 | 
			
		||||
msgid "Away"
 | 
			
		||||
msgstr "Ausente"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:204
 | 
			
		||||
#: ../js/ui/userMenu.js:205
 | 
			
		||||
msgid "Idle"
 | 
			
		||||
msgstr "Inactivo"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:207
 | 
			
		||||
#: ../js/ui/userMenu.js:208
 | 
			
		||||
msgid "Offline"
 | 
			
		||||
msgstr "Desconectado"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:779
 | 
			
		||||
#: ../js/ui/userMenu.js:781
 | 
			
		||||
msgid "Notifications"
 | 
			
		||||
msgstr "Notificacións"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:795
 | 
			
		||||
#: ../js/ui/userMenu.js:797
 | 
			
		||||
msgid "Switch User"
 | 
			
		||||
msgstr "Cambiar de usuario"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:800
 | 
			
		||||
#: ../js/ui/userMenu.js:802
 | 
			
		||||
msgid "Log Out"
 | 
			
		||||
msgstr "Saír da sesión"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:820
 | 
			
		||||
#: ../js/ui/userMenu.js:822
 | 
			
		||||
msgid "Install Updates & Restart"
 | 
			
		||||
msgstr "Instalar actualizacións e reiniciar"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:838
 | 
			
		||||
#: ../js/ui/userMenu.js:840
 | 
			
		||||
msgid "Your chat status will be set to busy"
 | 
			
		||||
msgstr "O seu estado de conversa definirase como «ocupado»"
 | 
			
		||||
msgstr "O seu estado de conversa estabelecerase a «ocupado»"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:839
 | 
			
		||||
#: ../js/ui/userMenu.js:841
 | 
			
		||||
msgid ""
 | 
			
		||||
"Notifications are now disabled, including chat messages. Your online status "
 | 
			
		||||
"has been adjusted to let others know that you might not see their messages."
 | 
			
		||||
@@ -1839,33 +1828,35 @@ msgstr ""
 | 
			
		||||
"conversa. O seu estado de conexión axustouse para que outros saiban que non "
 | 
			
		||||
"quere ver as súas mensaxes."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:885
 | 
			
		||||
#: ../js/ui/userMenu.js:888
 | 
			
		||||
msgid "Other users are logged in."
 | 
			
		||||
msgstr "Hai outros usuarios conectados."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:890
 | 
			
		||||
#: ../js/ui/userMenu.js:893
 | 
			
		||||
msgid "Shutting down might cause them to lose unsaved work."
 | 
			
		||||
msgstr "Se apaga o computador pode perder o traballo que non gardou."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:916
 | 
			
		||||
#. Translators: Remote here refers to a remote session, like a ssh login
 | 
			
		||||
#: ../js/ui/userMenu.js:921
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%s (remote)"
 | 
			
		||||
msgstr "%s (remoto)"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:918
 | 
			
		||||
#. Translators: Console here refers to a tty like a VT console
 | 
			
		||||
#: ../js/ui/userMenu.js:924
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%s (console)"
 | 
			
		||||
msgstr "%s (consola)"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/viewSelector.js:101
 | 
			
		||||
#: ../js/ui/viewSelector.js:100
 | 
			
		||||
msgid "Applications"
 | 
			
		||||
msgstr "Aplicativos"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/viewSelector.js:105
 | 
			
		||||
#: ../js/ui/viewSelector.js:104
 | 
			
		||||
msgid "Search"
 | 
			
		||||
msgstr "Buscar"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/wanda.js:92
 | 
			
		||||
#: ../js/ui/wanda.js:77
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid ""
 | 
			
		||||
"Sorry, no wisdom for you today:\n"
 | 
			
		||||
@@ -1874,7 +1865,7 @@ msgstr ""
 | 
			
		||||
"Hoxe non ten ningunha mensaxe:\n"
 | 
			
		||||
"%s"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/wanda.js:96
 | 
			
		||||
#: ../js/ui/wanda.js:81
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%s the Oracle says"
 | 
			
		||||
msgstr "%s o oráculo dí"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								po/lt.po
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								po/lt.po
									
									
									
									
									
								
							@@ -461,7 +461,7 @@ msgstr "Nepavyko įvykdyti „%s“:"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:349
 | 
			
		||||
msgid "Frequent"
 | 
			
		||||
msgstr "Dažniausios"
 | 
			
		||||
msgstr "Dažnai naudojamos"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:356
 | 
			
		||||
msgid "All"
 | 
			
		||||
@@ -1262,7 +1262,7 @@ msgstr "Apžvalga"
 | 
			
		||||
#. characters.
 | 
			
		||||
#: ../js/ui/overview.js:271
 | 
			
		||||
msgid "Type to search…"
 | 
			
		||||
msgstr "Rašykite ko ieškote…"
 | 
			
		||||
msgstr "Rašykite, ko ieškote…"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/panel.js:612
 | 
			
		||||
msgid "Quit"
 | 
			
		||||
@@ -1299,7 +1299,7 @@ msgstr "Užverti"
 | 
			
		||||
#. long format
 | 
			
		||||
#: ../js/ui/screenShield.js:86
 | 
			
		||||
msgid "%A, %B %d"
 | 
			
		||||
msgstr "%A, %B %d"
 | 
			
		||||
msgstr "%A, %B %d d."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:151
 | 
			
		||||
#, c-format
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										320
									
								
								po/ml.po
									
									
									
									
									
								
							
							
						
						
									
										320
									
								
								po/ml.po
									
									
									
									
									
								
							@@ -10,9 +10,9 @@ msgstr ""
 | 
			
		||||
"Project-Id-Version: gnome-shell master\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
 | 
			
		||||
"shell&keywords=I18N+L10N&component=general\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-23 11:49+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-03-25 14:57+0530\n"
 | 
			
		||||
"Last-Translator: Ani Peter <peter.ani@gmail.com>\n"
 | 
			
		||||
"POT-Creation-Date: 2013-04-24 18:23+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-04-25 00:32+0530\n"
 | 
			
		||||
"Last-Translator: Balasankar C <c.balasankar@gmail.com>\n"
 | 
			
		||||
"Language-Team: American English <kde-i18n-doc@kde.org>\n"
 | 
			
		||||
"Language: ml\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
@@ -44,10 +44,14 @@ msgid "Focus the active notification"
 | 
			
		||||
msgstr "സജീവമായ അറിയിപ്പിനെ കേന്ദ്രീകരിക്കുക"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:4
 | 
			
		||||
msgid "Show the overview"
 | 
			
		||||
msgstr "പൊതുവായ അവലോകനം കാണിക്കുക"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:5
 | 
			
		||||
msgid "Show all applications"
 | 
			
		||||
msgstr "എല്ലാ പ്രയോഗങ്ങളും കാണിയ്ക്കുക"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:5
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:6
 | 
			
		||||
msgid "Open the application menu"
 | 
			
		||||
msgstr "പ്രയോഗത്തിന്റെ മെനു തുറക്കുക"
 | 
			
		||||
 | 
			
		||||
@@ -71,8 +75,7 @@ msgstr "ഗ്നോം ഷെല് എക്സ്റ്റെന്ഷ
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:1
 | 
			
		||||
msgid "Enable internal tools useful for developers and testers from Alt-F2"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Alt-F2-ല് ഡവലപ്പര്മാര്ക്കും ടെസ്റ്റേര്സിനും പ്രയോജനകരമായ ആന്തരിക "
 | 
			
		||||
"പ്രയോഗങ്ങള് പ്രവര്ത്തന "
 | 
			
		||||
"Alt-F2-ല് ഡവലപ്പര്മാര്ക്കും ടെസ്റ്റേര്സിനും പ്രയോജനകരമായ ആന്തരിക പ്രയോഗങ്ങള് പ്രവര്ത്തന "
 | 
			
		||||
"സജ്ജമാക്കുന്നു"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:2
 | 
			
		||||
@@ -80,8 +83,7 @@ msgid ""
 | 
			
		||||
"Allows access to internal debugging and monitoring tools using the Alt-F2 "
 | 
			
		||||
"dialog."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Alt-F2 ഡയലോഗ് ഉപയോഗിച്ചു് ആന്തരിക ഡീബഗ്ഗിലേക്കും നീരീക്ഷണ പ്രയോഗങ്ങളിലേക്കും "
 | 
			
		||||
"പ്രവേശനം "
 | 
			
		||||
"Alt-F2 ഡയലോഗ് ഉപയോഗിച്ചു് ആന്തരിക ഡീബഗ്ഗിലേക്കും നീരീക്ഷണ പ്രയോഗങ്ങളിലേക്കും പ്രവേശനം "
 | 
			
		||||
"അനുവദിയ്ക്കുക."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:3
 | 
			
		||||
@@ -95,19 +97,14 @@ msgid ""
 | 
			
		||||
"list. You can also manipulate this list with the EnableExtension and "
 | 
			
		||||
"DisableExtension DBus methods on org.gnome.Shell."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"ഗ്നോം ഷെല് എക്സ്റ്റെന്ഷനുകള്ക്കു് ഒരു യുയുഐഡി വിശേഷതയുണ്ടു്; ലഭ്യമാക്കേണ്ട "
 | 
			
		||||
"എക്സ്റ്റെന്ഷനുകള് ഈ കീ പട്ടിക "
 | 
			
		||||
"ലഭ്യമാക്കുന്നു. ലഭ്യമാക്കേണ്ട ഏതു് എക്സ്റ്റെന്ഷനും ഈ പട്ടികയിലുണ്ടാവണം. "
 | 
			
		||||
"org.gnome.Shell-ല് "
 | 
			
		||||
"നിങ്ങള്ക്കു് EnableExtension, DisableExtension എന്നീ ഡീബസ് രീതികളിലൂടെ ഈ "
 | 
			
		||||
"പട്ടിക "
 | 
			
		||||
"ഗ്നോം ഷെല് എക്സ്റ്റെന്ഷനുകള്ക്കു് ഒരു യുയുഐഡി വിശേഷതയുണ്ടു്; ലഭ്യമാക്കേണ്ട എക്സ്റ്റെന്ഷനുകള് ഈ കീ പട്ടിക "
 | 
			
		||||
"ലഭ്യമാക്കുന്നു. ലഭ്യമാക്കേണ്ട ഏതു് എക്സ്റ്റെന്ഷനും ഈ പട്ടികയിലുണ്ടാവണം. org.gnome.Shell-ല് "
 | 
			
		||||
"നിങ്ങള്ക്കു് EnableExtension, DisableExtension എന്നീ ഡീബസ് രീതികളിലൂടെ ഈ പട്ടിക "
 | 
			
		||||
"കൈകാര്യം ചെയ്യുവാനും സാധിയ്ക്കുന്നു."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:5
 | 
			
		||||
msgid "Whether to collect stats about applications usage"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"പ്രയോഗങ്ങളുടെ ഉപയോഗത്തെപ്പറ്റിയുള്ള സ്ഥിതിവിവരക്കണക്കുകള് ശേഖരിയ്ക്കണമോ "
 | 
			
		||||
"എന്നു്"
 | 
			
		||||
msgstr "പ്രയോഗങ്ങളുടെ ഉപയോഗത്തെപ്പറ്റിയുള്ള സ്ഥിതിവിവരക്കണക്കുകള് ശേഖരിയ്ക്കണമോ എന്നു്"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:6
 | 
			
		||||
msgid ""
 | 
			
		||||
@@ -116,12 +113,9 @@ msgid ""
 | 
			
		||||
"want to disable this for privacy reasons. Please note that doing so won't "
 | 
			
		||||
"remove already saved data."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"ഏറ്റവും കൂടുതല് തവണ ഉപയോഗിയ്ക്കുന്ന പ്രയോഗങ്ങള് ലഭ്യമാക്കുന്നതിനായി ഷെല് "
 | 
			
		||||
"സാധാരണയായി സജീവമായ "
 | 
			
		||||
"പ്രയോഗങ്ങളെ നിരീക്ഷിയ്ക്കുന്നു. (ഉദാഹരണത്തിനു്, ലോഞ്ചേര്സ്). ഈ ഡേറ്റാ "
 | 
			
		||||
"സ്വകാര്യമായി "
 | 
			
		||||
"സൂക്ഷിയ്ക്കുന്നെങ്കിലും, ചില കാരണങ്ങളാല് ഇതു് പ്രവര്ത്തന "
 | 
			
		||||
"രഹിതമാക്കേണ്ടതുണ്ടു്. ഇങ്ങനെ ചെയ്യുന്നതു് "
 | 
			
		||||
"ഏറ്റവും കൂടുതല് തവണ ഉപയോഗിയ്ക്കുന്ന പ്രയോഗങ്ങള് ലഭ്യമാക്കുന്നതിനായി ഷെല് സാധാരണയായി സജീവമായ "
 | 
			
		||||
"പ്രയോഗങ്ങളെ നിരീക്ഷിയ്ക്കുന്നു. (ഉദാഹരണത്തിനു്, ലോഞ്ചേര്സ്). ഈ ഡേറ്റാ സ്വകാര്യമായി "
 | 
			
		||||
"സൂക്ഷിയ്ക്കുന്നെങ്കിലും, ചില കാരണങ്ങളാല് ഇതു് പ്രവര്ത്തന രഹിതമാക്കേണ്ടതുണ്ടു്. ഇങ്ങനെ ചെയ്യുന്നതു് "
 | 
			
		||||
"നിങ്ങള് സൂക്ഷിച്ച ഡേറ്റയെ ബാധിയ്ക്കുന്നതല്ല."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:7
 | 
			
		||||
@@ -132,8 +126,7 @@ msgstr "ഇഷ്ടമുള്ള പ്രയോഗങ്ങള്ക്
 | 
			
		||||
msgid ""
 | 
			
		||||
"The applications corresponding to these identifiers will be displayed in the "
 | 
			
		||||
"favorites area."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"ഈ ഐഡന്റിഫയറുകള്ക്കുള്ള പ്രയോഗങ്ങള് ഉചിതമായ സ്ഥലങ്ങളില് കാണിയ്ക്കുന്നു."
 | 
			
		||||
msgstr "ഈ ഐഡന്റിഫയറുകള്ക്കുള്ള പ്രയോഗങ്ങള് ഉചിതമായ സ്ഥലങ്ങളില് കാണിയ്ക്കുന്നു."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:9
 | 
			
		||||
msgid "List of categories that should be displayed as folders"
 | 
			
		||||
@@ -144,8 +137,8 @@ msgid ""
 | 
			
		||||
"Each category name in this list will be represented as folder in the "
 | 
			
		||||
"application view, rather than being displayed inline in the main view."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"ഈ പട്ടികയിലുള്ള ഓരോ വിഭാഗത്തിന്റെ പേരും, പ്രധാന കാഴ്ചയില് ഓരോ വരിയായി "
 | 
			
		||||
"കാണിയ്ക്കുന്നതിനു് പകരം പ്രയോഗങ്ങളുടെ കാഴ്ചയില് ഫോള്ഡറായി കാണിയ്ക്കുന്നു. "
 | 
			
		||||
"ഈ പട്ടികയിലുള്ള ഓരോ വിഭാഗത്തിന്റെ പേരും, പ്രധാന കാഴ്ചയില് ഓരോ വരിയായി കാണിയ്ക്കുന്നതിനു് "
 | 
			
		||||
"പകരം പ്രയോഗങ്ങളുടെ കാഴ്ചയില് ഫോള്ഡറായി കാണിയ്ക്കുന്നു. "
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:11
 | 
			
		||||
msgid "History for command (Alt-F2) dialog"
 | 
			
		||||
@@ -160,8 +153,7 @@ msgid ""
 | 
			
		||||
"Internally used to store the last IM presence explicitly set by the user. "
 | 
			
		||||
"The value here is from the TpConnectionPresenceType enumeration."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"ഉപയോക്താവു് സജ്ജമാക്കിയ അവസാന ഐഎം ആന്തരികമായി സൂക്ഷിയ്ക്കുന്നതിനു് "
 | 
			
		||||
"ഉപയോഗിയ്ക്കുന്നു. മൂല്യം "
 | 
			
		||||
"ഉപയോക്താവു് സജ്ജമാക്കിയ അവസാന ഐഎം ആന്തരികമായി സൂക്ഷിയ്ക്കുന്നതിനു് ഉപയോഗിയ്ക്കുന്നു. മൂല്യം "
 | 
			
		||||
"TpConnectionPresenceType തരത്തിലുള്ളതാകുന്നു."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
 | 
			
		||||
@@ -169,8 +161,7 @@ msgid ""
 | 
			
		||||
"Internally used to store the last session presence status for the user. The "
 | 
			
		||||
"value here is from the GsmPresenceStatus enumeration."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"ഉപയോക്താവിനുള്ള അവസാന സെഷന് അവസ്ഥ ആന്തരികമായി സൂക്ഷിയ്ക്കുന്നതിനു് "
 | 
			
		||||
"ഉപയോഗിയ്ക്കുന്നു. മൂല്യം "
 | 
			
		||||
"ഉപയോക്താവിനുള്ള അവസാന സെഷന് അവസ്ഥ ആന്തരികമായി സൂക്ഷിയ്ക്കുന്നതിനു് ഉപയോഗിയ്ക്കുന്നു. മൂല്യം "
 | 
			
		||||
"GsmPresenceStatus തരത്തിലുള്ളതാകുന്നു."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
 | 
			
		||||
@@ -182,15 +173,13 @@ msgid ""
 | 
			
		||||
"This key overrides the automatic hiding of the 'Log out' menuitem in single-"
 | 
			
		||||
"user, single-session situations."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"സിംഗിള് യൂസര്, സിംഗിള് സെഷനില് 'ലോഗൌട്ട്' മെനുവസ്തു അദൃശ്യമാക്കുന്നതിനായി "
 | 
			
		||||
"ഈ കീ ഉപയോഗിയ്ക്കുന്നു"
 | 
			
		||||
"സിംഗിള് യൂസര്, സിംഗിള് സെഷനില് 'ലോഗൌട്ട്' മെനുവസ്തു അദൃശ്യമാക്കുന്നതിനായി ഈ കീ ഉപയോഗിയ്ക്കുന്നു"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
 | 
			
		||||
msgid ""
 | 
			
		||||
"Whether to remember password for mounting encrypted or remote filesystems"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"എന്ക്രിപ്റ്റ് ചെയ്തതോ വിദൂരമോ ആയ ഫയല്സിസ്റ്റങ്ങള് മൌണ്ട് ചെയ്യുമ്പോഴുള്ള "
 | 
			
		||||
"രഹസ്യവാക്ക് ഓര്മ്മിക്കണോ എന്ന്"
 | 
			
		||||
"എന്ക്രിപ്റ്റ് ചെയ്തതോ വിദൂരമോ ആയ ഫയല്സിസ്റ്റങ്ങള് മൌണ്ട് ചെയ്യുമ്പോഴുള്ള രഹസ്യവാക്ക് ഓര്മ്മിക്കണോ എന്ന്"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
 | 
			
		||||
msgid ""
 | 
			
		||||
@@ -199,10 +188,9 @@ msgid ""
 | 
			
		||||
"'Remember Password' checkbox will be present. This key sets the default "
 | 
			
		||||
"state of the checkbox."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"ഒരു എന്ക്രിപ്റ്റ് ചെയ്ത ഡിവൈസ് അല്ലെങ്കില് വിദൂര ഫയല്സിസ്റ്റം മൌണ്ട് "
 | 
			
		||||
"ചെയ്യുമ്പോള് ഷെല് ഒരു രഹസ്യവാക്ക് ആവശ്യപ്പെടുന്നു. രഹസ്യവാക്ക് "
 | 
			
		||||
"സൂക്ഷിയ്ക്കുവാന് സാധ്യമെങ്കില്,  'രഹസ്യവാക്ക് ഓര്ത്തു്വയ്ക്കുക' "
 | 
			
		||||
"ചെക്ക്ബോക്സ് കാണാം. ഈ കീ ചെക്ക്ബോക്സിന്റെ സ്വതവേയുള്ള അവസ്ഥ സജ്ജമാക്കുന്നു."
 | 
			
		||||
"ഒരു എന്ക്രിപ്റ്റ് ചെയ്ത ഡിവൈസ് അല്ലെങ്കില് വിദൂര ഫയല്സിസ്റ്റം മൌണ്ട് ചെയ്യുമ്പോള് ഷെല് ഒരു രഹസ്യവാക്ക് "
 | 
			
		||||
"ആവശ്യപ്പെടുന്നു. രഹസ്യവാക്ക് സൂക്ഷിയ്ക്കുവാന് സാധ്യമെങ്കില്,  'രഹസ്യവാക്ക് ഓര്ത്തു്വയ്ക്കുക' ചെക്ക്ബോക്സ് "
 | 
			
		||||
"കാണാം. ഈ കീ ചെക്ക്ബോക്സിന്റെ സ്വതവേയുള്ള അവസ്ഥ സജ്ജമാക്കുന്നു."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
 | 
			
		||||
msgid "Show the week date in the calendar"
 | 
			
		||||
@@ -228,61 +216,65 @@ msgstr "\"പ്രയോഗങ്ങള് കാണിയ്ക്കുക
 | 
			
		||||
msgid ""
 | 
			
		||||
"Keybinding to open the \"Show Applications\" view of the Activities Overview."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"പ്രവര്ത്തികളുടെ അവലോകനത്തിന്റെ \"പ്രയോഗങ്ങള് കാണിയ്ക്കുക\" എന്ന കാഴ്ച "
 | 
			
		||||
"തുറക്കുന്നതിനുള്ള കീബൈന്ഡിങ്"
 | 
			
		||||
"പ്രവര്ത്തികളുടെ അവലോകനത്തിന്റെ \"പ്രയോഗങ്ങള് കാണിയ്ക്കുക\" എന്ന കാഴ്ച തുറക്കുന്നതിനുള്ള കീബൈന്ഡിങ്"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
 | 
			
		||||
msgid "Keybinding to open the overview"
 | 
			
		||||
msgstr "പൊതുവായ അവലോകനം  തുറക്കുന്നതിനുള്ള കീബൈന്ഡിങ്"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
 | 
			
		||||
msgid "Keybinding to open the Activities Overview."
 | 
			
		||||
msgstr "പ്രയോഗങ്ങളുടെ പൊതുവായ അവലോകനം എന്ന കാഴ്ച തുറക്കുന്നതിനുള്ള കീബൈന്ഡിങ്"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
 | 
			
		||||
msgid "Keybinding to toggle the visibility of the message tray"
 | 
			
		||||
msgstr "സന്ദേശ ട്രേയുടെ ദൃശ്യത ടൊഗ്ഗിള് ചെയ്യുന്നതിനുള്ള കീക്കൂട്ടം"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
 | 
			
		||||
msgid "Keybinding to toggle the visibility of the message tray."
 | 
			
		||||
msgstr "സന്ദേശ ട്രേയുടെ ദൃശ്യത ടൊഗ്ഗിള് ചെയ്യുന്നതിനുള്ള കീക്കൂട്ടം."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
 | 
			
		||||
msgid "Keybinding to focus the active notification"
 | 
			
		||||
msgstr "സജീവമായ അറിയിപ്പിനുള്ള കീബൈന്ഡിങ്"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
 | 
			
		||||
msgid "Keybinding to focus the active notification."
 | 
			
		||||
msgstr "സജീവമായ അറിയിപ്പിനുള്ള കീബൈന്ഡിങ്."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
 | 
			
		||||
msgid "Keybinding to toggle the screen recorder"
 | 
			
		||||
msgstr "സ്ക്രീന് റിക്കോര്ഡര് ടൊഗ്ഗിള് ചെയ്യുന്നതിനുള്ള കീക്കൂട്ടം"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:32
 | 
			
		||||
msgid "Keybinding to start/stop the builtin screen recorder."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"ബിള്ട്ടിന് സ്ക്രീന് റിക്കോര്ഡര് തുടങ്ങുവാന്/നിര്ത്തുന്നതിനുള്ള "
 | 
			
		||||
"കീക്കൂട്ടം."
 | 
			
		||||
msgstr "ബിള്ട്ടിന് സ്ക്രീന് റിക്കോര്ഡര് തുടങ്ങുവാന്/നിര്ത്തുന്നതിനുള്ള കീക്കൂട്ടം."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:33
 | 
			
		||||
msgid "Which keyboard to use"
 | 
			
		||||
msgstr "ഏതു് കീബോര്ഡ് ഉപയോഗിയ്ക്കണം"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:32
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:34
 | 
			
		||||
msgid "The type of keyboard to use."
 | 
			
		||||
msgstr "ഏതു് തരം കീബോര്ഡ് ഉപയോഗിയ്ക്കണം."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:33
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:35
 | 
			
		||||
msgid "Framerate used for recording screencasts."
 | 
			
		||||
msgstr "സ്ക്രീന്കാസ്റ്റുകള് റിക്കോര്ഡ് ചെയ്യുന്നതിനുള്ള ഫ്രെയിം റേറ്റ്."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:34
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:36
 | 
			
		||||
msgid ""
 | 
			
		||||
"The framerate of the resulting screencast recordered by GNOME Shell's "
 | 
			
		||||
"screencast recorder in frames-per-second."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"ഗ്നോം ഷെല്ലിന്റെ സ്ക്രീന്കാസ്റ്റ് റിക്കോര്ഡര് റീക്കോര്ഡ് ചെയ്തിട്ടുള്ള "
 | 
			
		||||
"സ്ക്രീന്കാസ്റ്റിന്റെ "
 | 
			
		||||
"ഗ്നോം ഷെല്ലിന്റെ സ്ക്രീന്കാസ്റ്റ് റിക്കോര്ഡര് റീക്കോര്ഡ് ചെയ്തിട്ടുള്ള സ്ക്രീന്കാസ്റ്റിന്റെ "
 | 
			
		||||
"ഫ്രെയിംറേറ്റ്, ഒരു സെക്കന്ഡില് ഒരു ഫ്രെയിം."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:35
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:37
 | 
			
		||||
msgid "The gstreamer pipeline used to encode the screencast"
 | 
			
		||||
msgstr "സ്ക്രീന്കാസ്റ്റ് എന്കോഡ് ചെയ്യുന്നതിനുള്ള gstreamer പൈപ്പ്ലൈന്"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:37
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:39
 | 
			
		||||
#, no-c-format
 | 
			
		||||
msgid ""
 | 
			
		||||
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
 | 
			
		||||
@@ -296,78 +288,68 @@ msgid ""
 | 
			
		||||
"threads=%T ! queue ! webmmux' and records to WEBM using the VP8 codec. %T is "
 | 
			
		||||
"used as a placeholder for a guess at the optimal thread count on the system."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"റിക്കോര്ഡിങുകള് എന്കോഡ് ചെയ്യുന്നതിനായി GStreamer പൈപ്പ് ലൈന് "
 | 
			
		||||
"ഉപയോഗിയ്ക്കുന്നു. gst-launch-"
 | 
			
		||||
"നുള്ള സിന്റാക്സ് ഉപയോഗിയ്ക്കുന്നു. കാലിയായി സജ്ജമാക്കുമ്പോള് "
 | 
			
		||||
"കാലിയാകുന്നു.ഇതു് നിലവില് 'vp8enc "
 | 
			
		||||
"റിക്കോര്ഡിങുകള് എന്കോഡ് ചെയ്യുന്നതിനായി GStreamer പൈപ്പ് ലൈന് ഉപയോഗിയ്ക്കുന്നു. gst-launch-"
 | 
			
		||||
"നുള്ള സിന്റാക്സ് ഉപയോഗിയ്ക്കുന്നു. കാലിയായി സജ്ജമാക്കുമ്പോള് കാലിയാകുന്നു.ഇതു് നിലവില് 'vp8enc "
 | 
			
		||||
"min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! "
 | 
			
		||||
"queue ! webmmux' ആകുന്നുസ WEBM VP8 കോഡ് ഉപയോഗിച്ചു് റിക്കോര്ഡ് ചെയ്യുന്നു."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:38
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:40
 | 
			
		||||
msgid "File extension used for storing the screencast"
 | 
			
		||||
msgstr "സ്ക്രീന്കാസ്റ്റ് സൂക്ഷിയ്ക്കുന്നതിനുള്ള ഫയല് എക്സ്റ്റെന്ഷന്"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:39
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:41
 | 
			
		||||
msgid ""
 | 
			
		||||
"The filename for recorded screencasts will be a unique filename based on the "
 | 
			
		||||
"current date, and use this extension. It should be changed when recording to "
 | 
			
		||||
"a different container format."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"റിക്കോര്ഡ് ചെയ്ത സ്ക്രീന്കാസ്റ്റുകള്ക്കുള്ള ഫയല്നാമം നിലവിലുള്ള തീയതി, "
 | 
			
		||||
"എക്സ്റ്റെന്ഷന് എന്നിവ "
 | 
			
		||||
"അനുസരിച്ചാകുന്നു. മറ്റൊരു ശൈലിയിലേക്കു് റിക്കോര്ഡ് ചെയ്യുമ്പോള് ഇതു് "
 | 
			
		||||
"മാറ്റണം."
 | 
			
		||||
"റിക്കോര്ഡ് ചെയ്ത സ്ക്രീന്കാസ്റ്റുകള്ക്കുള്ള ഫയല്നാമം നിലവിലുള്ള തീയതി, എക്സ്റ്റെന്ഷന് എന്നിവ "
 | 
			
		||||
"അനുസരിച്ചാകുന്നു. മറ്റൊരു ശൈലിയിലേക്കു് റിക്കോര്ഡ് ചെയ്യുമ്പോള് ഇതു് മാറ്റണം."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:40
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:42
 | 
			
		||||
msgid "The application icon mode."
 | 
			
		||||
msgstr "പ്രയോഗത്തിന്റെ ഐക്കണ് മോഡ്."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:41
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:43
 | 
			
		||||
msgid ""
 | 
			
		||||
"Configures how the windows are shown in the switcher. Valid possibilities "
 | 
			
		||||
"are 'thumbnail-only' (shows a thumbnail of the window), 'app-icon-"
 | 
			
		||||
"only' (shows only the application icon) or 'both'."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"സ്വിച്ചറില് ജാലകങ്ങള് എങ്ങനെ കാണിയ്ക്കുന്നു എന്നു് ക്രമീകരിയ്ക്കുന്നു. "
 | 
			
		||||
"ശരിയായ "
 | 
			
		||||
"സാധ്യതകള്: 'thumbnail-only' (ജാലകത്തിന്റെ പ്രതിരൂപം കാണിയ്ക്കുന്നു), "
 | 
			
		||||
"'app-icon-"
 | 
			
		||||
"സ്വിച്ചറില് ജാലകങ്ങള് എങ്ങനെ കാണിയ്ക്കുന്നു എന്നു് ക്രമീകരിയ്ക്കുന്നു. ശരിയായ സാധ്യതകള്: "
 | 
			
		||||
"'thumbnail-only' (ജാലകത്തിന്റെ പ്രതിരൂപം കാണിയ്ക്കുന്നു), 'app-icon-"
 | 
			
		||||
"only' (പ്രയോഗത്തിന്റെ പ്രതിരൂപം കാണിയ്ക്കുന്നു) അല്ലെങ്കില് 'both'."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:42
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:44
 | 
			
		||||
msgid "Attach modal dialog to the parent window"
 | 
			
		||||
msgstr "പേരന്റ് ജാലകത്തിലേക്കു് ഡയലോഗ് ചേര്ക്കുക"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:43
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:45
 | 
			
		||||
msgid ""
 | 
			
		||||
"This key overrides the key in org.gnome.mutter when running GNOME Shell."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"ഗ്നോം ഷെല് പ്രവര്ത്തിയ്ക്കുമ്പോള് org.gnome.mutter-ലുള്ള കീ ഈ കീ "
 | 
			
		||||
"തിരുത്തിയെഴുതുന്നു."
 | 
			
		||||
msgstr "ഗ്നോം ഷെല് പ്രവര്ത്തിയ്ക്കുമ്പോള് org.gnome.mutter-ലുള്ള കീ ഈ കീ തിരുത്തിയെഴുതുന്നു."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:44
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:46
 | 
			
		||||
msgid "Arrangement of buttons on the titlebar"
 | 
			
		||||
msgstr "തലക്കെട്ടിനുള്ള ബാറില് ബട്ടണുകളുടെ ക്രമീകരണം"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:45
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:47
 | 
			
		||||
msgid ""
 | 
			
		||||
"This key overrides the key in org.gnome.desktop.wm.preferences when running "
 | 
			
		||||
"GNOME Shell."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"ഗ്നോം ഷെല് പ്രവര്ത്തിയ്ക്കുമ്പോള് org.gnome.desktop.wm.preferences-ലുള്ള "
 | 
			
		||||
"കീ ഈ കീ തിരുത്തിയെഴുതുന്നു."
 | 
			
		||||
"ഗ്നോം ഷെല് പ്രവര്ത്തിയ്ക്കുമ്പോള് org.gnome.desktop.wm.preferences-ലുള്ള കീ ഈ കീ "
 | 
			
		||||
"തിരുത്തിയെഴുതുന്നു."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:46
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:48
 | 
			
		||||
msgid "Enable edge tiling when dropping windows on screen edges"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"സ്ക്രീന് കോണുകളില് ജാലകങ്ങള് എത്തിയ്ക്കുമ്പോള് കോണ് ചരിയ്ക്കുന്നതിനായി "
 | 
			
		||||
"പ്രവര്ത്തന സജ്ജമാക്കുക"
 | 
			
		||||
msgstr "സ്ക്രീന് കോണുകളില് ജാലകങ്ങള് എത്തിയ്ക്കുമ്പോള് കോണ് ചരിയ്ക്കുന്നതിനായി പ്രവര്ത്തന സജ്ജമാക്കുക"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:47
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:49
 | 
			
		||||
msgid "Workspaces are managed dynamically"
 | 
			
		||||
msgstr "പണിയിടങ്ങള് ഡയനാമിക്കായി കൈകാര്യം ചെയ്തിരിക്കുന്നു"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:48
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:50
 | 
			
		||||
msgid "Workspaces only on primary monitor"
 | 
			
		||||
msgstr "പ്രധാന മോണിറ്ററില് മാത്രം പണിയിടങ്ങള്"
 | 
			
		||||
 | 
			
		||||
@@ -382,12 +364,9 @@ msgstr "എക്സ്റ്റെന്ഷന്"
 | 
			
		||||
 | 
			
		||||
#: ../js/extensionPrefs/main.js:189
 | 
			
		||||
msgid "Select an extension to configure using the combobox above."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"മുകളിലുള്ള കോമ്പോ ബോക്സ് ഉപയോഗിച്ചു് ക്രമീകരിയ്ക്കുന്നതിനുള്ളൊരു "
 | 
			
		||||
"എക്സ്റ്റെന്ഷന് തെരഞ്ഞെടുക്കുക."
 | 
			
		||||
msgstr "മുകളിലുള്ള കോമ്പോ ബോക്സ് ഉപയോഗിച്ചു് ക്രമീകരിയ്ക്കുന്നതിനുള്ളൊരു എക്സ്റ്റെന്ഷന് തെരഞ്ഞെടുക്കുക."
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:405
 | 
			
		||||
#| msgid "Session..."
 | 
			
		||||
msgid "Session…"
 | 
			
		||||
msgstr "പ്രവര്ത്തനവേള..."
 | 
			
		||||
 | 
			
		||||
@@ -398,32 +377,32 @@ msgstr "പ്രവര്ത്തനവേള..."
 | 
			
		||||
msgid "Not listed?"
 | 
			
		||||
msgstr "ലഭ്യമല്ലേ?"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:786 ../js/ui/components/networkAgent.js:137
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:375
 | 
			
		||||
#: ../js/gdm/loginDialog.js:787 ../js/ui/components/networkAgent.js:137
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:376
 | 
			
		||||
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:399
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:99
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:100
 | 
			
		||||
#: ../js/ui/userMenu.js:938
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "വേണ്ട"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:802
 | 
			
		||||
#: ../js/gdm/loginDialog.js:803
 | 
			
		||||
msgctxt "button"
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr "അകത്തുകയറുക"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:802
 | 
			
		||||
#: ../js/gdm/loginDialog.js:803
 | 
			
		||||
msgid "Next"
 | 
			
		||||
msgstr "അടുത്തത്"
 | 
			
		||||
 | 
			
		||||
#. TTLS and PEAP are actually much more complicated, but this complication
 | 
			
		||||
#. is not visible here since we only care about phase2 authentication
 | 
			
		||||
#. (and don't even care of which one)
 | 
			
		||||
#: ../js/gdm/loginDialog.js:917 ../js/ui/components/networkAgent.js:260
 | 
			
		||||
#: ../js/gdm/loginDialog.js:918 ../js/ui/components/networkAgent.js:260
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:278
 | 
			
		||||
msgid "Username: "
 | 
			
		||||
msgstr "ഉപയോക്തൃ നാമം: "
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:1173
 | 
			
		||||
#: ../js/gdm/loginDialog.js:1174
 | 
			
		||||
msgid "Login Window"
 | 
			
		||||
msgstr "പ്രവേശന ജാലകം"
 | 
			
		||||
 | 
			
		||||
@@ -476,23 +455,23 @@ msgstr "ആജ്ഞ പ്രാവര്ത്തികമാക്കാ
 | 
			
		||||
msgid "Execution of '%s' failed:"
 | 
			
		||||
msgstr "'%s' നടപ്പിലാക്കുന്നതില് പരാജയപ്പെട്ടു:"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:349
 | 
			
		||||
#: ../js/ui/appDisplay.js:351
 | 
			
		||||
msgid "Frequent"
 | 
			
		||||
msgstr "ഇടയ്ക്കിടെ"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:356
 | 
			
		||||
#: ../js/ui/appDisplay.js:358
 | 
			
		||||
msgid "All"
 | 
			
		||||
msgstr "എല്ലാം"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:914
 | 
			
		||||
#: ../js/ui/appDisplay.js:916
 | 
			
		||||
msgid "New Window"
 | 
			
		||||
msgstr "പുതിയ വിന്ഡോ"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:917 ../js/ui/dash.js:284
 | 
			
		||||
#: ../js/ui/appDisplay.js:919 ../js/ui/dash.js:284
 | 
			
		||||
msgid "Remove from Favorites"
 | 
			
		||||
msgstr "ഇഷ്ടപ്പെട്ടവയില് നിന്നും നീക്കം ചെയ്യുക"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:918
 | 
			
		||||
#: ../js/ui/appDisplay.js:920
 | 
			
		||||
msgid "Add to Favorites"
 | 
			
		||||
msgstr "ഇഷ്ടപ്പെട്ടവയിലേക്ക് ചേര്ക്കുക"
 | 
			
		||||
 | 
			
		||||
@@ -529,7 +508,7 @@ msgctxt "event list time"
 | 
			
		||||
msgid "%H\\u2236%M"
 | 
			
		||||
msgstr "%H\\u2236%M"
 | 
			
		||||
 | 
			
		||||
#. Transators: Shown in calendar event list, if 12h format,
 | 
			
		||||
#. Translators: Shown in calendar event list, if 12h format,
 | 
			
		||||
#. \u2236 is a ratio character, similar to : and \u2009 is
 | 
			
		||||
#. a thin space
 | 
			
		||||
#: ../js/ui/calendar.js:77
 | 
			
		||||
@@ -732,8 +711,7 @@ msgid ""
 | 
			
		||||
"Passwords or encryption keys are required to access the wireless network "
 | 
			
		||||
"'%s'."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"വയര്ലെസ് നെറ്റ്വര്ക്ക് '%s'-ലേക്ക് പ്രവേശിക്കുന്നതിനായി രഹസ്യവാക്കുകള് "
 | 
			
		||||
"അല്ലെങ്കില് എന്ക്രിപ്ഷന് കീകള് "
 | 
			
		||||
"വയര്ലെസ് നെറ്റ്വര്ക്ക് '%s'-ലേക്ക് പ്രവേശിക്കുന്നതിനായി രഹസ്യവാക്കുകള് അല്ലെങ്കില് എന്ക്രിപ്ഷന് കീകള് "
 | 
			
		||||
"ആവശ്യമുണ്ടു്."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:314
 | 
			
		||||
@@ -790,7 +768,7 @@ msgid "Sorry, that didn't work. Please try again."
 | 
			
		||||
msgstr "ക്ഷമിക്കണം, അതു ശരിയല്ല. ദയവായി വീണ്ടും ശ്രമിക്കുക."
 | 
			
		||||
 | 
			
		||||
#. Translators: this is a filename used for screencast recording
 | 
			
		||||
#: ../js/ui/components/recorder.js:48
 | 
			
		||||
#: ../js/ui/components/recorder.js:47
 | 
			
		||||
#, no-c-format
 | 
			
		||||
msgid "Screencast from %d %t"
 | 
			
		||||
msgstr "%d-ല് നിന്നുള്ള സ്ക്രീന്കാസ്റ്റ്, %t-ല്"
 | 
			
		||||
@@ -913,8 +891,7 @@ msgstr "%s നിങ്ങള്ക്കു് %s അയച്ചിരി
 | 
			
		||||
#: ../js/ui/components/telepathyClient.js:1206
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%s would like permission to see when you are online"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"നിങ്ങള് ഓണ്ലൈന് ആകുമ്പോള് കാണുന്നതിനുള്ള അനുമതി %s-നു് ആവശ്യമുണ്ടു്"
 | 
			
		||||
msgstr "നിങ്ങള് ഓണ്ലൈന് ആകുമ്പോള് കാണുന്നതിനുള്ള അനുമതി %s-നു് ആവശ്യമുണ്ടു്"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/telepathyClient.js:1298
 | 
			
		||||
msgid "Network error"
 | 
			
		||||
@@ -987,9 +964,7 @@ msgstr "ഈ അക്കൌണ്ട് നിലവില് സര്വ
 | 
			
		||||
#: ../js/ui/components/telepathyClient.js:1332
 | 
			
		||||
msgid ""
 | 
			
		||||
"Connection has been replaced by a new connection using the same resource"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"അതേ ശ്രോതസ്സ് ഉപയോഗിച്ചു് ഒരു പുതിയ കണക്ഷന് ഉപയോഗിച്ചു് ഈ കണക്ഷന് "
 | 
			
		||||
"മാറ്റിസ്ഥാപിയ്ക്കുന്നു"
 | 
			
		||||
msgstr "അതേ ശ്രോതസ്സ് ഉപയോഗിച്ചു് ഒരു പുതിയ കണക്ഷന് ഉപയോഗിച്ചു് ഈ കണക്ഷന് മാറ്റിസ്ഥാപിയ്ക്കുന്നു"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/telepathyClient.js:1334
 | 
			
		||||
msgid "The account already exists on the server"
 | 
			
		||||
@@ -1006,17 +981,14 @@ msgstr "സമ്മതപത്രം വീണ്ടും ആവശ്യപ
 | 
			
		||||
#: ../js/ui/components/telepathyClient.js:1340
 | 
			
		||||
msgid ""
 | 
			
		||||
"Certificate uses an insecure cipher algorithm or is cryptographically weak"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"സമ്മതപത്രം സുരക്ഷിതമല്ലാത്തൊരു സിഫര് ആല്ഗോരിഥം ഉപയോഗിയ്ക്കുന്നു "
 | 
			
		||||
"അല്ലെങ്കില് ഉചിതമല്ല"
 | 
			
		||||
msgstr "സമ്മതപത്രം സുരക്ഷിതമല്ലാത്തൊരു സിഫര് ആല്ഗോരിഥം ഉപയോഗിയ്ക്കുന്നു അല്ലെങ്കില് ഉചിതമല്ല"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/telepathyClient.js:1342
 | 
			
		||||
msgid ""
 | 
			
		||||
"The length of the server certificate, or the depth of the server certificate "
 | 
			
		||||
"chain, exceed the limits imposed by the cryptography library"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"സര്വറിന്റെ സമ്മതപത്രത്തിന്റെ വ്യാപ്തി, അല്ലെങ്കില് സര്വര് സമ്മതപത്ര "
 | 
			
		||||
"ചെയിന്റെ വ്യാപ്തി, എന്നിവ "
 | 
			
		||||
"സര്വറിന്റെ സമ്മതപത്രത്തിന്റെ വ്യാപ്തി, അല്ലെങ്കില് സര്വര് സമ്മതപത്ര ചെയിന്റെ വ്യാപ്തി, എന്നിവ "
 | 
			
		||||
"പരിധിയില് കൂടുന്നു"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/telepathyClient.js:1344
 | 
			
		||||
@@ -1085,8 +1057,7 @@ msgstr "പുറത്ത് കടക്കുക"
 | 
			
		||||
#: ../js/ui/endSessionDialog.js:65
 | 
			
		||||
msgid "Click Log Out to quit these applications and log out of the system."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"ഈ പ്രയോഗങ്ങളില് നിന്നും പുറത്തു് കടക്കുന്നതിനായി പുറത്തു കടക്കുക ക്ലിക്ക് "
 | 
			
		||||
"ചെയ്തു് സിസ്റ്റത്തില് നിന്നും "
 | 
			
		||||
"ഈ പ്രയോഗങ്ങളില് നിന്നും പുറത്തു് കടക്കുന്നതിനായി പുറത്തു കടക്കുക ക്ലിക്ക് ചെയ്തു് സിസ്റ്റത്തില് നിന്നും "
 | 
			
		||||
"പുറത്തു് കടക്കുക."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/endSessionDialog.js:67
 | 
			
		||||
@@ -1120,8 +1091,7 @@ msgstr "നിര്ത്തുക"
 | 
			
		||||
#: ../js/ui/endSessionDialog.js:84
 | 
			
		||||
msgid "Click Power Off to quit these applications and power off the system."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"ഈ പ്രയോഗങ്ങളില് നിന്നും പുറത്തു് കടക്കുന്നതിനായി പവര് ഓഫ് ചെയ്യുക ക്ലിക്ക് "
 | 
			
		||||
"ചെയ്തു സിസ്റ്റിന്റെ പവര് "
 | 
			
		||||
"ഈ പ്രയോഗങ്ങളില് നിന്നും പുറത്തു് കടക്കുന്നതിനായി പവര് ഓഫ് ചെയ്യുക ക്ലിക്ക് ചെയ്തു സിസ്റ്റിന്റെ പവര് "
 | 
			
		||||
"ഓഫ് ചെയ്യുക."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/endSessionDialog.js:86
 | 
			
		||||
@@ -1152,8 +1122,7 @@ msgstr "പുനരാരംഭിക്കുക"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/endSessionDialog.js:101
 | 
			
		||||
msgid "Click Restart to quit these applications and restart the system."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"ഈ പ്രയോഗങ്ങള് നിറുത്തി സിസ്റ്റം പുനരാരംഭിക്കുവാന് പുനരാരംഭിക്കൂ അമര്ത്തുക"
 | 
			
		||||
msgstr "ഈ പ്രയോഗങ്ങള് നിറുത്തി സിസ്റ്റം പുനരാരംഭിക്കുവാന് പുനരാരംഭിക്കൂ അമര്ത്തുക"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/endSessionDialog.js:103
 | 
			
		||||
#, c-format
 | 
			
		||||
@@ -1173,9 +1142,7 @@ msgstr "ഇന്സ്റ്റോള്"
 | 
			
		||||
#: ../js/ui/extensionDownloader.js:204
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Download and install '%s' from extensions.gnome.org?"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"extensions.gnome.org ഇല് നിന്നും '%s' ഡൗണ്ലോട് ചെയ്ത് ഇന്സ്റ്റോള് "
 | 
			
		||||
"ചെയ്യേണമോ?"
 | 
			
		||||
msgstr "extensions.gnome.org ഇല് നിന്നും '%s' ഡൗണ്ലോട് ചെയ്ത് ഇന്സ്റ്റോള് ചെയ്യേണമോ?"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/keyboard.js:619 ../js/ui/status/keyboard.js:314
 | 
			
		||||
#: ../js/ui/status/power.js:211
 | 
			
		||||
@@ -1204,7 +1171,9 @@ msgstr "പിശകുകള് കാണിക്കുക"
 | 
			
		||||
msgid "Enabled"
 | 
			
		||||
msgstr "പ്രവര്ത്തനക്ഷമമാക്കി"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:769
 | 
			
		||||
#. translators:
 | 
			
		||||
#. * The device has been disabled
 | 
			
		||||
#: ../js/ui/lookingGlass.js:769 ../src/gvc/gvc-mixer-control.c:1830
 | 
			
		||||
msgid "Disabled"
 | 
			
		||||
msgstr "പ്രവര്ത്തനരഹിതമാക്കി"
 | 
			
		||||
 | 
			
		||||
@@ -1237,7 +1206,6 @@ msgid "Remove"
 | 
			
		||||
msgstr "നീക്കം ചെയ്യുക"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:1501
 | 
			
		||||
#| msgid "No Messages"
 | 
			
		||||
msgid "Clear Messages"
 | 
			
		||||
msgstr "സന്ദേശങ്ങള് വെടിപ്പാക്കുക"
 | 
			
		||||
 | 
			
		||||
@@ -1245,35 +1213,35 @@ msgstr "സന്ദേശങ്ങള് വെടിപ്പാക്ക
 | 
			
		||||
msgid "Notification Settings"
 | 
			
		||||
msgstr "അറിയിപ്പു് ക്രമീകരണങ്ങള്"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:1709
 | 
			
		||||
#: ../js/ui/messageTray.js:1710
 | 
			
		||||
msgid "No Messages"
 | 
			
		||||
msgstr "സന്ദേശങ്ങളില്ല"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:1782
 | 
			
		||||
#: ../js/ui/messageTray.js:1783
 | 
			
		||||
msgid "Message Tray"
 | 
			
		||||
msgstr "സന്ദേശത്തിന്റെ ട്രേ"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:2810
 | 
			
		||||
#: ../js/ui/messageTray.js:2801
 | 
			
		||||
msgid "System Information"
 | 
			
		||||
msgstr "സിസ്റ്റത്തെക്കുറിച്ചുള്ള വിവരം"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/notificationDaemon.js:629 ../src/shell-app.c:374
 | 
			
		||||
#: ../js/ui/notificationDaemon.js:629 ../src/shell-app.c:378
 | 
			
		||||
msgctxt "program"
 | 
			
		||||
msgid "Unknown"
 | 
			
		||||
msgstr "അജ്ഞാതം"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/overviewControls.js:463 ../js/ui/screenShield.js:149
 | 
			
		||||
#: ../js/ui/overviewControls.js:472 ../js/ui/screenShield.js:149
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%d new message"
 | 
			
		||||
msgid_plural "%d new messages"
 | 
			
		||||
msgstr[0] "%d പുതിയ സന്ദേശം"
 | 
			
		||||
msgstr[1] "%d പുതിയ സന്ദേശങ്ങള്"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/overview.js:84
 | 
			
		||||
#: ../js/ui/overview.js:82
 | 
			
		||||
msgid "Undo"
 | 
			
		||||
msgstr "വേണ്ട"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/overview.js:129
 | 
			
		||||
#: ../js/ui/overview.js:127
 | 
			
		||||
msgid "Overview"
 | 
			
		||||
msgstr "അവലോകനം"
 | 
			
		||||
 | 
			
		||||
@@ -1281,22 +1249,21 @@ msgstr "അവലോകനം"
 | 
			
		||||
#. in the search entry when no search is
 | 
			
		||||
#. active; it should not exceed ~30
 | 
			
		||||
#. characters.
 | 
			
		||||
#: ../js/ui/overview.js:271
 | 
			
		||||
#| msgid "Type to search..."
 | 
			
		||||
#: ../js/ui/overview.js:260
 | 
			
		||||
msgid "Type to search…"
 | 
			
		||||
msgstr "തെരയുന്നതിനായി ടൈപ്പ് ചെയ്യുക..."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/panel.js:612
 | 
			
		||||
#: ../js/ui/panel.js:641
 | 
			
		||||
msgid "Quit"
 | 
			
		||||
msgstr "നിര്ത്തുക"
 | 
			
		||||
 | 
			
		||||
#. Translators: If there is no suitable word for "Activities"
 | 
			
		||||
#. in your language, you can use the word for "Overview".
 | 
			
		||||
#: ../js/ui/panel.js:636
 | 
			
		||||
#: ../js/ui/panel.js:692
 | 
			
		||||
msgid "Activities"
 | 
			
		||||
msgstr "പ്രവര്ത്തനങ്ങള്"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/panel.js:933
 | 
			
		||||
#: ../js/ui/panel.js:989
 | 
			
		||||
msgid "Top Bar"
 | 
			
		||||
msgstr "മുകളിലുള്ള ബാര്"
 | 
			
		||||
 | 
			
		||||
@@ -1305,15 +1272,15 @@ msgstr "മുകളിലുള്ള ബാര്"
 | 
			
		||||
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
 | 
			
		||||
#. switches containing "◯" and "|"). Other values will
 | 
			
		||||
#. simply result in invisible toggle switches.
 | 
			
		||||
#: ../js/ui/popupMenu.js:727
 | 
			
		||||
#: ../js/ui/popupMenu.js:718
 | 
			
		||||
msgid "toggle-switch-us"
 | 
			
		||||
msgstr "toggle-switch-us"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/runDialog.js:73
 | 
			
		||||
#: ../js/ui/runDialog.js:74
 | 
			
		||||
msgid "Enter a Command"
 | 
			
		||||
msgstr "ഒരു കമാന്ഡ് നല്കുക"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/runDialog.js:109
 | 
			
		||||
#: ../js/ui/runDialog.js:110
 | 
			
		||||
msgid "Close"
 | 
			
		||||
msgstr "അടക്കുക"
 | 
			
		||||
 | 
			
		||||
@@ -1334,7 +1301,7 @@ msgstr[1] "%d പുതിയ അറിയിപ്പുകള്"
 | 
			
		||||
msgid "Lock"
 | 
			
		||||
msgstr "പൂട്ടുക"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:637
 | 
			
		||||
#: ../js/ui/screenShield.js:641
 | 
			
		||||
msgid "GNOME needs to lock the screen"
 | 
			
		||||
msgstr "ഗ്നോമിന് സ്ക്രീന് പൂട്ടണം"
 | 
			
		||||
 | 
			
		||||
@@ -1345,17 +1312,15 @@ msgstr "ഗ്നോമിന് സ്ക്രീന് പൂട്ടണ
 | 
			
		||||
#.
 | 
			
		||||
#. XXX: another option is to kick the user into the gdm login
 | 
			
		||||
#. screen, where we're not affected by grabs
 | 
			
		||||
#: ../js/ui/screenShield.js:758 ../js/ui/screenShield.js:1194
 | 
			
		||||
#| msgid "Unable to connect to %s"
 | 
			
		||||
#: ../js/ui/screenShield.js:762 ../js/ui/screenShield.js:1198
 | 
			
		||||
msgid "Unable to lock"
 | 
			
		||||
msgstr "പൂട്ടുവാന് സാധ്യമല്ല"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:759 ../js/ui/screenShield.js:1195
 | 
			
		||||
#: ../js/ui/screenShield.js:763 ../js/ui/screenShield.js:1199
 | 
			
		||||
msgid "Lock was blocked by an application"
 | 
			
		||||
msgstr "പൂട്ടുന്ന സംവിധാനം ഒരു പ്രയോഗം തടസ്സപ്പെടുത്തിയിരിയ്ക്കുന്നു"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/searchDisplay.js:453
 | 
			
		||||
#| msgid "Searching..."
 | 
			
		||||
msgid "Searching…"
 | 
			
		||||
msgstr "തെരയുന്നു..."
 | 
			
		||||
 | 
			
		||||
@@ -1371,11 +1336,11 @@ msgstr "പകര്ത്തുക"
 | 
			
		||||
msgid "Paste"
 | 
			
		||||
msgstr "ഒട്ടിയ്ക്കുക"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellEntry.js:106
 | 
			
		||||
#: ../js/ui/shellEntry.js:101
 | 
			
		||||
msgid "Show Text"
 | 
			
		||||
msgstr "പദാവലി കാണിക്കുക"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellEntry.js:108
 | 
			
		||||
#: ../js/ui/shellEntry.js:103
 | 
			
		||||
msgid "Hide Text"
 | 
			
		||||
msgstr "പദാവലി മറക്കുക"
 | 
			
		||||
 | 
			
		||||
@@ -1387,7 +1352,7 @@ msgstr "രഹസ്യവാക്ക്"
 | 
			
		||||
msgid "Remember Password"
 | 
			
		||||
msgstr "രഹസ്യവാക്ക് ഓര്ത്തു് വയ്ക്കുക"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:113
 | 
			
		||||
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:114
 | 
			
		||||
msgid "Unlock"
 | 
			
		||||
msgstr "പൂട്ട് തുറക്കുക"
 | 
			
		||||
 | 
			
		||||
@@ -1451,12 +1416,10 @@ msgid "Visibility"
 | 
			
		||||
msgstr "കാഴ്ച"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:59
 | 
			
		||||
#| msgid "Send Files to Device..."
 | 
			
		||||
msgid "Send Files to Device…"
 | 
			
		||||
msgstr "ഡിവൈസിലേക്കു് ഫയലുകള് അയയ്ക്കുക..."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:60
 | 
			
		||||
#| msgid "Set Up a New Device..."
 | 
			
		||||
msgid "Set Up a New Device…"
 | 
			
		||||
msgstr "പുതിയൊരു ഡിവൈസ് സജ്ജമാക്കുക..."
 | 
			
		||||
 | 
			
		||||
@@ -1483,7 +1446,6 @@ msgid "connecting..."
 | 
			
		||||
msgstr "ബന്ധിപ്പിയ്ക്കുന്നു...."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:239
 | 
			
		||||
#| msgid "Send Files..."
 | 
			
		||||
msgid "Send Files…"
 | 
			
		||||
msgstr "ഫയലുകള് അയയ്ക്കുക..."
 | 
			
		||||
 | 
			
		||||
@@ -1696,7 +1658,6 @@ msgstr "ഊര്ജ്ജ ക്രമീകരണങ്ങള്"
 | 
			
		||||
#. 0 is reported when UPower does not have enough data
 | 
			
		||||
#. to estimate battery life
 | 
			
		||||
#: ../js/ui/status/power.js:99
 | 
			
		||||
#| msgid "Estimating..."
 | 
			
		||||
msgid "Estimating…"
 | 
			
		||||
msgstr "കണക്കുകൂട്ടുന്നു..."
 | 
			
		||||
 | 
			
		||||
@@ -1796,11 +1757,11 @@ msgstr "ഒച്ച"
 | 
			
		||||
msgid "Microphone"
 | 
			
		||||
msgstr "മൈക്രോഫോണ്"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/unlockDialog.js:124
 | 
			
		||||
#: ../js/ui/unlockDialog.js:125
 | 
			
		||||
msgid "Log in as another user"
 | 
			
		||||
msgstr "മറ്റൊരു ഉപയോക്താവായി പ്രവേശിയ്ക്കുക"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/unlockDialog.js:145
 | 
			
		||||
#: ../js/ui/unlockDialog.js:146
 | 
			
		||||
msgid "Unlock Window"
 | 
			
		||||
msgstr "ജാലകത്തിന്റെ പൂട്ടു തുറക്കുക"
 | 
			
		||||
 | 
			
		||||
@@ -1853,10 +1814,8 @@ msgid ""
 | 
			
		||||
"Notifications are now disabled, including chat messages. Your online status "
 | 
			
		||||
"has been adjusted to let others know that you might not see their messages."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"ചാറ്റ് സന്ദേശങ്ങള് എന്ന പോലെ അറിയിപ്പുകള് പ്രവര്ത്തന രഹിതമാക്കുന്നു. "
 | 
			
		||||
"മറ്റുള്ളവരുടെ ചാറ്റ് സന്ദേശങ്ങള് "
 | 
			
		||||
"നിങ്ങള്ക്കു് കാണുവാന് സാധ്യമല്ല എന്നു് നിങ്ങളുടെ ഓണ്ലൈന് അവസ്ഥയില് "
 | 
			
		||||
"വ്യക്തമാക്കുന്നു."
 | 
			
		||||
"ചാറ്റ് സന്ദേശങ്ങള് എന്ന പോലെ അറിയിപ്പുകള് പ്രവര്ത്തന രഹിതമാക്കുന്നു. മറ്റുള്ളവരുടെ ചാറ്റ് സന്ദേശങ്ങള് "
 | 
			
		||||
"നിങ്ങള്ക്കു് കാണുവാന് സാധ്യമല്ല എന്നു് നിങ്ങളുടെ ഓണ്ലൈന് അവസ്ഥയില് വ്യക്തമാക്കുന്നു."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/userMenu.js:888
 | 
			
		||||
msgid "Other users are logged in."
 | 
			
		||||
@@ -1909,6 +1868,28 @@ msgstr "'%s' തയ്യാറാണ്"
 | 
			
		||||
msgid "Evolution Calendar"
 | 
			
		||||
msgstr "ഇവല്യൂഷന് കലണ്ടര്"
 | 
			
		||||
 | 
			
		||||
#. translators:
 | 
			
		||||
#. * The number of sound outputs on a particular device
 | 
			
		||||
#: ../src/gvc/gvc-mixer-control.c:1837
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%u Output"
 | 
			
		||||
msgid_plural "%u Outputs"
 | 
			
		||||
msgstr[0] "%u ഔട്ട്പുട്ട്"
 | 
			
		||||
msgstr[1] "%u ഔട്ട്പുട്ടുകള്"
 | 
			
		||||
 | 
			
		||||
#. translators:
 | 
			
		||||
#. * The number of sound inputs on a particular device
 | 
			
		||||
#: ../src/gvc/gvc-mixer-control.c:1847
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%u Input"
 | 
			
		||||
msgid_plural "%u Inputs"
 | 
			
		||||
msgstr[0] "%u ഇന്പുട്ട്"
 | 
			
		||||
msgstr[1] "%u ഇന്പുട്ടുകള്"
 | 
			
		||||
 | 
			
		||||
#: ../src/gvc/gvc-mixer-control.c:2371
 | 
			
		||||
msgid "System Sounds"
 | 
			
		||||
msgstr "സിസ്റ്റം ശബ്ദങ്ങള്"
 | 
			
		||||
 | 
			
		||||
#: ../src/main.c:347
 | 
			
		||||
msgid "Print version"
 | 
			
		||||
msgstr "പ്രിന്റ് ചെയ്യുവാന് സാധിയ്ക്കുന്ന പതിപ്പു്"
 | 
			
		||||
@@ -1925,7 +1906,7 @@ msgstr "ഒരു പ്രത്യേക മോഡ് ഉപയോഗിയ്
 | 
			
		||||
msgid "List possible modes"
 | 
			
		||||
msgstr "സാധ്യമായ മോഡുകള് ലഭ്യമാക്കുക"
 | 
			
		||||
 | 
			
		||||
#: ../src/shell-app.c:622
 | 
			
		||||
#: ../src/shell-app.c:626
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Failed to launch '%s'"
 | 
			
		||||
msgstr "'%s' ലഭ്യമാക്കുന്നതില് പരാജയം"
 | 
			
		||||
@@ -1955,19 +1936,6 @@ msgstr "ഉപയോക്താവു് ആധികാരികത ഉറപ
 | 
			
		||||
#~ msgid "More..."
 | 
			
		||||
#~ msgstr "കൂടുതല്..."
 | 
			
		||||
 | 
			
		||||
#~ msgid "%u Output"
 | 
			
		||||
#~ msgid_plural "%u Outputs"
 | 
			
		||||
#~ msgstr[0] "%u ഔട്ട്പുട്ട്"
 | 
			
		||||
#~ msgstr[1] "%u ഔട്ട്പുട്ടുകള്"
 | 
			
		||||
 | 
			
		||||
#~ msgid "%u Input"
 | 
			
		||||
#~ msgid_plural "%u Inputs"
 | 
			
		||||
#~ msgstr[0] "%u ഇന്പുട്ട്"
 | 
			
		||||
#~ msgstr[1] "%u ഇന്പുട്ടുകള്"
 | 
			
		||||
 | 
			
		||||
#~ msgid "System Sounds"
 | 
			
		||||
#~ msgstr "സിസ്റ്റം ശബ്ദങ്ങള്"
 | 
			
		||||
 | 
			
		||||
#~ msgctxt "event list time"
 | 
			
		||||
#~ msgid "%H:%M"
 | 
			
		||||
#~ msgstr "%H:%M"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										335
									
								
								po/nb.po
									
									
									
									
									
								
							
							
						
						
									
										335
									
								
								po/nb.po
									
									
									
									
									
								
							@@ -6,10 +6,10 @@
 | 
			
		||||
# Torstein Adolf Winterseth <kvikende@fsfe.org>, 2010.
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: gnome-shell 3.8.x\n"
 | 
			
		||||
"Project-Id-Version: gnome-shell 3.9.x\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2013-04-03 13:31+0200\n"
 | 
			
		||||
"PO-Revision-Date: 2013-04-03 13:31+0200\n"
 | 
			
		||||
"POT-Creation-Date: 2013-05-28 09:43+0200\n"
 | 
			
		||||
"PO-Revision-Date: 2013-05-28 09:44+0200\n"
 | 
			
		||||
"Last-Translator: Kjartan Maraas <kmaraas@gnome.org>\n"
 | 
			
		||||
"Language-Team: Norwegian bokmål <i18n-nb@lister.ping.uio.no>\n"
 | 
			
		||||
"Language: \n"
 | 
			
		||||
@@ -39,10 +39,14 @@ msgid "Focus the active notification"
 | 
			
		||||
msgstr "Fokuser aktiv varsling"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:4
 | 
			
		||||
msgid "Show the overview"
 | 
			
		||||
msgstr "Vis oversikt"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:5
 | 
			
		||||
msgid "Show all applications"
 | 
			
		||||
msgstr "Vis alle programmer"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:5
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:6
 | 
			
		||||
msgid "Open the application menu"
 | 
			
		||||
msgstr "Åpne programmenyen"
 | 
			
		||||
 | 
			
		||||
@@ -92,26 +96,10 @@ msgstr ""
 | 
			
		||||
"EnablExtension og DisableExtension på org.gnome.Shell."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:5
 | 
			
		||||
msgid "Whether to collect stats about applications usage"
 | 
			
		||||
msgstr "Om det skal samles statistikk om bruk av programmer"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:6
 | 
			
		||||
msgid ""
 | 
			
		||||
"The shell normally monitors active applications in order to present the most "
 | 
			
		||||
"used ones (e.g. in launchers). While this data will be kept private, you may "
 | 
			
		||||
"want to disable this for privacy reasons. Please note that doing so won't "
 | 
			
		||||
"remove already saved data."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"GNOME Shell vil normalt holde øye med åpne programmer for å kunne vise de "
 | 
			
		||||
"mest bruke (for eksempel i oppstartsmenyer). Denne informasjonen vil bli "
 | 
			
		||||
"holdt privat, men du kan deaktivere denne lagringen av personvernårsaker. "
 | 
			
		||||
"Hvis du slår det av, vil det ikke fjerne allerede lagret informasjon."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:7
 | 
			
		||||
msgid "List of desktop file IDs for favorite applications"
 | 
			
		||||
msgstr "Liste av skrivebordfil-ider for favorittprogrammer"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:8
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:6
 | 
			
		||||
msgid ""
 | 
			
		||||
"The applications corresponding to these identifiers will be displayed in the "
 | 
			
		||||
"favorites area."
 | 
			
		||||
@@ -119,52 +107,52 @@ msgstr ""
 | 
			
		||||
"Programmene som passer til disse identifikatorene vil bli vist i "
 | 
			
		||||
"favorittområdet."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:9
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:7
 | 
			
		||||
msgid "List of categories that should be displayed as folders"
 | 
			
		||||
msgstr "Liste med kategorier som skal vises som mapper"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:10
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:8
 | 
			
		||||
msgid ""
 | 
			
		||||
"Each category name in this list will be represented as folder in the "
 | 
			
		||||
"application view, rather than being displayed inline in the main view."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:11
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:9
 | 
			
		||||
msgid "History for command (Alt-F2) dialog"
 | 
			
		||||
msgstr "Historikk for kommandodialog (Alt-F2)"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:12
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:10
 | 
			
		||||
msgid "History for the looking glass dialog"
 | 
			
		||||
msgstr "Historikk for forstørrelsesglass-dialogen"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:11
 | 
			
		||||
msgid ""
 | 
			
		||||
"Internally used to store the last IM presence explicitly set by the user. "
 | 
			
		||||
"The value here is from the TpConnectionPresenceType enumeration."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:12
 | 
			
		||||
msgid ""
 | 
			
		||||
"Internally used to store the last session presence status for the user. The "
 | 
			
		||||
"value here is from the GsmPresenceStatus enumeration."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
 | 
			
		||||
msgid "Always show the 'Log out' menuitem in the user menu."
 | 
			
		||||
msgstr "Alltid vis menyoppføringen «Logg ut» i brukermenyen."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
 | 
			
		||||
msgid ""
 | 
			
		||||
"This key overrides the automatic hiding of the 'Log out' menuitem in single-"
 | 
			
		||||
"user, single-session situations."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
 | 
			
		||||
msgid ""
 | 
			
		||||
"Whether to remember password for mounting encrypted or remote filesystems"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
 | 
			
		||||
msgid ""
 | 
			
		||||
"The shell will request a password when an encrypted device or a remote "
 | 
			
		||||
"filesystem is mounted. If the password can be saved for future use a "
 | 
			
		||||
@@ -172,32 +160,40 @@ msgid ""
 | 
			
		||||
"state of the checkbox."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
 | 
			
		||||
msgid "Show the week date in the calendar"
 | 
			
		||||
msgstr "Vis dato for uken i kalender"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
 | 
			
		||||
msgid "If true, display the ISO week date in the calendar."
 | 
			
		||||
msgstr "Viser ISO-ukedato i kalenderen hvis «true»."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
 | 
			
		||||
msgid "Keybinding to open the application menu"
 | 
			
		||||
msgstr "Tastaturbinding som åpner programmenyen"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
 | 
			
		||||
msgid "Keybinding to open the application menu."
 | 
			
		||||
msgstr "Tastaturbinding som åpner programmenyen."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
 | 
			
		||||
msgid "Keybinding to open the \"Show Applications\" view"
 | 
			
		||||
msgstr "Tastaturbinding som åpner visningen «Vis programmer»"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
 | 
			
		||||
msgid ""
 | 
			
		||||
"Keybinding to open the \"Show Applications\" view of the Activities Overview."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Tastaturbinding som åpner visningen «Vis programmer» i aktivitetsoversikten."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
 | 
			
		||||
msgid "Keybinding to open the overview"
 | 
			
		||||
msgstr "Tastaturbinding som åpner oversikten"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
 | 
			
		||||
msgid "Keybinding to open the Activities Overview."
 | 
			
		||||
msgstr "Tastaturbinding som åpner aktivitetsoversikten."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
 | 
			
		||||
msgid "Keybinding to toggle the visibility of the message tray"
 | 
			
		||||
msgstr "Tastaturbinding som slår av/på synlighet for meldingstrau"
 | 
			
		||||
@@ -335,43 +331,50 @@ msgstr "Utvidelse"
 | 
			
		||||
msgid "Select an extension to configure using the combobox above."
 | 
			
		||||
msgstr "Velg en utvidelse som skal konfigureres med komboboksen over."
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:405
 | 
			
		||||
#: ../js/gdm/loginDialog.js:371
 | 
			
		||||
msgid "Session…"
 | 
			
		||||
msgstr "Økt …"
 | 
			
		||||
 | 
			
		||||
#. translators: this message is shown below the user list on the
 | 
			
		||||
#. login screen. It can be activated to reveal an entry for
 | 
			
		||||
#. manually entering the username.
 | 
			
		||||
#: ../js/gdm/loginDialog.js:630
 | 
			
		||||
#: ../js/gdm/loginDialog.js:601
 | 
			
		||||
msgid "Not listed?"
 | 
			
		||||
msgstr "Ikke listet?"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:786 ../js/ui/components/networkAgent.js:137
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:375
 | 
			
		||||
#: ../js/gdm/loginDialog.js:776 ../js/ui/components/networkAgent.js:137
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:161 ../js/ui/endSessionDialog.js:376
 | 
			
		||||
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:399
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:99
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:96
 | 
			
		||||
#: ../js/ui/userMenu.js:938
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "Avbryt"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:802
 | 
			
		||||
#: ../js/gdm/loginDialog.js:791
 | 
			
		||||
msgctxt "button"
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr "Logg inn"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:802
 | 
			
		||||
#: ../js/gdm/loginDialog.js:791
 | 
			
		||||
msgid "Next"
 | 
			
		||||
msgstr "Neste"
 | 
			
		||||
 | 
			
		||||
#. Translators: this message is shown below the username entry field
 | 
			
		||||
#. to clue the user in on how to login to the local network realm
 | 
			
		||||
#: ../js/gdm/loginDialog.js:888
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "(e.g., user or %s)"
 | 
			
		||||
msgstr "(f.eks. bruker eller %s)"
 | 
			
		||||
 | 
			
		||||
#. TTLS and PEAP are actually much more complicated, but this complication
 | 
			
		||||
#. is not visible here since we only care about phase2 authentication
 | 
			
		||||
#. (and don't even care of which one)
 | 
			
		||||
#: ../js/gdm/loginDialog.js:917 ../js/ui/components/networkAgent.js:260
 | 
			
		||||
#: ../js/gdm/loginDialog.js:892 ../js/ui/components/networkAgent.js:260
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:278
 | 
			
		||||
msgid "Username: "
 | 
			
		||||
msgstr "Brukernavn: "
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:1173
 | 
			
		||||
#: ../js/gdm/loginDialog.js:1158
 | 
			
		||||
msgid "Login Window"
 | 
			
		||||
msgstr "Innloggingsvindu"
 | 
			
		||||
 | 
			
		||||
@@ -394,21 +397,16 @@ msgstr "Start på nytt"
 | 
			
		||||
msgid "Power Off"
 | 
			
		||||
msgstr "Slå av"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/util.js:249
 | 
			
		||||
#: ../js/gdm/util.js:247
 | 
			
		||||
msgid "Authentication error"
 | 
			
		||||
msgstr "Autentiseringsfeil"
 | 
			
		||||
 | 
			
		||||
#. Translators: this message is shown below the password entry field
 | 
			
		||||
#. to indicate the user can swipe their finger instead
 | 
			
		||||
#: ../js/gdm/util.js:366
 | 
			
		||||
#: ../js/gdm/util.js:364
 | 
			
		||||
msgid "(or swipe finger)"
 | 
			
		||||
msgstr "(eller dra finger)"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/util.js:391
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "(e.g., user or %s)"
 | 
			
		||||
msgstr "(f.eks. bruker eller %s)"
 | 
			
		||||
 | 
			
		||||
#: ../js/misc/util.js:97
 | 
			
		||||
msgid "Command not found"
 | 
			
		||||
msgstr "Kommando ikke funnet"
 | 
			
		||||
@@ -424,23 +422,23 @@ msgstr "Klarte ikke å lese kommando:"
 | 
			
		||||
msgid "Execution of '%s' failed:"
 | 
			
		||||
msgstr "Kjøring av «%s» feilet:"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:349
 | 
			
		||||
#: ../js/ui/appDisplay.js:361
 | 
			
		||||
msgid "Frequent"
 | 
			
		||||
msgstr "Ofte"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:356
 | 
			
		||||
#: ../js/ui/appDisplay.js:368
 | 
			
		||||
msgid "All"
 | 
			
		||||
msgstr "Alle"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:914
 | 
			
		||||
#: ../js/ui/appDisplay.js:960
 | 
			
		||||
msgid "New Window"
 | 
			
		||||
msgstr "Nytt vindu"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:917 ../js/ui/dash.js:284
 | 
			
		||||
#: ../js/ui/appDisplay.js:963 ../js/ui/dash.js:284
 | 
			
		||||
msgid "Remove from Favorites"
 | 
			
		||||
msgstr "Fjern fra favoritter"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:918
 | 
			
		||||
#: ../js/ui/appDisplay.js:964
 | 
			
		||||
msgid "Add to Favorites"
 | 
			
		||||
msgstr "Legg til i favoritter"
 | 
			
		||||
 | 
			
		||||
@@ -579,35 +577,35 @@ msgid "S"
 | 
			
		||||
msgstr "Lø"
 | 
			
		||||
 | 
			
		||||
#. Translators: Text to show if there are no events
 | 
			
		||||
#: ../js/ui/calendar.js:720
 | 
			
		||||
#: ../js/ui/calendar.js:735
 | 
			
		||||
msgid "Nothing Scheduled"
 | 
			
		||||
msgstr "Ingenting planlagt"
 | 
			
		||||
 | 
			
		||||
#. Translators: Shown on calendar heading when selected day occurs on current year
 | 
			
		||||
#: ../js/ui/calendar.js:736
 | 
			
		||||
#: ../js/ui/calendar.js:751
 | 
			
		||||
msgctxt "calendar heading"
 | 
			
		||||
msgid "%A, %B %d"
 | 
			
		||||
msgstr "%A %B %d"
 | 
			
		||||
 | 
			
		||||
#. Translators: Shown on calendar heading when selected day occurs on different year
 | 
			
		||||
#: ../js/ui/calendar.js:739
 | 
			
		||||
#: ../js/ui/calendar.js:754
 | 
			
		||||
msgctxt "calendar heading"
 | 
			
		||||
msgid "%A, %B %d, %Y"
 | 
			
		||||
msgstr "%A %B %d, %Y"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:749
 | 
			
		||||
#: ../js/ui/calendar.js:764
 | 
			
		||||
msgid "Today"
 | 
			
		||||
msgstr "I dag"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:753
 | 
			
		||||
#: ../js/ui/calendar.js:768
 | 
			
		||||
msgid "Tomorrow"
 | 
			
		||||
msgstr "I morgen"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:764
 | 
			
		||||
#: ../js/ui/calendar.js:779
 | 
			
		||||
msgid "This week"
 | 
			
		||||
msgstr "Denne uken"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:772
 | 
			
		||||
#: ../js/ui/calendar.js:787
 | 
			
		||||
msgid "Next week"
 | 
			
		||||
msgstr "Neste uke"
 | 
			
		||||
 | 
			
		||||
@@ -632,11 +630,11 @@ msgstr "Åpne med %s"
 | 
			
		||||
msgid "Eject"
 | 
			
		||||
msgstr "Løs ut"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/keyring.js:82 ../js/ui/components/polkitAgent.js:268
 | 
			
		||||
#: ../js/ui/components/keyring.js:88 ../js/ui/components/polkitAgent.js:280
 | 
			
		||||
msgid "Password:"
 | 
			
		||||
msgstr "Passord:"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/keyring.js:101
 | 
			
		||||
#: ../js/ui/components/keyring.js:107
 | 
			
		||||
msgid "Type again:"
 | 
			
		||||
msgstr "Skriv på nytt:"
 | 
			
		||||
 | 
			
		||||
@@ -716,15 +714,15 @@ msgstr "Nettverkspassord for mobilt bredbånd"
 | 
			
		||||
msgid "A password is required to connect to '%s'."
 | 
			
		||||
msgstr "Et passord kreves for å koble til «%s»."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:55
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:54
 | 
			
		||||
msgid "Authentication Required"
 | 
			
		||||
msgstr "Autentisering kreves"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:93
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:92
 | 
			
		||||
msgid "Administrator"
 | 
			
		||||
msgstr "Administrator"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:165
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:170
 | 
			
		||||
msgid "Authenticate"
 | 
			
		||||
msgstr "Autentiser"
 | 
			
		||||
 | 
			
		||||
@@ -732,12 +730,12 @@ msgstr "Autentiser"
 | 
			
		||||
#. * requested authentication was not gained; this can happen
 | 
			
		||||
#. * because of an authentication error (like invalid password),
 | 
			
		||||
#. * for instance.
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:256 ../js/ui/shellMountOperation.js:383
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:266 ../js/ui/shellMountOperation.js:383
 | 
			
		||||
msgid "Sorry, that didn't work. Please try again."
 | 
			
		||||
msgstr "Beklager, det virket ikke. Vennligst prøv igjen."
 | 
			
		||||
 | 
			
		||||
#. Translators: this is a filename used for screencast recording
 | 
			
		||||
#: ../js/ui/components/recorder.js:48
 | 
			
		||||
#: ../js/ui/components/recorder.js:47
 | 
			
		||||
#, no-c-format
 | 
			
		||||
msgid "Screencast from %d %t"
 | 
			
		||||
msgstr "Skjermvideo fra %d %t"
 | 
			
		||||
@@ -995,22 +993,22 @@ msgstr "Vis programmer"
 | 
			
		||||
msgid "Dash"
 | 
			
		||||
msgstr "Favoritter"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/dateMenu.js:91
 | 
			
		||||
#: ../js/ui/dateMenu.js:86
 | 
			
		||||
msgid "Open Calendar"
 | 
			
		||||
msgstr "Åpne kalender"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/dateMenu.js:96
 | 
			
		||||
#: ../js/ui/dateMenu.js:90
 | 
			
		||||
msgid "Open Clocks"
 | 
			
		||||
msgstr "Åpne Klokker"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/dateMenu.js:105
 | 
			
		||||
#: ../js/ui/dateMenu.js:97
 | 
			
		||||
msgid "Date & Time Settings"
 | 
			
		||||
msgstr "Innstillinger for dato og klokkeslett"
 | 
			
		||||
 | 
			
		||||
#. Translators: This is the date format to use when the calendar popup is
 | 
			
		||||
#. * shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
 | 
			
		||||
#.
 | 
			
		||||
#: ../js/ui/dateMenu.js:215
 | 
			
		||||
#: ../js/ui/dateMenu.js:208
 | 
			
		||||
msgid "%A %B %e, %Y"
 | 
			
		||||
msgstr "%a %e %B, %Y"
 | 
			
		||||
 | 
			
		||||
@@ -1115,56 +1113,56 @@ msgstr "Installer"
 | 
			
		||||
msgid "Download and install '%s' from extensions.gnome.org?"
 | 
			
		||||
msgstr "Last ned og installer «%s» fra extensions.gnome.org?"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/keyboard.js:619 ../js/ui/status/keyboard.js:314
 | 
			
		||||
#: ../js/ui/keyboard.js:619 ../js/ui/status/keyboard.js:333
 | 
			
		||||
#: ../js/ui/status/power.js:211
 | 
			
		||||
msgid "Keyboard"
 | 
			
		||||
msgstr "Tastatur"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:693
 | 
			
		||||
#: ../js/ui/lookingGlass.js:689
 | 
			
		||||
msgid "No extensions installed"
 | 
			
		||||
msgstr "Ingen utvidelser installert"
 | 
			
		||||
 | 
			
		||||
#. Translators: argument is an extension UUID.
 | 
			
		||||
#: ../js/ui/lookingGlass.js:747
 | 
			
		||||
#: ../js/ui/lookingGlass.js:743
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%s has not emitted any errors."
 | 
			
		||||
msgstr "%s har ikke avgitt noen feil."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:753
 | 
			
		||||
#: ../js/ui/lookingGlass.js:749
 | 
			
		||||
msgid "Hide Errors"
 | 
			
		||||
msgstr "Skjul feil"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:757 ../js/ui/lookingGlass.js:817
 | 
			
		||||
#: ../js/ui/lookingGlass.js:753 ../js/ui/lookingGlass.js:813
 | 
			
		||||
msgid "Show Errors"
 | 
			
		||||
msgstr "Vis feil"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:766
 | 
			
		||||
#: ../js/ui/lookingGlass.js:762
 | 
			
		||||
msgid "Enabled"
 | 
			
		||||
msgstr "Aktivert"
 | 
			
		||||
 | 
			
		||||
#. translators:
 | 
			
		||||
#. * The device has been disabled
 | 
			
		||||
#: ../js/ui/lookingGlass.js:769 ../src/gvc/gvc-mixer-control.c:1830
 | 
			
		||||
#: ../js/ui/lookingGlass.js:765 ../src/gvc/gvc-mixer-control.c:1830
 | 
			
		||||
msgid "Disabled"
 | 
			
		||||
msgstr "Deaktivert"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:771
 | 
			
		||||
#: ../js/ui/lookingGlass.js:767
 | 
			
		||||
msgid "Error"
 | 
			
		||||
msgstr "Feil"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:773
 | 
			
		||||
#: ../js/ui/lookingGlass.js:769
 | 
			
		||||
msgid "Out of date"
 | 
			
		||||
msgstr "Utdatert"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:775
 | 
			
		||||
#: ../js/ui/lookingGlass.js:771
 | 
			
		||||
msgid "Downloading"
 | 
			
		||||
msgstr "Laster ned"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:799
 | 
			
		||||
#: ../js/ui/lookingGlass.js:795
 | 
			
		||||
msgid "View Source"
 | 
			
		||||
msgstr "Vis kildekode"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:808
 | 
			
		||||
#: ../js/ui/lookingGlass.js:804
 | 
			
		||||
msgid "Web Page"
 | 
			
		||||
msgstr "Nettside"
 | 
			
		||||
 | 
			
		||||
@@ -1184,35 +1182,35 @@ msgstr "Tøm meldinger"
 | 
			
		||||
msgid "Notification Settings"
 | 
			
		||||
msgstr "Innstillinger for varsling"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:1709
 | 
			
		||||
#: ../js/ui/messageTray.js:1707
 | 
			
		||||
msgid "No Messages"
 | 
			
		||||
msgstr "Ingen meldinger"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:1782
 | 
			
		||||
#: ../js/ui/messageTray.js:1780
 | 
			
		||||
msgid "Message Tray"
 | 
			
		||||
msgstr "Meldingstrau"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:2810
 | 
			
		||||
#: ../js/ui/messageTray.js:2805
 | 
			
		||||
msgid "System Information"
 | 
			
		||||
msgstr "Systeminformasjon"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/notificationDaemon.js:629 ../src/shell-app.c:374
 | 
			
		||||
#: ../js/ui/notificationDaemon.js:629 ../src/shell-app.c:378
 | 
			
		||||
msgctxt "program"
 | 
			
		||||
msgid "Unknown"
 | 
			
		||||
msgstr "Ukjent"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/overviewControls.js:463 ../js/ui/screenShield.js:149
 | 
			
		||||
#: ../js/ui/overviewControls.js:472 ../js/ui/screenShield.js:150
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%d new message"
 | 
			
		||||
msgid_plural "%d new messages"
 | 
			
		||||
msgstr[0] "%d ny melding"
 | 
			
		||||
msgstr[1] "%d nye meldinger"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/overview.js:84
 | 
			
		||||
#: ../js/ui/overview.js:82
 | 
			
		||||
msgid "Undo"
 | 
			
		||||
msgstr "Angre"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/overview.js:129
 | 
			
		||||
#: ../js/ui/overview.js:127
 | 
			
		||||
msgid "Overview"
 | 
			
		||||
msgstr "Oversikt"
 | 
			
		||||
 | 
			
		||||
@@ -1220,21 +1218,21 @@ msgstr "Oversikt"
 | 
			
		||||
#. in the search entry when no search is
 | 
			
		||||
#. active; it should not exceed ~30
 | 
			
		||||
#. characters.
 | 
			
		||||
#: ../js/ui/overview.js:271
 | 
			
		||||
#: ../js/ui/overview.js:258
 | 
			
		||||
msgid "Type to search…"
 | 
			
		||||
msgstr "Skriv for å søke …"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/panel.js:612
 | 
			
		||||
#: ../js/ui/panel.js:642
 | 
			
		||||
msgid "Quit"
 | 
			
		||||
msgstr "Avslutt"
 | 
			
		||||
 | 
			
		||||
#. Translators: If there is no suitable word for "Activities"
 | 
			
		||||
#. in your language, you can use the word for "Overview".
 | 
			
		||||
#: ../js/ui/panel.js:636
 | 
			
		||||
#: ../js/ui/panel.js:693
 | 
			
		||||
msgid "Activities"
 | 
			
		||||
msgstr "Aktiviteter"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/panel.js:933
 | 
			
		||||
#: ../js/ui/panel.js:989
 | 
			
		||||
msgid "Top Bar"
 | 
			
		||||
msgstr "Topp-panel"
 | 
			
		||||
 | 
			
		||||
@@ -1243,36 +1241,36 @@ msgstr "Topp-panel"
 | 
			
		||||
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
 | 
			
		||||
#. switches containing "◯" and "|"). Other values will
 | 
			
		||||
#. simply result in invisible toggle switches.
 | 
			
		||||
#: ../js/ui/popupMenu.js:727
 | 
			
		||||
#: ../js/ui/popupMenu.js:738
 | 
			
		||||
msgid "toggle-switch-us"
 | 
			
		||||
msgstr "toggle-switch-intl"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/runDialog.js:73
 | 
			
		||||
#: ../js/ui/runDialog.js:74
 | 
			
		||||
msgid "Enter a Command"
 | 
			
		||||
msgstr "Oppgi en kommando"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/runDialog.js:109
 | 
			
		||||
#: ../js/ui/runDialog.js:110
 | 
			
		||||
msgid "Close"
 | 
			
		||||
msgstr "Lukk"
 | 
			
		||||
 | 
			
		||||
#. Translators: This is a time format for a date in
 | 
			
		||||
#. long format
 | 
			
		||||
#: ../js/ui/screenShield.js:86
 | 
			
		||||
#: ../js/ui/screenShield.js:87
 | 
			
		||||
msgid "%A, %B %d"
 | 
			
		||||
msgstr "%A, %B %d"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:151
 | 
			
		||||
#: ../js/ui/screenShield.js:152
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%d new notification"
 | 
			
		||||
msgid_plural "%d new notifications"
 | 
			
		||||
msgstr[0] "%d ny varsling"
 | 
			
		||||
msgstr[1] "%d nye varslinger"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:438 ../js/ui/userMenu.js:807
 | 
			
		||||
#: ../js/ui/screenShield.js:449 ../js/ui/userMenu.js:807
 | 
			
		||||
msgid "Lock"
 | 
			
		||||
msgstr "Lås"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:640
 | 
			
		||||
#: ../js/ui/screenShield.js:652
 | 
			
		||||
msgid "GNOME needs to lock the screen"
 | 
			
		||||
msgstr "GNOME må låse skjermen"
 | 
			
		||||
 | 
			
		||||
@@ -1283,11 +1281,11 @@ msgstr "GNOME må låse skjermen"
 | 
			
		||||
#.
 | 
			
		||||
#. XXX: another option is to kick the user into the gdm login
 | 
			
		||||
#. screen, where we're not affected by grabs
 | 
			
		||||
#: ../js/ui/screenShield.js:761 ../js/ui/screenShield.js:1197
 | 
			
		||||
#: ../js/ui/screenShield.js:773 ../js/ui/screenShield.js:1213
 | 
			
		||||
msgid "Unable to lock"
 | 
			
		||||
msgstr "Kan ikke låse"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:762 ../js/ui/screenShield.js:1198
 | 
			
		||||
#: ../js/ui/screenShield.js:774 ../js/ui/screenShield.js:1214
 | 
			
		||||
msgid "Lock was blocked by an application"
 | 
			
		||||
msgstr "Låsing ble stoppet av et program"
 | 
			
		||||
 | 
			
		||||
@@ -1299,19 +1297,19 @@ msgstr "Søker …"
 | 
			
		||||
msgid "No results."
 | 
			
		||||
msgstr "Ingen resultater."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellEntry.js:29
 | 
			
		||||
#: ../js/ui/shellEntry.js:27
 | 
			
		||||
msgid "Copy"
 | 
			
		||||
msgstr "Kopier"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellEntry.js:34
 | 
			
		||||
#: ../js/ui/shellEntry.js:32
 | 
			
		||||
msgid "Paste"
 | 
			
		||||
msgstr "Lim inn"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellEntry.js:106
 | 
			
		||||
#: ../js/ui/shellEntry.js:99
 | 
			
		||||
msgid "Show Text"
 | 
			
		||||
msgstr "Vis tekst"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellEntry.js:108
 | 
			
		||||
#: ../js/ui/shellEntry.js:101
 | 
			
		||||
msgid "Hide Text"
 | 
			
		||||
msgstr "Skjul tekst"
 | 
			
		||||
 | 
			
		||||
@@ -1323,7 +1321,7 @@ msgstr "Passord"
 | 
			
		||||
msgid "Remember Password"
 | 
			
		||||
msgstr "Husk passord"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:113
 | 
			
		||||
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:109
 | 
			
		||||
msgid "Unlock"
 | 
			
		||||
msgstr "Lås opp"
 | 
			
		||||
 | 
			
		||||
@@ -1378,7 +1376,7 @@ msgstr "Stor tekst"
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:28 ../js/ui/status/bluetooth.js:32
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:289 ../js/ui/status/bluetooth.js:321
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:357 ../js/ui/status/bluetooth.js:388
 | 
			
		||||
#: ../js/ui/status/network.js:826
 | 
			
		||||
#: ../js/ui/status/network.js:739
 | 
			
		||||
msgid "Bluetooth"
 | 
			
		||||
msgstr "Bluetooth"
 | 
			
		||||
 | 
			
		||||
@@ -1399,7 +1397,7 @@ msgid "Bluetooth Settings"
 | 
			
		||||
msgstr "Innstillinger for Bluetooth"
 | 
			
		||||
 | 
			
		||||
#. TRANSLATORS: this means that bluetooth was disabled by hardware rfkill
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:104 ../js/ui/status/network.js:178
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:104 ../js/ui/status/network.js:142
 | 
			
		||||
msgid "hardware disabled"
 | 
			
		||||
msgstr "maskinvare slått av"
 | 
			
		||||
 | 
			
		||||
@@ -1407,12 +1405,12 @@ msgstr "maskinvare slått av"
 | 
			
		||||
msgid "Connection"
 | 
			
		||||
msgstr "Tilkobling"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:208 ../js/ui/status/network.js:460
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:208 ../js/ui/status/network.js:404
 | 
			
		||||
msgid "disconnecting..."
 | 
			
		||||
msgstr "kobler fra …"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:221 ../js/ui/status/network.js:466
 | 
			
		||||
#: ../js/ui/status/network.js:1546
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:221 ../js/ui/status/network.js:410
 | 
			
		||||
#: ../js/ui/status/network.js:1343
 | 
			
		||||
msgid "connecting..."
 | 
			
		||||
msgstr "kobler til …"
 | 
			
		||||
 | 
			
		||||
@@ -1467,8 +1465,9 @@ msgstr "Enhet %s vil koble seg sammen med denne datamaskinen"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:366
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Please confirm whether the PIN '%06d' matches the one on the device."
 | 
			
		||||
msgstr "Vennligst bekreft om PIN «%06d» er lik den som brukes på enheten."
 | 
			
		||||
msgid ""
 | 
			
		||||
"Please confirm whether the Passkey '%06d' matches the one on the device."
 | 
			
		||||
msgstr "Vennligst bekreft om passord «%06d» er lik den som brukes på enheten."
 | 
			
		||||
 | 
			
		||||
#. Translators: this is the verb, not the noun
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:369
 | 
			
		||||
@@ -1492,11 +1491,11 @@ msgstr "Vennligst oppgi PIN som oppgitt på enheten."
 | 
			
		||||
msgid "OK"
 | 
			
		||||
msgstr "OK"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/keyboard.js:368
 | 
			
		||||
#: ../js/ui/status/keyboard.js:396
 | 
			
		||||
msgid "Show Keyboard Layout"
 | 
			
		||||
msgstr "Vis tastaturutforming"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/keyboard.js:373
 | 
			
		||||
#: ../js/ui/status/keyboard.js:401
 | 
			
		||||
msgid "Region & Language Settings"
 | 
			
		||||
msgstr "Innstillinger for region og språk"
 | 
			
		||||
 | 
			
		||||
@@ -1504,117 +1503,91 @@ msgstr "Innstillinger for region og språk"
 | 
			
		||||
msgid "Volume, network, battery"
 | 
			
		||||
msgstr "Volum, nettverk, batteri"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:104
 | 
			
		||||
#: ../js/ui/status/network.js:75
 | 
			
		||||
msgid "<unknown>"
 | 
			
		||||
msgstr "<ukjent>"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:127
 | 
			
		||||
msgid "Wi-Fi"
 | 
			
		||||
msgstr "Wi-Fi"
 | 
			
		||||
 | 
			
		||||
#. Translators: this indicates that wireless or wwan is disabled by hardware killswitch
 | 
			
		||||
#: ../js/ui/status/network.js:200
 | 
			
		||||
#: ../js/ui/status/network.js:164
 | 
			
		||||
msgid "disabled"
 | 
			
		||||
msgstr "slått av"
 | 
			
		||||
 | 
			
		||||
#. Translators: this is for network devices that are physically present but are not
 | 
			
		||||
#. under NetworkManager's control (and thus cannot be used in the menu)
 | 
			
		||||
#: ../js/ui/status/network.js:458
 | 
			
		||||
#: ../js/ui/status/network.js:402
 | 
			
		||||
msgid "unmanaged"
 | 
			
		||||
msgstr "ikke håndtert"
 | 
			
		||||
 | 
			
		||||
#. Translators: this is for network connections that require some kind of key or password
 | 
			
		||||
#: ../js/ui/status/network.js:469 ../js/ui/status/network.js:1549
 | 
			
		||||
#: ../js/ui/status/network.js:413 ../js/ui/status/network.js:1346
 | 
			
		||||
msgid "authentication required"
 | 
			
		||||
msgstr "autentisering kreves"
 | 
			
		||||
 | 
			
		||||
#. Translators: this is for devices that require some kind of firmware or kernel
 | 
			
		||||
#. module, which is missing
 | 
			
		||||
#: ../js/ui/status/network.js:479
 | 
			
		||||
#: ../js/ui/status/network.js:423
 | 
			
		||||
msgid "firmware missing"
 | 
			
		||||
msgstr "fastvare mangler"
 | 
			
		||||
 | 
			
		||||
#. Translators: this is for wired network devices that are physically disconnected
 | 
			
		||||
#: ../js/ui/status/network.js:486
 | 
			
		||||
#: ../js/ui/status/network.js:430
 | 
			
		||||
msgid "cable unplugged"
 | 
			
		||||
msgstr "kabel koblet fra"
 | 
			
		||||
 | 
			
		||||
#. Translators: this is for a network device that cannot be activated (for example it
 | 
			
		||||
#. is disabled by rfkill, or it has no coverage
 | 
			
		||||
#: ../js/ui/status/network.js:491
 | 
			
		||||
#: ../js/ui/status/network.js:435
 | 
			
		||||
msgid "unavailable"
 | 
			
		||||
msgstr "ikke tilgjengelig"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:493 ../js/ui/status/network.js:1551
 | 
			
		||||
#: ../js/ui/status/network.js:437 ../js/ui/status/network.js:1348
 | 
			
		||||
msgid "connection failed"
 | 
			
		||||
msgstr "tilkobling feilet"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:552 ../js/ui/status/network.js:1435
 | 
			
		||||
#: ../js/ui/status/network.js:1627
 | 
			
		||||
#: ../js/ui/status/network.js:490 ../js/ui/status/network.js:1236
 | 
			
		||||
#: ../js/ui/status/network.js:1424
 | 
			
		||||
msgid "More…"
 | 
			
		||||
msgstr "Mer …"
 | 
			
		||||
 | 
			
		||||
#. TRANSLATORS: this is the indication that a connection for another logged in user is active,
 | 
			
		||||
#. and we cannot access its settings (including the name)
 | 
			
		||||
#: ../js/ui/status/network.js:588 ../js/ui/status/network.js:1365
 | 
			
		||||
#: ../js/ui/status/network.js:518 ../js/ui/status/network.js:1191
 | 
			
		||||
msgid "Connected (private)"
 | 
			
		||||
msgstr "Tilkoblet (privat)"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:667
 | 
			
		||||
#: ../js/ui/status/network.js:597
 | 
			
		||||
msgid "Wired"
 | 
			
		||||
msgstr "Kablet"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:668
 | 
			
		||||
msgid "Auto Ethernet"
 | 
			
		||||
msgstr "Automatisk Ethernet"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:695
 | 
			
		||||
#: ../js/ui/status/network.js:611
 | 
			
		||||
msgid "Mobile broadband"
 | 
			
		||||
msgstr "Mobilt bredbånd"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:728
 | 
			
		||||
msgid "Auto broadband"
 | 
			
		||||
msgstr "Automatisk bredbånd"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:731
 | 
			
		||||
msgid "Auto dial-up"
 | 
			
		||||
msgstr "Automatisk oppringt"
 | 
			
		||||
 | 
			
		||||
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
 | 
			
		||||
#: ../js/ui/status/network.js:861 ../js/ui/status/network.js:1382
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Auto %s"
 | 
			
		||||
msgstr "Automatisk %s"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:863
 | 
			
		||||
msgid "Auto bluetooth"
 | 
			
		||||
msgstr "Automatisk Bluetooth"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:1384
 | 
			
		||||
msgid "Auto wireless"
 | 
			
		||||
msgstr "Automatisk trådløst"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:1729
 | 
			
		||||
#: ../js/ui/status/network.js:1522
 | 
			
		||||
msgid "Enable networking"
 | 
			
		||||
msgstr "Slå på nettverk"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:1771
 | 
			
		||||
msgid "Wi-Fi"
 | 
			
		||||
msgstr "Wi-Fi"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:1790
 | 
			
		||||
#: ../js/ui/status/network.js:1583
 | 
			
		||||
msgid "Network Settings"
 | 
			
		||||
msgstr "Innstillinger for nettverk"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:1807
 | 
			
		||||
#: ../js/ui/status/network.js:1600
 | 
			
		||||
msgid "Network Manager"
 | 
			
		||||
msgstr "Nettverkshåndtering"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:1897
 | 
			
		||||
#: ../js/ui/status/network.js:1690
 | 
			
		||||
msgid "Connection failed"
 | 
			
		||||
msgstr "Tilkobling feilet"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:1898
 | 
			
		||||
#: ../js/ui/status/network.js:1691
 | 
			
		||||
msgid "Activation of network connection failed"
 | 
			
		||||
msgstr "Aktivering av nettverkstilkobling feilet"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:2276
 | 
			
		||||
#: ../js/ui/status/network.js:2047
 | 
			
		||||
msgid "Networking is disabled"
 | 
			
		||||
msgstr "Nettverk er slått av"
 | 
			
		||||
 | 
			
		||||
@@ -1728,11 +1701,11 @@ msgstr "Volum"
 | 
			
		||||
msgid "Microphone"
 | 
			
		||||
msgstr "Mikrofon"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/unlockDialog.js:124
 | 
			
		||||
#: ../js/ui/unlockDialog.js:120
 | 
			
		||||
msgid "Log in as another user"
 | 
			
		||||
msgstr "Logg inn som en annen bruker"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/unlockDialog.js:145
 | 
			
		||||
#: ../js/ui/unlockDialog.js:141
 | 
			
		||||
msgid "Unlock Window"
 | 
			
		||||
msgstr "Lås opp vindu"
 | 
			
		||||
 | 
			
		||||
@@ -1860,36 +1833,36 @@ msgid_plural "%u Inputs"
 | 
			
		||||
msgstr[0] "%u inngang"
 | 
			
		||||
msgstr[1] "%u innganger"
 | 
			
		||||
 | 
			
		||||
#: ../src/gvc/gvc-mixer-control.c:2371
 | 
			
		||||
#: ../src/gvc/gvc-mixer-control.c:2373
 | 
			
		||||
msgid "System Sounds"
 | 
			
		||||
msgstr "Systemlyder"
 | 
			
		||||
 | 
			
		||||
#: ../src/main.c:347
 | 
			
		||||
#: ../src/main.c:372
 | 
			
		||||
msgid "Print version"
 | 
			
		||||
msgstr "Skriv ut versjon"
 | 
			
		||||
 | 
			
		||||
#: ../src/main.c:353
 | 
			
		||||
#: ../src/main.c:378
 | 
			
		||||
msgid "Mode used by GDM for login screen"
 | 
			
		||||
msgstr "Modus som brukes av GDM for innloggingsskjermen"
 | 
			
		||||
 | 
			
		||||
#: ../src/main.c:359
 | 
			
		||||
#: ../src/main.c:384
 | 
			
		||||
msgid "Use a specific mode, e.g. \"gdm\" for login screen"
 | 
			
		||||
msgstr "Bruk spesifikt modus, f.eks «gdm» for innloggingsskjerm"
 | 
			
		||||
 | 
			
		||||
#: ../src/main.c:365
 | 
			
		||||
#: ../src/main.c:390
 | 
			
		||||
msgid "List possible modes"
 | 
			
		||||
msgstr "Vis mulige modi"
 | 
			
		||||
 | 
			
		||||
#: ../src/shell-app.c:622
 | 
			
		||||
#: ../src/shell-app.c:626
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Failed to launch '%s'"
 | 
			
		||||
msgstr "Klarte ikke å starte «%s»"
 | 
			
		||||
 | 
			
		||||
#: ../src/shell-keyring-prompt.c:708
 | 
			
		||||
#: ../src/shell-keyring-prompt.c:714
 | 
			
		||||
msgid "Passwords do not match."
 | 
			
		||||
msgstr "Passordene er ikke like."
 | 
			
		||||
 | 
			
		||||
#: ../src/shell-keyring-prompt.c:716
 | 
			
		||||
#: ../src/shell-keyring-prompt.c:722
 | 
			
		||||
msgid "Password cannot be blank"
 | 
			
		||||
msgstr "Passordet kan ikke være tomt"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										401
									
								
								po/sk.po
									
									
									
									
									
								
							
							
						
						
									
										401
									
								
								po/sk.po
									
									
									
									
									
								
							@@ -10,8 +10,8 @@ msgstr ""
 | 
			
		||||
"Project-Id-Version: gnome-shell\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
 | 
			
		||||
"shell&keywords=I18N+L10N&component=general\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-23 11:49+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-03-23 16:21+0000\n"
 | 
			
		||||
"POT-Creation-Date: 2013-05-24 21:21+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-05-24 23:24+0100\n"
 | 
			
		||||
"Last-Translator: Dušan Kazik <prescott66@gmail.com>\n"
 | 
			
		||||
"Language-Team: Slovak <gnome-sk-list@gnome.org>\n"
 | 
			
		||||
"Language: sk\n"
 | 
			
		||||
@@ -34,22 +34,30 @@ msgstr "Zaznamenať dianie na obrazovke"
 | 
			
		||||
msgid "System"
 | 
			
		||||
msgstr "Systém"
 | 
			
		||||
 | 
			
		||||
# nazov klavesovej skratky
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:2
 | 
			
		||||
msgid "Show the message tray"
 | 
			
		||||
msgstr "Zobrazí lištu správ"
 | 
			
		||||
msgstr "Zobraziť lištu správ"
 | 
			
		||||
 | 
			
		||||
# nazov klavesovej skratky
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:3
 | 
			
		||||
msgid "Focus the active notification"
 | 
			
		||||
msgstr "Zamerať aktívne oznámenie"
 | 
			
		||||
 | 
			
		||||
# tooltip
 | 
			
		||||
# nazov klavesovej skratky
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:4
 | 
			
		||||
msgid "Show all applications"
 | 
			
		||||
msgstr "Zobrazí všetky aplikácie"
 | 
			
		||||
msgid "Show the overview"
 | 
			
		||||
msgstr "Zobraziť prehľad"
 | 
			
		||||
 | 
			
		||||
# nazov klavesovej skratky
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:5
 | 
			
		||||
msgid "Show all applications"
 | 
			
		||||
msgstr "Zobraziť všetky aplikácie"
 | 
			
		||||
 | 
			
		||||
# nazov klavesovej skratky
 | 
			
		||||
#: ../data/50-gnome-shell-system.xml.in.h:6
 | 
			
		||||
msgid "Open the application menu"
 | 
			
		||||
msgstr "Otvorí ponuku aplikácií"
 | 
			
		||||
msgstr "Otvoriť ponuku aplikácií"
 | 
			
		||||
 | 
			
		||||
#: ../data/gnome-shell.desktop.in.in.h:1
 | 
			
		||||
msgid "GNOME Shell"
 | 
			
		||||
@@ -100,26 +108,10 @@ msgstr ""
 | 
			
		||||
"gnome.Shell."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:5
 | 
			
		||||
msgid "Whether to collect stats about applications usage"
 | 
			
		||||
msgstr "Či sa majú zhromažďovať štatistické údaje o používaní aplikácií"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:6
 | 
			
		||||
msgid ""
 | 
			
		||||
"The shell normally monitors active applications in order to present the most "
 | 
			
		||||
"used ones (e.g. in launchers). While this data will be kept private, you may "
 | 
			
		||||
"want to disable this for privacy reasons. Please note that doing so won't "
 | 
			
		||||
"remove already saved data."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Prostredie shell obvykle sleduje aktívne aplikácie, aby mohlo ponúkať "
 | 
			
		||||
"najpoužívanejšie z nich (napr. v spúšťačoch). Aj keď sú tieto údaje "
 | 
			
		||||
"uchovávané v tajnosti, môžete ich kvôli lepšej ochrane súkromia zakázať. Ak "
 | 
			
		||||
"tak urobíte, údaje, ktoré už boli uložené, zostanú zachované."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:7
 | 
			
		||||
msgid "List of desktop file IDs for favorite applications"
 | 
			
		||||
msgstr "Zoznam identifikátorov súborov plochy pre obľúbené aplikácie"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:8
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:6
 | 
			
		||||
msgid ""
 | 
			
		||||
"The applications corresponding to these identifiers will be displayed in the "
 | 
			
		||||
"favorites area."
 | 
			
		||||
@@ -128,29 +120,29 @@ msgstr ""
 | 
			
		||||
"obľúbenými aplikáciami."
 | 
			
		||||
 | 
			
		||||
# summary
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:9
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:7
 | 
			
		||||
msgid "List of categories that should be displayed as folders"
 | 
			
		||||
msgstr "Zoznam kategórií, ktoré sa majú zobraziť ako priečinky"
 | 
			
		||||
 | 
			
		||||
# description
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:10
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:8
 | 
			
		||||
msgid ""
 | 
			
		||||
"Each category name in this list will be represented as folder in the "
 | 
			
		||||
"application view, rather than being displayed inline in the main view."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Každá z názvov kategórií v tomto zoznamu bude reprezentovaná ako priečinok v zobrazení aplikácií namiesto toho, aby sa zobrazila v hlavnom zobrazení."
 | 
			
		||||
"Každá z názvov kategórií v tomto zoznamu bude reprezentovaná ako priečinok v "
 | 
			
		||||
"zobrazení aplikácií namiesto toho, aby sa zobrazila v hlavnom zobrazení."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:11
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:9
 | 
			
		||||
msgid "History for command (Alt-F2) dialog"
 | 
			
		||||
msgstr "História dialógového okna príkazov (Alt-F2)"
 | 
			
		||||
 | 
			
		||||
# * https://live.gnome.org/GnomeShell/LookingGlass
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:12
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:10
 | 
			
		||||
msgid "History for the looking glass dialog"
 | 
			
		||||
msgstr "História dialógového okna integrovaného odlaďovača"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:11
 | 
			
		||||
msgid ""
 | 
			
		||||
"Internally used to store the last IM presence explicitly set by the user. "
 | 
			
		||||
"The value here is from the TpConnectionPresenceType enumeration."
 | 
			
		||||
@@ -159,7 +151,7 @@ msgstr ""
 | 
			
		||||
"komunikátora výlučne nastavenej používateľom. Táto hodnota je z vymenovaných "
 | 
			
		||||
"hodnôt typu TpConnectionPresenceType."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:12
 | 
			
		||||
msgid ""
 | 
			
		||||
"Internally used to store the last session presence status for the user. The "
 | 
			
		||||
"value here is from the GsmPresenceStatus enumeration."
 | 
			
		||||
@@ -168,11 +160,11 @@ msgstr ""
 | 
			
		||||
"používateľa. Táto hodnota je z vymenovaných hodnôt typu "
 | 
			
		||||
"GsmPresenceStatusType."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
 | 
			
		||||
msgid "Always show the 'Log out' menuitem in the user menu."
 | 
			
		||||
msgstr "Vždy zobraziť položku „Odhlásiť sa“ v ponuke používateľa"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
 | 
			
		||||
msgid ""
 | 
			
		||||
"This key overrides the automatic hiding of the 'Log out' menuitem in single-"
 | 
			
		||||
"user, single-session situations."
 | 
			
		||||
@@ -181,7 +173,7 @@ msgstr ""
 | 
			
		||||
"s jedným používateľom alebo jednou reláciou."
 | 
			
		||||
 | 
			
		||||
# summary
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
 | 
			
		||||
msgid ""
 | 
			
		||||
"Whether to remember password for mounting encrypted or remote filesystems"
 | 
			
		||||
msgstr ""
 | 
			
		||||
@@ -189,7 +181,7 @@ msgstr ""
 | 
			
		||||
"prenosných súborových systémov"
 | 
			
		||||
 | 
			
		||||
# description
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
 | 
			
		||||
msgid ""
 | 
			
		||||
"The shell will request a password when an encrypted device or a remote "
 | 
			
		||||
"filesystem is mounted. If the password can be saved for future use a "
 | 
			
		||||
@@ -201,34 +193,42 @@ msgstr ""
 | 
			
		||||
"zobrazí sa zaškrtávacie pole „Zapamätať heslo“. Tento kľúč nastaví "
 | 
			
		||||
"predvolený stav zaškrtávacieho poľa."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
 | 
			
		||||
msgid "Show the week date in the calendar"
 | 
			
		||||
msgstr "Zobraziť čísla týždňov v kalendári"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
 | 
			
		||||
msgid "If true, display the ISO week date in the calendar."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Ak je true, zobrazí v kalendári poradie dní v týždni podľa štandardu ISO."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
 | 
			
		||||
msgid "Keybinding to open the application menu"
 | 
			
		||||
msgstr "Klávesová skratka na otvorenie ponuky aplikácií"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
 | 
			
		||||
msgid "Keybinding to open the application menu."
 | 
			
		||||
msgstr "Klávesová skratka na otvorenie ponuky aplikácií."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
 | 
			
		||||
msgid "Keybinding to open the \"Show Applications\" view"
 | 
			
		||||
msgstr "Klávesová skratka na otvorenie pohľadu „Zobraziť aplikácie“"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
 | 
			
		||||
msgid ""
 | 
			
		||||
"Keybinding to open the \"Show Applications\" view of the Activities Overview."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Klávesová skratka na otvorenie pohľadu „Zobraziť aplikácie“ v prehľade "
 | 
			
		||||
"aktivít."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
 | 
			
		||||
msgid "Keybinding to open the overview"
 | 
			
		||||
msgstr "Klávesová skratka na otvorenie prehľadu"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
 | 
			
		||||
msgid "Keybinding to open the Activities Overview."
 | 
			
		||||
msgstr "Klávesová skratka na otvorenie prehľadu aktivít."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
 | 
			
		||||
msgid "Keybinding to toggle the visibility of the message tray"
 | 
			
		||||
msgstr "Klávesová skratka na prepnutie viditeľnosti lišty správ"
 | 
			
		||||
@@ -384,7 +384,7 @@ msgstr "Rozšírenie"
 | 
			
		||||
msgid "Select an extension to configure using the combobox above."
 | 
			
		||||
msgstr "Použitím ponuky vyberte rozšírenie na nastavenie"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:405
 | 
			
		||||
#: ../js/gdm/loginDialog.js:371
 | 
			
		||||
msgid "Session…"
 | 
			
		||||
msgstr "Relácia…"
 | 
			
		||||
 | 
			
		||||
@@ -392,36 +392,43 @@ msgstr "Relácia…"
 | 
			
		||||
#. translators: this message is shown below the user list on the
 | 
			
		||||
#. login screen. It can be activated to reveal an entry for
 | 
			
		||||
#. manually entering the username.
 | 
			
		||||
#: ../js/gdm/loginDialog.js:630
 | 
			
		||||
#: ../js/gdm/loginDialog.js:601
 | 
			
		||||
msgid "Not listed?"
 | 
			
		||||
msgstr "Nie ste v zozname?"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:786 ../js/ui/components/networkAgent.js:137
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:375
 | 
			
		||||
#: ../js/gdm/loginDialog.js:776 ../js/ui/components/networkAgent.js:137
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:161 ../js/ui/endSessionDialog.js:376
 | 
			
		||||
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:399
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:99
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:96
 | 
			
		||||
#: ../js/ui/userMenu.js:938
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "Zrušiť"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:802
 | 
			
		||||
#: ../js/gdm/loginDialog.js:791
 | 
			
		||||
msgctxt "button"
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr "Prihlásiť sa"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:802
 | 
			
		||||
#: ../js/gdm/loginDialog.js:791
 | 
			
		||||
msgid "Next"
 | 
			
		||||
msgstr "Ďalej"
 | 
			
		||||
 | 
			
		||||
#. Translators: this message is shown below the username entry field
 | 
			
		||||
#. to clue the user in on how to login to the local network realm
 | 
			
		||||
#: ../js/gdm/loginDialog.js:888
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "(e.g., user or %s)"
 | 
			
		||||
msgstr "(napr., používateľ alebo %s)"
 | 
			
		||||
 | 
			
		||||
#. TTLS and PEAP are actually much more complicated, but this complication
 | 
			
		||||
#. is not visible here since we only care about phase2 authentication
 | 
			
		||||
#. (and don't even care of which one)
 | 
			
		||||
#: ../js/gdm/loginDialog.js:917 ../js/ui/components/networkAgent.js:260
 | 
			
		||||
#: ../js/gdm/loginDialog.js:892 ../js/ui/components/networkAgent.js:260
 | 
			
		||||
#: ../js/ui/components/networkAgent.js:278
 | 
			
		||||
msgid "Username: "
 | 
			
		||||
msgstr "Používateľské meno: "
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/loginDialog.js:1173
 | 
			
		||||
#: ../js/gdm/loginDialog.js:1158
 | 
			
		||||
msgid "Login Window"
 | 
			
		||||
msgstr "Prihlasovacie okno"
 | 
			
		||||
 | 
			
		||||
@@ -444,21 +451,16 @@ msgstr "Reštartovať"
 | 
			
		||||
msgid "Power Off"
 | 
			
		||||
msgstr "Vypnúť"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/util.js:249
 | 
			
		||||
#: ../js/gdm/util.js:247
 | 
			
		||||
msgid "Authentication error"
 | 
			
		||||
msgstr "Chyba pri overovaní totožnosti"
 | 
			
		||||
 | 
			
		||||
#. Translators: this message is shown below the password entry field
 | 
			
		||||
#. to indicate the user can swipe their finger instead
 | 
			
		||||
#: ../js/gdm/util.js:366
 | 
			
		||||
#: ../js/gdm/util.js:364
 | 
			
		||||
msgid "(or swipe finger)"
 | 
			
		||||
msgstr "(alebo prejdite prstom)"
 | 
			
		||||
 | 
			
		||||
#: ../js/gdm/util.js:391
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "(e.g., user or %s)"
 | 
			
		||||
msgstr "(napr., používateľ alebo %s)"
 | 
			
		||||
 | 
			
		||||
#: ../js/misc/util.js:97
 | 
			
		||||
msgid "Command not found"
 | 
			
		||||
msgstr "Príkaz nebol nájdený"
 | 
			
		||||
@@ -474,23 +476,23 @@ msgstr "Nepodarilo sa analyzovať príkaz:"
 | 
			
		||||
msgid "Execution of '%s' failed:"
 | 
			
		||||
msgstr "Spustenie „%s“ zlyhalo:"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:349
 | 
			
		||||
#: ../js/ui/appDisplay.js:361
 | 
			
		||||
msgid "Frequent"
 | 
			
		||||
msgstr "Často používané"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:356
 | 
			
		||||
#: ../js/ui/appDisplay.js:368
 | 
			
		||||
msgid "All"
 | 
			
		||||
msgstr "Všetky"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:914
 | 
			
		||||
#: ../js/ui/appDisplay.js:960
 | 
			
		||||
msgid "New Window"
 | 
			
		||||
msgstr "Nové okno"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:917 ../js/ui/dash.js:284
 | 
			
		||||
#: ../js/ui/appDisplay.js:963 ../js/ui/dash.js:284
 | 
			
		||||
msgid "Remove from Favorites"
 | 
			
		||||
msgstr "Odstrániť z obľúbených"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/appDisplay.js:918
 | 
			
		||||
#: ../js/ui/appDisplay.js:964
 | 
			
		||||
msgid "Add to Favorites"
 | 
			
		||||
msgstr "Pridať do obľúbených"
 | 
			
		||||
 | 
			
		||||
@@ -527,7 +529,7 @@ msgctxt "event list time"
 | 
			
		||||
msgid "%H\\u2236%M"
 | 
			
		||||
msgstr "%H\\u2236%M"
 | 
			
		||||
 | 
			
		||||
#. Transators: Shown in calendar event list, if 12h format,
 | 
			
		||||
#. Translators: Shown in calendar event list, if 12h format,
 | 
			
		||||
#. \u2236 is a ratio character, similar to : and \u2009 is
 | 
			
		||||
#. a thin space
 | 
			
		||||
#: ../js/ui/calendar.js:77
 | 
			
		||||
@@ -629,35 +631,35 @@ msgid "S"
 | 
			
		||||
msgstr "So"
 | 
			
		||||
 | 
			
		||||
#. Translators: Text to show if there are no events
 | 
			
		||||
#: ../js/ui/calendar.js:720
 | 
			
		||||
#: ../js/ui/calendar.js:735
 | 
			
		||||
msgid "Nothing Scheduled"
 | 
			
		||||
msgstr "Žiadne naplánované udalosti"
 | 
			
		||||
 | 
			
		||||
#. Translators: Shown on calendar heading when selected day occurs on current year
 | 
			
		||||
#: ../js/ui/calendar.js:736
 | 
			
		||||
#: ../js/ui/calendar.js:751
 | 
			
		||||
msgctxt "calendar heading"
 | 
			
		||||
msgid "%A, %B %d"
 | 
			
		||||
msgstr "%A, %e. %B"
 | 
			
		||||
 | 
			
		||||
#. Translators: Shown on calendar heading when selected day occurs on different year
 | 
			
		||||
#: ../js/ui/calendar.js:739
 | 
			
		||||
#: ../js/ui/calendar.js:754
 | 
			
		||||
msgctxt "calendar heading"
 | 
			
		||||
msgid "%A, %B %d, %Y"
 | 
			
		||||
msgstr "%A, %e. %B %Y"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:749
 | 
			
		||||
#: ../js/ui/calendar.js:764
 | 
			
		||||
msgid "Today"
 | 
			
		||||
msgstr "Dnes"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:753
 | 
			
		||||
#: ../js/ui/calendar.js:768
 | 
			
		||||
msgid "Tomorrow"
 | 
			
		||||
msgstr "Zajtra"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:764
 | 
			
		||||
#: ../js/ui/calendar.js:779
 | 
			
		||||
msgid "This week"
 | 
			
		||||
msgstr "Tento týždeň"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/calendar.js:772
 | 
			
		||||
#: ../js/ui/calendar.js:787
 | 
			
		||||
msgid "Next week"
 | 
			
		||||
msgstr "Ďalší týždeň"
 | 
			
		||||
 | 
			
		||||
@@ -683,11 +685,11 @@ msgstr "Otvoriť pomocou programu %s"
 | 
			
		||||
msgid "Eject"
 | 
			
		||||
msgstr "Vysunúť"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/keyring.js:82 ../js/ui/components/polkitAgent.js:268
 | 
			
		||||
#: ../js/ui/components/keyring.js:88 ../js/ui/components/polkitAgent.js:280
 | 
			
		||||
msgid "Password:"
 | 
			
		||||
msgstr "Heslo:"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/keyring.js:101
 | 
			
		||||
#: ../js/ui/components/keyring.js:107
 | 
			
		||||
msgid "Type again:"
 | 
			
		||||
msgstr "Zadajte znovu:"
 | 
			
		||||
 | 
			
		||||
@@ -767,16 +769,16 @@ msgstr "Heslo k mobilnej sieti"
 | 
			
		||||
msgid "A password is required to connect to '%s'."
 | 
			
		||||
msgstr "Na pripojenie k „%s“ sa požaduje heslo."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:55
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:54
 | 
			
		||||
msgid "Authentication Required"
 | 
			
		||||
msgstr "Požaduje sa overenie totožnosti"
 | 
			
		||||
 | 
			
		||||
# PŠ: ináč toto je riadna hlúposť, keďže sa pýta heslo používateľa "root"
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:93
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:92
 | 
			
		||||
msgid "Administrator"
 | 
			
		||||
msgstr "Správca"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:165
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:170
 | 
			
		||||
msgid "Authenticate"
 | 
			
		||||
msgstr "Overiť totožnosť"
 | 
			
		||||
 | 
			
		||||
@@ -784,13 +786,13 @@ msgstr "Overiť totožnosť"
 | 
			
		||||
#. * requested authentication was not gained; this can happen
 | 
			
		||||
#. * because of an authentication error (like invalid password),
 | 
			
		||||
#. * for instance.
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:256 ../js/ui/shellMountOperation.js:383
 | 
			
		||||
#: ../js/ui/components/polkitAgent.js:266 ../js/ui/shellMountOperation.js:383
 | 
			
		||||
msgid "Sorry, that didn't work. Please try again."
 | 
			
		||||
msgstr "Prepáčte, ale nezabralo to. Skúste to, prosím, znova."
 | 
			
		||||
 | 
			
		||||
# %d je datum, %t je cas
 | 
			
		||||
#. Translators: this is a filename used for screencast recording
 | 
			
		||||
#: ../js/ui/components/recorder.js:48
 | 
			
		||||
#: ../js/ui/components/recorder.js:47
 | 
			
		||||
#, no-c-format
 | 
			
		||||
msgid "Screencast from %d %t"
 | 
			
		||||
msgstr "Záznam videa obrazovky dňa %d o %t"
 | 
			
		||||
@@ -1049,22 +1051,22 @@ msgstr "Zobrazí aplikácie"
 | 
			
		||||
msgid "Dash"
 | 
			
		||||
msgstr "Dok"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/dateMenu.js:91
 | 
			
		||||
#: ../js/ui/dateMenu.js:86
 | 
			
		||||
msgid "Open Calendar"
 | 
			
		||||
msgstr "Otvoriť kalendár"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/dateMenu.js:96
 | 
			
		||||
#: ../js/ui/dateMenu.js:90
 | 
			
		||||
msgid "Open Clocks"
 | 
			
		||||
msgstr "Otvoriť hodiny"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/dateMenu.js:105
 | 
			
		||||
#: ../js/ui/dateMenu.js:97
 | 
			
		||||
msgid "Date & Time Settings"
 | 
			
		||||
msgstr "Nastavenia dátumu a času"
 | 
			
		||||
 | 
			
		||||
#. Translators: This is the date format to use when the calendar popup is
 | 
			
		||||
#. * shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
 | 
			
		||||
#.
 | 
			
		||||
#: ../js/ui/dateMenu.js:215
 | 
			
		||||
#: ../js/ui/dateMenu.js:208
 | 
			
		||||
msgid "%A %B %e, %Y"
 | 
			
		||||
msgstr "%A, %e. %B %Y"
 | 
			
		||||
 | 
			
		||||
@@ -1178,50 +1180,52 @@ msgstr "Stiahnuť a nainštalovať „%s“ z extensions.gnome.org?"
 | 
			
		||||
msgid "Keyboard"
 | 
			
		||||
msgstr "Klávesnica"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:693
 | 
			
		||||
#: ../js/ui/lookingGlass.js:689
 | 
			
		||||
msgid "No extensions installed"
 | 
			
		||||
msgstr "Žiadne nainštalované rozšírenia"
 | 
			
		||||
 | 
			
		||||
#. Translators: argument is an extension UUID.
 | 
			
		||||
#: ../js/ui/lookingGlass.js:747
 | 
			
		||||
#: ../js/ui/lookingGlass.js:743
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%s has not emitted any errors."
 | 
			
		||||
msgstr "%s nevyslal žiadnu chybu."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:753
 | 
			
		||||
#: ../js/ui/lookingGlass.js:749
 | 
			
		||||
msgid "Hide Errors"
 | 
			
		||||
msgstr "Skryť chyby"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:757 ../js/ui/lookingGlass.js:817
 | 
			
		||||
#: ../js/ui/lookingGlass.js:753 ../js/ui/lookingGlass.js:813
 | 
			
		||||
msgid "Show Errors"
 | 
			
		||||
msgstr "Zobraziť chyby"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:766
 | 
			
		||||
#: ../js/ui/lookingGlass.js:762
 | 
			
		||||
msgid "Enabled"
 | 
			
		||||
msgstr "Povolené"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:769
 | 
			
		||||
#. translators:
 | 
			
		||||
#. * The device has been disabled
 | 
			
		||||
#: ../js/ui/lookingGlass.js:765 ../src/gvc/gvc-mixer-control.c:1830
 | 
			
		||||
msgid "Disabled"
 | 
			
		||||
msgstr "Zakázané"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:771
 | 
			
		||||
#: ../js/ui/lookingGlass.js:767
 | 
			
		||||
msgid "Error"
 | 
			
		||||
msgstr "Chyba"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:773
 | 
			
		||||
#: ../js/ui/lookingGlass.js:769
 | 
			
		||||
msgid "Out of date"
 | 
			
		||||
msgstr "Neaktuálne"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:775
 | 
			
		||||
#: ../js/ui/lookingGlass.js:771
 | 
			
		||||
msgid "Downloading"
 | 
			
		||||
msgstr "Sťahuje sa"
 | 
			
		||||
 | 
			
		||||
# PK: ide tu o zdrojovy kod?
 | 
			
		||||
#: ../js/ui/lookingGlass.js:799
 | 
			
		||||
#: ../js/ui/lookingGlass.js:795
 | 
			
		||||
msgid "View Source"
 | 
			
		||||
msgstr "Zobraziť zdroj"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/lookingGlass.js:808
 | 
			
		||||
#: ../js/ui/lookingGlass.js:804
 | 
			
		||||
msgid "Web Page"
 | 
			
		||||
msgstr "Webová stránka"
 | 
			
		||||
 | 
			
		||||
@@ -1241,26 +1245,26 @@ msgstr "Vymazať správy"
 | 
			
		||||
msgid "Notification Settings"
 | 
			
		||||
msgstr "Nastavenia oznámení"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:1709
 | 
			
		||||
#: ../js/ui/messageTray.js:1707
 | 
			
		||||
msgid "No Messages"
 | 
			
		||||
msgstr "Žiadne správy"
 | 
			
		||||
 | 
			
		||||
# DK: zvazoval som pouzit "Panel správ"
 | 
			
		||||
# neviem co bude vhodnejsie ako preklad "tray"
 | 
			
		||||
#: ../js/ui/messageTray.js:1782
 | 
			
		||||
#: ../js/ui/messageTray.js:1780
 | 
			
		||||
msgid "Message Tray"
 | 
			
		||||
msgstr "Lišta správ"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/messageTray.js:2810
 | 
			
		||||
#: ../js/ui/messageTray.js:2800
 | 
			
		||||
msgid "System Information"
 | 
			
		||||
msgstr "Informácie o systéme"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/notificationDaemon.js:629 ../src/shell-app.c:374
 | 
			
		||||
#: ../js/ui/notificationDaemon.js:629 ../src/shell-app.c:378
 | 
			
		||||
msgctxt "program"
 | 
			
		||||
msgid "Unknown"
 | 
			
		||||
msgstr "Neznámy"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/overviewControls.js:463 ../js/ui/screenShield.js:149
 | 
			
		||||
#: ../js/ui/overviewControls.js:472 ../js/ui/screenShield.js:150
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%d new message"
 | 
			
		||||
msgid_plural "%d new messages"
 | 
			
		||||
@@ -1268,11 +1272,11 @@ msgstr[0] "%d nových správ"
 | 
			
		||||
msgstr[1] "%d nová správa"
 | 
			
		||||
msgstr[2] "%d nové správy"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/overview.js:84
 | 
			
		||||
#: ../js/ui/overview.js:82
 | 
			
		||||
msgid "Undo"
 | 
			
		||||
msgstr "Vrátiť"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/overview.js:129
 | 
			
		||||
#: ../js/ui/overview.js:127
 | 
			
		||||
msgid "Overview"
 | 
			
		||||
msgstr "Prehľad"
 | 
			
		||||
 | 
			
		||||
@@ -1281,21 +1285,21 @@ msgstr "Prehľad"
 | 
			
		||||
#. in the search entry when no search is
 | 
			
		||||
#. active; it should not exceed ~30
 | 
			
		||||
#. characters.
 | 
			
		||||
#: ../js/ui/overview.js:271
 | 
			
		||||
#: ../js/ui/overview.js:258
 | 
			
		||||
msgid "Type to search…"
 | 
			
		||||
msgstr "Zadajte text na vyhľadanie…"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/panel.js:612
 | 
			
		||||
#: ../js/ui/panel.js:642
 | 
			
		||||
msgid "Quit"
 | 
			
		||||
msgstr "Ukončiť"
 | 
			
		||||
 | 
			
		||||
#. Translators: If there is no suitable word for "Activities"
 | 
			
		||||
#. in your language, you can use the word for "Overview".
 | 
			
		||||
#: ../js/ui/panel.js:636
 | 
			
		||||
#: ../js/ui/panel.js:693
 | 
			
		||||
msgid "Activities"
 | 
			
		||||
msgstr "Aktivity"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/panel.js:933
 | 
			
		||||
#: ../js/ui/panel.js:989
 | 
			
		||||
msgid "Top Bar"
 | 
			
		||||
msgstr "Horná lišta"
 | 
			
		||||
 | 
			
		||||
@@ -1304,15 +1308,15 @@ msgstr "Horná lišta"
 | 
			
		||||
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
 | 
			
		||||
#. switches containing "◯" and "|"). Other values will
 | 
			
		||||
#. simply result in invisible toggle switches.
 | 
			
		||||
#: ../js/ui/popupMenu.js:727
 | 
			
		||||
#: ../js/ui/popupMenu.js:738
 | 
			
		||||
msgid "toggle-switch-us"
 | 
			
		||||
msgstr "toggle-switch-intl"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/runDialog.js:73
 | 
			
		||||
#: ../js/ui/runDialog.js:74
 | 
			
		||||
msgid "Enter a Command"
 | 
			
		||||
msgstr "Zadajte príkaz"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/runDialog.js:109
 | 
			
		||||
#: ../js/ui/runDialog.js:110
 | 
			
		||||
msgid "Close"
 | 
			
		||||
msgstr "Zavrieť"
 | 
			
		||||
 | 
			
		||||
@@ -1321,11 +1325,11 @@ msgstr "Zavrieť"
 | 
			
		||||
# v ostatnych retazcoch je pouzite %e, tak to bude asi OK
 | 
			
		||||
#. Translators: This is a time format for a date in
 | 
			
		||||
#. long format
 | 
			
		||||
#: ../js/ui/screenShield.js:86
 | 
			
		||||
#: ../js/ui/screenShield.js:87
 | 
			
		||||
msgid "%A, %B %d"
 | 
			
		||||
msgstr "%A, %e. %B"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:151
 | 
			
		||||
#: ../js/ui/screenShield.js:152
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%d new notification"
 | 
			
		||||
msgid_plural "%d new notifications"
 | 
			
		||||
@@ -1333,11 +1337,11 @@ msgstr[0] "%d nových oznámení"
 | 
			
		||||
msgstr[1] "%d nové oznámenie"
 | 
			
		||||
msgstr[2] "%d nové oznámenia"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:438 ../js/ui/userMenu.js:807
 | 
			
		||||
#: ../js/ui/screenShield.js:449 ../js/ui/userMenu.js:807
 | 
			
		||||
msgid "Lock"
 | 
			
		||||
msgstr "Uzamknúť"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:637
 | 
			
		||||
#: ../js/ui/screenShield.js:652
 | 
			
		||||
msgid "GNOME needs to lock the screen"
 | 
			
		||||
msgstr "Prostredie GNOME vyžaduje uzamknutie obrazovky"
 | 
			
		||||
 | 
			
		||||
@@ -1348,11 +1352,11 @@ msgstr "Prostredie GNOME vyžaduje uzamknutie obrazovky"
 | 
			
		||||
#.
 | 
			
		||||
#. XXX: another option is to kick the user into the gdm login
 | 
			
		||||
#. screen, where we're not affected by grabs
 | 
			
		||||
#: ../js/ui/screenShield.js:758 ../js/ui/screenShield.js:1194
 | 
			
		||||
#: ../js/ui/screenShield.js:773 ../js/ui/screenShield.js:1213
 | 
			
		||||
msgid "Unable to lock"
 | 
			
		||||
msgstr "Nepodarilo sa uzamknúť obrazovku"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/screenShield.js:759 ../js/ui/screenShield.js:1195
 | 
			
		||||
#: ../js/ui/screenShield.js:774 ../js/ui/screenShield.js:1214
 | 
			
		||||
msgid "Lock was blocked by an application"
 | 
			
		||||
msgstr "Uzamknutie bolo zablokované aplikáciou"
 | 
			
		||||
 | 
			
		||||
@@ -1364,19 +1368,19 @@ msgstr "Hľadá sa…"
 | 
			
		||||
msgid "No results."
 | 
			
		||||
msgstr "Žiadne výsledky."
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellEntry.js:29
 | 
			
		||||
#: ../js/ui/shellEntry.js:27
 | 
			
		||||
msgid "Copy"
 | 
			
		||||
msgstr "Kopírovať"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellEntry.js:34
 | 
			
		||||
#: ../js/ui/shellEntry.js:32
 | 
			
		||||
msgid "Paste"
 | 
			
		||||
msgstr "Prilepiť"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellEntry.js:106
 | 
			
		||||
#: ../js/ui/shellEntry.js:99
 | 
			
		||||
msgid "Show Text"
 | 
			
		||||
msgstr "Zobraziť text"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellEntry.js:108
 | 
			
		||||
#: ../js/ui/shellEntry.js:101
 | 
			
		||||
msgid "Hide Text"
 | 
			
		||||
msgstr "Skryť text"
 | 
			
		||||
 | 
			
		||||
@@ -1388,7 +1392,7 @@ msgstr "Heslo"
 | 
			
		||||
msgid "Remember Password"
 | 
			
		||||
msgstr "Zapamätať heslo"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:113
 | 
			
		||||
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:109
 | 
			
		||||
msgid "Unlock"
 | 
			
		||||
msgstr "Odblokovať"
 | 
			
		||||
 | 
			
		||||
@@ -1446,7 +1450,7 @@ msgstr "Veľký text"
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:28 ../js/ui/status/bluetooth.js:32
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:289 ../js/ui/status/bluetooth.js:321
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:357 ../js/ui/status/bluetooth.js:388
 | 
			
		||||
#: ../js/ui/status/network.js:826
 | 
			
		||||
#: ../js/ui/status/network.js:739
 | 
			
		||||
msgid "Bluetooth"
 | 
			
		||||
msgstr "Bluetooth"
 | 
			
		||||
 | 
			
		||||
@@ -1467,7 +1471,7 @@ msgid "Bluetooth Settings"
 | 
			
		||||
msgstr "Nastavenia Bluetooth"
 | 
			
		||||
 | 
			
		||||
#. TRANSLATORS: this means that bluetooth was disabled by hardware rfkill
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:104 ../js/ui/status/network.js:178
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:104 ../js/ui/status/network.js:142
 | 
			
		||||
msgid "hardware disabled"
 | 
			
		||||
msgstr "hardvér zakázaný"
 | 
			
		||||
 | 
			
		||||
@@ -1475,12 +1479,12 @@ msgstr "hardvér zakázaný"
 | 
			
		||||
msgid "Connection"
 | 
			
		||||
msgstr "Pripojenie"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:208 ../js/ui/status/network.js:460
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:208 ../js/ui/status/network.js:404
 | 
			
		||||
msgid "disconnecting..."
 | 
			
		||||
msgstr "odpája sa…"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:221 ../js/ui/status/network.js:466
 | 
			
		||||
#: ../js/ui/status/network.js:1546
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:221 ../js/ui/status/network.js:410
 | 
			
		||||
#: ../js/ui/status/network.js:1343
 | 
			
		||||
msgid "connecting..."
 | 
			
		||||
msgstr "pripája sa…"
 | 
			
		||||
 | 
			
		||||
@@ -1536,8 +1540,9 @@ msgstr "Zariadenie %s sa chce spárovať s týmto počítačom"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:366
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Please confirm whether the PIN '%06d' matches the one on the device."
 | 
			
		||||
msgstr "Prosím, potvrďte, či sa PIN „%06d“ zhoduje s tým na zariadení."
 | 
			
		||||
msgid ""
 | 
			
		||||
"Please confirm whether the Passkey '%06d' matches the one on the device."
 | 
			
		||||
msgstr "Prosím, potvrďte, či sa heslo „%06d“ zhoduje s tým na zariadení."
 | 
			
		||||
 | 
			
		||||
#. Translators: this is the verb, not the noun
 | 
			
		||||
#: ../js/ui/status/bluetooth.js:369
 | 
			
		||||
@@ -1574,117 +1579,91 @@ msgid "Volume, network, battery"
 | 
			
		||||
msgstr "Hlasitosť, sieť, batéria"
 | 
			
		||||
 | 
			
		||||
# zariadenie
 | 
			
		||||
#: ../js/ui/status/network.js:104
 | 
			
		||||
#: ../js/ui/status/network.js:75
 | 
			
		||||
msgid "<unknown>"
 | 
			
		||||
msgstr "<neznáme>"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:127
 | 
			
		||||
msgid "Wi-Fi"
 | 
			
		||||
msgstr "Wi-Fi"
 | 
			
		||||
 | 
			
		||||
#. Translators: this indicates that wireless or wwan is disabled by hardware killswitch
 | 
			
		||||
#: ../js/ui/status/network.js:200
 | 
			
		||||
#: ../js/ui/status/network.js:164
 | 
			
		||||
msgid "disabled"
 | 
			
		||||
msgstr "zakázané"
 | 
			
		||||
 | 
			
		||||
#. Translators: this is for network devices that are physically present but are not
 | 
			
		||||
#. under NetworkManager's control (and thus cannot be used in the menu)
 | 
			
		||||
#: ../js/ui/status/network.js:458
 | 
			
		||||
#: ../js/ui/status/network.js:402
 | 
			
		||||
msgid "unmanaged"
 | 
			
		||||
msgstr "nespravované"
 | 
			
		||||
 | 
			
		||||
#. Translators: this is for network connections that require some kind of key or password
 | 
			
		||||
#: ../js/ui/status/network.js:469 ../js/ui/status/network.js:1549
 | 
			
		||||
#: ../js/ui/status/network.js:413 ../js/ui/status/network.js:1346
 | 
			
		||||
msgid "authentication required"
 | 
			
		||||
msgstr "požaduje sa overenie totožnosti"
 | 
			
		||||
 | 
			
		||||
#. Translators: this is for devices that require some kind of firmware or kernel
 | 
			
		||||
#. module, which is missing
 | 
			
		||||
#: ../js/ui/status/network.js:479
 | 
			
		||||
#: ../js/ui/status/network.js:423
 | 
			
		||||
msgid "firmware missing"
 | 
			
		||||
msgstr "chýba firmvér"
 | 
			
		||||
 | 
			
		||||
#. Translators: this is for wired network devices that are physically disconnected
 | 
			
		||||
#: ../js/ui/status/network.js:486
 | 
			
		||||
#: ../js/ui/status/network.js:430
 | 
			
		||||
msgid "cable unplugged"
 | 
			
		||||
msgstr "kábel odpojený"
 | 
			
		||||
 | 
			
		||||
#. Translators: this is for a network device that cannot be activated (for example it
 | 
			
		||||
#. is disabled by rfkill, or it has no coverage
 | 
			
		||||
#: ../js/ui/status/network.js:491
 | 
			
		||||
#: ../js/ui/status/network.js:435
 | 
			
		||||
msgid "unavailable"
 | 
			
		||||
msgstr "nedostupné"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:493 ../js/ui/status/network.js:1551
 | 
			
		||||
#: ../js/ui/status/network.js:437 ../js/ui/status/network.js:1348
 | 
			
		||||
msgid "connection failed"
 | 
			
		||||
msgstr "pripojenie zlyhalo"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:552 ../js/ui/status/network.js:1435
 | 
			
		||||
#: ../js/ui/status/network.js:1627
 | 
			
		||||
#: ../js/ui/status/network.js:490 ../js/ui/status/network.js:1236
 | 
			
		||||
#: ../js/ui/status/network.js:1424
 | 
			
		||||
msgid "More…"
 | 
			
		||||
msgstr "Viac…"
 | 
			
		||||
 | 
			
		||||
#. TRANSLATORS: this is the indication that a connection for another logged in user is active,
 | 
			
		||||
#. and we cannot access its settings (including the name)
 | 
			
		||||
#: ../js/ui/status/network.js:588 ../js/ui/status/network.js:1365
 | 
			
		||||
#: ../js/ui/status/network.js:518 ../js/ui/status/network.js:1191
 | 
			
		||||
msgid "Connected (private)"
 | 
			
		||||
msgstr "Pripojené (súkromne)"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:667
 | 
			
		||||
#: ../js/ui/status/network.js:597
 | 
			
		||||
msgid "Wired"
 | 
			
		||||
msgstr "Drôtové pripojenie"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:668
 | 
			
		||||
msgid "Auto Ethernet"
 | 
			
		||||
msgstr "Automatický ethernet"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:695
 | 
			
		||||
#: ../js/ui/status/network.js:611
 | 
			
		||||
msgid "Mobile broadband"
 | 
			
		||||
msgstr "Širokopásmové pripojenie"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:728
 | 
			
		||||
msgid "Auto broadband"
 | 
			
		||||
msgstr "Automatické širokopásmové pripojenie"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:731
 | 
			
		||||
msgid "Auto dial-up"
 | 
			
		||||
msgstr "Automatické vytáčané pripojenie"
 | 
			
		||||
 | 
			
		||||
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
 | 
			
		||||
#: ../js/ui/status/network.js:861 ../js/ui/status/network.js:1382
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Auto %s"
 | 
			
		||||
msgstr "Automatické pripojenie %s"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:863
 | 
			
		||||
msgid "Auto bluetooth"
 | 
			
		||||
msgstr "Automatický bluetooth"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:1384
 | 
			
		||||
msgid "Auto wireless"
 | 
			
		||||
msgstr "Automatická bezdrôtová sieť"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:1729
 | 
			
		||||
#: ../js/ui/status/network.js:1522
 | 
			
		||||
msgid "Enable networking"
 | 
			
		||||
msgstr "Povoliť sieť"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:1771
 | 
			
		||||
msgid "Wi-Fi"
 | 
			
		||||
msgstr "Wi-Fi"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:1790
 | 
			
		||||
#: ../js/ui/status/network.js:1583
 | 
			
		||||
msgid "Network Settings"
 | 
			
		||||
msgstr "Nastavenia siete"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:1807
 | 
			
		||||
#: ../js/ui/status/network.js:1600
 | 
			
		||||
msgid "Network Manager"
 | 
			
		||||
msgstr "Správca siete"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:1897
 | 
			
		||||
#: ../js/ui/status/network.js:1690
 | 
			
		||||
msgid "Connection failed"
 | 
			
		||||
msgstr "Pripojenie zlyhalo"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:1898
 | 
			
		||||
#: ../js/ui/status/network.js:1691
 | 
			
		||||
msgid "Activation of network connection failed"
 | 
			
		||||
msgstr "Aktivácia pripojenia k sieti zlyhala"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/status/network.js:2276
 | 
			
		||||
#: ../js/ui/status/network.js:2047
 | 
			
		||||
msgid "Networking is disabled"
 | 
			
		||||
msgstr "Sieť je zakázaná"
 | 
			
		||||
 | 
			
		||||
@@ -1802,11 +1781,11 @@ msgstr "Hlasitosť"
 | 
			
		||||
msgid "Microphone"
 | 
			
		||||
msgstr "Mikrofón"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/unlockDialog.js:124
 | 
			
		||||
#: ../js/ui/unlockDialog.js:120
 | 
			
		||||
msgid "Log in as another user"
 | 
			
		||||
msgstr "Prihlásiť ako iný používateľ"
 | 
			
		||||
 | 
			
		||||
#: ../js/ui/unlockDialog.js:145
 | 
			
		||||
#: ../js/ui/unlockDialog.js:141
 | 
			
		||||
msgid "Unlock Window"
 | 
			
		||||
msgstr "Odomykacie okno"
 | 
			
		||||
 | 
			
		||||
@@ -1915,32 +1894,56 @@ msgstr "Program „%s“ je pripravený"
 | 
			
		||||
msgid "Evolution Calendar"
 | 
			
		||||
msgstr "Kalendár Evolution"
 | 
			
		||||
 | 
			
		||||
#: ../src/main.c:347
 | 
			
		||||
#. translators:
 | 
			
		||||
#. * The number of sound outputs on a particular device
 | 
			
		||||
#: ../src/gvc/gvc-mixer-control.c:1837
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%u Output"
 | 
			
		||||
msgid_plural "%u Outputs"
 | 
			
		||||
msgstr[0] "%u výstupov"
 | 
			
		||||
msgstr[1] "%u výstup"
 | 
			
		||||
msgstr[2] "%u výstupy"
 | 
			
		||||
 | 
			
		||||
#. translators:
 | 
			
		||||
#. * The number of sound inputs on a particular device
 | 
			
		||||
#: ../src/gvc/gvc-mixer-control.c:1847
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%u Input"
 | 
			
		||||
msgid_plural "%u Inputs"
 | 
			
		||||
msgstr[0] "%u vstupov"
 | 
			
		||||
msgstr[1] "%u vstup"
 | 
			
		||||
msgstr[2] "%u vstupy"
 | 
			
		||||
 | 
			
		||||
#: ../src/gvc/gvc-mixer-control.c:2373
 | 
			
		||||
msgid "System Sounds"
 | 
			
		||||
msgstr "Systémové zvuky"
 | 
			
		||||
 | 
			
		||||
#: ../src/main.c:372
 | 
			
		||||
msgid "Print version"
 | 
			
		||||
msgstr "Verzia pre tlač"
 | 
			
		||||
 | 
			
		||||
#: ../src/main.c:353
 | 
			
		||||
#: ../src/main.c:378
 | 
			
		||||
msgid "Mode used by GDM for login screen"
 | 
			
		||||
msgstr "Režim používaný GDM pre prihlasovaciu obrazovku"
 | 
			
		||||
 | 
			
		||||
#: ../src/main.c:359
 | 
			
		||||
#: ../src/main.c:384
 | 
			
		||||
msgid "Use a specific mode, e.g. \"gdm\" for login screen"
 | 
			
		||||
msgstr "Použitie zvláštneho režimu, napr. „gdm“  pre prihlasovaciu obrazovku"
 | 
			
		||||
 | 
			
		||||
#: ../src/main.c:365
 | 
			
		||||
#: ../src/main.c:390
 | 
			
		||||
msgid "List possible modes"
 | 
			
		||||
msgstr "Zoznam možných režimov"
 | 
			
		||||
 | 
			
		||||
#: ../src/shell-app.c:622
 | 
			
		||||
#: ../src/shell-app.c:626
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Failed to launch '%s'"
 | 
			
		||||
msgstr "Zlyhalo spustenie „%s“"
 | 
			
		||||
 | 
			
		||||
#: ../src/shell-keyring-prompt.c:708
 | 
			
		||||
#: ../src/shell-keyring-prompt.c:714
 | 
			
		||||
msgid "Passwords do not match."
 | 
			
		||||
msgstr "Heslá sa nezhodujú."
 | 
			
		||||
 | 
			
		||||
#: ../src/shell-keyring-prompt.c:716
 | 
			
		||||
#: ../src/shell-keyring-prompt.c:722
 | 
			
		||||
msgid "Password cannot be blank"
 | 
			
		||||
msgstr "Heslo nemôže byť prázdne"
 | 
			
		||||
 | 
			
		||||
@@ -1948,3 +1951,35 @@ msgstr "Heslo nemôže byť prázdne"
 | 
			
		||||
#: ../src/shell-polkit-authentication-agent.c:343
 | 
			
		||||
msgid "Authentication dialog was dismissed by the user"
 | 
			
		||||
msgstr "Dialógové okno overenia totožnosti bolo zatvorené používateľom"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Whether to collect stats about applications usage"
 | 
			
		||||
#~ msgstr "Či sa majú zhromažďovať štatistické údaje o používaní aplikácií"
 | 
			
		||||
 | 
			
		||||
#~ msgid ""
 | 
			
		||||
#~ "The shell normally monitors active applications in order to present the "
 | 
			
		||||
#~ "most used ones (e.g. in launchers). While this data will be kept private, "
 | 
			
		||||
#~ "you may want to disable this for privacy reasons. Please note that doing "
 | 
			
		||||
#~ "so won't remove already saved data."
 | 
			
		||||
#~ msgstr ""
 | 
			
		||||
#~ "Prostredie shell obvykle sleduje aktívne aplikácie, aby mohlo ponúkať "
 | 
			
		||||
#~ "najpoužívanejšie z nich (napr. v spúšťačoch). Aj keď sú tieto údaje "
 | 
			
		||||
#~ "uchovávané v tajnosti, môžete ich kvôli lepšej ochrane súkromia zakázať. "
 | 
			
		||||
#~ "Ak tak urobíte, údaje, ktoré už boli uložené, zostanú zachované."
 | 
			
		||||
 | 
			
		||||
#~ msgid "Auto Ethernet"
 | 
			
		||||
#~ msgstr "Automatický ethernet"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Auto broadband"
 | 
			
		||||
#~ msgstr "Automatické širokopásmové pripojenie"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Auto dial-up"
 | 
			
		||||
#~ msgstr "Automatické vytáčané pripojenie"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Auto %s"
 | 
			
		||||
#~ msgstr "Automatické pripojenie %s"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Auto bluetooth"
 | 
			
		||||
#~ msgstr "Automatický bluetooth"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Auto wireless"
 | 
			
		||||
#~ msgstr "Automatická bezdrôtová sieť"
 | 
			
		||||
 
 | 
			
		||||
@@ -129,13 +129,18 @@ shell_public_headers_h =		\
 | 
			
		||||
	shell-wm.h			\
 | 
			
		||||
	shell-xfixes-cursor.h
 | 
			
		||||
 | 
			
		||||
shell_private_sources = \
 | 
			
		||||
	gactionmuxer.h			\
 | 
			
		||||
	gactionmuxer.c			\
 | 
			
		||||
	gactionobservable.h		\
 | 
			
		||||
	gactionobservable.c		\
 | 
			
		||||
	gactionobserver.h		\
 | 
			
		||||
	gactionobserver.c
 | 
			
		||||
shell_private_sources = 		\
 | 
			
		||||
	gtkactionmuxer.h		\
 | 
			
		||||
	gtkactionmuxer.c		\
 | 
			
		||||
	gtkactionobservable.h		\
 | 
			
		||||
	gtkactionobservable.c		\
 | 
			
		||||
	gtkactionobserver.h		\
 | 
			
		||||
	gtkactionobserver.c		\
 | 
			
		||||
	gtkmenutrackeritem.c		\
 | 
			
		||||
	gtkmenutrackeritem.h		\
 | 
			
		||||
	gtkmenutracker.c		\
 | 
			
		||||
	gtkmenutracker.h		\
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
libgnome_shell_la_SOURCES =		\
 | 
			
		||||
	$(shell_built_sources)		\
 | 
			
		||||
@@ -158,6 +163,8 @@ libgnome_shell_la_SOURCES =		\
 | 
			
		||||
	shell-invert-lightness-effect.c	\
 | 
			
		||||
	shell-keyring-prompt.h		\
 | 
			
		||||
	shell-keyring-prompt.c		\
 | 
			
		||||
	shell-menu-tracker.c		\
 | 
			
		||||
	shell-menu-tracker.h		\
 | 
			
		||||
	shell-mount-operation.c		\
 | 
			
		||||
	shell-network-agent.c		\
 | 
			
		||||
	shell-perf-log.c		\
 | 
			
		||||
@@ -286,12 +293,34 @@ libgnome_shell_la_LIBADD =		\
 | 
			
		||||
 | 
			
		||||
libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
 | 
			
		||||
 | 
			
		||||
Shell-0.1.gir: libgnome-shell.la St-1.0.gir
 | 
			
		||||
ShellMenu-0.1.gir: libgnome-shell.la
 | 
			
		||||
ShellMenu_0_1_gir_INCLUDES = Gio-2.0
 | 
			
		||||
ShellMenu_0_1_gir_CFLAGS = $(libgnome_shell_la_CPPFLAGS) -I $(srcdir)
 | 
			
		||||
ShellMenu_0_1_gir_LIBS = libgnome-shell.la
 | 
			
		||||
ShellMenu_0_1_gir_FILES = \
 | 
			
		||||
	gtkactionmuxer.h		\
 | 
			
		||||
	gtkactionmuxer.c		\
 | 
			
		||||
	gtkactionobservable.h		\
 | 
			
		||||
	gtkactionobservable.c		\
 | 
			
		||||
	gtkactionobserver.h		\
 | 
			
		||||
	gtkactionobserver.c		\
 | 
			
		||||
	gtkmenutrackeritem.c		\
 | 
			
		||||
	gtkmenutrackeritem.h		\
 | 
			
		||||
	$(NULL)
 | 
			
		||||
ShellMenu_0_1_gir_SCANNERFLAGS = 	\
 | 
			
		||||
	--namespace=ShellMenu --identifier-prefix=Gtk \
 | 
			
		||||
	$(if $(BLUETOOTH_DIR),-L $(BLUETOOTH_DIR),)
 | 
			
		||||
INTROSPECTION_GIRS += ShellMenu-0.1.gir
 | 
			
		||||
CLEANFILES += ShellMenu-0.1.gir
 | 
			
		||||
 | 
			
		||||
Shell-0.1.gir: libgnome-shell.la St-1.0.gir ShellMenu-0.1.gir
 | 
			
		||||
Shell_0_1_gir_INCLUDES = Clutter-1.0 ClutterX11-1.0 Meta-3.0 TelepathyGLib-0.12 Soup-2.4 GMenu-3.0 NetworkManager-1.0 NMClient-1.0
 | 
			
		||||
Shell_0_1_gir_CFLAGS = $(libgnome_shell_la_CPPFLAGS) -I $(srcdir)
 | 
			
		||||
Shell_0_1_gir_LIBS = libgnome-shell.la
 | 
			
		||||
Shell_0_1_gir_FILES = $(libgnome_shell_la_gir_sources)
 | 
			
		||||
Shell_0_1_gir_SCANNERFLAGS = --include-uninstalled=$(builddir)/St-1.0.gir \
 | 
			
		||||
Shell_0_1_gir_SCANNERFLAGS =	\
 | 
			
		||||
	--include-uninstalled=$(builddir)/St-1.0.gir \
 | 
			
		||||
	--include-uninstalled=$(builddir)/ShellMenu-0.1.gir \
 | 
			
		||||
	--add-include-path=$(MUTTER_GIR_DIR) $(if $(BLUETOOTH_DIR),-L $(BLUETOOTH_DIR),)
 | 
			
		||||
INTROSPECTION_GIRS += Shell-0.1.gir
 | 
			
		||||
CLEANFILES += Shell-0.1.gir
 | 
			
		||||
 
 | 
			
		||||
@@ -1,546 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2011 Canonical Limited
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the licence, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the
 | 
			
		||||
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 | 
			
		||||
 * Boston, MA 02111-1307, USA.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Ryan Lortie <desrt@desrt.ca>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "gactionmuxer.h"
 | 
			
		||||
 | 
			
		||||
#include "gactionobservable.h"
 | 
			
		||||
#include "gactionobserver.h"
 | 
			
		||||
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * SECTION:gactionmuxer
 | 
			
		||||
 * @short_description: Aggregate and monitor several action groups
 | 
			
		||||
 *
 | 
			
		||||
 * #GActionMuxer is a #GActionGroup and #GActionObservable that is
 | 
			
		||||
 * capable of containing other #GActionGroup instances.
 | 
			
		||||
 *
 | 
			
		||||
 * The typical use is aggregating all of the actions applicable to a
 | 
			
		||||
 * particular context into a single action group, with namespacing.
 | 
			
		||||
 *
 | 
			
		||||
 * Consider the case of two action groups -- one containing actions
 | 
			
		||||
 * applicable to an entire application (such as 'quit') and one
 | 
			
		||||
 * containing actions applicable to a particular window in the
 | 
			
		||||
 * application (such as 'fullscreen').
 | 
			
		||||
 *
 | 
			
		||||
 * In this case, each of these action groups could be added to a
 | 
			
		||||
 * #GActionMuxer with the prefixes "app" and "win", respectively.  This
 | 
			
		||||
 * would expose the actions as "app.quit" and "win.fullscreen" on the
 | 
			
		||||
 * #GActionGroup interface presented by the #GActionMuxer.
 | 
			
		||||
 *
 | 
			
		||||
 * Activations and state change requests on the #GActionMuxer are wired
 | 
			
		||||
 * through to the underlying action group in the expected way.
 | 
			
		||||
 *
 | 
			
		||||
 * This class is typically only used at the site of "consumption" of
 | 
			
		||||
 * actions (eg: when displaying a menu that contains many actions on
 | 
			
		||||
 * different objects).
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static void     g_action_muxer_group_iface_init         (GActionGroupInterface      *iface);
 | 
			
		||||
static void     g_action_muxer_observable_iface_init    (GActionObservableInterface *iface);
 | 
			
		||||
 | 
			
		||||
typedef GObjectClass GActionMuxerClass;
 | 
			
		||||
 | 
			
		||||
struct _GActionMuxer
 | 
			
		||||
{
 | 
			
		||||
  GObject parent_instance;
 | 
			
		||||
 | 
			
		||||
  GHashTable *actions;
 | 
			
		||||
  GHashTable *groups;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE_WITH_CODE (GActionMuxer, g_action_muxer, G_TYPE_OBJECT,
 | 
			
		||||
                         G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, g_action_muxer_group_iface_init)
 | 
			
		||||
                         G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_OBSERVABLE, g_action_muxer_observable_iface_init))
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  GActionMuxer *muxer;
 | 
			
		||||
  GSList       *watchers;
 | 
			
		||||
  gchar        *fullname;
 | 
			
		||||
} Action;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  GActionMuxer *muxer;
 | 
			
		||||
  GActionGroup *group;
 | 
			
		||||
  gchar        *prefix;
 | 
			
		||||
  gulong        handler_ids[4];
 | 
			
		||||
} Group;
 | 
			
		||||
 | 
			
		||||
static gchar **
 | 
			
		||||
g_action_muxer_list_actions (GActionGroup *action_group)
 | 
			
		||||
{
 | 
			
		||||
  GActionMuxer *muxer = G_ACTION_MUXER (action_group);
 | 
			
		||||
  GHashTableIter iter;
 | 
			
		||||
  gchar *key;
 | 
			
		||||
  gchar **keys;
 | 
			
		||||
  gsize i;
 | 
			
		||||
 | 
			
		||||
  keys = g_new (gchar *, g_hash_table_size (muxer->actions) + 1);
 | 
			
		||||
 | 
			
		||||
  i = 0;
 | 
			
		||||
  g_hash_table_iter_init (&iter, muxer->actions);
 | 
			
		||||
  while (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL))
 | 
			
		||||
    keys[i++] = g_strdup (key);
 | 
			
		||||
  keys[i] = NULL;
 | 
			
		||||
 | 
			
		||||
  return keys;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Group *
 | 
			
		||||
g_action_muxer_find_group (GActionMuxer  *muxer,
 | 
			
		||||
                              const gchar     **name)
 | 
			
		||||
{
 | 
			
		||||
  const gchar *dot;
 | 
			
		||||
  gchar *prefix;
 | 
			
		||||
  Group *group;
 | 
			
		||||
 | 
			
		||||
  dot = strchr (*name, '.');
 | 
			
		||||
 | 
			
		||||
  if (!dot)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  prefix = g_strndup (*name, dot - *name);
 | 
			
		||||
  group = g_hash_table_lookup (muxer->groups, prefix);
 | 
			
		||||
  g_free (prefix);
 | 
			
		||||
 | 
			
		||||
  *name = dot + 1;
 | 
			
		||||
 | 
			
		||||
  return group;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Action *
 | 
			
		||||
g_action_muxer_lookup_action (GActionMuxer  *muxer,
 | 
			
		||||
                              const gchar   *prefix,
 | 
			
		||||
                              const gchar   *action_name,
 | 
			
		||||
                              gchar        **fullname)
 | 
			
		||||
{
 | 
			
		||||
  Action *action;
 | 
			
		||||
 | 
			
		||||
  *fullname = g_strconcat (prefix, ".", action_name, NULL);
 | 
			
		||||
  action = g_hash_table_lookup (muxer->actions, *fullname);
 | 
			
		||||
 | 
			
		||||
  return action;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
g_action_muxer_action_enabled_changed (GActionGroup *action_group,
 | 
			
		||||
                                       const gchar  *action_name,
 | 
			
		||||
                                       gboolean      enabled,
 | 
			
		||||
                                       gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  Group *group = user_data;
 | 
			
		||||
  gchar *fullname;
 | 
			
		||||
  Action *action;
 | 
			
		||||
  GSList *node;
 | 
			
		||||
 | 
			
		||||
  action = g_action_muxer_lookup_action (group->muxer, group->prefix, action_name, &fullname);
 | 
			
		||||
  for (node = action ? action->watchers : NULL; node; node = node->next)
 | 
			
		||||
    g_action_observer_action_enabled_changed (node->data, G_ACTION_OBSERVABLE (group->muxer), fullname, enabled);
 | 
			
		||||
  g_action_group_action_enabled_changed (G_ACTION_GROUP (group->muxer), fullname, enabled);
 | 
			
		||||
  g_free (fullname);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
g_action_muxer_action_state_changed (GActionGroup *action_group,
 | 
			
		||||
                                     const gchar  *action_name,
 | 
			
		||||
                                     GVariant     *state,
 | 
			
		||||
                                     gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  Group *group = user_data;
 | 
			
		||||
  gchar *fullname;
 | 
			
		||||
  Action *action;
 | 
			
		||||
  GSList *node;
 | 
			
		||||
 | 
			
		||||
  action = g_action_muxer_lookup_action (group->muxer, group->prefix, action_name, &fullname);
 | 
			
		||||
  for (node = action ? action->watchers : NULL; node; node = node->next)
 | 
			
		||||
    g_action_observer_action_state_changed (node->data, G_ACTION_OBSERVABLE (group->muxer), fullname, state);
 | 
			
		||||
  g_action_group_action_state_changed (G_ACTION_GROUP (group->muxer), fullname, state);
 | 
			
		||||
  g_free (fullname);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
g_action_muxer_action_added (GActionGroup *action_group,
 | 
			
		||||
                             const gchar  *action_name,
 | 
			
		||||
                             gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  const GVariantType *parameter_type;
 | 
			
		||||
  Group *group = user_data;
 | 
			
		||||
  gboolean enabled;
 | 
			
		||||
  GVariant *state;
 | 
			
		||||
 | 
			
		||||
  if (g_action_group_query_action (group->group, action_name, &enabled, ¶meter_type, NULL, NULL, &state))
 | 
			
		||||
    {
 | 
			
		||||
      gchar *fullname;
 | 
			
		||||
      Action *action;
 | 
			
		||||
      GSList *node;
 | 
			
		||||
 | 
			
		||||
      action = g_action_muxer_lookup_action (group->muxer, group->prefix, action_name, &fullname);
 | 
			
		||||
 | 
			
		||||
      for (node = action ? action->watchers : NULL; node; node = node->next)
 | 
			
		||||
        g_action_observer_action_added (node->data,
 | 
			
		||||
                                        G_ACTION_OBSERVABLE (group->muxer),
 | 
			
		||||
                                        fullname, parameter_type, enabled, state);
 | 
			
		||||
 | 
			
		||||
      g_action_group_action_added (G_ACTION_GROUP (group->muxer), fullname);
 | 
			
		||||
 | 
			
		||||
      if (state)
 | 
			
		||||
        g_variant_unref (state);
 | 
			
		||||
 | 
			
		||||
      g_free (fullname);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
g_action_muxer_action_removed (GActionGroup *action_group,
 | 
			
		||||
                               const gchar  *action_name,
 | 
			
		||||
                               gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  Group *group = user_data;
 | 
			
		||||
  gchar *fullname;
 | 
			
		||||
  Action *action;
 | 
			
		||||
  GSList *node;
 | 
			
		||||
 | 
			
		||||
  action = g_action_muxer_lookup_action (group->muxer, group->prefix, action_name, &fullname);
 | 
			
		||||
  for (node = action ? action->watchers : NULL; node; node = node->next)
 | 
			
		||||
    g_action_observer_action_removed (node->data, G_ACTION_OBSERVABLE (group->muxer), fullname);
 | 
			
		||||
  g_action_group_action_removed (G_ACTION_GROUP (group->muxer), fullname);
 | 
			
		||||
  g_free (fullname);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
g_action_muxer_query_action (GActionGroup        *action_group,
 | 
			
		||||
                             const gchar         *action_name,
 | 
			
		||||
                             gboolean            *enabled,
 | 
			
		||||
                             const GVariantType **parameter_type,
 | 
			
		||||
                             const GVariantType **state_type,
 | 
			
		||||
                             GVariant           **state_hint,
 | 
			
		||||
                             GVariant           **state)
 | 
			
		||||
{
 | 
			
		||||
  GActionMuxer *muxer = G_ACTION_MUXER (action_group);
 | 
			
		||||
  Group *group;
 | 
			
		||||
 | 
			
		||||
  group = g_action_muxer_find_group (muxer, &action_name);
 | 
			
		||||
 | 
			
		||||
  if (!group)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  return g_action_group_query_action (group->group, action_name, enabled,
 | 
			
		||||
                                      parameter_type, state_type, state_hint, state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GVariant *
 | 
			
		||||
get_platform_data (void)
 | 
			
		||||
{
 | 
			
		||||
  gchar time[32];
 | 
			
		||||
  GVariantBuilder *builder;
 | 
			
		||||
  GVariant *result;
 | 
			
		||||
 | 
			
		||||
  g_snprintf (time, 32, "_TIME%d", clutter_get_current_event_time ());
 | 
			
		||||
 | 
			
		||||
  builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
 | 
			
		||||
 | 
			
		||||
  g_variant_builder_add (builder, "{sv}", "desktop-startup-id",
 | 
			
		||||
                         g_variant_new_string (time));
 | 
			
		||||
 | 
			
		||||
  result = g_variant_builder_end (builder);
 | 
			
		||||
  g_variant_builder_unref (builder);
 | 
			
		||||
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
g_action_muxer_activate_action (GActionGroup *action_group,
 | 
			
		||||
                                const gchar  *action_name,
 | 
			
		||||
                                GVariant     *parameter)
 | 
			
		||||
{
 | 
			
		||||
  GActionMuxer *muxer = G_ACTION_MUXER (action_group);
 | 
			
		||||
  Group *group;
 | 
			
		||||
 | 
			
		||||
  group = g_action_muxer_find_group (muxer, &action_name);
 | 
			
		||||
 | 
			
		||||
  if (group)
 | 
			
		||||
    {
 | 
			
		||||
      if (G_IS_REMOTE_ACTION_GROUP (group->group))
 | 
			
		||||
        g_remote_action_group_activate_action_full (G_REMOTE_ACTION_GROUP (group->group),
 | 
			
		||||
                                                    action_name,
 | 
			
		||||
                                                    parameter,
 | 
			
		||||
                                                    get_platform_data ());
 | 
			
		||||
      else
 | 
			
		||||
        g_action_group_activate_action (group->group, action_name, parameter);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
g_action_muxer_change_action_state (GActionGroup *action_group,
 | 
			
		||||
                                    const gchar  *action_name,
 | 
			
		||||
                                    GVariant     *state)
 | 
			
		||||
{
 | 
			
		||||
  GActionMuxer *muxer = G_ACTION_MUXER (action_group);
 | 
			
		||||
  Group *group;
 | 
			
		||||
 | 
			
		||||
  group = g_action_muxer_find_group (muxer, &action_name);
 | 
			
		||||
 | 
			
		||||
  if (group)
 | 
			
		||||
    {
 | 
			
		||||
      if (G_IS_REMOTE_ACTION_GROUP (group->group))
 | 
			
		||||
        g_remote_action_group_change_action_state_full (G_REMOTE_ACTION_GROUP (group->group),
 | 
			
		||||
                                                        action_name,
 | 
			
		||||
                                                        state,
 | 
			
		||||
                                                        get_platform_data ());
 | 
			
		||||
      else
 | 
			
		||||
        g_action_group_change_action_state (group->group, action_name, state);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
g_action_muxer_unregister_internal (Action   *action,
 | 
			
		||||
                                    gpointer  observer)
 | 
			
		||||
{
 | 
			
		||||
  GActionMuxer *muxer = action->muxer;
 | 
			
		||||
  GSList **ptr;
 | 
			
		||||
 | 
			
		||||
  for (ptr = &action->watchers; *ptr; ptr = &(*ptr)->next)
 | 
			
		||||
    if ((*ptr)->data == observer)
 | 
			
		||||
      {
 | 
			
		||||
        *ptr = g_slist_remove (*ptr, observer);
 | 
			
		||||
 | 
			
		||||
        if (action->watchers == NULL)
 | 
			
		||||
          {
 | 
			
		||||
            g_hash_table_remove (muxer->actions, action->fullname);
 | 
			
		||||
            g_free (action->fullname);
 | 
			
		||||
 | 
			
		||||
            g_slice_free (Action, action);
 | 
			
		||||
 | 
			
		||||
            g_object_unref (muxer);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
g_action_muxer_weak_notify (gpointer  data,
 | 
			
		||||
                            GObject  *where_the_object_was)
 | 
			
		||||
{
 | 
			
		||||
  Action *action = data;
 | 
			
		||||
 | 
			
		||||
  g_action_muxer_unregister_internal (action, where_the_object_was);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
g_action_muxer_register_observer (GActionObservable *observable,
 | 
			
		||||
                                  const gchar       *name,
 | 
			
		||||
                                  GActionObserver   *observer)
 | 
			
		||||
{
 | 
			
		||||
  GActionMuxer *muxer = G_ACTION_MUXER (observable);
 | 
			
		||||
  Action *action;
 | 
			
		||||
 | 
			
		||||
  action = g_hash_table_lookup (muxer->actions, name);
 | 
			
		||||
 | 
			
		||||
  if (action == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      action = g_slice_new (Action);
 | 
			
		||||
      action->muxer = g_object_ref (muxer);
 | 
			
		||||
      action->fullname = g_strdup (name);
 | 
			
		||||
      action->watchers = NULL;
 | 
			
		||||
 | 
			
		||||
      g_hash_table_insert (muxer->actions, action->fullname, action);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  action->watchers = g_slist_prepend (action->watchers, observer);
 | 
			
		||||
  g_object_weak_ref (G_OBJECT (observer), g_action_muxer_weak_notify, action);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
g_action_muxer_unregister_observer (GActionObservable *observable,
 | 
			
		||||
                                    const gchar       *name,
 | 
			
		||||
                                    GActionObserver   *observer)
 | 
			
		||||
{
 | 
			
		||||
  GActionMuxer *muxer = G_ACTION_MUXER (observable);
 | 
			
		||||
  Action *action;
 | 
			
		||||
 | 
			
		||||
  action = g_hash_table_lookup (muxer->actions, name);
 | 
			
		||||
  g_object_weak_unref (G_OBJECT (observer), g_action_muxer_weak_notify, action);
 | 
			
		||||
  g_action_muxer_unregister_internal (action, observer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
g_action_muxer_free_group (gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  Group *group = data;
 | 
			
		||||
  gint i;
 | 
			
		||||
 | 
			
		||||
  /* 'for loop' or 'four loop'? */
 | 
			
		||||
  for (i = 0; i < 4; i++)
 | 
			
		||||
    g_signal_handler_disconnect (group->group, group->handler_ids[i]);
 | 
			
		||||
 | 
			
		||||
  g_object_unref (group->group);
 | 
			
		||||
  g_free (group->prefix);
 | 
			
		||||
 | 
			
		||||
  g_slice_free (Group, group);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
g_action_muxer_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  GActionMuxer *muxer = G_ACTION_MUXER (object);
 | 
			
		||||
 | 
			
		||||
  g_assert_cmpint (g_hash_table_size (muxer->actions), ==, 0);
 | 
			
		||||
  g_hash_table_unref (muxer->actions);
 | 
			
		||||
  g_hash_table_unref (muxer->groups);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (g_action_muxer_parent_class)
 | 
			
		||||
    ->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
g_action_muxer_init (GActionMuxer *muxer)
 | 
			
		||||
{
 | 
			
		||||
  muxer->actions = g_hash_table_new (g_str_hash, g_str_equal);
 | 
			
		||||
  muxer->groups = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_action_muxer_free_group);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
g_action_muxer_observable_iface_init (GActionObservableInterface *iface)
 | 
			
		||||
{
 | 
			
		||||
  iface->register_observer = g_action_muxer_register_observer;
 | 
			
		||||
  iface->unregister_observer = g_action_muxer_unregister_observer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
g_action_muxer_group_iface_init (GActionGroupInterface *iface)
 | 
			
		||||
{
 | 
			
		||||
  iface->list_actions = g_action_muxer_list_actions;
 | 
			
		||||
  iface->query_action = g_action_muxer_query_action;
 | 
			
		||||
  iface->activate_action = g_action_muxer_activate_action;
 | 
			
		||||
  iface->change_action_state = g_action_muxer_change_action_state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
g_action_muxer_class_init (GObjectClass *class)
 | 
			
		||||
{
 | 
			
		||||
  class->finalize = g_action_muxer_finalize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * g_action_muxer_insert:
 | 
			
		||||
 * @muxer: a #GActionMuxer
 | 
			
		||||
 * @prefix: the prefix string for the action group
 | 
			
		||||
 * @action_group: a #GActionGroup
 | 
			
		||||
 *
 | 
			
		||||
 * Adds the actions in @action_group to the list of actions provided by
 | 
			
		||||
 * @muxer.  @prefix is prefixed to each action name, such that for each
 | 
			
		||||
 * action <varname>x</varname> in @action_group, there is an equivalent
 | 
			
		||||
 * action @prefix<literal>.</literal><varname>x</varname> in @muxer.
 | 
			
		||||
 *
 | 
			
		||||
 * For example, if @prefix is "<literal>app</literal>" and @action_group
 | 
			
		||||
 * contains an action called "<literal>quit</literal>", then @muxer will
 | 
			
		||||
 * now contain an action called "<literal>app.quit</literal>".
 | 
			
		||||
 *
 | 
			
		||||
 * If any #GActionObservers are registered for actions in the group,
 | 
			
		||||
 * "action_added" notifications will be emitted, as appropriate.
 | 
			
		||||
 *
 | 
			
		||||
 * @prefix must not contain a dot ('.').
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
g_action_muxer_insert (GActionMuxer *muxer,
 | 
			
		||||
                       const gchar  *prefix,
 | 
			
		||||
                       GActionGroup *action_group)
 | 
			
		||||
{
 | 
			
		||||
  gchar **actions;
 | 
			
		||||
  Group *group;
 | 
			
		||||
  gint i;
 | 
			
		||||
 | 
			
		||||
  /* TODO: diff instead of ripout and replace */
 | 
			
		||||
  g_action_muxer_remove (muxer, prefix);
 | 
			
		||||
 | 
			
		||||
  group = g_slice_new (Group);
 | 
			
		||||
  group->muxer = muxer;
 | 
			
		||||
  group->group = g_object_ref (action_group);
 | 
			
		||||
  group->prefix = g_strdup (prefix);
 | 
			
		||||
 | 
			
		||||
  g_hash_table_insert (muxer->groups, group->prefix, group);
 | 
			
		||||
 | 
			
		||||
  actions = g_action_group_list_actions (group->group);
 | 
			
		||||
  for (i = 0; actions[i]; i++)
 | 
			
		||||
    g_action_muxer_action_added (group->group, actions[i], group);
 | 
			
		||||
  g_strfreev (actions);
 | 
			
		||||
 | 
			
		||||
  group->handler_ids[0] = g_signal_connect (group->group, "action-added",
 | 
			
		||||
                                            G_CALLBACK (g_action_muxer_action_added), group);
 | 
			
		||||
  group->handler_ids[1] = g_signal_connect (group->group, "action-removed",
 | 
			
		||||
                                            G_CALLBACK (g_action_muxer_action_removed), group);
 | 
			
		||||
  group->handler_ids[2] = g_signal_connect (group->group, "action-enabled-changed",
 | 
			
		||||
                                            G_CALLBACK (g_action_muxer_action_enabled_changed), group);
 | 
			
		||||
  group->handler_ids[3] = g_signal_connect (group->group, "action-state-changed",
 | 
			
		||||
                                            G_CALLBACK (g_action_muxer_action_state_changed), group);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * g_action_muxer_remove:
 | 
			
		||||
 * @muxer: a #GActionMuxer
 | 
			
		||||
 * @prefix: the prefix of the action group to remove
 | 
			
		||||
 *
 | 
			
		||||
 * Removes a #GActionGroup from the #GActionMuxer.
 | 
			
		||||
 *
 | 
			
		||||
 * If any #GActionObservers are registered for actions in the group,
 | 
			
		||||
 * "action_removed" notifications will be emitted, as appropriate.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
g_action_muxer_remove (GActionMuxer *muxer,
 | 
			
		||||
                       const gchar  *prefix)
 | 
			
		||||
{
 | 
			
		||||
  Group *group;
 | 
			
		||||
 | 
			
		||||
  group = g_hash_table_lookup (muxer->groups, prefix);
 | 
			
		||||
 | 
			
		||||
  if (group != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      gchar **actions;
 | 
			
		||||
      gint i;
 | 
			
		||||
 | 
			
		||||
      g_hash_table_steal (muxer->groups, prefix);
 | 
			
		||||
 | 
			
		||||
      actions = g_action_group_list_actions (group->group);
 | 
			
		||||
      for (i = 0; actions[i]; i++)
 | 
			
		||||
        g_action_muxer_action_removed (group->group, actions[i], group);
 | 
			
		||||
      g_strfreev (actions);
 | 
			
		||||
 | 
			
		||||
      g_action_muxer_free_group (group);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * g_action_muxer_new:
 | 
			
		||||
 *
 | 
			
		||||
 * Creates a new #GActionMuxer.
 | 
			
		||||
 */
 | 
			
		||||
GActionMuxer *
 | 
			
		||||
g_action_muxer_new (void)
 | 
			
		||||
{
 | 
			
		||||
  return g_object_new (G_TYPE_ACTION_MUXER, NULL);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,53 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2011 Canonical Limited
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the licence, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the
 | 
			
		||||
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 | 
			
		||||
 * Boston, MA 02111-1307, USA.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Ryan Lortie <desrt@desrt.ca>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __G_ACTION_MUXER_H__
 | 
			
		||||
#define __G_ACTION_MUXER_H__
 | 
			
		||||
 | 
			
		||||
#include <gio/gio.h>
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define G_TYPE_ACTION_MUXER                                 (g_action_muxer_get_type ())
 | 
			
		||||
#define G_ACTION_MUXER(inst)                                (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
 | 
			
		||||
                                                             G_TYPE_ACTION_MUXER, GActionMuxer))
 | 
			
		||||
#define G_IS_ACTION_MUXER(inst)                             (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
 | 
			
		||||
                                                             G_TYPE_ACTION_MUXER))
 | 
			
		||||
 | 
			
		||||
typedef struct _GActionMuxer                                GActionMuxer;
 | 
			
		||||
 | 
			
		||||
G_GNUC_INTERNAL
 | 
			
		||||
GType                   g_action_muxer_get_type                         (void);
 | 
			
		||||
G_GNUC_INTERNAL
 | 
			
		||||
GActionMuxer *          g_action_muxer_new                              (void);
 | 
			
		||||
 | 
			
		||||
G_GNUC_INTERNAL
 | 
			
		||||
void                    g_action_muxer_insert                           (GActionMuxer *muxer,
 | 
			
		||||
                                                                         const gchar  *prefix,
 | 
			
		||||
                                                                         GActionGroup *group);
 | 
			
		||||
 | 
			
		||||
G_GNUC_INTERNAL
 | 
			
		||||
void                    g_action_muxer_remove                           (GActionMuxer *muxer,
 | 
			
		||||
                                                                         const gchar  *prefix);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif /* __G_ACTION_MUXER_H__ */
 | 
			
		||||
@@ -1,80 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2011 Canonical Limited
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of the
 | 
			
		||||
 * licence or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
 | 
			
		||||
 * USA.
 | 
			
		||||
 *
 | 
			
		||||
 * Authors: Ryan Lortie <desrt@desrt.ca>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "gactionobservable.h"
 | 
			
		||||
 | 
			
		||||
G_DEFINE_INTERFACE (GActionObservable, g_action_observable, G_TYPE_OBJECT)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * SECTION:gactionobserable
 | 
			
		||||
 * @short_description: an interface implemented by objects that report
 | 
			
		||||
 *                     changes to actions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
g_action_observable_default_init (GActionObservableInterface *iface)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * g_action_observable_register_observer:
 | 
			
		||||
 * @observable: a #GActionObservable
 | 
			
		||||
 * @action_name: the name of the action
 | 
			
		||||
 * @observer: the #GActionObserver to which the events will be reported
 | 
			
		||||
 *
 | 
			
		||||
 * Registers @observer as being interested in changes to @action_name on
 | 
			
		||||
 * @observable.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
g_action_observable_register_observer (GActionObservable *observable,
 | 
			
		||||
                                       const gchar       *action_name,
 | 
			
		||||
                                       GActionObserver   *observer)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (G_IS_ACTION_OBSERVABLE (observable));
 | 
			
		||||
 | 
			
		||||
  G_ACTION_OBSERVABLE_GET_IFACE (observable)
 | 
			
		||||
    ->register_observer (observable, action_name, observer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * g_action_observable_unregister_observer:
 | 
			
		||||
 * @observable: a #GActionObservable
 | 
			
		||||
 * @action_name: the name of the action
 | 
			
		||||
 * @observer: the #GActionObserver to which the events will be reported
 | 
			
		||||
 *
 | 
			
		||||
 * Removes the registration of @observer as being interested in changes
 | 
			
		||||
 * to @action_name on @observable.
 | 
			
		||||
 *
 | 
			
		||||
 * If the observer was registered multiple times, it must be
 | 
			
		||||
 * unregistered an equal number of times.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
g_action_observable_unregister_observer (GActionObservable *observable,
 | 
			
		||||
                                         const gchar       *action_name,
 | 
			
		||||
                                         GActionObserver   *observer)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (G_IS_ACTION_OBSERVABLE (observable));
 | 
			
		||||
 | 
			
		||||
  G_ACTION_OBSERVABLE_GET_IFACE (observable)
 | 
			
		||||
    ->unregister_observer (observable, action_name, observer);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,64 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2011 Canonical Limited
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of the
 | 
			
		||||
 * licence or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
 | 
			
		||||
 * USA.
 | 
			
		||||
 *
 | 
			
		||||
 * Authors: Ryan Lortie <desrt@desrt.ca>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __G_ACTION_OBSERVABLE_H__
 | 
			
		||||
#define __G_ACTION_OBSERVABLE_H__
 | 
			
		||||
 | 
			
		||||
#include "gactionobserver.h"
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define G_TYPE_ACTION_OBSERVABLE                            (g_action_observable_get_type ())
 | 
			
		||||
#define G_ACTION_OBSERVABLE(inst)                           (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
 | 
			
		||||
                                                             G_TYPE_ACTION_OBSERVABLE, GActionObservable))
 | 
			
		||||
#define G_IS_ACTION_OBSERVABLE(inst)                        (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
 | 
			
		||||
                                                             G_TYPE_ACTION_OBSERVABLE))
 | 
			
		||||
#define G_ACTION_OBSERVABLE_GET_IFACE(inst)                 (G_TYPE_INSTANCE_GET_INTERFACE ((inst),                  \
 | 
			
		||||
                                                             G_TYPE_ACTION_OBSERVABLE, GActionObservableInterface))
 | 
			
		||||
 | 
			
		||||
typedef struct _GActionObservableInterface                  GActionObservableInterface;
 | 
			
		||||
 | 
			
		||||
struct _GActionObservableInterface
 | 
			
		||||
{
 | 
			
		||||
  GTypeInterface g_iface;
 | 
			
		||||
 | 
			
		||||
  void (* register_observer)   (GActionObservable *observable,
 | 
			
		||||
                                const gchar       *action_name,
 | 
			
		||||
                                GActionObserver   *observer);
 | 
			
		||||
  void (* unregister_observer) (GActionObservable *observable,
 | 
			
		||||
                                const gchar       *action_name,
 | 
			
		||||
                                GActionObserver   *observer);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_GNUC_INTERNAL
 | 
			
		||||
GType                   g_action_observable_get_type                    (void);
 | 
			
		||||
G_GNUC_INTERNAL
 | 
			
		||||
void                    g_action_observable_register_observer           (GActionObservable  *observable,
 | 
			
		||||
                                                                         const gchar        *action_name,
 | 
			
		||||
                                                                         GActionObserver    *observer);
 | 
			
		||||
G_GNUC_INTERNAL
 | 
			
		||||
void                    g_action_observable_unregister_observer         (GActionObservable  *observable,
 | 
			
		||||
                                                                         const gchar        *action_name,
 | 
			
		||||
                                                                         GActionObserver    *observer);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif /* __G_ACTION_OBSERVABLE_H__ */
 | 
			
		||||
@@ -1,90 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2011 Canonical Limited
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of the
 | 
			
		||||
 * licence or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
 | 
			
		||||
 * USA.
 | 
			
		||||
 *
 | 
			
		||||
 * Authors: Ryan Lortie <desrt@desrt.ca>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __G_ACTION_OBSERVER_H__
 | 
			
		||||
#define __G_ACTION_OBSERVER_H__
 | 
			
		||||
 | 
			
		||||
#include <gio/gio.h>
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define G_TYPE_ACTION_OBSERVER                              (g_action_observer_get_type ())
 | 
			
		||||
#define G_ACTION_OBSERVER(inst)                             (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
 | 
			
		||||
                                                             G_TYPE_ACTION_OBSERVER, GActionObserver))
 | 
			
		||||
#define G_IS_ACTION_OBSERVER(inst)                          (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
 | 
			
		||||
                                                             G_TYPE_ACTION_OBSERVER))
 | 
			
		||||
#define G_ACTION_OBSERVER_GET_IFACE(inst)                   (G_TYPE_INSTANCE_GET_INTERFACE ((inst),                  \
 | 
			
		||||
                                                             G_TYPE_ACTION_OBSERVER, GActionObserverInterface))
 | 
			
		||||
 | 
			
		||||
typedef struct _GActionObserverInterface                    GActionObserverInterface;
 | 
			
		||||
typedef struct _GActionObservable                           GActionObservable;
 | 
			
		||||
typedef struct _GActionObserver                             GActionObserver;
 | 
			
		||||
 | 
			
		||||
struct _GActionObserverInterface
 | 
			
		||||
{
 | 
			
		||||
  GTypeInterface g_iface;
 | 
			
		||||
 | 
			
		||||
  void (* action_added)           (GActionObserver    *observer,
 | 
			
		||||
                                   GActionObservable  *observable,
 | 
			
		||||
                                   const gchar        *action_name,
 | 
			
		||||
                                   const GVariantType *parameter_type,
 | 
			
		||||
                                   gboolean            enabled,
 | 
			
		||||
                                   GVariant           *state);
 | 
			
		||||
  void (* action_enabled_changed) (GActionObserver    *observer,
 | 
			
		||||
                                   GActionObservable  *observable,
 | 
			
		||||
                                   const gchar        *action_name,
 | 
			
		||||
                                   gboolean            enabled);
 | 
			
		||||
  void (* action_state_changed)   (GActionObserver    *observer,
 | 
			
		||||
                                   GActionObservable  *observable,
 | 
			
		||||
                                   const gchar        *action_name,
 | 
			
		||||
                                   GVariant           *state);
 | 
			
		||||
  void (* action_removed)         (GActionObserver    *observer,
 | 
			
		||||
                                   GActionObservable  *observable,
 | 
			
		||||
                                   const gchar        *action_name);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_GNUC_INTERNAL
 | 
			
		||||
GType                   g_action_observer_get_type                      (void);
 | 
			
		||||
G_GNUC_INTERNAL
 | 
			
		||||
void                    g_action_observer_action_added                  (GActionObserver    *observer,
 | 
			
		||||
                                                                         GActionObservable  *observable,
 | 
			
		||||
                                                                         const gchar        *action_name,
 | 
			
		||||
                                                                         const GVariantType *parameter_type,
 | 
			
		||||
                                                                         gboolean            enabled,
 | 
			
		||||
                                                                         GVariant           *state);
 | 
			
		||||
G_GNUC_INTERNAL
 | 
			
		||||
void                    g_action_observer_action_enabled_changed        (GActionObserver    *observer,
 | 
			
		||||
                                                                         GActionObservable  *observable,
 | 
			
		||||
                                                                         const gchar        *action_name,
 | 
			
		||||
                                                                         gboolean            enabled);
 | 
			
		||||
G_GNUC_INTERNAL
 | 
			
		||||
void                    g_action_observer_action_state_changed          (GActionObserver    *observer,
 | 
			
		||||
                                                                         GActionObservable  *observable,
 | 
			
		||||
                                                                         const gchar        *action_name,
 | 
			
		||||
                                                                         GVariant           *state);
 | 
			
		||||
G_GNUC_INTERNAL
 | 
			
		||||
void                    g_action_observer_action_removed                (GActionObserver    *observer,
 | 
			
		||||
                                                                         GActionObservable  *observable,
 | 
			
		||||
                                                                         const gchar        *action_name);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif /* __G_ACTION_OBSERVER_H__ */
 | 
			
		||||
							
								
								
									
										808
									
								
								src/gtkactionmuxer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										808
									
								
								src/gtkactionmuxer.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,808 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2011 Canonical Limited
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the licence, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Ryan Lortie <desrt@desrt.ca>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "gtkactionmuxer.h"
 | 
			
		||||
 | 
			
		||||
#include "gtkactionobservable.h"
 | 
			
		||||
#include "gtkactionobserver.h"
 | 
			
		||||
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SECTION:gtkactionmuxer
 | 
			
		||||
 * @short_description: Aggregate and monitor several action groups
 | 
			
		||||
 *
 | 
			
		||||
 * #GtkActionMuxer is a #GActionGroup and #GtkActionObservable that is
 | 
			
		||||
 * capable of containing other #GActionGroup instances.
 | 
			
		||||
 *
 | 
			
		||||
 * The typical use is aggregating all of the actions applicable to a
 | 
			
		||||
 * particular context into a single action group, with namespacing.
 | 
			
		||||
 *
 | 
			
		||||
 * Consider the case of two action groups -- one containing actions
 | 
			
		||||
 * applicable to an entire application (such as 'quit') and one
 | 
			
		||||
 * containing actions applicable to a particular window in the
 | 
			
		||||
 * application (such as 'fullscreen').
 | 
			
		||||
 *
 | 
			
		||||
 * In this case, each of these action groups could be added to a
 | 
			
		||||
 * #GtkActionMuxer with the prefixes "app" and "win", respectively.  This
 | 
			
		||||
 * would expose the actions as "app.quit" and "win.fullscreen" on the
 | 
			
		||||
 * #GActionGroup interface presented by the #GtkActionMuxer.
 | 
			
		||||
 *
 | 
			
		||||
 * Activations and state change requests on the #GtkActionMuxer are wired
 | 
			
		||||
 * through to the underlying action group in the expected way.
 | 
			
		||||
 *
 | 
			
		||||
 * This class is typically only used at the site of "consumption" of
 | 
			
		||||
 * actions (eg: when displaying a menu that contains many actions on
 | 
			
		||||
 * different objects).
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static void     gtk_action_muxer_group_iface_init         (GActionGroupInterface        *iface);
 | 
			
		||||
static void     gtk_action_muxer_observable_iface_init    (GtkActionObservableInterface *iface);
 | 
			
		||||
 | 
			
		||||
typedef GObjectClass GtkActionMuxerClass;
 | 
			
		||||
 | 
			
		||||
struct _GtkActionMuxer
 | 
			
		||||
{
 | 
			
		||||
  GObject parent_instance;
 | 
			
		||||
 | 
			
		||||
  GHashTable *observed_actions;
 | 
			
		||||
  GHashTable *groups;
 | 
			
		||||
  GtkActionMuxer *parent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE_WITH_CODE (GtkActionMuxer, gtk_action_muxer, G_TYPE_OBJECT,
 | 
			
		||||
                         G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, gtk_action_muxer_group_iface_init)
 | 
			
		||||
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTION_OBSERVABLE, gtk_action_muxer_observable_iface_init))
 | 
			
		||||
 | 
			
		||||
enum
 | 
			
		||||
{
 | 
			
		||||
  PROP_0,
 | 
			
		||||
  PROP_PARENT,
 | 
			
		||||
  NUM_PROPERTIES
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static GParamSpec *properties[NUM_PROPERTIES];
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer;
 | 
			
		||||
  GSList       *watchers;
 | 
			
		||||
  gchar        *fullname;
 | 
			
		||||
} Action;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer;
 | 
			
		||||
  GActionGroup *group;
 | 
			
		||||
  gchar        *prefix;
 | 
			
		||||
  gulong        handler_ids[4];
 | 
			
		||||
} Group;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_append_group_actions (gpointer key,
 | 
			
		||||
                                       gpointer value,
 | 
			
		||||
                                       gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  const gchar *prefix = key;
 | 
			
		||||
  Group *group = value;
 | 
			
		||||
  GArray *actions = user_data;
 | 
			
		||||
  gchar **group_actions;
 | 
			
		||||
  gchar **action;
 | 
			
		||||
 | 
			
		||||
  group_actions = g_action_group_list_actions (group->group);
 | 
			
		||||
  for (action = group_actions; *action; action++)
 | 
			
		||||
    {
 | 
			
		||||
      gchar *fullname;
 | 
			
		||||
 | 
			
		||||
      fullname = g_strconcat (prefix, ".", *action, NULL);
 | 
			
		||||
      g_array_append_val (actions, fullname);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_strfreev (group_actions);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gchar **
 | 
			
		||||
gtk_action_muxer_list_actions (GActionGroup *action_group)
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
 | 
			
		||||
  GArray *actions;
 | 
			
		||||
 | 
			
		||||
  actions = g_array_new (TRUE, FALSE, sizeof (gchar *));
 | 
			
		||||
 | 
			
		||||
  for ( ; muxer != NULL; muxer = muxer->parent)
 | 
			
		||||
    {
 | 
			
		||||
      g_hash_table_foreach (muxer->groups,
 | 
			
		||||
                            gtk_action_muxer_append_group_actions,
 | 
			
		||||
                            actions);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return (gchar **) g_array_free (actions, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Group *
 | 
			
		||||
gtk_action_muxer_find_group (GtkActionMuxer  *muxer,
 | 
			
		||||
                             const gchar     *full_name,
 | 
			
		||||
                             const gchar    **action_name)
 | 
			
		||||
{
 | 
			
		||||
  const gchar *dot;
 | 
			
		||||
  gchar *prefix;
 | 
			
		||||
  Group *group;
 | 
			
		||||
 | 
			
		||||
  dot = strchr (full_name, '.');
 | 
			
		||||
 | 
			
		||||
  if (!dot)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  prefix = g_strndup (full_name, dot - full_name);
 | 
			
		||||
  group = g_hash_table_lookup (muxer->groups, prefix);
 | 
			
		||||
  g_free (prefix);
 | 
			
		||||
 | 
			
		||||
  if (action_name)
 | 
			
		||||
    *action_name = dot + 1;
 | 
			
		||||
 | 
			
		||||
  return group;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_action_enabled_changed (GtkActionMuxer *muxer,
 | 
			
		||||
                                         const gchar    *action_name,
 | 
			
		||||
                                         gboolean        enabled)
 | 
			
		||||
{
 | 
			
		||||
  Action *action;
 | 
			
		||||
  GSList *node;
 | 
			
		||||
 | 
			
		||||
  action = g_hash_table_lookup (muxer->observed_actions, action_name);
 | 
			
		||||
  for (node = action ? action->watchers : NULL; node; node = node->next)
 | 
			
		||||
    gtk_action_observer_action_enabled_changed (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name, enabled);
 | 
			
		||||
  g_action_group_action_enabled_changed (G_ACTION_GROUP (muxer), action_name, enabled);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_group_action_enabled_changed (GActionGroup *action_group,
 | 
			
		||||
                                               const gchar  *action_name,
 | 
			
		||||
                                               gboolean      enabled,
 | 
			
		||||
                                               gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  Group *group = user_data;
 | 
			
		||||
  gchar *fullname;
 | 
			
		||||
 | 
			
		||||
  fullname = g_strconcat (group->prefix, ".", action_name, NULL);
 | 
			
		||||
  gtk_action_muxer_action_enabled_changed (group->muxer, fullname, enabled);
 | 
			
		||||
 | 
			
		||||
  g_free (fullname);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_parent_action_enabled_changed (GActionGroup *action_group,
 | 
			
		||||
                                                const gchar  *action_name,
 | 
			
		||||
                                                gboolean      enabled,
 | 
			
		||||
                                                gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer = user_data;
 | 
			
		||||
 | 
			
		||||
  gtk_action_muxer_action_enabled_changed (muxer, action_name, enabled);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_action_state_changed (GtkActionMuxer *muxer,
 | 
			
		||||
                                       const gchar    *action_name,
 | 
			
		||||
                                       GVariant       *state)
 | 
			
		||||
{
 | 
			
		||||
  Action *action;
 | 
			
		||||
  GSList *node;
 | 
			
		||||
 | 
			
		||||
  action = g_hash_table_lookup (muxer->observed_actions, action_name);
 | 
			
		||||
  for (node = action ? action->watchers : NULL; node; node = node->next)
 | 
			
		||||
    gtk_action_observer_action_state_changed (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name, state);
 | 
			
		||||
  g_action_group_action_state_changed (G_ACTION_GROUP (muxer), action_name, state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_group_action_state_changed (GActionGroup *action_group,
 | 
			
		||||
                                             const gchar  *action_name,
 | 
			
		||||
                                             GVariant     *state,
 | 
			
		||||
                                             gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  Group *group = user_data;
 | 
			
		||||
  gchar *fullname;
 | 
			
		||||
 | 
			
		||||
  fullname = g_strconcat (group->prefix, ".", action_name, NULL);
 | 
			
		||||
  gtk_action_muxer_action_state_changed (group->muxer, fullname, state);
 | 
			
		||||
 | 
			
		||||
  g_free (fullname);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_parent_action_state_changed (GActionGroup *action_group,
 | 
			
		||||
                                              const gchar  *action_name,
 | 
			
		||||
                                              GVariant     *state,
 | 
			
		||||
                                              gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer = user_data;
 | 
			
		||||
 | 
			
		||||
  gtk_action_muxer_action_state_changed (muxer, action_name, state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_action_added (GtkActionMuxer *muxer,
 | 
			
		||||
                               const gchar    *action_name,
 | 
			
		||||
                               GActionGroup   *original_group,
 | 
			
		||||
                               const gchar    *orignal_action_name)
 | 
			
		||||
{
 | 
			
		||||
  const GVariantType *parameter_type;
 | 
			
		||||
  gboolean enabled;
 | 
			
		||||
  GVariant *state;
 | 
			
		||||
  Action *action;
 | 
			
		||||
 | 
			
		||||
  action = g_hash_table_lookup (muxer->observed_actions, action_name);
 | 
			
		||||
 | 
			
		||||
  if (action && action->watchers &&
 | 
			
		||||
      g_action_group_query_action (original_group, orignal_action_name,
 | 
			
		||||
                                   &enabled, ¶meter_type, NULL, NULL, &state))
 | 
			
		||||
    {
 | 
			
		||||
      GSList *node;
 | 
			
		||||
 | 
			
		||||
      for (node = action->watchers; node; node = node->next)
 | 
			
		||||
        gtk_action_observer_action_added (node->data,
 | 
			
		||||
                                        GTK_ACTION_OBSERVABLE (muxer),
 | 
			
		||||
                                        action_name, parameter_type, enabled, state);
 | 
			
		||||
 | 
			
		||||
      if (state)
 | 
			
		||||
        g_variant_unref (state);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_action_group_action_added (G_ACTION_GROUP (muxer), action_name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_action_added_to_group (GActionGroup *action_group,
 | 
			
		||||
                                        const gchar  *action_name,
 | 
			
		||||
                                        gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  Group *group = user_data;
 | 
			
		||||
  gchar *fullname;
 | 
			
		||||
 | 
			
		||||
  fullname = g_strconcat (group->prefix, ".", action_name, NULL);
 | 
			
		||||
  gtk_action_muxer_action_added (group->muxer, fullname, action_group, action_name);
 | 
			
		||||
 | 
			
		||||
  g_free (fullname);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_action_added_to_parent (GActionGroup *action_group,
 | 
			
		||||
                                         const gchar  *action_name,
 | 
			
		||||
                                         gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer = user_data;
 | 
			
		||||
 | 
			
		||||
  gtk_action_muxer_action_added (muxer, action_name, action_group, action_name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_action_removed (GtkActionMuxer *muxer,
 | 
			
		||||
                                 const gchar    *action_name)
 | 
			
		||||
{
 | 
			
		||||
  Action *action;
 | 
			
		||||
  GSList *node;
 | 
			
		||||
 | 
			
		||||
  action = g_hash_table_lookup (muxer->observed_actions, action_name);
 | 
			
		||||
  for (node = action ? action->watchers : NULL; node; node = node->next)
 | 
			
		||||
    gtk_action_observer_action_removed (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name);
 | 
			
		||||
  g_action_group_action_removed (G_ACTION_GROUP (muxer), action_name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_action_removed_from_group (GActionGroup *action_group,
 | 
			
		||||
                                            const gchar  *action_name,
 | 
			
		||||
                                            gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  Group *group = user_data;
 | 
			
		||||
  gchar *fullname;
 | 
			
		||||
 | 
			
		||||
  fullname = g_strconcat (group->prefix, ".", action_name, NULL);
 | 
			
		||||
  gtk_action_muxer_action_removed (group->muxer, fullname);
 | 
			
		||||
 | 
			
		||||
  g_free (fullname);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_action_removed_from_parent (GActionGroup *action_group,
 | 
			
		||||
                                             const gchar  *action_name,
 | 
			
		||||
                                             gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer = user_data;
 | 
			
		||||
 | 
			
		||||
  gtk_action_muxer_action_removed (muxer, action_name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
gtk_action_muxer_query_action (GActionGroup        *action_group,
 | 
			
		||||
                               const gchar         *action_name,
 | 
			
		||||
                               gboolean            *enabled,
 | 
			
		||||
                               const GVariantType **parameter_type,
 | 
			
		||||
                               const GVariantType **state_type,
 | 
			
		||||
                               GVariant           **state_hint,
 | 
			
		||||
                               GVariant           **state)
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
 | 
			
		||||
  Group *group;
 | 
			
		||||
  const gchar *unprefixed_name;
 | 
			
		||||
 | 
			
		||||
  group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name);
 | 
			
		||||
 | 
			
		||||
  if (group)
 | 
			
		||||
    return g_action_group_query_action (group->group, unprefixed_name, enabled,
 | 
			
		||||
                                        parameter_type, state_type, state_hint, state);
 | 
			
		||||
 | 
			
		||||
  if (muxer->parent)
 | 
			
		||||
    return g_action_group_query_action (G_ACTION_GROUP (muxer->parent), action_name,
 | 
			
		||||
                                        enabled, parameter_type,
 | 
			
		||||
                                        state_type, state_hint, state);
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_activate_action (GActionGroup *action_group,
 | 
			
		||||
                                  const gchar  *action_name,
 | 
			
		||||
                                  GVariant     *parameter)
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
 | 
			
		||||
  Group *group;
 | 
			
		||||
  const gchar *unprefixed_name;
 | 
			
		||||
 | 
			
		||||
  group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name);
 | 
			
		||||
 | 
			
		||||
  if (group)
 | 
			
		||||
    g_action_group_activate_action (group->group, unprefixed_name, parameter);
 | 
			
		||||
  else if (muxer->parent)
 | 
			
		||||
    g_action_group_activate_action (G_ACTION_GROUP (muxer->parent), action_name, parameter);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GVariant *
 | 
			
		||||
get_platform_data (void)
 | 
			
		||||
{
 | 
			
		||||
  gchar time[32];
 | 
			
		||||
  GVariantBuilder *builder;
 | 
			
		||||
  GVariant *result;
 | 
			
		||||
 | 
			
		||||
  g_snprintf (time, 32, "_TIME%d", clutter_get_current_event_time ());
 | 
			
		||||
 | 
			
		||||
  builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
 | 
			
		||||
 | 
			
		||||
  g_variant_builder_add (builder, "{sv}", "desktop-startup-id",
 | 
			
		||||
                         g_variant_new_string (time));
 | 
			
		||||
 | 
			
		||||
  result = g_variant_builder_end (builder);
 | 
			
		||||
  g_variant_builder_unref (builder);
 | 
			
		||||
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_change_action_state (GActionGroup *action_group,
 | 
			
		||||
                                      const gchar  *action_name,
 | 
			
		||||
                                      GVariant     *state)
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
 | 
			
		||||
  Group *group;
 | 
			
		||||
  const gchar *unprefixed_name;
 | 
			
		||||
 | 
			
		||||
  group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name);
 | 
			
		||||
 | 
			
		||||
  if (group)
 | 
			
		||||
    {
 | 
			
		||||
      if (G_IS_REMOTE_ACTION_GROUP (group->group))
 | 
			
		||||
        g_remote_action_group_change_action_state_full (G_REMOTE_ACTION_GROUP (group->group),
 | 
			
		||||
                                                        unprefixed_name,
 | 
			
		||||
                                                        state,
 | 
			
		||||
                                                        get_platform_data ());
 | 
			
		||||
      else
 | 
			
		||||
        g_action_group_change_action_state (group->group, unprefixed_name, state);
 | 
			
		||||
    }
 | 
			
		||||
  else if (muxer->parent)
 | 
			
		||||
    g_action_group_change_action_state (G_ACTION_GROUP (muxer->parent), action_name, state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_unregister_internal (Action   *action,
 | 
			
		||||
                                      gpointer  observer)
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer = action->muxer;
 | 
			
		||||
  GSList **ptr;
 | 
			
		||||
 | 
			
		||||
  for (ptr = &action->watchers; *ptr; ptr = &(*ptr)->next)
 | 
			
		||||
    if ((*ptr)->data == observer)
 | 
			
		||||
      {
 | 
			
		||||
        *ptr = g_slist_remove (*ptr, observer);
 | 
			
		||||
 | 
			
		||||
        if (action->watchers == NULL)
 | 
			
		||||
            g_hash_table_remove (muxer->observed_actions, action->fullname);
 | 
			
		||||
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_weak_notify (gpointer  data,
 | 
			
		||||
                              GObject  *where_the_object_was)
 | 
			
		||||
{
 | 
			
		||||
  Action *action = data;
 | 
			
		||||
 | 
			
		||||
  gtk_action_muxer_unregister_internal (action, where_the_object_was);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_register_observer (GtkActionObservable *observable,
 | 
			
		||||
                                    const gchar         *name,
 | 
			
		||||
                                    GtkActionObserver   *observer)
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer = GTK_ACTION_MUXER (observable);
 | 
			
		||||
  Action *action;
 | 
			
		||||
 | 
			
		||||
  action = g_hash_table_lookup (muxer->observed_actions, name);
 | 
			
		||||
 | 
			
		||||
  if (action == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      action = g_slice_new (Action);
 | 
			
		||||
      action->muxer = muxer;
 | 
			
		||||
      action->fullname = g_strdup (name);
 | 
			
		||||
      action->watchers = NULL;
 | 
			
		||||
 | 
			
		||||
      g_hash_table_insert (muxer->observed_actions, action->fullname, action);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  action->watchers = g_slist_prepend (action->watchers, observer);
 | 
			
		||||
  g_object_weak_ref (G_OBJECT (observer), gtk_action_muxer_weak_notify, action);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_unregister_observer (GtkActionObservable *observable,
 | 
			
		||||
                                      const gchar         *name,
 | 
			
		||||
                                      GtkActionObserver   *observer)
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer = GTK_ACTION_MUXER (observable);
 | 
			
		||||
  Action *action;
 | 
			
		||||
 | 
			
		||||
  action = g_hash_table_lookup (muxer->observed_actions, name);
 | 
			
		||||
  g_object_weak_unref (G_OBJECT (observer), gtk_action_muxer_weak_notify, action);
 | 
			
		||||
  gtk_action_muxer_unregister_internal (action, observer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_free_group (gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  Group *group = data;
 | 
			
		||||
  gint i;
 | 
			
		||||
 | 
			
		||||
  /* 'for loop' or 'four loop'? */
 | 
			
		||||
  for (i = 0; i < 4; i++)
 | 
			
		||||
    g_signal_handler_disconnect (group->group, group->handler_ids[i]);
 | 
			
		||||
 | 
			
		||||
  g_object_unref (group->group);
 | 
			
		||||
  g_free (group->prefix);
 | 
			
		||||
 | 
			
		||||
  g_slice_free (Group, group);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_free_action (gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  Action *action = data;
 | 
			
		||||
  GSList *it;
 | 
			
		||||
 | 
			
		||||
  for (it = action->watchers; it; it = it->next)
 | 
			
		||||
    g_object_weak_unref (G_OBJECT (it->data), gtk_action_muxer_weak_notify, action);
 | 
			
		||||
 | 
			
		||||
  g_slist_free (action->watchers);
 | 
			
		||||
  g_free (action->fullname);
 | 
			
		||||
 | 
			
		||||
  g_slice_free (Action, action);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
 | 
			
		||||
 | 
			
		||||
  g_assert_cmpint (g_hash_table_size (muxer->observed_actions), ==, 0);
 | 
			
		||||
  g_hash_table_unref (muxer->observed_actions);
 | 
			
		||||
  g_hash_table_unref (muxer->groups);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (gtk_action_muxer_parent_class)
 | 
			
		||||
    ->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_dispose (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
 | 
			
		||||
 | 
			
		||||
  if (muxer->parent)
 | 
			
		||||
  {
 | 
			
		||||
    g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_added_to_parent, muxer);
 | 
			
		||||
    g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_removed_from_parent, muxer);
 | 
			
		||||
    g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_enabled_changed, muxer);
 | 
			
		||||
    g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_state_changed, muxer);
 | 
			
		||||
 | 
			
		||||
    g_clear_object (&muxer->parent);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  g_hash_table_remove_all (muxer->observed_actions);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (gtk_action_muxer_parent_class)
 | 
			
		||||
    ->dispose (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_get_property (GObject    *object,
 | 
			
		||||
                               guint       property_id,
 | 
			
		||||
                               GValue     *value,
 | 
			
		||||
                               GParamSpec *pspec)
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
 | 
			
		||||
 | 
			
		||||
  switch (property_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_PARENT:
 | 
			
		||||
      g_value_set_object (value, gtk_action_muxer_get_parent (muxer));
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_set_property (GObject      *object,
 | 
			
		||||
                               guint         property_id,
 | 
			
		||||
                               const GValue *value,
 | 
			
		||||
                               GParamSpec   *pspec)
 | 
			
		||||
{
 | 
			
		||||
  GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
 | 
			
		||||
 | 
			
		||||
  switch (property_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_PARENT:
 | 
			
		||||
      gtk_action_muxer_set_parent (muxer, g_value_get_object (value));
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_init (GtkActionMuxer *muxer)
 | 
			
		||||
{
 | 
			
		||||
  muxer->observed_actions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gtk_action_muxer_free_action);
 | 
			
		||||
  muxer->groups = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gtk_action_muxer_free_group);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_observable_iface_init (GtkActionObservableInterface *iface)
 | 
			
		||||
{
 | 
			
		||||
  iface->register_observer = gtk_action_muxer_register_observer;
 | 
			
		||||
  iface->unregister_observer = gtk_action_muxer_unregister_observer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_group_iface_init (GActionGroupInterface *iface)
 | 
			
		||||
{
 | 
			
		||||
  iface->list_actions = gtk_action_muxer_list_actions;
 | 
			
		||||
  iface->query_action = gtk_action_muxer_query_action;
 | 
			
		||||
  iface->activate_action = gtk_action_muxer_activate_action;
 | 
			
		||||
  iface->change_action_state = gtk_action_muxer_change_action_state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_action_muxer_class_init (GObjectClass *class)
 | 
			
		||||
{
 | 
			
		||||
  class->get_property = gtk_action_muxer_get_property;
 | 
			
		||||
  class->set_property = gtk_action_muxer_set_property;
 | 
			
		||||
  class->finalize = gtk_action_muxer_finalize;
 | 
			
		||||
  class->dispose = gtk_action_muxer_dispose;
 | 
			
		||||
 | 
			
		||||
  properties[PROP_PARENT] = g_param_spec_object ("parent", "Parent",
 | 
			
		||||
                                                 "The parent muxer",
 | 
			
		||||
                                                 GTK_TYPE_ACTION_MUXER,
 | 
			
		||||
                                                 G_PARAM_READWRITE |
 | 
			
		||||
                                                 G_PARAM_STATIC_STRINGS);
 | 
			
		||||
 | 
			
		||||
  g_object_class_install_properties (class, NUM_PROPERTIES, properties);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * gtk_action_muxer_insert:
 | 
			
		||||
 * @muxer: a #GtkActionMuxer
 | 
			
		||||
 * @prefix: the prefix string for the action group
 | 
			
		||||
 * @action_group: a #GActionGroup
 | 
			
		||||
 *
 | 
			
		||||
 * Adds the actions in @action_group to the list of actions provided by
 | 
			
		||||
 * @muxer.  @prefix is prefixed to each action name, such that for each
 | 
			
		||||
 * action <varname>x</varname> in @action_group, there is an equivalent
 | 
			
		||||
 * action @prefix<literal>.</literal><varname>x</varname> in @muxer.
 | 
			
		||||
 *
 | 
			
		||||
 * For example, if @prefix is "<literal>app</literal>" and @action_group
 | 
			
		||||
 * contains an action called "<literal>quit</literal>", then @muxer will
 | 
			
		||||
 * now contain an action called "<literal>app.quit</literal>".
 | 
			
		||||
 *
 | 
			
		||||
 * If any #GtkActionObservers are registered for actions in the group,
 | 
			
		||||
 * "action_added" notifications will be emitted, as appropriate.
 | 
			
		||||
 *
 | 
			
		||||
 * @prefix must not contain a dot ('.').
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
gtk_action_muxer_insert (GtkActionMuxer *muxer,
 | 
			
		||||
                         const gchar    *prefix,
 | 
			
		||||
                         GActionGroup   *action_group)
 | 
			
		||||
{
 | 
			
		||||
  gchar **actions;
 | 
			
		||||
  Group *group;
 | 
			
		||||
  gint i;
 | 
			
		||||
 | 
			
		||||
  /* TODO: diff instead of ripout and replace */
 | 
			
		||||
  gtk_action_muxer_remove (muxer, prefix);
 | 
			
		||||
 | 
			
		||||
  group = g_slice_new (Group);
 | 
			
		||||
  group->muxer = muxer;
 | 
			
		||||
  group->group = g_object_ref (action_group);
 | 
			
		||||
  group->prefix = g_strdup (prefix);
 | 
			
		||||
 | 
			
		||||
  g_hash_table_insert (muxer->groups, group->prefix, group);
 | 
			
		||||
 | 
			
		||||
  actions = g_action_group_list_actions (group->group);
 | 
			
		||||
  for (i = 0; actions[i]; i++)
 | 
			
		||||
    gtk_action_muxer_action_added_to_group (group->group, actions[i], group);
 | 
			
		||||
  g_strfreev (actions);
 | 
			
		||||
 | 
			
		||||
  group->handler_ids[0] = g_signal_connect (group->group, "action-added",
 | 
			
		||||
                                            G_CALLBACK (gtk_action_muxer_action_added_to_group), group);
 | 
			
		||||
  group->handler_ids[1] = g_signal_connect (group->group, "action-removed",
 | 
			
		||||
                                            G_CALLBACK (gtk_action_muxer_action_removed_from_group), group);
 | 
			
		||||
  group->handler_ids[2] = g_signal_connect (group->group, "action-enabled-changed",
 | 
			
		||||
                                            G_CALLBACK (gtk_action_muxer_group_action_enabled_changed), group);
 | 
			
		||||
  group->handler_ids[3] = g_signal_connect (group->group, "action-state-changed",
 | 
			
		||||
                                            G_CALLBACK (gtk_action_muxer_group_action_state_changed), group);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * gtk_action_muxer_remove:
 | 
			
		||||
 * @muxer: a #GtkActionMuxer
 | 
			
		||||
 * @prefix: the prefix of the action group to remove
 | 
			
		||||
 *
 | 
			
		||||
 * Removes a #GActionGroup from the #GtkActionMuxer.
 | 
			
		||||
 *
 | 
			
		||||
 * If any #GtkActionObservers are registered for actions in the group,
 | 
			
		||||
 * "action_removed" notifications will be emitted, as appropriate.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
gtk_action_muxer_remove (GtkActionMuxer *muxer,
 | 
			
		||||
                         const gchar    *prefix)
 | 
			
		||||
{
 | 
			
		||||
  Group *group;
 | 
			
		||||
 | 
			
		||||
  group = g_hash_table_lookup (muxer->groups, prefix);
 | 
			
		||||
 | 
			
		||||
  if (group != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      gchar **actions;
 | 
			
		||||
      gint i;
 | 
			
		||||
 | 
			
		||||
      g_hash_table_steal (muxer->groups, prefix);
 | 
			
		||||
 | 
			
		||||
      actions = g_action_group_list_actions (group->group);
 | 
			
		||||
      for (i = 0; actions[i]; i++)
 | 
			
		||||
        gtk_action_muxer_action_removed_from_group (group->group, actions[i], group);
 | 
			
		||||
      g_strfreev (actions);
 | 
			
		||||
 | 
			
		||||
      gtk_action_muxer_free_group (group);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * gtk_action_muxer_new:
 | 
			
		||||
 *
 | 
			
		||||
 * Creates a new #GtkActionMuxer.
 | 
			
		||||
 */
 | 
			
		||||
GtkActionMuxer *
 | 
			
		||||
gtk_action_muxer_new (void)
 | 
			
		||||
{
 | 
			
		||||
  return g_object_new (GTK_TYPE_ACTION_MUXER, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * gtk_action_muxer_get_parent:
 | 
			
		||||
 * @muxer: a #GtkActionMuxer
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: (transfer none): the parent of @muxer, or NULL.
 | 
			
		||||
 */
 | 
			
		||||
GtkActionMuxer *
 | 
			
		||||
gtk_action_muxer_get_parent (GtkActionMuxer *muxer)
 | 
			
		||||
{
 | 
			
		||||
  g_return_val_if_fail (GTK_IS_ACTION_MUXER (muxer), NULL);
 | 
			
		||||
 | 
			
		||||
  return muxer->parent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * gtk_action_muxer_set_parent:
 | 
			
		||||
 * @muxer: a #GtkActionMuxer
 | 
			
		||||
 * @parent: (allow-none): the new parent #GtkActionMuxer
 | 
			
		||||
 *
 | 
			
		||||
 * Sets the parent of @muxer to @parent.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
gtk_action_muxer_set_parent (GtkActionMuxer *muxer,
 | 
			
		||||
                             GtkActionMuxer *parent)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (GTK_IS_ACTION_MUXER (muxer));
 | 
			
		||||
  g_return_if_fail (parent == NULL || GTK_IS_ACTION_MUXER (parent));
 | 
			
		||||
 | 
			
		||||
  if (muxer->parent == parent)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (muxer->parent != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      gchar **actions;
 | 
			
		||||
      gchar **it;
 | 
			
		||||
 | 
			
		||||
      actions = g_action_group_list_actions (G_ACTION_GROUP (muxer->parent));
 | 
			
		||||
      for (it = actions; *it; it++)
 | 
			
		||||
        gtk_action_muxer_action_removed (muxer, *it);
 | 
			
		||||
      g_strfreev (actions);
 | 
			
		||||
 | 
			
		||||
      g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_added_to_parent, muxer);
 | 
			
		||||
      g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_removed_from_parent, muxer);
 | 
			
		||||
      g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_enabled_changed, muxer);
 | 
			
		||||
      g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_state_changed, muxer);
 | 
			
		||||
 | 
			
		||||
      g_object_unref (muxer->parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  muxer->parent = parent;
 | 
			
		||||
 | 
			
		||||
  if (muxer->parent != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      gchar **actions;
 | 
			
		||||
      gchar **it;
 | 
			
		||||
 | 
			
		||||
      g_object_ref (muxer->parent);
 | 
			
		||||
 | 
			
		||||
      actions = g_action_group_list_actions (G_ACTION_GROUP (muxer->parent));
 | 
			
		||||
      for (it = actions; *it; it++)
 | 
			
		||||
        gtk_action_muxer_action_added (muxer, *it, G_ACTION_GROUP (muxer->parent), *it);
 | 
			
		||||
      g_strfreev (actions);
 | 
			
		||||
 | 
			
		||||
      g_signal_connect (muxer->parent, "action-added",
 | 
			
		||||
                        G_CALLBACK (gtk_action_muxer_action_added_to_parent), muxer);
 | 
			
		||||
      g_signal_connect (muxer->parent, "action-removed",
 | 
			
		||||
                        G_CALLBACK (gtk_action_muxer_action_removed_from_parent), muxer);
 | 
			
		||||
      g_signal_connect (muxer->parent, "action-enabled-changed",
 | 
			
		||||
                        G_CALLBACK (gtk_action_muxer_parent_action_enabled_changed), muxer);
 | 
			
		||||
      g_signal_connect (muxer->parent, "action-state-changed",
 | 
			
		||||
                        G_CALLBACK (gtk_action_muxer_parent_action_state_changed), muxer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_object_notify_by_pspec (G_OBJECT (muxer), properties[PROP_PARENT]);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								src/gtkactionmuxer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/gtkactionmuxer.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2011 Canonical Limited
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the licence, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Ryan Lortie <desrt@desrt.ca>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __GTK_ACTION_MUXER_H__
 | 
			
		||||
#define __GTK_ACTION_MUXER_H__
 | 
			
		||||
 | 
			
		||||
#include <gio/gio.h>
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define GTK_TYPE_ACTION_MUXER                               (gtk_action_muxer_get_type ())
 | 
			
		||||
#define GTK_ACTION_MUXER(inst)                              (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
 | 
			
		||||
                                                             GTK_TYPE_ACTION_MUXER, GtkActionMuxer))
 | 
			
		||||
#define GTK_IS_ACTION_MUXER(inst)                           (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
 | 
			
		||||
                                                             GTK_TYPE_ACTION_MUXER))
 | 
			
		||||
 | 
			
		||||
typedef struct _GtkActionMuxer                              GtkActionMuxer;
 | 
			
		||||
 | 
			
		||||
GType                   gtk_action_muxer_get_type                       (void);
 | 
			
		||||
GtkActionMuxer *        gtk_action_muxer_new                            (void);
 | 
			
		||||
 | 
			
		||||
void                    gtk_action_muxer_insert                         (GtkActionMuxer *muxer,
 | 
			
		||||
                                                                         const gchar    *prefix,
 | 
			
		||||
                                                                         GActionGroup   *action_group);
 | 
			
		||||
 | 
			
		||||
void                    gtk_action_muxer_remove                         (GtkActionMuxer *muxer,
 | 
			
		||||
                                                                         const gchar    *prefix);
 | 
			
		||||
 | 
			
		||||
GtkActionMuxer *        gtk_action_muxer_get_parent                     (GtkActionMuxer *muxer);
 | 
			
		||||
 | 
			
		||||
void                    gtk_action_muxer_set_parent                     (GtkActionMuxer *muxer,
 | 
			
		||||
                                                                         GtkActionMuxer *parent);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif /* __GTK_ACTION_MUXER_H__ */
 | 
			
		||||
							
								
								
									
										78
									
								
								src/gtkactionobservable.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/gtkactionobservable.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2011 Canonical Limited
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of the
 | 
			
		||||
 * licence or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * Authors: Ryan Lortie <desrt@desrt.ca>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "gtkactionobservable.h"
 | 
			
		||||
 | 
			
		||||
G_DEFINE_INTERFACE (GtkActionObservable, gtk_action_observable, G_TYPE_OBJECT)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * SECTION:gtkactionobserable
 | 
			
		||||
 * @short_description: an interface implemented by objects that report
 | 
			
		||||
 *                     changes to actions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
gtk_action_observable_default_init (GtkActionObservableInterface *iface)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * gtk_action_observable_register_observer:
 | 
			
		||||
 * @observable: a #GtkActionObservable
 | 
			
		||||
 * @action_name: the name of the action
 | 
			
		||||
 * @observer: the #GtkActionObserver to which the events will be reported
 | 
			
		||||
 *
 | 
			
		||||
 * Registers @observer as being interested in changes to @action_name on
 | 
			
		||||
 * @observable.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
gtk_action_observable_register_observer (GtkActionObservable *observable,
 | 
			
		||||
                                         const gchar         *action_name,
 | 
			
		||||
                                         GtkActionObserver   *observer)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (GTK_IS_ACTION_OBSERVABLE (observable));
 | 
			
		||||
 | 
			
		||||
  GTK_ACTION_OBSERVABLE_GET_IFACE (observable)
 | 
			
		||||
    ->register_observer (observable, action_name, observer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * gtk_action_observable_unregister_observer:
 | 
			
		||||
 * @observable: a #GtkActionObservable
 | 
			
		||||
 * @action_name: the name of the action
 | 
			
		||||
 * @observer: the #GtkActionObserver to which the events will be reported
 | 
			
		||||
 *
 | 
			
		||||
 * Removes the registration of @observer as being interested in changes
 | 
			
		||||
 * to @action_name on @observable.
 | 
			
		||||
 *
 | 
			
		||||
 * If the observer was registered multiple times, it must be
 | 
			
		||||
 * unregistered an equal number of times.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
gtk_action_observable_unregister_observer (GtkActionObservable *observable,
 | 
			
		||||
                                           const gchar         *action_name,
 | 
			
		||||
                                           GtkActionObserver   *observer)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (GTK_IS_ACTION_OBSERVABLE (observable));
 | 
			
		||||
 | 
			
		||||
  GTK_ACTION_OBSERVABLE_GET_IFACE (observable)
 | 
			
		||||
    ->unregister_observer (observable, action_name, observer);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										60
									
								
								src/gtkactionobservable.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/gtkactionobservable.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2011 Canonical Limited
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of the
 | 
			
		||||
 * licence or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * Authors: Ryan Lortie <desrt@desrt.ca>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __GTK_ACTION_OBSERVABLE_H__
 | 
			
		||||
#define __GTK_ACTION_OBSERVABLE_H__
 | 
			
		||||
 | 
			
		||||
#include "gtkactionobserver.h"
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define GTK_TYPE_ACTION_OBSERVABLE                          (gtk_action_observable_get_type ())
 | 
			
		||||
#define GTK_ACTION_OBSERVABLE(inst)                         (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
 | 
			
		||||
                                                             GTK_TYPE_ACTION_OBSERVABLE, GtkActionObservable))
 | 
			
		||||
#define GTK_IS_ACTION_OBSERVABLE(inst)                      (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
 | 
			
		||||
                                                             GTK_TYPE_ACTION_OBSERVABLE))
 | 
			
		||||
#define GTK_ACTION_OBSERVABLE_GET_IFACE(inst)               (G_TYPE_INSTANCE_GET_INTERFACE ((inst),                  \
 | 
			
		||||
                                                             GTK_TYPE_ACTION_OBSERVABLE,                             \
 | 
			
		||||
                                                             GtkActionObservableInterface))
 | 
			
		||||
 | 
			
		||||
typedef struct _GtkActionObservableInterface                GtkActionObservableInterface;
 | 
			
		||||
 | 
			
		||||
struct _GtkActionObservableInterface
 | 
			
		||||
{
 | 
			
		||||
  GTypeInterface g_iface;
 | 
			
		||||
 | 
			
		||||
  void (* register_observer)   (GtkActionObservable *observable,
 | 
			
		||||
                                const gchar         *action_name,
 | 
			
		||||
                                GtkActionObserver   *observer);
 | 
			
		||||
  void (* unregister_observer) (GtkActionObservable *observable,
 | 
			
		||||
                                const gchar         *action_name,
 | 
			
		||||
                                GtkActionObserver   *observer);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
GType                   gtk_action_observable_get_type                  (void);
 | 
			
		||||
void                    gtk_action_observable_register_observer         (GtkActionObservable *observable,
 | 
			
		||||
                                                                         const gchar         *action_name,
 | 
			
		||||
                                                                         GtkActionObserver   *observer);
 | 
			
		||||
void                    gtk_action_observable_unregister_observer       (GtkActionObservable *observable,
 | 
			
		||||
                                                                         const gchar         *action_name,
 | 
			
		||||
                                                                         GtkActionObserver   *observer);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif /* __GTK_ACTION_OBSERVABLE_H__ */
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2011 Canonical Limited
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * This library is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of the
 | 
			
		||||
 * licence or (at your option) any later version.
 | 
			
		||||
@@ -12,25 +12,23 @@
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
 | 
			
		||||
 * USA.
 | 
			
		||||
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * Authors: Ryan Lortie <desrt@desrt.ca>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "gactionobserver.h"
 | 
			
		||||
#include "gtkactionobserver.h"
 | 
			
		||||
 | 
			
		||||
G_DEFINE_INTERFACE (GActionObserver, g_action_observer, G_TYPE_OBJECT)
 | 
			
		||||
G_DEFINE_INTERFACE (GtkActionObserver, gtk_action_observer, G_TYPE_OBJECT)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SECTION:gactionobserver
 | 
			
		||||
 * SECTION:gtkactionobserver
 | 
			
		||||
 * @short_description: an interface implemented by objects that are
 | 
			
		||||
 *                     interested in monitoring actions for changes
 | 
			
		||||
 *
 | 
			
		||||
 * GActionObserver is a simple interface allowing objects that wish to
 | 
			
		||||
 * GtkActionObserver is a simple interface allowing objects that wish to
 | 
			
		||||
 * be notified of changes to actions to be notified of those changes.
 | 
			
		||||
 *
 | 
			
		||||
 * It is also possible to monitor changes to action groups using
 | 
			
		||||
@@ -52,13 +50,13 @@ G_DEFINE_INTERFACE (GActionObserver, g_action_observer, G_TYPE_OBJECT)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
g_action_observer_default_init (GActionObserverInterface *class)
 | 
			
		||||
gtk_action_observer_default_init (GtkActionObserverInterface *class)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * g_action_observer_action_added:
 | 
			
		||||
 * @observer: a #GActionObserver
 | 
			
		||||
/**
 | 
			
		||||
 * gtk_action_observer_action_added:
 | 
			
		||||
 * @observer: a #GtkActionObserver
 | 
			
		||||
 * @observable: the source of the event
 | 
			
		||||
 * @action_name: the name of the action
 | 
			
		||||
 * @enabled: %TRUE if the action is now enabled
 | 
			
		||||
@@ -74,22 +72,22 @@ g_action_observer_default_init (GActionObserverInterface *class)
 | 
			
		||||
 * observer has explicitly registered itself to receive events.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
g_action_observer_action_added (GActionObserver    *observer,
 | 
			
		||||
                                GActionObservable  *observable,
 | 
			
		||||
                                const gchar        *action_name,
 | 
			
		||||
                                const GVariantType *parameter_type,
 | 
			
		||||
                                gboolean            enabled,
 | 
			
		||||
                                GVariant           *state)
 | 
			
		||||
gtk_action_observer_action_added (GtkActionObserver   *observer,
 | 
			
		||||
                                  GtkActionObservable *observable,
 | 
			
		||||
                                  const gchar         *action_name,
 | 
			
		||||
                                  const GVariantType  *parameter_type,
 | 
			
		||||
                                  gboolean             enabled,
 | 
			
		||||
                                  GVariant            *state)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (G_IS_ACTION_OBSERVER (observer));
 | 
			
		||||
  g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
 | 
			
		||||
 | 
			
		||||
  G_ACTION_OBSERVER_GET_IFACE (observer)
 | 
			
		||||
  GTK_ACTION_OBSERVER_GET_IFACE (observer)
 | 
			
		||||
    ->action_added (observer, observable, action_name, parameter_type, enabled, state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * g_action_observer_action_enabled_changed:
 | 
			
		||||
 * @observer: a #GActionObserver
 | 
			
		||||
/**
 | 
			
		||||
 * gtk_action_observer_action_enabled_changed:
 | 
			
		||||
 * @observer: a #GtkActionObserver
 | 
			
		||||
 * @observable: the source of the event
 | 
			
		||||
 * @action_name: the name of the action
 | 
			
		||||
 * @enabled: %TRUE if the action is now enabled
 | 
			
		||||
@@ -101,45 +99,45 @@ g_action_observer_action_added (GActionObserver    *observer,
 | 
			
		||||
 * observer has explicitly registered itself to receive events.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
g_action_observer_action_enabled_changed (GActionObserver   *observer,
 | 
			
		||||
                                          GActionObservable *observable,
 | 
			
		||||
                                          const gchar       *action_name,
 | 
			
		||||
                                          gboolean           enabled)
 | 
			
		||||
gtk_action_observer_action_enabled_changed (GtkActionObserver   *observer,
 | 
			
		||||
                                            GtkActionObservable *observable,
 | 
			
		||||
                                            const gchar         *action_name,
 | 
			
		||||
                                            gboolean             enabled)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (G_IS_ACTION_OBSERVER (observer));
 | 
			
		||||
  g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
 | 
			
		||||
 | 
			
		||||
  G_ACTION_OBSERVER_GET_IFACE (observer)
 | 
			
		||||
  GTK_ACTION_OBSERVER_GET_IFACE (observer)
 | 
			
		||||
    ->action_enabled_changed (observer, observable, action_name, enabled);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * g_action_observer_action_state_changed:
 | 
			
		||||
 * @observer: a #GActionObserver
 | 
			
		||||
/**
 | 
			
		||||
 * gtk_action_observer_action_state_changed:
 | 
			
		||||
 * @observer: a #GtkActionObserver
 | 
			
		||||
 * @observable: the source of the event
 | 
			
		||||
 * @action_name: the name of the action
 | 
			
		||||
 * @state: the new state of the action
 | 
			
		||||
 *
 | 
			
		||||
 * This function is called when an action that the observer is
 | 
			
		||||
 * registered to receive events for changes its state.
 | 
			
		||||
 * registered to receive events for changes to its state.
 | 
			
		||||
 *
 | 
			
		||||
 * This function should only be called by objects with which the
 | 
			
		||||
 * observer has explicitly registered itself to receive events.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
g_action_observer_action_state_changed (GActionObserver   *observer,
 | 
			
		||||
                                        GActionObservable *observable,
 | 
			
		||||
                                        const gchar       *action_name,
 | 
			
		||||
                                        GVariant          *state)
 | 
			
		||||
gtk_action_observer_action_state_changed (GtkActionObserver   *observer,
 | 
			
		||||
                                          GtkActionObservable *observable,
 | 
			
		||||
                                          const gchar         *action_name,
 | 
			
		||||
                                          GVariant            *state)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (G_IS_ACTION_OBSERVER (observer));
 | 
			
		||||
  g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
 | 
			
		||||
 | 
			
		||||
  G_ACTION_OBSERVER_GET_IFACE (observer)
 | 
			
		||||
  GTK_ACTION_OBSERVER_GET_IFACE (observer)
 | 
			
		||||
    ->action_state_changed (observer, observable, action_name, state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * g_action_observer_action_removed:
 | 
			
		||||
 * @observer: a #GActionObserver
 | 
			
		||||
/**
 | 
			
		||||
 * gtk_action_observer_action_removed:
 | 
			
		||||
 * @observer: a #GtkActionObserver
 | 
			
		||||
 * @observable: the source of the event
 | 
			
		||||
 * @action_name: the name of the action
 | 
			
		||||
 *
 | 
			
		||||
@@ -150,12 +148,12 @@ g_action_observer_action_state_changed (GActionObserver   *observer,
 | 
			
		||||
 * observer has explicitly registered itself to receive events.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
g_action_observer_action_removed (GActionObserver   *observer,
 | 
			
		||||
                                  GActionObservable *observable,
 | 
			
		||||
                                  const gchar       *action_name)
 | 
			
		||||
gtk_action_observer_action_removed (GtkActionObserver   *observer,
 | 
			
		||||
                                    GtkActionObservable *observable,
 | 
			
		||||
                                    const gchar         *action_name)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (G_IS_ACTION_OBSERVER (observer));
 | 
			
		||||
  g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
 | 
			
		||||
 | 
			
		||||
  G_ACTION_OBSERVER_GET_IFACE (observer)
 | 
			
		||||
  GTK_ACTION_OBSERVER_GET_IFACE (observer)
 | 
			
		||||
    ->action_removed (observer, observable, action_name);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										83
									
								
								src/gtkactionobserver.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/gtkactionobserver.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2011 Canonical Limited
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as
 | 
			
		||||
 * published by the Free Software Foundation; either version 2 of the
 | 
			
		||||
 * licence or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * Authors: Ryan Lortie <desrt@desrt.ca>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __GTK_ACTION_OBSERVER_H__
 | 
			
		||||
#define __GTK_ACTION_OBSERVER_H__
 | 
			
		||||
 | 
			
		||||
#include <gio/gio.h>
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define GTK_TYPE_ACTION_OBSERVER                            (gtk_action_observer_get_type ())
 | 
			
		||||
#define GTK_ACTION_OBSERVER(inst)                           (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
 | 
			
		||||
                                                             GTK_TYPE_ACTION_OBSERVER, GtkActionObserver))
 | 
			
		||||
#define GTK_IS_ACTION_OBSERVER(inst)                        (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
 | 
			
		||||
                                                             GTK_TYPE_ACTION_OBSERVER))
 | 
			
		||||
#define GTK_ACTION_OBSERVER_GET_IFACE(inst)                 (G_TYPE_INSTANCE_GET_INTERFACE ((inst),                  \
 | 
			
		||||
                                                             GTK_TYPE_ACTION_OBSERVER, GtkActionObserverInterface))
 | 
			
		||||
 | 
			
		||||
typedef struct _GtkActionObserverInterface                  GtkActionObserverInterface;
 | 
			
		||||
typedef struct _GtkActionObservable                         GtkActionObservable;
 | 
			
		||||
typedef struct _GtkActionObserver                           GtkActionObserver;
 | 
			
		||||
 | 
			
		||||
struct _GtkActionObserverInterface
 | 
			
		||||
{
 | 
			
		||||
  GTypeInterface g_iface;
 | 
			
		||||
 | 
			
		||||
  void (* action_added)           (GtkActionObserver    *observer,
 | 
			
		||||
                                   GtkActionObservable  *observable,
 | 
			
		||||
                                   const gchar          *action_name,
 | 
			
		||||
                                   const GVariantType   *parameter_type,
 | 
			
		||||
                                   gboolean              enabled,
 | 
			
		||||
                                   GVariant             *state);
 | 
			
		||||
  void (* action_enabled_changed) (GtkActionObserver    *observer,
 | 
			
		||||
                                   GtkActionObservable  *observable,
 | 
			
		||||
                                   const gchar          *action_name,
 | 
			
		||||
                                   gboolean              enabled);
 | 
			
		||||
  void (* action_state_changed)   (GtkActionObserver    *observer,
 | 
			
		||||
                                   GtkActionObservable  *observable,
 | 
			
		||||
                                   const gchar          *action_name,
 | 
			
		||||
                                   GVariant             *state);
 | 
			
		||||
  void (* action_removed)         (GtkActionObserver    *observer,
 | 
			
		||||
                                   GtkActionObservable  *observable,
 | 
			
		||||
                                   const gchar          *action_name);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
GType                   gtk_action_observer_get_type                    (void);
 | 
			
		||||
void                    gtk_action_observer_action_added                (GtkActionObserver   *observer,
 | 
			
		||||
                                                                         GtkActionObservable *observable,
 | 
			
		||||
                                                                         const gchar         *action_name,
 | 
			
		||||
                                                                         const GVariantType  *parameter_type,
 | 
			
		||||
                                                                         gboolean             enabled,
 | 
			
		||||
                                                                         GVariant            *state);
 | 
			
		||||
void                    gtk_action_observer_action_enabled_changed      (GtkActionObserver   *observer,
 | 
			
		||||
                                                                         GtkActionObservable *observable,
 | 
			
		||||
                                                                         const gchar         *action_name,
 | 
			
		||||
                                                                         gboolean             enabled);
 | 
			
		||||
void                    gtk_action_observer_action_state_changed        (GtkActionObserver   *observer,
 | 
			
		||||
                                                                         GtkActionObservable *observable,
 | 
			
		||||
                                                                         const gchar         *action_name,
 | 
			
		||||
                                                                         GVariant            *state);
 | 
			
		||||
void                    gtk_action_observer_action_removed              (GtkActionObserver   *observer,
 | 
			
		||||
                                                                         GtkActionObservable *observable,
 | 
			
		||||
                                                                         const gchar         *action_name);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif /* __GTK_ACTION_OBSERVER_H__ */
 | 
			
		||||
							
								
								
									
										495
									
								
								src/gtkmenutracker.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										495
									
								
								src/gtkmenutracker.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,495 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2013 Canonical Limited
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the licence, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the
 | 
			
		||||
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 | 
			
		||||
 * Boston, MA 02111-1307, USA.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Ryan Lortie <desrt@desrt.ca>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "gtkmenutracker.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SECTION:gtkmenutracker
 | 
			
		||||
 * @Title: GtkMenuTracker
 | 
			
		||||
 * @Short_description: A helper class for interpreting #GMenuModel
 | 
			
		||||
 *
 | 
			
		||||
 * #GtkMenuTracker is a simple object to ease implementations of #GMenuModel.
 | 
			
		||||
 * Given a #GtkActionObservable (usually a #GActionMuxer) along with a
 | 
			
		||||
 * #GMenuModel, it will tell you which menu items to create and where to place
 | 
			
		||||
 * them. If a menu item is removed, it will tell you the position of the menu
 | 
			
		||||
 * item to remove.
 | 
			
		||||
 *
 | 
			
		||||
 * Using #GtkMenuTracker is fairly simple. The only guarantee you must make
 | 
			
		||||
 * to #GtkMenuTracker is that you must obey all insert signals and track the
 | 
			
		||||
 * position of items that #GtkMenuTracker gives you. That is, #GtkMenuTracker
 | 
			
		||||
 * expects positions of all the latter items to change when it calls your
 | 
			
		||||
 * insertion callback with an early position, as it may ask you to remove
 | 
			
		||||
 * an item with a readjusted position later.
 | 
			
		||||
 *
 | 
			
		||||
 * #GtkMenuTracker will give you a #GtkMenuTrackerItem in your callback. You
 | 
			
		||||
 * must hold onto this object until a remove signal is emitted. This item
 | 
			
		||||
 * represents a single menu item, which can be one of three classes: normal item,
 | 
			
		||||
 * separator, or submenu.
 | 
			
		||||
 *
 | 
			
		||||
 * Certain properties on the #GtkMenuTrackerItem are mutable, and you must
 | 
			
		||||
 * listen for changes in the item. For more details, see the documentation
 | 
			
		||||
 * for #GtkMenuTrackerItem along with https://live.gnome.org/GApplication/GMenuModel.
 | 
			
		||||
 *
 | 
			
		||||
 * The idea of @with_separators is for special cases where menu models may
 | 
			
		||||
 * be tracked in places where separators are not available, like in toplevel
 | 
			
		||||
 * "File", "Edit" menu bars. Ignoring separator items is wrong, as #GtkMenuTracker
 | 
			
		||||
 * expects the position to change, so we must tell #GtkMenuTracker to ignore
 | 
			
		||||
 * separators itself.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
typedef struct _GtkMenuTrackerSection GtkMenuTrackerSection;
 | 
			
		||||
 | 
			
		||||
struct _GtkMenuTracker
 | 
			
		||||
{
 | 
			
		||||
  GtkActionObservable      *observable;
 | 
			
		||||
  GtkMenuTrackerInsertFunc  insert_func;
 | 
			
		||||
  GtkMenuTrackerRemoveFunc  remove_func;
 | 
			
		||||
  gpointer                  user_data;
 | 
			
		||||
 | 
			
		||||
  GtkMenuTrackerSection    *toplevel;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _GtkMenuTrackerSection
 | 
			
		||||
{
 | 
			
		||||
  GMenuModel *model;
 | 
			
		||||
  GSList     *items;
 | 
			
		||||
  gchar      *action_namespace;
 | 
			
		||||
 | 
			
		||||
  guint       with_separators : 1;
 | 
			
		||||
  guint       has_separator   : 1;
 | 
			
		||||
 | 
			
		||||
  gulong      handler;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static GtkMenuTrackerSection *  gtk_menu_tracker_section_new    (GtkMenuTracker        *tracker,
 | 
			
		||||
                                                                 GMenuModel            *model,
 | 
			
		||||
                                                                 gboolean               with_separators,
 | 
			
		||||
                                                                 gint                   offset,
 | 
			
		||||
                                                                 const gchar           *action_namespace);
 | 
			
		||||
static void                    gtk_menu_tracker_section_free    (GtkMenuTrackerSection *section);
 | 
			
		||||
 | 
			
		||||
static GtkMenuTrackerSection *
 | 
			
		||||
gtk_menu_tracker_section_find_model (GtkMenuTrackerSection *section,
 | 
			
		||||
                                     GMenuModel            *model,
 | 
			
		||||
                                     gint                  *offset)
 | 
			
		||||
{
 | 
			
		||||
  GSList *item;
 | 
			
		||||
 | 
			
		||||
  if (section->has_separator)
 | 
			
		||||
    (*offset)++;
 | 
			
		||||
 | 
			
		||||
  if (section->model == model)
 | 
			
		||||
    return section;
 | 
			
		||||
 | 
			
		||||
  for (item = section->items; item; item = item->next)
 | 
			
		||||
    {
 | 
			
		||||
      GtkMenuTrackerSection *subsection = item->data;
 | 
			
		||||
 | 
			
		||||
      if (subsection)
 | 
			
		||||
        {
 | 
			
		||||
          GtkMenuTrackerSection *found_section;
 | 
			
		||||
 | 
			
		||||
          found_section = gtk_menu_tracker_section_find_model (subsection, model, offset);
 | 
			
		||||
 | 
			
		||||
          if (found_section)
 | 
			
		||||
            return found_section;
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        (*offset)++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* this is responsible for syncing the showing of a separator for a
 | 
			
		||||
 * single subsection (and its children).
 | 
			
		||||
 *
 | 
			
		||||
 * we only ever show separators if we have _actual_ children (ie: we do
 | 
			
		||||
 * not show a separator if the section contains only empty child
 | 
			
		||||
 * sections).  it's difficult to determine this on-the-fly, so we have
 | 
			
		||||
 * this separate function to come back later and figure it out.
 | 
			
		||||
 *
 | 
			
		||||
 * 'section' is that section.
 | 
			
		||||
 *
 | 
			
		||||
 * 'tracker' is passed in so that we can emit callbacks when we decide
 | 
			
		||||
 * to add/remove separators.
 | 
			
		||||
 *
 | 
			
		||||
 * 'offset' is passed in so we know which position to emit in our
 | 
			
		||||
 * callbacks.  ie: if we add a separator right at the top of this
 | 
			
		||||
 * section then we would emit it with this offset.  deeper inside, we
 | 
			
		||||
 * adjust accordingly.
 | 
			
		||||
 *
 | 
			
		||||
 * could_have_separator is true in two situations:
 | 
			
		||||
 *
 | 
			
		||||
 *  - our parent section had with_separators defined and we are not the
 | 
			
		||||
 *    first section (ie: we should add a separator if we have content in
 | 
			
		||||
 *    order to divide us from the items above)
 | 
			
		||||
 *
 | 
			
		||||
 *  - if we had a 'label' attribute set for this section
 | 
			
		||||
 *
 | 
			
		||||
 * parent_model and parent_index are passed in so that we can give them
 | 
			
		||||
 * to the insertion callback so that it can see the label (and anything
 | 
			
		||||
 * else that happens to be defined on the section).
 | 
			
		||||
 *
 | 
			
		||||
 * we iterate each item in ourselves.  for subsections, we recursively
 | 
			
		||||
 * run ourselves to sync separators.  after we are done, we notice if we
 | 
			
		||||
 * have any items in us or if we are completely empty and sync if our
 | 
			
		||||
 * separator is shown or not.
 | 
			
		||||
 */
 | 
			
		||||
static gint
 | 
			
		||||
gtk_menu_tracker_section_sync_separators (GtkMenuTrackerSection *section,
 | 
			
		||||
                                          GtkMenuTracker        *tracker,
 | 
			
		||||
                                          gint                   offset,
 | 
			
		||||
                                          gboolean               could_have_separator,
 | 
			
		||||
                                          GMenuModel            *parent_model,
 | 
			
		||||
                                          gint                   parent_index)
 | 
			
		||||
{
 | 
			
		||||
  gboolean should_have_separator;
 | 
			
		||||
  gint n_items = 0;
 | 
			
		||||
  GSList *item;
 | 
			
		||||
  gint i = 0;
 | 
			
		||||
 | 
			
		||||
  for (item = section->items; item; item = item->next)
 | 
			
		||||
    {
 | 
			
		||||
      GtkMenuTrackerSection *subsection = item->data;
 | 
			
		||||
 | 
			
		||||
      if (subsection)
 | 
			
		||||
        {
 | 
			
		||||
          gboolean could_have_separator;
 | 
			
		||||
 | 
			
		||||
          could_have_separator = (section->with_separators && i > 0) ||
 | 
			
		||||
                                 g_menu_model_get_item_attribute (section->model, i, "label", "s", NULL);
 | 
			
		||||
 | 
			
		||||
          n_items += gtk_menu_tracker_section_sync_separators (subsection, tracker, offset + n_items,
 | 
			
		||||
                                                               could_have_separator, section->model, i);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        n_items++;
 | 
			
		||||
 | 
			
		||||
      i++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  should_have_separator = could_have_separator && n_items != 0;
 | 
			
		||||
 | 
			
		||||
  if (should_have_separator > section->has_separator)
 | 
			
		||||
    {
 | 
			
		||||
      /* Add a separator */
 | 
			
		||||
      GtkMenuTrackerItem *item;
 | 
			
		||||
 | 
			
		||||
      item = _gtk_menu_tracker_item_new (tracker->observable, parent_model, parent_index, NULL, TRUE);
 | 
			
		||||
      (* tracker->insert_func) (item, offset, tracker->user_data);
 | 
			
		||||
      g_object_unref (item);
 | 
			
		||||
 | 
			
		||||
      section->has_separator = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  else if (should_have_separator < section->has_separator)
 | 
			
		||||
    {
 | 
			
		||||
      /* Remove a separator */
 | 
			
		||||
      (* tracker->remove_func) (offset, tracker->user_data);
 | 
			
		||||
      section->has_separator = FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  n_items += section->has_separator;
 | 
			
		||||
 | 
			
		||||
  return n_items;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gint
 | 
			
		||||
gtk_menu_tracker_section_measure (GtkMenuTrackerSection *section)
 | 
			
		||||
{
 | 
			
		||||
  GSList *item;
 | 
			
		||||
  gint n_items;
 | 
			
		||||
 | 
			
		||||
  if (section == NULL)
 | 
			
		||||
    return 1;
 | 
			
		||||
 | 
			
		||||
  n_items = 0;
 | 
			
		||||
 | 
			
		||||
  if (section->has_separator)
 | 
			
		||||
    n_items++;
 | 
			
		||||
 | 
			
		||||
  for (item = section->items; item; item = item->next)
 | 
			
		||||
    n_items += gtk_menu_tracker_section_measure (item->data);
 | 
			
		||||
 | 
			
		||||
  return n_items;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_remove_items (GtkMenuTracker  *tracker,
 | 
			
		||||
                               GSList         **change_point,
 | 
			
		||||
                               gint             offset,
 | 
			
		||||
                               gint             n_items)
 | 
			
		||||
{
 | 
			
		||||
  gint i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < n_items; i++)
 | 
			
		||||
    {
 | 
			
		||||
      GtkMenuTrackerSection *subsection;
 | 
			
		||||
      gint n;
 | 
			
		||||
 | 
			
		||||
      subsection = (*change_point)->data;
 | 
			
		||||
      *change_point = g_slist_delete_link (*change_point, *change_point);
 | 
			
		||||
 | 
			
		||||
      n = gtk_menu_tracker_section_measure (subsection);
 | 
			
		||||
      gtk_menu_tracker_section_free (subsection);
 | 
			
		||||
 | 
			
		||||
      while (n--)
 | 
			
		||||
        (* tracker->remove_func) (offset, tracker->user_data);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_add_items (GtkMenuTracker         *tracker,
 | 
			
		||||
                            GtkMenuTrackerSection  *section,
 | 
			
		||||
                            GSList                **change_point,
 | 
			
		||||
                            gint                    offset,
 | 
			
		||||
                            GMenuModel             *model,
 | 
			
		||||
                            gint                    position,
 | 
			
		||||
                            gint                    n_items)
 | 
			
		||||
{
 | 
			
		||||
  while (n_items--)
 | 
			
		||||
    {
 | 
			
		||||
      GMenuModel *submenu;
 | 
			
		||||
 | 
			
		||||
      submenu = g_menu_model_get_item_link (model, position + n_items, G_MENU_LINK_SECTION);
 | 
			
		||||
      g_assert (submenu != model);
 | 
			
		||||
      if (submenu != NULL)
 | 
			
		||||
        {
 | 
			
		||||
          GtkMenuTrackerSection *subsection;
 | 
			
		||||
          gchar *action_namespace = NULL;
 | 
			
		||||
 | 
			
		||||
          g_menu_model_get_item_attribute (model, position + n_items,
 | 
			
		||||
                                           G_MENU_ATTRIBUTE_ACTION_NAMESPACE, "s", &action_namespace);
 | 
			
		||||
 | 
			
		||||
          if (section->action_namespace)
 | 
			
		||||
            {
 | 
			
		||||
              gchar *namespace;
 | 
			
		||||
 | 
			
		||||
              namespace = g_strjoin (".", section->action_namespace, action_namespace, NULL);
 | 
			
		||||
              subsection = gtk_menu_tracker_section_new (tracker, submenu, FALSE, offset, namespace);
 | 
			
		||||
              g_free (namespace);
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            subsection = gtk_menu_tracker_section_new (tracker, submenu, FALSE, offset, section->action_namespace);
 | 
			
		||||
 | 
			
		||||
          *change_point = g_slist_prepend (*change_point, subsection);
 | 
			
		||||
          g_free (action_namespace);
 | 
			
		||||
          g_object_unref (submenu);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          GtkMenuTrackerItem *item;
 | 
			
		||||
 | 
			
		||||
          item = _gtk_menu_tracker_item_new (tracker->observable, model, position + n_items,
 | 
			
		||||
                                             section->action_namespace, FALSE);
 | 
			
		||||
          (* tracker->insert_func) (item, offset, tracker->user_data);
 | 
			
		||||
          g_object_unref (item);
 | 
			
		||||
 | 
			
		||||
          *change_point = g_slist_prepend (*change_point, NULL);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_model_changed (GMenuModel *model,
 | 
			
		||||
                                gint        position,
 | 
			
		||||
                                gint        removed,
 | 
			
		||||
                                gint        added,
 | 
			
		||||
                                gpointer    user_data)
 | 
			
		||||
{
 | 
			
		||||
  GtkMenuTracker *tracker = user_data;
 | 
			
		||||
  GtkMenuTrackerSection *section;
 | 
			
		||||
  GSList **change_point;
 | 
			
		||||
  gint offset = 0;
 | 
			
		||||
  gint i;
 | 
			
		||||
 | 
			
		||||
  /* First find which section the changed model corresponds to, and the
 | 
			
		||||
   * position of that section within the overall menu.
 | 
			
		||||
   */
 | 
			
		||||
  section = gtk_menu_tracker_section_find_model (tracker->toplevel, model, &offset);
 | 
			
		||||
 | 
			
		||||
  /* Next, seek through that section to the change point.  This gives us
 | 
			
		||||
   * the correct GSList** to make the change to and also finds the final
 | 
			
		||||
   * offset at which we will make the changes (by measuring the number
 | 
			
		||||
   * of items within each item of the section before the change point).
 | 
			
		||||
   */
 | 
			
		||||
  change_point = §ion->items;
 | 
			
		||||
  for (i = 0; i < position; i++)
 | 
			
		||||
    {
 | 
			
		||||
      offset += gtk_menu_tracker_section_measure ((*change_point)->data);
 | 
			
		||||
      change_point = &(*change_point)->next;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* We remove items in order and add items in reverse order.  This
 | 
			
		||||
   * means that the offset used for all inserts and removes caused by a
 | 
			
		||||
   * single change will be the same.
 | 
			
		||||
   *
 | 
			
		||||
   * This also has a performance advantage: GtkMenuShell stores the
 | 
			
		||||
   * menu items in a linked list.  In the case where we are creating a
 | 
			
		||||
   * menu for the first time, adding the items in reverse order means
 | 
			
		||||
   * that we only ever insert at index zero, prepending the list.  This
 | 
			
		||||
   * means that we can populate in O(n) time instead of O(n^2) that we
 | 
			
		||||
   * would do by appending.
 | 
			
		||||
   */
 | 
			
		||||
  gtk_menu_tracker_remove_items (tracker, change_point, offset, removed);
 | 
			
		||||
  gtk_menu_tracker_add_items (tracker, section, change_point, offset, model, position, added);
 | 
			
		||||
 | 
			
		||||
  /* The offsets for insertion/removal of separators will be all over
 | 
			
		||||
   * the place, however...
 | 
			
		||||
   */
 | 
			
		||||
  gtk_menu_tracker_section_sync_separators (tracker->toplevel, tracker, 0, FALSE, NULL, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_section_free (GtkMenuTrackerSection *section)
 | 
			
		||||
{
 | 
			
		||||
  if (section == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  g_signal_handler_disconnect (section->model, section->handler);
 | 
			
		||||
  g_slist_free_full (section->items, (GDestroyNotify) gtk_menu_tracker_section_free);
 | 
			
		||||
  g_free (section->action_namespace);
 | 
			
		||||
  g_object_unref (section->model);
 | 
			
		||||
  g_slice_free (GtkMenuTrackerSection, section);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GtkMenuTrackerSection *
 | 
			
		||||
gtk_menu_tracker_section_new (GtkMenuTracker *tracker,
 | 
			
		||||
                              GMenuModel     *model,
 | 
			
		||||
                              gboolean        with_separators,
 | 
			
		||||
                              gint            offset,
 | 
			
		||||
                              const gchar    *action_namespace)
 | 
			
		||||
{
 | 
			
		||||
  GtkMenuTrackerSection *section;
 | 
			
		||||
 | 
			
		||||
  section = g_slice_new0 (GtkMenuTrackerSection);
 | 
			
		||||
  section->model = g_object_ref (model);
 | 
			
		||||
  section->with_separators = with_separators;
 | 
			
		||||
  section->action_namespace = g_strdup (action_namespace);
 | 
			
		||||
 | 
			
		||||
  gtk_menu_tracker_add_items (tracker, section, §ion->items, offset, model, 0, g_menu_model_get_n_items (model));
 | 
			
		||||
  section->handler = g_signal_connect (model, "items-changed", G_CALLBACK (gtk_menu_tracker_model_changed), tracker);
 | 
			
		||||
 | 
			
		||||
  return section;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*< private >
 | 
			
		||||
 * gtk_menu_tracker_new:
 | 
			
		||||
 * @model: the model to flatten
 | 
			
		||||
 * @with_separators: if the toplevel should have separators (ie: TRUE
 | 
			
		||||
 *   for menus, FALSE for menubars)
 | 
			
		||||
 * @action_namespace: the passed-in action namespace
 | 
			
		||||
 * @insert_func: insert callback
 | 
			
		||||
 * @remove_func: remove callback
 | 
			
		||||
 * @user_data user data for callbacks
 | 
			
		||||
 *
 | 
			
		||||
 * Creates a GtkMenuTracker for @model, holding a ref on @model for as
 | 
			
		||||
 * long as the tracker is alive.
 | 
			
		||||
 *
 | 
			
		||||
 * This flattens out the model, merging sections and inserting
 | 
			
		||||
 * separators where appropriate.  It monitors for changes and performs
 | 
			
		||||
 * updates on the fly.  It also handles action_namespace for subsections
 | 
			
		||||
 * (but you will need to handle it yourself for submenus).
 | 
			
		||||
 *
 | 
			
		||||
 * When the tracker is first created, @insert_func will be called many
 | 
			
		||||
 * times to populate the menu with the initial contents of @model
 | 
			
		||||
 * (unless it is empty), before gtk_menu_tracker_new() returns.  For
 | 
			
		||||
 * this reason, the menu that is using the tracker ought to be empty
 | 
			
		||||
 * when it creates the tracker.
 | 
			
		||||
 *
 | 
			
		||||
 * Future changes to @model will result in more calls to @insert_func
 | 
			
		||||
 * and @remove_func.
 | 
			
		||||
 *
 | 
			
		||||
 * The position argument to both functions is the linear 0-based
 | 
			
		||||
 * position in the menu at which the item in question should be inserted
 | 
			
		||||
 * or removed.
 | 
			
		||||
 *
 | 
			
		||||
 * For @insert_func, @model and @item_index are used to get the
 | 
			
		||||
 * information about the menu item to insert.  @action_namespace is the
 | 
			
		||||
 * action namespace that actions referred to from that item should place
 | 
			
		||||
 * themselves in.  Note that if the item is a submenu and the
 | 
			
		||||
 * "action-namespace" attribute is defined on the item, it will _not_ be
 | 
			
		||||
 * applied to the @action_namespace argument as it is meant for the
 | 
			
		||||
 * items inside of the submenu, not the submenu item itself.
 | 
			
		||||
 *
 | 
			
		||||
 * @is_separator is set to %TRUE in case the item being added is a
 | 
			
		||||
 * separator.  @model and @item_index will still be meaningfully set in
 | 
			
		||||
 * this case -- to the section menu item corresponding to the separator.
 | 
			
		||||
 * This is useful if the section specifies a label, for example.  If
 | 
			
		||||
 * there is an "action-namespace" attribute on this menu item then it
 | 
			
		||||
 * should be ignored by the consumer because #GtkMenuTracker has already
 | 
			
		||||
 * handled it.
 | 
			
		||||
 *
 | 
			
		||||
 * When using #GtkMenuTracker there is no need to hold onto @model or
 | 
			
		||||
 * monitor it for changes.  The model will be unreffed when
 | 
			
		||||
 * gtk_menu_tracker_free() is called.
 | 
			
		||||
 */
 | 
			
		||||
GtkMenuTracker *
 | 
			
		||||
gtk_menu_tracker_new (GtkActionObservable      *observable,
 | 
			
		||||
                      GMenuModel               *model,
 | 
			
		||||
                      gboolean                  with_separators,
 | 
			
		||||
                      const gchar              *action_namespace,
 | 
			
		||||
                      GtkMenuTrackerInsertFunc  insert_func,
 | 
			
		||||
                      GtkMenuTrackerRemoveFunc  remove_func,
 | 
			
		||||
                      gpointer                  user_data)
 | 
			
		||||
{
 | 
			
		||||
  GtkMenuTracker *tracker;
 | 
			
		||||
 | 
			
		||||
  tracker = g_slice_new (GtkMenuTracker);
 | 
			
		||||
  tracker->observable = g_object_ref (observable);
 | 
			
		||||
  tracker->insert_func = insert_func;
 | 
			
		||||
  tracker->remove_func = remove_func;
 | 
			
		||||
  tracker->user_data = user_data;
 | 
			
		||||
 | 
			
		||||
  tracker->toplevel = gtk_menu_tracker_section_new (tracker, model, with_separators, 0, action_namespace);
 | 
			
		||||
  gtk_menu_tracker_section_sync_separators (tracker->toplevel, tracker, 0, FALSE, NULL, 0);
 | 
			
		||||
 | 
			
		||||
  return tracker;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GtkMenuTracker *
 | 
			
		||||
gtk_menu_tracker_new_for_item_submenu (GtkMenuTrackerItem       *item,
 | 
			
		||||
                                       GtkMenuTrackerInsertFunc  insert_func,
 | 
			
		||||
                                       GtkMenuTrackerRemoveFunc  remove_func,
 | 
			
		||||
                                       gpointer                  user_data)
 | 
			
		||||
{
 | 
			
		||||
  return gtk_menu_tracker_new (_gtk_menu_tracker_item_get_observable (item),
 | 
			
		||||
                               _gtk_menu_tracker_item_get_submenu (item),
 | 
			
		||||
                               TRUE,
 | 
			
		||||
                               _gtk_menu_tracker_item_get_submenu_namespace (item),
 | 
			
		||||
                               insert_func, remove_func, user_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*< private >
 | 
			
		||||
 * gtk_menu_tracker_free:
 | 
			
		||||
 * @tracker: a #GtkMenuTracker
 | 
			
		||||
 *
 | 
			
		||||
 * Frees the tracker, ...
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
gtk_menu_tracker_free (GtkMenuTracker *tracker)
 | 
			
		||||
{
 | 
			
		||||
  gtk_menu_tracker_section_free (tracker->toplevel);
 | 
			
		||||
  g_object_unref (tracker->observable);
 | 
			
		||||
  g_slice_free (GtkMenuTracker, tracker);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								src/gtkmenutracker.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/gtkmenutracker.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2013 Canonical Limited
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the licence, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the
 | 
			
		||||
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 | 
			
		||||
 * Boston, MA 02111-1307, USA.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Ryan Lortie <desrt@desrt.ca>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __GTK_MENU_TRACKER_H__
 | 
			
		||||
#define __GTK_MENU_TRACKER_H__
 | 
			
		||||
 | 
			
		||||
#include "gtkmenutrackeritem.h"
 | 
			
		||||
 | 
			
		||||
typedef struct _GtkMenuTracker GtkMenuTracker;
 | 
			
		||||
 | 
			
		||||
typedef void         (* GtkMenuTrackerInsertFunc)                       (GtkMenuTrackerItem       *item,
 | 
			
		||||
                                                                         gint                      position,
 | 
			
		||||
                                                                         gpointer                  user_data);
 | 
			
		||||
 | 
			
		||||
typedef void         (* GtkMenuTrackerRemoveFunc)                       (gint                      position,
 | 
			
		||||
                                                                         gpointer                  user_data);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
GtkMenuTracker *        gtk_menu_tracker_new                            (GtkActionObservable      *observer,
 | 
			
		||||
                                                                         GMenuModel               *model,
 | 
			
		||||
                                                                         gboolean                  with_separators,
 | 
			
		||||
                                                                         const gchar              *action_namespace,
 | 
			
		||||
                                                                         GtkMenuTrackerInsertFunc  insert_func,
 | 
			
		||||
                                                                         GtkMenuTrackerRemoveFunc  remove_func,
 | 
			
		||||
                                                                         gpointer                  user_data);
 | 
			
		||||
 | 
			
		||||
GtkMenuTracker *        gtk_menu_tracker_new_for_item_submenu           (GtkMenuTrackerItem       *item,
 | 
			
		||||
                                                                         GtkMenuTrackerInsertFunc  insert_func,
 | 
			
		||||
                                                                         GtkMenuTrackerRemoveFunc  remove_func,
 | 
			
		||||
                                                                         gpointer                  user_data);
 | 
			
		||||
 | 
			
		||||
void                    gtk_menu_tracker_free                           (GtkMenuTracker           *tracker);
 | 
			
		||||
 | 
			
		||||
#endif /* __GTK_MENU_TRACKER_H__ */
 | 
			
		||||
							
								
								
									
										788
									
								
								src/gtkmenutrackeritem.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										788
									
								
								src/gtkmenutrackeritem.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,788 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2013 Canonical Limited
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the licence, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the
 | 
			
		||||
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 | 
			
		||||
 * Boston, MA 02111-1307, USA.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Ryan Lortie <desrt@desrt.ca>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "gtkmenutrackeritem.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SECTION:gtkmenutrackeritem
 | 
			
		||||
 * @Title: GtkMenuTrackerItem
 | 
			
		||||
 * @Short_description: Small helper for model menu items
 | 
			
		||||
 *
 | 
			
		||||
 * A #GtkMenuTrackerItem is a small helper class used by #GtkMenuTracker to
 | 
			
		||||
 * represent menu items. It has one of three classes: normal item, separator,
 | 
			
		||||
 * or submenu.
 | 
			
		||||
 *
 | 
			
		||||
 * If an item is one of the non-normal classes (submenu, separator), only the
 | 
			
		||||
 * label of the item needs to be respected. Otherwise, all the properties
 | 
			
		||||
 * of the item contribute to the item's appearance and state.
 | 
			
		||||
 *
 | 
			
		||||
 * Implementing the appearance of the menu item is up to toolkits, and certain
 | 
			
		||||
 * toolkits may choose to ignore certain properties, like icon or accel. The
 | 
			
		||||
 * role of the item determines its accessibility role, along with its
 | 
			
		||||
 * decoration if the GtkMenuTrackerItem::toggled property is true. As an
 | 
			
		||||
 * example, if the item has the role %GTK_MENU_TRACKER_ITEM_ROLE_CHECK and
 | 
			
		||||
 * GtkMenuTrackerItem::toggled is %FALSE, its accessible role should be that of
 | 
			
		||||
 * a check menu item, and no decoration should be drawn. But if
 | 
			
		||||
 * GtkMenuTrackerItem::toggled is %TRUE, a checkmark should be drawn.
 | 
			
		||||
 *
 | 
			
		||||
 * All properties except for the two class-determining properties,
 | 
			
		||||
 * GtkMenuTrackerItem::is-separator and GtkMenuTrackerItem::has-submenu are
 | 
			
		||||
 * allowed to change, so listen to the notify signals to update your item's
 | 
			
		||||
 * appearance. When using a GObject library, this can conveniently be done
 | 
			
		||||
 * with g_object_bind_property() and #GBinding, and this is how this is
 | 
			
		||||
 * implemented in GTK+; the appearance side is implemented in #GtkModelMenuItem.
 | 
			
		||||
 *
 | 
			
		||||
 * When an item is clicked, simply call gtk_menu_tracker_item_activated() in
 | 
			
		||||
 * response. The #GtkMenuTrackerItem will take care of everything related to
 | 
			
		||||
 * activating the item and will itself update the state of all items in
 | 
			
		||||
 * response.
 | 
			
		||||
 *
 | 
			
		||||
 * Submenus are a special case of menu item. When an item is a submenu, you
 | 
			
		||||
 * should create a submenu for it with gtk_menu_tracker_new_item_for_submenu(),
 | 
			
		||||
 * and apply the same menu tracking logic you would for a toplevel menu.
 | 
			
		||||
 * Applications using submenus may want to lazily build their submenus in
 | 
			
		||||
 * response to the user clicking on it, as building a submenu may be expensive.
 | 
			
		||||
 *
 | 
			
		||||
 * Thus, the submenu has two special controls -- the submenu's visibility
 | 
			
		||||
 * should be controlled by the GtkMenuTrackerItem::submenu-shown property,
 | 
			
		||||
 * and if a user clicks on the submenu, do not immediately show the menu,
 | 
			
		||||
 * but call gtk_menu_tracker_item_request_submenu_shown() and wait for the
 | 
			
		||||
 * GtkMenuTrackerItem::submenu-shown property to update. If the user navigates,
 | 
			
		||||
 * the application may want to be notified so it can cancel the expensive
 | 
			
		||||
 * operation that it was using to build the submenu. Thus,
 | 
			
		||||
 * gtk_menu_tracker_item_request_submenu_shown() takes a boolean parameter.
 | 
			
		||||
 * Use %TRUE when the user wants to open the submenu, and %FALSE when the
 | 
			
		||||
 * user wants to close the submenu.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
typedef GObjectClass GtkMenuTrackerItemClass;
 | 
			
		||||
 | 
			
		||||
struct _GtkMenuTrackerItem
 | 
			
		||||
{
 | 
			
		||||
  GObject parent_instance;
 | 
			
		||||
 | 
			
		||||
  GtkActionObservable *observable;
 | 
			
		||||
  gchar *action_namespace;
 | 
			
		||||
  GMenuItem *item;
 | 
			
		||||
  GtkMenuTrackerItemRole role : 4;
 | 
			
		||||
  guint is_separator : 1;
 | 
			
		||||
  guint can_activate : 1;
 | 
			
		||||
  guint sensitive : 1;
 | 
			
		||||
  guint toggled : 1;
 | 
			
		||||
  guint submenu_shown : 1;
 | 
			
		||||
  guint submenu_requested : 1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
  PROP_0,
 | 
			
		||||
  PROP_IS_SEPARATOR,
 | 
			
		||||
  PROP_HAS_SUBMENU,
 | 
			
		||||
  PROP_LABEL,
 | 
			
		||||
  PROP_ICON,
 | 
			
		||||
  PROP_SENSITIVE,
 | 
			
		||||
  PROP_VISIBLE,
 | 
			
		||||
  PROP_ROLE,
 | 
			
		||||
  PROP_TOGGLED,
 | 
			
		||||
  PROP_ACCEL,
 | 
			
		||||
  PROP_SUBMENU_SHOWN,
 | 
			
		||||
  N_PROPS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static GParamSpec *gtk_menu_tracker_item_pspecs[N_PROPS];
 | 
			
		||||
 | 
			
		||||
static void gtk_menu_tracker_item_init_observer_iface (GtkActionObserverInterface *iface);
 | 
			
		||||
G_DEFINE_TYPE_WITH_CODE (GtkMenuTrackerItem, gtk_menu_tracker_item, G_TYPE_OBJECT,
 | 
			
		||||
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTION_OBSERVER, gtk_menu_tracker_item_init_observer_iface))
 | 
			
		||||
 | 
			
		||||
GType
 | 
			
		||||
gtk_menu_tracker_item_role_get_type (void)
 | 
			
		||||
{
 | 
			
		||||
  static gsize gtk_menu_tracker_item_role_type;
 | 
			
		||||
 | 
			
		||||
  if (g_once_init_enter (>k_menu_tracker_item_role_type))
 | 
			
		||||
    {
 | 
			
		||||
      static const GEnumValue values[] = {
 | 
			
		||||
        { GTK_MENU_TRACKER_ITEM_ROLE_NORMAL, "GTK_MENU_TRACKER_ITEM_ROLE_NORMAL", "normal" },
 | 
			
		||||
        { GTK_MENU_TRACKER_ITEM_ROLE_CHECK, "GTK_MENU_TRACKER_ITEM_ROLE_CHECK", "check" },
 | 
			
		||||
        { GTK_MENU_TRACKER_ITEM_ROLE_RADIO, "GTK_MENU_TRACKER_ITEM_ROLE_RADIO", "radio" },
 | 
			
		||||
        { 0, NULL, NULL }
 | 
			
		||||
      };
 | 
			
		||||
      GType type;
 | 
			
		||||
 | 
			
		||||
      type = g_enum_register_static ("GtkMenuTrackerItemRole", values);
 | 
			
		||||
 | 
			
		||||
      g_once_init_leave (>k_menu_tracker_item_role_type, type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return gtk_menu_tracker_item_role_type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_item_get_property (GObject    *object,
 | 
			
		||||
                                    guint       prop_id,
 | 
			
		||||
                                    GValue     *value,
 | 
			
		||||
                                    GParamSpec *pspec)
 | 
			
		||||
{
 | 
			
		||||
  GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (object);
 | 
			
		||||
 | 
			
		||||
  switch (prop_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_IS_SEPARATOR:
 | 
			
		||||
      g_value_set_boolean (value, gtk_menu_tracker_item_get_is_separator (self));
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_HAS_SUBMENU:
 | 
			
		||||
      g_value_set_boolean (value, gtk_menu_tracker_item_get_has_submenu (self));
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_LABEL:
 | 
			
		||||
      g_value_set_string (value, gtk_menu_tracker_item_get_label (self));
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_ICON:
 | 
			
		||||
      g_value_set_object (value, gtk_menu_tracker_item_get_icon (self));
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_SENSITIVE:
 | 
			
		||||
      g_value_set_boolean (value, gtk_menu_tracker_item_get_sensitive (self));
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_VISIBLE:
 | 
			
		||||
      g_value_set_boolean (value, gtk_menu_tracker_item_get_visible (self));
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_ROLE:
 | 
			
		||||
      g_value_set_enum (value, gtk_menu_tracker_item_get_role (self));
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_TOGGLED:
 | 
			
		||||
      g_value_set_boolean (value, gtk_menu_tracker_item_get_toggled (self));
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_ACCEL:
 | 
			
		||||
      g_value_set_string (value, gtk_menu_tracker_item_get_accel (self));
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_SUBMENU_SHOWN:
 | 
			
		||||
      g_value_set_boolean (value, gtk_menu_tracker_item_get_submenu_shown (self));
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_item_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (object);
 | 
			
		||||
 | 
			
		||||
  g_free (self->action_namespace);
 | 
			
		||||
 | 
			
		||||
  if (self->observable)
 | 
			
		||||
    g_object_unref (self->observable);
 | 
			
		||||
 | 
			
		||||
  g_object_unref (self->item);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (gtk_menu_tracker_item_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_item_init (GtkMenuTrackerItem * self)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_item_class_init (GtkMenuTrackerItemClass *class)
 | 
			
		||||
{
 | 
			
		||||
  class->get_property = gtk_menu_tracker_item_get_property;
 | 
			
		||||
  class->finalize = gtk_menu_tracker_item_finalize;
 | 
			
		||||
 | 
			
		||||
  gtk_menu_tracker_item_pspecs[PROP_IS_SEPARATOR] =
 | 
			
		||||
    g_param_spec_boolean ("is-separator", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
 | 
			
		||||
  gtk_menu_tracker_item_pspecs[PROP_HAS_SUBMENU] =
 | 
			
		||||
    g_param_spec_boolean ("has-submenu", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
 | 
			
		||||
  gtk_menu_tracker_item_pspecs[PROP_LABEL] =
 | 
			
		||||
    g_param_spec_string ("label", "", "", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
 | 
			
		||||
  gtk_menu_tracker_item_pspecs[PROP_ICON] =
 | 
			
		||||
    g_param_spec_object ("icon", "", "", G_TYPE_ICON, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
 | 
			
		||||
  gtk_menu_tracker_item_pspecs[PROP_SENSITIVE] =
 | 
			
		||||
    g_param_spec_boolean ("sensitive", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
 | 
			
		||||
  gtk_menu_tracker_item_pspecs[PROP_VISIBLE] =
 | 
			
		||||
    g_param_spec_boolean ("visible", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
 | 
			
		||||
  gtk_menu_tracker_item_pspecs[PROP_ROLE] =
 | 
			
		||||
    g_param_spec_enum ("role", "", "",
 | 
			
		||||
                       GTK_TYPE_MENU_TRACKER_ITEM_ROLE, GTK_MENU_TRACKER_ITEM_ROLE_NORMAL,
 | 
			
		||||
                       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
 | 
			
		||||
  gtk_menu_tracker_item_pspecs[PROP_TOGGLED] =
 | 
			
		||||
    g_param_spec_boolean ("toggled", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
 | 
			
		||||
  gtk_menu_tracker_item_pspecs[PROP_ACCEL] =
 | 
			
		||||
    g_param_spec_string ("accel", "", "", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
 | 
			
		||||
  gtk_menu_tracker_item_pspecs[PROP_SUBMENU_SHOWN] =
 | 
			
		||||
    g_param_spec_boolean ("submenu-shown", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
 | 
			
		||||
 | 
			
		||||
  g_object_class_install_properties (class, N_PROPS, gtk_menu_tracker_item_pspecs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_item_action_added (GtkActionObserver   *observer,
 | 
			
		||||
                                    GtkActionObservable *observable,
 | 
			
		||||
                                    const gchar         *action_name,
 | 
			
		||||
                                    const GVariantType  *parameter_type,
 | 
			
		||||
                                    gboolean             enabled,
 | 
			
		||||
                                    GVariant            *state)
 | 
			
		||||
{
 | 
			
		||||
  GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer);
 | 
			
		||||
  GVariant *action_target;
 | 
			
		||||
 | 
			
		||||
  action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET, NULL);
 | 
			
		||||
 | 
			
		||||
  self->can_activate = (action_target == NULL && parameter_type == NULL) ||
 | 
			
		||||
                        (action_target != NULL && parameter_type != NULL &&
 | 
			
		||||
                        g_variant_is_of_type (action_target, parameter_type));
 | 
			
		||||
 | 
			
		||||
  if (!self->can_activate)
 | 
			
		||||
    {
 | 
			
		||||
      if (action_target)
 | 
			
		||||
        g_variant_unref (action_target);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  self->sensitive = enabled;
 | 
			
		||||
 | 
			
		||||
  if (action_target != NULL && state != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      self->toggled = g_variant_equal (state, action_target);
 | 
			
		||||
      self->role = GTK_MENU_TRACKER_ITEM_ROLE_RADIO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  else if (state != NULL && g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
 | 
			
		||||
    {
 | 
			
		||||
      self->toggled = g_variant_get_boolean (state);
 | 
			
		||||
      self->role = GTK_MENU_TRACKER_ITEM_ROLE_CHECK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_object_freeze_notify (G_OBJECT (self));
 | 
			
		||||
 | 
			
		||||
  if (self->sensitive)
 | 
			
		||||
    g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]);
 | 
			
		||||
 | 
			
		||||
  if (self->toggled)
 | 
			
		||||
    g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_TOGGLED]);
 | 
			
		||||
 | 
			
		||||
  if (self->role != GTK_MENU_TRACKER_ITEM_ROLE_NORMAL)
 | 
			
		||||
    g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ROLE]);
 | 
			
		||||
 | 
			
		||||
  g_object_thaw_notify (G_OBJECT (self));
 | 
			
		||||
 | 
			
		||||
  if (action_target)
 | 
			
		||||
    g_variant_unref (action_target);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_item_action_enabled_changed (GtkActionObserver   *observer,
 | 
			
		||||
                                              GtkActionObservable *observable,
 | 
			
		||||
                                              const gchar         *action_name,
 | 
			
		||||
                                              gboolean             enabled)
 | 
			
		||||
{
 | 
			
		||||
  GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer);
 | 
			
		||||
 | 
			
		||||
  if (!self->can_activate)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (self->sensitive == enabled)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  self->sensitive = enabled;
 | 
			
		||||
 | 
			
		||||
  g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_item_action_state_changed (GtkActionObserver   *observer,
 | 
			
		||||
                                            GtkActionObservable *observable,
 | 
			
		||||
                                            const gchar         *action_name,
 | 
			
		||||
                                            GVariant            *state)
 | 
			
		||||
{
 | 
			
		||||
  GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer);
 | 
			
		||||
  GVariant *action_target;
 | 
			
		||||
  gboolean was_toggled;
 | 
			
		||||
 | 
			
		||||
  if (!self->can_activate)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET, NULL);
 | 
			
		||||
  was_toggled = self->toggled;
 | 
			
		||||
 | 
			
		||||
  if (action_target)
 | 
			
		||||
    {
 | 
			
		||||
      self->toggled = g_variant_equal (state, action_target);
 | 
			
		||||
      g_variant_unref (action_target);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  else if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
 | 
			
		||||
    self->toggled = g_variant_get_boolean (state);
 | 
			
		||||
 | 
			
		||||
  else
 | 
			
		||||
    self->toggled = FALSE;
 | 
			
		||||
 | 
			
		||||
  if (self->toggled != was_toggled)
 | 
			
		||||
    g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_TOGGLED]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_item_action_removed (GtkActionObserver   *observer,
 | 
			
		||||
                                      GtkActionObservable *observable,
 | 
			
		||||
                                      const gchar         *action_name)
 | 
			
		||||
{
 | 
			
		||||
  GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer);
 | 
			
		||||
 | 
			
		||||
  if (!self->can_activate)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  g_object_freeze_notify (G_OBJECT (self));
 | 
			
		||||
 | 
			
		||||
  if (self->sensitive)
 | 
			
		||||
    {
 | 
			
		||||
      self->sensitive = FALSE;
 | 
			
		||||
      g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (self->toggled)
 | 
			
		||||
    {
 | 
			
		||||
      self->toggled = FALSE;
 | 
			
		||||
      g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_TOGGLED]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (self->role != GTK_MENU_TRACKER_ITEM_ROLE_NORMAL)
 | 
			
		||||
    {
 | 
			
		||||
      self->role = GTK_MENU_TRACKER_ITEM_ROLE_NORMAL;
 | 
			
		||||
      g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ROLE]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_object_thaw_notify (G_OBJECT (self));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_item_init_observer_iface (GtkActionObserverInterface *iface)
 | 
			
		||||
{
 | 
			
		||||
  iface->action_added = gtk_menu_tracker_item_action_added;
 | 
			
		||||
  iface->action_enabled_changed = gtk_menu_tracker_item_action_enabled_changed;
 | 
			
		||||
  iface->action_state_changed = gtk_menu_tracker_item_action_state_changed;
 | 
			
		||||
  iface->action_removed = gtk_menu_tracker_item_action_removed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GtkMenuTrackerItem *
 | 
			
		||||
_gtk_menu_tracker_item_new (GtkActionObservable *observable,
 | 
			
		||||
                            GMenuModel          *model,
 | 
			
		||||
                            gint                 item_index,
 | 
			
		||||
                            const gchar         *action_namespace,
 | 
			
		||||
                            gboolean             is_separator)
 | 
			
		||||
{
 | 
			
		||||
  GtkMenuTrackerItem *self;
 | 
			
		||||
  const gchar *action_name;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (GTK_IS_ACTION_OBSERVABLE (observable), NULL);
 | 
			
		||||
  g_return_val_if_fail (G_IS_MENU_MODEL (model), NULL);
 | 
			
		||||
 | 
			
		||||
  self = g_object_new (GTK_TYPE_MENU_TRACKER_ITEM, NULL);
 | 
			
		||||
  self->item = g_menu_item_new_from_model (model, item_index);
 | 
			
		||||
  self->action_namespace = g_strdup (action_namespace);
 | 
			
		||||
  self->observable = g_object_ref (observable);
 | 
			
		||||
  self->is_separator = is_separator;
 | 
			
		||||
 | 
			
		||||
  if (!is_separator && g_menu_item_get_attribute (self->item, "action", "&s", &action_name))
 | 
			
		||||
    {
 | 
			
		||||
      GActionGroup *group = G_ACTION_GROUP (observable);
 | 
			
		||||
      const GVariantType *parameter_type;
 | 
			
		||||
      gboolean enabled;
 | 
			
		||||
      GVariant *state;
 | 
			
		||||
      gboolean found;
 | 
			
		||||
 | 
			
		||||
      state = NULL;
 | 
			
		||||
 | 
			
		||||
      if (action_namespace)
 | 
			
		||||
        {
 | 
			
		||||
          gchar *full_action;
 | 
			
		||||
 | 
			
		||||
          full_action = g_strjoin (".", action_namespace, action_name, NULL);
 | 
			
		||||
          gtk_action_observable_register_observer (self->observable, full_action, GTK_ACTION_OBSERVER (self));
 | 
			
		||||
          found = g_action_group_query_action (group, full_action, &enabled, ¶meter_type, NULL, NULL, &state);
 | 
			
		||||
          g_free (full_action);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          gtk_action_observable_register_observer (self->observable, action_name, GTK_ACTION_OBSERVER (self));
 | 
			
		||||
          found = g_action_group_query_action (group, action_name, &enabled, ¶meter_type, NULL, NULL, &state);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      if (found)
 | 
			
		||||
        gtk_menu_tracker_item_action_added (GTK_ACTION_OBSERVER (self), observable, NULL, parameter_type, enabled, state);
 | 
			
		||||
      else
 | 
			
		||||
        gtk_menu_tracker_item_action_removed (GTK_ACTION_OBSERVER (self), observable, NULL);
 | 
			
		||||
 | 
			
		||||
      if (state)
 | 
			
		||||
        g_variant_unref (state);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    self->sensitive = TRUE;
 | 
			
		||||
 | 
			
		||||
  return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GtkActionObservable *
 | 
			
		||||
_gtk_menu_tracker_item_get_observable (GtkMenuTrackerItem *self)
 | 
			
		||||
{
 | 
			
		||||
  return self->observable;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * gtk_menu_tracker_item_get_is_separator:
 | 
			
		||||
 * @self: A #GtkMenuTrackerItem instance
 | 
			
		||||
 *
 | 
			
		||||
 * Returns whether the menu item is a separator. If so, only
 | 
			
		||||
 * certain properties may need to be obeyed. See the documentation
 | 
			
		||||
 * for #GtkMenuTrackerItem.
 | 
			
		||||
 */
 | 
			
		||||
gboolean
 | 
			
		||||
gtk_menu_tracker_item_get_is_separator (GtkMenuTrackerItem *self)
 | 
			
		||||
{
 | 
			
		||||
  return self->is_separator;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * gtk_menu_tracker_item_get_has_submenu:
 | 
			
		||||
 * @self: A #GtkMenuTrackerItem instance
 | 
			
		||||
 *
 | 
			
		||||
 * Returns whether the menu item has a submenu. If so, only
 | 
			
		||||
 * certain properties may need to be obeyed. See the documentation
 | 
			
		||||
 * for #GtkMenuTrackerItem.
 | 
			
		||||
 */
 | 
			
		||||
gboolean
 | 
			
		||||
gtk_menu_tracker_item_get_has_submenu (GtkMenuTrackerItem *self)
 | 
			
		||||
{
 | 
			
		||||
  GMenuModel *link;
 | 
			
		||||
 | 
			
		||||
  link = g_menu_item_get_link (self->item, G_MENU_LINK_SUBMENU);
 | 
			
		||||
 | 
			
		||||
  if (link)
 | 
			
		||||
    {
 | 
			
		||||
      g_object_unref (link);
 | 
			
		||||
      return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const gchar *
 | 
			
		||||
gtk_menu_tracker_item_get_label (GtkMenuTrackerItem *self)
 | 
			
		||||
{
 | 
			
		||||
  const gchar *label = NULL;
 | 
			
		||||
 | 
			
		||||
  g_menu_item_get_attribute (self->item, G_MENU_ATTRIBUTE_LABEL, "&s", &label);
 | 
			
		||||
 | 
			
		||||
  return label;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * gtk_menu_tracker_item_get_icon:
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: (transfer full):
 | 
			
		||||
 */
 | 
			
		||||
GIcon *
 | 
			
		||||
gtk_menu_tracker_item_get_icon (GtkMenuTrackerItem *self)
 | 
			
		||||
{
 | 
			
		||||
  GVariant *icon_data;
 | 
			
		||||
  GIcon *icon;
 | 
			
		||||
 | 
			
		||||
  icon_data = g_menu_item_get_attribute_value (self->item, "icon", NULL);
 | 
			
		||||
 | 
			
		||||
  if (icon_data == NULL)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  icon = g_icon_deserialize (icon_data);
 | 
			
		||||
  g_variant_unref (icon_data);
 | 
			
		||||
 | 
			
		||||
  return icon;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
gtk_menu_tracker_item_get_sensitive (GtkMenuTrackerItem *self)
 | 
			
		||||
{
 | 
			
		||||
  return self->sensitive;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
gtk_menu_tracker_item_get_visible (GtkMenuTrackerItem *self)
 | 
			
		||||
{
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GtkMenuTrackerItemRole
 | 
			
		||||
gtk_menu_tracker_item_get_role (GtkMenuTrackerItem *self)
 | 
			
		||||
{
 | 
			
		||||
  return self->role;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
gtk_menu_tracker_item_get_toggled (GtkMenuTrackerItem *self)
 | 
			
		||||
{
 | 
			
		||||
  return self->toggled;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const gchar *
 | 
			
		||||
gtk_menu_tracker_item_get_accel (GtkMenuTrackerItem *self)
 | 
			
		||||
{
 | 
			
		||||
  const gchar *accel = NULL;
 | 
			
		||||
 | 
			
		||||
  g_menu_item_get_attribute (self->item, "accel", "&s", &accel);
 | 
			
		||||
 | 
			
		||||
  return accel;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GMenuModel *
 | 
			
		||||
_gtk_menu_tracker_item_get_submenu (GtkMenuTrackerItem *self)
 | 
			
		||||
{
 | 
			
		||||
  return g_menu_item_get_link (self->item, "submenu");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gchar *
 | 
			
		||||
_gtk_menu_tracker_item_get_submenu_namespace (GtkMenuTrackerItem *self)
 | 
			
		||||
{
 | 
			
		||||
  const gchar *namespace;
 | 
			
		||||
 | 
			
		||||
  if (g_menu_item_get_attribute (self->item, "action-namespace", "&s", &namespace))
 | 
			
		||||
    {
 | 
			
		||||
      if (self->action_namespace)
 | 
			
		||||
        return g_strjoin (".", self->action_namespace, namespace, NULL);
 | 
			
		||||
      else
 | 
			
		||||
        return g_strdup (namespace);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    return g_strdup (self->action_namespace);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
gtk_menu_tracker_item_get_should_request_show (GtkMenuTrackerItem *self)
 | 
			
		||||
{
 | 
			
		||||
  return g_menu_item_get_attribute (self->item, "submenu-action", "&s", NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
gtk_menu_tracker_item_get_submenu_shown (GtkMenuTrackerItem *self)
 | 
			
		||||
{
 | 
			
		||||
  return self->submenu_shown;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_item_set_submenu_shown (GtkMenuTrackerItem *self,
 | 
			
		||||
                                         gboolean            submenu_shown)
 | 
			
		||||
{
 | 
			
		||||
  if (submenu_shown == self->submenu_shown)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  self->submenu_shown = submenu_shown;
 | 
			
		||||
  g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SUBMENU_SHOWN]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
gtk_menu_tracker_item_activated (GtkMenuTrackerItem *self)
 | 
			
		||||
{
 | 
			
		||||
  const gchar *action_name;
 | 
			
		||||
  GVariant *action_target;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (GTK_IS_MENU_TRACKER_ITEM (self));
 | 
			
		||||
 | 
			
		||||
  if (!self->can_activate)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  g_menu_item_get_attribute (self->item, G_MENU_ATTRIBUTE_ACTION, "&s", &action_name);
 | 
			
		||||
  action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET, NULL);
 | 
			
		||||
 | 
			
		||||
  if (self->action_namespace)
 | 
			
		||||
    {
 | 
			
		||||
      gchar *full_action;
 | 
			
		||||
 | 
			
		||||
      full_action = g_strjoin (".", self->action_namespace, action_name, NULL);
 | 
			
		||||
      g_action_group_activate_action (G_ACTION_GROUP (self->observable), full_action, action_target);
 | 
			
		||||
      g_free (full_action);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    g_action_group_activate_action (G_ACTION_GROUP (self->observable), action_name, action_target);
 | 
			
		||||
 | 
			
		||||
  if (action_target)
 | 
			
		||||
    g_variant_unref (action_target);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  GtkMenuTrackerItem *item;
 | 
			
		||||
  gchar              *submenu_action;
 | 
			
		||||
  gboolean            first_time;
 | 
			
		||||
} GtkMenuTrackerOpener;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_opener_update (GtkMenuTrackerOpener *opener)
 | 
			
		||||
{
 | 
			
		||||
  GActionGroup *group = G_ACTION_GROUP (opener->item->observable);
 | 
			
		||||
  gboolean is_open = TRUE;
 | 
			
		||||
 | 
			
		||||
  /* We consider the menu as being "open" if the action does not exist
 | 
			
		||||
   * or if there is another problem (no state, wrong state type, etc.).
 | 
			
		||||
   * If the action exists, with the correct state then we consider it
 | 
			
		||||
   * open if we have ever seen this state equal to TRUE.
 | 
			
		||||
   *
 | 
			
		||||
   * In the event that we see the state equal to FALSE, we force it back
 | 
			
		||||
   * to TRUE.  We do not signal that the menu was closed because this is
 | 
			
		||||
   * likely to create UI thrashing.
 | 
			
		||||
   *
 | 
			
		||||
   * The only way the menu can have a true-to-false submenu-shown
 | 
			
		||||
   * transition is if the user calls _request_submenu_shown (FALSE).
 | 
			
		||||
   * That is handled in _free() below.
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  if (g_action_group_has_action (group, opener->submenu_action))
 | 
			
		||||
    {
 | 
			
		||||
      GVariant *state = g_action_group_get_action_state (group, opener->submenu_action);
 | 
			
		||||
 | 
			
		||||
      if (state)
 | 
			
		||||
        {
 | 
			
		||||
          if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
 | 
			
		||||
            is_open = g_variant_get_boolean (state);
 | 
			
		||||
          g_variant_unref (state);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* If it is already open, signal that.
 | 
			
		||||
   *
 | 
			
		||||
   * If it is not open, ask it to open.
 | 
			
		||||
   */
 | 
			
		||||
  if (is_open)
 | 
			
		||||
    gtk_menu_tracker_item_set_submenu_shown (opener->item, TRUE);
 | 
			
		||||
 | 
			
		||||
  if (!is_open || opener->first_time)
 | 
			
		||||
    {
 | 
			
		||||
      g_action_group_change_action_state (group, opener->submenu_action, g_variant_new_boolean (TRUE));
 | 
			
		||||
      opener->first_time = FALSE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_opener_added (GActionGroup *group,
 | 
			
		||||
                               const gchar  *action_name,
 | 
			
		||||
                               gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  GtkMenuTrackerOpener *opener = user_data;
 | 
			
		||||
 | 
			
		||||
  if (g_str_equal (action_name, opener->submenu_action))
 | 
			
		||||
    gtk_menu_tracker_opener_update (opener);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_opener_removed (GActionGroup *action_group,
 | 
			
		||||
                                 const gchar  *action_name,
 | 
			
		||||
                                 gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  GtkMenuTrackerOpener *opener = user_data;
 | 
			
		||||
 | 
			
		||||
  if (g_str_equal (action_name, opener->submenu_action))
 | 
			
		||||
    gtk_menu_tracker_opener_update (opener);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_opener_changed (GActionGroup *action_group,
 | 
			
		||||
                                 const gchar  *action_name,
 | 
			
		||||
                                 GVariant     *new_state,
 | 
			
		||||
                                 gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  GtkMenuTrackerOpener *opener = user_data;
 | 
			
		||||
 | 
			
		||||
  if (g_str_equal (action_name, opener->submenu_action))
 | 
			
		||||
    gtk_menu_tracker_opener_update (opener);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
gtk_menu_tracker_opener_free (gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  GtkMenuTrackerOpener *opener = data;
 | 
			
		||||
 | 
			
		||||
  g_signal_handlers_disconnect_by_func (opener->item->observable, gtk_menu_tracker_opener_added, opener);
 | 
			
		||||
  g_signal_handlers_disconnect_by_func (opener->item->observable, gtk_menu_tracker_opener_removed, opener);
 | 
			
		||||
  g_signal_handlers_disconnect_by_func (opener->item->observable, gtk_menu_tracker_opener_changed, opener);
 | 
			
		||||
 | 
			
		||||
  g_action_group_change_action_state (G_ACTION_GROUP (opener->item->observable),
 | 
			
		||||
                                      opener->submenu_action,
 | 
			
		||||
                                      g_variant_new_boolean (FALSE));
 | 
			
		||||
 | 
			
		||||
  gtk_menu_tracker_item_set_submenu_shown (opener->item, FALSE);
 | 
			
		||||
 | 
			
		||||
  g_free (opener->submenu_action);
 | 
			
		||||
 | 
			
		||||
  g_slice_free (GtkMenuTrackerOpener, opener);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GtkMenuTrackerOpener *
 | 
			
		||||
gtk_menu_tracker_opener_new (GtkMenuTrackerItem *item,
 | 
			
		||||
                             const gchar        *submenu_action)
 | 
			
		||||
{
 | 
			
		||||
  GtkMenuTrackerOpener *opener;
 | 
			
		||||
 | 
			
		||||
  opener = g_slice_new (GtkMenuTrackerOpener);
 | 
			
		||||
  opener->first_time = TRUE;
 | 
			
		||||
  opener->item = item;
 | 
			
		||||
 | 
			
		||||
  if (item->action_namespace)
 | 
			
		||||
    opener->submenu_action = g_strjoin (".", item->action_namespace, submenu_action, NULL);
 | 
			
		||||
  else
 | 
			
		||||
    opener->submenu_action = g_strdup (submenu_action);
 | 
			
		||||
 | 
			
		||||
  g_signal_connect (item->observable, "action-added", G_CALLBACK (gtk_menu_tracker_opener_added), opener);
 | 
			
		||||
  g_signal_connect (item->observable, "action-removed", G_CALLBACK (gtk_menu_tracker_opener_removed), opener);
 | 
			
		||||
  g_signal_connect (item->observable, "action-state-changed", G_CALLBACK (gtk_menu_tracker_opener_changed), opener);
 | 
			
		||||
 | 
			
		||||
  gtk_menu_tracker_opener_update (opener);
 | 
			
		||||
 | 
			
		||||
  return opener;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
gtk_menu_tracker_item_request_submenu_shown (GtkMenuTrackerItem *self,
 | 
			
		||||
                                             gboolean            shown)
 | 
			
		||||
{
 | 
			
		||||
  const gchar *submenu_action;
 | 
			
		||||
  gboolean has_submenu_action;
 | 
			
		||||
 | 
			
		||||
  if (shown == self->submenu_requested)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  has_submenu_action = g_menu_item_get_attribute (self->item, "submenu-action", "&s", &submenu_action);
 | 
			
		||||
 | 
			
		||||
  self->submenu_requested = shown;
 | 
			
		||||
 | 
			
		||||
  /* If we have a submenu action, start a submenu opener and wait
 | 
			
		||||
   * for the reply from the client. Otherwise, simply open the
 | 
			
		||||
   * submenu immediately.
 | 
			
		||||
   */
 | 
			
		||||
  if (has_submenu_action)
 | 
			
		||||
    {
 | 
			
		||||
      if (shown)
 | 
			
		||||
        g_object_set_data_full (G_OBJECT (self), "submenu-opener",
 | 
			
		||||
                                gtk_menu_tracker_opener_new (self, submenu_action),
 | 
			
		||||
                                gtk_menu_tracker_opener_free);
 | 
			
		||||
      else
 | 
			
		||||
        g_object_set_data (G_OBJECT (self), "submenu-opener", NULL);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    gtk_menu_tracker_item_set_submenu_shown (self, shown);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										84
									
								
								src/gtkmenutrackeritem.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/gtkmenutrackeritem.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2011, 2013 Canonical Limited
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the licence, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Ryan Lortie <desrt@desrt.ca>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __GTK_MENU_TRACKER_ITEM_H__
 | 
			
		||||
#define __GTK_MENU_TRACKER_ITEM_H__
 | 
			
		||||
 | 
			
		||||
#include "gtkactionobservable.h"
 | 
			
		||||
 | 
			
		||||
#define GTK_TYPE_MENU_TRACKER_ITEM                          (gtk_menu_tracker_item_get_type ())
 | 
			
		||||
#define GTK_MENU_TRACKER_ITEM(inst)                         (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
 | 
			
		||||
                                                             GTK_TYPE_MENU_TRACKER_ITEM, GtkMenuTrackerItem))
 | 
			
		||||
#define GTK_IS_MENU_TRACKER_ITEM(inst)                      (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
 | 
			
		||||
                                                             GTK_TYPE_MENU_TRACKER_ITEM))
 | 
			
		||||
 | 
			
		||||
typedef struct _GtkMenuTrackerItem GtkMenuTrackerItem;
 | 
			
		||||
 | 
			
		||||
#define GTK_TYPE_MENU_TRACKER_ITEM_ROLE                     (gtk_menu_tracker_item_role_get_type ())
 | 
			
		||||
 | 
			
		||||
typedef enum  {
 | 
			
		||||
  GTK_MENU_TRACKER_ITEM_ROLE_NORMAL,
 | 
			
		||||
  GTK_MENU_TRACKER_ITEM_ROLE_CHECK,
 | 
			
		||||
  GTK_MENU_TRACKER_ITEM_ROLE_RADIO,
 | 
			
		||||
} GtkMenuTrackerItemRole;
 | 
			
		||||
 | 
			
		||||
GType                   gtk_menu_tracker_item_get_type                  (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
GType                   gtk_menu_tracker_item_role_get_type             (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
GtkMenuTrackerItem *   _gtk_menu_tracker_item_new                       (GtkActionObservable *observable,
 | 
			
		||||
                                                                         GMenuModel          *model,
 | 
			
		||||
                                                                         gint                 item_index,
 | 
			
		||||
                                                                         const gchar         *action_namespace,
 | 
			
		||||
                                                                         gboolean             is_separator);
 | 
			
		||||
 | 
			
		||||
GtkActionObservable *  _gtk_menu_tracker_item_get_observable            (GtkMenuTrackerItem *self);
 | 
			
		||||
 | 
			
		||||
gboolean                gtk_menu_tracker_item_get_is_separator          (GtkMenuTrackerItem *self);
 | 
			
		||||
 | 
			
		||||
gboolean                gtk_menu_tracker_item_get_has_submenu           (GtkMenuTrackerItem *self);
 | 
			
		||||
 | 
			
		||||
const gchar *           gtk_menu_tracker_item_get_label                 (GtkMenuTrackerItem *self);
 | 
			
		||||
 | 
			
		||||
GIcon *                 gtk_menu_tracker_item_get_icon                  (GtkMenuTrackerItem *self);
 | 
			
		||||
 | 
			
		||||
gboolean                gtk_menu_tracker_item_get_sensitive             (GtkMenuTrackerItem *self);
 | 
			
		||||
 | 
			
		||||
gboolean                gtk_menu_tracker_item_get_visible               (GtkMenuTrackerItem *self);
 | 
			
		||||
 | 
			
		||||
GtkMenuTrackerItemRole  gtk_menu_tracker_item_get_role                  (GtkMenuTrackerItem *self);
 | 
			
		||||
 | 
			
		||||
gboolean                gtk_menu_tracker_item_get_toggled               (GtkMenuTrackerItem *self);
 | 
			
		||||
 | 
			
		||||
const gchar *           gtk_menu_tracker_item_get_accel                 (GtkMenuTrackerItem *self);
 | 
			
		||||
 | 
			
		||||
GMenuModel *           _gtk_menu_tracker_item_get_submenu               (GtkMenuTrackerItem *self);
 | 
			
		||||
 | 
			
		||||
gchar *                _gtk_menu_tracker_item_get_submenu_namespace     (GtkMenuTrackerItem *self);
 | 
			
		||||
 | 
			
		||||
gboolean                gtk_menu_tracker_item_get_should_request_show   (GtkMenuTrackerItem *self);
 | 
			
		||||
 | 
			
		||||
void                    gtk_menu_tracker_item_activated                 (GtkMenuTrackerItem *self);
 | 
			
		||||
 | 
			
		||||
void                    gtk_menu_tracker_item_request_submenu_shown     (GtkMenuTrackerItem *self,
 | 
			
		||||
                                                                         gboolean            shown);
 | 
			
		||||
 | 
			
		||||
gboolean                gtk_menu_tracker_item_get_submenu_shown         (GtkMenuTrackerItem *self);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										2
									
								
								src/gvc
									
									
									
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								src/gvc
									
									
									
									
									
								
							 Submodule src/gvc updated: 03894efbcd...ed0ec42401
									
								
							
							
								
								
									
										28
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								src/main.c
									
									
									
									
									
								
							@@ -47,6 +47,11 @@ static char *session_mode = NULL;
 | 
			
		||||
#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1
 | 
			
		||||
#define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
  SHELL_DEBUG_BACKTRACE_WARNINGS = 1,
 | 
			
		||||
};
 | 
			
		||||
static int _shell_debug;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
shell_dbus_acquire_name (GDBusProxy *bus,
 | 
			
		||||
                         guint32     request_name_flags,
 | 
			
		||||
@@ -269,6 +274,17 @@ shell_a11y_init (void)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
shell_init_debug (const char *debug_env)
 | 
			
		||||
{
 | 
			
		||||
  static const GDebugKey keys[] = {
 | 
			
		||||
    { "backtrace-warnings", SHELL_DEBUG_BACKTRACE_WARNINGS }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  _shell_debug = g_parse_debug_string (debug_env, keys,
 | 
			
		||||
                                       G_N_ELEMENTS (keys));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
default_log_handler (const char     *log_domain,
 | 
			
		||||
                     GLogLevelFlags  log_level,
 | 
			
		||||
@@ -286,6 +302,15 @@ default_log_handler (const char     *log_domain,
 | 
			
		||||
   * with those. */
 | 
			
		||||
  if (!log_domain || !g_str_has_prefix (log_domain, "tp-glib"))
 | 
			
		||||
    g_log_default_handler (log_domain, log_level, message, data);
 | 
			
		||||
 | 
			
		||||
  /* Filter out Gjs logs, those already have the stack */
 | 
			
		||||
  if (log_domain && strcmp (log_domain, "Gjs") == 0)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if ((_shell_debug & SHELL_DEBUG_BACKTRACE_WARNINGS) &&
 | 
			
		||||
      ((log_level & G_LOG_LEVEL_CRITICAL) ||
 | 
			
		||||
       (log_level & G_LOG_LEVEL_WARNING)))
 | 
			
		||||
    gjs_dumpstack ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -406,6 +431,8 @@ main (int argc, char **argv)
 | 
			
		||||
  g_setenv ("GJS_DEBUG_OUTPUT", "stderr", TRUE);
 | 
			
		||||
  g_setenv ("GJS_DEBUG_TOPICS", "JS ERROR;JS LOG", TRUE);
 | 
			
		||||
 | 
			
		||||
  shell_init_debug (g_getenv ("SHELL_DEBUG"));
 | 
			
		||||
 | 
			
		||||
  shell_dbus_init (meta_get_replace_current_wm ());
 | 
			
		||||
  shell_a11y_init ();
 | 
			
		||||
  shell_perf_log_init ();
 | 
			
		||||
@@ -419,6 +446,7 @@ main (int argc, char **argv)
 | 
			
		||||
  tp_debug_set_flags ("all");
 | 
			
		||||
 | 
			
		||||
  sender = tp_debug_sender_dup ();
 | 
			
		||||
 | 
			
		||||
  g_log_set_default_handler (default_log_handler, sender);
 | 
			
		||||
 | 
			
		||||
  /* Initialize the global object */
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user