Compare commits
	
		
			24 Commits
		
	
	
		
			3.1.91.1
			...
			overview-r
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 9efa271888 | ||
|   | 9ed3ce9006 | ||
|   | b400fc2837 | ||
|   | a66af6fbac | ||
|   | 1bbc138ed2 | ||
|   | 868d4756e4 | ||
|   | dfa3be59dc | ||
|   | 62677336a5 | ||
|   | 264a82cbfc | ||
|   | f8cfd9f903 | ||
|   | 13f8cd3bcf | ||
|   | e1f336374b | ||
|   | 0ba1387d19 | ||
|   | 8832ce3a2b | ||
|   | 91d7a022a9 | ||
|   | 95d15725fc | ||
|   | bb2b7d83af | ||
|   | 0abac6f67d | ||
|   | e00398e2ac | ||
|   | 0f19492545 | ||
|   | 9d46a6ceea | ||
|   | 6432de95cc | ||
|   | 738fc375c0 | ||
|   | 4e9a530a64 | 
							
								
								
									
										25
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -3,11 +3,11 @@ | ||||
| *.o | ||||
| .deps | ||||
| .libs | ||||
| ABOUT-NLS | ||||
| ChangeLog | ||||
| INSTALL | ||||
| Makefile | ||||
| Makefile.in | ||||
| NEWS | ||||
| aclocal.m4 | ||||
| autom4te.cache | ||||
| config.h | ||||
| @@ -18,10 +18,13 @@ config | ||||
| configure | ||||
| data/gnome-shell.desktop | ||||
| data/gnome-shell.desktop.in | ||||
| data/gnome-shell-clock-preferences.desktop | ||||
| data/gnome-shell-clock-preferences.desktop.in | ||||
| data/gschemas.compiled | ||||
| data/org.gnome.shell.gschema.xml | ||||
| data/org.gnome.shell.gschema.valid | ||||
| js/misc/config.js | ||||
| data/org.gnome.accessibility.magnifier.gschema.xml | ||||
| data/org.gnome.accessibility.magnifier.gschema.valid | ||||
| intltool-extract.in | ||||
| intltool-merge.in | ||||
| intltool-update.in | ||||
| @@ -30,13 +33,8 @@ m4/ | ||||
| omf.make | ||||
| po/*.gmo | ||||
| po/gnome-shell.pot | ||||
| po/*.header | ||||
| po/*.sed | ||||
| po/*.sin | ||||
| po/Makefile.in.in | ||||
| po/Makevars.template | ||||
| po/POTFILES | ||||
| po/Rules-quot | ||||
| po/stamp-it | ||||
| scripts/launcher.pyc | ||||
| src/*.gir | ||||
| @@ -45,25 +43,16 @@ src/*-enum-types.[ch] | ||||
| src/*-marshal.[ch] | ||||
| src/Makefile | ||||
| src/Makefile.in | ||||
| src/calendar-server/org.gnome.Shell.CalendarServer.service | ||||
| src/gnomeshell-taskpanel | ||||
| src/gnome-shell | ||||
| src/gnome-shell-calendar-server | ||||
| src/gnome-shell-extension-tool | ||||
| src/gnome-shell-hotplug-sniffer | ||||
| src/gnome-shell-jhbuild | ||||
| src/gnome-shell-perf-helper | ||||
| src/gnome-shell-real | ||||
| src/hotplug-sniffer/org.gnome.Shell.HotplugSniffer.service | ||||
| src/gnome-shell-clock-preferences | ||||
| src/run-js-test | ||||
| src/test-recorder | ||||
| src/test-recorder.ogg | ||||
| src/test-theme | ||||
| src/st.h | ||||
| src/stamp-st.h | ||||
| src/stamp-st.h.tmp | ||||
| stamp-h1 | ||||
| tests/run-test.sh | ||||
| xmldocs.make | ||||
| *~ | ||||
| *.patch | ||||
| *.sw? | ||||
|   | ||||
| @@ -3,5 +3,5 @@ E-mail: otaylor@redhat.com | ||||
| Userid: otaylor | ||||
|  | ||||
| Colin Walters | ||||
| E-mail: walters@verbum.org | ||||
| E-mail: walters@redhat.com | ||||
| Userid: walters | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| # Point to our macro directory and pick up user flags from the environment | ||||
| ACLOCAL_AMFLAGS  = -I m4 ${ACLOCAL_FLAGS} | ||||
|  | ||||
| SUBDIRS = data js src browser-plugin tests po man | ||||
| SUBDIRS = data js src tests po man | ||||
|  | ||||
| EXTRA_DIST =		\ | ||||
| 	.project	\ | ||||
|   | ||||
							
								
								
									
										458
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						| @@ -1,458 +0,0 @@ | ||||
| 3.1.91.1 | ||||
| ======== | ||||
|  | ||||
| * Add a browser plugin - this plugin, tied to extensions.gnome.org, | ||||
|   allows users to download and install shell extensions, and enable, | ||||
|   disable, and uninstall extensions they already have installed. | ||||
|   [Jasper; #658070, #658612] | ||||
| * Improve adding links to URLs in notifications [Dan; #636252] | ||||
| * Remove "connection lost" notifications after reconnecting [Giovanni; #658049] | ||||
| * Hide the onscreen keyboard when leaving a text entry [Dan; #658591] | ||||
| * Fixes for translated strings [Florian; #639987, #644097, #645037] | ||||
| * Bug fixes for network menu [Florian; #658492] | ||||
| * Code cleanup [Dan; #646934] | ||||
| * Build fixes [Javier, Rico] | ||||
| * Misc bug fixes [Emmanuele, Florian, Jasper, Marina, Matthias, Ray; | ||||
|   #652837, #658423, #658503, #658525, #658562, #658624, #658640, #658983] | ||||
|  | ||||
| Conributors: | ||||
|  Emmanuele Bassi, Giovanni Campagna, Matthias Clasen, Javier Jardón, | ||||
|  Florian Muellner, Jasper St. Pierre, Ray Strode, Rico Tzschichholz, | ||||
|  Dan Winship, Marina Zhurakhinskaya | ||||
|  | ||||
| Translations: | ||||
|  Ihar Hrachyshka [be], Bruce Cowan [en_GB], Jorge González, | ||||
|  Daniel Mustieles [es], Timo Jyrinki [fi], Bruno Brouard, Luc Guillemin, | ||||
|  Claude Paroz, Luc Pionchon [fr], Fran Dieguez [gl], Rajesh Ranjan [hi], | ||||
|  Andika Triwidada [id], Luca Ferretti [it], Changwoo Ryu [ko], | ||||
|  Rudolfs Mazurs [lt], Kjartan Maraas [nb], Manoj Kumar Giri [or], | ||||
|  A S Alam [pa], Piotr Drąg [pl], Duarte Loreto [pt], Henrique P. Machado, | ||||
|  Gabriel F. Vilar [pt_BR], Daniel Nylander [se], Matej Urbančič [sl], | ||||
|  Tirumurti Vasudevan [ta], Yinghua Wang [zh_CN], | ||||
|  Chao-Hsiung Liao [zh_HK, zh_TW] | ||||
|  | ||||
| 3.1.91 | ||||
| ====== | ||||
|  | ||||
| * Fix problem with applications vanishing from alt-Tab when | ||||
|   desktop files change. [Colin; #657990] | ||||
| * Fix interaction of on-screen keyboard with run-dialog and | ||||
|   Looking Glass console [Dan; #657986] | ||||
| * Add public API for adding and removing search providers | ||||
|   [Philippe; #657548, #658113] | ||||
| * Allow changing IM status with scroll wheel [Florian; #657973] | ||||
| * Limit volume slider to 100% [Bastien; #657607] | ||||
| * Change "Do Not Disturb" to "Notifications" in user menu [Florian; #652718] | ||||
| * Switch browser in default favorites to Epiphany [Colin; #650616] | ||||
| * Misc bug fixes [Dan, Florian, Jasper, Marc-Antoine, Rui; | ||||
|   #649631, #655069, #656142, #657703, #657759, #658007, #658065, #658176] | ||||
|  | ||||
| Contributors: | ||||
|  Rui Matos, Florian Müllner, Philippe Normand, Marc-Antoine Perennou, | ||||
|  Jasper St. Pierre, Colin Walters, Dan Winship | ||||
|  | ||||
| Translations: | ||||
|  Ihar Hrachyshka [be], Mario Blättermann [de], Kris Thomsen [da], | ||||
|  Jorge González [es], Arash Mousavi [fa], Fran Dieguez [gl], | ||||
|  Takayuki Kusano [ja],Aurimas Černius [lt], Kjartan Maraas [nb], A S Alam [pa], | ||||
|  Stas Solovey [ru], Daniel Nylander [se], Tirumurti Vasudevan [ta], | ||||
|  Chao-Hsiung Liao [zh_HK, zh_TW] | ||||
|  | ||||
| 3.1.90.1 | ||||
| ======== | ||||
|  | ||||
| * Fix typo that was breaking the "Login Screen" mode [Marc-Antoine] | ||||
| * Fix build with new gobject-introspection [Dan] | ||||
| * Use a better icon for removable devices [Cosimo; #657757] | ||||
| * Add support for asynchronous search provides [Philippe, Jasper, Seif; #655220] | ||||
| * Misc bug fixes [Alex, Guillaume, Jasper; #657657, #657696] | ||||
| * Misc build fixes [Adel; #657697] | ||||
|  | ||||
| Contributors: | ||||
|  Cosimo Cecchi, Guillaume Desmottes, Adel Gadllah, Alexander Larsson, Seif Lotfy, | ||||
|  Philippe Normand, Marc-Antoine Perennou, Jasper St. Pierre, Dan Winship | ||||
|  | ||||
| Translations: | ||||
|  Jorge González, Daniel Mustieles [es], Stas Solovey [ru] | ||||
|  | ||||
| 3.1.90 | ||||
| ====== | ||||
| * Add an on-screen keyboard that uses Caribou as a backend | ||||
|   [Nohemi, Dan; #612662] | ||||
| * Allow searching for people in the overview using libfolks | ||||
|   as the backend [Morten; #643018] | ||||
| * Add a "Login Screen" mode to be used when GDM is running; this | ||||
|   mode has a stripped down user interface, and also contains the | ||||
|   code to display the user list and authentication. [Ray; #657082] | ||||
| * Rework user menu to separate out "Do Not Disturb" from the IM | ||||
|   status and to visually match GNOME Contacts. [Florian; #652837] | ||||
| * Implement displaying images such as cover-art in notifications | ||||
|   [Neha, Marina; #621009] | ||||
| * Support default actions for notifications [Florian; #655818] | ||||
| * Networking | ||||
|   - Stop using nm-applet for dialogs; do them as proper system modal | ||||
|     dialogs in the shell code. [Giovanni; #650244] | ||||
|   - Fix handling of hidden access points [Giovanni; #646454] | ||||
| * Telepathy integration | ||||
|   - Support subscription requests [Guillaume, Xavier; #653941] | ||||
|   - Notify on account connection errors [Alban, Jasper, Xavier; #654159] | ||||
|   - Allow approving file transfers [Guillaume; #653940] | ||||
|   - Improve styling of messages [Jasper; #640271] | ||||
| * Extension system [Jasper; #654770] | ||||
|   - Support live enabling and disabling of extensions | ||||
|   - Add the ability to install extensions from HTTP | ||||
|   - Enhance D-Bus interface for controlling extensions | ||||
|   - Collect errors separately for each extension | ||||
| * Add Main.panel.addToStatusArea for extension convenience | ||||
|   [Giovanni, Jasper, Marc-Antoine; #653205] | ||||
| * Port to the new gnome-menus API. Clean up and speed up | ||||
|   application information loading [Colin; #648149, #656546] | ||||
| * Use the accountsservice library rather than cut-and-pasted GDM code | ||||
|   [Florian; #650893] | ||||
| * Add a D-Bus interface to take a screenshot; this will avoid various race | ||||
|   conditions with the current gnome-screenshot approach [Adel; #652952] | ||||
| * Show numeric indicators to distinguish duplicate keyboard names | ||||
|   [Giovanni; #650128] | ||||
| * Add GNOME Documents to the favorites list [Adel; #657520] | ||||
| * Update the clock immediately on resume from suspend [Colin; #656403] | ||||
| * Remove animation support from StAdjustment [Ray; #657082] | ||||
| * Support configuration of calendar applications via gsettings | ||||
|   [Tassilo; #651190] | ||||
| * Don't fade in alt-Tab - wait a bit and show it instantly [Rui; #652346] | ||||
| * Darken workspace background on all workspaces [Rui; #656433] | ||||
| * Improve detection of the starting day of the week [Florian; #649078] | ||||
| * Add StButtonAccessible [Alejandro] | ||||
| * Visual tweaks to match mockups | ||||
|   [Allan, Dan, Jasper, Marina; #640271, #655627, #655428, #656732] | ||||
| * Misc bug fixes [Dan, Florian, Giovanni, Guillaume, Jasper, Jeremy, Rui; | ||||
|   #645708, #646761, #653119, #654398, #656125, #654707, #654898, #654638, | ||||
|   #656335, #657111] | ||||
| * Code cleanups [Colin, Dan, Guillaume, Ray; | ||||
|   #652718, #654639, #648651, #655813, #657082] | ||||
| * String tweaks [Jasper, Jeremy; #652984, #640271] | ||||
| * Build fixes [Jasper, Nohemi; #644275, #655812] | ||||
|  | ||||
| Contributors: | ||||
|  Jeremy Bicha, Giovanni Campagna, Xavier Claessens, Alban Crequy, | ||||
|  Guillaume Desmottes, Allan Day, Neha Doijode, Nohemi Fernandez, | ||||
|  Tassilo Horn, Rui Matos, Morten Mjelva, Florian Müllner, Alejandro Piñeiro, | ||||
|  Jasper St. Pierre, Ray Strode, Colin Walters, Dan Winship, | ||||
|  Marina Zhurakhinskaya | ||||
|  | ||||
| Translations: | ||||
|  Ivaylo Valkov [bg], Mario Blättermann [de], Diego Escalante Urrelo, | ||||
|  Jorge González, Daniel Mustieles [es], Arash Mousavi [fa], Fran Dieguez [gl], | ||||
|  Yaron Shahrabani [he], Andika Triwidada, Wibiharto [id], | ||||
|  Aurimas Černius [lt], Umarzuki Bin Mochlis Moktar [ml], Kjartan Maraas [nb], | ||||
|  A S Alam [pa], Daniel Nylander [se], Ngô Chin, Nguyễn Thái Ngọc Duy [vi], | ||||
|  Aron Xu [zh_CN], Chao-Hsiung Liao [zh_HK, zh_TW] | ||||
|  | ||||
| 3.1.4 | ||||
| ===== | ||||
| * Take over inserted media handling and autorun from gnome-session [Cosimo] | ||||
| * Message Tray | ||||
|   - Display a count of unread notifications on icons | ||||
|     [Jasper, Guillaume; #649356, #654139] | ||||
|   - Only remove icons when the sender quits from D-Bus, not when it | ||||
|     closes its last window [Neha, Marina; #645764] | ||||
|   - Solve problems switching chats between shell and Empathy | ||||
|     [Guillaume; #654237] | ||||
|   - Fix handling of bad GMarkup in messages [Dan; #650298] | ||||
|   - Never show notifications when the screensaver is active [Dan; #654550] | ||||
| * Telepathy integrationpp | ||||
|   - Implement Telepathy Debug interface to enable empathy-debugger | ||||
|     [Guillaume; #652816] | ||||
|   - Allow approving room invitations, and audio/video calls | ||||
|     [Guillaume; #653740 #653939] | ||||
|   - Send typing notifications [Jonny; #650196] | ||||
| * Fix selection highlighting for light-on-dark entries [Jasper; #643768] | ||||
| * Make control-Return in the overview open a new window [Maxim] | ||||
| * Delay showing the alt-Tab switcher to reduce visual noise when | ||||
|   flipping betweeen windows [Dan; #652346] | ||||
| * When we have vertically stacked monitors, put the message tray | ||||
|   on the bottom one [Dan; #636963] | ||||
| * Fix various problems with keynav and the Activities button | ||||
|   [Dan; #641253 #645759] | ||||
| * Ensure screensaver is locked when switching users [Colin; #654565] | ||||
| * Improve extension creation tool [Jasper; #653206] | ||||
| * Fix compatibility with latest GJS [Giovanni; #654349] | ||||
| * Code cleanups [Adel, Dan, Jasper; #645759 #654577 #654791 #654987] | ||||
| * Misc bug fixes [Richard, Dan, Florian, Giovanni, Jasper, Marc-Antoine, Rui; | ||||
|   #647175 #649513 #650452 #651082 #653700 #653989 #654105 #654791 #654267 | ||||
|   #654269 #654527 #655446] | ||||
| * Build fixes [Florian, Siegfried; #654300] | ||||
|  | ||||
| Contributors: | ||||
|  Giovanni Campagna, Cosimo Cecchi, Guillaume Desmottes, Neha Doijode, | ||||
|  Maxim Ermilov, Adel Gadllah, Siegfried-Angel Gevatter Pujals, Richard Hughes, | ||||
|  Jonny Lamb, Rui Matos, Florian Müllner, Marc-Antoine Perennou, Colin Walters, | ||||
|  Dan Winship, Marina Zhurakhinskaya | ||||
|  | ||||
| Translations: | ||||
|  Mario Blättermann, Paul Seyfert [de], Jorge González, Daniel Mustieles [es], | ||||
|  Fran Dieguez [gl], Yaron Shahrabani [he], Luca Ferretti [it], | ||||
|  Rudolfs Mazurs [lv], Kjartan Maraas [nb], A S Alam [pa], Yuri Kozlov [ru], | ||||
|  Michal Štrba, Matej Urbančič [sl] | ||||
|  | ||||
| 3.1.3 | ||||
| ===== | ||||
| * Fix problem with "user theme extension" breaking the CSS for other | ||||
|   extensions [Giovanni; #650971] | ||||
| * Telepathy IM framework integration | ||||
|   - Switch to using telepathy-glib rather than talking to | ||||
|     Telepathy via D-Bus [Guillaume, Jasper; #645585, #649633, #651138, #651227] | ||||
|   - Acknowledge messages when the user clicks on them [Guillaume, #647893] | ||||
|   - Fix problem with telepathy icon blinking for incoming messages | ||||
|     even though the user has been notified of them [Guillaume; #643594] | ||||
| * Networking | ||||
|   - keep wirelesss networks in predictable order [Giovanni; #646580, #652313] | ||||
|   - Show unmanaged devices in the menu [Giovanni; #646946] | ||||
|   - Fix overflow when too many VPN connections [Giovanni; #651602] | ||||
| * Bluetooth | ||||
|   - Show "hardware disabled" when disabled by rfkill [Giovanni; #648048] | ||||
|   - Fix bug updating status of devices [Giovanni; #647565] | ||||
| * LookingGlass console: | ||||
|   - Add a "Memory" tab [Colin; #650692] | ||||
|   - Make escape work from any page [Dan Winship; #647303] | ||||
|   - Provide a way to refer to panel items as, e.g., | ||||
|     Main.panel._activities [Dan Winship; #646915] | ||||
| * User menu | ||||
|   - Fix problem with suspend menu option locking the screen even when the user | ||||
|     disabled that. [Florian; #652327] | ||||
|   - Hide "power off..." option if shutdown is disabled via PolicyKit | ||||
|     [Florian; #652038] | ||||
| * Track changes to WM_CLASS (fixes problems with LibreOffice tracking) | ||||
|   [Colin; #649315] | ||||
| * Remove app tracking workarounds for Firefox and LibreOffice [Colin; #651015] | ||||
| * Use upstream gettext autoconfigury rather than glib version [Javier; #631576] | ||||
| * Show messages in the message tray when an application is fullscreen | ||||
|   [Dan Winship; #608667] | ||||
| * Don't autohide the workspace pager if there is more than one workspace | ||||
|   [Florian; #652714, #653078, #653142] | ||||
| * Don't always slide out the workspace pager at drag begin [Florian; #652730] | ||||
| * Only offer to remove a favorite app when dragging it's icon [Owen; #642895] | ||||
| * Allow dropping an icon anywhere on a workspace [Adel; #652079] | ||||
| * st-scroll-view: Make the fade effect and offset themable [Jasper; #651813] | ||||
| * Obey the user's preference when running an application in a terminal | ||||
|   from the run dialog [Florian; #648422] | ||||
| * Consistently exit overview when launching external applications | ||||
|   [Colin; #653095] | ||||
| * Adapt to changes in GJS for how GObject APIs are bound | ||||
|   [Alex, Colin, Florian, Jasper, Marc-Antoine; #649981, #652597] | ||||
| * Fix problems with scrolling in overflow for alt-Tab switcher | ||||
|   [Dan Winship, Adel; #647807] | ||||
| * Mark relationships between labels and actors for accessibility [Alejandro] | ||||
| * Add org.gnome.shell.enabled-extensions complementing disabled-extensions | ||||
|   GSetting [Tassilo; #651088] | ||||
| * Visual tweaks [Jakub, Jasper; #646261, #652715] | ||||
| * Switch to building against clutter-1.7 with independent Cogl [Adel; #653397] | ||||
| * Code cleanups [Colin, Dan Winship, Florian; #633620, #645031, #648755, #648758, | ||||
|   #648760, #649203, #649517, #650317, #652730] | ||||
| * Memory leak fixes [Colin, Maxim; #649508, #650934] | ||||
| * Build Fixes [Colin, Dan Winship, Florian, Ionut, Morten, Owen, Sean; #647395, | ||||
|   #648006, #650869, #653199, #653275 | ||||
| * Miscellaneous bug fixes [Adam, Adel, Dan Williams, Dan Winship, Florian, | ||||
|   Ionut, Jasper, Maxim, Ray; #620105, #639459, #641570, #642793, #643513, | ||||
|   #645848, #646919, #647186, #648305, #648410, #648562, #648894, #649001, | ||||
|   #645990, #647893, #647907, #651012, #651086, #651606, #651569, #651866, | ||||
|   #652388,  #653511] | ||||
|  | ||||
| Contributors: | ||||
|  Ionut Biru, Giovanni Campagna, Guillaume Desmottes, Adam Dingle, | ||||
|  Maxim Ermilov, Adel Gadllah, Tassilo Horn, Javier Jardón, Jonny Lamb, | ||||
|  Alexander Larsson, Rui Matos, Morten Mjelva, Florian Müllner, | ||||
|  Marc-Antoine Perennou, Alejandro Piñeiro, Jasper St. Pierre, Jakub Steiner, | ||||
|  Ray Strode, Owen Taylor, Colin Walters, Dan Williams, Sean Wilson, Dan Winship | ||||
|  | ||||
| Translations: | ||||
|  Daniel Martinez Cucalon [ar], Ihar Hrachyshka [be], Carles Ferrando, | ||||
|  Gil Forcada, Sílvia Miranda [ca], Kristjan Schmidt [eo], Jorge González, | ||||
|  Daniel Mustieles [es], Seán de Búrca [ga], Fran Diéguez [gl], | ||||
|  Yaron Shahrabani [he], Kjartan Maraas [nb], Misha Shnurapet, | ||||
|  Yuri Myasoedov [ru], Daniel Nylander [se], Peter Mráz [sk], | ||||
|  Matej Urbančič [sl], Krishnababu Krothapalli [te], Daniel Korostil [uk], | ||||
|  Aron Xu [zh_CN] | ||||
|  | ||||
| 3.0.2 | ||||
| ===== | ||||
| * Network Menu [Dan Williams] | ||||
|   - Fix connecting to WPA2 Enterprise access points | ||||
|     Fixes https://bugzilla.gnome.org/show_bug.cgi?id=648171 | ||||
|   - Show the mobile broadband wizard when selecting 3G network | ||||
|     Fixes https://bugzilla.gnome.org/show_bug.cgi?id=649318 | ||||
|   - Miscellaneous bug fixes | ||||
|     648648, 650124 | ||||
| * Fix duplicate icons in the application browser [Owen] | ||||
|   https://bugzilla.gnome.org/show_bug.cgi?id=648739 | ||||
| * Make clicking anywhere on the volume icon slider work [Giovanni] | ||||
|   https://bugzilla.gnome.org/show_bug.cgi?id=646660 | ||||
| * Fix a case where activating and clicking the hot corner | ||||
|   at the same time could result in immediately leaving the | ||||
|   overview [Rui] | ||||
|   https://bugzilla.gnome.org/show_bug.cgi?id=649427 | ||||
| * Fix a case where applications became misordered in Alt-Tab [Jasper] | ||||
|   https://bugzilla.gnome.org/show_bug.cgi?id=643302 | ||||
| * Fix a bug where messages you send could show up in | ||||
|   notifications as if someone else sent them [Jonny] | ||||
|   https://bugzilla.gnome.org/show_bug.cgi?id=650219 | ||||
| * Memory leak fixes [Colin, Maxim] | ||||
|   642652, 649508, 649497 | ||||
| * Miscellaneous minor bug fixes [Adel, Christopher, Jasper] | ||||
|   649596, 648765, 648983, 649632 | ||||
|  | ||||
| Contributors: | ||||
|  Christopher Aillon, Giovanni Campagna, Maxim Ermilov, | ||||
|  Adel Gadllah, Jonny Lamb, Rui Matos, Jasper St. Pierre, | ||||
|  Owen Taylor, Colin Walters, Dan Williams | ||||
|  | ||||
| Translations: | ||||
|  Arash Mousavi [fa], Seán de Búrca [ga], Timo Jyrinki [fi], | ||||
|  Sigurd Gartmann [nb], Daniel Nylander [se], Peter Mráz [sl], | ||||
|  Abduxukur Abdurixit [ug], Nguyễn Thái Ngọc Duy [vi] | ||||
|  | ||||
| 3.0.1 | ||||
| ===== | ||||
|  | ||||
| * Network menu | ||||
|   - Fix problems updating the menu for mobile broadband devices [Giovanni] | ||||
|     https://bugzilla.gnome.org/show_bug.cgi?id=646395 | ||||
|   - Fix missing device descriptions with multiple devices of the | ||||
|     same type [Giovanni] | ||||
|     https://bugzilla.gnome.org/show_bug.cgi?id=646074 | ||||
|   - Label ad-hoc neworks with an appropriate icon [Dan] | ||||
|     https://bugzilla.gnome.org/show_bug.cgi?id=646141 | ||||
|   - Fix displaying some devices states as "invalid" [Dan] | ||||
|     https://bugzilla.gnome.org/show_bug.cgi?id=646946 | ||||
|   - Fix problems with access points that don't report a SSID [Giovanni] | ||||
|     https://bugzilla.gnome.org/show_bug.cgi?id=647040 | ||||
|   - Miscellaneous minor bug fixes [Dan, Giovanni, Owen] | ||||
|     645981, 646558, 646443, 646708, 646968 | ||||
| * Application menu and icon | ||||
|   - Fix bug where application menu icon was missing at GNOME Shell | ||||
|     startup. [Florian] | ||||
|     https://bugzilla.gnome.org/show_bug.cgi?id=644122 | ||||
|   - Fix missing application menu for dialog windows [Colin] | ||||
|     https://bugzilla.gnome.org/show_bug.cgi?id=647082 | ||||
|  -  When launching an application through an alternate launcher | ||||
|     (like for a System Settings pane), association the windows with | ||||
|     the application, not the launcher. [Colin] | ||||
|     https://bugzilla.gnome.org/show_bug.cgi?id=646689 | ||||
| * Activities overview | ||||
|   - Load the applications view incrementally to avoid potentially freezing | ||||
|     for multiple seconds [Colin] | ||||
|     https://bugzilla.gnome.org/show_bug.cgi?id=647778 | ||||
|   - Fix bug where package installation while the overview | ||||
|     was up could result in a corrupted application display. [Giovanni] | ||||
|     https://bugzilla.gnome.org/show_bug.cgi?id=645801 | ||||
|   - Fix dragging from the search results to launch apps and docs [Florian] | ||||
|     https://bugzilla.gnome.org/show_bug.cgi?id=645990 | ||||
|   - Fix flickering of selection when searching in the overview [Florian] | ||||
|     https://bugzilla.gnome.org/show_bug.cgi?id=646019 | ||||
|   - Fix bug when typing into the search box when text was already | ||||
|     selected [Nohemi] | ||||
|     https://bugzilla.gnome.org/show_bug.cgi?id=636341 | ||||
| * Fix layout of notifications for right-to-left languages [Florian] | ||||
|   https://bugzilla.gnome.org/show_bug.cgi?id=646921 | ||||
| * Remove a confusing special case where Alt-Tab sometimes switched | ||||
|   to a different window of the same application rather than to | ||||
|   a different application. [Rui] | ||||
|   https://bugzilla.gnome.org/show_bug.cgi?id=648132 | ||||
| * Fix a crash that could happen when a window was opened on a | ||||
|   workspace that was immediately removed [Dan] | ||||
|   https://bugzilla.gnome.org/show_bug.cgi?id=648132 | ||||
| * Fix keyboard navigation in logout/reboot dialogs [Dan] | ||||
|   https://bugzilla.gnome.org/show_bug.cgi?id=646740 | ||||
| * Fix missing inspector icon in Looking Glass console [Dan] | ||||
| * Miscellaneous minor bug fixes [Adel, Colin, Dan, Florian, Nohemi] | ||||
|   645648, 646205, 646257, 646855, 647098, 646730 | ||||
|  | ||||
| Contributors: | ||||
|  Giovanni Campagna, Nohemi Fernandez, Adel Gadllah, Rui Matos, Florian Müllner, | ||||
|  Owen Taylor, Colin Walters, Dan Winship | ||||
|  | ||||
| Translations: | ||||
|  Hendrik Richter [de], Jorge González [es], Arash Mousavi [fa], | ||||
|  Fran Diéguez [gl], Jiro Matsuzawa [ja], Piotr Drąg [pl], Daniel Nylander [sv], | ||||
|  Sira Nokyoongtong [th], Muhammet Kara [tr], Nguyễn Thái Ngọc Duy [vi], | ||||
|  Aron Xu [zh_CN], Chao-Hsiung Liao [zh_HK, zh_TW] | ||||
|  | ||||
| 3.0.0.2 | ||||
| ======= | ||||
|  | ||||
| * Fix missing import that was preventing extensions from loading. | ||||
|   [Maxim Ermilov] | ||||
|   https://bugzilla.gnome.org/show_bug.cgi?id=646333 | ||||
|  | ||||
| Translations: | ||||
|  Timo Jyrinki [fi] | ||||
|  | ||||
| 3.0.0.1 | ||||
| ======= | ||||
|  | ||||
| * Fix problem with stuck event handling if network menu pops down while | ||||
|   user is using the scrollbar. [Owen Taylor] | ||||
|   https://bugzilla.gnome.org/show_bug.cgi?id=646825 | ||||
|  | ||||
| Contributors to GNOME Shell 3.0 | ||||
| =============================== | ||||
|  | ||||
| Code: | ||||
|  | ||||
|  Josh Adams, Kiyoshi Aman, Nuno Araujo, Emmanuele Bassi, Dirk-Jan C. Binnema, | ||||
|  Wouter Bolsterlee, Raphael Bosshard, Milan Bouchet-Valat, Christina Boumpouka, | ||||
|  Mathieu Bridon, Alban Browaeys, Phil Bull, Micro Cai, Giovanni Campagna, | ||||
|  Cosimo Cecchi, Tor-björn Claesson, Matthias Clasen, Jason D. Clinton, | ||||
|  Frederic Crozat, Guillaume Desmottes, Sander Dijkhuis, Neha Doijode, | ||||
|  Maxim Ermilov, Diego Escalante Urrelo, Luca Ferretti, Steve Frécinaux, | ||||
|  Takao Fujiwara, Adel Gadllah, Vadim Girlin, Nick Glynn, Guido Günther, | ||||
|  Leon Handreke, Lex Hider, Richard Hughes, Javier Jardón, Abderrahim Kitouni, | ||||
|  Andre Klapper, Alexander Larsson, Nickolas Lloyd, Ryan Lortie, Kjartan Maraas, | ||||
|  Koop Mast, Rui Matos, Jonathan Matthew, William Jon McCann, Morten Mjelva, | ||||
|  Federico Mena Quintero, Florian Müllner, Jon Nettleton, Hellyna Ng, | ||||
|  Discardi Nicola, Carlos Martín Nieto, Bastien Nocera, Bill Nottingham, | ||||
|  Matt Novenstern, Marc-Antoine Perennou, Neil Perry, Frédéric Péters, | ||||
|  Alejandro Piñeiro, Siegfried-Angel Gevatter Pujals, "res", Neil Roberts, | ||||
|  "Sardem FF7", Florian Scandella, Joseph Scheuhammer, Christian Schramm, | ||||
|  Gustavo Noronha Silva, Jasper St. Pierre, Eric Springer, Jakub Steiner, | ||||
|  Jonathan Strander, Ray Strode, Owen Taylor, Rico Tzschichholz, | ||||
|  Sergey V. Udaltsov, Daiki Ueno, Vincent Untz, Marcelo Jorge Vieira, | ||||
|  Mads Villadsen, Colin Walters, Dan Winship, William Wolf, Thomas Wood, | ||||
|  Pierre Yager, David Zeuthen, Marina Zhurakhinskaya | ||||
|  | ||||
| Design: | ||||
|  | ||||
|  Allan Day, William Jon McCann, Jeremy Perry, Jakub Steiner | ||||
|  2008 Boston GNOME design hackfest participants (especially Neil J. Patel | ||||
|  for turning the resulting sketches into our first mockups.) | ||||
|  Everybody on irc.gnome.org:#gnome-design | ||||
|  | ||||
| Translations: | ||||
|  | ||||
|  Friedel Wolff (af), Khaled Hosny (ar), Ivaylo Valkov (bg), Jamil Ahmed (bn) | ||||
|  Runa Bhattacharjee (bn_IN), Gil Forcada, Siegfried-Angel Gevatter Pujals, | ||||
|  Jordi Serratosa (ca), Andre Klapper, Petr Kovar (cs), Kenneth Nielsen, | ||||
|  Kris Thomsen (da), Mario Blättermann, Hendrik Brandt, Christian Kirbach, | ||||
|  Hendrik Richter, Wolfgang Stöggl (de), Michael Kotsarinis, Kostas Papadimas, | ||||
|  Jennie Petoumenou, Sterios Prosiniklis, Fotis Tsamis, Simos Xenitellis (el), | ||||
|  Bruce Cowan, Philip Withnall (en_GB), Jorge Gonzalez, Daniel Mustieles (es), | ||||
|  Mattias Põldaru, Ivar Smolin (et), Inaki Larranaga Murgoitio (eu), | ||||
|  Mahyar Moghimi (fa), Timo Jyrinki (fi), Cyril Arnaud, Bruno Brouard, | ||||
|  Pablo Martin-Gomez, Claude Paroz, Frédéric Peters (fr), Seán de Búrca (ga) | ||||
|  Francisco Diéguez, Antón Méixome (gl), Sweta Kothari (gu), Liel Fridman, | ||||
|  Yaron Shahrabani (he), Rajesh Ranjan (hi), Gabor Kelemen (hu), Milo Casagrande, | ||||
|  Luca Ferretti (it), Dirgita, Andika Triwidada (id), Takayuki KUSANO, | ||||
|  Takayoshi OKANO, Kiyotaka NISHIBORI, Futoshi NISHIO (ja), Shankar Prasad (kn), | ||||
|  Young-Ho Cha, Changwoo Ryu (ko), Žygimantas Beručka, Gintautas Miliauskas (lt), | ||||
|  Rudolfs Mazurs (lv), Sandeep Shedmake (mr), Kjartan Maraas (nb), | ||||
|  Wouter Bolsterlee, Sander Dijkhuis, Reinout van Schouwen (nl), | ||||
|  Torstein Winterseth (nn), A S Alam (pa), Tomasz Dominikowski, Piotr Drąg (pl), | ||||
|  Duarte Loreto (pt), Felipe Borges, Rodrigo Padula de Oliveira, | ||||
|  Rodrigo L. M. Flores, Amanda Magalhães, Og B. Maciel, Gabriel F. Vilar, | ||||
|  Jonh Wendell (pt_BR), Lucian Adrian Grijincu, Daniel Șerbănescu (ro), | ||||
|  Sergey V. Kovylov, Andrey Korzinev, Yuri Myasoedov, Marina Zhurakhinskaya (ru), | ||||
|  Daniel Nylander (se), Matej Urbančič, Andrej Žnidaršič (sl), | ||||
|  Miloš Popović (sr, sr@latin), Miroslav Nikolić (sr), Tirumurti Vasudevan (ta), | ||||
|  Sira Nokyoongtong (th), Baris Cicek (tr), Abduxukur Abdurixit, | ||||
|  Gheyret T. Kenji (ug), Maxim V. Dziumanenko, Daniel Korostil (uk), | ||||
|  Nguyễn Thái Ngọc Duy (vi), Jessica Ban, 'jiero', Wei Li, YunQiang Su, Ray Wang, | ||||
|  Aron Xu (zh_CN), Chao-Hsiung Liao (zh_HK, zh_TW) | ||||
| @@ -1,21 +0,0 @@ | ||||
|  | ||||
| mozillalibdir = $(libdir)/mozilla/plugins | ||||
|  | ||||
| mozillalib_LTLIBRARIES = libgnome-shell-browser-plugin.la | ||||
|  | ||||
| libgnome_shell_browser_plugin_la_LDFLAGS = -module -avoid-version -no-undefined | ||||
|  | ||||
| libgnome_shell_browser_plugin_la_LIBADD = 	\ | ||||
| 	$(BROWSER_PLUGIN_LIBS) | ||||
|  | ||||
| libgnome_shell_browser_plugin_la_SOURCES = 	\ | ||||
| 	browser-plugin.c \ | ||||
| 	npapi/npapi.h \ | ||||
| 	npapi/npfunctions.h \ | ||||
| 	npapi/npruntime.h \ | ||||
| 	npapi/nptypes.h | ||||
|  | ||||
| libgnome_shell_browser_plugin_la_CFLAGS = 	\ | ||||
| 	$(BROWSER_PLUGIN_CFLAGS)		\ | ||||
| 	-DG_DISABLE_DEPRECATED			\ | ||||
| 	-DG_LOG_DOMAIN=\"GnomeShellBrowserPlugin\" | ||||
| @@ -1,17 +0,0 @@ | ||||
| The GNOME Shell Browser Plugin provides integration with gnome-shell and the | ||||
| corresponding extensions repository, codenamed "SweetTooth". The plugin allows | ||||
| the extensions repository to provide good integration, letting the website | ||||
| know which extensions are enabled and disabled, and allowing the website to | ||||
| enable, disable and install them. | ||||
|  | ||||
| Bugs should be reported at http://bugzilla.gnome.org against the 'gnome-shell' | ||||
| product. | ||||
|  | ||||
| License | ||||
| ======= | ||||
| The GNOME Shell Browser Plugin, like GNOME Shell itself is distributed under | ||||
| the GNU General Public License, version 2 or later. The plugin also contains | ||||
| header files from the "NPAPI SDK" project, tri-licensed under MPL 1.1, GPL 2.0 | ||||
| and LGPL 2.1. These headers are third-party sources and can be retrieved from: | ||||
|  | ||||
|   http://code.google.com/p/npapi-sdk/ | ||||
| @@ -1,824 +0,0 @@ | ||||
| /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ | ||||
| /* | ||||
|  * Copyright (C) 2011 Red Hat | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU General Public License as | ||||
|  * published by the Free Software Foundation; either version 2 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, but | ||||
|  * WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software | ||||
|  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||||
|  * 02111-1307, USA. | ||||
|  * | ||||
|  * Authors: | ||||
|  *      Jasper St. Pierre <jstpierre@mecheye.net> | ||||
|  *      Giovanni Campagna <scampa.giovanni@gmail.com> | ||||
|  */ | ||||
|  | ||||
| #include <string.h> | ||||
|  | ||||
| #define XP_UNIX 1 | ||||
|  | ||||
| #include "npapi/npapi.h" | ||||
| #include "npapi/npruntime.h" | ||||
| #include "npapi/npfunctions.h" | ||||
|  | ||||
| #include <glib.h> | ||||
| #include <gio/gio.h> | ||||
| #include <json-glib/json-glib.h> | ||||
|  | ||||
| #define ORIGIN "extensions.gnome.org" | ||||
| #define PLUGIN_NAME "Gnome Shell Integration" | ||||
| #define PLUGIN_DESCRIPTION "This plugin provides integration with Gnome Shell " \ | ||||
|       "for live extension enabling and disabling. " \ | ||||
|       "It can be used only by extensions.gnome.org" | ||||
| #define PLUGIN_MIME_STRING "application/x-gnome-shell-integration::Gnome Shell Integration Dummy Content-Type"; | ||||
|  | ||||
| #define PLUGIN_API_VERSION 1 | ||||
|  | ||||
| typedef struct { | ||||
|   GDBusProxy *proxy; | ||||
| } PluginData; | ||||
|  | ||||
| /* =============== public entry points =================== */ | ||||
|  | ||||
| static NPNetscapeFuncs funcs; | ||||
|  | ||||
| static inline gchar * | ||||
| get_string_property (NPP         instance, | ||||
|                      NPObject   *obj, | ||||
|                      const char *name) | ||||
| { | ||||
|   NPVariant result = { NPVariantType_Void }; | ||||
|   NPString result_str; | ||||
|   gchar *result_copy; | ||||
|  | ||||
|   result_copy = NULL; | ||||
|  | ||||
|   if (!funcs.getproperty (instance, obj, | ||||
|                           funcs.getstringidentifier (name), | ||||
|                           &result)) | ||||
|     goto out; | ||||
|  | ||||
|   if (!NPVARIANT_IS_STRING (result)) | ||||
|     goto out; | ||||
|  | ||||
|   result_str = NPVARIANT_TO_STRING (result); | ||||
|   if (strlen (result_str.UTF8Characters) != result_str.UTF8Length) | ||||
|     goto out; | ||||
|  | ||||
|   result_copy = g_strdup (result_str.UTF8Characters); | ||||
|  | ||||
|  out: | ||||
|   funcs.releasevariantvalue (&result); | ||||
|   return result_copy; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| check_origin_and_protocol (NPP instance) | ||||
| { | ||||
|   gboolean ret = FALSE; | ||||
|   NPError error; | ||||
|   NPObject *window = NULL; | ||||
|   NPVariant document = { NPVariantType_Void }; | ||||
|   NPVariant location = { NPVariantType_Void }; | ||||
|   gchar *hostname = NULL; | ||||
|   gchar *protocol = NULL; | ||||
|  | ||||
|   error = funcs.getvalue (instance, NPNVWindowNPObject, &window); | ||||
|   if (error != NPERR_NO_ERROR) | ||||
|     goto out; | ||||
|  | ||||
|   if (!funcs.getproperty (instance, window, | ||||
|                           funcs.getstringidentifier ("document"), | ||||
|                           &document)) | ||||
|     goto out; | ||||
|  | ||||
|   if (!NPVARIANT_IS_OBJECT (document)) | ||||
|     goto out; | ||||
|  | ||||
|   if (!funcs.getproperty (instance, NPVARIANT_TO_OBJECT (document), | ||||
|                           funcs.getstringidentifier ("location"), | ||||
|                           &location)) | ||||
|     goto out; | ||||
|  | ||||
|   if (!NPVARIANT_IS_OBJECT (document)) | ||||
|     goto out; | ||||
|  | ||||
|   hostname = get_string_property (instance, | ||||
|                                   NPVARIANT_TO_OBJECT (location), | ||||
|                                   "hostname"); | ||||
|  | ||||
|   if (g_strcmp0 (hostname, ORIGIN)) | ||||
|     { | ||||
|       g_debug ("origin does not match, is %s", | ||||
|                hostname); | ||||
|  | ||||
|       goto out; | ||||
|     } | ||||
|  | ||||
|   protocol = get_string_property (instance, | ||||
|                                   NPVARIANT_TO_OBJECT (location), | ||||
|                                   "protocol"); | ||||
|  | ||||
|   if (g_strcmp0 (protocol, "https:") != 0) | ||||
|     { | ||||
|       g_debug ("protocol does not match, is %s", | ||||
|                protocol); | ||||
|  | ||||
|       goto out; | ||||
|     } | ||||
|  | ||||
|   ret = TRUE; | ||||
|  | ||||
|  out: | ||||
|   g_free (protocol); | ||||
|   g_free (hostname); | ||||
|  | ||||
|   funcs.releasevariantvalue (&location); | ||||
|   funcs.releasevariantvalue (&document); | ||||
|  | ||||
|   if (window != NULL) | ||||
|     funcs.releaseobject (window); | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| NPError | ||||
| NP_Initialize(NPNetscapeFuncs *pfuncs, NPPluginFuncs *plugin) | ||||
| { | ||||
|   /* global initialization routine, called once when plugin | ||||
|      is loaded */ | ||||
|  | ||||
|   g_debug ("plugin loaded"); | ||||
|  | ||||
|   memcpy (&funcs, pfuncs, sizeof (funcs)); | ||||
|  | ||||
|   plugin->size = sizeof(NPPluginFuncs); | ||||
|   plugin->newp = NPP_New; | ||||
|   plugin->destroy = NPP_Destroy; | ||||
|   plugin->getvalue = NPP_GetValue; | ||||
|  | ||||
|   return NPERR_NO_ERROR; | ||||
| } | ||||
|  | ||||
| NPError | ||||
| NP_Shutdown(void) | ||||
| { | ||||
|   return NPERR_NO_ERROR; | ||||
| } | ||||
|  | ||||
| const char* | ||||
| NP_GetMIMEDescription(void) | ||||
| { | ||||
|   return PLUGIN_MIME_STRING; | ||||
| } | ||||
|  | ||||
| NPError | ||||
| NP_GetValue(void         *instance, | ||||
|             NPPVariable   variable, | ||||
|             void         *value) | ||||
| { | ||||
|   switch (variable) { | ||||
|   case NPPVpluginNameString: | ||||
|     *(char**)value = PLUGIN_NAME; | ||||
|     break; | ||||
|   case NPPVpluginDescriptionString: | ||||
|     *(char**)value = PLUGIN_DESCRIPTION; | ||||
|     break; | ||||
|   default: | ||||
|     ; | ||||
|   } | ||||
|  | ||||
|   return NPERR_NO_ERROR; | ||||
| } | ||||
|  | ||||
| NPError | ||||
| NPP_New(NPMIMEType    mimetype, | ||||
|         NPP           instance, | ||||
|         uint16_t      mode, | ||||
|         int16_t       argc, | ||||
|         char        **argn, | ||||
|         char        **argv, | ||||
|         NPSavedData  *saved) | ||||
| { | ||||
|   /* instance initialization function */ | ||||
|   PluginData *data; | ||||
|   GError *error = NULL; | ||||
|  | ||||
|   g_debug ("plugin created"); | ||||
|  | ||||
|   if (!check_origin_and_protocol (instance)) | ||||
|     return NPERR_GENERIC_ERROR; | ||||
|  | ||||
|   data = g_slice_new (PluginData); | ||||
|   instance->pdata = data; | ||||
|  | ||||
|   data->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, | ||||
|                                                G_DBUS_PROXY_FLAGS_NONE, | ||||
|                                                NULL, /* interface info */ | ||||
|                                                "org.gnome.Shell", | ||||
|                                                "/org/gnome/Shell", | ||||
|                                                "org.gnome.Shell", | ||||
|                                                NULL, /* GCancellable */ | ||||
|                                                &error); | ||||
|   if (!data->proxy) | ||||
|     { | ||||
|       /* ignore error if the shell is not running, otherwise warn */ | ||||
|       if (error->domain != G_DBUS_ERROR || | ||||
|           error->code != G_DBUS_ERROR_NAME_HAS_NO_OWNER) | ||||
|         { | ||||
|           g_warning ("Failed to set up Shell proxy: %s", error->message); | ||||
|         } | ||||
|       g_clear_error (&error); | ||||
|       return NPERR_GENERIC_ERROR; | ||||
|     } | ||||
|  | ||||
|   g_debug ("plugin created successfully"); | ||||
|  | ||||
|   return NPERR_NO_ERROR; | ||||
| } | ||||
|  | ||||
| NPError | ||||
| NPP_Destroy(NPP           instance, | ||||
| 	    NPSavedData **saved) | ||||
| { | ||||
|   /* instance finalization function */ | ||||
|  | ||||
|   PluginData *data = instance->pdata; | ||||
|  | ||||
|   g_debug ("plugin destroyed"); | ||||
|  | ||||
|   g_object_unref (data->proxy); | ||||
|  | ||||
|   g_slice_free (PluginData, data); | ||||
|  | ||||
|   return NPERR_NO_ERROR; | ||||
| } | ||||
|  | ||||
| /* =================== scripting interface =================== */ | ||||
|  | ||||
| typedef struct { | ||||
| 	NPObject     parent; | ||||
| 	NPP          instance; | ||||
| 	GDBusProxy  *proxy; | ||||
| 	NPObject    *listener; | ||||
| 	gint         signal_id; | ||||
| } PluginObject; | ||||
|  | ||||
| static void | ||||
| on_shell_signal (GDBusProxy *proxy, | ||||
|                  gchar      *sender_name, | ||||
|                  gchar      *signal_name, | ||||
|                  GVariant   *parameters, | ||||
|                  gpointer    user_data) | ||||
| { | ||||
|   PluginObject *obj = user_data; | ||||
|  | ||||
|   if (strcmp (signal_name, "ExtensionStatusChanged") == 0) | ||||
|     { | ||||
|       gchar *uuid; | ||||
|       gint32 status; | ||||
|       gchar *error; | ||||
|       NPVariant args[3]; | ||||
|       NPVariant result; | ||||
|  | ||||
|       g_variant_get (parameters, "(sis)", &uuid, &status, &error); | ||||
|       STRINGZ_TO_NPVARIANT (uuid, args[0]); | ||||
|       INT32_TO_NPVARIANT (status, args[1]); | ||||
|       STRINGZ_TO_NPVARIANT (error, args[2]); | ||||
|  | ||||
|       funcs.invokeDefault (obj->instance, obj->listener, | ||||
| 			   args, 3, &result); | ||||
|  | ||||
|       funcs.releasevariantvalue (&result); | ||||
|       g_free (uuid); | ||||
|       g_free (error); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static NPObject * | ||||
| plugin_object_allocate (NPP      instance, | ||||
|                         NPClass *klass) | ||||
| { | ||||
|   PluginData *data = instance->pdata; | ||||
|   PluginObject *obj = g_slice_new0 (PluginObject); | ||||
|  | ||||
|   obj->instance = instance; | ||||
|   obj->proxy = g_object_ref (data->proxy); | ||||
|   obj->signal_id = g_signal_connect (obj->proxy, "g-signal", | ||||
|                                      G_CALLBACK (on_shell_signal), obj); | ||||
|  | ||||
|   g_debug ("plugin object created"); | ||||
|  | ||||
|   return (NPObject*)obj; | ||||
| } | ||||
|  | ||||
| static void | ||||
| plugin_object_deallocate (NPObject *npobj) | ||||
| { | ||||
|   PluginObject *obj = (PluginObject*)npobj; | ||||
|  | ||||
|   g_signal_handler_disconnect (obj->proxy, obj->signal_id); | ||||
|   g_object_unref (obj->proxy); | ||||
|  | ||||
|   if (obj->listener) | ||||
|     funcs.releaseobject (obj->listener); | ||||
|  | ||||
|   g_debug ("plugin object destroyed"); | ||||
|  | ||||
|   g_slice_free (PluginObject, obj); | ||||
| } | ||||
|  | ||||
| static NPIdentifier api_version_id; | ||||
| static NPIdentifier shell_version_id; | ||||
| static NPIdentifier get_info_id; | ||||
| static NPIdentifier list_extensions_id; | ||||
| static NPIdentifier enable_extension_id; | ||||
| static NPIdentifier install_extension_id; | ||||
| static NPIdentifier uninstall_extension_id; | ||||
| static NPIdentifier onextension_changed_id; | ||||
| static NPIdentifier get_errors_id; | ||||
|  | ||||
| static bool | ||||
| plugin_object_has_method (NPObject     *npobj, | ||||
|                           NPIdentifier  name) | ||||
| { | ||||
|   return (name == get_info_id || | ||||
|           name == list_extensions_id || | ||||
|           name == enable_extension_id || | ||||
|           name == install_extension_id || | ||||
|           name == uninstall_extension_id || | ||||
|           name == get_errors_id); | ||||
| } | ||||
|  | ||||
| static inline gboolean | ||||
| uuid_is_valid (const gchar *uuid) | ||||
| { | ||||
|   gsize i; | ||||
|  | ||||
|   for (i = 0; uuid[i]; i ++) | ||||
|     { | ||||
|       gchar c = uuid[i]; | ||||
|       if (c < 32 || c >= 127) | ||||
|         return FALSE; | ||||
|  | ||||
|       switch (c) | ||||
|         { | ||||
|         case '&': | ||||
|         case '<': | ||||
|         case '>': | ||||
|         case '/': | ||||
|         case '\\': | ||||
|           return FALSE; | ||||
|         default: | ||||
|           break; | ||||
|         } | ||||
|     } | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| jsonify_variant (GVariant  *variant, | ||||
|                  NPVariant *result) | ||||
| { | ||||
|   gboolean ret; | ||||
|   GVariant *real_value; | ||||
|   JsonNode *root; | ||||
|   JsonGenerator *generator; | ||||
|   gsize json_length; | ||||
|   gchar *json; | ||||
|   gchar *buffer; | ||||
|  | ||||
|   ret = TRUE; | ||||
|  | ||||
|   /* DBus methods can return multiple values, | ||||
|    * but we're only interested in the first. */ | ||||
|   g_variant_get (variant, "(@*)", &real_value); | ||||
|  | ||||
|   root = json_gvariant_serialize (real_value); | ||||
|  | ||||
|   generator = json_generator_new (); | ||||
|   json_generator_set_root (generator, root); | ||||
|   json = json_generator_to_data (generator, &json_length); | ||||
|  | ||||
|   buffer = funcs.memalloc (json_length + 1); | ||||
|   if (!buffer) | ||||
|     { | ||||
|       ret = FALSE; | ||||
|       goto out; | ||||
|     } | ||||
|  | ||||
|   strcpy (buffer, json); | ||||
|  | ||||
|   STRINGN_TO_NPVARIANT (buffer, json_length, *result); | ||||
|  | ||||
|  out: | ||||
|   g_variant_unref (variant); | ||||
|   g_variant_unref (real_value); | ||||
|   json_node_free (root); | ||||
|   g_free (json); | ||||
|  | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| plugin_list_extensions (PluginObject  *obj, | ||||
|                         NPVariant     *result) | ||||
| { | ||||
|   GError *error = NULL; | ||||
|   GVariant *res; | ||||
|  | ||||
|   res = g_dbus_proxy_call_sync (obj->proxy, | ||||
|                                 "ListExtensions", | ||||
|                                 NULL, /* parameters */ | ||||
|                                 G_DBUS_CALL_FLAGS_NONE, | ||||
|                                 -1, /* timeout */ | ||||
|                                 NULL, /* cancellable */ | ||||
|                                 &error); | ||||
|  | ||||
|   if (!res) | ||||
|     { | ||||
|       g_warning ("Failed to retrieve extension list: %s", error->message); | ||||
|       g_error_free (error); | ||||
|       return FALSE; | ||||
|     } | ||||
|  | ||||
|   return jsonify_variant (res, result); | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| plugin_enable_extension (PluginObject *obj, | ||||
|                          NPString      uuid, | ||||
|                          gboolean      enabled) | ||||
| { | ||||
|   const gchar *uuid_str = uuid.UTF8Characters; | ||||
|   if (!uuid_is_valid (uuid_str)) | ||||
|     return FALSE; | ||||
|  | ||||
|   g_dbus_proxy_call (obj->proxy, | ||||
|                      (enabled ? "EnableExtension" : "DisableExtension"), | ||||
|                      g_variant_new ("(s)", uuid_str), | ||||
|                      G_DBUS_CALL_FLAGS_NONE, | ||||
|                      -1, /* timeout */ | ||||
|                      NULL, /* cancellable */ | ||||
|                      NULL, /* callback */ | ||||
|                      NULL /* user_data */); | ||||
|  | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| plugin_install_extension (PluginObject *obj, | ||||
|                           NPString      uuid, | ||||
|                           NPString      version_tag) | ||||
| { | ||||
|   const gchar *uuid_str = uuid.UTF8Characters; | ||||
|   if (!uuid_is_valid (uuid_str)) | ||||
|     return FALSE; | ||||
|  | ||||
|   g_dbus_proxy_call (obj->proxy, | ||||
|                      "InstallRemoteExtension", | ||||
|                      g_variant_new ("(ss)", | ||||
|                                     uuid_str, | ||||
|                                     version_tag.UTF8Characters), | ||||
|                      G_DBUS_CALL_FLAGS_NONE, | ||||
|                      -1, /* timeout */ | ||||
|                      NULL, /* cancellable */ | ||||
|                      NULL, /* callback */ | ||||
|                      NULL /* user_data */); | ||||
|  | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| plugin_uninstall_extension (PluginObject *obj, | ||||
|                             NPString      uuid, | ||||
|                             NPVariant    *result) | ||||
| { | ||||
|   GError *error = NULL; | ||||
|   GVariant *res; | ||||
|   const gchar *uuid_str; | ||||
|  | ||||
|   uuid_str = uuid.UTF8Characters; | ||||
|   if (!uuid_is_valid (uuid_str)) | ||||
|     return FALSE; | ||||
|  | ||||
|   res = g_dbus_proxy_call_sync (obj->proxy, | ||||
|                                 "UninstallExtension", | ||||
|                                 g_variant_new ("(s)", | ||||
|                                                uuid_str), | ||||
|                                 G_DBUS_CALL_FLAGS_NONE, | ||||
|                                 -1, /* timeout */ | ||||
|                                 NULL, /* cancellable */ | ||||
|                                 &error); | ||||
|  | ||||
|   if (!res) | ||||
|     { | ||||
|       g_warning ("Failed to uninstall extension: %s", error->message); | ||||
|       g_error_free (error); | ||||
|       return FALSE; | ||||
|     } | ||||
|  | ||||
|   return jsonify_variant (res, result); | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| plugin_get_info (PluginObject *obj, | ||||
|                  NPString      uuid, | ||||
|                  NPVariant    *result) | ||||
| { | ||||
|   GError *error = NULL; | ||||
|   GVariant *res; | ||||
|   const gchar *uuid_str; | ||||
|  | ||||
|   uuid_str = uuid.UTF8Characters; | ||||
|   if (!uuid_is_valid (uuid_str)) | ||||
|     return FALSE; | ||||
|  | ||||
|   res = g_dbus_proxy_call_sync (obj->proxy, | ||||
|                                 "GetExtensionInfo", | ||||
|                                 g_variant_new ("(s)", uuid_str), | ||||
|                                 G_DBUS_CALL_FLAGS_NONE, | ||||
|                                 -1, /* timeout */ | ||||
|                                 NULL, /* cancellable */ | ||||
|                                 &error); | ||||
|  | ||||
|   if (!res) | ||||
|     { | ||||
|       g_warning ("Failed to retrieve extension metadata: %s", error->message); | ||||
|       g_error_free (error); | ||||
|       return FALSE; | ||||
|     } | ||||
|  | ||||
|   return jsonify_variant (res, result); | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| plugin_get_errors (PluginObject *obj, | ||||
|                    NPString      uuid, | ||||
|                    NPVariant    *result) | ||||
| { | ||||
|   GError *error = NULL; | ||||
|   GVariant *res; | ||||
|   const gchar *uuid_str; | ||||
|  | ||||
|   uuid_str = uuid.UTF8Characters; | ||||
|   if (!uuid_is_valid (uuid_str)) | ||||
|     return FALSE; | ||||
|  | ||||
|   res = g_dbus_proxy_call_sync (obj->proxy, | ||||
|                                 "GetExtensionErrors", | ||||
|                                 g_variant_new ("(s)", uuid_str), | ||||
|                                 G_DBUS_CALL_FLAGS_NONE, | ||||
|                                 -1, /* timeout */ | ||||
|                                 NULL, /* cancellable */ | ||||
|                                 &error); | ||||
|  | ||||
|   if (!res) | ||||
|     { | ||||
|       g_warning ("Failed to retrieve errors: %s", error->message); | ||||
|       g_error_free (error); | ||||
|       return FALSE; | ||||
|     } | ||||
|  | ||||
|   return jsonify_variant (res, result); | ||||
| } | ||||
|  | ||||
| static int | ||||
| plugin_get_api_version (PluginObject  *obj, | ||||
|                         NPVariant     *result) | ||||
| { | ||||
|   INT32_TO_NPVARIANT (PLUGIN_API_VERSION, *result); | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| plugin_get_shell_version (PluginObject  *obj, | ||||
|                           NPVariant     *result) | ||||
| { | ||||
|   GVariant *res; | ||||
|   const gchar *version; | ||||
|   gsize length; | ||||
|   gchar *buffer; | ||||
|   gboolean ret; | ||||
|  | ||||
|   ret = TRUE; | ||||
|  | ||||
|   res = g_dbus_proxy_get_cached_property (obj->proxy, | ||||
|                                           "ShellVersion"); | ||||
|  | ||||
|   if (res == NULL) | ||||
|     { | ||||
|       g_warning ("Failed to grab shell version."); | ||||
|       version = "-1"; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       g_variant_get (res, "&s", &version); | ||||
|     } | ||||
|  | ||||
|   length = strlen (version); | ||||
|   buffer = funcs.memalloc (length + 1); | ||||
|   if (!buffer) | ||||
|     { | ||||
|       ret = FALSE; | ||||
|       goto out; | ||||
|     } | ||||
|   strcpy (buffer, version); | ||||
|  | ||||
|   STRINGN_TO_NPVARIANT (buffer, length, *result); | ||||
|  | ||||
|  out: | ||||
|   g_variant_unref (res); | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| static bool | ||||
| plugin_object_invoke (NPObject        *npobj, | ||||
|                       NPIdentifier     name, | ||||
|                       const NPVariant *args, | ||||
|                       uint32_t         argc, | ||||
|                       NPVariant       *result) | ||||
| { | ||||
|   PluginObject *obj; | ||||
|  | ||||
|   g_debug ("invoking plugin object method"); | ||||
|  | ||||
|   obj = (PluginObject*) npobj; | ||||
|  | ||||
|   VOID_TO_NPVARIANT (*result); | ||||
|  | ||||
|   if (!plugin_object_has_method (npobj, name)) | ||||
|     return FALSE; | ||||
|  | ||||
|   if (name == list_extensions_id) | ||||
|     return plugin_list_extensions (obj, result); | ||||
|   else if (name == get_info_id) | ||||
|     { | ||||
|       if (!NPVARIANT_IS_STRING(args[0])) return FALSE; | ||||
|  | ||||
|       return plugin_get_info (obj, NPVARIANT_TO_STRING(args[0]), result); | ||||
|     } | ||||
|   else if (name == enable_extension_id) | ||||
|     { | ||||
|       if (!NPVARIANT_IS_STRING(args[0])) return FALSE; | ||||
|       if (!NPVARIANT_IS_BOOLEAN(args[1])) return FALSE; | ||||
|  | ||||
|       return plugin_enable_extension (obj, | ||||
|                                       NPVARIANT_TO_STRING(args[0]), | ||||
|                                       NPVARIANT_TO_BOOLEAN(args[1])); | ||||
|     } | ||||
|   else if (name == install_extension_id) | ||||
|     { | ||||
|       if (!NPVARIANT_IS_STRING(args[0])) return FALSE; | ||||
|       if (!NPVARIANT_IS_STRING(args[1])) return FALSE; | ||||
|  | ||||
|       return plugin_install_extension (obj, | ||||
|                                        NPVARIANT_TO_STRING(args[0]), | ||||
|                                        NPVARIANT_TO_STRING(args[1])); | ||||
|     } | ||||
|   else if (name == uninstall_extension_id) | ||||
|     { | ||||
|       if (!NPVARIANT_IS_STRING(args[0])) return FALSE; | ||||
|  | ||||
|       return plugin_uninstall_extension (obj, | ||||
|                                          NPVARIANT_TO_STRING(args[0]), | ||||
|                                          result); | ||||
|     } | ||||
|   else if (name == get_errors_id) | ||||
|     { | ||||
|       if (!NPVARIANT_IS_STRING(args[0])) return FALSE; | ||||
|  | ||||
|       return plugin_get_errors (obj, | ||||
|                                 NPVARIANT_TO_STRING(args[0]), | ||||
|                                 result); | ||||
|     } | ||||
|  | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| static bool | ||||
| plugin_object_has_property (NPObject     *npobj, | ||||
|                             NPIdentifier  name) | ||||
| { | ||||
|   return (name == onextension_changed_id || | ||||
|           name == api_version_id || | ||||
|           name == shell_version_id); | ||||
| } | ||||
|  | ||||
| static bool | ||||
| plugin_object_get_property (NPObject     *npobj, | ||||
|                             NPIdentifier  name, | ||||
|                             NPVariant    *result) | ||||
| { | ||||
|   PluginObject *obj; | ||||
|  | ||||
|   if (!plugin_object_has_property (npobj, name)) | ||||
|     return FALSE; | ||||
|  | ||||
|   obj = (PluginObject*) npobj; | ||||
|   if (name == api_version_id) | ||||
|     return plugin_get_api_version (obj, result); | ||||
|   else if (name == shell_version_id) | ||||
|     return plugin_get_shell_version (obj, result); | ||||
|   else if (name == onextension_changed_id) | ||||
|     { | ||||
|       if (obj->listener) | ||||
|         OBJECT_TO_NPVARIANT (obj->listener, *result); | ||||
|       else | ||||
|         NULL_TO_NPVARIANT (*result); | ||||
|     } | ||||
|  | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| static bool | ||||
| plugin_object_set_property (NPObject        *npobj, | ||||
|                             NPIdentifier     name, | ||||
|                             const NPVariant *value) | ||||
| { | ||||
|   PluginObject *obj; | ||||
|  | ||||
|   if (!plugin_object_has_property (npobj, name)) | ||||
|     return FALSE; | ||||
|  | ||||
|   if (name == onextension_changed_id) | ||||
|     { | ||||
|       obj = (PluginObject*) npobj; | ||||
|       if (obj->listener) | ||||
|         funcs.releaseobject (obj->listener); | ||||
|  | ||||
|       obj->listener = NULL; | ||||
|       if (NPVARIANT_IS_OBJECT (*value)) | ||||
|         { | ||||
|           obj->listener = NPVARIANT_TO_OBJECT (*value); | ||||
|           funcs.retainobject (obj->listener); | ||||
|           return TRUE; | ||||
|         } | ||||
|       else if (NPVARIANT_IS_NULL (*value)) | ||||
|         return TRUE; | ||||
|     } | ||||
|  | ||||
|   return FALSE; | ||||
| } | ||||
|  | ||||
| static NPClass plugin_class = { | ||||
|   NP_CLASS_STRUCT_VERSION, | ||||
|   plugin_object_allocate, | ||||
|   plugin_object_deallocate, | ||||
|   NULL, /* invalidate */ | ||||
|   plugin_object_has_method, | ||||
|   plugin_object_invoke, | ||||
|   NULL, /* invoke default */ | ||||
|   plugin_object_has_property, | ||||
|   plugin_object_get_property, | ||||
|   plugin_object_set_property, | ||||
|   NULL, /* remove property */ | ||||
|   NULL, /* enumerate */ | ||||
|   NULL, /* construct */ | ||||
| }; | ||||
|  | ||||
| static void | ||||
| init_methods_and_properties (void) | ||||
| { | ||||
|   /* this is the JS public API; it is manipulated through NPIdentifiers for speed */ | ||||
|   api_version_id = funcs.getstringidentifier ("apiVersion"); | ||||
|   shell_version_id = funcs.getstringidentifier ("shellVersion"); | ||||
|  | ||||
|   get_info_id = funcs.getstringidentifier ("getExtensionInfo"); | ||||
|   list_extensions_id = funcs.getstringidentifier ("listExtensions"); | ||||
|   enable_extension_id = funcs.getstringidentifier ("setExtensionEnabled"); | ||||
|   install_extension_id = funcs.getstringidentifier ("installExtension"); | ||||
|   uninstall_extension_id = funcs.getstringidentifier ("uninstallExtension"); | ||||
|   get_errors_id = funcs.getstringidentifier ("getExtensionErrors"); | ||||
|  | ||||
|   onextension_changed_id = funcs.getstringidentifier ("onchange"); | ||||
| } | ||||
|  | ||||
| NPError | ||||
| NPP_GetValue(NPP          instance, | ||||
| 	     NPPVariable  variable, | ||||
| 	     void        *value) | ||||
| { | ||||
|   g_debug ("NPP_GetValue called"); | ||||
|  | ||||
|   switch (variable) { | ||||
|   case NPPVpluginScriptableNPObject: | ||||
|     g_debug ("creating scriptable object"); | ||||
|     init_methods_and_properties (); | ||||
|  | ||||
|     *(NPObject**)value = funcs.createobject (instance, &plugin_class); | ||||
|     break; | ||||
|   default: | ||||
|     ; | ||||
|   } | ||||
|  | ||||
|   return NPERR_NO_ERROR; | ||||
| } | ||||
| @@ -1,893 +0,0 @@ | ||||
| /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | ||||
| /* ***** BEGIN LICENSE BLOCK ***** | ||||
|  * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | ||||
|  * | ||||
|  * The contents of this file are subject to the Mozilla Public License Version | ||||
|  * 1.1 (the "License"); you may not use this file except in compliance with | ||||
|  * the License. You may obtain a copy of the License at | ||||
|  * http://www.mozilla.org/MPL/ | ||||
|  * | ||||
|  * Software distributed under the License is distributed on an "AS IS" basis, | ||||
|  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | ||||
|  * for the specific language governing rights and limitations under the | ||||
|  * License. | ||||
|  * | ||||
|  * The Original Code is mozilla.org code. | ||||
|  * | ||||
|  * The Initial Developer of the Original Code is | ||||
|  * Netscape Communications Corporation. | ||||
|  * Portions created by the Initial Developer are Copyright (C) 1998 | ||||
|  * the Initial Developer. All Rights Reserved. | ||||
|  * | ||||
|  * Contributor(s): | ||||
|  * | ||||
|  * Alternatively, the contents of this file may be used under the terms of | ||||
|  * either the GNU General Public License Version 2 or later (the "GPL"), or | ||||
|  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), | ||||
|  * in which case the provisions of the GPL or the LGPL are applicable instead | ||||
|  * of those above. If you wish to allow use of your version of this file only | ||||
|  * under the terms of either the GPL or the LGPL, and not to allow others to | ||||
|  * use your version of this file under the terms of the MPL, indicate your | ||||
|  * decision by deleting the provisions above and replace them with the notice | ||||
|  * and other provisions required by the GPL or the LGPL. If you do not delete | ||||
|  * the provisions above, a recipient may use your version of this file under | ||||
|  * the terms of any one of the MPL, the GPL or the LGPL. | ||||
|  * | ||||
|  * ***** END LICENSE BLOCK ***** */ | ||||
|  | ||||
| #ifndef npapi_h_ | ||||
| #define npapi_h_ | ||||
|  | ||||
| #if defined(__OS2__) | ||||
| #pragma pack(1) | ||||
| #endif | ||||
|  | ||||
| #include "nptypes.h" | ||||
|  | ||||
| #if defined(__OS2__) || defined(OS2) | ||||
| #ifndef XP_OS2 | ||||
| #define XP_OS2 1 | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #if defined(_WIN32) && !defined(__SYMBIAN32__) | ||||
| #include <windef.h> | ||||
| #ifndef XP_WIN | ||||
| #define XP_WIN 1 | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #if defined(__SYMBIAN32__) | ||||
| #ifndef XP_SYMBIAN | ||||
| #define XP_SYMBIAN 1 | ||||
| #undef XP_WIN | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #if defined(__APPLE_CC__) && !defined(XP_UNIX) | ||||
| #ifndef XP_MACOSX | ||||
| #define XP_MACOSX 1 | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #if defined(XP_MACOSX) && defined(__LP64__) | ||||
| #define NP_NO_QUICKDRAW | ||||
| #define NP_NO_CARBON | ||||
| #endif | ||||
|  | ||||
| #if defined(XP_MACOSX) | ||||
| #include <ApplicationServices/ApplicationServices.h> | ||||
| #include <OpenGL/OpenGL.h> | ||||
| #ifndef NP_NO_CARBON | ||||
| #include <Carbon/Carbon.h> | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #if defined(XP_UNIX) | ||||
| #include <stdio.h> | ||||
| #if defined(MOZ_X11) | ||||
| #include <X11/Xlib.h> | ||||
| #include <X11/Xutil.h> | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #if defined(XP_SYMBIAN) | ||||
| #include <QEvent> | ||||
| #include <QRegion> | ||||
| #endif | ||||
|  | ||||
| /*----------------------------------------------------------------------*/ | ||||
| /*                        Plugin Version Constants                      */ | ||||
| /*----------------------------------------------------------------------*/ | ||||
|  | ||||
| #define NP_VERSION_MAJOR 0 | ||||
| #define NP_VERSION_MINOR 27 | ||||
|  | ||||
|  | ||||
| /* The OS/2 version of Netscape uses RC_DATA to define the | ||||
|    mime types, file extensions, etc that are required. | ||||
|    Use a vertical bar to separate types, end types with \0. | ||||
|    FileVersion and ProductVersion are 32bit ints, all other | ||||
|    entries are strings that MUST be terminated with a \0. | ||||
|  | ||||
| AN EXAMPLE: | ||||
|  | ||||
| RCDATA NP_INFO_ProductVersion { 1,0,0,1,} | ||||
|  | ||||
| RCDATA NP_INFO_MIMEType    { "video/x-video|", | ||||
|                              "video/x-flick\0" } | ||||
| RCDATA NP_INFO_FileExtents { "avi|", | ||||
|                              "flc\0" } | ||||
| RCDATA NP_INFO_FileOpenName{ "MMOS2 video player(*.avi)|", | ||||
|                              "MMOS2 Flc/Fli player(*.flc)\0" } | ||||
|  | ||||
| RCDATA NP_INFO_FileVersion       { 1,0,0,1 } | ||||
| RCDATA NP_INFO_CompanyName       { "Netscape Communications\0" } | ||||
| RCDATA NP_INFO_FileDescription   { "NPAVI32 Extension DLL\0" | ||||
| RCDATA NP_INFO_InternalName      { "NPAVI32\0" ) | ||||
| RCDATA NP_INFO_LegalCopyright    { "Copyright Netscape Communications \251 1996\0" | ||||
| RCDATA NP_INFO_OriginalFilename  { "NVAPI32.DLL" } | ||||
| RCDATA NP_INFO_ProductName       { "NPAVI32 Dynamic Link Library\0" } | ||||
| */ | ||||
| /* RC_DATA types for version info - required */ | ||||
| #define NP_INFO_ProductVersion      1 | ||||
| #define NP_INFO_MIMEType            2 | ||||
| #define NP_INFO_FileOpenName        3 | ||||
| #define NP_INFO_FileExtents         4 | ||||
| /* RC_DATA types for version info - used if found */ | ||||
| #define NP_INFO_FileDescription     5 | ||||
| #define NP_INFO_ProductName         6 | ||||
| /* RC_DATA types for version info - optional */ | ||||
| #define NP_INFO_CompanyName         7 | ||||
| #define NP_INFO_FileVersion         8 | ||||
| #define NP_INFO_InternalName        9 | ||||
| #define NP_INFO_LegalCopyright      10 | ||||
| #define NP_INFO_OriginalFilename    11 | ||||
|  | ||||
| #ifndef RC_INVOKED | ||||
|  | ||||
| /*----------------------------------------------------------------------*/ | ||||
| /*                       Definition of Basic Types                      */ | ||||
| /*----------------------------------------------------------------------*/ | ||||
|  | ||||
| typedef unsigned char NPBool; | ||||
| typedef int16_t       NPError; | ||||
| typedef int16_t       NPReason; | ||||
| typedef char*         NPMIMEType; | ||||
|  | ||||
| /*----------------------------------------------------------------------*/ | ||||
| /*                       Structures and definitions                     */ | ||||
| /*----------------------------------------------------------------------*/ | ||||
|  | ||||
| #if !defined(__LP64__) | ||||
| #if defined(XP_MACOSX) | ||||
| #pragma options align=mac68k | ||||
| #endif | ||||
| #endif /* __LP64__ */ | ||||
|  | ||||
| /* | ||||
|  *  NPP is a plug-in's opaque instance handle | ||||
|  */ | ||||
| typedef struct _NPP | ||||
| { | ||||
|   void* pdata;      /* plug-in private data */ | ||||
|   void* ndata;      /* netscape private data */ | ||||
| } NPP_t; | ||||
|  | ||||
| typedef NPP_t*  NPP; | ||||
|  | ||||
| typedef struct _NPStream | ||||
| { | ||||
|   void*    pdata; /* plug-in private data */ | ||||
|   void*    ndata; /* netscape private data */ | ||||
|   const    char* url; | ||||
|   uint32_t end; | ||||
|   uint32_t lastmodified; | ||||
|   void*    notifyData; | ||||
|   const    char* headers; /* Response headers from host. | ||||
|                            * Exists only for >= NPVERS_HAS_RESPONSE_HEADERS. | ||||
|                            * Used for HTTP only; NULL for non-HTTP. | ||||
|                            * Available from NPP_NewStream onwards. | ||||
|                            * Plugin should copy this data before storing it. | ||||
|                            * Includes HTTP status line and all headers, | ||||
|                            * preferably verbatim as received from server, | ||||
|                            * headers formatted as in HTTP ("Header: Value"), | ||||
|                            * and newlines (\n, NOT \r\n) separating lines. | ||||
|                            * Terminated by \n\0 (NOT \n\n\0). */ | ||||
| } NPStream; | ||||
|  | ||||
| typedef struct _NPByteRange | ||||
| { | ||||
|   int32_t  offset; /* negative offset means from the end */ | ||||
|   uint32_t length; | ||||
|   struct _NPByteRange* next; | ||||
| } NPByteRange; | ||||
|  | ||||
| typedef struct _NPSavedData | ||||
| { | ||||
|   int32_t len; | ||||
|   void*   buf; | ||||
| } NPSavedData; | ||||
|  | ||||
| typedef struct _NPRect | ||||
| { | ||||
|   uint16_t top; | ||||
|   uint16_t left; | ||||
|   uint16_t bottom; | ||||
|   uint16_t right; | ||||
| } NPRect; | ||||
|  | ||||
| typedef struct _NPSize | ||||
| { | ||||
|   int32_t width; | ||||
|   int32_t height; | ||||
| } NPSize; | ||||
|  | ||||
| typedef enum { | ||||
|   NPFocusNext = 0, | ||||
|   NPFocusPrevious = 1 | ||||
| } NPFocusDirection; | ||||
|  | ||||
| /* Return values for NPP_HandleEvent */ | ||||
| #define kNPEventNotHandled 0 | ||||
| #define kNPEventHandled 1 | ||||
| /* Exact meaning must be spec'd in event model. */ | ||||
| #define kNPEventStartIME 2 | ||||
|  | ||||
| #if defined(XP_UNIX) | ||||
| /* | ||||
|  * Unix specific structures and definitions | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Callback Structures. | ||||
|  * | ||||
|  * These are used to pass additional platform specific information. | ||||
|  */ | ||||
| enum { | ||||
|   NP_SETWINDOW = 1, | ||||
|   NP_PRINT | ||||
| }; | ||||
|  | ||||
| typedef struct | ||||
| { | ||||
|   int32_t type; | ||||
| } NPAnyCallbackStruct; | ||||
|  | ||||
| typedef struct | ||||
| { | ||||
|   int32_t      type; | ||||
| #if defined(MOZ_X11) | ||||
|   Display*     display; | ||||
|   Visual*      visual; | ||||
|   Colormap     colormap; | ||||
|   unsigned int depth; | ||||
| #endif | ||||
| } NPSetWindowCallbackStruct; | ||||
|  | ||||
| typedef struct | ||||
| { | ||||
|   int32_t type; | ||||
|   FILE* fp; | ||||
| } NPPrintCallbackStruct; | ||||
|  | ||||
| #endif /* XP_UNIX */ | ||||
|  | ||||
| #if defined(XP_MACOSX) | ||||
| typedef enum { | ||||
| #ifndef NP_NO_QUICKDRAW | ||||
|   NPDrawingModelQuickDraw = 0, | ||||
| #endif | ||||
|   NPDrawingModelCoreGraphics = 1, | ||||
|   NPDrawingModelOpenGL = 2, | ||||
|   NPDrawingModelCoreAnimation = 3, | ||||
|   NPDrawingModelInvalidatingCoreAnimation = 4 | ||||
| } NPDrawingModel; | ||||
|  | ||||
| typedef enum { | ||||
| #ifndef NP_NO_CARBON | ||||
|   NPEventModelCarbon = 0, | ||||
| #endif | ||||
|   NPEventModelCocoa = 1 | ||||
| } NPEventModel; | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  *   The following masks are applied on certain platforms to NPNV and | ||||
|  *   NPPV selectors that pass around pointers to COM interfaces. Newer | ||||
|  *   compilers on some platforms may generate vtables that are not | ||||
|  *   compatible with older compilers. To prevent older plugins from | ||||
|  *   not understanding a new browser's ABI, these masks change the | ||||
|  *   values of those selectors on those platforms. To remain backwards | ||||
|  *   compatible with different versions of the browser, plugins can | ||||
|  *   use these masks to dynamically determine and use the correct C++ | ||||
|  *   ABI that the browser is expecting. This does not apply to Windows | ||||
|  *   as Microsoft's COM ABI will likely not change. | ||||
|  */ | ||||
|  | ||||
| #define NP_ABI_GCC3_MASK  0x10000000 | ||||
| /* | ||||
|  *   gcc 3.x generated vtables on UNIX and OSX are incompatible with | ||||
|  *   previous compilers. | ||||
|  */ | ||||
| #if (defined(XP_UNIX) && defined(__GNUC__) && (__GNUC__ >= 3)) | ||||
| #define _NP_ABI_MIXIN_FOR_GCC3 NP_ABI_GCC3_MASK | ||||
| #else | ||||
| #define _NP_ABI_MIXIN_FOR_GCC3 0 | ||||
| #endif | ||||
|  | ||||
| #if defined(XP_MACOSX) | ||||
| #define NP_ABI_MACHO_MASK 0x01000000 | ||||
| #define _NP_ABI_MIXIN_FOR_MACHO NP_ABI_MACHO_MASK | ||||
| #else | ||||
| #define _NP_ABI_MIXIN_FOR_MACHO 0 | ||||
| #endif | ||||
|  | ||||
| #define NP_ABI_MASK (_NP_ABI_MIXIN_FOR_GCC3 | _NP_ABI_MIXIN_FOR_MACHO) | ||||
|  | ||||
| /* | ||||
|  * List of variable names for which NPP_GetValue shall be implemented | ||||
|  */ | ||||
| typedef enum { | ||||
|   NPPVpluginNameString = 1, | ||||
|   NPPVpluginDescriptionString, | ||||
|   NPPVpluginWindowBool, | ||||
|   NPPVpluginTransparentBool, | ||||
|   NPPVjavaClass, | ||||
|   NPPVpluginWindowSize, | ||||
|   NPPVpluginTimerInterval, | ||||
|   NPPVpluginScriptableInstance = (10 | NP_ABI_MASK), | ||||
|   NPPVpluginScriptableIID = 11, | ||||
|   NPPVjavascriptPushCallerBool = 12, | ||||
|   NPPVpluginKeepLibraryInMemory = 13, | ||||
|   NPPVpluginNeedsXEmbed         = 14, | ||||
|  | ||||
|   /* Get the NPObject for scripting the plugin. Introduced in NPAPI minor version 14. | ||||
|    */ | ||||
|   NPPVpluginScriptableNPObject  = 15, | ||||
|  | ||||
|   /* Get the plugin value (as \0-terminated UTF-8 string data) for | ||||
|    * form submission if the plugin is part of a form. Use | ||||
|    * NPN_MemAlloc() to allocate memory for the string data. Introduced | ||||
|    * in NPAPI minor version 15. | ||||
|    */ | ||||
|   NPPVformValue = 16, | ||||
|  | ||||
|   NPPVpluginUrlRequestsDisplayedBool = 17, | ||||
|  | ||||
|   /* Checks if the plugin is interested in receiving the http body of | ||||
|    * all http requests (including failed ones, http status != 200). | ||||
|    */ | ||||
|   NPPVpluginWantsAllNetworkStreams = 18, | ||||
|  | ||||
|   /* Browsers can retrieve a native ATK accessibility plug ID via this variable. */ | ||||
|   NPPVpluginNativeAccessibleAtkPlugId = 19, | ||||
|  | ||||
|   /* Checks to see if the plug-in would like the browser to load the "src" attribute. */ | ||||
|   NPPVpluginCancelSrcStream = 20, | ||||
|  | ||||
|   NPPVsupportsAdvancedKeyHandling = 21, | ||||
|  | ||||
|   NPPVpluginUsesDOMForCursorBool = 22 | ||||
|  | ||||
| #if defined(XP_MACOSX) | ||||
|   /* Used for negotiating drawing models */ | ||||
|   , NPPVpluginDrawingModel = 1000 | ||||
|   /* Used for negotiating event models */ | ||||
|   , NPPVpluginEventModel = 1001 | ||||
|   /* In the NPDrawingModelCoreAnimation drawing model, the browser asks the plug-in for a Core Animation layer. */ | ||||
|   , NPPVpluginCoreAnimationLayer = 1003 | ||||
| #endif | ||||
|  | ||||
| #if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6) | ||||
|   , NPPVpluginWindowlessLocalBool = 2002 | ||||
| #endif | ||||
| } NPPVariable; | ||||
|  | ||||
| /* | ||||
|  * List of variable names for which NPN_GetValue should be implemented. | ||||
|  */ | ||||
| typedef enum { | ||||
|   NPNVxDisplay = 1, | ||||
|   NPNVxtAppContext, | ||||
|   NPNVnetscapeWindow, | ||||
|   NPNVjavascriptEnabledBool, | ||||
|   NPNVasdEnabledBool, | ||||
|   NPNVisOfflineBool, | ||||
|  | ||||
|   NPNVserviceManager = (10 | NP_ABI_MASK), | ||||
|   NPNVDOMElement     = (11 | NP_ABI_MASK), | ||||
|   NPNVDOMWindow      = (12 | NP_ABI_MASK), | ||||
|   NPNVToolkit        = (13 | NP_ABI_MASK), | ||||
|   NPNVSupportsXEmbedBool = 14, | ||||
|  | ||||
|   /* Get the NPObject wrapper for the browser window. */ | ||||
|   NPNVWindowNPObject = 15, | ||||
|  | ||||
|   /* Get the NPObject wrapper for the plugins DOM element. */ | ||||
|   NPNVPluginElementNPObject = 16, | ||||
|  | ||||
|   NPNVSupportsWindowless = 17, | ||||
|  | ||||
|   NPNVprivateModeBool = 18, | ||||
|  | ||||
|   NPNVsupportsAdvancedKeyHandling = 21 | ||||
|  | ||||
| #if defined(XP_MACOSX) | ||||
|   /* Used for negotiating drawing models */ | ||||
|   , NPNVpluginDrawingModel = 1000 | ||||
| #ifndef NP_NO_QUICKDRAW | ||||
|   , NPNVsupportsQuickDrawBool = 2000 | ||||
| #endif | ||||
|   , NPNVsupportsCoreGraphicsBool = 2001 | ||||
|   , NPNVsupportsOpenGLBool = 2002 | ||||
|   , NPNVsupportsCoreAnimationBool = 2003 | ||||
|   , NPNVsupportsInvalidatingCoreAnimationBool = 2004 | ||||
| #ifndef NP_NO_CARBON | ||||
|   , NPNVsupportsCarbonBool = 3000 /* TRUE if the browser supports the Carbon event model */ | ||||
| #endif | ||||
|   , NPNVsupportsCocoaBool = 3001 /* TRUE if the browser supports the Cocoa event model */ | ||||
|   , NPNVsupportsUpdatedCocoaTextInputBool = 3002 /* TRUE if the browser supports the updated | ||||
|                                                     Cocoa text input specification. */ | ||||
|   , NPNVsupportsCompositingCoreAnimationPluginsBool = 74656 /* TRUE if the browser supports | ||||
|                                                                CA model compositing */ | ||||
| #endif | ||||
| #if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6) | ||||
|   , NPNVSupportsWindowlessLocal = 2002 | ||||
| #endif | ||||
| } NPNVariable; | ||||
|  | ||||
| typedef enum { | ||||
|   NPNURLVCookie = 501, | ||||
|   NPNURLVProxy | ||||
| } NPNURLVariable; | ||||
|  | ||||
| /* | ||||
|  * The type of Toolkit the widgets use | ||||
|  */ | ||||
| typedef enum { | ||||
|   NPNVGtk12 = 1, | ||||
|   NPNVGtk2 | ||||
| } NPNToolkitType; | ||||
|  | ||||
| /* | ||||
|  * The type of a NPWindow - it specifies the type of the data structure | ||||
|  * returned in the window field. | ||||
|  */ | ||||
| typedef enum { | ||||
|   NPWindowTypeWindow = 1, | ||||
|   NPWindowTypeDrawable | ||||
| } NPWindowType; | ||||
|  | ||||
| typedef struct _NPWindow | ||||
| { | ||||
|   void* window;  /* Platform specific window handle */ | ||||
|                  /* OS/2: x - Position of bottom left corner */ | ||||
|                  /* OS/2: y - relative to visible netscape window */ | ||||
|   int32_t  x;      /* Position of top left corner relative */ | ||||
|   int32_t  y;      /* to a netscape page. */ | ||||
|   uint32_t width;  /* Maximum window size */ | ||||
|   uint32_t height; | ||||
|   NPRect   clipRect; /* Clipping rectangle in port coordinates */ | ||||
| #if (defined(XP_UNIX) || defined(XP_SYMBIAN)) && !defined(XP_MACOSX) | ||||
|   void * ws_info; /* Platform-dependent additional data */ | ||||
| #endif /* XP_UNIX */ | ||||
|   NPWindowType type; /* Is this a window or a drawable? */ | ||||
| } NPWindow; | ||||
|  | ||||
| typedef struct _NPImageExpose | ||||
| { | ||||
|   char*    data;       /* image pointer */ | ||||
|   int32_t  stride;     /* Stride of data image pointer */ | ||||
|   int32_t  depth;      /* Depth of image pointer */ | ||||
|   int32_t  x;          /* Expose x */ | ||||
|   int32_t  y;          /* Expose y */ | ||||
|   uint32_t width;      /* Expose width */ | ||||
|   uint32_t height;     /* Expose height */ | ||||
|   NPSize   dataSize;   /* Data buffer size */ | ||||
|   float    translateX; /* translate X matrix value */ | ||||
|   float    translateY; /* translate Y matrix value */ | ||||
|   float    scaleX;     /* scale X matrix value */ | ||||
|   float    scaleY;     /* scale Y matrix value */ | ||||
| } NPImageExpose; | ||||
|  | ||||
| typedef struct _NPFullPrint | ||||
| { | ||||
|   NPBool pluginPrinted;/* Set TRUE if plugin handled fullscreen printing */ | ||||
|   NPBool printOne;     /* TRUE if plugin should print one copy to default | ||||
|                           printer */ | ||||
|   void* platformPrint; /* Platform-specific printing info */ | ||||
| } NPFullPrint; | ||||
|  | ||||
| typedef struct _NPEmbedPrint | ||||
| { | ||||
|   NPWindow window; | ||||
|   void* platformPrint; /* Platform-specific printing info */ | ||||
| } NPEmbedPrint; | ||||
|  | ||||
| typedef struct _NPPrint | ||||
| { | ||||
|   uint16_t mode;               /* NP_FULL or NP_EMBED */ | ||||
|   union | ||||
|   { | ||||
|     NPFullPrint fullPrint;   /* if mode is NP_FULL */ | ||||
|     NPEmbedPrint embedPrint; /* if mode is NP_EMBED */ | ||||
|   } print; | ||||
| } NPPrint; | ||||
|  | ||||
| #if defined(XP_MACOSX) | ||||
| #ifndef NP_NO_CARBON | ||||
| typedef EventRecord NPEvent; | ||||
| #endif | ||||
| #elif defined(XP_SYMBIAN) | ||||
| typedef QEvent NPEvent; | ||||
| #elif defined(XP_WIN) | ||||
| typedef struct _NPEvent | ||||
| { | ||||
|   uint16_t event; | ||||
|   uintptr_t wParam; | ||||
|   uintptr_t lParam; | ||||
| } NPEvent; | ||||
| #elif defined(XP_OS2) | ||||
| typedef struct _NPEvent | ||||
| { | ||||
|   uint32_t event; | ||||
|   uint32_t wParam; | ||||
|   uint32_t lParam; | ||||
| } NPEvent; | ||||
| #elif defined(XP_UNIX) && defined(MOZ_X11) | ||||
| typedef XEvent NPEvent; | ||||
| #else | ||||
| typedef void*  NPEvent; | ||||
| #endif | ||||
|  | ||||
| #if defined(XP_MACOSX) | ||||
| typedef void* NPRegion; | ||||
| #ifndef NP_NO_QUICKDRAW | ||||
| typedef RgnHandle NPQDRegion; | ||||
| #endif | ||||
| typedef CGPathRef NPCGRegion; | ||||
| #elif defined(XP_WIN) | ||||
| typedef HRGN NPRegion; | ||||
| #elif defined(XP_UNIX) && defined(MOZ_X11) | ||||
| typedef Region NPRegion; | ||||
| #elif defined(XP_SYMBIAN) | ||||
| typedef QRegion* NPRegion; | ||||
| #else | ||||
| typedef void *NPRegion; | ||||
| #endif | ||||
|  | ||||
| typedef struct _NPNSString NPNSString; | ||||
| typedef struct _NPNSWindow NPNSWindow; | ||||
| typedef struct _NPNSMenu   NPNSMenu; | ||||
|  | ||||
| #if defined(XP_MACOSX) | ||||
| typedef NPNSMenu NPMenu; | ||||
| #else | ||||
| typedef void *NPMenu; | ||||
| #endif | ||||
|  | ||||
| typedef enum { | ||||
|   NPCoordinateSpacePlugin = 1, | ||||
|   NPCoordinateSpaceWindow, | ||||
|   NPCoordinateSpaceFlippedWindow, | ||||
|   NPCoordinateSpaceScreen, | ||||
|   NPCoordinateSpaceFlippedScreen | ||||
| } NPCoordinateSpace; | ||||
|  | ||||
| #if defined(XP_MACOSX) | ||||
|  | ||||
| #ifndef NP_NO_QUICKDRAW | ||||
| typedef struct NP_Port | ||||
| { | ||||
|   CGrafPtr port; | ||||
|   int32_t portx; /* position inside the topmost window */ | ||||
|   int32_t porty; | ||||
| } NP_Port; | ||||
| #endif /* NP_NO_QUICKDRAW */ | ||||
|  | ||||
| /* | ||||
|  * NP_CGContext is the type of the NPWindow's 'window' when the plugin specifies NPDrawingModelCoreGraphics | ||||
|  * as its drawing model. | ||||
|  */ | ||||
|  | ||||
| typedef struct NP_CGContext | ||||
| { | ||||
|   CGContextRef context; | ||||
|   void *window; /* A WindowRef under the Carbon event model. */ | ||||
| } NP_CGContext; | ||||
|  | ||||
| /* | ||||
|  * NP_GLContext is the type of the NPWindow's 'window' when the plugin specifies NPDrawingModelOpenGL as its | ||||
|  * drawing model. | ||||
|  */ | ||||
|  | ||||
| typedef struct NP_GLContext | ||||
| { | ||||
|   CGLContextObj context; | ||||
| #ifdef NP_NO_CARBON | ||||
|   NPNSWindow *window; | ||||
| #else | ||||
|   void *window; /* Can be either an NSWindow or a WindowRef depending on the event model */ | ||||
| #endif | ||||
| } NP_GLContext; | ||||
|  | ||||
| typedef enum { | ||||
|   NPCocoaEventDrawRect = 1, | ||||
|   NPCocoaEventMouseDown, | ||||
|   NPCocoaEventMouseUp, | ||||
|   NPCocoaEventMouseMoved, | ||||
|   NPCocoaEventMouseEntered, | ||||
|   NPCocoaEventMouseExited, | ||||
|   NPCocoaEventMouseDragged, | ||||
|   NPCocoaEventKeyDown, | ||||
|   NPCocoaEventKeyUp, | ||||
|   NPCocoaEventFlagsChanged, | ||||
|   NPCocoaEventFocusChanged, | ||||
|   NPCocoaEventWindowFocusChanged, | ||||
|   NPCocoaEventScrollWheel, | ||||
|   NPCocoaEventTextInput | ||||
| } NPCocoaEventType; | ||||
|  | ||||
| typedef struct _NPCocoaEvent { | ||||
|   NPCocoaEventType type; | ||||
|   uint32_t version; | ||||
|   union { | ||||
|     struct { | ||||
|       uint32_t modifierFlags; | ||||
|       double   pluginX; | ||||
|       double   pluginY; | ||||
|       int32_t  buttonNumber; | ||||
|       int32_t  clickCount; | ||||
|       double   deltaX; | ||||
|       double   deltaY; | ||||
|       double   deltaZ; | ||||
|     } mouse; | ||||
|     struct { | ||||
|       uint32_t    modifierFlags; | ||||
|       NPNSString *characters; | ||||
|       NPNSString *charactersIgnoringModifiers; | ||||
|       NPBool      isARepeat; | ||||
|       uint16_t    keyCode; | ||||
|     } key; | ||||
|     struct { | ||||
|       CGContextRef context; | ||||
|       double x; | ||||
|       double y; | ||||
|       double width; | ||||
|       double height; | ||||
|     } draw; | ||||
|     struct { | ||||
|       NPBool hasFocus; | ||||
|     } focus; | ||||
|     struct { | ||||
|       NPNSString *text; | ||||
|     } text; | ||||
|   } data; | ||||
| } NPCocoaEvent; | ||||
|  | ||||
| #ifndef NP_NO_CARBON | ||||
| /* Non-standard event types that can be passed to HandleEvent */ | ||||
| enum NPEventType { | ||||
|   NPEventType_GetFocusEvent = (osEvt + 16), | ||||
|   NPEventType_LoseFocusEvent, | ||||
|   NPEventType_AdjustCursorEvent, | ||||
|   NPEventType_MenuCommandEvent, | ||||
|   NPEventType_ClippingChangedEvent, | ||||
|   NPEventType_ScrollingBeginsEvent = 1000, | ||||
|   NPEventType_ScrollingEndsEvent | ||||
| }; | ||||
| #endif /* NP_NO_CARBON */ | ||||
|  | ||||
| #endif /* XP_MACOSX */ | ||||
|  | ||||
| /* | ||||
|  * Values for mode passed to NPP_New: | ||||
|  */ | ||||
| #define NP_EMBED 1 | ||||
| #define NP_FULL  2 | ||||
|  | ||||
| /* | ||||
|  * Values for stream type passed to NPP_NewStream: | ||||
|  */ | ||||
| #define NP_NORMAL     1 | ||||
| #define NP_SEEK       2 | ||||
| #define NP_ASFILE     3 | ||||
| #define NP_ASFILEONLY 4 | ||||
|  | ||||
| #define NP_MAXREADY (((unsigned)(~0)<<1)>>1) | ||||
|  | ||||
| /* | ||||
|  * Flags for NPP_ClearSiteData. | ||||
|  */ | ||||
| #define NP_CLEAR_ALL   0 | ||||
| #define NP_CLEAR_CACHE (1 << 0) | ||||
|  | ||||
| #if !defined(__LP64__) | ||||
| #if defined(XP_MACOSX) | ||||
| #pragma options align=reset | ||||
| #endif | ||||
| #endif /* __LP64__ */ | ||||
|  | ||||
| /*----------------------------------------------------------------------*/ | ||||
| /*       Error and Reason Code definitions                              */ | ||||
| /*----------------------------------------------------------------------*/ | ||||
|  | ||||
| /* | ||||
|  * Values of type NPError: | ||||
|  */ | ||||
| #define NPERR_BASE                         0 | ||||
| #define NPERR_NO_ERROR                    (NPERR_BASE + 0) | ||||
| #define NPERR_GENERIC_ERROR               (NPERR_BASE + 1) | ||||
| #define NPERR_INVALID_INSTANCE_ERROR      (NPERR_BASE + 2) | ||||
| #define NPERR_INVALID_FUNCTABLE_ERROR     (NPERR_BASE + 3) | ||||
| #define NPERR_MODULE_LOAD_FAILED_ERROR    (NPERR_BASE + 4) | ||||
| #define NPERR_OUT_OF_MEMORY_ERROR         (NPERR_BASE + 5) | ||||
| #define NPERR_INVALID_PLUGIN_ERROR        (NPERR_BASE + 6) | ||||
| #define NPERR_INVALID_PLUGIN_DIR_ERROR    (NPERR_BASE + 7) | ||||
| #define NPERR_INCOMPATIBLE_VERSION_ERROR  (NPERR_BASE + 8) | ||||
| #define NPERR_INVALID_PARAM               (NPERR_BASE + 9) | ||||
| #define NPERR_INVALID_URL                 (NPERR_BASE + 10) | ||||
| #define NPERR_FILE_NOT_FOUND              (NPERR_BASE + 11) | ||||
| #define NPERR_NO_DATA                     (NPERR_BASE + 12) | ||||
| #define NPERR_STREAM_NOT_SEEKABLE         (NPERR_BASE + 13) | ||||
| #define NPERR_TIME_RANGE_NOT_SUPPORTED    (NPERR_BASE + 14) | ||||
| #define NPERR_MALFORMED_SITE              (NPERR_BASE + 15) | ||||
|  | ||||
| /* | ||||
|  * Values of type NPReason: | ||||
|  */ | ||||
| #define NPRES_BASE          0 | ||||
| #define NPRES_DONE         (NPRES_BASE + 0) | ||||
| #define NPRES_NETWORK_ERR  (NPRES_BASE + 1) | ||||
| #define NPRES_USER_BREAK   (NPRES_BASE + 2) | ||||
|  | ||||
| /* | ||||
|  * Don't use these obsolete error codes any more. | ||||
|  */ | ||||
| #define NP_NOERR  NP_NOERR_is_obsolete_use_NPERR_NO_ERROR | ||||
| #define NP_EINVAL NP_EINVAL_is_obsolete_use_NPERR_GENERIC_ERROR | ||||
| #define NP_EABORT NP_EABORT_is_obsolete_use_NPRES_USER_BREAK | ||||
|  | ||||
| /* | ||||
|  * Version feature information | ||||
|  */ | ||||
| #define NPVERS_HAS_STREAMOUTPUT             8 | ||||
| #define NPVERS_HAS_NOTIFICATION             9 | ||||
| #define NPVERS_HAS_LIVECONNECT              9 | ||||
| #define NPVERS_68K_HAS_LIVECONNECT          11 | ||||
| #define NPVERS_HAS_WINDOWLESS               11 | ||||
| #define NPVERS_HAS_XPCONNECT_SCRIPTING      13 | ||||
| #define NPVERS_HAS_NPRUNTIME_SCRIPTING      14 | ||||
| #define NPVERS_HAS_FORM_VALUES              15 | ||||
| #define NPVERS_HAS_POPUPS_ENABLED_STATE     16 | ||||
| #define NPVERS_HAS_RESPONSE_HEADERS         17 | ||||
| #define NPVERS_HAS_NPOBJECT_ENUM            18 | ||||
| #define NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL 19 | ||||
| #define NPVERS_HAS_ALL_NETWORK_STREAMS      20 | ||||
| #define NPVERS_HAS_URL_AND_AUTH_INFO        21 | ||||
| #define NPVERS_HAS_PRIVATE_MODE             22 | ||||
| #define NPVERS_MACOSX_HAS_COCOA_EVENTS      23 | ||||
| #define NPVERS_HAS_ADVANCED_KEY_HANDLING    25 | ||||
| #define NPVERS_HAS_URL_REDIRECT_HANDLING    26 | ||||
| #define NPVERS_HAS_CLEAR_SITE_DATA          27 | ||||
|  | ||||
| /*----------------------------------------------------------------------*/ | ||||
| /*                        Function Prototypes                           */ | ||||
| /*----------------------------------------------------------------------*/ | ||||
|  | ||||
| #if defined(__OS2__) | ||||
| #define NP_LOADDS _System | ||||
| #else | ||||
| #define NP_LOADDS | ||||
| #endif | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| /* NPP_* functions are provided by the plugin and called by the navigator. */ | ||||
|  | ||||
| #if defined(XP_UNIX) | ||||
| const char* NPP_GetMIMEDescription(void); | ||||
| #endif | ||||
|  | ||||
| NPError NP_LOADDS NPP_New(NPMIMEType pluginType, NPP instance, | ||||
|                           uint16_t mode, int16_t argc, char* argn[], | ||||
|                           char* argv[], NPSavedData* saved); | ||||
| NPError NP_LOADDS NPP_Destroy(NPP instance, NPSavedData** save); | ||||
| NPError NP_LOADDS NPP_SetWindow(NPP instance, NPWindow* window); | ||||
| NPError NP_LOADDS NPP_NewStream(NPP instance, NPMIMEType type, | ||||
|                                 NPStream* stream, NPBool seekable, | ||||
|                                 uint16_t* stype); | ||||
| NPError NP_LOADDS NPP_DestroyStream(NPP instance, NPStream* stream, | ||||
|                                     NPReason reason); | ||||
| int32_t NP_LOADDS NPP_WriteReady(NPP instance, NPStream* stream); | ||||
| int32_t NP_LOADDS NPP_Write(NPP instance, NPStream* stream, int32_t offset, | ||||
|                             int32_t len, void* buffer); | ||||
| void    NP_LOADDS NPP_StreamAsFile(NPP instance, NPStream* stream, | ||||
|                                    const char* fname); | ||||
| void    NP_LOADDS NPP_Print(NPP instance, NPPrint* platformPrint); | ||||
| int16_t NP_LOADDS NPP_HandleEvent(NPP instance, void* event); | ||||
| void    NP_LOADDS NPP_URLNotify(NPP instance, const char* url, | ||||
|                                 NPReason reason, void* notifyData); | ||||
| NPError NP_LOADDS NPP_GetValue(NPP instance, NPPVariable variable, void *value); | ||||
| NPError NP_LOADDS NPP_SetValue(NPP instance, NPNVariable variable, void *value); | ||||
| NPBool  NP_LOADDS NPP_GotFocus(NPP instance, NPFocusDirection direction); | ||||
| void    NP_LOADDS NPP_LostFocus(NPP instance); | ||||
| void    NP_LOADDS NPP_URLRedirectNotify(NPP instance, const char* url, int32_t status, void* notifyData); | ||||
| NPError NP_LOADDS NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge); | ||||
| char**  NP_LOADDS NPP_GetSitesWithData(void); | ||||
|  | ||||
| /* NPN_* functions are provided by the navigator and called by the plugin. */ | ||||
| void        NP_LOADDS NPN_Version(int* plugin_major, int* plugin_minor, | ||||
|                                   int* netscape_major, int* netscape_minor); | ||||
| NPError     NP_LOADDS NPN_GetURLNotify(NPP instance, const char* url, | ||||
|                                        const char* target, void* notifyData); | ||||
| NPError     NP_LOADDS NPN_GetURL(NPP instance, const char* url, | ||||
|                                  const char* target); | ||||
| NPError     NP_LOADDS NPN_PostURLNotify(NPP instance, const char* url, | ||||
|                                         const char* target, uint32_t len, | ||||
|                                         const char* buf, NPBool file, | ||||
|                                         void* notifyData); | ||||
| NPError     NP_LOADDS NPN_PostURL(NPP instance, const char* url, | ||||
|                                   const char* target, uint32_t len, | ||||
|                                   const char* buf, NPBool file); | ||||
| NPError     NP_LOADDS NPN_RequestRead(NPStream* stream, NPByteRange* rangeList); | ||||
| NPError     NP_LOADDS NPN_NewStream(NPP instance, NPMIMEType type, | ||||
|                                     const char* target, NPStream** stream); | ||||
| int32_t     NP_LOADDS NPN_Write(NPP instance, NPStream* stream, int32_t len, | ||||
|                                 void* buffer); | ||||
| NPError     NP_LOADDS NPN_DestroyStream(NPP instance, NPStream* stream, | ||||
|                                         NPReason reason); | ||||
| void        NP_LOADDS NPN_Status(NPP instance, const char* message); | ||||
| const char* NP_LOADDS NPN_UserAgent(NPP instance); | ||||
| void*       NP_LOADDS NPN_MemAlloc(uint32_t size); | ||||
| void        NP_LOADDS NPN_MemFree(void* ptr); | ||||
| uint32_t    NP_LOADDS NPN_MemFlush(uint32_t size); | ||||
| void        NP_LOADDS NPN_ReloadPlugins(NPBool reloadPages); | ||||
| NPError     NP_LOADDS NPN_GetValue(NPP instance, NPNVariable variable, | ||||
|                                    void *value); | ||||
| NPError     NP_LOADDS NPN_SetValue(NPP instance, NPPVariable variable, | ||||
|                                    void *value); | ||||
| void        NP_LOADDS NPN_InvalidateRect(NPP instance, NPRect *invalidRect); | ||||
| void        NP_LOADDS NPN_InvalidateRegion(NPP instance, | ||||
|                                            NPRegion invalidRegion); | ||||
| void        NP_LOADDS NPN_ForceRedraw(NPP instance); | ||||
| void        NP_LOADDS NPN_PushPopupsEnabledState(NPP instance, NPBool enabled); | ||||
| void        NP_LOADDS NPN_PopPopupsEnabledState(NPP instance); | ||||
| void        NP_LOADDS NPN_PluginThreadAsyncCall(NPP instance, | ||||
|                                                 void (*func) (void *), | ||||
|                                                 void *userData); | ||||
| NPError     NP_LOADDS NPN_GetValueForURL(NPP instance, NPNURLVariable variable, | ||||
|                                          const char *url, char **value, | ||||
|                                          uint32_t *len); | ||||
| NPError     NP_LOADDS NPN_SetValueForURL(NPP instance, NPNURLVariable variable, | ||||
|                                          const char *url, const char *value, | ||||
|                                          uint32_t len); | ||||
| NPError     NP_LOADDS NPN_GetAuthenticationInfo(NPP instance, | ||||
|                                                 const char *protocol, | ||||
|                                                 const char *host, int32_t port, | ||||
|                                                 const char *scheme, | ||||
|                                                 const char *realm, | ||||
|                                                 char **username, uint32_t *ulen, | ||||
|                                                 char **password, | ||||
|                                                 uint32_t *plen); | ||||
| uint32_t    NP_LOADDS NPN_ScheduleTimer(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID)); | ||||
| void        NP_LOADDS NPN_UnscheduleTimer(NPP instance, uint32_t timerID); | ||||
| NPError     NP_LOADDS NPN_PopUpContextMenu(NPP instance, NPMenu* menu); | ||||
| NPBool      NP_LOADDS NPN_ConvertPoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace); | ||||
| NPBool      NP_LOADDS NPN_HandleEvent(NPP instance, void *event, NPBool handled); | ||||
| NPBool      NP_LOADDS NPN_UnfocusInstance(NPP instance, NPFocusDirection direction); | ||||
| void        NP_LOADDS NPN_URLRedirectResponse(NPP instance, void* notifyData, NPBool allow); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| }  /* end extern "C" */ | ||||
| #endif | ||||
|  | ||||
| #endif /* RC_INVOKED */ | ||||
| #if defined(__OS2__) | ||||
| #pragma pack() | ||||
| #endif | ||||
|  | ||||
| #endif /* npapi_h_ */ | ||||
| @@ -1,322 +0,0 @@ | ||||
| /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | ||||
| /* ***** BEGIN LICENSE BLOCK ***** | ||||
|  * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | ||||
|  * | ||||
|  * The contents of this file are subject to the Mozilla Public License Version | ||||
|  * 1.1 (the "License"); you may not use this file except in compliance with | ||||
|  * the License. You may obtain a copy of the License at | ||||
|  * http://www.mozilla.org/MPL/ | ||||
|  * | ||||
|  * Software distributed under the License is distributed on an "AS IS" basis, | ||||
|  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | ||||
|  * for the specific language governing rights and limitations under the | ||||
|  * License. | ||||
|  * | ||||
|  * The Original Code is mozilla.org code. | ||||
|  * | ||||
|  * The Initial Developer of the Original Code is | ||||
|  * Netscape Communications Corporation. | ||||
|  * Portions created by the Initial Developer are Copyright (C) 1998 | ||||
|  * the Initial Developer. All Rights Reserved. | ||||
|  * | ||||
|  * Contributor(s): | ||||
|  * | ||||
|  * Alternatively, the contents of this file may be used under the terms of | ||||
|  * either the GNU General Public License Version 2 or later (the "GPL"), or | ||||
|  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), | ||||
|  * in which case the provisions of the GPL or the LGPL are applicable instead | ||||
|  * of those above. If you wish to allow use of your version of this file only | ||||
|  * under the terms of either the GPL or the LGPL, and not to allow others to | ||||
|  * use your version of this file under the terms of the MPL, indicate your | ||||
|  * decision by deleting the provisions above and replace them with the notice | ||||
|  * and other provisions required by the GPL or the LGPL. If you do not delete | ||||
|  * the provisions above, a recipient may use your version of this file under | ||||
|  * the terms of any one of the MPL, the GPL or the LGPL. | ||||
|  * | ||||
|  * ***** END LICENSE BLOCK ***** */ | ||||
|  | ||||
| #ifndef npfunctions_h_ | ||||
| #define npfunctions_h_ | ||||
|  | ||||
| #ifdef __OS2__ | ||||
| #pragma pack(1) | ||||
| #define NP_LOADDS _System | ||||
| #else | ||||
| #define NP_LOADDS | ||||
| #endif | ||||
|  | ||||
| #include "npapi.h" | ||||
| #include "npruntime.h" | ||||
|  | ||||
| typedef NPError      (* NP_LOADDS NPP_NewProcPtr)(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved); | ||||
| typedef NPError      (* NP_LOADDS NPP_DestroyProcPtr)(NPP instance, NPSavedData** save); | ||||
| typedef NPError      (* NP_LOADDS NPP_SetWindowProcPtr)(NPP instance, NPWindow* window); | ||||
| typedef NPError      (* NP_LOADDS NPP_NewStreamProcPtr)(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype); | ||||
| typedef NPError      (* NP_LOADDS NPP_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason); | ||||
| typedef int32_t      (* NP_LOADDS NPP_WriteReadyProcPtr)(NPP instance, NPStream* stream); | ||||
| typedef int32_t      (* NP_LOADDS NPP_WriteProcPtr)(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer); | ||||
| typedef void         (* NP_LOADDS NPP_StreamAsFileProcPtr)(NPP instance, NPStream* stream, const char* fname); | ||||
| typedef void         (* NP_LOADDS NPP_PrintProcPtr)(NPP instance, NPPrint* platformPrint); | ||||
| typedef int16_t      (* NP_LOADDS NPP_HandleEventProcPtr)(NPP instance, void* event); | ||||
| typedef void         (* NP_LOADDS NPP_URLNotifyProcPtr)(NPP instance, const char* url, NPReason reason, void* notifyData); | ||||
| /* Any NPObjects returned to the browser via NPP_GetValue should be retained | ||||
|    by the plugin on the way out. The browser is responsible for releasing. */ | ||||
| typedef NPError      (* NP_LOADDS NPP_GetValueProcPtr)(NPP instance, NPPVariable variable, void *ret_value); | ||||
| typedef NPError      (* NP_LOADDS NPP_SetValueProcPtr)(NPP instance, NPNVariable variable, void *value); | ||||
| typedef NPBool       (* NP_LOADDS NPP_GotFocusPtr)(NPP instance, NPFocusDirection direction); | ||||
| typedef void         (* NP_LOADDS NPP_LostFocusPtr)(NPP instance); | ||||
| typedef void         (* NP_LOADDS NPP_URLRedirectNotifyPtr)(NPP instance, const char* url, int32_t status, void* notifyData); | ||||
| typedef NPError      (* NP_LOADDS NPP_ClearSiteDataPtr)(const char* site, uint64_t flags, uint64_t maxAge); | ||||
| typedef char**       (* NP_LOADDS NPP_GetSitesWithDataPtr)(void); | ||||
|  | ||||
| typedef NPError      (*NPN_GetValueProcPtr)(NPP instance, NPNVariable variable, void *ret_value); | ||||
| typedef NPError      (*NPN_SetValueProcPtr)(NPP instance, NPPVariable variable, void *value); | ||||
| typedef NPError      (*NPN_GetURLNotifyProcPtr)(NPP instance, const char* url, const char* window, void* notifyData); | ||||
| typedef NPError      (*NPN_PostURLNotifyProcPtr)(NPP instance, const char* url, const char* window, uint32_t len, const char* buf, NPBool file, void* notifyData); | ||||
| typedef NPError      (*NPN_GetURLProcPtr)(NPP instance, const char* url, const char* window); | ||||
| typedef NPError      (*NPN_PostURLProcPtr)(NPP instance, const char* url, const char* window, uint32_t len, const char* buf, NPBool file); | ||||
| typedef NPError      (*NPN_RequestReadProcPtr)(NPStream* stream, NPByteRange* rangeList); | ||||
| typedef NPError      (*NPN_NewStreamProcPtr)(NPP instance, NPMIMEType type, const char* window, NPStream** stream); | ||||
| typedef int32_t      (*NPN_WriteProcPtr)(NPP instance, NPStream* stream, int32_t len, void* buffer); | ||||
| typedef NPError      (*NPN_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason); | ||||
| typedef void         (*NPN_StatusProcPtr)(NPP instance, const char* message); | ||||
| /* Browser manages the lifetime of the buffer returned by NPN_UserAgent, don't | ||||
|    depend on it sticking around and don't free it. */ | ||||
| typedef const char*  (*NPN_UserAgentProcPtr)(NPP instance); | ||||
| typedef void*        (*NPN_MemAllocProcPtr)(uint32_t size); | ||||
| typedef void         (*NPN_MemFreeProcPtr)(void* ptr); | ||||
| typedef uint32_t     (*NPN_MemFlushProcPtr)(uint32_t size); | ||||
| typedef void         (*NPN_ReloadPluginsProcPtr)(NPBool reloadPages); | ||||
| typedef void*        (*NPN_GetJavaEnvProcPtr)(void); | ||||
| typedef void*        (*NPN_GetJavaPeerProcPtr)(NPP instance); | ||||
| typedef void         (*NPN_InvalidateRectProcPtr)(NPP instance, NPRect *rect); | ||||
| typedef void         (*NPN_InvalidateRegionProcPtr)(NPP instance, NPRegion region); | ||||
| typedef void         (*NPN_ForceRedrawProcPtr)(NPP instance); | ||||
| typedef NPIdentifier (*NPN_GetStringIdentifierProcPtr)(const NPUTF8* name); | ||||
| typedef void         (*NPN_GetStringIdentifiersProcPtr)(const NPUTF8** names, int32_t nameCount, NPIdentifier* identifiers); | ||||
| typedef NPIdentifier (*NPN_GetIntIdentifierProcPtr)(int32_t intid); | ||||
| typedef bool         (*NPN_IdentifierIsStringProcPtr)(NPIdentifier identifier); | ||||
| typedef NPUTF8*      (*NPN_UTF8FromIdentifierProcPtr)(NPIdentifier identifier); | ||||
| typedef int32_t      (*NPN_IntFromIdentifierProcPtr)(NPIdentifier identifier); | ||||
| typedef NPObject*    (*NPN_CreateObjectProcPtr)(NPP npp, NPClass *aClass); | ||||
| typedef NPObject*    (*NPN_RetainObjectProcPtr)(NPObject *obj); | ||||
| typedef void         (*NPN_ReleaseObjectProcPtr)(NPObject *obj); | ||||
| typedef bool         (*NPN_InvokeProcPtr)(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result); | ||||
| typedef bool         (*NPN_InvokeDefaultProcPtr)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result); | ||||
| typedef bool         (*NPN_EvaluateProcPtr)(NPP npp, NPObject *obj, NPString *script, NPVariant *result); | ||||
| typedef bool         (*NPN_GetPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result); | ||||
| typedef bool         (*NPN_SetPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value); | ||||
| typedef bool         (*NPN_RemovePropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName); | ||||
| typedef bool         (*NPN_HasPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName); | ||||
| typedef bool         (*NPN_HasMethodProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName); | ||||
| typedef void         (*NPN_ReleaseVariantValueProcPtr)(NPVariant *variant); | ||||
| typedef void         (*NPN_SetExceptionProcPtr)(NPObject *obj, const NPUTF8 *message); | ||||
| typedef void         (*NPN_PushPopupsEnabledStateProcPtr)(NPP npp, NPBool enabled); | ||||
| typedef void         (*NPN_PopPopupsEnabledStateProcPtr)(NPP npp); | ||||
| typedef bool         (*NPN_EnumerateProcPtr)(NPP npp, NPObject *obj, NPIdentifier **identifier, uint32_t *count); | ||||
| typedef void         (*NPN_PluginThreadAsyncCallProcPtr)(NPP instance, void (*func)(void *), void *userData); | ||||
| typedef bool         (*NPN_ConstructProcPtr)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result); | ||||
| typedef NPError      (*NPN_GetValueForURLPtr)(NPP npp, NPNURLVariable variable, const char *url, char **value, uint32_t *len); | ||||
| typedef NPError      (*NPN_SetValueForURLPtr)(NPP npp, NPNURLVariable variable, const char *url, const char *value, uint32_t len); | ||||
| typedef NPError      (*NPN_GetAuthenticationInfoPtr)(NPP npp, const char *protocol, const char *host, int32_t port, const char *scheme, const char *realm, char **username, uint32_t *ulen, char **password, uint32_t *plen); | ||||
| typedef uint32_t     (*NPN_ScheduleTimerPtr)(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID)); | ||||
| typedef void         (*NPN_UnscheduleTimerPtr)(NPP instance, uint32_t timerID); | ||||
| typedef NPError      (*NPN_PopUpContextMenuPtr)(NPP instance, NPMenu* menu); | ||||
| typedef NPBool       (*NPN_ConvertPointPtr)(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace); | ||||
| typedef NPBool       (*NPN_HandleEventPtr)(NPP instance, void *event, NPBool handled); | ||||
| typedef NPBool       (*NPN_UnfocusInstancePtr)(NPP instance, NPFocusDirection direction); | ||||
| typedef void         (*NPN_URLRedirectResponsePtr)(NPP instance, void* notifyData, NPBool allow); | ||||
|  | ||||
| typedef struct _NPPluginFuncs { | ||||
|   uint16_t size; | ||||
|   uint16_t version; | ||||
|   NPP_NewProcPtr newp; | ||||
|   NPP_DestroyProcPtr destroy; | ||||
|   NPP_SetWindowProcPtr setwindow; | ||||
|   NPP_NewStreamProcPtr newstream; | ||||
|   NPP_DestroyStreamProcPtr destroystream; | ||||
|   NPP_StreamAsFileProcPtr asfile; | ||||
|   NPP_WriteReadyProcPtr writeready; | ||||
|   NPP_WriteProcPtr write; | ||||
|   NPP_PrintProcPtr print; | ||||
|   NPP_HandleEventProcPtr event; | ||||
|   NPP_URLNotifyProcPtr urlnotify; | ||||
|   void* javaClass; | ||||
|   NPP_GetValueProcPtr getvalue; | ||||
|   NPP_SetValueProcPtr setvalue; | ||||
|   NPP_GotFocusPtr gotfocus; | ||||
|   NPP_LostFocusPtr lostfocus; | ||||
|   NPP_URLRedirectNotifyPtr urlredirectnotify; | ||||
|   NPP_ClearSiteDataPtr clearsitedata; | ||||
|   NPP_GetSitesWithDataPtr getsiteswithdata; | ||||
| } NPPluginFuncs; | ||||
|  | ||||
| typedef struct _NPNetscapeFuncs { | ||||
|   uint16_t size; | ||||
|   uint16_t version; | ||||
|   NPN_GetURLProcPtr geturl; | ||||
|   NPN_PostURLProcPtr posturl; | ||||
|   NPN_RequestReadProcPtr requestread; | ||||
|   NPN_NewStreamProcPtr newstream; | ||||
|   NPN_WriteProcPtr write; | ||||
|   NPN_DestroyStreamProcPtr destroystream; | ||||
|   NPN_StatusProcPtr status; | ||||
|   NPN_UserAgentProcPtr uagent; | ||||
|   NPN_MemAllocProcPtr memalloc; | ||||
|   NPN_MemFreeProcPtr memfree; | ||||
|   NPN_MemFlushProcPtr memflush; | ||||
|   NPN_ReloadPluginsProcPtr reloadplugins; | ||||
|   NPN_GetJavaEnvProcPtr getJavaEnv; | ||||
|   NPN_GetJavaPeerProcPtr getJavaPeer; | ||||
|   NPN_GetURLNotifyProcPtr geturlnotify; | ||||
|   NPN_PostURLNotifyProcPtr posturlnotify; | ||||
|   NPN_GetValueProcPtr getvalue; | ||||
|   NPN_SetValueProcPtr setvalue; | ||||
|   NPN_InvalidateRectProcPtr invalidaterect; | ||||
|   NPN_InvalidateRegionProcPtr invalidateregion; | ||||
|   NPN_ForceRedrawProcPtr forceredraw; | ||||
|   NPN_GetStringIdentifierProcPtr getstringidentifier; | ||||
|   NPN_GetStringIdentifiersProcPtr getstringidentifiers; | ||||
|   NPN_GetIntIdentifierProcPtr getintidentifier; | ||||
|   NPN_IdentifierIsStringProcPtr identifierisstring; | ||||
|   NPN_UTF8FromIdentifierProcPtr utf8fromidentifier; | ||||
|   NPN_IntFromIdentifierProcPtr intfromidentifier; | ||||
|   NPN_CreateObjectProcPtr createobject; | ||||
|   NPN_RetainObjectProcPtr retainobject; | ||||
|   NPN_ReleaseObjectProcPtr releaseobject; | ||||
|   NPN_InvokeProcPtr invoke; | ||||
|   NPN_InvokeDefaultProcPtr invokeDefault; | ||||
|   NPN_EvaluateProcPtr evaluate; | ||||
|   NPN_GetPropertyProcPtr getproperty; | ||||
|   NPN_SetPropertyProcPtr setproperty; | ||||
|   NPN_RemovePropertyProcPtr removeproperty; | ||||
|   NPN_HasPropertyProcPtr hasproperty; | ||||
|   NPN_HasMethodProcPtr hasmethod; | ||||
|   NPN_ReleaseVariantValueProcPtr releasevariantvalue; | ||||
|   NPN_SetExceptionProcPtr setexception; | ||||
|   NPN_PushPopupsEnabledStateProcPtr pushpopupsenabledstate; | ||||
|   NPN_PopPopupsEnabledStateProcPtr poppopupsenabledstate; | ||||
|   NPN_EnumerateProcPtr enumerate; | ||||
|   NPN_PluginThreadAsyncCallProcPtr pluginthreadasynccall; | ||||
|   NPN_ConstructProcPtr construct; | ||||
|   NPN_GetValueForURLPtr getvalueforurl; | ||||
|   NPN_SetValueForURLPtr setvalueforurl; | ||||
|   NPN_GetAuthenticationInfoPtr getauthenticationinfo; | ||||
|   NPN_ScheduleTimerPtr scheduletimer; | ||||
|   NPN_UnscheduleTimerPtr unscheduletimer; | ||||
|   NPN_PopUpContextMenuPtr popupcontextmenu; | ||||
|   NPN_ConvertPointPtr convertpoint; | ||||
|   NPN_HandleEventPtr handleevent; | ||||
|   NPN_UnfocusInstancePtr unfocusinstance; | ||||
|   NPN_URLRedirectResponsePtr urlredirectresponse; | ||||
| } NPNetscapeFuncs; | ||||
|  | ||||
| #ifdef XP_MACOSX | ||||
| /* | ||||
|  * Mac OS X version(s) of NP_GetMIMEDescription(const char *) | ||||
|  * These can be called to retreive MIME information from the plugin dynamically | ||||
|  * | ||||
|  * Note: For compatibility with Quicktime, BPSupportedMIMEtypes is another way | ||||
|  *       to get mime info from the plugin only on OSX and may not be supported | ||||
|  *       in furture version -- use NP_GetMIMEDescription instead | ||||
|  */ | ||||
| enum | ||||
| { | ||||
|  kBPSupportedMIMETypesStructVers_1    = 1 | ||||
| }; | ||||
| typedef struct _BPSupportedMIMETypes | ||||
| { | ||||
|  SInt32    structVersion;      /* struct version */ | ||||
|  Handle    typeStrings;        /* STR# formated handle, allocated by plug-in */ | ||||
|  Handle    infoStrings;        /* STR# formated handle, allocated by plug-in */ | ||||
| } BPSupportedMIMETypes; | ||||
| OSErr BP_GetSupportedMIMETypes(BPSupportedMIMETypes *mimeInfo, UInt32 flags); | ||||
| #define NP_GETMIMEDESCRIPTION_NAME "NP_GetMIMEDescription" | ||||
| typedef const char* (*NP_GetMIMEDescriptionProcPtr)(void); | ||||
| typedef OSErr (*BP_GetSupportedMIMETypesProcPtr)(BPSupportedMIMETypes*, UInt32); | ||||
| #endif | ||||
|  | ||||
| #if defined(_WIN32) | ||||
| #define OSCALL WINAPI | ||||
| #else | ||||
| #if defined(__OS2__) | ||||
| #define OSCALL _System | ||||
| #else | ||||
| #define OSCALL | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #if defined(XP_UNIX) | ||||
| /* GCC 3.3 and later support the visibility attribute. */ | ||||
| #if defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) | ||||
| #define NP_VISIBILITY_DEFAULT __attribute__((visibility("default"))) | ||||
| #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) | ||||
| #define NP_VISIBILITY_DEFAULT __global | ||||
| #else | ||||
| #define NP_VISIBILITY_DEFAULT | ||||
| #endif | ||||
| #define NP_EXPORT(__type) NP_VISIBILITY_DEFAULT __type | ||||
| #endif | ||||
|  | ||||
| #if defined(_WIN32) || defined (__OS2__) | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| /* plugin meta member functions */ | ||||
| #if defined(__OS2__) | ||||
| typedef struct _NPPluginData {   /* Alternate OS2 Plugin interface */ | ||||
|   char *pMimeTypes; | ||||
|   char *pFileExtents; | ||||
|   char *pFileOpenTemplate; | ||||
|   char *pProductName; | ||||
|   char *pProductDescription; | ||||
|   unsigned long dwProductVersionMS; | ||||
|   unsigned long dwProductVersionLS; | ||||
| } NPPluginData; | ||||
| typedef NPError     (*NP_GetPluginDataFunc)(NPPluginData*); | ||||
| NPError OSCALL      NP_GetPluginData(NPPluginData * pPluginData); | ||||
| #endif | ||||
| typedef NPError     (*NP_GetEntryPointsFunc)(NPPluginFuncs*); | ||||
| NPError OSCALL      NP_GetEntryPoints(NPPluginFuncs* pFuncs); | ||||
| typedef NPError     (*NP_InitializeFunc)(NPNetscapeFuncs*); | ||||
| NPError OSCALL      NP_Initialize(NPNetscapeFuncs* bFuncs); | ||||
| typedef NPError     (*NP_ShutdownFunc)(void); | ||||
| NPError OSCALL      NP_Shutdown(void); | ||||
| typedef const char* (*NP_GetMIMEDescriptionFunc)(void); | ||||
| const char*         NP_GetMIMEDescription(void); | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #if defined(__OS2__) | ||||
| #pragma pack() | ||||
| #endif | ||||
|  | ||||
| #ifdef XP_UNIX | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| typedef char*          (*NP_GetPluginVersionFunc)(void); | ||||
| NP_EXPORT(char*)       NP_GetPluginVersion(void); | ||||
| typedef const char*    (*NP_GetMIMEDescriptionFunc)(void); | ||||
| NP_EXPORT(const char*) NP_GetMIMEDescription(void); | ||||
| #ifdef XP_MACOSX | ||||
| typedef NPError        (*NP_InitializeFunc)(NPNetscapeFuncs*); | ||||
| NP_EXPORT(NPError)     NP_Initialize(NPNetscapeFuncs* bFuncs); | ||||
| typedef NPError        (*NP_GetEntryPointsFunc)(NPPluginFuncs*); | ||||
| NP_EXPORT(NPError)     NP_GetEntryPoints(NPPluginFuncs* pFuncs); | ||||
| #else | ||||
| typedef NPError        (*NP_InitializeFunc)(NPNetscapeFuncs*, NPPluginFuncs*); | ||||
| NP_EXPORT(NPError)     NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs); | ||||
| #endif | ||||
| typedef NPError        (*NP_ShutdownFunc)(void); | ||||
| NP_EXPORT(NPError)     NP_Shutdown(void); | ||||
| typedef NPError        (*NP_GetValueFunc)(void *, NPPVariable, void *); | ||||
| NP_EXPORT(NPError)     NP_GetValue(void *future, NPPVariable aVariable, void *aValue); | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #endif /* npfunctions_h_ */ | ||||
| @@ -1,393 +0,0 @@ | ||||
| /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | ||||
| /* | ||||
|  * Copyright (c) 2004, Apple Computer, Inc. and The Mozilla Foundation. | ||||
|  * All rights reserved. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are | ||||
|  * met: | ||||
|  * | ||||
|  * 1. Redistributions of source code must retain the above copyright | ||||
|  * notice, this list of conditions and the following disclaimer. | ||||
|  * 2. Redistributions in binary form must reproduce the above copyright | ||||
|  * notice, this list of conditions and the following disclaimer in the | ||||
|  * documentation and/or other materials provided with the distribution. | ||||
|  * 3. Neither the names of Apple Computer, Inc. ("Apple") or The Mozilla | ||||
|  * Foundation ("Mozilla") nor the names of their contributors may be used | ||||
|  * to endorse or promote products derived from this software without | ||||
|  * specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY APPLE, MOZILLA AND THEIR CONTRIBUTORS "AS | ||||
|  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||||
|  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | ||||
|  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE, MOZILLA OR | ||||
|  * THEIR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
|  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | ||||
|  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||||
|  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||||
|  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||||
|  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  * | ||||
|  */ | ||||
| #ifndef _NP_RUNTIME_H_ | ||||
| #define _NP_RUNTIME_H_ | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #include "nptypes.h" | ||||
|  | ||||
| /* | ||||
|     This API is used to facilitate binding code written in C to script | ||||
|     objects.  The API in this header does not assume the presence of a | ||||
|     user agent.  That is, it can be used to bind C code to scripting | ||||
|     environments outside of the context of a user agent. | ||||
|  | ||||
|     However, the normal use of the this API is in the context of a | ||||
|     scripting environment running in a browser or other user agent. | ||||
|     In particular it is used to support the extended Netscape | ||||
|     script-ability API for plugins (NP-SAP).  NP-SAP is an extension | ||||
|     of the Netscape plugin API.  As such we have adopted the use of | ||||
|     the "NP" prefix for this API. | ||||
|  | ||||
|     The following NP{N|P}Variables were added to the Netscape plugin | ||||
|     API (in npapi.h): | ||||
|  | ||||
|     NPNVWindowNPObject | ||||
|     NPNVPluginElementNPObject | ||||
|     NPPVpluginScriptableNPObject | ||||
|  | ||||
|     These variables are exposed through NPN_GetValue() and | ||||
|     NPP_GetValue() (respectively) and are used to establish the | ||||
|     initial binding between the user agent and native code.  The DOM | ||||
|     objects in the user agent can be examined and manipulated using | ||||
|     the NPN_ functions that operate on NPObjects described in this | ||||
|     header. | ||||
|  | ||||
|     To the extent possible the assumptions about the scripting | ||||
|     language used by the scripting environment have been minimized. | ||||
| */ | ||||
|  | ||||
| #define NP_BEGIN_MACRO  do { | ||||
| #define NP_END_MACRO    } while (0) | ||||
|  | ||||
| /* | ||||
|     Objects (non-primitive data) passed between 'C' and script is | ||||
|     always wrapped in an NPObject.  The 'interface' of an NPObject is | ||||
|     described by an NPClass. | ||||
| */ | ||||
| typedef struct NPObject NPObject; | ||||
| typedef struct NPClass NPClass; | ||||
|  | ||||
| typedef char NPUTF8; | ||||
| typedef struct _NPString { | ||||
|     const NPUTF8 *UTF8Characters; | ||||
|     uint32_t UTF8Length; | ||||
| } NPString; | ||||
|  | ||||
| typedef enum { | ||||
|     NPVariantType_Void, | ||||
|     NPVariantType_Null, | ||||
|     NPVariantType_Bool, | ||||
|     NPVariantType_Int32, | ||||
|     NPVariantType_Double, | ||||
|     NPVariantType_String, | ||||
|     NPVariantType_Object | ||||
| } NPVariantType; | ||||
|  | ||||
| typedef struct _NPVariant { | ||||
|     NPVariantType type; | ||||
|     union { | ||||
|         bool boolValue; | ||||
|         int32_t intValue; | ||||
|         double doubleValue; | ||||
|         NPString stringValue; | ||||
|         NPObject *objectValue; | ||||
|     } value; | ||||
| } NPVariant; | ||||
|  | ||||
| /* | ||||
|     NPN_ReleaseVariantValue is called on all 'out' parameters | ||||
|     references.  Specifically it is to be called on variants that own | ||||
|     their value, as is the case with all non-const NPVariant* | ||||
|     arguments after a successful call to any methods (except this one) | ||||
|     in this API. | ||||
|  | ||||
|     After calling NPN_ReleaseVariantValue, the type of the variant | ||||
|     will be NPVariantType_Void. | ||||
| */ | ||||
| void NPN_ReleaseVariantValue(NPVariant *variant); | ||||
|  | ||||
| #define NPVARIANT_IS_VOID(_v)    ((_v).type == NPVariantType_Void) | ||||
| #define NPVARIANT_IS_NULL(_v)    ((_v).type == NPVariantType_Null) | ||||
| #define NPVARIANT_IS_BOOLEAN(_v) ((_v).type == NPVariantType_Bool) | ||||
| #define NPVARIANT_IS_INT32(_v)   ((_v).type == NPVariantType_Int32) | ||||
| #define NPVARIANT_IS_DOUBLE(_v)  ((_v).type == NPVariantType_Double) | ||||
| #define NPVARIANT_IS_STRING(_v)  ((_v).type == NPVariantType_String) | ||||
| #define NPVARIANT_IS_OBJECT(_v)  ((_v).type == NPVariantType_Object) | ||||
|  | ||||
| #define NPVARIANT_TO_BOOLEAN(_v) ((_v).value.boolValue) | ||||
| #define NPVARIANT_TO_INT32(_v)   ((_v).value.intValue) | ||||
| #define NPVARIANT_TO_DOUBLE(_v)  ((_v).value.doubleValue) | ||||
| #define NPVARIANT_TO_STRING(_v)  ((_v).value.stringValue) | ||||
| #define NPVARIANT_TO_OBJECT(_v)  ((_v).value.objectValue) | ||||
|  | ||||
| #define VOID_TO_NPVARIANT(_v)                                                 \ | ||||
| NP_BEGIN_MACRO                                                                \ | ||||
|     (_v).type = NPVariantType_Void;                                           \ | ||||
|     (_v).value.objectValue = NULL;                                            \ | ||||
| NP_END_MACRO | ||||
|  | ||||
| #define NULL_TO_NPVARIANT(_v)                                                 \ | ||||
| NP_BEGIN_MACRO                                                                \ | ||||
|     (_v).type = NPVariantType_Null;                                           \ | ||||
|     (_v).value.objectValue = NULL;                                            \ | ||||
| NP_END_MACRO | ||||
|  | ||||
| #define BOOLEAN_TO_NPVARIANT(_val, _v)                                        \ | ||||
| NP_BEGIN_MACRO                                                                \ | ||||
|     (_v).type = NPVariantType_Bool;                                           \ | ||||
|     (_v).value.boolValue = !!(_val);                                          \ | ||||
| NP_END_MACRO | ||||
|  | ||||
| #define INT32_TO_NPVARIANT(_val, _v)                                          \ | ||||
| NP_BEGIN_MACRO                                                                \ | ||||
|     (_v).type = NPVariantType_Int32;                                          \ | ||||
|     (_v).value.intValue = _val;                                               \ | ||||
| NP_END_MACRO | ||||
|  | ||||
| #define DOUBLE_TO_NPVARIANT(_val, _v)                                         \ | ||||
| NP_BEGIN_MACRO                                                                \ | ||||
|     (_v).type = NPVariantType_Double;                                         \ | ||||
|     (_v).value.doubleValue = _val;                                            \ | ||||
| NP_END_MACRO | ||||
|  | ||||
| #define STRINGZ_TO_NPVARIANT(_val, _v)                                        \ | ||||
| NP_BEGIN_MACRO                                                                \ | ||||
|     (_v).type = NPVariantType_String;                                         \ | ||||
|     NPString str = { _val, (uint32_t)(strlen(_val)) };                        \ | ||||
|     (_v).value.stringValue = str;                                             \ | ||||
| NP_END_MACRO | ||||
|  | ||||
| #define STRINGN_TO_NPVARIANT(_val, _len, _v)                                  \ | ||||
| NP_BEGIN_MACRO                                                                \ | ||||
|     (_v).type = NPVariantType_String;                                         \ | ||||
|     NPString str = { _val, (uint32_t)(_len) };                                \ | ||||
|     (_v).value.stringValue = str;                                             \ | ||||
| NP_END_MACRO | ||||
|  | ||||
| #define OBJECT_TO_NPVARIANT(_val, _v)                                         \ | ||||
| NP_BEGIN_MACRO                                                                \ | ||||
|     (_v).type = NPVariantType_Object;                                         \ | ||||
|     (_v).value.objectValue = _val;                                            \ | ||||
| NP_END_MACRO | ||||
|  | ||||
|  | ||||
| /* | ||||
|   Type mappings (JavaScript types have been used for illustration | ||||
|     purposes): | ||||
|  | ||||
|   JavaScript       to             C (NPVariant with type:) | ||||
|   undefined                       NPVariantType_Void | ||||
|   null                            NPVariantType_Null | ||||
|   Boolean                         NPVariantType_Bool | ||||
|   Number                          NPVariantType_Double or NPVariantType_Int32 | ||||
|   String                          NPVariantType_String | ||||
|   Object                          NPVariantType_Object | ||||
|  | ||||
|   C (NPVariant with type:)   to   JavaScript | ||||
|   NPVariantType_Void              undefined | ||||
|   NPVariantType_Null              null | ||||
|   NPVariantType_Bool              Boolean | ||||
|   NPVariantType_Int32             Number | ||||
|   NPVariantType_Double            Number | ||||
|   NPVariantType_String            String | ||||
|   NPVariantType_Object            Object | ||||
| */ | ||||
|  | ||||
| typedef void *NPIdentifier; | ||||
|  | ||||
| /* | ||||
|     NPObjects have methods and properties.  Methods and properties are | ||||
|     identified with NPIdentifiers.  These identifiers may be reflected | ||||
|     in script.  NPIdentifiers can be either strings or integers, IOW, | ||||
|     methods and properties can be identified by either strings or | ||||
|     integers (i.e. foo["bar"] vs foo[1]). NPIdentifiers can be | ||||
|     compared using ==.  In case of any errors, the requested | ||||
|     NPIdentifier(s) will be NULL. NPIdentifier lifetime is controlled | ||||
|     by the browser. Plugins do not need to worry about memory management | ||||
|     with regards to NPIdentifiers. | ||||
| */ | ||||
| NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name); | ||||
| void NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount, | ||||
|                               NPIdentifier *identifiers); | ||||
| NPIdentifier NPN_GetIntIdentifier(int32_t intid); | ||||
| bool NPN_IdentifierIsString(NPIdentifier identifier); | ||||
|  | ||||
| /* | ||||
|     The NPUTF8 returned from NPN_UTF8FromIdentifier SHOULD be freed. | ||||
| */ | ||||
| NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier); | ||||
|  | ||||
| /* | ||||
|     Get the integer represented by identifier. If identifier is not an | ||||
|     integer identifier, the behaviour is undefined. | ||||
| */ | ||||
| int32_t NPN_IntFromIdentifier(NPIdentifier identifier); | ||||
|  | ||||
| /* | ||||
|     NPObject behavior is implemented using the following set of | ||||
|     callback functions. | ||||
|  | ||||
|     The NPVariant *result argument of these functions (where | ||||
|     applicable) should be released using NPN_ReleaseVariantValue(). | ||||
| */ | ||||
| typedef NPObject *(*NPAllocateFunctionPtr)(NPP npp, NPClass *aClass); | ||||
| typedef void (*NPDeallocateFunctionPtr)(NPObject *npobj); | ||||
| typedef void (*NPInvalidateFunctionPtr)(NPObject *npobj); | ||||
| typedef bool (*NPHasMethodFunctionPtr)(NPObject *npobj, NPIdentifier name); | ||||
| typedef bool (*NPInvokeFunctionPtr)(NPObject *npobj, NPIdentifier name, | ||||
|                                     const NPVariant *args, uint32_t argCount, | ||||
|                                     NPVariant *result); | ||||
| typedef bool (*NPInvokeDefaultFunctionPtr)(NPObject *npobj, | ||||
|                                            const NPVariant *args, | ||||
|                                            uint32_t argCount, | ||||
|                                            NPVariant *result); | ||||
| typedef bool (*NPHasPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name); | ||||
| typedef bool (*NPGetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name, | ||||
|                                          NPVariant *result); | ||||
| typedef bool (*NPSetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name, | ||||
|                                          const NPVariant *value); | ||||
| typedef bool (*NPRemovePropertyFunctionPtr)(NPObject *npobj, | ||||
|                                             NPIdentifier name); | ||||
| typedef bool (*NPEnumerationFunctionPtr)(NPObject *npobj, NPIdentifier **value, | ||||
|                                          uint32_t *count); | ||||
| typedef bool (*NPConstructFunctionPtr)(NPObject *npobj, | ||||
|                                        const NPVariant *args, | ||||
|                                        uint32_t argCount, | ||||
|                                        NPVariant *result); | ||||
|  | ||||
| /* | ||||
|     NPObjects returned by create, retain, invoke, and getProperty pass | ||||
|     a reference count to the caller.  That is, the callee adds a | ||||
|     reference count which passes to the caller.  It is the caller's | ||||
|     responsibility to release the returned object. | ||||
|  | ||||
|     NPInvokeFunctionPtr function may return 0 to indicate a void | ||||
|     result. | ||||
|  | ||||
|     NPInvalidateFunctionPtr is called by the scripting environment | ||||
|     when the native code is shutdown.  Any attempt to message a | ||||
|     NPObject instance after the invalidate callback has been | ||||
|     called will result in undefined behavior, even if the native code | ||||
|     is still retaining those NPObject instances.  (The runtime | ||||
|     will typically return immediately, with 0 or NULL, from an attempt | ||||
|     to dispatch to a NPObject, but this behavior should not be | ||||
|     depended upon.) | ||||
|  | ||||
|     The NPEnumerationFunctionPtr function may pass an array of | ||||
|     NPIdentifiers back to the caller. The callee allocs the memory of | ||||
|     the array using NPN_MemAlloc(), and it's the caller's responsibility | ||||
|     to release it using NPN_MemFree(). | ||||
| */ | ||||
| struct NPClass | ||||
| { | ||||
|     uint32_t structVersion; | ||||
|     NPAllocateFunctionPtr allocate; | ||||
|     NPDeallocateFunctionPtr deallocate; | ||||
|     NPInvalidateFunctionPtr invalidate; | ||||
|     NPHasMethodFunctionPtr hasMethod; | ||||
|     NPInvokeFunctionPtr invoke; | ||||
|     NPInvokeDefaultFunctionPtr invokeDefault; | ||||
|     NPHasPropertyFunctionPtr hasProperty; | ||||
|     NPGetPropertyFunctionPtr getProperty; | ||||
|     NPSetPropertyFunctionPtr setProperty; | ||||
|     NPRemovePropertyFunctionPtr removeProperty; | ||||
|     NPEnumerationFunctionPtr enumerate; | ||||
|     NPConstructFunctionPtr construct; | ||||
| }; | ||||
|  | ||||
| #define NP_CLASS_STRUCT_VERSION      3 | ||||
|  | ||||
| #define NP_CLASS_STRUCT_VERSION_ENUM 2 | ||||
| #define NP_CLASS_STRUCT_VERSION_CTOR 3 | ||||
|  | ||||
| #define NP_CLASS_STRUCT_VERSION_HAS_ENUM(npclass)   \ | ||||
|         ((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_ENUM) | ||||
|  | ||||
| #define NP_CLASS_STRUCT_VERSION_HAS_CTOR(npclass)   \ | ||||
|         ((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR) | ||||
|  | ||||
| struct NPObject { | ||||
|     NPClass *_class; | ||||
|     uint32_t referenceCount; | ||||
|     /* | ||||
|      * Additional space may be allocated here by types of NPObjects | ||||
|      */ | ||||
| }; | ||||
|  | ||||
| /* | ||||
|     If the class has an allocate function, NPN_CreateObject invokes | ||||
|     that function, otherwise a NPObject is allocated and | ||||
|     returned. This method will initialize the referenceCount member of | ||||
|     the NPObject to 1. | ||||
| */ | ||||
| NPObject *NPN_CreateObject(NPP npp, NPClass *aClass); | ||||
|  | ||||
| /* | ||||
|     Increment the NPObject's reference count. | ||||
| */ | ||||
| NPObject *NPN_RetainObject(NPObject *npobj); | ||||
|  | ||||
| /* | ||||
|     Decremented the NPObject's reference count.  If the reference | ||||
|     count goes to zero, the class's destroy function is invoke if | ||||
|     specified, otherwise the object is freed directly. | ||||
| */ | ||||
| void NPN_ReleaseObject(NPObject *npobj); | ||||
|  | ||||
| /* | ||||
|     Functions to access script objects represented by NPObject. | ||||
|  | ||||
|     Calls to script objects are synchronous.  If a function returns a | ||||
|     value, it will be supplied via the result NPVariant | ||||
|     argument. Successful calls will return true, false will be | ||||
|     returned in case of an error. | ||||
|  | ||||
|     Calls made from plugin code to script must be made from the thread | ||||
|     on which the plugin was initialized. | ||||
| */ | ||||
|  | ||||
| bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName, | ||||
|                 const NPVariant *args, uint32_t argCount, NPVariant *result); | ||||
| bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args, | ||||
|                        uint32_t argCount, NPVariant *result); | ||||
| bool NPN_Evaluate(NPP npp, NPObject *npobj, NPString *script, | ||||
|                   NPVariant *result); | ||||
| bool NPN_GetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, | ||||
|                      NPVariant *result); | ||||
| bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, | ||||
|                      const NPVariant *value); | ||||
| bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName); | ||||
| bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName); | ||||
| bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName); | ||||
| bool NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier, | ||||
|                    uint32_t *count); | ||||
| bool NPN_Construct(NPP npp, NPObject *npobj, const NPVariant *args, | ||||
|                    uint32_t argCount, NPVariant *result); | ||||
|  | ||||
| /* | ||||
|     NPN_SetException may be called to trigger a script exception upon | ||||
|     return from entry points into NPObjects.  Typical usage: | ||||
|  | ||||
|     NPN_SetException (npobj, message); | ||||
| */ | ||||
| void NPN_SetException(NPObject *npobj, const NPUTF8 *message); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
| @@ -1,121 +0,0 @@ | ||||
| /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | ||||
| /* ***** BEGIN LICENSE BLOCK ***** | ||||
|  * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | ||||
|  * | ||||
|  * The contents of this file are subject to the Mozilla Public License Version | ||||
|  * 1.1 (the "License"); you may not use this file except in compliance with | ||||
|  * the License. You may obtain a copy of the License at | ||||
|  * http://www.mozilla.org/MPL/ | ||||
|  * | ||||
|  * Software distributed under the License is distributed on an "AS IS" basis, | ||||
|  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | ||||
|  * for the specific language governing rights and limitations under the | ||||
|  * License. | ||||
|  * | ||||
|  * The Original Code is mozilla.org code. | ||||
|  * | ||||
|  * The Initial Developer of the Original Code is | ||||
|  * mozilla.org. | ||||
|  * Portions created by the Initial Developer are Copyright (C) 2004 | ||||
|  * the Initial Developer. All Rights Reserved. | ||||
|  * | ||||
|  * Contributor(s): | ||||
|  *   Johnny Stenback <jst@mozilla.org> (Original author) | ||||
|  * | ||||
|  * Alternatively, the contents of this file may be used under the terms of | ||||
|  * either the GNU General Public License Version 2 or later (the "GPL"), or | ||||
|  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), | ||||
|  * in which case the provisions of the GPL or the LGPL are applicable instead | ||||
|  * of those above. If you wish to allow use of your version of this file only | ||||
|  * under the terms of either the GPL or the LGPL, and not to allow others to | ||||
|  * use your version of this file under the terms of the MPL, indicate your | ||||
|  * decision by deleting the provisions above and replace them with the notice | ||||
|  * and other provisions required by the GPL or the LGPL. If you do not delete | ||||
|  * the provisions above, a recipient may use your version of this file under | ||||
|  * the terms of any one of the MPL, the GPL or the LGPL. | ||||
|  * | ||||
|  * ***** END LICENSE BLOCK ***** */ | ||||
|  | ||||
| #ifndef nptypes_h_ | ||||
| #define nptypes_h_ | ||||
|  | ||||
| /* | ||||
|  * Header file for ensuring that C99 types ([u]int32_t, [u]int64_t and bool) and | ||||
|  * true/false macros are available. | ||||
|  */ | ||||
|  | ||||
| #if defined(WIN32) || defined(OS2) | ||||
|   /* | ||||
|    * Win32 and OS/2 don't know C99, so define [u]int_16/32/64 here. The bool | ||||
|    * is predefined tho, both in C and C++. | ||||
|    */ | ||||
|   typedef short int16_t; | ||||
|   typedef unsigned short uint16_t; | ||||
|   typedef int int32_t; | ||||
|   typedef unsigned int uint32_t; | ||||
|   typedef long long int64_t; | ||||
|   typedef unsigned long long uint64_t; | ||||
| #elif defined(_AIX) || defined(__sun) || defined(__osf__) || defined(IRIX) || defined(HPUX) | ||||
|   /* | ||||
|    * AIX and SunOS ship a inttypes.h header that defines [u]int32_t, | ||||
|    * but not bool for C. | ||||
|    */ | ||||
|   #include <inttypes.h> | ||||
|  | ||||
|   #ifndef __cplusplus | ||||
|     typedef int bool; | ||||
|     #define true   1 | ||||
|     #define false  0 | ||||
|   #endif | ||||
| #elif defined(bsdi) || defined(FREEBSD) || defined(OPENBSD) | ||||
|   /* | ||||
|    * BSD/OS, FreeBSD, and OpenBSD ship sys/types.h that define int32_t and | ||||
|    * u_int32_t. | ||||
|    */ | ||||
|   #include <sys/types.h> | ||||
|  | ||||
|   /* | ||||
|    * BSD/OS ships no header that defines uint32_t, nor bool (for C) | ||||
|    */ | ||||
|   #if defined(bsdi) | ||||
|   typedef u_int32_t uint32_t; | ||||
|   typedef u_int64_t uint64_t; | ||||
|  | ||||
|   #if !defined(__cplusplus) | ||||
|     typedef int bool; | ||||
|     #define true   1 | ||||
|     #define false  0 | ||||
|   #endif | ||||
|   #else | ||||
|   /* | ||||
|    * FreeBSD and OpenBSD define uint32_t and bool. | ||||
|    */ | ||||
|     #include <inttypes.h> | ||||
|     #include <stdbool.h> | ||||
|   #endif | ||||
| #elif defined(BEOS) | ||||
|   #include <inttypes.h> | ||||
| #else | ||||
|   /* | ||||
|    * For those that ship a standard C99 stdint.h header file, include | ||||
|    * it. Can't do the same for stdbool.h tho, since some systems ship | ||||
|    * with a stdbool.h file that doesn't compile! | ||||
|    */ | ||||
|   #include <stdint.h> | ||||
|  | ||||
|   #ifndef __cplusplus | ||||
|     #if !defined(__GNUC__) || (__GNUC__ > 2 || __GNUC_MINOR__ > 95) | ||||
|       #include <stdbool.h> | ||||
|     #else | ||||
|       /* | ||||
|        * GCC 2.91 can't deal with a typedef for bool, but a #define | ||||
|        * works. | ||||
|        */ | ||||
|       #define bool int | ||||
|       #define true   1 | ||||
|       #define false  0 | ||||
|     #endif | ||||
|   #endif | ||||
| #endif | ||||
|  | ||||
| #endif /* nptypes_h_ */ | ||||
							
								
								
									
										172
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						| @@ -1,16 +1,13 @@ | ||||
| AC_PREREQ(2.63) | ||||
| AC_INIT([gnome-shell],[3.1.91.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell]) | ||||
| AC_INIT([gnome-shell],[2.91.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]) | ||||
| AC_CONFIG_MACRO_DIR([m4]) | ||||
| AC_CONFIG_AUX_DIR([config]) | ||||
|  | ||||
| AC_SUBST([PACKAGE_NAME], ["$PACKAGE_NAME"]) | ||||
| AC_SUBST([PACKAGE_VERSION], ["$PACKAGE_VERSION"]) | ||||
|  | ||||
| AM_INIT_AUTOMAKE([1.10 dist-xz no-dist-gzip foreign]) | ||||
| AM_MAINTAINER_MODE([enable]) | ||||
| AM_INIT_AUTOMAKE([1.10 dist-bzip2 no-dist-gzip foreign]) | ||||
| AM_MAINTAINER_MODE | ||||
|  | ||||
| m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) | ||||
|  | ||||
| @@ -23,16 +20,12 @@ AM_PROG_CC_C_O | ||||
| LT_PREREQ([2.2.6]) | ||||
| LT_INIT([disable-static]) | ||||
|  | ||||
| # i18n | ||||
| IT_PROG_INTLTOOL([0.40]) | ||||
|  | ||||
| AM_GNU_GETTEXT([external]) | ||||
| AM_GNU_GETTEXT_VERSION([0.17]) | ||||
|  | ||||
| GETTEXT_PACKAGE=gnome-shell | ||||
| AC_SUBST(GETTEXT_PACKAGE) | ||||
| AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", | ||||
|                    [The prefix for our gettext translation domains.]) | ||||
| IT_PROG_INTLTOOL(0.26) | ||||
| AM_GLIB_GNU_GETTEXT | ||||
|  | ||||
| PKG_PROG_PKG_CONFIG([0.22]) | ||||
|  | ||||
| @@ -56,116 +49,71 @@ AC_MSG_CHECKING([for GStreamer (needed for recording functionality)]) | ||||
| if $PKG_CONFIG --exists gstreamer-0.10 '>=' $GSTREAMER_MIN_VERSION ; then | ||||
|    AC_MSG_RESULT(yes) | ||||
|    build_recorder=true | ||||
|    recorder_modules="gstreamer-0.10 gstreamer-base-0.10 x11" | ||||
|    PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0 xfixes) | ||||
|    recorder_modules="gstreamer-0.10 gstreamer-base-0.10 xfixes" | ||||
|    PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0) | ||||
| else | ||||
|    AC_MSG_RESULT(no) | ||||
| fi | ||||
|  | ||||
| AM_CONDITIONAL(BUILD_RECORDER, $build_recorder) | ||||
|  | ||||
| CLUTTER_MIN_VERSION=1.7.5 | ||||
| GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1 | ||||
| GJS_MIN_VERSION=1.29.15 | ||||
| MUTTER_MIN_VERSION=3.0.0 | ||||
| FOLKS_MIN_VERSION=0.5.2 | ||||
| GTK_MIN_VERSION=3.0.0 | ||||
| GIO_MIN_VERSION=2.29.10 | ||||
| LIBECAL_MIN_VERSION=2.32.0 | ||||
| LIBEDATASERVER_MIN_VERSION=1.2.0 | ||||
| LIBEDATASERVERUI_MIN_VERSION=2.91.6 | ||||
| TELEPATHY_GLIB_MIN_VERSION=0.15.5 | ||||
| TELEPATHY_LOGGER_MIN_VERSION=0.2.4 | ||||
| POLKIT_MIN_VERSION=0.100 | ||||
| STARTUP_NOTIFICATION_MIN_VERSION=0.11 | ||||
| CLUTTER_MIN_VERSION=1.3.14 | ||||
| GOBJECT_INTROSPECTION_MIN_VERSION=0.6.11 | ||||
| GJS_MIN_VERSION=0.7 | ||||
| MUTTER_MIN_VERSION=2.91.0 | ||||
| GTK_MIN_VERSION=2.91.0 | ||||
| GIO_MIN_VERSION=2.25.9 | ||||
|  | ||||
| # Collect more than 20 libraries for a prize! | ||||
| PKG_CHECK_MODULES(GNOME_SHELL, gio-2.0 >= $GIO_MIN_VERSION | ||||
|                                gio-unix-2.0 dbus-glib-1 libxml-2.0 | ||||
|                                gtk+-3.0 >= $GTK_MIN_VERSION | ||||
|                                folks >= $FOLKS_MIN_VERSION | ||||
|                                libmutter >= $MUTTER_MIN_VERSION | ||||
|                                gjs-internals-1.0 >= $GJS_MIN_VERSION | ||||
| 			       libgnome-menu-3.0 $recorder_modules gconf-2.0 | ||||
|                                gdk-x11-3.0 libsoup-2.4 | ||||
| 			       clutter-x11-1.0 >= $CLUTTER_MIN_VERSION | ||||
| 			       clutter-glx-1.0 >= $CLUTTER_MIN_VERSION | ||||
|                                libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION | ||||
|                                gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION | ||||
| 			       libcanberra | ||||
|                                telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION | ||||
|                                telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION | ||||
|                                polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes | ||||
|                                libnm-glib libnm-util gnome-keyring-1) | ||||
|  | ||||
| PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0) | ||||
|  | ||||
| PKG_CHECK_MODULES(SHELL_HOTPLUG_SNIFFER, gio-2.0 gdk-pixbuf-2.0) | ||||
|  | ||||
| PKG_CHECK_MODULES(BROWSER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION json-glib-1.0 >= 0.13.2) | ||||
|  | ||||
| GJS_VERSION=`$PKG_CONFIG --modversion gjs-internals-1.0` | ||||
| AC_DEFINE_UNQUOTED([GJS_VERSION], ["$GJS_VERSION"], [The version of GJS we're linking to]) | ||||
| AC_SUBST([GJS_VERSION], ["$GJS_VERSION"]) | ||||
|  | ||||
| GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION]) | ||||
| JHBUILD_TYPELIBDIR="$INTROSPECTION_TYPELIBDIR" | ||||
| AC_SUBST(JHBUILD_TYPELIBDIR) | ||||
| PKG_CHECK_MODULES(MUTTER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION | ||||
|                                  gio-unix-2.0 dbus-glib-1 | ||||
|                                  gtk+-3.0 >= $GTK_MIN_VERSION | ||||
|                                  mutter-plugins >= $MUTTER_MIN_VERSION | ||||
|                                  gjs-internals-1.0 >= $GJS_MIN_VERSION | ||||
| 				 libgnome-menu $recorder_modules gconf-2.0 | ||||
|                                  gdk-x11-3.0 | ||||
| 				 clutter-x11-1.0 >= $CLUTTER_MIN_VERSION | ||||
| 				 clutter-glx-1.0 >= $CLUTTER_MIN_VERSION | ||||
|                                  libstartup-notification-1.0 | ||||
|                                  gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION | ||||
| 				 libcanberra) | ||||
|  | ||||
| saved_CFLAGS=$CFLAGS | ||||
| saved_LIBS=$LIBS | ||||
| CFLAGS=$GNOME_SHELL_CFLAGS | ||||
| LIBS=$GNOME_SHELL_LIBS | ||||
| AC_CHECK_FUNCS(JS_NewGlobalObject XFixesCreatePointerBarrier) | ||||
| CFLAGS=$MUTTER_PLUGIN_CFLAGS | ||||
| LIBS=$MUTTER_PLUGIN_LIBS | ||||
| # sn_startup_sequence_get_application_id, we can replace with a version check later | ||||
| AC_CHECK_FUNCS(JS_NewGlobalObject sn_startup_sequence_get_application_id) | ||||
| CFLAGS=$saved_CFLAGS | ||||
| LIBS=$saved_LIBS | ||||
|  | ||||
| PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.2 gnome-desktop-3.0 >= 2.90.0 x11) | ||||
| PKG_CHECK_MODULES(TIDY, clutter-1.0) | ||||
| PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 gnome-desktop-3.0 >= 2.90.0) | ||||
| PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-3.0) | ||||
| PKG_CHECK_MODULES(TRAY, gtk+-3.0) | ||||
| PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0) | ||||
| PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 0.1.7) | ||||
|  | ||||
| AC_MSG_CHECKING([for bluetooth support]) | ||||
| PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0], | ||||
|         [BLUETOOTH_DIR=`$PKG_CONFIG --variable=applet_libdir gnome-bluetooth-1.0` | ||||
| 	 BLUETOOTH_LIBS=`$PKG_CONFIG --variable=applet_libs gnome-bluetooth-1.0` | ||||
| 	 AC_SUBST([BLUETOOTH_LIBS],["$BLUETOOTH_LIBS"]) | ||||
| 	 AC_DEFINE_UNQUOTED([BLUETOOTH_DIR],["$BLUETOOTH_DIR"],[Path to installed GnomeBluetooth typelib and library]) | ||||
| 	 AC_DEFINE([HAVE_BLUETOOTH],[1],[Define if you have libgnome-bluetooth-applet]) | ||||
| 	 AC_SUBST([HAVE_BLUETOOTH],[1]) | ||||
| 	 AC_MSG_RESULT([yes])], | ||||
| 	[AC_DEFINE([HAVE_BLUETOOTH],[0]) | ||||
| 	 AC_SUBST([HAVE_BLUETOOTH],[0]) | ||||
| 	 AC_MSG_RESULT([no])]) | ||||
| PKG_CHECK_MODULES(JS_TEST, clutter-x11-1.0 gjs-1.0 gobject-introspection-1.0 gtk+-3.0) | ||||
|  | ||||
| PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION libedataserverui-3.0 >= $LIBEDATASERVERUI_MIN_VERSION gio-2.0) | ||||
| AC_SUBST(CALENDAR_SERVER_CFLAGS) | ||||
| AC_SUBST(CALENDAR_SERVER_LIBS) | ||||
|  | ||||
| MUTTER_GIR_DIR=`$PKG_CONFIG --variable=girdir libmutter` | ||||
| MUTTER_TYPELIB_DIR=`$PKG_CONFIG --variable=typelibdir libmutter` | ||||
| AC_SUBST(MUTTER_GIR_DIR) | ||||
| AC_SUBST(MUTTER_TYPELIB_DIR) | ||||
| MUTTER_BIN_DIR=`$PKG_CONFIG --variable=exec_prefix mutter-plugins`/bin | ||||
| # FIXME: metacity-plugins.pc should point directly to its .gir file | ||||
| MUTTER_LIB_DIR=`$PKG_CONFIG --variable=libdir mutter-plugins` | ||||
| MUTTER_PLUGIN_DIR=`$PKG_CONFIG --variable=plugindir mutter-plugins` | ||||
| AC_SUBST(MUTTER_BIN_DIR) | ||||
| AC_SUBST(MUTTER_LIB_DIR) | ||||
| AC_SUBST(MUTTER_PLUGIN_DIR) | ||||
|  | ||||
| GJS_JS_DIR=`$PKG_CONFIG --variable=jsdir gjs-1.0` | ||||
| GJS_JS_NATIVE_DIR=`$PKG_CONFIG --variable=jsnativedir gjs-1.0` | ||||
| GJS_CONSOLE=`$PKG_CONFIG --variable=gjs_console gjs-1.0` | ||||
| AC_SUBST(GJS_JS_DIR) | ||||
| AC_SUBST(GJS_JS_NATIVE_DIR) | ||||
| AC_SUBST(GJS_CONSOLE) | ||||
|  | ||||
| AC_CHECK_FUNCS(fdwalk) | ||||
| AC_CHECK_FUNCS(mallinfo) | ||||
| AC_CHECK_HEADERS([sys/resource.h]) | ||||
|  | ||||
| # _NL_TIME_FIRST_WEEKDAY is an enum and not a define | ||||
| AC_MSG_CHECKING([for _NL_TIME_FIRST_WEEKDAY]) | ||||
| AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <langinfo.h>]], | ||||
|                                    [[nl_langinfo(_NL_TIME_FIRST_WEEKDAY);]])], | ||||
|                [langinfo_ok=yes], [langinfo_ok=no]) | ||||
| AC_MSG_RESULT($langinfo_ok) | ||||
| if test "$langinfo_ok" = "yes"; then | ||||
|   AC_DEFINE([HAVE__NL_TIME_FIRST_WEEKDAY], [1], | ||||
|             [Define if _NL_TIME_FIRST_WEEKDAY is available]) | ||||
| fi | ||||
|  | ||||
| # Sets GLIB_GENMARSHAL and GLIB_MKENUMS | ||||
| AM_PATH_GLIB_2_0() | ||||
| G_IR_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0` | ||||
| @@ -206,42 +154,22 @@ if test "$enable_compile_warnings" != no ; then | ||||
| fi | ||||
| changequote([,])dnl | ||||
|  | ||||
| AC_ARG_ENABLE(jhbuild-wrapper-script, | ||||
|   AS_HELP_STRING([--jhbuild-wrapper-script=yes],[Make "gnome-shell" script work for jhbuild]),,enable_jhbuild_wrapper_script=no) | ||||
| AM_CONDITIONAL(USE_JHBUILD_WRAPPER_SCRIPT, test "x$enable_jhbuild_wrapper_script" = xyes) | ||||
| AC_PATH_PROG(mutter, [mutter]) | ||||
| AC_SUBST(mutter) | ||||
|  | ||||
| AC_MSG_CHECKING([location of system Certificate Authority list]) | ||||
| AC_ARG_WITH(ca-certificates, | ||||
|             [AC_HELP_STRING([--with-ca-certificates=@<:@path@:>@], | ||||
|                             [path to system Certificate Authority list])]) | ||||
|  | ||||
| if test "$with_ca_certificates" = "no"; then | ||||
|     AC_MSG_RESULT([disabled]) | ||||
| AC_MSG_CHECKING([if mutter was compiled with GTK+-3.0]) | ||||
| if $PKG_CONFIG --libs libmutter-private | grep gtk-x11-3 >/dev/null; then | ||||
|   AC_MSG_RESULT(yes) | ||||
| else | ||||
|     if test -z "$with_ca_certificates"; then | ||||
|         for f in /etc/pki/tls/certs/ca-bundle.crt \ | ||||
|                  /etc/ssl/certs/ca-certificates.crt; do | ||||
|              if test -f "$f"; then | ||||
|                 with_ca_certificates="$f" | ||||
|              fi | ||||
|         done | ||||
|         if test -z "$with_ca_certificates"; then | ||||
|             AC_MSG_ERROR([could not find. Use --with-ca-certificates=path to set, or --without-ca-certificates to disable]) | ||||
|         fi | ||||
|    fi | ||||
|  | ||||
|    AC_MSG_RESULT($with_ca_certificates) | ||||
|    AC_DEFINE_UNQUOTED(SHELL_SYSTEM_CA_FILE, ["$with_ca_certificates"], [The system TLS CA list]) | ||||
|   AC_MSG_RESULT(no) | ||||
|   AC_MSG_ERROR([GNOME Shell requires Mutter to be compiled against GTK+-3.0]) | ||||
| fi | ||||
| AC_SUBST(SHELL_SYSTEM_CA_FILE,["$with_ca_certificates"]) | ||||
|  | ||||
| AC_CONFIG_FILES([ | ||||
|   Makefile | ||||
|   data/Makefile | ||||
|   js/Makefile | ||||
|   js/misc/config.js | ||||
|   src/Makefile | ||||
|   browser-plugin/Makefile | ||||
|   tests/Makefile | ||||
|   po/Makefile.in | ||||
|   man/Makefile | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| desktopdir=$(datadir)/applications | ||||
| desktop_DATA = gnome-shell.desktop | ||||
| desktop_DATA = gnome-shell.desktop gnome-shell-clock-preferences.desktop | ||||
|  | ||||
| # We substitute in bindir so it works as an autostart | ||||
| # file when built in a non-system prefix | ||||
| @@ -12,42 +12,49 @@ desktop_DATA = gnome-shell.desktop | ||||
| %.desktop:%.desktop.in | ||||
| 	$(AM_V_GEN) sed s/^_// < $< > $@ || rm $@ | ||||
|  | ||||
| searchprovidersdir = $(pkgdatadir)/search_providers | ||||
| dist_searchproviders_DATA =				\ | ||||
| 	search_providers/google.xml				\ | ||||
| 	search_providers/wikipedia.xml | ||||
| dist_pkgdata_DATA = clock-preferences.ui | ||||
|  | ||||
| imagesdir = $(pkgdatadir)/images | ||||
| dist_images_DATA =				\ | ||||
| 	close-black.svg				\ | ||||
| 	magnifier.svg | ||||
|  | ||||
| themedir = $(pkgdatadir)/theme | ||||
| dist_theme_DATA =				\ | ||||
| 	theme/calendar-arrow-left.svg		\ | ||||
| 	theme/calendar-arrow-right.svg		\ | ||||
| 	theme/calendar-today.svg		\ | ||||
| 	theme/add-workspace.svg			\ | ||||
| 	theme/close-window.svg			\ | ||||
| 	theme/close.svg				\ | ||||
| 	theme/corner-ripple-ltr.png		\ | ||||
| 	theme/corner-ripple-rtl.png		\ | ||||
| 	theme/corner-ripple.png			\ | ||||
| 	theme/dash-placeholder.svg		\ | ||||
| 	theme/filter-selected-ltr.svg		\ | ||||
| 	theme/filter-selected-rtl.svg		\ | ||||
| 	theme/gdm.css				\ | ||||
| 	theme/dialog-error.svg			\ | ||||
| 	theme/gnome-shell.css			\ | ||||
| 	theme/panel-border.svg			\ | ||||
| 	theme/panel-button-border.svg		\ | ||||
| 	theme/panel-button-highlight-narrow.svg	\ | ||||
| 	theme/panel-button-highlight-wide.svg	\ | ||||
| 	theme/process-working.svg		\ | ||||
| 	theme/mosaic-view-active.svg		\ | ||||
| 	theme/mosaic-view.svg			\ | ||||
| 	theme/move-window-on-new.svg		\ | ||||
| 	theme/process-working.png		\ | ||||
| 	theme/remove-workspace.svg		\ | ||||
| 	theme/running-indicator.svg		\ | ||||
| 	theme/scroll-button-down-hover.png	\ | ||||
| 	theme/scroll-button-down.png		\ | ||||
| 	theme/scroll-button-up-hover.png	\ | ||||
| 	theme/scroll-button-up.png		\ | ||||
| 	theme/scroll-hhandle.svg		\ | ||||
| 	theme/scroll-vhandle.svg		\ | ||||
| 	theme/source-button-border.svg		\ | ||||
| 	theme/section-more.svg			\ | ||||
| 	theme/section-more-open.svg		\ | ||||
| 	theme/separator-white.png		\ | ||||
| 	theme/single-view-active.svg		\ | ||||
| 	theme/single-view.svg			\ | ||||
| 	theme/toggle-off-us.svg			\ | ||||
| 	theme/toggle-off-intl.svg		\ | ||||
| 	theme/toggle-on-us.svg			\ | ||||
| 	theme/toggle-on-intl.svg		\ | ||||
| 	theme/ws-switch-arrow-up.svg		\ | ||||
| 	theme/ws-switch-arrow-down.svg | ||||
| 	theme/ws-switch-arrow-left.svg		\ | ||||
| 	theme/ws-switch-arrow-right.svg | ||||
|  | ||||
| gsettings_SCHEMAS = org.gnome.shell.gschema.xml | ||||
| gsettings_SCHEMAS =					\ | ||||
| 	org.gnome.accessibility.magnifier.gschema.xml	\ | ||||
| 	org.gnome.shell.gschema.xml | ||||
|  | ||||
| @INTLTOOL_XML_NOMERGE_RULE@ | ||||
| @GSETTINGS_RULES@ | ||||
| @@ -64,6 +71,11 @@ all-local: gschemas.compiled | ||||
| gconfschemadir  = @GCONF_SCHEMA_FILE_DIR@ | ||||
| gconfschema_DATA = gnome-shell.schemas | ||||
|  | ||||
| menudir = $(sysconfdir)/xdg/menus | ||||
|  | ||||
| menu_DATA = \ | ||||
| 	gs-applications.menu | ||||
|  | ||||
| shadersdir = $(pkgdatadir)/shaders | ||||
| shaders_DATA = \ | ||||
| 	shaders/dim-window.glsl | ||||
| @@ -75,13 +87,16 @@ install-data-local: | ||||
|  | ||||
| EXTRA_DIST =						\ | ||||
| 	gnome-shell.desktop.in.in			\ | ||||
| 	gnome-shell-clock-preferences.desktop.in.in	\ | ||||
| 	$(menu_DATA)					\ | ||||
| 	$(gconfschema_DATA)				\ | ||||
| 	$(shaders_DATA)					\ | ||||
| 	org.gnome.accessibility.magnifier.gschema.xml.in \ | ||||
| 	org.gnome.shell.gschema.xml.in | ||||
|  | ||||
| CLEANFILES =						\ | ||||
| 	gnome-shell.desktop.in				\ | ||||
| 	gnome-shell-clock-preferences.desktop.in	\ | ||||
| 	$(desktop_DATA)					\ | ||||
| 	$(gsettings_SCHEMAS)				\ | ||||
| 	gschemas.compiled | ||||
|   | ||||
							
								
								
									
										188
									
								
								data/clock-preferences.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,188 @@ | ||||
| <?xml version="1.0"?> | ||||
| <interface domain="gnome-shell"> | ||||
|   <requires lib="gtk+" version="2.16"/> | ||||
|   <!-- interface-naming-policy project-wide --> | ||||
|   <object class="GtkDialog" id="prefs-dialog"> | ||||
|     <property name="border_width">5</property> | ||||
|     <property name="title" translatable="yes">Clock Preferences</property> | ||||
|     <property name="window_position">center</property> | ||||
|     <property name="type_hint">normal</property> | ||||
|     <property name="has_separator">False</property> | ||||
|     <child internal-child="vbox"> | ||||
|       <object class="GtkVBox" id="dialog-vbox1"> | ||||
|         <property name="visible">True</property> | ||||
|         <property name="orientation">vertical</property> | ||||
|         <property name="spacing">2</property> | ||||
|         <child> | ||||
|           <object class="GtkVBox" id="vbox1"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="orientation">vertical</property> | ||||
|             <property name="spacing">18</property> | ||||
|             <child> | ||||
|               <object class="GtkFrame" id="frame1"> | ||||
|                 <property name="visible">True</property> | ||||
|                 <property name="label_xalign">0</property> | ||||
|                 <property name="shadow_type">none</property> | ||||
|                 <child> | ||||
|                   <object class="GtkAlignment" id="alignment1"> | ||||
|                     <property name="visible">True</property> | ||||
|                     <property name="top_padding">6</property> | ||||
|                     <property name="left_padding">12</property> | ||||
|                     <property name="right_padding">6</property> | ||||
|                     <child> | ||||
|                       <object class="GtkHBox" id="hbox1"> | ||||
|                         <property name="visible">True</property> | ||||
|                         <property name="spacing">12</property> | ||||
|                         <child> | ||||
|                           <object class="GtkRadioButton" id="12hr_radio"> | ||||
|                             <property name="label" translatable="yes">_12 hour format</property> | ||||
|                             <property name="visible">True</property> | ||||
|                             <property name="can_focus">True</property> | ||||
|                             <property name="receives_default">False</property> | ||||
|                             <property name="use_underline">True</property> | ||||
|                             <property name="draw_indicator">True</property> | ||||
|                           </object> | ||||
|                           <packing> | ||||
|                             <property name="expand">False</property> | ||||
|                             <property name="fill">False</property> | ||||
|                             <property name="position">0</property> | ||||
|                           </packing> | ||||
|                         </child> | ||||
|                         <child> | ||||
|                           <object class="GtkRadioButton" id="24hr_radio"> | ||||
|                             <property name="label" translatable="yes">_24 hour format</property> | ||||
|                             <property name="visible">True</property> | ||||
|                             <property name="can_focus">True</property> | ||||
|                             <property name="receives_default">False</property> | ||||
|                             <property name="use_underline">True</property> | ||||
|                             <property name="draw_indicator">True</property> | ||||
|                             <property name="group">12hr_radio</property> | ||||
|                           </object> | ||||
|                           <packing> | ||||
|                             <property name="expand">False</property> | ||||
|                             <property name="fill">False</property> | ||||
|                             <property name="position">1</property> | ||||
|                           </packing> | ||||
|                         </child> | ||||
|                       </object> | ||||
|                     </child> | ||||
|                   </object> | ||||
|                 </child> | ||||
|                 <child type="label"> | ||||
|                   <object class="GtkLabel" id="label_format"> | ||||
|                     <property name="visible">True</property> | ||||
|                     <property name="label" translatable="yes">Clock Format</property> | ||||
|                     <attributes> | ||||
|                       <attribute name="weight" value="bold"/> | ||||
|                     </attributes> | ||||
|                   </object> | ||||
|                 </child> | ||||
|               </object> | ||||
|               <packing> | ||||
|                 <property name="expand">False</property> | ||||
|                 <property name="fill">False</property> | ||||
|                 <property name="position">0</property> | ||||
|               </packing> | ||||
|             </child> | ||||
|             <child> | ||||
|               <object class="GtkFrame" id="frame2"> | ||||
|                 <property name="visible">True</property> | ||||
|                 <property name="label_xalign">0</property> | ||||
|                 <property name="shadow_type">none</property> | ||||
|                 <child> | ||||
|                   <object class="GtkAlignment" id="alignment2"> | ||||
|                     <property name="visible">True</property> | ||||
|                     <property name="top_padding">6</property> | ||||
|                     <property name="left_padding">12</property> | ||||
|                     <child> | ||||
|                       <object class="GtkVBox" id="vbox2"> | ||||
|                         <property name="visible">True</property> | ||||
|                         <property name="orientation">vertical</property> | ||||
|                         <property name="spacing">6</property> | ||||
|                         <child> | ||||
|                           <object class="GtkCheckButton" id="date_check"> | ||||
|                             <property name="label" translatable="yes">Show the _date</property> | ||||
|                             <property name="visible">True</property> | ||||
|                             <property name="can_focus">True</property> | ||||
|                             <property name="receives_default">False</property> | ||||
|                             <property name="use_underline">True</property> | ||||
|                             <property name="draw_indicator">True</property> | ||||
|                           </object> | ||||
|                           <packing> | ||||
|                             <property name="position">0</property> | ||||
|                           </packing> | ||||
|                         </child> | ||||
|                         <child> | ||||
|                           <object class="GtkCheckButton" id="seconds_check"> | ||||
|                             <property name="label" translatable="yes">Show seco_nds</property> | ||||
|                             <property name="visible">True</property> | ||||
|                             <property name="can_focus">True</property> | ||||
|                             <property name="receives_default">False</property> | ||||
|                             <property name="use_underline">True</property> | ||||
|                             <property name="draw_indicator">True</property> | ||||
|                           </object> | ||||
|                           <packing> | ||||
|                             <property name="position">1</property> | ||||
|                           </packing> | ||||
|                         </child> | ||||
|                       </object> | ||||
|                     </child> | ||||
|                   </object> | ||||
|                 </child> | ||||
|                 <child type="label"> | ||||
|                   <object class="GtkLabel" id="label_display"> | ||||
|                     <property name="visible">True</property> | ||||
|                     <property name="label" translatable="yes">Panel Display</property> | ||||
|                     <attributes> | ||||
|                       <attribute name="weight" value="bold"/> | ||||
|                     </attributes> | ||||
|                   </object> | ||||
|                 </child> | ||||
|               </object> | ||||
|               <packing> | ||||
|                 <property name="expand">False</property> | ||||
|                 <property name="fill">False</property> | ||||
|                 <property name="position">1</property> | ||||
|               </packing> | ||||
|             </child> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="padding">6</property> | ||||
|             <property name="position">1</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|         <child internal-child="action_area"> | ||||
|           <object class="GtkHButtonBox" id="dialog-action_area1"> | ||||
|             <property name="visible">True</property> | ||||
|             <property name="layout_style">end</property> | ||||
|             <child> | ||||
|               <placeholder/> | ||||
|             </child> | ||||
|             <child> | ||||
|               <object class="GtkButton" id="prefs_close_button"> | ||||
|                 <property name="label">gtk-close</property> | ||||
|                 <property name="visible">True</property> | ||||
|                 <property name="can_focus">True</property> | ||||
|                 <property name="receives_default">True</property> | ||||
|                 <property name="use_stock">True</property> | ||||
|               </object> | ||||
|               <packing> | ||||
|                 <property name="expand">False</property> | ||||
|                 <property name="fill">False</property> | ||||
|                 <property name="position">1</property> | ||||
|               </packing> | ||||
|             </child> | ||||
|           </object> | ||||
|           <packing> | ||||
|             <property name="expand">False</property> | ||||
|             <property name="pack_type">end</property> | ||||
|             <property name="position">0</property> | ||||
|           </packing> | ||||
|         </child> | ||||
|       </object> | ||||
|     </child> | ||||
|     <action-widgets> | ||||
|       <action-widget response="0">prefs_close_button</action-widget> | ||||
|     </action-widgets> | ||||
|   </object> | ||||
| </interface> | ||||
							
								
								
									
										66
									
								
								data/close-black.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,66 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    version="1.1" | ||||
|    id="Foreground" | ||||
|    x="0px" | ||||
|    y="0px" | ||||
|    width="16px" | ||||
|    height="16px" | ||||
|    viewBox="0 0 16 16" | ||||
|    enable-background="new 0 0 16 16" | ||||
|    xml:space="preserve" | ||||
|    sodipodi:version="0.32" | ||||
|    inkscape:version="0.46+devel" | ||||
|    sodipodi:docname="close-black.svg" | ||||
|    inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata | ||||
|    id="metadata2399"><rdf:RDF><cc:Work | ||||
|        rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type | ||||
|          rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs | ||||
|    id="defs2397"><linearGradient | ||||
|      id="linearGradient3173"><stop | ||||
|        style="stop-color:#c4c4c4;stop-opacity:1;" | ||||
|        offset="0" | ||||
|        id="stop3175" /><stop | ||||
|        style="stop-color:#ffffff;stop-opacity:1;" | ||||
|        offset="1" | ||||
|        id="stop3177" /></linearGradient><inkscape:perspective | ||||
|      sodipodi:type="inkscape:persp3d" | ||||
|      inkscape:vp_x="0 : 8 : 1" | ||||
|      inkscape:vp_y="0 : 1000 : 0" | ||||
|      inkscape:vp_z="16 : 8 : 1" | ||||
|      inkscape:persp3d-origin="8 : 5.3333333 : 1" | ||||
|      id="perspective2401" /></defs><sodipodi:namedview | ||||
|    inkscape:window-height="811" | ||||
|    inkscape:window-width="1272" | ||||
|    inkscape:pageshadow="2" | ||||
|    inkscape:pageopacity="0.0" | ||||
|    guidetolerance="10.0" | ||||
|    gridtolerance="10.0" | ||||
|    objecttolerance="10.0" | ||||
|    borderopacity="1.0" | ||||
|    bordercolor="#666666" | ||||
|    pagecolor="#ffffff" | ||||
|    id="base" | ||||
|    showgrid="false" | ||||
|    inkscape:zoom="32.125" | ||||
|    inkscape:cx="8" | ||||
|    inkscape:cy="10.440056" | ||||
|    inkscape:window-x="40" | ||||
|    inkscape:window-y="40" | ||||
|    inkscape:current-layer="Foreground" /> | ||||
| <path | ||||
|    fill-rule="evenodd" | ||||
|    clip-rule="evenodd" | ||||
|    d="M10.5,3.5l2,2L10,8l2.5,2.5l-2,2L8,10l-2.5,2.5l-2-2L6,8L3.5,5.5l2-2L8,6L10.5,3.5  z M0,8c0-4.418,3.582-8,8-8s8,3.582,8,8s-3.582,8-8,8S0,12.418,0,8z" | ||||
|    id="path2394" | ||||
|    style="fill-opacity:1;fill:#545454" /> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.3 KiB | 
							
								
								
									
										15
									
								
								data/gnome-shell-clock-preferences.desktop.in.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | ||||
| [Desktop Entry] | ||||
| _Name=Clock | ||||
| _Comment=Customize the panel clock | ||||
| Exec=@bindir@/gnome-shell-clock-preferences | ||||
| Icon=gnome-panel-clock | ||||
| Terminal=false | ||||
| Type=Application | ||||
| StartupNotify=true | ||||
| Categories=GNOME;GTK;Settings;DesktopSettings; | ||||
| OnlyShowIn=GNOME; | ||||
| X-GNOME-ShellOnly=true | ||||
| X-GNOME-Bugzilla-Bugzilla=GNOME | ||||
| X-GNOME-Bugzilla-Product=gnome-shell | ||||
| X-GNOME-Bugzilla-Component=general | ||||
| X-GNOME-Bugzilla-Version=@VERSION@ | ||||
| @@ -7,10 +7,9 @@ X-GNOME-Bugzilla-Bugzilla=GNOME | ||||
| X-GNOME-Bugzilla-Product=gnome-shell | ||||
| X-GNOME-Bugzilla-Component=general | ||||
| X-GNOME-Bugzilla-Version=@VERSION@ | ||||
| Categories=GNOME;GTK;Core; | ||||
| Categories=GNOME;GTK;Utility;Core; | ||||
| OnlyShowIn=GNOME; | ||||
| NoDisplay=true | ||||
| X-GNOME-Autostart-Phase=WindowManager | ||||
| X-GNOME-Provides=panel;windowmanager; | ||||
| X-GNOME-Autostart-Notify=true | ||||
| X-GNOME-AutoRestart=true | ||||
|   | ||||
| @@ -22,7 +22,7 @@ | ||||
|         <applyto>/desktop/gnome/shell/windows/button_layout</applyto> | ||||
|         <owner>gnome-shell</owner> | ||||
|         <type>string</type> | ||||
|         <default>:close</default> | ||||
|         <default>:minimize,maximize,close</default> | ||||
|         <locale name="C"> | ||||
|            <short>Arrangement of buttons on the titlebar</short> | ||||
|            <long> | ||||
| @@ -44,20 +44,19 @@ | ||||
|       </schema> | ||||
|  | ||||
|       <schema> | ||||
|         <key>/schemas/desktop/gnome/shell/windows/edge_tiling</key> | ||||
|         <applyto>/desktop/gnome/shell/windows/edge_tiling</applyto> | ||||
|         <key>/schemas/desktop/gnome/shell/windows/side_by_side_tiling</key> | ||||
|         <applyto>/desktop/gnome/shell/windows/side_by_side_tiling</applyto> | ||||
|         <owner>gnome-shell</owner> | ||||
|         <type>bool</type> | ||||
|         <default>true</default> | ||||
|         <locale name="C"> | ||||
|           <short>enable edge tiling when dropping windows on screen edges</short> | ||||
|           <short>enable side-by-side tiling when dropping windows on screen edges</short> | ||||
|           <long> | ||||
|              If enabled, dropping windows on vertical screen edges maximizes them | ||||
|              If enabled, dropping windows on screen edges maximizes them | ||||
|              vertically and resizes them horizontally to cover half of the | ||||
|              available area. Dropping windows on the top screen edge maximizes them | ||||
|              completely. | ||||
|              available area. | ||||
|  | ||||
|              This key overrides /apps/metacity/general/edge_tiling when | ||||
|              This key overrides /apps/metacity/general/side_by_side_tiling when | ||||
|              running GNOME Shell. | ||||
|           </long> | ||||
|         </locale> | ||||
| @@ -81,20 +80,5 @@ | ||||
|         </locale> | ||||
|       </schema> | ||||
|  | ||||
|       <schema> | ||||
|         <key>/schemas/desktop/gnome/shell/windows/workspaces_only_on_primary</key> | ||||
|         <applyto>/desktop/gnome/shell/windows/workspaces_only_on_primary</applyto> | ||||
|         <owner>gnome-shell</owner> | ||||
|         <type>bool</type> | ||||
|         <default>true</default> | ||||
|         <locale name="C"> | ||||
|           <short>Workspaces only on primary monitor</short> | ||||
|           <long> | ||||
|              This key overrides /apps/mutter/general/workspaces_only_on_primary when | ||||
|              running GNOME Shell. | ||||
|           </long> | ||||
|         </locale> | ||||
|       </schema> | ||||
|  | ||||
|   </schemalist> | ||||
| </gconfschemafile> | ||||
|   | ||||
							
								
								
									
										45
									
								
								data/gs-applications.menu
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,45 @@ | ||||
| <Menu> | ||||
|     <DefaultLayout> | ||||
|         <Menuname>Apps</Menuname> | ||||
|         <Menuname>Games</Menuname> | ||||
|         <Menuname>Tools</Menuname> | ||||
|     </DefaultLayout> | ||||
| 	<Name>Applications</Name> | ||||
| 	<AppDir>/usr/local/share/applications</AppDir> | ||||
| 	<DefaultAppDirs/> | ||||
| 	<Menu> | ||||
| 		<Name>Games</Name> | ||||
| 		<Include> | ||||
| 			<And> | ||||
| 				<Category>Game</Category> | ||||
| 			</And> | ||||
| 		</Include> | ||||
| 	</Menu> | ||||
| 	<Menu> | ||||
| 		<Name>Tools</Name> | ||||
| 		<Include> | ||||
| 			<Category>Development</Category> | ||||
| 			<And> | ||||
| 				<Category>System</Category> | ||||
| 				<Not> | ||||
| 					<Category>Settings</Category> | ||||
| 				</Not> | ||||
| 			</And> | ||||
| 			<Category>Utility</Category> | ||||
| 		</Include> | ||||
| 	</Menu> | ||||
| 	<Menu> | ||||
| 		<Name>Apps</Name> | ||||
| 		<OnlyUnallocated/> | ||||
| 		<Include> | ||||
| 			<And> | ||||
| 				<Or> | ||||
| 					<Category>Documentation</Category> | ||||
| 					<Not><Category>Core</Category></Not> | ||||
| 				</Or> | ||||
| 				<Not><Category>Settings</Category></Not> | ||||
| 				<Not><Category>Screensaver</Category></Not> | ||||
| 			</And> | ||||
| 		</Include> | ||||
| 	</Menu> | ||||
| </Menu> | ||||
							
								
								
									
										80
									
								
								data/magnifier.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,80 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    version="1.0" | ||||
|    id="Foreground" | ||||
|    x="0px" | ||||
|    y="0px" | ||||
|    width="18" | ||||
|    height="18" | ||||
|    viewBox="0 0 18 18" | ||||
|    enable-background="new 0 0 29 18" | ||||
|    xml:space="preserve" | ||||
|    sodipodi:version="0.32" | ||||
|    inkscape:version="0.46+devel" | ||||
|    sodipodi:docname="magnifier.svg" | ||||
|    inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata | ||||
|    id="metadata16"><rdf:RDF><cc:Work | ||||
|        rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type | ||||
|          rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs | ||||
|    id="defs14"><inkscape:perspective | ||||
|      sodipodi:type="inkscape:persp3d" | ||||
|      inkscape:vp_x="0 : 9 : 1" | ||||
|      inkscape:vp_y="0 : 1000 : 0" | ||||
|      inkscape:vp_z="29 : 9 : 1" | ||||
|      inkscape:persp3d-origin="14.5 : 6 : 1" | ||||
|      id="perspective18" /></defs><sodipodi:namedview | ||||
|    inkscape:window-height="728" | ||||
|    inkscape:window-width="1103" | ||||
|    inkscape:pageshadow="2" | ||||
|    inkscape:pageopacity="1" | ||||
|    guidetolerance="10.0" | ||||
|    gridtolerance="10.0" | ||||
|    objecttolerance="10.0" | ||||
|    borderopacity="1.0" | ||||
|    bordercolor="#666666" | ||||
|    pagecolor="#000000" | ||||
|    id="base" | ||||
|    showgrid="true" | ||||
|    inkscape:zoom="27.260185" | ||||
|    inkscape:cx="9.5844061" | ||||
|    inkscape:cy="9.4435574" | ||||
|    inkscape:window-x="142" | ||||
|    inkscape:window-y="26" | ||||
|    inkscape:current-layer="Foreground" | ||||
|    inkscape:snap-global="true" | ||||
|    showguides="false"><inkscape:grid | ||||
|      type="xygrid" | ||||
|      id="grid2391" | ||||
|      empspacing="5" | ||||
|      visible="true" | ||||
|      enabled="true" | ||||
|      snapvisiblegridlinesonly="true" /></sodipodi:namedview> | ||||
|  | ||||
| <g | ||||
|    id="g5" | ||||
|    style="fill:#ffffff;fill-opacity:1" | ||||
|    transform="translate(-4,-0.023114)"> | ||||
| 	<path | ||||
|    d="m 6.246,13.98 c -0.319,-0.319 -0.319,-0.837 0,-1.157 L 9.963,9.106 c 0.319,-0.319 0.837,-0.319 1.157,0 l 0.786,0.787 c 0.32,0.319 0.32,0.837 0,1.157 l -3.717,3.717 c -0.32,0.319 -0.838,0.319 -1.157,0 l -0.786,-0.787 0,0 z" | ||||
|    id="path7" | ||||
|    style="fill:#ffffff;fill-opacity:1" /> | ||||
| 	<path | ||||
|    d="M 9.076,11.937" | ||||
|    id="path9" | ||||
|    style="fill:#ffffff;fill-opacity:1" /> | ||||
| </g> | ||||
| <path | ||||
|    clip-rule="evenodd" | ||||
|    d="m 7.25,7.476886 c 0,-1.243 1.007,-2.25 2.2499998,-2.25 1.2430002,0 2.2500002,1.007 2.2500002,2.25 0,1.243 -1.007,2.25 -2.2500002,2.25 C 8.257,9.726886 7.25,8.719886 7.25,7.476886 z m -2.25,0 c 0,-2.485 2.015,-4.5 4.4999998,-4.5 2.4850002,0 4.5000002,2.015 4.5000002,4.5 0,2.4849998 -2.015,4.5 -4.5000002,4.5 C 7.015,11.976886 5,9.9618858 5,7.476886 z" | ||||
|    id="path11" | ||||
|    style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd" /> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.9 KiB | 
							
								
								
									
										133
									
								
								data/org.gnome.accessibility.magnifier.gschema.xml.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,133 @@ | ||||
| <schemalist> | ||||
|  | ||||
|   <enum id="MouseTrackingMode"> | ||||
|     <value nick="none"         value="0"/> | ||||
|     <value nick="centered"     value="1"/> | ||||
|     <value nick="proportional" value="2"/> | ||||
|     <value nick="push"         value="3"/> | ||||
|   </enum> | ||||
|  | ||||
|   <enum id="ScreenPosition"> | ||||
|     <value nick="none"        value="0"/> | ||||
|     <value nick="full-screen" value="1"/> | ||||
|     <value nick="top-half"    value="2"/> | ||||
|     <value nick="bottom-half" value="3"/> | ||||
|     <value nick="left-half"   value="4"/> | ||||
|     <value nick="right-half"  value="5"/> | ||||
|   </enum> | ||||
|  | ||||
|   <schema id="org.gnome.accessibility.magnifier" | ||||
|           path="/desktop/gnome/accessibility/magnifier/" | ||||
|           gettext-domain="@GETTEXT_PACKAGE@"> | ||||
|     <key name="show-magnifier" type="b"> | ||||
|       <default>false</default> | ||||
|       <_summary>Show or hide the magnifier</_summary> | ||||
|       <_description> | ||||
|         Show or hide the magnifier and all of its zoom regions. | ||||
|       </_description> | ||||
|     </key> | ||||
|     <key name="mouse-tracking" enum="MouseTrackingMode"> | ||||
|       <default>'proportional'</default> | ||||
|       <_summary>Mouse Tracking Mode</_summary> | ||||
|       <_description> | ||||
|         Determines the position of the magnified mouse image within the | ||||
|         magnified view and how it reacts to system mouse movement. The values | ||||
|         are | ||||
|         - none: no mouse tracking; | ||||
|         - centered: the mouse image is | ||||
|         displayed at the center of the zoom region (which also represents | ||||
|         the point under the system mouse) and the magnified contents are | ||||
|         scrolled as the system mouse moves; | ||||
|         - proportional: the position of the magnified mouse in the zoom region | ||||
|         is proportionally the same as the position of the system mouse on screen; | ||||
|         - push: when the magnified mouse intersects a boundary of the zoom | ||||
|         region, the contents are scrolled into view. | ||||
|       </_description> | ||||
|     </key> | ||||
|     <key name="screen-position" enum="ScreenPosition"> | ||||
|       <default>'full-screen'</default> | ||||
|       <_summary>Screen position</_summary> | ||||
|       <_description> | ||||
|         The magnified view either fills the entire screen, or occupies the | ||||
|         top-half, bottom-half, left-half, or right-half of the screen. | ||||
|       </_description> | ||||
|     </key> | ||||
|     <key name="mag-factor" type="d"> | ||||
|       <default>2.0</default> | ||||
|       <_summary>Magnification factor</_summary> | ||||
|       <_description> | ||||
|         The power of the magnification. A value of 1.0 means no magnification. | ||||
|         A value of 2.0 doubles the size. | ||||
|       </_description> | ||||
|     </key> | ||||
|     <key name="lens-mode" type="b"> | ||||
|       <default>false</default> | ||||
|       <_summary>Enable lens mode</_summary> | ||||
|       <_description> | ||||
|         Whether the magnified view should be centered over the location of | ||||
|         the system mouse and move with it. | ||||
|       </_description> | ||||
|     </key> | ||||
|     <key name="scroll-at-edges" type="b"> | ||||
|       <default>false</default> | ||||
|       <_summary> | ||||
|         Scroll magnified contents beyond the edges of the desktop | ||||
|       </_summary> | ||||
|       <_description> | ||||
|         For centered mouse tracking, when the system pointer is at or near the | ||||
|         edge of the screen, the magnified contents continue to scroll such that | ||||
|         the screen edge moves into the magnified view. | ||||
|       </_description> | ||||
|     </key> | ||||
|  | ||||
|     <!-- Cross-hairs --> | ||||
|     <key name="show-cross-hairs" type="b"> | ||||
|       <default>false</default> | ||||
|       <_summary>Show or hide crosshairs</_summary> | ||||
|       <_description> | ||||
|         Enables/disables display of crosshairs centered on the magnified | ||||
|         mouse sprite. | ||||
|       </_description> | ||||
|     </key> | ||||
|     <key name="cross-hairs-thickness" type="i"> | ||||
|       <default>8</default> | ||||
|       <_summary>Thickness of the crosshairs</_summary> | ||||
|       <_description> | ||||
|         Width of the vertical and horizontal lines that make up the crosshairs. | ||||
|       </_description> | ||||
|     </key> | ||||
|     <key name="cross-hairs-color" type="s"> | ||||
|       <default>'#ff0000'</default> | ||||
|       <_summary>Color of the crosshairs</_summary> | ||||
|       <_description> | ||||
|         The color of the the vertical and horizontal lines that make up | ||||
|         the crosshairs. | ||||
|       </_description> | ||||
|     </key> | ||||
|     <key name="cross-hairs-opacity" type="i"> | ||||
|       <default>169</default> | ||||
|       <_summary>Opacity of the crosshairs</_summary> | ||||
|       <_description> | ||||
|         Determines the transparency of the crosshairs, from fully opaque | ||||
|         to fully transparent. | ||||
|       </_description> | ||||
|     </key> | ||||
|     <key name="cross-hairs-length" type="i"> | ||||
|       <default>4096</default> | ||||
|       <_summary>Length of the crosshairs</_summary> | ||||
|       <_description> | ||||
|         Determines the length of the vertical and horizontal lines that | ||||
|         make up the crosshairs. | ||||
|       </_description> | ||||
|     </key> | ||||
|     <key name="cross-hairs-clip" type="b"> | ||||
|       <default>false</default> | ||||
|       <_summary>Clip the crosshairs at the center</_summary> | ||||
|       <_description> | ||||
|         Determines whether the crosshairs intersect the magnified mouse sprite, | ||||
|         or are clipped such that the ends of the horizontal and vertical lines | ||||
|         surround the mouse image. | ||||
|       </_description> | ||||
|     </key> | ||||
|   </schema> | ||||
| </schemalist> | ||||
| @@ -1,5 +1,5 @@ | ||||
| <schemalist> | ||||
|   <schema id="org.gnome.shell" path="/org/gnome/shell/" | ||||
|   <schema id="org.gnome.shell" path="/apps/gnome-shell/" | ||||
|           gettext-domain="@GETTEXT_PACKAGE@"> | ||||
|     <key name="development-tools" type="b"> | ||||
|       <default>true</default> | ||||
| @@ -11,13 +11,12 @@ | ||||
|         using the Alt-F2 dialog. | ||||
|       </_description> | ||||
|     </key> | ||||
|     <key name="enabled-extensions" type="as"> | ||||
|     <key name="disabled-extensions" type="as"> | ||||
|       <default>[]</default> | ||||
|       <_summary>Uuids of extensions to enable</_summary> | ||||
|       <_summary>Uuids of extensions to disable</_summary> | ||||
|       <_description> | ||||
|         GNOME Shell extensions have a uuid property; this key lists extensions | ||||
|         which should be loaded.  disabled-extensions overrides this setting for | ||||
|         extensions that appear in both lists. | ||||
|         GNOME Shell extensions have a uuid property; | ||||
|         this key lists extensions which should not be loaded. | ||||
|       </_description> | ||||
|     </key> | ||||
|     <key name="enable-app-monitoring" type="b"> | ||||
| @@ -31,32 +30,23 @@ | ||||
|       </_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> | ||||
|       <default>[ 'mozilla-firefox.desktop', 'evolution.desktop', 'openoffice.org-writer.desktop' ]</default> | ||||
|       <_summary>List of desktop file IDs for favorite applications</_summary> | ||||
|       <_description> | ||||
|         The applications corresponding to these identifiers | ||||
|         will be displayed in the favorites area. | ||||
|       </_description> | ||||
|     </key> | ||||
|     <key name="disabled-open-search-providers" type="as"> | ||||
|       <default>[]</default> | ||||
|       <_summary>disabled OpenSearch providers</_summary> | ||||
|     </key> | ||||
|     <key name="command-history" type="as"> | ||||
|       <default>[]</default> | ||||
|       <_summary>History for command (Alt-F2) dialog</_summary> | ||||
|     </key> | ||||
|     <key name="looking-glass-history" type="as"> | ||||
|       <default>[]</default> | ||||
|       <_summary>History for the looking glass dialog</_summary> | ||||
|     </key> | ||||
|     <child name="clock" schema="org.gnome.shell.clock"/> | ||||
|     <child name="calendar" schema="org.gnome.shell.calendar"/> | ||||
|     <child name="recorder" schema="org.gnome.shell.recorder"/> | ||||
|     <child name="keyboard" schema="org.gnome.shell.keyboard"/> | ||||
|   </schema> | ||||
|  | ||||
|   <schema id="org.gnome.shell.calendar" path="/org/gnome/shell/calendar/" | ||||
|   <schema id="org.gnome.shell.calendar" path="/apps/gnome-shell/calendar/" | ||||
|           gettext-domain="@GETTEXT_PACKAGE@"> | ||||
|     <key name="show-weekdate" type="b"> | ||||
|       <default>false</default> | ||||
| @@ -67,43 +57,58 @@ | ||||
|       </key> | ||||
|   </schema> | ||||
|  | ||||
|   <schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/" | ||||
|   <schema id="org.gnome.shell.clock" path="/apps/gnome-shell/clock/" | ||||
|           gettext-domain="@GETTEXT_PACKAGE@"> | ||||
|     <key name="show-keyboard" type="b"> | ||||
|       <default>false</default> | ||||
|       <_summary>Show the onscreen keyboard</_summary> | ||||
|     <key name="format" type="s"> | ||||
|       <default l10n="messages" context="hour_format"> | ||||
|       <!-- TRANSLATORS: This is the default hour format, choose ONLY '12-hour' or '24-hour'. --> | ||||
|         "12-hour" | ||||
|       </default> | ||||
|       <_summary>Hour format</_summary> | ||||
|       <_description> | ||||
|         If true, display onscreen keyboard. | ||||
|         This key specifies the hour format used by the panel clock. | ||||
|         Possible values are "12-hour", "24-hour", "unix" and "custom". If set | ||||
|         to "unix", the clock will display time in seconds since Epoch, | ||||
|         i.e. 1970-01-01. If set to "custom", the clock will display time | ||||
|         according to the format specified in the custom_format key. Note that | ||||
|         if set to either "unix" or "custom", the show_date and show_seconds | ||||
|         keys are ignored. | ||||
|       </_description> | ||||
|       <choices> | ||||
|         <choice value="12-hour"/> | ||||
|         <choice value="24-hour"/> | ||||
|         <choice value="unix"/> | ||||
|         <choice value="custom"/> | ||||
|       </choices> | ||||
|     </key> | ||||
|     <key name="custom-format" type="s"> | ||||
|       <default>''</default> | ||||
|       <_summary>Custom format of the clock</_summary> | ||||
|       <_description> | ||||
|         This key specifies the format used by the panel clock when the format | ||||
|         key is set to "custom". You can use conversion specifiers understood | ||||
|         by strftime() to obtain a specific format. See the strftime() manual | ||||
|         for more information. | ||||
|       </_description> | ||||
|     </key> | ||||
|     <key name="keyboard-type" type="s"> | ||||
|       <default>'touch'</default> | ||||
|       <_summary>Which keyboard to use</_summary> | ||||
|       <_description> | ||||
|         The type of keyboard to use. | ||||
|       </_description> | ||||
|     </key> | ||||
|   </schema> | ||||
|  | ||||
|   <schema id="org.gnome.shell.clock" path="/org/gnome/shell/clock/" | ||||
|           gettext-domain="@GETTEXT_PACKAGE@"> | ||||
|     <key name="show-seconds" type="b"> | ||||
|       <default>false</default> | ||||
|       <_summary>Show time with seconds</_summary> | ||||
|       <_description> | ||||
|         If true, display seconds in time. | ||||
|         If true and format is either "12-hour" or "24-hour", display seconds in time. | ||||
|       </_description> | ||||
|     </key> | ||||
|     <key name="show-date" type="b"> | ||||
|       <default>false</default> | ||||
|       <_summary>Show date in clock</_summary> | ||||
|       <_description> | ||||
|         If true, display date in the clock, in addition to time. | ||||
|         If true and format is either "12-hour" or "24-hour", | ||||
|         display date in the clock, in addition to time. | ||||
|       </_description> | ||||
|     </key> | ||||
|   </schema> | ||||
|  | ||||
|   <schema id="org.gnome.shell.recorder" path="/org/gnome/shell/recorder/" | ||||
|   <schema id="org.gnome.shell.recorder" path="/apps/gnome-shell/recorder/" | ||||
|           gettext-domain="@GETTEXT_PACKAGE@"> | ||||
|     <key name="framerate" type="i"> | ||||
|       <default>15</default> | ||||
| @@ -125,13 +130,11 @@ | ||||
|         take care of its own output - this might be used to send the output | ||||
|         to an icecast server via shout2send or similar. When unset or set | ||||
|         to an empty value, the default pipeline will be used. This is currently | ||||
|         'videorate ! vp8enc quality=10 speed=2 threads=%T ! queue ! webmmux' | ||||
|         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. | ||||
|         'videorate ! theoraenc ! oggmux' and records to Ogg Theora. | ||||
|       </_description> | ||||
|     </key> | ||||
|     <key name="file-extension" type="s"> | ||||
|       <default>'webm'</default> | ||||
|       <default>'ogv'</default> | ||||
|       <_summary>File extension used for storing the screencast</_summary> | ||||
|       <_description> | ||||
|         The filename for recorded screencasts will be a unique filename | ||||
|   | ||||
| @@ -1,7 +0,0 @@ | ||||
| <OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"> | ||||
| <ShortName>Google</ShortName> | ||||
| <Description>Google Search</Description> | ||||
| <InputEncoding>UTF-8</InputEncoding> | ||||
| <Image width="16" height="16">data:image/x-icon;base64,AAABAAEAEBAAAAEAGABoAwAAFgAAACgAAAAQAAAAIAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs9Pt8xetPtu9FsfFNtu%2BTzvb2%2B%2Fne4dFJeBw0egA%2FfAJAfAA8ewBBegAAAAD%2B%2FPtft98Mp%2BwWsfAVsvEbs%2FQeqvF8xO7%2F%2F%2F63yqkxdgM7gwE%2FggM%2BfQA%2BegBDeQDe7PIbotgQufcMufEPtfIPsvAbs%2FQvq%2Bfz%2Bf%2F%2B%2B%2FZKhR05hgBBhQI8hgBAgAI9ewD0%2B%2Fg3pswAtO8Cxf4Kw%2FsJvvYAqupKsNv%2B%2Fv7%2F%2FP5VkSU0iQA7jQA9hgBDgQU%2BfQH%2F%2Ff%2FQ6fM4sM4KsN8AteMCruIqqdbZ7PH8%2Fv%2Fg6Nc%2Fhg05kAA8jAM9iQI%2BhQA%2BgQDQu6b97uv%2F%2F%2F7V8Pqw3eiWz97q8%2Ff%2F%2F%2F%2F7%2FPptpkkqjQE4kwA7kAA5iwI8iAA8hQCOSSKdXjiyflbAkG7u2s%2F%2B%2F%2F39%2F%2F7r8utrqEYtjQE8lgA7kwA7kwA9jwA9igA9hACiWSekVRyeSgiYSBHx6N%2F%2B%2Fv7k7OFRmiYtlAA5lwI7lwI4lAA7kgI9jwE9iwI4iQCoVhWcTxCmb0K%2BooT8%2Fv%2F7%2F%2F%2FJ2r8fdwI1mwA3mQA3mgA8lAE8lAE4jwA9iwE%2BhwGfXifWvqz%2B%2Ff%2F58u%2Fev6Dt4tr%2B%2F%2F2ZuIUsggA7mgM6mAM3lgA5lgA6kQE%2FkwBChwHt4dv%2F%2F%2F728ei1bCi7VAC5XQ7kz7n%2F%2F%2F6bsZkgcB03lQA9lgM7kwA2iQktZToPK4r9%2F%2F%2F9%2F%2F%2FSqYK5UwDKZAS9WALIkFn%2B%2F%2F3%2F%2BP8oKccGGcIRJrERILYFEMwAAuEAAdX%2F%2Ff7%2F%2FP%2B%2BfDvGXQLIZgLEWgLOjlf7%2F%2F%2F%2F%2F%2F9QU90EAPQAAf8DAP0AAfMAAOUDAtr%2F%2F%2F%2F7%2B%2Fu2bCTIYwDPZgDBWQDSr4P%2F%2Fv%2F%2F%2FP5GRuABAPkAA%2FwBAfkDAPAAAesAAN%2F%2F%2B%2Fz%2F%2F%2F64g1C5VwDMYwK8Yg7y5tz8%2Fv%2FV1PYKDOcAAP0DAf4AAf0AAfYEAOwAAuAAAAD%2F%2FPvi28ymXyChTATRrIb8%2F%2F3v8fk6P8MAAdUCAvoAAP0CAP0AAfYAAO4AAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAA</Image> | ||||
| <Url type="text/html" method="GET" template="http://www.google.com/search?q={searchTerms}"/> | ||||
| </OpenSearchDescription> | ||||
| @@ -1,44 +0,0 @@ | ||||
| <OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"> | ||||
| <ShortName>Wikipedia</ShortName> | ||||
| <Description>Wikipedia, the free encyclopedia</Description> | ||||
| <InputEncoding>UTF-8</InputEncoding> | ||||
| <Image width="16" height="16">data:image/x-icon;base64,AAABAAEAEBAQAAEABAAoAQAAFgAAACgAAAAQAAAAIAAAAAEABAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAEAgQAhIOEAMjHyABIR0gA6ejpAGlqaQCpqKkAKCgoAPz9%2FAAZGBkAmJiYANjZ2ABXWFcAent6ALm6uQA8OjwAiIiIiIiIiIiIiI4oiL6IiIiIgzuIV4iIiIhndo53KIiIiB%2FWvXoYiIiIfEZfWBSIiIEGi%2FfoqoiIgzuL84i9iIjpGIoMiEHoiMkos3FojmiLlUipYliEWIF%2BiDe0GoRa7D6GPbjcu1yIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</Image> | ||||
| <Url type="text/html" method="GET" template="http://{language}.wikipedia.org/wiki/Special:Search?search={searchTerms}"/> | ||||
| <!-- The criterion for being below is being listed with more than 100,000 | ||||
| articles on http://meta.wikimedia.org/wiki/List_of_Wikipedias --> | ||||
| <Language>ar</Language> | ||||
| <Language>bg</Language> | ||||
| <Language>ca</Language> | ||||
| <Language>cs</Language> | ||||
| <Language>da</Language> | ||||
| <Language>de</Language> | ||||
| <Language>en</Language> | ||||
| <Language>eo</Language> | ||||
| <Language>es</Language> | ||||
| <Language>fa</Language> | ||||
| <Language>fi</Language> | ||||
| <Language>fr</Language> | ||||
| <Language>he</Language> | ||||
| <Language>hu</Language> | ||||
| <Language>id</Language> | ||||
| <Language>it</Language> | ||||
| <Language>ja</Language> | ||||
| <Language>ko</Language> | ||||
| <Language>lt</Language> | ||||
| <Language>nl</Language> | ||||
| <Language>no</Language> | ||||
| <Language>pl</Language> | ||||
| <Language>pt</Language> | ||||
| <Language>ro</Language> | ||||
| <Language>ru</Language> | ||||
| <Language>sk</Language> | ||||
| <Language>sl</Language> | ||||
| <Language>sr</Language> | ||||
| <Language>sv</Language> | ||||
| <Language>tr</Language> | ||||
| <Language>uk</Language> | ||||
| <Language>vi</Language> | ||||
| <Language>vo</Language> | ||||
| <Language>war</Language> | ||||
| <Language>zh</Language> | ||||
| </OpenSearchDescription> | ||||
							
								
								
									
										98
									
								
								data/theme/add-workspace.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,98 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="23" | ||||
|    height="15" | ||||
|    id="svg6375" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.47pre4 r22446" | ||||
|    sodipodi:docname="New document 13"> | ||||
|   <defs | ||||
|      id="defs6377"> | ||||
|     <inkscape:perspective | ||||
|        sodipodi:type="inkscape:persp3d" | ||||
|        inkscape:vp_x="0 : 16 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_z="32 : 16 : 1" | ||||
|        inkscape:persp3d-origin="16 : 10.666667 : 1" | ||||
|        id="perspective6383" /> | ||||
|     <inkscape:perspective | ||||
|        id="perspective6366" | ||||
|        inkscape:persp3d-origin="0.5 : 0.33333333 : 1" | ||||
|        inkscape:vp_z="1 : 0.5 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_x="0 : 0.5 : 1" | ||||
|        sodipodi:type="inkscape:persp3d" /> | ||||
|   </defs> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="11.197802" | ||||
|      inkscape:cx="16" | ||||
|      inkscape:cy="16" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="true" | ||||
|      inkscape:grid-bbox="true" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:window-width="1680" | ||||
|      inkscape:window-height="997" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="1" /> | ||||
|   <metadata | ||||
|      id="metadata6380"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title></dc:title> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      id="layer1" | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      transform="translate(0,-17)"> | ||||
|     <g | ||||
|        style="display:inline" | ||||
|        id="g6243" | ||||
|        transform="translate(-986.28859,-658.2796)"> | ||||
|       <rect | ||||
|          style="fill:#000000;fill-opacity:0.98770495;stroke:#666666;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" | ||||
|          id="rect5318" | ||||
|          width="22" | ||||
|          height="14" | ||||
|          x="986.89801" | ||||
|          y="675.86743" | ||||
|          rx="0.49999979" | ||||
|          ry="0.5" /> | ||||
|       <g | ||||
|          id="g5320" | ||||
|          transform="translate(402.77304,-12.882544)"> | ||||
|         <path | ||||
|            id="path5322" | ||||
|            d="m 595.125,692.53048 0,6.43903" | ||||
|            style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> | ||||
|         <path | ||||
|            id="path5324" | ||||
|            d="m 598.34451,695.75 -6.43902,0" | ||||
|            style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" /> | ||||
|       </g> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 3.2 KiB | 
| @@ -1,187 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:xlink="http://www.w3.org/1999/xlink" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="28" | ||||
|    height="25" | ||||
|    id="svg10621" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.48.1 r9760" | ||||
|    sodipodi:docname="calendar-today.svg"> | ||||
|   <defs | ||||
|      id="defs10623"> | ||||
|     <radialGradient | ||||
|        inkscape:collect="always" | ||||
|        xlink:href="#linearGradient34508-1-3" | ||||
|        id="radialGradient99561-1" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)" | ||||
|        cx="51" | ||||
|        cy="30" | ||||
|        fx="51" | ||||
|        fy="30" | ||||
|        r="42" /> | ||||
|     <linearGradient | ||||
|        inkscape:collect="always" | ||||
|        id="linearGradient34508-1-3"> | ||||
|       <stop | ||||
|          style="stop-color:#ffffff;stop-opacity:1;" | ||||
|          offset="0" | ||||
|          id="stop34510-1-9" /> | ||||
|       <stop | ||||
|          style="stop-color:#ffffff;stop-opacity:0;" | ||||
|          offset="1" | ||||
|          id="stop34512-4-5" /> | ||||
|     </linearGradient> | ||||
|     <radialGradient | ||||
|        r="42" | ||||
|        fy="30" | ||||
|        fx="51" | ||||
|        cy="30" | ||||
|        cx="51" | ||||
|        gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        id="radialGradient10592" | ||||
|        xlink:href="#linearGradient34508-1-3" | ||||
|        inkscape:collect="always" /> | ||||
|     <radialGradient | ||||
|        inkscape:collect="always" | ||||
|        xlink:href="#linearGradient34508-1-3" | ||||
|        id="radialGradient3770" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)" | ||||
|        cx="51" | ||||
|        cy="30" | ||||
|        fx="51" | ||||
|        fy="30" | ||||
|        r="42" /> | ||||
|     <radialGradient | ||||
|        inkscape:collect="always" | ||||
|        xlink:href="#linearGradient34508-1-3" | ||||
|        id="radialGradient3001" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)" | ||||
|        cx="51" | ||||
|        cy="30" | ||||
|        fx="51" | ||||
|        fy="30" | ||||
|        r="42" /> | ||||
|     <radialGradient | ||||
|        inkscape:collect="always" | ||||
|        xlink:href="#linearGradient34508-1-3" | ||||
|        id="radialGradient3007" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)" | ||||
|        cx="51" | ||||
|        cy="30" | ||||
|        fx="51" | ||||
|        fy="30" | ||||
|        r="42" /> | ||||
|     <radialGradient | ||||
|        inkscape:collect="always" | ||||
|        xlink:href="#linearGradient34508-1-3" | ||||
|        id="radialGradient3067" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)" | ||||
|        cx="51" | ||||
|        cy="30" | ||||
|        fx="51" | ||||
|        fy="30" | ||||
|        r="42" /> | ||||
|     <radialGradient | ||||
|        inkscape:collect="always" | ||||
|        xlink:href="#linearGradient34508-1-3" | ||||
|        id="radialGradient3072" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)" | ||||
|        cx="51" | ||||
|        cy="30" | ||||
|        fx="51" | ||||
|        fy="30" | ||||
|        r="42" /> | ||||
|     <radialGradient | ||||
|        inkscape:collect="always" | ||||
|        xlink:href="#linearGradient34508-1-3" | ||||
|        id="radialGradient2997" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)" | ||||
|        cx="51" | ||||
|        cy="30" | ||||
|        fx="51" | ||||
|        fy="30" | ||||
|        r="42" /> | ||||
|   </defs> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#000000" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="15.839192" | ||||
|      inkscape:cx="8.3750933" | ||||
|      inkscape:cy="8.0837211" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="false" | ||||
|      fit-margin-top="0" | ||||
|      fit-margin-left="0" | ||||
|      fit-margin-right="0" | ||||
|      fit-margin-bottom="0" | ||||
|      inkscape:window-width="1440" | ||||
|      inkscape:window-height="843" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="1" /> | ||||
|   <metadata | ||||
|      id="metadata10626"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title /> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1" | ||||
|      transform="translate(-469.08263,-536.99307)"> | ||||
|     <g | ||||
|        id="g3003"> | ||||
|       <path | ||||
|          inkscape:export-ydpi="90" | ||||
|          inkscape:export-xdpi="90" | ||||
|          inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/motion/textures/panel.png" | ||||
|          transform="matrix(0.43692393,0,0,1.3783114,460.60467,517.48289)" | ||||
|          sodipodi:end="6.2831853" | ||||
|          sodipodi:start="3.1415927" | ||||
|          d="M 9,29.999999 C 9.0000011,21.163443 27.804042,14 51.000002,14 74.195961,14 93,21.163444 93,30 l -42,0 z" | ||||
|          sodipodi:ry="16" | ||||
|          sodipodi:rx="42" | ||||
|          sodipodi:cy="30" | ||||
|          sodipodi:cx="51" | ||||
|          id="path34506-3" | ||||
|          style="opacity:0.4625;color:#000000;fill:url(#radialGradient2997);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|          sodipodi:type="arc" /> | ||||
|       <rect | ||||
|          y="558.85046" | ||||
|          x="468.96878" | ||||
|          height="3.1425927" | ||||
|          width="28.149134" | ||||
|          id="rect2996" | ||||
|          style="fill:#ffffff;fill-opacity:0.50196078;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none" /> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 5.7 KiB | 
| @@ -1,26 +1,24 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:xlink="http://www.w3.org/1999/xlink" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    version="1.0" | ||||
|    id="Foreground" | ||||
|    x="0px" | ||||
|    y="0px" | ||||
|    width="32" | ||||
|    height="32" | ||||
|    viewBox="0 0 23.272727 23.272727" | ||||
|    width="22" | ||||
|    height="22" | ||||
|    viewBox="0 0 16 16" | ||||
|    enable-background="new 0 0 16 16" | ||||
|    xml:space="preserve" | ||||
|    sodipodi:version="0.32" | ||||
|    inkscape:version="0.48+devel r10081 custom" | ||||
|    inkscape:version="0.46" | ||||
|    sodipodi:docname="close-window.svg" | ||||
|    inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata | ||||
|    id="metadata2399"><rdf:RDF><cc:Work | ||||
| @@ -39,49 +37,11 @@ | ||||
|      inkscape:vp_y="0 : 1000 : 0" | ||||
|      inkscape:vp_z="16 : 8 : 1" | ||||
|      inkscape:persp3d-origin="8 : 5.3333333 : 1" | ||||
|      id="perspective2401" /><filter | ||||
|      color-interpolation-filters="sRGB" | ||||
|      inkscape:collect="always" | ||||
|      id="filter16494-4" | ||||
|      x="-0.20989846" | ||||
|      width="1.4197969" | ||||
|      y="-0.20903821" | ||||
|      height="1.4180764"><feGaussianBlur | ||||
|        inkscape:collect="always" | ||||
|        stdDeviation="1.3282637" | ||||
|        id="feGaussianBlur16496-8" /></filter><radialGradient | ||||
|      inkscape:collect="always" | ||||
|      xlink:href="#linearGradient16498-6" | ||||
|      id="radialGradient16504-1" | ||||
|      cx="7.6582627" | ||||
|      cy="5.8191104" | ||||
|      fx="7.6582627" | ||||
|      fy="5.8191104" | ||||
|      r="8.6928644" | ||||
|      gradientTransform="matrix(1.0474339,0,0,1.0517402,-0.3632615,-0.42032492)" | ||||
|      gradientUnits="userSpaceOnUse" /><linearGradient | ||||
|      inkscape:collect="always" | ||||
|      id="linearGradient16498-6"><stop | ||||
|        style="stop-color:#7b7b7b;stop-opacity:1" | ||||
|        offset="0" | ||||
|        id="stop16500-8" /><stop | ||||
|        style="stop-color:#101010;stop-opacity:1" | ||||
|        offset="1" | ||||
|        id="stop16502-0" /></linearGradient><filter | ||||
|      color-interpolation-filters="sRGB" | ||||
|      inkscape:collect="always" | ||||
|      id="filter16524-9" | ||||
|      x="-0.212979" | ||||
|      width="1.425958" | ||||
|      y="-0.21305652" | ||||
|      height="1.426113"><feGaussianBlur | ||||
|        inkscape:collect="always" | ||||
|        stdDeviation="0.71020915" | ||||
|        id="feGaussianBlur16526-0" /></filter></defs><sodipodi:namedview | ||||
|    inkscape:window-height="1114" | ||||
|    inkscape:window-width="1463" | ||||
|      id="perspective2401" /></defs><sodipodi:namedview | ||||
|    inkscape:window-height="999" | ||||
|    inkscape:window-width="1680" | ||||
|    inkscape:pageshadow="2" | ||||
|    inkscape:pageopacity="0" | ||||
|    inkscape:pageopacity="1" | ||||
|    guidetolerance="10.0" | ||||
|    gridtolerance="10.0" | ||||
|    objecttolerance="10.0" | ||||
| @@ -90,63 +50,27 @@ | ||||
|    pagecolor="#000000" | ||||
|    id="base" | ||||
|    showgrid="false" | ||||
|    inkscape:zoom="1" | ||||
|    inkscape:cx="10.720189" | ||||
|    inkscape:cy="13.739577" | ||||
|    inkscape:zoom="25.648691" | ||||
|    inkscape:cx="8.8097603" | ||||
|    inkscape:cy="9.0472789" | ||||
|    inkscape:window-x="0" | ||||
|    inkscape:window-y="26" | ||||
|    inkscape:current-layer="Foreground" | ||||
|    showguides="true" | ||||
|    inkscape:guide-bbox="true" | ||||
|    borderlayer="true" | ||||
|    inkscape:showpageshadow="false" | ||||
|    inkscape:window-maximized="0"><inkscape:grid | ||||
|      type="xygrid" | ||||
|      id="grid11246" | ||||
|      empspacing="5" | ||||
|      visible="true" | ||||
|      enabled="true" | ||||
|      snapvisiblegridlinesonly="true" /></sodipodi:namedview> | ||||
|    inkscape:guide-bbox="true" /> | ||||
|  | ||||
| <g | ||||
|    style="display:inline" | ||||
|    id="g16402-8" | ||||
|    transform="translate(4.7533483,2.8238929)"><g | ||||
|      id="g3175-4"><path | ||||
|        sodipodi:type="inkscape:offset" | ||||
|        inkscape:radius="0" | ||||
|        inkscape:original="M 7.65625 0.125 C 3.2589349 0.125 -0.3125 3.7070002 -0.3125 8.125 C -0.3125 12.543001 3.2589349 16.125 7.65625 16.125 C 12.053566 16.125 15.625 12.543001 15.625 8.125 C 15.625 3.7070002 12.053566 0.125 7.65625 0.125 z " | ||||
|        xlink:href="#path2394-32" | ||||
|        style="opacity:0.52994014;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.18181825;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter16494-4);enable-background:accumulate" | ||||
|        id="path16480-5" | ||||
|        inkscape:href="#path2394-32" | ||||
|        d="m 7.65625,0.125 c -4.3973151,0 -7.96875,3.5820002 -7.96875,8 0,4.418001 3.5714349,8 7.96875,8 4.397316,0 7.96875,-3.581999 7.96875,-8 0,-4.4179998 -3.571434,-8 -7.96875,-8 z" | ||||
|        transform="translate(0,1.028519)" /><path | ||||
|        clip-rule="evenodd" | ||||
|        d="m -0.30428257,8.1237596 c 0,-4.4179998 3.56522987,-7.9999996 7.96254497,-7.9999996 4.3973156,0 7.9625456,3.5819998 7.9625456,7.9999996 0,4.4180014 -3.56523,8.0000004 -7.9625456,8.0000004 -4.3973151,0 -7.96254497,-3.581999 -7.96254497,-8.0000004 z" | ||||
|        id="path2394-32" | ||||
|        style="color:#000000;fill:url(#radialGradient16504-1);fill-opacity:1;fill-rule:nonzero;stroke:#eeeeec;stroke-width:1.4545455;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|        sodipodi:nodetypes="csssc" | ||||
|        inkscape:connector-curvature="0" /><g | ||||
|        id="g3172-6" /></g><g | ||||
|      transform="matrix(0.72727273,0,0,0.72727273,2.368236,2.1803254)" | ||||
|      style="fill:#ffffff;fill-opacity:1;display:inline" | ||||
|      id="g27275-6-6" | ||||
|      inkscape:label="window-close"><g | ||||
|        style="fill:#ffffff;fill-opacity:1;display:inline" | ||||
|        id="g27277-1-1" | ||||
|        transform="translate(-41,-760)"><path | ||||
|          sodipodi:type="inkscape:offset" | ||||
|          inkscape:radius="0" | ||||
|          inkscape:original="M 44.21875 764.1875 L 44.21875 765.1875 C 44.19684 765.46825 44.289258 765.74287 44.5 765.9375 L 46.78125 768.21875 L 44.5 770.46875 C 44.31181 770.65692 44.218747 770.92221 44.21875 771.1875 L 44.21875 772.1875 L 45.21875 772.1875 C 45.48404 772.1875 45.749336 772.09444 45.9375 771.90625 L 48.21875 769.625 L 50.5 771.90625 C 50.688164 772.0944 50.953449 772.18749 51.21875 772.1875 L 52.21875 772.1875 L 52.21875 771.1875 C 52.218742 770.9222 52.125688 770.65692 51.9375 770.46875 L 49.6875 768.21875 L 51.96875 765.9375 C 52.18441 765.73815 52.21875 765.47397 52.21875 765.1875 L 52.21875 764.1875 L 51.21875 764.1875 C 50.977922 764.1945 50.796875 764.2695 50.53125 764.5 L 48.21875 766.78125 L 45.9375 764.5 C 45.75987 764.31608 45.504951 764.1987 45.25 764.1875 C 45.23954 764.18704 45.22912 764.18738 45.21875 764.1875 L 44.21875 764.1875 z " | ||||
|          xlink:href="#path27279-0-5" | ||||
|          style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#bebebe;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.78124988;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter16524-9);enable-background:new;font-family:Andale Mono;-inkscape-font-specification:Andale Mono" | ||||
|          id="path16506-5" | ||||
|          inkscape:href="#path27279-0-5" | ||||
|          d="m 44.21875,764.1875 0,1 c -0.02191,0.28075 0.07051,0.55537 0.28125,0.75 l 2.28125,2.28125 -2.28125,2.25 c -0.18819,0.18817 -0.281253,0.45346 -0.28125,0.71875 l 0,1 1,0 c 0.26529,0 0.530586,-0.0931 0.71875,-0.28125 L 48.21875,769.625 50.5,771.90625 c 0.188164,0.18815 0.453449,0.28124 0.71875,0.28125 l 1,0 0,-1 c -8e-6,-0.2653 -0.09306,-0.53058 -0.28125,-0.71875 l -2.25,-2.25 2.28125,-2.28125 c 0.21566,-0.19935 0.25,-0.46353 0.25,-0.75 l 0,-1 -1,0 c -0.240828,0.007 -0.421875,0.082 -0.6875,0.3125 l -2.3125,2.28125 L 45.9375,764.5 c -0.17763,-0.18392 -0.432549,-0.3013 -0.6875,-0.3125 -0.01046,-4.6e-4 -0.02088,-1.2e-4 -0.03125,0 l -1,0 z" | ||||
|          transform="translate(0,1.3535534)" /><path | ||||
|          sodipodi:nodetypes="ccsccccccccccccccccccccccc" | ||||
|          style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#bebebe;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.78124988;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new;font-family:Andale Mono;-inkscape-font-specification:Andale Mono" | ||||
|          id="path27279-0-5" | ||||
|          inkscape:connector-curvature="0" | ||||
|          d="m 44.226475,764.17222 1,0 c 0.01037,-1.2e-4 0.02079,-4.6e-4 0.03125,0 0.254951,0.0112 0.50987,0.12858 0.6875,0.3125 l 2.28125,2.28125 2.3125,-2.28125 c 0.265625,-0.2305 0.446672,-0.3055 0.6875,-0.3125 l 1,0 0,1 c 0,0.28647 -0.03434,0.55065 -0.25,0.75 l -2.28125,2.28125 2.25,2.25 c 0.188188,0.18817 0.281242,0.45345 0.28125,0.71875 l 0,1 -1,0 c -0.265301,-1e-5 -0.530586,-0.0931 -0.71875,-0.28125 l -2.28125,-2.28125 -2.28125,2.28125 c -0.188164,0.18819 -0.45346,0.28125 -0.71875,0.28125 l -1,0 0,-1 c -3e-6,-0.26529 0.09306,-0.53058 0.28125,-0.71875 l 2.28125,-2.25 -2.28125,-2.28125 c -0.210742,-0.19463 -0.30316,-0.46925 -0.28125,-0.75 l 0,-1 z" /></g></g></g></svg> | ||||
|    id="g3175"><path | ||||
|      sodipodi:nodetypes="csssc" | ||||
|      style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.59217799;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|      id="path2394" | ||||
|      d="M 0.83987936,8.0425327 C 0.83987936,4.0805265 4.0712155,0.86823453 8.0567103,0.86823453 C 12.042205,0.86823453 15.273542,4.0805265 15.273542,8.0425327 C 15.273542,12.004539 12.042205,15.216831 8.0567103,15.216831 C 4.0712155,15.216831 0.83987936,12.004539 0.83987936,8.0425327 z" | ||||
|      clip-rule="evenodd" /><g | ||||
|      id="g3172"><path | ||||
|        style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.67127273;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|        d="M 5.4242673,5.3313047 L 10.515414,10.421272 L 10.714004,10.646491" | ||||
|        id="path3152" /></g></g><path | ||||
|    style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.67127273;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|    d="M 5.4402527,10.650392 L 10.688082,5.3573033" | ||||
|    id="path3154" | ||||
|    sodipodi:nodetypes="cc" /></svg> | ||||
| Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 3.2 KiB | 
| Before Width: | Height: | Size: 2.3 KiB | 
| Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB | 
							
								
								
									
										222
									
								
								data/theme/dialog-error.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,222 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:xlink="http://www.w3.org/1999/xlink" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="24" | ||||
|    height="24" | ||||
|    id="svg4908" | ||||
|    sodipodi:version="0.32" | ||||
|    inkscape:version="0.47 r22583" | ||||
|    sodipodi:docname="dialog-error.svg" | ||||
|    inkscape:output_extension="org.inkscape.output.svg.inkscape" | ||||
|    inkscape:export-filename="/home/andreas/project/gnome-icon-theme/scalable/actions/process-stop.png" | ||||
|    inkscape:export-xdpi="90" | ||||
|    inkscape:export-ydpi="90" | ||||
|    version="1.0"> | ||||
|   <defs | ||||
|      id="defs4910"> | ||||
|     <inkscape:perspective | ||||
|        sodipodi:type="inkscape:persp3d" | ||||
|        inkscape:vp_x="0 : 24 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_z="48 : 24 : 1" | ||||
|        inkscape:persp3d-origin="24 : 16 : 1" | ||||
|        id="perspective25" /> | ||||
|     <radialGradient | ||||
|        gradientTransform="matrix(1.349881,0,0,1.349881,-3.498814,-1.810859)" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        r="9.7183542" | ||||
|        fy="4.9892726" | ||||
|        fx="9.6893959" | ||||
|        cy="4.9892726" | ||||
|        cx="9.6893959" | ||||
|        id="radialGradient5177" | ||||
|        xlink:href="#linearGradient5171" | ||||
|        inkscape:collect="always" /> | ||||
|     <radialGradient | ||||
|        gradientTransform="matrix(2.417917,0,0,2.417917,-14.17917,-4.903184)" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        r="9.7785711" | ||||
|        fy="3.458019" | ||||
|        fx="10" | ||||
|        cy="3.458019" | ||||
|        cx="10" | ||||
|        id="radialGradient5157" | ||||
|        xlink:href="#linearGradient5151" | ||||
|        inkscape:collect="always" /> | ||||
|     <radialGradient | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        gradientTransform="matrix(0.928125,0,0,0.3143011,0.7718789,12.358015)" | ||||
|        r="9.0598059" | ||||
|        fy="18.022524" | ||||
|        fx="10.739184" | ||||
|        cy="18.022524" | ||||
|        cx="10.739184" | ||||
|        id="radialGradient5145" | ||||
|        xlink:href="#linearGradient5139" | ||||
|        inkscape:collect="always" /> | ||||
|     <linearGradient | ||||
|        id="linearGradient5139" | ||||
|        inkscape:collect="always"> | ||||
|       <stop | ||||
|          id="stop5141" | ||||
|          offset="0" | ||||
|          style="stop-color:black;stop-opacity:1;" /> | ||||
|       <stop | ||||
|          id="stop5143" | ||||
|          offset="1" | ||||
|          style="stop-color:black;stop-opacity:0;" /> | ||||
|     </linearGradient> | ||||
|     <linearGradient | ||||
|        id="linearGradient5151" | ||||
|        inkscape:collect="always"> | ||||
|       <stop | ||||
|          id="stop5153" | ||||
|          offset="0" | ||||
|          style="stop-color:white;stop-opacity:1;" /> | ||||
|       <stop | ||||
|          id="stop5155" | ||||
|          offset="1" | ||||
|          style="stop-color:white;stop-opacity:0;" /> | ||||
|     </linearGradient> | ||||
|     <linearGradient | ||||
|        id="linearGradient5171"> | ||||
|       <stop | ||||
|          id="stop5173" | ||||
|          offset="0" | ||||
|          style="stop-color:#fe3a00;stop-opacity:1" /> | ||||
|       <stop | ||||
|          id="stop5175" | ||||
|          offset="1" | ||||
|          style="stop-color:#c00;stop-opacity:1;" /> | ||||
|     </linearGradient> | ||||
|   </defs> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="22.627417" | ||||
|      inkscape:cx="24.442987" | ||||
|      inkscape:cy="10.142308" | ||||
|      inkscape:current-layer="g7001" | ||||
|      showgrid="false" | ||||
|      inkscape:grid-bbox="true" | ||||
|      inkscape:document-units="px" | ||||
|      showguides="true" | ||||
|      inkscape:guide-bbox="true" | ||||
|      inkscape:window-width="1674" | ||||
|      inkscape:window-height="970" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      width="48px" | ||||
|      height="48px" | ||||
|      inkscape:window-maximized="0" /> | ||||
|   <metadata | ||||
|      id="metadata4913"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title>Stop Process</dc:title> | ||||
|         <dc:date>December 2006</dc:date> | ||||
|         <dc:creator> | ||||
|           <cc:Agent> | ||||
|             <dc:title>Jakub Steiner</dc:title> | ||||
|           </cc:Agent> | ||||
|         </dc:creator> | ||||
|         <dc:contributor> | ||||
|           <cc:Agent> | ||||
|             <dc:title>Andreas Nilsson</dc:title> | ||||
|           </cc:Agent> | ||||
|         </dc:contributor> | ||||
|         <cc:license | ||||
|            rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" /> | ||||
|         <dc:subject> | ||||
|           <rdf:Bag> | ||||
|             <rdf:li>stop</rdf:li> | ||||
|             <rdf:li>halt</rdf:li> | ||||
|           </rdf:Bag> | ||||
|         </dc:subject> | ||||
|       </cc:Work> | ||||
|       <cc:License | ||||
|          rdf:about="http://creativecommons.org/licenses/GPL/2.0/"> | ||||
|         <cc:permits | ||||
|            rdf:resource="http://web.resource.org/cc/Reproduction" /> | ||||
|         <cc:permits | ||||
|            rdf:resource="http://web.resource.org/cc/Distribution" /> | ||||
|         <cc:requires | ||||
|            rdf:resource="http://web.resource.org/cc/Notice" /> | ||||
|         <cc:permits | ||||
|            rdf:resource="http://web.resource.org/cc/DerivativeWorks" /> | ||||
|         <cc:requires | ||||
|            rdf:resource="http://web.resource.org/cc/ShareAlike" /> | ||||
|         <cc:requires | ||||
|            rdf:resource="http://web.resource.org/cc/SourceCode" /> | ||||
|       </cc:License> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      id="layer1" | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      transform="translate(0,-24)"> | ||||
|     <g | ||||
|        inkscape:label="Layer 1" | ||||
|        id="g7001" | ||||
|        transform="matrix(1.4566048,0,0,1.4455352,0.4112881,1.2324709)"> | ||||
|       <path | ||||
|          transform="matrix(0.91468137,0,0,0.70055266,-1.8812476,17.474032)" | ||||
|          d="m 19.79899,18.022524 a 9.0598059,3.0935922 0 1 1 -18.1196115,0 9.0598059,3.0935922 0 1 1 18.1196115,0 z" | ||||
|          sodipodi:ry="3.0935922" | ||||
|          sodipodi:rx="9.0598059" | ||||
|          sodipodi:cy="18.022524" | ||||
|          sodipodi:cx="10.739184" | ||||
|          id="path5137" | ||||
|          style="color:#000000;fill:url(#radialGradient5145);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" | ||||
|          sodipodi:type="arc" /> | ||||
|       <path | ||||
|          transform="matrix(0.87347736,0,0,0.83068052,-0.79308842,15.602788)" | ||||
|          d="m 19.25,9.625 a 9.25,9.25 0 1 1 -18.5,0 9.25,9.25 0 1 1 18.5,0 z" | ||||
|          sodipodi:ry="9.25" | ||||
|          sodipodi:rx="9.25" | ||||
|          sodipodi:cy="9.625" | ||||
|          sodipodi:cx="10" | ||||
|          id="path4262" | ||||
|          style="color:#000000;fill:url(#radialGradient5177);fill-opacity:1;fill-rule:nonzero;stroke:#a40000;stroke-width:0.47435912;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" | ||||
|          sodipodi:type="arc" /> | ||||
|       <path | ||||
|          sodipodi:type="arc" | ||||
|          style="opacity:0.35393258;color:#000000;fill:none;stroke:url(#radialGradient5157);stroke-width:0.49999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" | ||||
|          id="path5149" | ||||
|          sodipodi:cx="10" | ||||
|          sodipodi:cy="9.625" | ||||
|          sodipodi:rx="9.25" | ||||
|          sodipodi:ry="9.25" | ||||
|          d="m 19.25,9.625 a 9.25,9.25 0 1 1 -18.5,0 9.25,9.25 0 1 1 18.5,0 z" | ||||
|          transform="matrix(0.82868359,0,0,0.78808147,-0.34515141,16.012803)" /> | ||||
|       <path | ||||
|          sodipodi:nodetypes="cc" | ||||
|          id="path5159" | ||||
|          d="m 4.834121,20.642783 6.215127,5.91061" | ||||
|          style="color:#000000;fill:none;stroke:#ffffff;stroke-width:1.21219134;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" /> | ||||
|       <path | ||||
|          style="color:#000000;fill:none;stroke:#ffffff;stroke-width:1.21219146;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" | ||||
|          d="M 11.04925,20.622826 4.8159529,26.553393" | ||||
|          id="path5161" | ||||
|          sodipodi:nodetypes="cc" /> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 8.0 KiB | 
| @@ -1,162 +0,0 @@ | ||||
| /* Copyright 2011, Red Hat, Inc. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it | ||||
|  * under the terms and conditions of the GNU Lesser General Public License, | ||||
|  * version 2.1, as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope it will be useful, but WITHOUT ANY | ||||
|  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||||
|  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for | ||||
|  * more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public License | ||||
|  * along with this program; if not, write to the Free Software Foundation, | ||||
|  * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||||
|  */ | ||||
|  | ||||
| /* Login Dialog */ | ||||
|  | ||||
| .login-dialog-title { | ||||
|     font-size: 14pt; | ||||
|     font-weight: bold; | ||||
|     color: #666666; | ||||
|     padding-bottom: 2em; | ||||
| } | ||||
|  | ||||
| .login-dialog { | ||||
|     border-radius: 16px; | ||||
|     min-height: 150px; | ||||
|     max-height: 700px; | ||||
|     min-width: 350px; | ||||
| } | ||||
|  | ||||
| .login-dialog-user-list-view { | ||||
|     -st-vfade-offset: 1em; | ||||
| } | ||||
|  | ||||
| .login-dialog-user-list { | ||||
|     spacing: 12px; | ||||
| } | ||||
|  | ||||
| .login-dialog-user-list-item { | ||||
|     color: #666666; | ||||
| } | ||||
|  | ||||
| .login-dialog-user-list-item:ltr { | ||||
|     padding-right: 1em; | ||||
| } | ||||
|  | ||||
| .login-dialog-user-list-item:rtl { | ||||
|     padding-left: 1em; | ||||
| } | ||||
|  | ||||
| .login-dialog-user-list-item .login-dialog-user-list-item-name { | ||||
|     font-size: 20pt; | ||||
|     padding-left: 1em; | ||||
|     color: #666666; | ||||
| } | ||||
|  | ||||
| .login-dialog-user-list-item:hover .login-dialog-user-list-item-name { | ||||
|     color: white; | ||||
| } | ||||
|  | ||||
| .login-dialog-user-list-item:focus .login-dialog-user-list-item-name { | ||||
|     color: white; | ||||
|     text-shadow: black 0px 2px 2px; | ||||
| } | ||||
|  | ||||
| .login-dialog-user-list-item-vertical-layout { | ||||
|     spacing: 2px; | ||||
| } | ||||
|  | ||||
| .login-dialog-user-list-item .login-dialog-user-list-item-focus-bin { | ||||
|     background-color: rgba(0,0,0,0.0); | ||||
|     height: 2px; | ||||
| } | ||||
|  | ||||
| .login-dialog-user-list-item:focus .login-dialog-user-list-item-focus-bin { | ||||
|     background-color: #666666; | ||||
| } | ||||
|  | ||||
| .login-dialog-user-list-item-icon { | ||||
|     border: 2px solid #8b8b8b; | ||||
|     border-radius: 8px; | ||||
|     width: 64px; | ||||
|     height: 64px; | ||||
| } | ||||
|  | ||||
| .login-dialog-not-listed-button { | ||||
|     padding-top: 2em; | ||||
| } | ||||
| .login-dialog-not-listed-label { | ||||
|     font-size: 14pt; | ||||
|     font-weight: bold; | ||||
|     color: #666666; | ||||
| } | ||||
|  | ||||
| .login-dialog-prompt-layout { | ||||
|     padding-bottom: 64px; | ||||
| } | ||||
| .login-dialog-prompt-label { | ||||
|     color: white; | ||||
|     font-size: 20pt; | ||||
| } | ||||
|  | ||||
| .login-dialog-prompt-entry { | ||||
|     padding: 4px; | ||||
|     border-radius: 4px; | ||||
|     border: 2px solid #5656cc; | ||||
|     color: black; | ||||
|     background-color: white; | ||||
|     caret-color: black; | ||||
|     caret-size: 1px; | ||||
|     width: 23em; | ||||
| } | ||||
|  | ||||
| .login-dialog-session-list { | ||||
|     color: #ffffff; | ||||
|     font-size: 10.5pt; | ||||
| } | ||||
|  | ||||
| .login-dialog-session-list-button { | ||||
|     padding: 4px; | ||||
| } | ||||
|  | ||||
| .login-dialog-session-list-button:focus { | ||||
|     background-color: #4c4c4c; | ||||
| } | ||||
|  | ||||
| .login-dialog-session-list-button:active { | ||||
|     background-color: #4c4c4c; | ||||
| } | ||||
|  | ||||
| .login-dialog-session-list-button:hover { | ||||
|     font-weight: bold; | ||||
| } | ||||
|  | ||||
| .login-dialog-session-list-scroll-view { | ||||
|     background-gradient-start: rgba(80,80,80,0.3); | ||||
|     background-gradient-end: rgba(80,80,80,0.7); | ||||
|     background-gradient-direction: vertical; | ||||
|     box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9); | ||||
|     border-radius: 8px; | ||||
|     border: 1px solid rgba(80,80,80,1.0); | ||||
|     padding: .5em; | ||||
| } | ||||
|  | ||||
| .login-dialog-session-list-item:focus { | ||||
|     background-color: #666666; | ||||
| } | ||||
|  | ||||
| .login-dialog-session-list-triangle { | ||||
|     padding-right: .5em; | ||||
| } | ||||
|  | ||||
| .login-dialog-session-list-item-box { | ||||
|     spacing: .25em; | ||||
| } | ||||
|  | ||||
| .login-dialog-session-list-item-dot { | ||||
|     width: .75em; | ||||
|     height: .75em; | ||||
| } | ||||
							
								
								
									
										113
									
								
								data/theme/mosaic-view-active.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,113 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="24" | ||||
|    height="16" | ||||
|    id="svg6503" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.47pre4 r22446" | ||||
|    sodipodi:docname="mosaic-view-active.svg"> | ||||
|   <defs | ||||
|      id="defs6505"> | ||||
|     <inkscape:perspective | ||||
|        sodipodi:type="inkscape:persp3d" | ||||
|        inkscape:vp_x="0 : 16 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_z="32 : 16 : 1" | ||||
|        inkscape:persp3d-origin="16 : 10.666667 : 1" | ||||
|        id="perspective6511" /> | ||||
|     <inkscape:perspective | ||||
|        id="perspective6494" | ||||
|        inkscape:persp3d-origin="0.5 : 0.33333333 : 1" | ||||
|        inkscape:vp_z="1 : 0.5 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_x="0 : 0.5 : 1" | ||||
|        sodipodi:type="inkscape:persp3d" /> | ||||
|   </defs> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="11.197802" | ||||
|      inkscape:cx="-15.97056" | ||||
|      inkscape:cy="16" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="true" | ||||
|      inkscape:grid-bbox="true" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:window-width="1680" | ||||
|      inkscape:window-height="997" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="1" /> | ||||
|   <metadata | ||||
|      id="metadata6508"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title /> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      id="layer1" | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      transform="translate(0,-16)"> | ||||
|     <g | ||||
|        style="display:inline;fill:#cbcbcb;fill-opacity:1" | ||||
|        transform="translate(-449.85476,-685.85869)" | ||||
|        id="g5306"> | ||||
|       <rect | ||||
|          style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none" | ||||
|          id="rect5308" | ||||
|          width="11" | ||||
|          height="7" | ||||
|          x="450.5" | ||||
|          y="710.5" | ||||
|          rx="0.99999958" | ||||
|          ry="1" /> | ||||
|       <rect | ||||
|          style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline" | ||||
|          id="rect5310" | ||||
|          width="11" | ||||
|          height="7" | ||||
|          x="462.5" | ||||
|          y="702.5" | ||||
|          rx="0.99999958" | ||||
|          ry="1" /> | ||||
|       <rect | ||||
|          style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999976000000002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline" | ||||
|          id="rect5312" | ||||
|          width="11" | ||||
|          height="7" | ||||
|          x="450.5" | ||||
|          y="702.5" | ||||
|          rx="0.99999958" | ||||
|          ry="1" /> | ||||
|       <rect | ||||
|          style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline" | ||||
|          id="rect5314" | ||||
|          width="11" | ||||
|          height="7" | ||||
|          x="462.5" | ||||
|          y="710.5" | ||||
|          rx="0.99999958" | ||||
|          ry="1" /> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 3.7 KiB | 
							
								
								
									
										113
									
								
								data/theme/mosaic-view.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,113 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="24" | ||||
|    height="16" | ||||
|    id="svg6503" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.47pre4 r22446" | ||||
|    sodipodi:docname="New document 19"> | ||||
|   <defs | ||||
|      id="defs6505"> | ||||
|     <inkscape:perspective | ||||
|        sodipodi:type="inkscape:persp3d" | ||||
|        inkscape:vp_x="0 : 16 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_z="32 : 16 : 1" | ||||
|        inkscape:persp3d-origin="16 : 10.666667 : 1" | ||||
|        id="perspective6511" /> | ||||
|     <inkscape:perspective | ||||
|        id="perspective6494" | ||||
|        inkscape:persp3d-origin="0.5 : 0.33333333 : 1" | ||||
|        inkscape:vp_z="1 : 0.5 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_x="0 : 0.5 : 1" | ||||
|        sodipodi:type="inkscape:persp3d" /> | ||||
|   </defs> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="11.197802" | ||||
|      inkscape:cx="16" | ||||
|      inkscape:cy="16" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="true" | ||||
|      inkscape:grid-bbox="true" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:window-width="1680" | ||||
|      inkscape:window-height="997" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="1" /> | ||||
|   <metadata | ||||
|      id="metadata6508"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title></dc:title> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      id="layer1" | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      transform="translate(0,-16)"> | ||||
|     <g | ||||
|        style="display:inline" | ||||
|        transform="translate(-449.85476,-685.85869)" | ||||
|        id="g5306"> | ||||
|       <rect | ||||
|          style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none" | ||||
|          id="rect5308" | ||||
|          width="11" | ||||
|          height="7" | ||||
|          x="450.5" | ||||
|          y="710.5" | ||||
|          rx="0.99999958" | ||||
|          ry="1" /> | ||||
|       <rect | ||||
|          style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline" | ||||
|          id="rect5310" | ||||
|          width="11" | ||||
|          height="7" | ||||
|          x="462.5" | ||||
|          y="702.5" | ||||
|          rx="0.99999958" | ||||
|          ry="1" /> | ||||
|       <rect | ||||
|          style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline" | ||||
|          id="rect5312" | ||||
|          width="11" | ||||
|          height="7" | ||||
|          x="450.5" | ||||
|          y="702.5" | ||||
|          rx="0.99999958" | ||||
|          ry="1" /> | ||||
|       <rect | ||||
|          style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline" | ||||
|          id="rect5314" | ||||
|          width="11" | ||||
|          height="7" | ||||
|          x="462.5" | ||||
|          y="710.5" | ||||
|          rx="0.99999958" | ||||
|          ry="1" /> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										89
									
								
								data/theme/move-window-on-new.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,89 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="98" | ||||
|    height="98" | ||||
|    id="svg6375" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.47 r22583" | ||||
|    sodipodi:docname="add-workspace.svg"> | ||||
|   <defs | ||||
|      id="defs6377"> | ||||
|     <inkscape:perspective | ||||
|        sodipodi:type="inkscape:persp3d" | ||||
|        inkscape:vp_x="0 : 16 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_z="32 : 16 : 1" | ||||
|        inkscape:persp3d-origin="16 : 10.666667 : 1" | ||||
|        id="perspective6383" /> | ||||
|     <inkscape:perspective | ||||
|        id="perspective6366" | ||||
|        inkscape:persp3d-origin="0.5 : 0.33333333 : 1" | ||||
|        inkscape:vp_z="1 : 0.5 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_x="0 : 0.5 : 1" | ||||
|        sodipodi:type="inkscape:persp3d" /> | ||||
|   </defs> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="3.9590209" | ||||
|      inkscape:cx="56.650687" | ||||
|      inkscape:cy="20.635343" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="true" | ||||
|      inkscape:grid-bbox="true" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:window-width="1680" | ||||
|      inkscape:window-height="997" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="1" /> | ||||
|   <metadata | ||||
|      id="metadata6380"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title></dc:title> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      id="layer1" | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      transform="translate(0,66)"> | ||||
|     <g | ||||
|        id="g2824" | ||||
|        transform="matrix(11.568551,0,0,11.698271,-78.828159,-304.81518)"> | ||||
|       <path | ||||
|          style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" | ||||
|          d="m 11.07363,21.36834 0,6.43903" | ||||
|          id="path5322" /> | ||||
|       <path | ||||
|          style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" | ||||
|          d="m 14.29314,24.58786 -6.43902,0" | ||||
|          id="path5324" /> | ||||
|     </g> | ||||
|     <path | ||||
|        style="fill:#000000;fill-opacity:0.98823529" | ||||
|        d="m 48.239516,97.908047 c -0.41677,-0.05102 -1.269253,-0.222408 -1.894408,-0.380859 -4.088493,-1.036262 -7.520781,-4.753234 -8.330163,-9.021094 -0.154947,-0.817026 -0.257819,-6.68112 -0.257819,-14.696556 l 0,-13.337088 -13.829177,-0.08909 C 10.802042,60.298796 10.026884,60.268266 8.6851548,59.783022 3.6288503,57.954375 0.62673331,53.828648 0.62673331,48.708554 c 0,-5.625522 4.25936019,-10.425065 9.97721469,-11.242548 0.987903,-0.141242 7.368912,-0.254994 14.460646,-0.257791 l 12.692532,-0.005 0,-13.586668 c 0,-14.6441583 0.03287,-15.0698926 1.364686,-17.6753047 2.185477,-4.2754229 6.938193,-6.75739913 11.687647,-6.10355607 3.382776,0.46569661 6.737962,2.72496967 8.414081,5.66577137 1.480816,2.5981315 1.519067,3.0522448 1.519067,18.0333334 l 0,13.666424 12.692533,0.005 c 7.091733,0.0028 13.472742,0.116549 14.460646,0.257791 6.395303,0.914337 10.804785,6.623716 9.941157,12.871766 -0.698243,5.051565 -4.792685,9.104635 -9.941157,9.840713 -0.987904,0.141242 -7.368913,0.254995 -14.460646,0.257791 l -12.692533,0.005 0,13.801945 c 0,13.031417 -0.02798,13.895893 -0.501177,15.484801 -1.526902,5.127058 -6.919246,8.802262 -12.001914,8.18002 z" | ||||
|        id="path2828" | ||||
|        transform="translate(0,-66)" /> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 4.0 KiB | 
| @@ -1,33 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    width="3" | ||||
|    height="10" | ||||
|    id="svg2" | ||||
|    version="1.1"> | ||||
|   <defs | ||||
|      id="defs4" /> | ||||
|   <metadata | ||||
|      id="metadata7"> | ||||
|   </metadata> | ||||
|   <g | ||||
|      id="layer1"> | ||||
|     <rect | ||||
|        style="fill:#000000;fill-opacity:1;stroke-width:0.43599999000000000;stroke-miterlimit:4;stroke-dasharray:none" | ||||
|        id="rect3779" | ||||
|        width="3" | ||||
|        height="10" | ||||
|        x="0" | ||||
|        y="0" /> | ||||
|     <rect | ||||
|        style="fill:#536272;fill-opacity:1;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none" | ||||
|        id="rect3796" | ||||
|        width="3" | ||||
|        height="1" | ||||
|        x="0" | ||||
|        y="9" /> | ||||
|   </g> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 787 B | 
| @@ -1,74 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="21" | ||||
|    height="10" | ||||
|    id="svg2" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.48.1 r9760" | ||||
|    sodipodi:docname="panel-button-border.svg"> | ||||
|   <defs | ||||
|      id="defs4" /> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#000000" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="44.8" | ||||
|      inkscape:cx="8.6594891" | ||||
|      inkscape:cy="5.7029946" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="true" | ||||
|      showguides="true" | ||||
|      inkscape:guide-bbox="true" | ||||
|      inkscape:window-width="1440" | ||||
|      inkscape:window-height="843" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="1" | ||||
|      guidetolerance="10000" | ||||
|      objecttolerance="10000"> | ||||
|     <inkscape:grid | ||||
|        type="xygrid" | ||||
|        id="grid3792" | ||||
|        empspacing="10" | ||||
|        visible="true" | ||||
|        enabled="true" | ||||
|        snapvisiblegridlinesonly="true" /> | ||||
|   </sodipodi:namedview> | ||||
|   <metadata | ||||
|      id="metadata7"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title /> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1"> | ||||
|     <rect | ||||
|        style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none" | ||||
|        id="rect3796" | ||||
|        width="3" | ||||
|        height="2" | ||||
|        x="9" | ||||
|        y="8" /> | ||||
|   </g> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 2.0 KiB | 
| @@ -1,111 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:xlink="http://www.w3.org/1999/xlink" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="30" | ||||
|    height="25" | ||||
|    id="svg10621" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.48.1 r9760" | ||||
|    sodipodi:docname="panel-button-highlight-narrow.svg"> | ||||
|   <defs | ||||
|      id="defs10623"> | ||||
|     <radialGradient | ||||
|        inkscape:collect="always" | ||||
|        xlink:href="#linearGradient34508-1-3" | ||||
|        id="radialGradient99561-1" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)" | ||||
|        cx="51" | ||||
|        cy="30" | ||||
|        fx="51" | ||||
|        fy="30" | ||||
|        r="42" /> | ||||
|     <linearGradient | ||||
|        inkscape:collect="always" | ||||
|        id="linearGradient34508-1-3"> | ||||
|       <stop | ||||
|          style="stop-color:#ffffff;stop-opacity:1;" | ||||
|          offset="0" | ||||
|          id="stop34510-1-9" /> | ||||
|       <stop | ||||
|          style="stop-color:#ffffff;stop-opacity:0;" | ||||
|          offset="1" | ||||
|          id="stop34512-4-5" /> | ||||
|     </linearGradient> | ||||
|     <radialGradient | ||||
|        r="42" | ||||
|        fy="30" | ||||
|        fx="51" | ||||
|        cy="30" | ||||
|        cx="51" | ||||
|        gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        id="radialGradient10592" | ||||
|        xlink:href="#linearGradient34508-1-3" | ||||
|        inkscape:collect="always" /> | ||||
|   </defs> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#000000" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="1.979899" | ||||
|      inkscape:cx="-171.36384" | ||||
|      inkscape:cy="-53.255157" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="false" | ||||
|      fit-margin-top="0" | ||||
|      fit-margin-left="0" | ||||
|      fit-margin-right="0" | ||||
|      fit-margin-bottom="0" | ||||
|      inkscape:window-width="1440" | ||||
|      inkscape:window-height="843" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="1" /> | ||||
|   <metadata | ||||
|      id="metadata10626"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title /> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1" | ||||
|      transform="translate(-468.08632,-537.03477)"> | ||||
|     <path | ||||
|        sodipodi:type="arc" | ||||
|        style="opacity:0.4625;color:#000000;fill:url(#radialGradient10592);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|        id="path34506-3" | ||||
|        sodipodi:cx="51" | ||||
|        sodipodi:cy="30" | ||||
|        sodipodi:rx="42" | ||||
|        sodipodi:ry="16" | ||||
|        d="M 9,29.999999 C 9.0000011,21.163443 27.804042,14 51.000002,14 74.195961,14 93,21.163444 93,30 l -42,0 z" | ||||
|        sodipodi:start="3.1415927" | ||||
|        sodipodi:end="6.2831853" | ||||
|        transform="matrix(0.35714286,0,0,1.5625,464.87203,515.15977)" | ||||
|        inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/motion/textures/panel.png" | ||||
|        inkscape:export-xdpi="90" | ||||
|        inkscape:export-ydpi="90" /> | ||||
|   </g> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 3.5 KiB | 
| @@ -1,111 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:xlink="http://www.w3.org/1999/xlink" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="84" | ||||
|    height="25" | ||||
|    id="svg10621" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.48.0 r9654" | ||||
|    sodipodi:docname="panel-button-highlight-wide.svg"> | ||||
|   <defs | ||||
|      id="defs10623"> | ||||
|     <radialGradient | ||||
|        inkscape:collect="always" | ||||
|        xlink:href="#linearGradient34508-1-3" | ||||
|        id="radialGradient99561-1" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)" | ||||
|        cx="51" | ||||
|        cy="30" | ||||
|        fx="51" | ||||
|        fy="30" | ||||
|        r="42" /> | ||||
|     <linearGradient | ||||
|        inkscape:collect="always" | ||||
|        id="linearGradient34508-1-3"> | ||||
|       <stop | ||||
|          style="stop-color:#ffffff;stop-opacity:1;" | ||||
|          offset="0" | ||||
|          id="stop34510-1-9" /> | ||||
|       <stop | ||||
|          style="stop-color:#ffffff;stop-opacity:0;" | ||||
|          offset="1" | ||||
|          id="stop34512-4-5" /> | ||||
|     </linearGradient> | ||||
|     <radialGradient | ||||
|        r="42" | ||||
|        fy="30" | ||||
|        fx="51" | ||||
|        cy="30" | ||||
|        cx="51" | ||||
|        gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        id="radialGradient10592" | ||||
|        xlink:href="#linearGradient34508-1-3" | ||||
|        inkscape:collect="always" /> | ||||
|   </defs> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#000000" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="1.979899" | ||||
|      inkscape:cx="-118.50071" | ||||
|      inkscape:cy="27.304508" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="false" | ||||
|      fit-margin-top="0" | ||||
|      fit-margin-left="0" | ||||
|      fit-margin-right="0" | ||||
|      fit-margin-bottom="0" | ||||
|      inkscape:window-width="1440" | ||||
|      inkscape:window-height="843" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="1" /> | ||||
|   <metadata | ||||
|      id="metadata10626"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title /> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1" | ||||
|      transform="translate(-441.08632,-537.03477)"> | ||||
|     <path | ||||
|        sodipodi:type="arc" | ||||
|        style="opacity:0.4625;color:#000000;fill:url(#radialGradient10592);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|        id="path34506-3" | ||||
|        sodipodi:cx="51" | ||||
|        sodipodi:cy="30" | ||||
|        sodipodi:rx="42" | ||||
|        sodipodi:ry="16" | ||||
|        d="M 9,29.999999 C 9.0000011,21.163443 27.804042,14 51.000002,14 74.195961,14 93,21.163444 93,30 l -42,0 z" | ||||
|        sodipodi:start="3.1415927" | ||||
|        sodipodi:end="6.2831853" | ||||
|        transform="matrix(1,0,0,1.5625,432.08632,515.15977)" | ||||
|        inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/motion/textures/panel.png" | ||||
|        inkscape:export-xdpi="90" | ||||
|        inkscape:export-ydpi="90" /> | ||||
|   </g> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								data/theme/process-working.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.0 KiB | 
| @@ -1,261 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:xlink="http://www.w3.org/1999/xlink" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    id="svg5369" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.48+devel r10053 custom" | ||||
|    width="96" | ||||
|    height="48" | ||||
|    sodipodi:docname="process-working.svg" | ||||
|    style="display:inline"> | ||||
|   <metadata | ||||
|      id="metadata5375"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title></dc:title> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <defs | ||||
|      id="defs5373" /> | ||||
|   <sodipodi:namedview | ||||
|      pagecolor="#808080" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1" | ||||
|      objecttolerance="10" | ||||
|      gridtolerance="10" | ||||
|      guidetolerance="10" | ||||
|      inkscape:pageopacity="0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:window-width="1975" | ||||
|      inkscape:window-height="1098" | ||||
|      id="namedview5371" | ||||
|      showgrid="true" | ||||
|      borderlayer="true" | ||||
|      inkscape:showpageshadow="false" | ||||
|      inkscape:zoom="16" | ||||
|      inkscape:cx="53.997662" | ||||
|      inkscape:cy="22.367695" | ||||
|      inkscape:window-x="1600" | ||||
|      inkscape:window-y="33" | ||||
|      inkscape:window-maximized="0" | ||||
|      inkscape:current-layer="layer2"> | ||||
|     <inkscape:grid | ||||
|        type="xygrid" | ||||
|        id="grid11933" | ||||
|        empspacing="5" | ||||
|        visible="true" | ||||
|        enabled="true" | ||||
|        snapvisiblegridlinesonly="true" /> | ||||
|   </sodipodi:namedview> | ||||
|   <g | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1" | ||||
|      inkscape:label="tiles" | ||||
|      style="display:none"> | ||||
|     <rect | ||||
|        style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|        id="rect12451" | ||||
|        width="24" | ||||
|        height="24" | ||||
|        x="0" | ||||
|        y="0" /> | ||||
|     <rect | ||||
|        y="24" | ||||
|        x="0" | ||||
|        height="24" | ||||
|        width="24" | ||||
|        id="rect12453" | ||||
|        style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | ||||
|     <rect | ||||
|        y="0" | ||||
|        x="24" | ||||
|        height="24" | ||||
|        width="24" | ||||
|        id="rect12455" | ||||
|        style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | ||||
|     <rect | ||||
|        style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|        id="rect12457" | ||||
|        width="24" | ||||
|        height="24" | ||||
|        x="24" | ||||
|        y="24" /> | ||||
|     <rect | ||||
|        style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|        id="rect12459" | ||||
|        width="24" | ||||
|        height="24" | ||||
|        x="48" | ||||
|        y="0" /> | ||||
|     <rect | ||||
|        y="24" | ||||
|        x="48" | ||||
|        height="24" | ||||
|        width="24" | ||||
|        id="rect12461" | ||||
|        style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | ||||
|     <rect | ||||
|        y="0" | ||||
|        x="72" | ||||
|        height="24" | ||||
|        width="24" | ||||
|        id="rect12463" | ||||
|        style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | ||||
|     <rect | ||||
|        style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|        id="rect12465" | ||||
|        width="24" | ||||
|        height="24" | ||||
|        x="72" | ||||
|        y="24" /> | ||||
|   </g> | ||||
|   <g | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer2" | ||||
|      inkscape:label="spinner"> | ||||
|     <g | ||||
|        transform="matrix(0.28240106,0,0,0.28240106,146.92015,-382.52444)" | ||||
|        id="g10450-5" | ||||
|        style="display:inline"> | ||||
|       <path | ||||
|          inkscape:connector-curvature="0" | ||||
|          style="opacity:0.6;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|          d="m -477.76072,1373.3569 0,9.4717" | ||||
|          id="path18768" | ||||
|          sodipodi:nodetypes="cc" | ||||
|          inkscape:transform-center-y="-4.6808838" /> | ||||
|       <path | ||||
|          inkscape:connector-curvature="0" | ||||
|          inkscape:transform-center-y="-3.3099227" | ||||
|          sodipodi:nodetypes="cc" | ||||
|          id="path18770" | ||||
|          d="m -461.0171,1380.2922 -7.23427,7.3824" | ||||
|          style="opacity:0.7;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|          inkscape:transform-center-x="-3.3098966" /> | ||||
|       <path | ||||
|          inkscape:connector-curvature="0" | ||||
|          inkscape:transform-center-x="-4.6808962" | ||||
|          style="opacity:0.8;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|          d="m -454.08163,1397.0359 -9.47165,0" | ||||
|          id="path18772" | ||||
|          sodipodi:nodetypes="cc" | ||||
|          inkscape:transform-center-y="-2.6596956e-05" /> | ||||
|       <path | ||||
|          inkscape:connector-curvature="0" | ||||
|          sodipodi:nodetypes="cc" | ||||
|          id="path18774" | ||||
|          d="m -461.01709,1413.7796 -6.93831,-7.0864" | ||||
|          style="opacity:0.9;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|          inkscape:transform-center-x="-3.3098966" | ||||
|          inkscape:transform-center-y="3.3098652" /> | ||||
|       <path | ||||
|          inkscape:connector-curvature="0" | ||||
|          inkscape:transform-center-y="4.6808757" | ||||
|          style="color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|          d="m -477.76074,1420.715 9e-5,-9.4716" | ||||
|          id="path18776" | ||||
|          sodipodi:nodetypes="cc" /> | ||||
|       <path | ||||
|          inkscape:connector-curvature="0" | ||||
|          sodipodi:nodetypes="cc" | ||||
|          id="path18778" | ||||
|          d="m -494.50442,1413.7796 6.79048,-6.9384" | ||||
|          style="opacity:0.3;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|          inkscape:transform-center-y="3.3098769" | ||||
|          inkscape:transform-center-x="3.3098883" /> | ||||
|       <path | ||||
|          inkscape:connector-curvature="0" | ||||
|          inkscape:transform-center-x="4.6808941" | ||||
|          style="opacity:0.4;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|          d="m -501.43987,1397.0359 9.47174,0" | ||||
|          id="path18780" | ||||
|          sodipodi:nodetypes="cc" | ||||
|          inkscape:transform-center-y="-2.6596956e-05" /> | ||||
|       <path | ||||
|          inkscape:connector-curvature="0" | ||||
|          sodipodi:nodetypes="cc" | ||||
|          id="path18782" | ||||
|          d="m -494.5044,1380.2922 6.64243,6.9384" | ||||
|          style="opacity:0.5;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|          inkscape:transform-center-x="3.3098902" | ||||
|          inkscape:transform-center-y="-3.3099302" /> | ||||
|     </g> | ||||
|     <use | ||||
|        style="display:inline" | ||||
|        x="0" | ||||
|        y="0" | ||||
|        xlink:href="#g10450-5" | ||||
|        id="use4981" | ||||
|        transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,36,-4.9705636)" | ||||
|        width="400" | ||||
|        height="400" /> | ||||
|     <use | ||||
|        style="display:inline" | ||||
|        x="0" | ||||
|        y="0" | ||||
|        xlink:href="#use4981" | ||||
|        id="use4983" | ||||
|        transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,43.032478,-21.909695)" | ||||
|        width="400" | ||||
|        height="400" /> | ||||
|     <use | ||||
|        style="display:inline" | ||||
|        x="0" | ||||
|        y="0" | ||||
|        xlink:href="#use4983" | ||||
|        id="use4985" | ||||
|        transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,50.081986,-38.904617)" | ||||
|        width="400" | ||||
|        height="400" /> | ||||
|     <use | ||||
|        style="display:inline" | ||||
|        x="0" | ||||
|        y="0" | ||||
|        xlink:href="#use4985" | ||||
|        id="use4987" | ||||
|        transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,-38.919996,-31.872139)" | ||||
|        width="400" | ||||
|        height="400" /> | ||||
|     <use | ||||
|        style="display:inline" | ||||
|        x="0" | ||||
|        y="0" | ||||
|        xlink:href="#use4987" | ||||
|        id="use4989" | ||||
|        transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,52.986628,2.0890543)" | ||||
|        width="400" | ||||
|        height="400" /> | ||||
|     <use | ||||
|        style="display:inline" | ||||
|        x="0" | ||||
|        y="0" | ||||
|        xlink:href="#use4989" | ||||
|        id="use4991" | ||||
|        transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,60.013026,-14.912936)" | ||||
|        width="400" | ||||
|        height="400" /> | ||||
|     <use | ||||
|        style="display:inline" | ||||
|        x="0" | ||||
|        y="0" | ||||
|        xlink:href="#use4991" | ||||
|        id="use4993" | ||||
|        transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,67.022396,-31.859127)" | ||||
|        width="400" | ||||
|        height="400" /> | ||||
|   </g> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 9.8 KiB | 
							
								
								
									
										92
									
								
								data/theme/remove-workspace.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,92 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="23" | ||||
|    height="15" | ||||
|    id="svg5501" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.47pre4 r22446" | ||||
|    sodipodi:docname="add-workspace.svg"> | ||||
|   <defs | ||||
|      id="defs5503"> | ||||
|     <inkscape:perspective | ||||
|        sodipodi:type="inkscape:persp3d" | ||||
|        inkscape:vp_x="0 : 16 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_z="32 : 16 : 1" | ||||
|        inkscape:persp3d-origin="16 : 10.666667 : 1" | ||||
|        id="perspective5509" /> | ||||
|     <inkscape:perspective | ||||
|        id="perspective5314" | ||||
|        inkscape:persp3d-origin="0.5 : 0.33333333 : 1" | ||||
|        inkscape:vp_z="1 : 0.5 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_x="0 : 0.5 : 1" | ||||
|        sodipodi:type="inkscape:persp3d" /> | ||||
|   </defs> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="11.197802" | ||||
|      inkscape:cx="-0.074583208" | ||||
|      inkscape:cy="16" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="true" | ||||
|      inkscape:grid-bbox="true" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:window-width="1680" | ||||
|      inkscape:window-height="997" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="1" | ||||
|      inkscape:snap-grids="true" | ||||
|      inkscape:snap-bbox="true" /> | ||||
|   <metadata | ||||
|      id="metadata5506"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title></dc:title> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      id="layer1" | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      transform="translate(0,-17)"> | ||||
|     <g | ||||
|        style="display:inline" | ||||
|        id="g6239" | ||||
|        transform="translate(-953.97989,-657.32287)"> | ||||
|       <rect | ||||
|          style="fill:#000000;fill-opacity:0.98770495;stroke:#666666;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" | ||||
|          id="rect5318-6" | ||||
|          width="22" | ||||
|          height="14" | ||||
|          x="954.5" | ||||
|          y="675" | ||||
|          rx="0.49999979" | ||||
|          ry="0.5" /> | ||||
|       <path | ||||
|          style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" | ||||
|          d="m 968.71951,682 -6.43902,0" | ||||
|          id="path5324-5" /> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.9 KiB | 
| @@ -2,62 +2,24 @@ | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:xlink="http://www.w3.org/1999/xlink" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="119.97824" | ||||
|    height="119.97824" | ||||
|    width="74.01342" | ||||
|    height="74.006706" | ||||
|    id="svg7355" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.48.1 r9760" | ||||
|    sodipodi:docname="running-indicator.svg"> | ||||
|   <metadata | ||||
|      id="metadata4175"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <sodipodi:namedview | ||||
|      pagecolor="#2c1cff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1" | ||||
|      objecttolerance="10" | ||||
|      gridtolerance="10" | ||||
|      guidetolerance="10" | ||||
|      inkscape:pageopacity="1" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:window-width="1920" | ||||
|      inkscape:window-height="1141" | ||||
|      id="namedview4173" | ||||
|      showgrid="false" | ||||
|      inkscape:zoom="8.1348081" | ||||
|      inkscape:cx="81.120662" | ||||
|      inkscape:cy="58.117986" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="1" | ||||
|      inkscape:current-layer="g30864" /> | ||||
|    version="1.1"> | ||||
|   <defs | ||||
|      id="defs7357"> | ||||
|     <radialGradient | ||||
|        xlink:href="#linearGradient36429" | ||||
|        id="radialGradient7461" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        gradientTransform="matrix(1.011539,0,0,0.57582113,-0.39262194,71.83807)" | ||||
|        cx="47.428951" | ||||
|        cy="167.16817" | ||||
|        fx="47.428951" | ||||
|        fy="167.16817" | ||||
|        gradientTransform="matrix(1.0525552,0,0,1.0525552,-2.5162753,-9.0000838)" | ||||
|        cx="47.878681" | ||||
|        cy="171.25" | ||||
|        fx="47.878681" | ||||
|        fy="171.25" | ||||
|        r="37" /> | ||||
|     <linearGradient | ||||
|        id="linearGradient36429"> | ||||
| @@ -97,34 +59,31 @@ | ||||
|        fx="49.067139" | ||||
|        cy="242.50381" | ||||
|        cx="49.067139" | ||||
|        gradientTransform="matrix(1.1891549,0,0,0.15252127,-9.281289,132.52772)" | ||||
|        gradientTransform="matrix(1.1891549,0,0,0.55513246,-9.281289,36.12653)" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        id="radialGradient7488" | ||||
|        xlink:href="#linearGradient36471" /> | ||||
|   </defs> | ||||
|   <g | ||||
|      id="layer1" | ||||
|      transform="matrix(1.6213276,0,0,1.6213276,-431.6347,-272.5745)"> | ||||
|      transform="translate(-266.21629,-168.11809)"> | ||||
|     <g | ||||
|        style="display:inline" | ||||
|        id="g30864" | ||||
|        transform="translate(255.223,70.118091)"> | ||||
|       <rect | ||||
|          ry="3.4593496" | ||||
|          rx="3.4593496" | ||||
|          y="99.596962" | ||||
|          x="12.596948" | ||||
|          height="71.116341" | ||||
|          width="71.116341" | ||||
|          ry="3.5996203" | ||||
|          rx="3.5996203" | ||||
|          y="98" | ||||
|          x="11" | ||||
|          height="74" | ||||
|          width="74" | ||||
|          id="rect14000" | ||||
|          style="opacity:0.37187500000000001;fill:url(#radialGradient7461);fill-opacity:1;stroke:none" /> | ||||
|          style="opacity:0.371875;fill:url(#radialGradient7461);fill-opacity:1;stroke:none" /> | ||||
|       <path | ||||
|          id="rect34520" | ||||
|          d="m 83.273151,166.72152 c 0,1.96759 -1.584022,3.55163 -3.551629,3.55163 l -63.443032,0 c -1.967608,0 -3.551648,-1.58402 -3.551643,-3.55164 0,-5.85318 0,-5.85318 0,0" | ||||
|          style="opacity:0.35;fill:none;stroke:url(#radialGradient7488);stroke-width:1;stroke-opacity:1" | ||||
|          connector-curvature="0" | ||||
|          inkscape:connector-curvature="0" | ||||
|          sodipodi:nodetypes="ccscc" /> | ||||
|          d="m 84.506708,167.95508 c 6e-6,1.96759 -1.584022,3.55162 -3.551629,3.55163 l -65.910146,0 c -1.967608,-1e-5 -3.551648,-1.58402 -3.551643,-3.55164" | ||||
|          style="opacity:0.2;fill:none;stroke:url(#radialGradient7488);stroke-width:1;stroke-opacity:1" /> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
|   | ||||
| Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 2.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								data/theme/scroll-button-down-hover.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 225 B | 
							
								
								
									
										
											BIN
										
									
								
								data/theme/scroll-button-down.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 225 B | 
							
								
								
									
										
											BIN
										
									
								
								data/theme/scroll-button-up-hover.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 211 B | 
							
								
								
									
										
											BIN
										
									
								
								data/theme/scroll-button-up.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 211 B | 
| @@ -9,14 +9,29 @@ | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="16" | ||||
|    height="16" | ||||
|    id="svg2" | ||||
|    width="5.8600588" | ||||
|    height="9" | ||||
|    id="svg3647" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.48+devel r9942 custom" | ||||
|    sodipodi:docname="arrow-left.svg"> | ||||
|    inkscape:version="0.47 r22583" | ||||
|    sodipodi:docname="section-more.svg"> | ||||
|   <defs | ||||
|      id="defs4" /> | ||||
|      id="defs3649"> | ||||
|     <inkscape:perspective | ||||
|        sodipodi:type="inkscape:persp3d" | ||||
|        inkscape:vp_x="0 : 526.18109 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_z="744.09448 : 526.18109 : 1" | ||||
|        inkscape:persp3d-origin="372.04724 : 350.78739 : 1" | ||||
|        id="perspective3655" /> | ||||
|     <inkscape:perspective | ||||
|        id="perspective3603" | ||||
|        inkscape:persp3d-origin="0.5 : 0.33333333 : 1" | ||||
|        inkscape:vp_z="1 : 0.5 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_x="0 : 0.5 : 1" | ||||
|        sodipodi:type="inkscape:persp3d" /> | ||||
|   </defs> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
| @@ -24,29 +39,19 @@ | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="1" | ||||
|      inkscape:cx="7.7366092" | ||||
|      inkscape:cy="6.4536271" | ||||
|      inkscape:zoom="82.777778" | ||||
|      inkscape:cx="2.9300294" | ||||
|      inkscape:cy="5.466443" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="false" | ||||
|      borderlayer="true" | ||||
|      inkscape:showpageshadow="false" | ||||
|      inkscape:window-width="930" | ||||
|      inkscape:window-height="681" | ||||
|      inkscape:window-x="1892" | ||||
|      inkscape:window-y="272" | ||||
|      inkscape:window-maximized="0"> | ||||
|     <inkscape:grid | ||||
|        type="xygrid" | ||||
|        id="grid17403" | ||||
|        empspacing="5" | ||||
|        visible="true" | ||||
|        enabled="true" | ||||
|        snapvisiblegridlinesonly="true" /> | ||||
|   </sodipodi:namedview> | ||||
|      inkscape:window-width="1680" | ||||
|      inkscape:window-height="997" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="1" /> | ||||
|   <metadata | ||||
|      id="metadata7"> | ||||
|      id="metadata3652"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
| @@ -61,22 +66,22 @@ | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1" | ||||
|      transform="translate(0,-1036.3622)"> | ||||
|      transform="translate(-262.78425,-490.71933)"> | ||||
|     <path | ||||
|        sodipodi:type="star" | ||||
|        style="fill:#5f5f5f;fill-opacity:1;stroke:#5f5f5f;stroke-width:0.43015847;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" | ||||
|        id="path18028" | ||||
|        sodipodi:sides="3" | ||||
|        sodipodi:cx="84.5" | ||||
|        sodipodi:cy="337.5" | ||||
|        sodipodi:r1="5" | ||||
|        sodipodi:r2="2.5" | ||||
|        sodipodi:arg1="0.52359878" | ||||
|        sodipodi:arg2="1.5707963" | ||||
|        inkscape:flatsided="true" | ||||
|        inkscape:rounded="0" | ||||
|        transform="matrix(0,-0.98149546,0.71467449,0,25.404986,578.15569)" | ||||
|        d="M 88.830127,340 80.169873,340 84.5,332.5 88.830127,340 z" | ||||
|        inkscape:randomized="0" | ||||
|        d="M 88.830127,340 80.169873,340 84.5,332.5 z" | ||||
|        transform="matrix(0,1.3621708,-0.99186247,0,342.48324,929.32667)" /> | ||||
|        inkscape:rounded="0" | ||||
|        inkscape:flatsided="true" | ||||
|        sodipodi:arg2="1.5707963" | ||||
|        sodipodi:arg1="0.52359878" | ||||
|        sodipodi:r2="2.5" | ||||
|        sodipodi:r1="5" | ||||
|        sodipodi:cy="337.5" | ||||
|        sodipodi:cx="84.5" | ||||
|        sodipodi:sides="3" | ||||
|        id="path5497-5" | ||||
|        style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.59699643;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" | ||||
|        sodipodi:type="star" /> | ||||
|   </g> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.8 KiB | 
							
								
								
									
										85
									
								
								data/theme/calendar-arrow-left.svg → data/theme/section-more.svg
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						| @@ -9,14 +9,29 @@ | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="16" | ||||
|    height="16" | ||||
|    id="svg2" | ||||
|    width="5.8600588" | ||||
|    height="9" | ||||
|    id="svg3647" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.48+devel r9942 custom" | ||||
|    sodipodi:docname="New document 4"> | ||||
|    inkscape:version="0.46+devel" | ||||
|    sodipodi:docname="New document 6"> | ||||
|   <defs | ||||
|      id="defs4" /> | ||||
|      id="defs3649"> | ||||
|     <inkscape:perspective | ||||
|        sodipodi:type="inkscape:persp3d" | ||||
|        inkscape:vp_x="0 : 526.18109 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_z="744.09448 : 526.18109 : 1" | ||||
|        inkscape:persp3d-origin="372.04724 : 350.78739 : 1" | ||||
|        id="perspective3655" /> | ||||
|     <inkscape:perspective | ||||
|        id="perspective3603" | ||||
|        inkscape:persp3d-origin="0.5 : 0.33333333 : 1" | ||||
|        inkscape:vp_z="1 : 0.5 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_x="0 : 0.5 : 1" | ||||
|        sodipodi:type="inkscape:persp3d" /> | ||||
|   </defs> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
| @@ -24,29 +39,19 @@ | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="1" | ||||
|      inkscape:cx="8.984481" | ||||
|      inkscape:cy="5.6224906" | ||||
|      inkscape:zoom="0.35" | ||||
|      inkscape:cx="112.21575" | ||||
|      inkscape:cy="-32.642856" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="false" | ||||
|      borderlayer="true" | ||||
|      inkscape:showpageshadow="false" | ||||
|      inkscape:window-width="930" | ||||
|      inkscape:window-height="681" | ||||
|      inkscape:window-x="1892" | ||||
|      inkscape:window-y="272" | ||||
|      inkscape:window-maximized="0"> | ||||
|     <inkscape:grid | ||||
|        type="xygrid" | ||||
|        id="grid17403" | ||||
|        empspacing="5" | ||||
|        visible="true" | ||||
|        enabled="true" | ||||
|        snapvisiblegridlinesonly="true" /> | ||||
|   </sodipodi:namedview> | ||||
|      inkscape:window-width="609" | ||||
|      inkscape:window-height="501" | ||||
|      inkscape:window-x="164" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="0" /> | ||||
|   <metadata | ||||
|      id="metadata7"> | ||||
|      id="metadata3652"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
| @@ -61,22 +66,22 @@ | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1" | ||||
|      transform="translate(0,-1036.3622)"> | ||||
|      transform="translate(-262.78425,-490.71933)"> | ||||
|     <path | ||||
|        sodipodi:type="star" | ||||
|        style="fill:#5f5f5f;fill-opacity:1;stroke:#5f5f5f;stroke-width:0.43015847;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" | ||||
|        id="path18028" | ||||
|        sodipodi:sides="3" | ||||
|        sodipodi:cx="84.5" | ||||
|        sodipodi:cy="337.5" | ||||
|        sodipodi:r1="5" | ||||
|        sodipodi:r2="2.5" | ||||
|        sodipodi:arg1="0.52359878" | ||||
|        sodipodi:arg2="1.5707963" | ||||
|        inkscape:flatsided="true" | ||||
|        inkscape:rounded="0" | ||||
|        transform="matrix(0,0.98149546,-0.71467449,0,506.02358,412.28296)" | ||||
|        d="M 88.830127,340 80.169873,340 84.5,332.5 88.830127,340 z" | ||||
|        inkscape:randomized="0" | ||||
|        d="M 88.830127,340 80.169873,340 84.5,332.5 z" | ||||
|        transform="matrix(0,1.3621708,0.99186247,0,-325.48222,929.32667)" /> | ||||
|        inkscape:rounded="0" | ||||
|        inkscape:flatsided="true" | ||||
|        sodipodi:arg2="1.5707963" | ||||
|        sodipodi:arg1="0.52359878" | ||||
|        sodipodi:r2="2.5" | ||||
|        sodipodi:r1="5" | ||||
|        sodipodi:cy="337.5" | ||||
|        sodipodi:cx="84.5" | ||||
|        sodipodi:sides="3" | ||||
|        id="path5497-5" | ||||
|        style="fill:#5f5f5f;fill-opacity:1;stroke:#5f5f5f;stroke-width:0.59699643;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" | ||||
|        sodipodi:type="star" /> | ||||
|   </g> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								data/theme/separator-white.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 531 B | 
| @@ -9,23 +9,23 @@ | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="10" | ||||
|    height="20" | ||||
|    id="svg10003" | ||||
|    width="24" | ||||
|    height="16" | ||||
|    id="svg6446" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.47 r22583" | ||||
|    sodipodi:docname="filter-selected.svg"> | ||||
|    inkscape:version="0.47pre4 r22446" | ||||
|    sodipodi:docname="single-view-active.svg"> | ||||
|   <defs | ||||
|      id="defs10005"> | ||||
|      id="defs6448"> | ||||
|     <inkscape:perspective | ||||
|        sodipodi:type="inkscape:persp3d" | ||||
|        inkscape:vp_x="0 : 32 : 1" | ||||
|        inkscape:vp_x="0 : 16 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_z="64 : 32 : 1" | ||||
|        inkscape:persp3d-origin="32 : 21.333333 : 1" | ||||
|        id="perspective10011" /> | ||||
|        inkscape:vp_z="32 : 16 : 1" | ||||
|        inkscape:persp3d-origin="16 : 10.666667 : 1" | ||||
|        id="perspective6454" /> | ||||
|     <inkscape:perspective | ||||
|        id="perspective9998" | ||||
|        id="perspective6441" | ||||
|        inkscape:persp3d-origin="0.5 : 0.33333333 : 1" | ||||
|        inkscape:vp_z="1 : 0.5 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
| @@ -39,20 +39,20 @@ | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="5.5" | ||||
|      inkscape:cx="32" | ||||
|      inkscape:cy="10.181818" | ||||
|      inkscape:zoom="11.197802" | ||||
|      inkscape:cx="0.014720032" | ||||
|      inkscape:cy="16" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="true" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:grid-bbox="true" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:window-width="1680" | ||||
|      inkscape:window-height="994" | ||||
|      inkscape:window-height="997" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="1" /> | ||||
|   <metadata | ||||
|      id="metadata10008"> | ||||
|      id="metadata6451"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
| @@ -67,15 +67,15 @@ | ||||
|      id="layer1" | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      transform="translate(0,-44)"> | ||||
|     <path | ||||
|        inkscape:export-ydpi="90" | ||||
|        inkscape:export-xdpi="90" | ||||
|        inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/app-picker.png" | ||||
|        sodipodi:nodetypes="cccc" | ||||
|        inkscape:connector-curvature="0" | ||||
|        id="rect34320" | ||||
|        d="m -0.18726572,54.181804 10.55634072,10.55636 10e-6,-21.11269 z" | ||||
|        style="opacity:0.21000001;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.99999988;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | ||||
|      transform="translate(0,-17)"> | ||||
|     <rect | ||||
|        ry="0.5" | ||||
|        rx="0.49999979" | ||||
|        y="17.483809" | ||||
|        x="0.53483802" | ||||
|        height="15" | ||||
|        width="23" | ||||
|        id="rect5304" | ||||
|        style="fill:#cccccc;fill-opacity:1;stroke:#cccccc;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" /> | ||||
|   </g> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.4 KiB | 
| @@ -9,23 +9,23 @@ | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="10" | ||||
|    height="20" | ||||
|    id="svg10003" | ||||
|    width="24" | ||||
|    height="16" | ||||
|    id="svg6446" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.48.1 r9760" | ||||
|    sodipodi:docname="filter-selected-ltr.svg"> | ||||
|    inkscape:version="0.47pre4 r22446" | ||||
|    sodipodi:docname="single-view.svg"> | ||||
|   <defs | ||||
|      id="defs10005"> | ||||
|      id="defs6448"> | ||||
|     <inkscape:perspective | ||||
|        sodipodi:type="inkscape:persp3d" | ||||
|        inkscape:vp_x="0 : 32 : 1" | ||||
|        inkscape:vp_x="0 : 16 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_z="64 : 32 : 1" | ||||
|        inkscape:persp3d-origin="32 : 21.333333 : 1" | ||||
|        id="perspective10011" /> | ||||
|        inkscape:vp_z="32 : 16 : 1" | ||||
|        inkscape:persp3d-origin="16 : 10.666667 : 1" | ||||
|        id="perspective6454" /> | ||||
|     <inkscape:perspective | ||||
|        id="perspective9998" | ||||
|        id="perspective6441" | ||||
|        inkscape:persp3d-origin="0.5 : 0.33333333 : 1" | ||||
|        inkscape:vp_z="1 : 0.5 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
| @@ -37,29 +37,29 @@ | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="5.5" | ||||
|      inkscape:cx="32.363636" | ||||
|      inkscape:cy="10.181818" | ||||
|      inkscape:zoom="11.197802" | ||||
|      inkscape:cx="0.014720032" | ||||
|      inkscape:cy="16" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="true" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:grid-bbox="true" | ||||
|      inkscape:window-width="1440" | ||||
|      inkscape:window-height="839" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:window-width="1680" | ||||
|      inkscape:window-height="997" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="1" /> | ||||
|   <metadata | ||||
|      id="metadata10008"> | ||||
|      id="metadata6451"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title></dc:title> | ||||
|         <dc:title /> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
| @@ -67,15 +67,15 @@ | ||||
|      id="layer1" | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      transform="translate(0,-44)"> | ||||
|     <path | ||||
|        inkscape:export-ydpi="90" | ||||
|        inkscape:export-xdpi="90" | ||||
|        inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/app-picker.png" | ||||
|        sodipodi:nodetypes="cccc" | ||||
|        inkscape:connector-curvature="0" | ||||
|        id="rect34320" | ||||
|        d="m 10.369085,54.181804 -10.55634072,10.55636 -1e-5,-21.11269 z" | ||||
|        style="opacity:0.21000001;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.99999988;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> | ||||
|      transform="translate(0,-17)"> | ||||
|     <rect | ||||
|        ry="0.5" | ||||
|        rx="0.49999979" | ||||
|        y="17.483809" | ||||
|        x="0.53483802" | ||||
|        height="15" | ||||
|        width="23" | ||||
|        id="rect5304" | ||||
|        style="fill:#626262;fill-opacity:1;stroke:#cccccc;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" /> | ||||
|   </g> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.4 KiB | 
| @@ -1,74 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="21" | ||||
|    height="10" | ||||
|    id="svg2" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.48.0 r9654" | ||||
|    sodipodi:docname="source-button-border.svg"> | ||||
|   <defs | ||||
|      id="defs4" /> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#000000" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="44.8" | ||||
|      inkscape:cx="8.704132" | ||||
|      inkscape:cy="5.7029946" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="true" | ||||
|      showguides="true" | ||||
|      inkscape:guide-bbox="true" | ||||
|      inkscape:window-width="1600" | ||||
|      inkscape:window-height="1145" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="1" | ||||
|      guidetolerance="10000" | ||||
|      objecttolerance="10000"> | ||||
|     <inkscape:grid | ||||
|        type="xygrid" | ||||
|        id="grid3792" | ||||
|        empspacing="10" | ||||
|        visible="true" | ||||
|        enabled="true" | ||||
|        snapvisiblegridlinesonly="true" /> | ||||
|   </sodipodi:namedview> | ||||
|   <metadata | ||||
|      id="metadata7"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title></dc:title> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1"> | ||||
|     <rect | ||||
|        style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none" | ||||
|        id="rect3796" | ||||
|        width="19" | ||||
|        height="2" | ||||
|        x="1" | ||||
|        y="8" /> | ||||
|   </g> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 2.0 KiB | 
| @@ -13,8 +13,8 @@ | ||||
|    height="22" | ||||
|    id="svg3199" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.48.1 r9760" | ||||
|    sodipodi:docname="toggle-on-intl.svg"> | ||||
|    inkscape:version="0.47 r22583" | ||||
|    sodipodi:docname="New document 11"> | ||||
|   <defs | ||||
|      id="defs3201"> | ||||
|     <inkscape:perspective | ||||
| @@ -39,14 +39,14 @@ | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="1" | ||||
|      inkscape:cx="49.147112" | ||||
|      inkscape:cy="17.532036" | ||||
|      inkscape:zoom="0.35" | ||||
|      inkscape:cx="32.500004" | ||||
|      inkscape:cy="10.999997" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="false" | ||||
|      inkscape:window-width="1412" | ||||
|      inkscape:window-height="1067" | ||||
|      inkscape:window-width="609" | ||||
|      inkscape:window-height="501" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="0" /> | ||||
| @@ -58,7 +58,7 @@ | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title /> | ||||
|         <dc:title></dc:title> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
| @@ -72,7 +72,7 @@ | ||||
|        transform="translate(-453.5,448.36218)" | ||||
|        id="g16453"> | ||||
|       <rect | ||||
|          style="color:#000000;fill:#4a90d9;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994000000003;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|          style="color:#000000;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|          id="rect16256-9-4" | ||||
|          width="63.000004" | ||||
|          height="19" | ||||
|   | ||||
| Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB | 
| @@ -13,8 +13,8 @@ | ||||
|    height="22" | ||||
|    id="svg2857" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.48.1 r9760" | ||||
|    sodipodi:docname="toggle-on-us.svg"> | ||||
|    inkscape:version="0.47 r22583" | ||||
|    sodipodi:docname="New document 2"> | ||||
|   <defs | ||||
|      id="defs2859"> | ||||
|     <inkscape:perspective | ||||
| @@ -40,18 +40,16 @@ | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="1" | ||||
|      inkscape:cx="19.689855" | ||||
|      inkscape:cy="2.0517979" | ||||
|      inkscape:cx="-69.642856" | ||||
|      inkscape:cy="42.428569" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="false" | ||||
|      inkscape:window-width="941" | ||||
|      inkscape:window-height="751" | ||||
|      inkscape:window-x="2577" | ||||
|      inkscape:window-y="206" | ||||
|      inkscape:window-maximized="0" | ||||
|      borderlayer="true" | ||||
|      inkscape:showpageshadow="false" /> | ||||
|      inkscape:window-width="609" | ||||
|      inkscape:window-height="501" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="0" /> | ||||
|   <metadata | ||||
|      id="metadata2862"> | ||||
|     <rdf:RDF> | ||||
| @@ -60,7 +58,7 @@ | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title /> | ||||
|         <dc:title></dc:title> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
| @@ -74,7 +72,7 @@ | ||||
|        transform="translate(-351.35714,708.36218)" | ||||
|        id="g16453"> | ||||
|       <rect | ||||
|          style="color:#000000;fill:#4a90d9;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994000000003;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|          style="color:#000000;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | ||||
|          id="rect16256-9-4" | ||||
|          width="63.000004" | ||||
|          height="19" | ||||
|   | ||||
| Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.7 KiB | 
							
								
								
									
										96
									
								
								data/theme/ws-switch-arrow-left.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,96 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
| <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="96" height="96" id="svg25070" version="1.1" inkscape:version="0.47 r22583" sodipodi:docname="dark-arrow-larger.svg"> | ||||
|   <defs id="defs25072"> | ||||
|     <inkscape:perspective sodipodi:type="inkscape:persp3d" inkscape:vp_x="0 : 24 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_z="48 : 24 : 1" inkscape:persp3d-origin="24 : 16 : 1" id="perspective25078"/> | ||||
|     <inkscape:perspective id="perspective24985" inkscape:persp3d-origin="0.5 : 0.33333333 : 1" inkscape:vp_z="1 : 0.5 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_x="0 : 0.5 : 1" sodipodi:type="inkscape:persp3d"/> | ||||
|     <linearGradient inkscape:collect="always" xlink:href="#linearGradient4034-0-4" id="linearGradient24957" gradientUnits="userSpaceOnUse" gradientTransform="translate(6)" x1="-86.552246" y1="185.439" x2="-83.37072" y2="197.31261"/> | ||||
|     <linearGradient inkscape:collect="always" id="linearGradient4034-0-4"> | ||||
|       <stop style="stop-color: rgb(238, 238, 236); stop-opacity: 1;" offset="0" id="stop4036-5-7"/> | ||||
|       <stop style="stop-color: rgb(186, 189, 182); stop-opacity: 1;" offset="1" id="stop4038-9-6"/> | ||||
|     </linearGradient> | ||||
|     <filter id="filter24765" inkscape:label="Invert" x="0" y="0" width="1" height="1" inkscape:menu="Color" inkscape:menu-tooltip="Invert colors" color-interpolation-filters="sRGB"> | ||||
|       <feColorMatrix id="feColorMatrix24767" type="saturate" values="1" result="fbSourceGraphic"/> | ||||
|       <feColorMatrix id="feColorMatrix24769" in="fbSourceGraphic" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/> | ||||
|     </filter> | ||||
|     <linearGradient inkscape:collect="always" xlink:href="#linearGradient4632-1-3-9-3-2" id="linearGradient24955" gradientUnits="userSpaceOnUse" gradientTransform="translate(-5)" x1="-74.520325" y1="169.06032" x2="-74.520325" y2="205.94189"/> | ||||
|     <linearGradient id="linearGradient4632-1-3-9-3-2"> | ||||
|       <stop style="stop-color: rgb(238, 238, 236); stop-opacity: 1;" offset="0" id="stop4634-1-8-3-9-0"/> | ||||
|       <stop id="stop4636-1-9-9-8-8" offset="0.0274937" style="stop-color: rgb(255, 255, 255); stop-opacity: 1;"/> | ||||
|       <stop id="stop4638-8-3-9-6-6" offset="0.274937" style="stop-color: rgb(242, 242, 242); stop-opacity: 1;"/> | ||||
|       <stop id="stop4640-8-5-7-8-9" offset="0.38707438" style="stop-color: rgb(238, 238, 236); stop-opacity: 1;"/> | ||||
|       <stop id="stop4642-5-41-9-6-9" offset="0.66528589" style="stop-color: rgb(217, 218, 216); stop-opacity: 1;"/> | ||||
|       <stop id="stop4644-5-2-7-9-2" offset="0.76745707" style="stop-color: rgb(223, 224, 221); stop-opacity: 1;"/> | ||||
|       <stop style="stop-color: rgb(240, 240, 240); stop-opacity: 1;" offset="1" id="stop4646-3-2-3-7-3"/> | ||||
|     </linearGradient> | ||||
|     <radialGradient inkscape:collect="always" xlink:href="#linearGradient4869-4-1" id="radialGradient24959" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0075, 0, 0, 1.0075, -5.4544, -1.25141)" cx="-33.412369" cy="185.74171" fx="-33.412369" fy="185.74171" r="2.3554697"/> | ||||
|     <linearGradient id="linearGradient4869-4-1"> | ||||
|       <stop style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" offset="0" id="stop4871-6-2"/> | ||||
|       <stop id="stop4879-7-4" offset="0.31807542" style="stop-color: rgb(238, 238, 236); stop-opacity: 1;"/> | ||||
|       <stop id="stop4877-6-1" offset="0.74691135" style="stop-color: rgb(200, 201, 198); stop-opacity: 1;"/> | ||||
|       <stop style="stop-color: rgb(211, 215, 207); stop-opacity: 1;" offset="1" id="stop4873-1-0"/> | ||||
|     </linearGradient> | ||||
|     <filter id="filter25011" inkscape:label="Invert" x="0" y="0" width="1" height="1" inkscape:menu="Color" inkscape:menu-tooltip="Invert colors" color-interpolation-filters="sRGB"> | ||||
|       <feColorMatrix id="feColorMatrix25013" type="saturate" values="1" result="fbSourceGraphic"/> | ||||
|       <feColorMatrix id="feColorMatrix25015" in="fbSourceGraphic" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/> | ||||
|     </filter> | ||||
|     <radialGradient inkscape:collect="always" xlink:href="#linearGradient4869-4-0" id="radialGradient24961" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0075, 0, 0, 1.0075, -5.4544, -1.25141)" cx="-33.412369" cy="185.74171" fx="-33.412369" fy="185.74171" r="2.3554697"/> | ||||
|     <linearGradient id="linearGradient4869-4-0"> | ||||
|       <stop style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" offset="0" id="stop4871-6-8"/> | ||||
|       <stop id="stop4879-7-5" offset="0.31807542" style="stop-color: rgb(238, 238, 236); stop-opacity: 1;"/> | ||||
|       <stop id="stop4877-6-5" offset="0.74691135" style="stop-color: rgb(200, 201, 198); stop-opacity: 1;"/> | ||||
|       <stop style="stop-color: rgb(211, 215, 207); stop-opacity: 1;" offset="1" id="stop4873-1-4"/> | ||||
|     </linearGradient> | ||||
|     <filter id="filter25023" inkscape:label="Invert" x="0" y="0" width="1" height="1" inkscape:menu="Color" inkscape:menu-tooltip="Invert colors" color-interpolation-filters="sRGB"> | ||||
|       <feColorMatrix id="feColorMatrix25025" type="saturate" values="1" result="fbSourceGraphic"/> | ||||
|       <feColorMatrix id="feColorMatrix25027" in="fbSourceGraphic" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/> | ||||
|     </filter> | ||||
|     <linearGradient inkscape:collect="always" xlink:href="#linearGradient4941" id="linearGradient24963" gradientUnits="userSpaceOnUse" x1="-39.858727" y1="184.61784" x2="-38.244785" y2="188.84898"/> | ||||
|     <linearGradient inkscape:collect="always" id="linearGradient4941"> | ||||
|       <stop style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" offset="0" id="stop4943"/> | ||||
|       <stop style="stop-color: rgb(255, 255, 255); stop-opacity: 0;" offset="1" id="stop4945"/> | ||||
|     </linearGradient> | ||||
|     <filter id="filter25033" inkscape:label="Invert" x="0" y="0" width="1" height="1" inkscape:menu="Color" inkscape:menu-tooltip="Invert colors" color-interpolation-filters="sRGB"> | ||||
|       <feColorMatrix id="feColorMatrix25035" type="saturate" values="1" result="fbSourceGraphic"/> | ||||
|       <feColorMatrix id="feColorMatrix25037" in="fbSourceGraphic" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/> | ||||
|     </filter> | ||||
|     <linearGradient inkscape:collect="always" xlink:href="#linearGradient4941-7" id="linearGradient24965" gradientUnits="userSpaceOnUse" x1="-39.858727" y1="184.61784" x2="-38.244785" y2="188.84898"/> | ||||
|     <linearGradient inkscape:collect="always" id="linearGradient4941-7"> | ||||
|       <stop style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" offset="0" id="stop4943-2"/> | ||||
|       <stop style="stop-color: rgb(255, 255, 255); stop-opacity: 0;" offset="1" id="stop4945-5"/> | ||||
|     </linearGradient> | ||||
|     <filter id="filter25043" inkscape:label="Invert" x="0" y="0" width="1" height="1" inkscape:menu="Color" inkscape:menu-tooltip="Invert colors" color-interpolation-filters="sRGB"> | ||||
|       <feColorMatrix id="feColorMatrix25045" type="saturate" values="1" result="fbSourceGraphic"/> | ||||
|       <feColorMatrix id="feColorMatrix25047" in="fbSourceGraphic" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/> | ||||
|     </filter> | ||||
|     <filter id="filter25049" inkscape:label="Invert" x="0" y="0" width="1" height="1" inkscape:menu="Color" inkscape:menu-tooltip="Invert colors" color-interpolation-filters="sRGB"> | ||||
|       <feColorMatrix id="feColorMatrix25051" type="saturate" values="1" result="fbSourceGraphic"/> | ||||
|       <feColorMatrix id="feColorMatrix25053" in="fbSourceGraphic" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/> | ||||
|     </filter> | ||||
|     <filter id="filter25055" inkscape:label="Invert" x="0" y="0" width="1" height="1" inkscape:menu="Color" inkscape:menu-tooltip="Invert colors" color-interpolation-filters="sRGB"> | ||||
|       <feColorMatrix id="feColorMatrix25057" type="saturate" values="1" result="fbSourceGraphic"/> | ||||
|       <feColorMatrix id="feColorMatrix25059" in="fbSourceGraphic" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/> | ||||
|     </filter> | ||||
|   </defs> | ||||
|   <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="2.8284271" inkscape:cx="48.631638" inkscape:cy="57.536221" inkscape:current-layer="layer1" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" inkscape:window-width="1200" inkscape:window-height="851" inkscape:window-x="0" inkscape:window-y="52" inkscape:window-maximized="0"/> | ||||
|   <metadata id="metadata25075"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> | ||||
|         <dc:title/> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer" transform="translate(0, 48)"> | ||||
|     <g id="g4030-1-8" transform="matrix(2, 0, 0, 2, 193.25, -374.967)" style="stroke: rgb(0, 0, 0); display: inline; stroke-opacity: 1;"> | ||||
|       <path sodipodi:nodetypes="ccc" id="path3165-7-3" d="m -72.5,173.5 -14,14 14,14" style="overflow: visible; marker: none; color: rgb(0, 0, 0); fill: none; stroke: rgb(0, 0, 0); stroke-width: 7; stroke-linecap: round; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-opacity: 1; stroke-dasharray: none; stroke-dashoffset: 0pt; visibility: visible; display: inline;"/> | ||||
|     </g> | ||||
|     <path sodipodi:type="arc" style="overflow: visible; marker: none; color: rgb(0, 0, 0); fill: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 0.523439; visibility: visible; display: inline;" id="path4050-2-7-9-4" sodipodi:cx="-38.59375" sodipodi:cy="186.40625" sodipodi:rx="2.09375" sodipodi:ry="2.09375" d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z" transform="matrix(3.34328, 0, 0, 3.34328, 185.28, -623.176)"/> | ||||
|     <path sodipodi:type="arc" style="overflow: visible; marker: none; color: rgb(0, 0, 0); fill: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 0.523439; visibility: visible; display: inline;" id="path4050-2-7-9-4-8" sodipodi:cx="-38.59375" sodipodi:cy="186.40625" sodipodi:rx="2.09375" sodipodi:ry="2.09375" d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z" transform="matrix(3.34328, 0, 0, 3.34328, 207.28, -623.176)"/> | ||||
|     <path sodipodi:type="arc" style="overflow: visible; marker: none; color: rgb(0, 0, 0); fill: none; stroke: rgb(0, 0, 0); stroke-width: 0.697921; stroke-linecap: round; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-opacity: 1; stroke-dasharray: none; stroke-dashoffset: 0pt; visibility: visible; display: inline;" id="path4050-2-7-9-4-0" sodipodi:cx="-38.59375" sodipodi:cy="186.40625" sodipodi:rx="2.09375" sodipodi:ry="2.09375" d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z" transform="matrix(2.86565, 0, 0, 2.86565, 166.846, -534.143)"/> | ||||
|     <path sodipodi:type="arc" style="overflow: visible; marker: none; color: rgb(0, 0, 0); fill: none; stroke: rgb(0, 0, 0); stroke-width: 0.697921; stroke-linecap: round; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-opacity: 1; stroke-dasharray: none; stroke-dashoffset: 0pt; visibility: visible; display: inline;" id="path4050-2-7-9-4-0-9" sodipodi:cx="-38.59375" sodipodi:cy="186.40625" sodipodi:rx="2.09375" sodipodi:ry="2.09375" d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z" transform="matrix(2.86565, 0, 0, 2.86565, 188.846, -534.143)"/> | ||||
|     <path style="overflow: visible; marker: none; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; text-indent: 0pt; text-align: start; text-decoration: none; line-height: normal; letter-spacing: normal; word-spacing: normal; text-transform: none; direction: ltr; text-anchor: start; opacity: 0.35; color: rgb(0, 0, 0); fill: none; stroke: rgb(0, 0, 0); stroke-width: 1; stroke-miterlimit: 4; stroke-dasharray: none; visibility: visible; display: inline; font-family: Bitstream Vera Sans; stroke-opacity: 1;" d="m 317.06251,365.96875 c -0.76948,0.0224 -1.52555,0.35464 -2.0625,0.90625 l -16.125,16.125 16.125,16.125 c 1.11265,1.11265 3.13735,1.11265 4.25,0 1.11265,-1.11264 1.11265,-3.13735 0,-4.25 l -11.875,-11.875 11.875,-11.875 c 0.86584,-0.83655 1.1475,-2.22114 0.6773,-3.32947 -0.47021,-1.10834 -1.66156,-1.86802 -2.8648,-1.82678 z" id="path3165-7-3-1" sodipodi:nodetypes="ccccscccsc" transform="matrix(2, 0, 0, 2, -586, -765.967)"/> | ||||
|     <path style="overflow: visible; marker: none; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; text-indent: 0pt; text-align: start; text-decoration: none; line-height: normal; letter-spacing: normal; word-spacing: normal; text-transform: none; direction: ltr; text-anchor: start; color: rgb(0, 0, 0); fill: none; stroke: rgb(0, 0, 0); stroke-width: 1; stroke-linecap: round; stroke-miterlimit: 4; stroke-dasharray: none; visibility: visible; display: inline; font-family: Bitstream Vera Sans; stroke-opacity: 1;" d="m 320.08435,397.03059 c 0.007,-0.79449 -0.27079,-1.59203 -0.83434,-2.15559 L 307.37501,383 m 12.5523,-15.20447 c -0.47021,-1.10834 -1.66156,-1.86802 -2.8648,-1.82678 -0.76948,0.0224 -1.52555,0.35464 -2.0625,0.90625 L 298.87501,383" id="path3165-7-3-1-9" sodipodi:nodetypes="ccccccc" transform="matrix(2, 0, 0, 2, -586, -765.967)"/> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 13 KiB | 
| @@ -2,51 +2,13 @@ | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
| 
 | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:xlink="http://www.w3.org/1999/xlink" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    version="1.1" | ||||
|    width="96" | ||||
|    height="96" | ||||
|    id="svg25070" | ||||
|    inkscape:version="0.48.0 r9654" | ||||
|    sodipodi:docname="ws-switch-arrow-down.svg"> | ||||
|   <metadata | ||||
|      id="metadata3353"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <sodipodi:namedview | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1" | ||||
|      objecttolerance="10" | ||||
|      gridtolerance="10" | ||||
|      guidetolerance="10" | ||||
|      inkscape:pageopacity="0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:window-width="718" | ||||
|      inkscape:window-height="480" | ||||
|      id="namedview3351" | ||||
|      showgrid="false" | ||||
|      inkscape:zoom="2.6979167" | ||||
|      inkscape:cx="48" | ||||
|      inkscape:cy="48" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="0" | ||||
|      inkscape:current-layer="svg25070" /> | ||||
|    id="svg25070"> | ||||
|   <defs | ||||
|      id="defs25072"> | ||||
|     <linearGradient | ||||
| @@ -326,7 +288,7 @@ | ||||
|     </filter> | ||||
|   </defs> | ||||
|   <g | ||||
|      transform="matrix(0,1,-1,0,48.0003,4.1307112e-7)" | ||||
|      transform="translate(0,48)" | ||||
|      id="layer1"> | ||||
|     <g | ||||
|        transform="matrix(-2,0,0,2,-97.2497,-374.967)" | ||||
| @@ -335,42 +297,35 @@ | ||||
|       <path | ||||
|          d="m -72.5,173.5 -14,14 14,14" | ||||
|          id="path3165-7-3" | ||||
|          style="color:#000000;fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" | ||||
|          inkscape:connector-curvature="0" /> | ||||
|          style="color:#000000;fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" /> | ||||
|     </g> | ||||
|     <path | ||||
|        d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z" | ||||
|        transform="matrix(-3.34328,0,0,3.34328,-89.2797,-623.176)" | ||||
|        id="path4050-2-7-9-4" | ||||
|        style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52343899;marker:none;visibility:visible;display:inline;overflow:visible" | ||||
|        inkscape:connector-curvature="0" /> | ||||
|        style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52343899;marker:none;visibility:visible;display:inline;overflow:visible" /> | ||||
|     <path | ||||
|        d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z" | ||||
|        transform="matrix(-3.34328,0,0,3.34328,-111.2797,-623.176)" | ||||
|        id="path4050-2-7-9-4-8" | ||||
|        style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52343899;marker:none;visibility:visible;display:inline;overflow:visible" | ||||
|        inkscape:connector-curvature="0" /> | ||||
|        style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52343899;marker:none;visibility:visible;display:inline;overflow:visible" /> | ||||
|     <path | ||||
|        d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z" | ||||
|        transform="matrix(-2.86565,0,0,2.86565,-70.8457,-534.143)" | ||||
|        id="path4050-2-7-9-4-0" | ||||
|        style="color:#000000;fill:none;stroke:#000000;stroke-width:0.69792098;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" | ||||
|        inkscape:connector-curvature="0" /> | ||||
|        style="color:#000000;fill:none;stroke:#000000;stroke-width:0.69792098;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" /> | ||||
|     <path | ||||
|        d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z" | ||||
|        transform="matrix(-2.86565,0,0,2.86565,-92.8457,-534.143)" | ||||
|        id="path4050-2-7-9-4-0-9" | ||||
|        style="color:#000000;fill:none;stroke:#000000;stroke-width:0.69792098;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" | ||||
|        inkscape:connector-curvature="0" /> | ||||
|        style="color:#000000;fill:none;stroke:#000000;stroke-width:0.69792098;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" /> | ||||
|     <path | ||||
|        d="m 47.87528,-34.0295 c 1.53896,0.0448 3.0511,0.70928 4.125,1.8125 l 32.25,32.25 -32.25,32.25 c -2.2253,2.2253 -6.2747,2.2253 -8.5,0 -2.2253,-2.22528 -2.2253,-6.2747 0,-8.5 l 23.75,-23.75 -23.75,-23.75 c -1.73168,-1.6731 -2.295,-4.44228 -1.3546,-6.65894 0.94042,-2.21668 3.32312,-3.73604 5.7296,-3.65356 z" | ||||
|        id="path3165-7-3-1" | ||||
|        style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0pt;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;opacity:0.35;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans" | ||||
|        inkscape:connector-curvature="0" /> | ||||
|        style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0pt;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;opacity:0.35;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans" /> | ||||
|     <path | ||||
|        d="m 41.8316,28.09418 c -0.014,-1.58898 0.54158,-3.18406 1.66868,-4.31118 l 23.75,-23.75 m -25.1046,-30.40894 c 0.94042,-2.21668 3.32312,-3.73604 5.7296,-3.65356 1.53896,0.0448 3.0511,0.70928 4.125,1.8125 l 32.25,32.25" | ||||
|        id="path3165-7-3-1-9" | ||||
|        style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0pt;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans" | ||||
|        inkscape:connector-curvature="0" /> | ||||
|        style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0pt;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans" /> | ||||
|   </g> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 12 KiB | 
| @@ -1,447 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:xlink="http://www.w3.org/1999/xlink" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="96" | ||||
|    height="96" | ||||
|    id="svg25070" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.48.0 r9654" | ||||
|    sodipodi:docname="ws-switch-arrow-up.svg"> | ||||
|   <defs | ||||
|      id="defs25072"> | ||||
|     <inkscape:perspective | ||||
|        sodipodi:type="inkscape:persp3d" | ||||
|        inkscape:vp_x="0 : 24 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_z="48 : 24 : 1" | ||||
|        inkscape:persp3d-origin="24 : 16 : 1" | ||||
|        id="perspective25078" /> | ||||
|     <inkscape:perspective | ||||
|        id="perspective24985" | ||||
|        inkscape:persp3d-origin="0.5 : 0.33333333 : 1" | ||||
|        inkscape:vp_z="1 : 0.5 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_x="0 : 0.5 : 1" | ||||
|        sodipodi:type="inkscape:persp3d" /> | ||||
|     <linearGradient | ||||
|        inkscape:collect="always" | ||||
|        xlink:href="#linearGradient4034-0-4" | ||||
|        id="linearGradient24957" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        gradientTransform="translate(6)" | ||||
|        x1="-86.552246" | ||||
|        y1="185.439" | ||||
|        x2="-83.37072" | ||||
|        y2="197.31261" /> | ||||
|     <linearGradient | ||||
|        inkscape:collect="always" | ||||
|        id="linearGradient4034-0-4"> | ||||
|       <stop | ||||
|          style="stop-color: rgb(238, 238, 236); stop-opacity: 1;" | ||||
|          offset="0" | ||||
|          id="stop4036-5-7" /> | ||||
|       <stop | ||||
|          style="stop-color: rgb(186, 189, 182); stop-opacity: 1;" | ||||
|          offset="1" | ||||
|          id="stop4038-9-6" /> | ||||
|     </linearGradient> | ||||
|     <filter | ||||
|        id="filter24765" | ||||
|        inkscape:label="Invert" | ||||
|        x="0" | ||||
|        y="0" | ||||
|        width="1" | ||||
|        height="1" | ||||
|        inkscape:menu="Color" | ||||
|        inkscape:menu-tooltip="Invert colors" | ||||
|        color-interpolation-filters="sRGB"> | ||||
|       <feColorMatrix | ||||
|          id="feColorMatrix24767" | ||||
|          type="saturate" | ||||
|          values="1" | ||||
|          result="fbSourceGraphic" /> | ||||
|       <feColorMatrix | ||||
|          id="feColorMatrix24769" | ||||
|          in="fbSourceGraphic" | ||||
|          values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" /> | ||||
|     </filter> | ||||
|     <linearGradient | ||||
|        inkscape:collect="always" | ||||
|        xlink:href="#linearGradient4632-1-3-9-3-2" | ||||
|        id="linearGradient24955" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        gradientTransform="translate(-5)" | ||||
|        x1="-74.520325" | ||||
|        y1="169.06032" | ||||
|        x2="-74.520325" | ||||
|        y2="205.94189" /> | ||||
|     <linearGradient | ||||
|        id="linearGradient4632-1-3-9-3-2"> | ||||
|       <stop | ||||
|          style="stop-color: rgb(238, 238, 236); stop-opacity: 1;" | ||||
|          offset="0" | ||||
|          id="stop4634-1-8-3-9-0" /> | ||||
|       <stop | ||||
|          id="stop4636-1-9-9-8-8" | ||||
|          offset="0.0274937" | ||||
|          style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" /> | ||||
|       <stop | ||||
|          id="stop4638-8-3-9-6-6" | ||||
|          offset="0.274937" | ||||
|          style="stop-color: rgb(242, 242, 242); stop-opacity: 1;" /> | ||||
|       <stop | ||||
|          id="stop4640-8-5-7-8-9" | ||||
|          offset="0.38707438" | ||||
|          style="stop-color: rgb(238, 238, 236); stop-opacity: 1;" /> | ||||
|       <stop | ||||
|          id="stop4642-5-41-9-6-9" | ||||
|          offset="0.66528589" | ||||
|          style="stop-color: rgb(217, 218, 216); stop-opacity: 1;" /> | ||||
|       <stop | ||||
|          id="stop4644-5-2-7-9-2" | ||||
|          offset="0.76745707" | ||||
|          style="stop-color: rgb(223, 224, 221); stop-opacity: 1;" /> | ||||
|       <stop | ||||
|          style="stop-color: rgb(240, 240, 240); stop-opacity: 1;" | ||||
|          offset="1" | ||||
|          id="stop4646-3-2-3-7-3" /> | ||||
|     </linearGradient> | ||||
|     <radialGradient | ||||
|        inkscape:collect="always" | ||||
|        xlink:href="#linearGradient4869-4-1" | ||||
|        id="radialGradient24959" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        gradientTransform="matrix(1.0075, 0, 0, 1.0075, -5.4544, -1.25141)" | ||||
|        cx="-33.412369" | ||||
|        cy="185.74171" | ||||
|        fx="-33.412369" | ||||
|        fy="185.74171" | ||||
|        r="2.3554697" /> | ||||
|     <linearGradient | ||||
|        id="linearGradient4869-4-1"> | ||||
|       <stop | ||||
|          style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" | ||||
|          offset="0" | ||||
|          id="stop4871-6-2" /> | ||||
|       <stop | ||||
|          id="stop4879-7-4" | ||||
|          offset="0.31807542" | ||||
|          style="stop-color: rgb(238, 238, 236); stop-opacity: 1;" /> | ||||
|       <stop | ||||
|          id="stop4877-6-1" | ||||
|          offset="0.74691135" | ||||
|          style="stop-color: rgb(200, 201, 198); stop-opacity: 1;" /> | ||||
|       <stop | ||||
|          style="stop-color: rgb(211, 215, 207); stop-opacity: 1;" | ||||
|          offset="1" | ||||
|          id="stop4873-1-0" /> | ||||
|     </linearGradient> | ||||
|     <filter | ||||
|        id="filter25011" | ||||
|        inkscape:label="Invert" | ||||
|        x="0" | ||||
|        y="0" | ||||
|        width="1" | ||||
|        height="1" | ||||
|        inkscape:menu="Color" | ||||
|        inkscape:menu-tooltip="Invert colors" | ||||
|        color-interpolation-filters="sRGB"> | ||||
|       <feColorMatrix | ||||
|          id="feColorMatrix25013" | ||||
|          type="saturate" | ||||
|          values="1" | ||||
|          result="fbSourceGraphic" /> | ||||
|       <feColorMatrix | ||||
|          id="feColorMatrix25015" | ||||
|          in="fbSourceGraphic" | ||||
|          values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" /> | ||||
|     </filter> | ||||
|     <radialGradient | ||||
|        inkscape:collect="always" | ||||
|        xlink:href="#linearGradient4869-4-0" | ||||
|        id="radialGradient24961" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        gradientTransform="matrix(1.0075, 0, 0, 1.0075, -5.4544, -1.25141)" | ||||
|        cx="-33.412369" | ||||
|        cy="185.74171" | ||||
|        fx="-33.412369" | ||||
|        fy="185.74171" | ||||
|        r="2.3554697" /> | ||||
|     <linearGradient | ||||
|        id="linearGradient4869-4-0"> | ||||
|       <stop | ||||
|          style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" | ||||
|          offset="0" | ||||
|          id="stop4871-6-8" /> | ||||
|       <stop | ||||
|          id="stop4879-7-5" | ||||
|          offset="0.31807542" | ||||
|          style="stop-color: rgb(238, 238, 236); stop-opacity: 1;" /> | ||||
|       <stop | ||||
|          id="stop4877-6-5" | ||||
|          offset="0.74691135" | ||||
|          style="stop-color: rgb(200, 201, 198); stop-opacity: 1;" /> | ||||
|       <stop | ||||
|          style="stop-color: rgb(211, 215, 207); stop-opacity: 1;" | ||||
|          offset="1" | ||||
|          id="stop4873-1-4" /> | ||||
|     </linearGradient> | ||||
|     <filter | ||||
|        id="filter25023" | ||||
|        inkscape:label="Invert" | ||||
|        x="0" | ||||
|        y="0" | ||||
|        width="1" | ||||
|        height="1" | ||||
|        inkscape:menu="Color" | ||||
|        inkscape:menu-tooltip="Invert colors" | ||||
|        color-interpolation-filters="sRGB"> | ||||
|       <feColorMatrix | ||||
|          id="feColorMatrix25025" | ||||
|          type="saturate" | ||||
|          values="1" | ||||
|          result="fbSourceGraphic" /> | ||||
|       <feColorMatrix | ||||
|          id="feColorMatrix25027" | ||||
|          in="fbSourceGraphic" | ||||
|          values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" /> | ||||
|     </filter> | ||||
|     <linearGradient | ||||
|        inkscape:collect="always" | ||||
|        xlink:href="#linearGradient4941" | ||||
|        id="linearGradient24963" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        x1="-39.858727" | ||||
|        y1="184.61784" | ||||
|        x2="-38.244785" | ||||
|        y2="188.84898" /> | ||||
|     <linearGradient | ||||
|        inkscape:collect="always" | ||||
|        id="linearGradient4941"> | ||||
|       <stop | ||||
|          style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" | ||||
|          offset="0" | ||||
|          id="stop4943" /> | ||||
|       <stop | ||||
|          style="stop-color: rgb(255, 255, 255); stop-opacity: 0;" | ||||
|          offset="1" | ||||
|          id="stop4945" /> | ||||
|     </linearGradient> | ||||
|     <filter | ||||
|        id="filter25033" | ||||
|        inkscape:label="Invert" | ||||
|        x="0" | ||||
|        y="0" | ||||
|        width="1" | ||||
|        height="1" | ||||
|        inkscape:menu="Color" | ||||
|        inkscape:menu-tooltip="Invert colors" | ||||
|        color-interpolation-filters="sRGB"> | ||||
|       <feColorMatrix | ||||
|          id="feColorMatrix25035" | ||||
|          type="saturate" | ||||
|          values="1" | ||||
|          result="fbSourceGraphic" /> | ||||
|       <feColorMatrix | ||||
|          id="feColorMatrix25037" | ||||
|          in="fbSourceGraphic" | ||||
|          values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" /> | ||||
|     </filter> | ||||
|     <linearGradient | ||||
|        inkscape:collect="always" | ||||
|        xlink:href="#linearGradient4941-7" | ||||
|        id="linearGradient24965" | ||||
|        gradientUnits="userSpaceOnUse" | ||||
|        x1="-39.858727" | ||||
|        y1="184.61784" | ||||
|        x2="-38.244785" | ||||
|        y2="188.84898" /> | ||||
|     <linearGradient | ||||
|        inkscape:collect="always" | ||||
|        id="linearGradient4941-7"> | ||||
|       <stop | ||||
|          style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" | ||||
|          offset="0" | ||||
|          id="stop4943-2" /> | ||||
|       <stop | ||||
|          style="stop-color: rgb(255, 255, 255); stop-opacity: 0;" | ||||
|          offset="1" | ||||
|          id="stop4945-5" /> | ||||
|     </linearGradient> | ||||
|     <filter | ||||
|        id="filter25043" | ||||
|        inkscape:label="Invert" | ||||
|        x="0" | ||||
|        y="0" | ||||
|        width="1" | ||||
|        height="1" | ||||
|        inkscape:menu="Color" | ||||
|        inkscape:menu-tooltip="Invert colors" | ||||
|        color-interpolation-filters="sRGB"> | ||||
|       <feColorMatrix | ||||
|          id="feColorMatrix25045" | ||||
|          type="saturate" | ||||
|          values="1" | ||||
|          result="fbSourceGraphic" /> | ||||
|       <feColorMatrix | ||||
|          id="feColorMatrix25047" | ||||
|          in="fbSourceGraphic" | ||||
|          values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" /> | ||||
|     </filter> | ||||
|     <filter | ||||
|        id="filter25049" | ||||
|        inkscape:label="Invert" | ||||
|        x="0" | ||||
|        y="0" | ||||
|        width="1" | ||||
|        height="1" | ||||
|        inkscape:menu="Color" | ||||
|        inkscape:menu-tooltip="Invert colors" | ||||
|        color-interpolation-filters="sRGB"> | ||||
|       <feColorMatrix | ||||
|          id="feColorMatrix25051" | ||||
|          type="saturate" | ||||
|          values="1" | ||||
|          result="fbSourceGraphic" /> | ||||
|       <feColorMatrix | ||||
|          id="feColorMatrix25053" | ||||
|          in="fbSourceGraphic" | ||||
|          values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" /> | ||||
|     </filter> | ||||
|     <filter | ||||
|        id="filter25055" | ||||
|        inkscape:label="Invert" | ||||
|        x="0" | ||||
|        y="0" | ||||
|        width="1" | ||||
|        height="1" | ||||
|        inkscape:menu="Color" | ||||
|        inkscape:menu-tooltip="Invert colors" | ||||
|        color-interpolation-filters="sRGB"> | ||||
|       <feColorMatrix | ||||
|          id="feColorMatrix25057" | ||||
|          type="saturate" | ||||
|          values="1" | ||||
|          result="fbSourceGraphic" /> | ||||
|       <feColorMatrix | ||||
|          id="feColorMatrix25059" | ||||
|          in="fbSourceGraphic" | ||||
|          values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" /> | ||||
|     </filter> | ||||
|   </defs> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="2.8284271" | ||||
|      inkscape:cx="-12.356322" | ||||
|      inkscape:cy="57.536221" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="true" | ||||
|      inkscape:grid-bbox="true" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:window-width="1200" | ||||
|      inkscape:window-height="840" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="0" /> | ||||
|   <metadata | ||||
|      id="metadata25075"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title /> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      id="layer1" | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      transform="translate(0, 48)"> | ||||
|     <g | ||||
|        id="g3181" | ||||
|        transform="matrix(0,1,-1,0,48.0003,-48)"> | ||||
|       <g | ||||
|          style="stroke:#000000;stroke-opacity:1;display:inline" | ||||
|          transform="matrix(2,0,0,2,193.25,-374.967)" | ||||
|          id="g4030-1-8"> | ||||
|         <path | ||||
|            style="color:#000000;fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" | ||||
|            d="m -72.5,173.5 -14,14 14,14" | ||||
|            id="path3165-7-3" | ||||
|            sodipodi:nodetypes="ccc" | ||||
|            inkscape:connector-curvature="0" /> | ||||
|       </g> | ||||
|       <path | ||||
|          transform="matrix(3.34328,0,0,3.34328,185.28,-623.176)" | ||||
|          d="m -36.5,186.40625 c 0,1.15635 -0.937404,2.09375 -2.09375,2.09375 -1.156346,0 -2.09375,-0.9374 -2.09375,-2.09375 0,-1.15635 0.937404,-2.09375 2.09375,-2.09375 1.156346,0 2.09375,0.9374 2.09375,2.09375 z" | ||||
|          sodipodi:ry="2.09375" | ||||
|          sodipodi:rx="2.09375" | ||||
|          sodipodi:cy="186.40625" | ||||
|          sodipodi:cx="-38.59375" | ||||
|          id="path4050-2-7-9-4" | ||||
|          style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52343899;marker:none;visibility:visible;display:inline;overflow:visible" | ||||
|          sodipodi:type="arc" /> | ||||
|       <path | ||||
|          transform="matrix(3.34328,0,0,3.34328,207.28,-623.176)" | ||||
|          d="m -36.5,186.40625 c 0,1.15635 -0.937404,2.09375 -2.09375,2.09375 -1.156346,0 -2.09375,-0.9374 -2.09375,-2.09375 0,-1.15635 0.937404,-2.09375 2.09375,-2.09375 1.156346,0 2.09375,0.9374 2.09375,2.09375 z" | ||||
|          sodipodi:ry="2.09375" | ||||
|          sodipodi:rx="2.09375" | ||||
|          sodipodi:cy="186.40625" | ||||
|          sodipodi:cx="-38.59375" | ||||
|          id="path4050-2-7-9-4-8" | ||||
|          style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52343899;marker:none;visibility:visible;display:inline;overflow:visible" | ||||
|          sodipodi:type="arc" /> | ||||
|       <path | ||||
|          transform="matrix(2.86565,0,0,2.86565,166.846,-534.143)" | ||||
|          d="m -36.5,186.40625 c 0,1.15635 -0.937404,2.09375 -2.09375,2.09375 -1.156346,0 -2.09375,-0.9374 -2.09375,-2.09375 0,-1.15635 0.937404,-2.09375 2.09375,-2.09375 1.156346,0 2.09375,0.9374 2.09375,2.09375 z" | ||||
|          sodipodi:ry="2.09375" | ||||
|          sodipodi:rx="2.09375" | ||||
|          sodipodi:cy="186.40625" | ||||
|          sodipodi:cx="-38.59375" | ||||
|          id="path4050-2-7-9-4-0" | ||||
|          style="color:#000000;fill:none;stroke:#000000;stroke-width:0.69792098;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" | ||||
|          sodipodi:type="arc" /> | ||||
|       <path | ||||
|          transform="matrix(2.86565,0,0,2.86565,188.846,-534.143)" | ||||
|          d="m -36.5,186.40625 c 0,1.15635 -0.937404,2.09375 -2.09375,2.09375 -1.156346,0 -2.09375,-0.9374 -2.09375,-2.09375 0,-1.15635 0.937404,-2.09375 2.09375,-2.09375 1.156346,0 2.09375,0.9374 2.09375,2.09375 z" | ||||
|          sodipodi:ry="2.09375" | ||||
|          sodipodi:rx="2.09375" | ||||
|          sodipodi:cy="186.40625" | ||||
|          sodipodi:cx="-38.59375" | ||||
|          id="path4050-2-7-9-4-0-9" | ||||
|          style="color:#000000;fill:none;stroke:#000000;stroke-width:0.69792098;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" | ||||
|          sodipodi:type="arc" /> | ||||
|       <path | ||||
|          transform="matrix(2,0,0,2,-586,-765.967)" | ||||
|          sodipodi:nodetypes="ccccscccsc" | ||||
|          id="path3165-7-3-1" | ||||
|          d="m 317.06251,365.96875 c -0.76948,0.0224 -1.52555,0.35464 -2.0625,0.90625 l -16.125,16.125 16.125,16.125 c 1.11265,1.11265 3.13735,1.11265 4.25,0 1.11265,-1.11264 1.11265,-3.13735 0,-4.25 l -11.875,-11.875 11.875,-11.875 c 0.86584,-0.83655 1.1475,-2.22114 0.6773,-3.32947 -0.47021,-1.10834 -1.66156,-1.86802 -2.8648,-1.82678 z" | ||||
|          style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0pt;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;opacity:0.35;color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans" | ||||
|          inkscape:connector-curvature="0" /> | ||||
|       <path | ||||
|          transform="matrix(2,0,0,2,-586,-765.967)" | ||||
|          sodipodi:nodetypes="ccccccc" | ||||
|          id="path3165-7-3-1-9" | ||||
|          d="m 320.08435,397.03059 c 0.007,-0.79449 -0.27079,-1.59203 -0.83434,-2.15559 L 307.37501,383 m 12.5523,-15.20447 c -0.47021,-1.10834 -1.66156,-1.86802 -2.8648,-1.82678 -0.76948,0.0224 -1.52555,0.35464 -2.0625,0.90625 L 298.87501,383" | ||||
|          style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0pt;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans" | ||||
|          inkscape:connector-curvature="0" /> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 16 KiB | 
| @@ -6,22 +6,6 @@ | ||||
|  | ||||
|   <name xml:lang="en">GNOME Shell</name> | ||||
|   <shortdesc xml:lang="en">Next generation GNOME desktop shell</shortdesc> | ||||
|   <description>GNOME Shell provides core user interface functions for the GNOME 3 | ||||
| desktop, like switching to windows and launching applications. | ||||
| GNOME Shell takes advantage of the capabilities of modern graphics | ||||
| hardware and introduces innovative user interface concepts to | ||||
| provide a visually attractive and easy to use experience. | ||||
|  | ||||
| Tarball releases are provided largely for distributions to build | ||||
| packages. If you are interested in building GNOME Shell from source, | ||||
| we would recommend building from version control using the build | ||||
| script described at: | ||||
|  | ||||
|  http://live.gnome.org/GnomeShell | ||||
|  | ||||
| Not only will that give you the very latest version of this rapidly | ||||
| changing project, it will be much easier than get GNOME Shell and | ||||
| its dependencies to build from tarballs.</description> | ||||
|   <!-- | ||||
|   <homepage rdf:resource="http://live.gnome.org/GnomeShell" /> | ||||
|   --> | ||||
| @@ -49,7 +33,7 @@ its dependencies to build from tarballs.</description> | ||||
|     <foaf:Person> | ||||
|       <foaf:name>Colin Walters</foaf:name> | ||||
|       <foaf:mbox rdf:resource="mailto:walters@verbum.org" /> | ||||
|       <gnome:userid>walters</gnome:userid> | ||||
|       <gnome:userid>cwalters</gnome:userid> | ||||
|     </foaf:Person> | ||||
|   </maintainer> | ||||
|   <maintainer> | ||||
|   | ||||
| @@ -2,38 +2,27 @@ | ||||
| jsdir = $(pkgdatadir)/js | ||||
|  | ||||
| nobase_dist_js_DATA = 	\ | ||||
| 	gdm/batch.js		\ | ||||
| 	gdm/loginDialog.js	\ | ||||
| 	misc/config.js		\ | ||||
| 	misc/docInfo.js		\ | ||||
| 	misc/fileUtils.js	\ | ||||
| 	misc/format.js		\ | ||||
| 	misc/gnomeSession.js	\ | ||||
| 	misc/history.js		\ | ||||
| 	misc/modemManager.js	\ | ||||
| 	misc/params.js		\ | ||||
| 	misc/screenSaver.js     \ | ||||
| 	misc/util.js		\ | ||||
| 	misc/telepathy.js	\ | ||||
| 	perf/core.js		\ | ||||
| 	prefs/clockPreferences.js \ | ||||
| 	ui/altTab.js		\ | ||||
| 	ui/appDisplay.js	\ | ||||
| 	ui/appFavorites.js	\ | ||||
| 	ui/automountManager.js  \ | ||||
| 	ui/autorunManager.js    \ | ||||
| 	ui/boxpointer.js	\ | ||||
| 	ui/calendar.js		\ | ||||
| 	ui/contactDisplay.js \ | ||||
| 	ui/ctrlAltTab.js	\ | ||||
| 	ui/chrome.js		\ | ||||
| 	ui/dash.js		\ | ||||
| 	ui/dateMenu.js		\ | ||||
| 	ui/dnd.js		\ | ||||
| 	ui/docDisplay.js	\ | ||||
| 	ui/endSessionDialog.js	\ | ||||
| 	ui/environment.js	\ | ||||
| 	ui/extensionSystem.js	\ | ||||
| 	ui/genericDisplay.js	\ | ||||
| 	ui/iconGrid.js		\ | ||||
| 	ui/keyboard.js		\ | ||||
| 	ui/layout.js		\ | ||||
| 	ui/lightbox.js		\ | ||||
| 	ui/link.js		\ | ||||
| 	ui/lookingGlass.js	\ | ||||
| @@ -41,15 +30,11 @@ nobase_dist_js_DATA = 	\ | ||||
| 	ui/magnifierDBus.js	\ | ||||
| 	ui/main.js		\ | ||||
| 	ui/messageTray.js	\ | ||||
| 	ui/modalDialog.js	\ | ||||
| 	ui/networkAgent.js	\ | ||||
| 	ui/shellMountOperation.js \ | ||||
| 	ui/notificationDaemon.js \ | ||||
| 	ui/overview.js		\ | ||||
| 	ui/panel.js		\ | ||||
| 	ui/panelMenu.js		\ | ||||
| 	ui/placeDisplay.js	\ | ||||
| 	ui/polkitAuthenticationAgent.js \ | ||||
| 	ui/popupMenu.js		\ | ||||
| 	ui/runDialog.js		\ | ||||
| 	ui/scripting.js		\ | ||||
| @@ -57,20 +42,15 @@ nobase_dist_js_DATA = 	\ | ||||
| 	ui/searchDisplay.js	\ | ||||
| 	ui/shellDBus.js		\ | ||||
| 	ui/statusIconDispatcher.js	\ | ||||
| 	ui/statusMenu.js	\ | ||||
| 	ui/status/accessibility.js	\ | ||||
| 	ui/status/keyboard.js	\ | ||||
| 	ui/status/network.js	\ | ||||
| 	ui/status/power.js	\ | ||||
| 	ui/status/volume.js	\ | ||||
| 	ui/status/bluetooth.js	\ | ||||
| 	ui/telepathyClient.js	\ | ||||
| 	ui/tweener.js		\ | ||||
| 	ui/userMenu.js		\ | ||||
| 	ui/viewSelector.js	\ | ||||
| 	ui/windowAttentionHandler.js	\ | ||||
| 	ui/windowManager.js	\ | ||||
| 	ui/workspace.js		\ | ||||
| 	ui/workspaceThumbnail.js	\ | ||||
| 	ui/workspacesView.js	\ | ||||
| 	ui/workspaceSwitcherPopup.js    \ | ||||
| 	ui/xdndHandler.js | ||||
| 	ui/workspaceSwitcherPopup.js | ||||
|   | ||||
							
								
								
									
										228
									
								
								js/gdm/batch.js
									
									
									
									
									
								
							
							
						
						| @@ -1,228 +0,0 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- | ||||
|  * | ||||
|  * Copyright 2011 Red Hat, Inc | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2, or (at your option) | ||||
|  * any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software | ||||
|  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||||
|  * 02111-1307, USA. | ||||
|  */ | ||||
|  | ||||
| const Lang = imports.lang; | ||||
| const Signals = imports.signals; | ||||
|  | ||||
| function Task() { | ||||
|     this._init.apply(this, arguments); | ||||
| } | ||||
|  | ||||
| Task.prototype = { | ||||
|     _init: function(scope, handler) { | ||||
|         if (scope) | ||||
|             this.scope = scope; | ||||
|         else | ||||
|             this.scope = this; | ||||
|  | ||||
|         this.handler = handler; | ||||
|     }, | ||||
|  | ||||
|     run: function() { | ||||
|         if (this.handler) | ||||
|             return this.handler.call(this.scope); | ||||
|  | ||||
|         return null; | ||||
|     }, | ||||
| }; | ||||
| Signals.addSignalMethods(Task.prototype); | ||||
|  | ||||
| function Hold() { | ||||
|     this._init.apply(this, arguments); | ||||
| } | ||||
|  | ||||
| Hold.prototype = { | ||||
|     __proto__: Task.prototype, | ||||
|  | ||||
|     _init: function() { | ||||
|         Task.prototype._init.call(this, | ||||
|                                   this, | ||||
|                                   function () { | ||||
|                                       return this; | ||||
|                                   }); | ||||
|  | ||||
|         this._acquisitions = 1; | ||||
|     }, | ||||
|  | ||||
|     acquire: function() { | ||||
|         if (this._acquisitions <= 0) | ||||
|             throw new Error("Cannot acquire hold after it's been released"); | ||||
|         this._acquisitions++; | ||||
|     }, | ||||
|  | ||||
|     acquireUntilAfter: function(hold) { | ||||
|         if (!hold.isAcquired()) | ||||
|             return; | ||||
|  | ||||
|         this.acquire(); | ||||
|         let signalId = hold.connect('release', Lang.bind(this, function() { | ||||
|                                         hold.disconnect(signalId); | ||||
|                                         this.release(); | ||||
|                                     })); | ||||
|     }, | ||||
|  | ||||
|     release: function() { | ||||
|         this._acquisitions--; | ||||
|  | ||||
|         if (this._acquisitions == 0) | ||||
|             this.emit('release'); | ||||
|     }, | ||||
|  | ||||
|     isAcquired: function() { | ||||
|         return this._acquisitions > 0; | ||||
|     } | ||||
| } | ||||
| Signals.addSignalMethods(Hold.prototype); | ||||
|  | ||||
| function Batch() { | ||||
|     this._init.apply(this, arguments); | ||||
| } | ||||
|  | ||||
| Batch.prototype = { | ||||
|     __proto__: Task.prototype, | ||||
|  | ||||
|     _init: function(scope, tasks) { | ||||
|         Task.prototype._init.call(this); | ||||
|  | ||||
|         this.tasks = []; | ||||
|  | ||||
|         for (let i = 0; i < tasks.length; i++) { | ||||
|             let task; | ||||
|  | ||||
|             if (tasks[i] instanceof Task) { | ||||
|                 task = tasks[i]; | ||||
|             } else if (typeof tasks[i] == 'function') { | ||||
|                 task = new Task(scope, tasks[i]); | ||||
|             } else { | ||||
|                 throw new Error('Batch tasks must be functions or Task, Hold or Batch objects'); | ||||
|             } | ||||
|  | ||||
|             this.tasks.push(task); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     process: function() { | ||||
|         throw new Error('Not implemented'); | ||||
|     }, | ||||
|  | ||||
|     runTask: function() { | ||||
|         if (!(this._currentTaskIndex in this.tasks)) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         return this.tasks[this._currentTaskIndex].run(); | ||||
|     }, | ||||
|  | ||||
|     _finish: function() { | ||||
|         this.hold.release(); | ||||
|     }, | ||||
|  | ||||
|     nextTask: function() { | ||||
|         this._currentTaskIndex++; | ||||
|  | ||||
|         // if the entire batch of tasks is finished, release | ||||
|         // the hold and notify anyone waiting on the batch | ||||
|         if (this._currentTaskIndex >= this.tasks.length) { | ||||
|             this._finish(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         this.process(); | ||||
|     }, | ||||
|  | ||||
|     _start: function() { | ||||
|         // acquire a hold to get released when the entire | ||||
|         // batch of tasks is finished | ||||
|         this.hold = new Hold(); | ||||
|         this._currentTaskIndex = 0; | ||||
|         this.process(); | ||||
|     }, | ||||
|  | ||||
|     run: function() { | ||||
|         this._start(); | ||||
|  | ||||
|         // hold may be destroyed at this point | ||||
|         // if we're already done running | ||||
|         return this.hold; | ||||
|     }, | ||||
|  | ||||
|     cancel: function() { | ||||
|         this.tasks = this.tasks.splice(0, this._currentTaskIndex + 1); | ||||
|     } | ||||
|  | ||||
| }; | ||||
| Signals.addSignalMethods(Batch.prototype); | ||||
|  | ||||
| function ConcurrentBatch() { | ||||
|     this._init.apply(this, arguments); | ||||
| } | ||||
|  | ||||
| ConcurrentBatch.prototype = { | ||||
|     __proto__: Batch.prototype, | ||||
|  | ||||
|     _init: function(scope, tasks) { | ||||
|         Batch.prototype._init.call(this, scope, tasks); | ||||
|     }, | ||||
|  | ||||
|     process: function() { | ||||
|        let hold = this.runTask(); | ||||
|  | ||||
|        if (hold) { | ||||
|            this.hold.acquireUntilAfter(hold); | ||||
|        } | ||||
|  | ||||
|        // Regardless of the state of the just run task, | ||||
|        // fire off the next one, so all the tasks can run | ||||
|        // concurrently. | ||||
|        this.nextTask(); | ||||
|     } | ||||
| }; | ||||
| Signals.addSignalMethods(ConcurrentBatch.prototype); | ||||
|  | ||||
| function ConsecutiveBatch() { | ||||
|     this._init.apply(this, arguments); | ||||
| } | ||||
|  | ||||
| ConsecutiveBatch.prototype = { | ||||
|     __proto__: Batch.prototype, | ||||
|  | ||||
|     _init: function(scope, tasks) { | ||||
|         Batch.prototype._init.call(this, scope, tasks); | ||||
|     }, | ||||
|  | ||||
|     process: function() { | ||||
|        let hold = this.runTask(); | ||||
|  | ||||
|        if (hold && hold.isAcquired()) { | ||||
|            // This task is inhibiting the batch. Wait on it | ||||
|            // before processing the next one. | ||||
|            let signalId = hold.connect('release', | ||||
|                                        Lang.bind(this, function() { | ||||
|                                            hold.disconnect(signalId); | ||||
|                                            this.nextTask(); | ||||
|                                        })); | ||||
|            return; | ||||
|        } else { | ||||
|            // This task finished, process the next one | ||||
|            this.nextTask(); | ||||
|        } | ||||
|     } | ||||
| }; | ||||
| Signals.addSignalMethods(ConsecutiveBatch.prototype); | ||||
| @@ -1,11 +0,0 @@ | ||||
| /* mode: js2; indent-tabs-mode: nil; tab-size: 4 */ | ||||
| /* The name of this package (not localized) */ | ||||
| const PACKAGE_NAME = '@PACKAGE_NAME@'; | ||||
| /* The version of this package */ | ||||
| const PACKAGE_VERSION = '@PACKAGE_VERSION@'; | ||||
| /* The version of GJS we're linking to */ | ||||
| const GJS_VERSION = '@GJS_VERSION@'; | ||||
| /* 1 if gnome-bluetooth is available, 0 otherwise */ | ||||
| const HAVE_BLUETOOTH = @HAVE_BLUETOOTH@; | ||||
| /* The system TLS CA list */ | ||||
| const SHELL_SYSTEM_CA_FILE = '@SHELL_SYSTEM_CA_FILE@'; | ||||
| @@ -29,8 +29,8 @@ DocInfo.prototype = { | ||||
|         return St.TextureCache.get_default().load_recent_thumbnail(size, this.recentInfo); | ||||
|     }, | ||||
|  | ||||
|     launch : function(workspaceIndex) { | ||||
|         Shell.DocSystem.get_default().open(this.recentInfo, workspaceIndex); | ||||
|     launch : function() { | ||||
|         Shell.DocSystem.get_default().open(this.recentInfo); | ||||
|     }, | ||||
|  | ||||
|     matchTerms: function(terms) { | ||||
| @@ -60,7 +60,8 @@ function getDocManager() { | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * DocManager wraps the DocSystem, primarily to expose DocInfo objects. | ||||
|  * DocManager wraps the DocSystem, primarily to expose DocInfo objects | ||||
|  * which conform to the GenericDisplay item API. | ||||
|  */ | ||||
| function DocManager() { | ||||
|     this._init(); | ||||
|   | ||||
| @@ -20,25 +20,3 @@ function listDirAsync(file, callback) { | ||||
|         enumerator.next_files_async(100, GLib.PRIORITY_LOW, null, onNextFileComplete); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function deleteGFile(file) { | ||||
|     // Work around 'delete' being a keyword in JS. | ||||
|     return file['delete'](null); | ||||
| } | ||||
|  | ||||
| function recursivelyDeleteDir(dir) { | ||||
|     let children = dir.enumerate_children('standard::name,standard::type', | ||||
|                                           Gio.FileQueryInfoFlags.NONE, null); | ||||
|  | ||||
|     let info, child; | ||||
|     while ((info = children.next_file(null)) != null) { | ||||
|         let type = info.get_file_type(); | ||||
|         let child = dir.get_child(info.get_name()); | ||||
|         if (type == Gio.FileType.REGULAR) | ||||
|             deleteGFile(child); | ||||
|         else if (type == Gio.TypeType.DIRECTORY) | ||||
|             recursivelyDeleteDir(child); | ||||
|     } | ||||
|  | ||||
|     deleteGFile(dir); | ||||
| } | ||||
|   | ||||
| @@ -2,13 +2,11 @@ | ||||
|  | ||||
| const DBus = imports.dbus; | ||||
| const Lang = imports.lang; | ||||
| const Signals = imports.signals; | ||||
|  | ||||
| const PresenceIface = { | ||||
|     name: 'org.gnome.SessionManager.Presence', | ||||
|     methods: [{ name: 'SetStatus', | ||||
|                 inSignature: 'u', | ||||
|                 outSignature: '' }], | ||||
|                 inSignature: 'u' }], | ||||
|     properties: [{ name: 'status', | ||||
|                    signature: 'u', | ||||
|                    access: 'readwrite' }], | ||||
| @@ -45,82 +43,3 @@ Presence.prototype = { | ||||
|     } | ||||
| }; | ||||
| DBus.proxifyPrototype(Presence.prototype, PresenceIface); | ||||
|  | ||||
| // Note inhibitors are immutable objects, so they don't | ||||
| // change at runtime (changes always come in the form | ||||
| // of new inhibitors) | ||||
| const InhibitorIface = { | ||||
|     name: 'org.gnome.SessionManager.Inhibitor', | ||||
|     properties: [{ name: 'app_id', | ||||
|                    signature: 's', | ||||
|                    access: 'readonly' }, | ||||
|                  { name: 'client_id', | ||||
|                    signature: 's', | ||||
|                    access: 'readonly' }, | ||||
|                  { name: 'reason', | ||||
|                    signature: 's', | ||||
|                    access: 'readonly' }, | ||||
|                  { name: 'flags', | ||||
|                    signature: 'u', | ||||
|                    access: 'readonly' }, | ||||
|                  { name: 'toplevel_xid', | ||||
|                    signature: 'u', | ||||
|                    access: 'readonly' }, | ||||
|                  { name: 'cookie', | ||||
|                    signature: 'u', | ||||
|                    access: 'readonly' }], | ||||
| }; | ||||
|  | ||||
| function Inhibitor(objectPath) { | ||||
|     this._init(objectPath); | ||||
| } | ||||
|  | ||||
| Inhibitor.prototype = { | ||||
|     _init: function(objectPath) { | ||||
|         DBus.session.proxifyObject(this, | ||||
|                                    "org.gnome.SessionManager", | ||||
|                                    objectPath); | ||||
|         this.isLoaded = false; | ||||
|         this._loadingPropertiesCount = InhibitorIface.properties.length; | ||||
|         for (let i = 0; i < InhibitorIface.properties.length; i++) { | ||||
|             let propertyName = InhibitorIface.properties[i].name; | ||||
|             this.GetRemote(propertyName, Lang.bind(this, | ||||
|                 function(value, exception) { | ||||
|                     if (exception) | ||||
|                         return; | ||||
|  | ||||
|                     this[propertyName] = value; | ||||
|                     this._loadingPropertiesCount--; | ||||
|  | ||||
|                     if (this._loadingPropertiesCount == 0) { | ||||
|                         this.isLoaded = true; | ||||
|                         this.emit("is-loaded"); | ||||
|                     } | ||||
|                 })); | ||||
|         } | ||||
|     }, | ||||
| }; | ||||
| DBus.proxifyPrototype(Inhibitor.prototype, InhibitorIface); | ||||
| Signals.addSignalMethods(Inhibitor.prototype); | ||||
|  | ||||
|  | ||||
| // Not the full interface, only the methods we use | ||||
| const SessionManagerIface = { | ||||
|     name: 'org.gnome.SessionManager', | ||||
|     methods: [ | ||||
|         { name: 'Logout', inSignature: 'u', outSignature: '' }, | ||||
|         { name: 'Shutdown', inSignature: '', outSignature: '' }, | ||||
|         { name: 'CanShutdown', inSignature: '', outSignature: 'b' } | ||||
|     ] | ||||
| }; | ||||
|  | ||||
| function SessionManager() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| SessionManager.prototype = { | ||||
|     _init: function() { | ||||
|         DBus.session.proxifyObject(this, 'org.gnome.SessionManager', '/org/gnome/SessionManager'); | ||||
|     } | ||||
| }; | ||||
| DBus.proxifyPrototype(SessionManager.prototype, SessionManagerIface); | ||||
| @@ -1,115 +0,0 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Lang = imports.lang; | ||||
| const Signals = imports.signals; | ||||
| const Clutter = imports.gi.Clutter; | ||||
| const Params = imports.misc.params; | ||||
|  | ||||
| const DEFAULT_LIMIT = 512; | ||||
|  | ||||
| function HistoryManager(params) { | ||||
|     this._init(params); | ||||
| } | ||||
|  | ||||
| HistoryManager.prototype = { | ||||
|     _init: function(params) { | ||||
|         params = Params.parse(params, { gsettingsKey: null, | ||||
|                                         limit: DEFAULT_LIMIT, | ||||
|                                         entry: null }); | ||||
|  | ||||
|         this._key = params.gsettingsKey; | ||||
|         this._limit = params.limit; | ||||
|  | ||||
|         this._historyIndex = 0; | ||||
|         if (this._key) { | ||||
|             this._history = global.settings.get_strv(this._key); | ||||
|             global.settings.connect('changed::' + this._key, | ||||
|                                     Lang.bind(this, this._historyChanged)); | ||||
|  | ||||
|         } else { | ||||
|             this._history = []; | ||||
|         } | ||||
|  | ||||
|         this._entry = params.entry; | ||||
|  | ||||
|         if (this._entry) { | ||||
|             this._entry.connect('key-press-event',  | ||||
|                                 Lang.bind(this, this._onEntryKeyPress)); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _historyChanged: function() { | ||||
|         this._history = global.settings.get_strv(this._key); | ||||
|         this._historyIndex = this._history.length; | ||||
|     }, | ||||
|  | ||||
|     prevItem: function(text) { | ||||
|         if (this._historyIndex <= 0) | ||||
|             return text; | ||||
|  | ||||
|         if (text) | ||||
|             this._history[this._historyIndex] = text; | ||||
|         this._historyIndex--; | ||||
|         return this._indexChanged(); | ||||
|     }, | ||||
|  | ||||
|     nextItem: function(text) { | ||||
|         if (this._historyIndex >= this._history.length) | ||||
|             return text; | ||||
|  | ||||
|         if (text) | ||||
|             this._history[this._historyIndex] = text; | ||||
|         this._historyIndex++; | ||||
|         return this._indexChanged(); | ||||
|     }, | ||||
|  | ||||
|     lastItem: function() { | ||||
|         if (this._historyIndex != this._history.length) { | ||||
|             this._historyIndex = this._history.length; | ||||
|             this._indexChanged(); | ||||
|         } | ||||
|  | ||||
|         return this._historyIndex[this._history.length]; | ||||
|     }, | ||||
|  | ||||
|     addItem: function(input) { | ||||
|         if (this._history.length == 0 || | ||||
|             this._history[this._history.length - 1] != input) { | ||||
|  | ||||
|             this._history.push(input); | ||||
|             this._save(); | ||||
|         } | ||||
|         this._historyIndex = this._history.length; | ||||
|     }, | ||||
|  | ||||
|     _onEntryKeyPress: function(entry, event) { | ||||
|         let symbol = event.get_key_symbol(); | ||||
|         if (symbol == Clutter.KEY_Up) { | ||||
|             this.prevItem(entry.get_text()); | ||||
|             return true; | ||||
|         } else if (symbol == Clutter.KEY_Down) { | ||||
|             this.nextItem(entry.get_text()); | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     }, | ||||
|  | ||||
|     _indexChanged: function() { | ||||
|         let current = this._history[this._historyIndex] || ''; | ||||
|         this.emit('changed', current); | ||||
|  | ||||
|         if (this._entry) | ||||
|             this._entry.set_text(current); | ||||
|  | ||||
|         return current; | ||||
|     }, | ||||
|  | ||||
|     _save: function() { | ||||
|         if (this._history.length > this._limit) | ||||
|             this._history.splice(0, this._history.length - this._limit); | ||||
|  | ||||
|         if (this._key) | ||||
|             global.settings.set_strv(this._key, this._history); | ||||
|     } | ||||
| }; | ||||
| Signals.addSignalMethods(HistoryManager.prototype); | ||||
| @@ -1,225 +0,0 @@ | ||||
| // -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- | ||||
|  | ||||
| const DBus = imports.dbus; | ||||
| const Lang = imports.lang; | ||||
| const Shell = imports.gi.Shell; | ||||
| const Signals = imports.signals; | ||||
|  | ||||
| // The following are not the complete interfaces, just the methods we need | ||||
| // (or may need in the future) | ||||
|  | ||||
| const ModemGsmNetworkInterface = { | ||||
|     name: 'org.freedesktop.ModemManager.Modem.Gsm.Network', | ||||
|     methods: [ | ||||
|         { name: 'GetRegistrationInfo', inSignature: '', outSignature: 'uss' }, | ||||
|         { name: 'GetSignalQuality', inSignature: '', outSignature: 'u' } | ||||
|     ], | ||||
|     properties: [ | ||||
|         { name: 'AccessTechnology', signature: 'u', access: 'read' } | ||||
|     ], | ||||
|     signals: [ | ||||
|         { name: 'SignalQuality', inSignature: 'u' }, | ||||
|         { name: 'RegistrationInfo', inSignature: 'uss' } | ||||
|     ] | ||||
| }; | ||||
| const ModemGsmNetworkProxy = DBus.makeProxyClass(ModemGsmNetworkInterface); | ||||
|  | ||||
| const ModemCdmaInterface = { | ||||
|     name: 'org.freedesktop.ModemManager.Modem.Cdma', | ||||
|     methods: [ | ||||
|         { name: 'GetSignalQuality', inSignature: '', outSignature: 'u' }, | ||||
|         { name: 'GetServingSystem', inSignature: '', outSignature: 'usu' } | ||||
|     ], | ||||
|     signals: [ | ||||
|         { name: 'SignalQuality', inSignature: 'u' } | ||||
|     ] | ||||
| }; | ||||
| const ModemCdmaProxy = DBus.makeProxyClass(ModemCdmaInterface); | ||||
|  | ||||
| let _providersTable; | ||||
| function _getProvidersTable() { | ||||
|     if (_providersTable) | ||||
|         return _providersTable; | ||||
|     let [providers, countryCodes] = Shell.mobile_providers_parse(); | ||||
|     return _providersTable = providers; | ||||
| } | ||||
|  | ||||
| function ModemGsm() { | ||||
|     this._init.apply(this, arguments); | ||||
| } | ||||
|  | ||||
| ModemGsm.prototype = { | ||||
|     _init: function(path) { | ||||
|         this._proxy = new ModemGsmNetworkProxy(DBus.system, 'org.freedesktop.ModemManager', path); | ||||
|  | ||||
|         this.signal_quality = 0; | ||||
|         this.operator_name = null; | ||||
|  | ||||
|         // Code is duplicated because the function have different signatures | ||||
|         this._proxy.connect('SignalQuality', Lang.bind(this, function(proxy, quality) { | ||||
|             this.signal_quality = quality; | ||||
|             this.emit('notify::signal-quality'); | ||||
|         })); | ||||
|         this._proxy.connect('RegistrationInfo', Lang.bind(this, function(proxy, status, code, name) { | ||||
|             this.operator_name = this._findOperatorName(name, code); | ||||
|             this.emit('notify::operator-name'); | ||||
|         })); | ||||
|         this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function(result, err) { | ||||
|             if (err) { | ||||
|                 log(err); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             let [status, code, name] = result; | ||||
|             this.operator_name = this._findOperatorName(name, code); | ||||
|             this.emit('notify::operator-name'); | ||||
|         })); | ||||
|         this._proxy.GetSignalQualityRemote(Lang.bind(this, function(result, err) { | ||||
|             if (err) { | ||||
|                 // it will return an error if the device is not connected | ||||
|                 this.signal_quality = 0; | ||||
|             } else { | ||||
|                 let [quality] = result; | ||||
|                 this.signal_quality = quality; | ||||
|             } | ||||
|             this.emit('notify::signal-quality'); | ||||
|         })); | ||||
|     }, | ||||
|  | ||||
|     _findOperatorName: function(name, opCode) { | ||||
|         if (name.length != 0 && (name.length > 6 || name.length < 5)) { | ||||
|             // this looks like a valid name, i.e. not an MCCMNC (that some | ||||
|             // devices return when not yet connected | ||||
|             return name; | ||||
|         } | ||||
|         if (isNaN(parseInt(name))) { | ||||
|             // name is definitely not a MCCMNC, so it may be a name | ||||
|             // after all; return that | ||||
|             return name; | ||||
|         } | ||||
|  | ||||
|         let needle; | ||||
|         if (name.length == 0 && opCode) | ||||
|             needle = opCode; | ||||
|         else if (name.length == 6 || name.length == 5) | ||||
|             needle = name; | ||||
|         else // nothing to search | ||||
|             return null; | ||||
|  | ||||
|         return this._findProviderForMCCMNC(needle); | ||||
|     }, | ||||
|  | ||||
|     _findProviderForMCCMNC: function(needle) { | ||||
|         let table = _getProvidersTable(); | ||||
|         let needlemcc = needle.substring(0, 3); | ||||
|         let needlemnc = needle.substring(3, needle.length); | ||||
|  | ||||
|         let name2, name3; | ||||
|         for (let iter in table) { | ||||
|             let providers = table[iter]; | ||||
|  | ||||
|             // Search through each country's providers | ||||
|             for (let i = 0; i < providers.length; i++) { | ||||
|                 let provider = providers[i]; | ||||
|  | ||||
|                 // Search through MCC/MNC list | ||||
|                 let list = provider.get_gsm_mcc_mnc(); | ||||
|                 for (let j = 0; j < list.length; j++) { | ||||
|                     let mccmnc = list[j]; | ||||
|  | ||||
|                     // Match both 2-digit and 3-digit MNC; prefer a | ||||
|                     // 3-digit match if found, otherwise a 2-digit one. | ||||
|                     if (mccmnc.mcc != needlemcc) | ||||
|                         continue;  // MCC was wrong | ||||
|  | ||||
|                     if (!name3 && needle.length == 6 && needlemnc == mccmnc.mnc) | ||||
|                         name3 = provider.name; | ||||
|  | ||||
|                     if (!name2 && needlemnc.substring(0, 2) == mccmnc.mnc.substring(0, 2)) | ||||
|                         name2 = provider.name; | ||||
|  | ||||
|                     if (name2 && name3) | ||||
|                         break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return name3 || name2 || null; | ||||
|     } | ||||
| } | ||||
| Signals.addSignalMethods(ModemGsm.prototype); | ||||
|  | ||||
| function ModemCdma() { | ||||
|     this._init.apply(this, arguments); | ||||
| } | ||||
|  | ||||
| ModemCdma.prototype = { | ||||
|     _init: function(path) { | ||||
|         this._proxy = new ModemCdmaProxy(DBus.system, 'org.freedesktop.ModemManager', path); | ||||
|  | ||||
|         this.signal_quality = 0; | ||||
|         this.operator_name = null; | ||||
|         this._proxy.connect('SignalQuality', Lang.bind(this, function(proxy, quality) { | ||||
|             this.signal_quality = quality; | ||||
|             this.emit('notify::signal-quality'); | ||||
|  | ||||
|             // receiving this signal means the device got activated | ||||
|             // and we can finally call GetServingSystem | ||||
|             if (this.operator_name == null) | ||||
|                 this._refreshServingSystem(); | ||||
|         })); | ||||
|         this._proxy.GetSignalQualityRemote(Lang.bind(this, function(result, err) { | ||||
|             if (err) { | ||||
|                 // it will return an error if the device is not connected | ||||
|                 this.signal_quality = 0; | ||||
|             } else { | ||||
|                 let [quality] = result; | ||||
|                 this.signal_quality = quality; | ||||
|             } | ||||
|             this.emit('notify::signal-quality'); | ||||
|         })); | ||||
|     }, | ||||
|  | ||||
|     _refreshServingSystem: function() { | ||||
|         this._proxy.GetServingSystemRemote(Lang.bind(this, function(result, err) { | ||||
|             if (err) { | ||||
|                 // it will return an error if the device is not connected | ||||
|                 this.operator_name = null; | ||||
|             } else { | ||||
|                 let [bandClass, band, id] = result; | ||||
|                 if (name.length > 0) | ||||
|                     this.operator_name = this._findProviderForSid(id); | ||||
|                 else | ||||
|                     this.operator_name = null; | ||||
|             } | ||||
|             this.emit('notify::operator-name'); | ||||
|         })); | ||||
|     }, | ||||
|  | ||||
|     _findProviderForSid: function(sid) { | ||||
|         if (sid == 0) | ||||
|             return null; | ||||
|  | ||||
|         let table = _getProvidersTable(); | ||||
|  | ||||
|         // Search through each country | ||||
|         for (let iter in table) { | ||||
|             let providers = table[iter]; | ||||
|  | ||||
|             // Search through each country's providers | ||||
|             for (let i = 0; i < providers.length; i++) { | ||||
|                 let provider = providers[i]; | ||||
|                 let cdma_sid = provider.get_cdma_sid(); | ||||
|  | ||||
|                 // Search through CDMA SID list | ||||
|                 for (let j = 0; j < cdma_sid.length; j++) { | ||||
|                     if (cdma_sid[j] == sid) | ||||
|                         return provider.name; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
| }; | ||||
| Signals.addSignalMethods(ModemCdma.prototype); | ||||
| @@ -1,53 +0,0 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const DBus = imports.dbus; | ||||
| const Lang = imports.lang; | ||||
|  | ||||
| const ScreenSaverIface = { | ||||
|     name: 'org.gnome.ScreenSaver', | ||||
|     methods: [{ name: 'GetActive', | ||||
|                 inSignature: '', | ||||
|                 outSignature: 'b' }, | ||||
|               { name: 'Lock', | ||||
|                 inSignature: '' }, | ||||
|               { name: 'SetActive', | ||||
|                 inSignature: 'b' }], | ||||
|     signals: [{ name: 'ActiveChanged', | ||||
|                 inSignature: 'b' }] | ||||
| }; | ||||
|  | ||||
| function ScreenSaverProxy() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| ScreenSaverProxy.prototype = { | ||||
|     _init: function() { | ||||
|         DBus.session.proxifyObject(this, | ||||
|                                    'org.gnome.ScreenSaver', | ||||
|                                    '/org/gnome/ScreenSaver'); | ||||
|  | ||||
|         DBus.session.watch_name('org.gnome.ScreenSaver', | ||||
|                                 false, // do not launch a name-owner if none exists | ||||
|                                 Lang.bind(this, this._onSSAppeared), | ||||
|                                 Lang.bind(this, this._onSSVanished)); | ||||
|  | ||||
|         this.screenSaverActive = false; | ||||
|         this.connect('ActiveChanged', | ||||
|                      Lang.bind(this, this._onActiveChanged)); | ||||
|     }, | ||||
|  | ||||
|     _onSSAppeared: function(owner) { | ||||
|         this.GetActiveRemote(Lang.bind(this, function(isActive) { | ||||
|             this.screenSaverActive = isActive; | ||||
|         })) | ||||
|     }, | ||||
|  | ||||
|     _onSSVanished: function(oldOwner) { | ||||
|         this.screenSaverActive = false; | ||||
|     }, | ||||
|  | ||||
|     _onActiveChanged: function(object, isActive) { | ||||
|         this.screenSaverActive = isActive; | ||||
|     } | ||||
| }; | ||||
| DBus.proxifyPrototype(ScreenSaverProxy.prototype, ScreenSaverIface); | ||||
							
								
								
									
										361
									
								
								js/misc/telepathy.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,361 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const DBus = imports.dbus; | ||||
|  | ||||
| // D-Bus utils | ||||
| function nameToPath(name) { | ||||
|     return '/' + name.replace(/\./g, '/'); | ||||
| }; | ||||
|  | ||||
| function pathToName(path) { | ||||
|     if (path[0] != '/') | ||||
|         throw new Error('not a D-Bus path: ' + path); | ||||
|     return path.substr(1).replace(/\//g, '.'); | ||||
| }; | ||||
|  | ||||
| // This is tp_escape_as_identifier() from telepathy-glib | ||||
| function escapeAsIdentifier(name) { | ||||
|     if (!name) | ||||
|         return '_'; | ||||
|  | ||||
|     // first char is replaced with _XX if it's non-alpha, | ||||
|     // later chars are replaced with _XX if they're non-alphanumeric | ||||
|     if (name.length == 1) { | ||||
|         return name.replace(/[^a-zA-Z]/, _hexEscape); | ||||
|     } else { | ||||
|         return (name[0].replace(/[^a-zA-Z]/, _hexEscape) + | ||||
|                 name.substring(1).replace(/[^a-zA-Z0-9]/g, _hexEscape)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function _hexEscape(ch) { | ||||
|     return '_' + ch.charCodeAt(0).toString(16); | ||||
| } | ||||
|  | ||||
| // Telepathy D-Bus interface definitions. Note that most of these are | ||||
| // incomplete, and only cover the methods/properties/signals that | ||||
| // we're currently using. | ||||
|  | ||||
| const TELEPATHY = 'org.freedesktop.Telepathy'; | ||||
|  | ||||
| const CLIENT_NAME = TELEPATHY + '.Client'; | ||||
| const ClientIface = { | ||||
|     name: CLIENT_NAME, | ||||
|     properties: [ | ||||
|         { name: 'Interfaces', | ||||
|           signature: 'as', | ||||
|           access: 'read' } | ||||
|     ] | ||||
| }; | ||||
|  | ||||
| const CLIENT_APPROVER_NAME = TELEPATHY + '.Client.Approver'; | ||||
| const ClientApproverIface = { | ||||
|     name: CLIENT_APPROVER_NAME, | ||||
|     methods: [ | ||||
|         { name: 'AddDispatchOperation', | ||||
|           inSignature: 'a(oa{sv})oa{sv}', | ||||
|           outSignature: '' } | ||||
|     ], | ||||
|     properties: [ | ||||
|         { name: 'ApproverChannelFilter', | ||||
|           signature: 'aa{sv}', | ||||
|           access: 'read' } | ||||
|     ] | ||||
| }; | ||||
|  | ||||
| const CLIENT_HANDLER_NAME = TELEPATHY + '.Client.Handler'; | ||||
| const ClientHandlerIface = { | ||||
|     name: CLIENT_HANDLER_NAME, | ||||
|     methods: [ | ||||
|         { name: 'HandleChannels', | ||||
|           inSignature: 'ooa(oa{sv})aota{sv}', | ||||
|           outSignature: '' } | ||||
|     ], | ||||
|     properties: [ | ||||
|         { name: 'HandlerChannelFilter', | ||||
|           signature: 'aa{sv}', | ||||
|           access: 'read' } | ||||
|     ] | ||||
| }; | ||||
|  | ||||
| const CLIENT_OBSERVER_NAME = TELEPATHY + '.Client.Observer'; | ||||
| const ClientObserverIface = { | ||||
|     name: CLIENT_OBSERVER_NAME, | ||||
|     methods: [ | ||||
|         { name: 'ObserveChannels', | ||||
|           inSignature: 'ooa(oa{sv})oaoa{sv}', | ||||
|           outSignature: '' } | ||||
|     ], | ||||
|     properties: [ | ||||
|         { name: 'ObserverChannelFilter', | ||||
|           signature: 'aa{sv}', | ||||
|           access: 'read' } | ||||
|     ] | ||||
| }; | ||||
|  | ||||
| const CHANNEL_DISPATCH_OPERATION_NAME = TELEPATHY + '.ChannelDispatchOperation'; | ||||
| const ChannelDispatchOperationIface = { | ||||
|     name: CHANNEL_DISPATCH_OPERATION_NAME, | ||||
|     methods: [ | ||||
|         { name: 'HandleWith', | ||||
|           inSignature: 's', | ||||
|           outSignature: '' }, | ||||
|         { name: 'Claim', | ||||
|           inSignature: '', | ||||
|           outSignature: '' } | ||||
|     ] | ||||
| }; | ||||
| let ChannelDispatchOperation = DBus.makeProxyClass(ChannelDispatchOperationIface); | ||||
|  | ||||
| const CONNECTION_NAME = TELEPATHY + '.Connection'; | ||||
| const ConnectionIface = { | ||||
|     name: CONNECTION_NAME, | ||||
|     signals: [ | ||||
|         { name: 'StatusChanged', | ||||
|           inSignature: 'uu' } | ||||
|     ] | ||||
| }; | ||||
| let Connection = DBus.makeProxyClass(ConnectionIface); | ||||
|  | ||||
| const ConnectionStatus = { | ||||
|     CONNECTED:    0, | ||||
|     CONNECTING:   1, | ||||
|     DISCONNECTED: 2 | ||||
| }; | ||||
|  | ||||
| const CONNECTION_ALIASING_NAME = CONNECTION_NAME + '.Interface.Aliasing'; | ||||
| const ConnectionAliasingIface = { | ||||
|     name: CONNECTION_ALIASING_NAME, | ||||
|     methods: [ | ||||
|         { name: 'RequestAliases', | ||||
|           inSignature: 'au', | ||||
|           outSignature: 'as' | ||||
|         } | ||||
|     ], | ||||
|     signals: [ | ||||
|         { name: 'AliasesChanged', | ||||
|           inSignature: 'a(us)' } | ||||
|     ] | ||||
| }; | ||||
| let ConnectionAliasing = DBus.makeProxyClass(ConnectionAliasingIface); | ||||
|  | ||||
| const CONNECTION_AVATARS_NAME = CONNECTION_NAME + '.Interface.Avatars'; | ||||
| const ConnectionAvatarsIface = { | ||||
|     name: CONNECTION_AVATARS_NAME, | ||||
|     methods: [ | ||||
|         { name: 'GetKnownAvatarTokens', | ||||
|           inSignature: 'au', | ||||
|           outSignature: 'a{us}' | ||||
|         }, | ||||
|         { name: 'RequestAvatars', | ||||
|           inSignature: 'au', | ||||
|           outSignature: '' | ||||
|         } | ||||
|     ], | ||||
|     signals: [ | ||||
|         { name: 'AvatarRetrieved', | ||||
|           inSignature: 'usays' | ||||
|         }, | ||||
|         { name: 'AvatarUpdated', | ||||
|           inSignature: 'us' | ||||
|         } | ||||
|     ] | ||||
| }; | ||||
| let ConnectionAvatars = DBus.makeProxyClass(ConnectionAvatarsIface); | ||||
|  | ||||
| const CONNECTION_CONTACTS_NAME = CONNECTION_NAME + '.Interface.Contacts'; | ||||
| const ConnectionContactsIface = { | ||||
|     name: CONNECTION_CONTACTS_NAME, | ||||
|     methods: [ | ||||
|         { name: 'GetContactAttributes', | ||||
|           inSignature: 'auasb', | ||||
|           outSignature: 'a{ua{sv}}' | ||||
|         } | ||||
|     ] | ||||
| }; | ||||
| let ConnectionContacts = DBus.makeProxyClass(ConnectionContactsIface); | ||||
|  | ||||
| const CONNECTION_REQUESTS_NAME = CONNECTION_NAME + '.Interface.Requests'; | ||||
| const ConnectionRequestsIface = { | ||||
|     name: CONNECTION_REQUESTS_NAME, | ||||
|     methods: [ | ||||
|         { name: 'CreateChannel', | ||||
|           inSignature: 'a{sv}', | ||||
|           outSignature: 'oa{sv}' | ||||
|         }, | ||||
|         { name: 'EnsureChannel', | ||||
|           inSignature: 'a{sv}', | ||||
|           outSignature: 'boa{sv}' | ||||
|         } | ||||
|     ], | ||||
|     properties: [ | ||||
|         { name: 'Channels', | ||||
|           signature: 'a(oa{sv})', | ||||
|           access: 'read' } | ||||
|     ], | ||||
|     signals: [ | ||||
|         { name: 'NewChannels', | ||||
|           inSignature: 'a(oa{sv})' | ||||
|         }, | ||||
|         { name: 'ChannelClosed', | ||||
|           inSignature: 'o' | ||||
|         } | ||||
|     ] | ||||
| }; | ||||
| let ConnectionRequests = DBus.makeProxyClass(ConnectionRequestsIface); | ||||
|  | ||||
| const CONNECTION_SIMPLE_PRESENCE_NAME = CONNECTION_NAME + '.Interface.SimplePresence'; | ||||
| const ConnectionSimplePresenceIface = { | ||||
|     name: CONNECTION_SIMPLE_PRESENCE_NAME, | ||||
|     methods: [ | ||||
|         { name: 'SetPresence', | ||||
|           inSignature: 'ss' | ||||
|         }, | ||||
|         { name: 'GetPresences', | ||||
|           inSignature: 'au', | ||||
|           outSignature: 'a{u(uss)}' | ||||
|         } | ||||
|     ], | ||||
|     signals: [ | ||||
|         { name: 'PresencesChanged', | ||||
|           inSignature: 'a{u(uss)}' } | ||||
|     ] | ||||
| }; | ||||
| let ConnectionSimplePresence = DBus.makeProxyClass(ConnectionSimplePresenceIface); | ||||
|  | ||||
| const ConnectionPresenceType = { | ||||
|     UNSET:         0, | ||||
|     OFFLINE:       1, | ||||
|     AVAILABLE:     2, | ||||
|     AWAY:          3, | ||||
|     EXTENDED_AWAY: 4, | ||||
|     HIDDEN:        5, | ||||
|     BUSY:          6, | ||||
|     UNKNOWN:       7, | ||||
|     ERROR:         8 | ||||
| }; | ||||
|  | ||||
| const HandleType = { | ||||
|     NONE:    0, | ||||
|     CONTACT: 1, | ||||
|     ROOM:    2, | ||||
|     LIST:    3, | ||||
|     GROUP:   4 | ||||
| }; | ||||
|  | ||||
| const CHANNEL_NAME = TELEPATHY + '.Channel'; | ||||
| const ChannelIface = { | ||||
|     name: CHANNEL_NAME, | ||||
|     signals: [ | ||||
|         { name: 'Closed', | ||||
|           inSignature: '' } | ||||
|     ] | ||||
| }; | ||||
| let Channel = DBus.makeProxyClass(ChannelIface); | ||||
|  | ||||
| const CHANNEL_TEXT_NAME = CHANNEL_NAME + '.Type.Text'; | ||||
| const ChannelTextIface = { | ||||
|     name: CHANNEL_TEXT_NAME, | ||||
|     methods: [ | ||||
|         { name: 'ListPendingMessages', | ||||
|           inSignature: 'b', | ||||
|           outSignature: 'a(uuuuus)' | ||||
|         }, | ||||
|         { name: 'AcknowledgePendingMessages', | ||||
|           inSignature: 'au', | ||||
|           outSignature: '' | ||||
|         }, | ||||
|         { name: 'Send', | ||||
|           inSignature: 'us', | ||||
|           outSignature: '' | ||||
|         } | ||||
|     ], | ||||
|     signals: [ | ||||
|         { name: 'Received', | ||||
|           inSignature: 'uuuuus' }, | ||||
|         { name: 'Sent', | ||||
|           inSignature: 'uus' } | ||||
|     ] | ||||
| }; | ||||
| let ChannelText = DBus.makeProxyClass(ChannelTextIface); | ||||
|  | ||||
| const ChannelTextMessageType = { | ||||
|     NORMAL: 0, | ||||
|     ACTION: 1, | ||||
|     NOTICE: 2, | ||||
|     AUTO_REPLY: 3, | ||||
|     DELIVERY_REPORT: 4 | ||||
| }; | ||||
|  | ||||
| const CHANNEL_CONTACT_LIST_NAME = CHANNEL_NAME + '.Type.ContactList'; | ||||
| // There is no interface associated with ContactList; it's just a | ||||
| // special kind of Channel.Interface.Group | ||||
|  | ||||
| const CHANNEL_GROUP_NAME = CHANNEL_NAME + '.Interface.Group'; | ||||
| const ChannelGroupIface = { | ||||
|     name: CHANNEL_GROUP_NAME, | ||||
|     properties: [ | ||||
|         { name: 'Members', | ||||
|           signature: 'au', | ||||
|           access: 'read' } | ||||
|     ], | ||||
|     signals: [ | ||||
|         { name: 'MembersChanged', | ||||
|           inSignature: 'sauauauauuu' } | ||||
|     ] | ||||
| }; | ||||
| let ChannelGroup = DBus.makeProxyClass(ChannelGroupIface); | ||||
|  | ||||
| const ACCOUNT_MANAGER_NAME = TELEPATHY + '.AccountManager'; | ||||
| const AccountManagerIface = { | ||||
|     name: ACCOUNT_MANAGER_NAME, | ||||
|     properties: [ | ||||
|         { name: 'ValidAccounts', | ||||
|           signature: 'ao', | ||||
|           access: 'read' } | ||||
|     ], | ||||
|     signals: [ | ||||
|         { name: 'AccountValidityChanged', | ||||
|           inSignature: 'ob' } | ||||
|     ] | ||||
| }; | ||||
| let AccountManager = DBus.makeProxyClass(AccountManagerIface); | ||||
|  | ||||
| const ACCOUNT_NAME = TELEPATHY + '.Account'; | ||||
| const AccountIface = { | ||||
|     name: ACCOUNT_NAME, | ||||
|     properties: [ | ||||
|         { name: 'Connection', | ||||
|           signature: 'o', | ||||
|           access: 'read' } | ||||
|     ] | ||||
| }; | ||||
| let Account = DBus.makeProxyClass(AccountIface); | ||||
|  | ||||
| const CHANNEL_DISPATCHER_NAME = TELEPATHY + '.ChannelDispatcher'; | ||||
| const ChannelDispatcherIface = { | ||||
|     name: CHANNEL_DISPATCHER_NAME, | ||||
|     methods: [ | ||||
|         { name: 'EnsureChannel', | ||||
|           inSignature: 'oa{sv}xs', | ||||
|           outSignature: 'o' } | ||||
|     ] | ||||
| }; | ||||
| let ChannelDispatcher = DBus.makeProxyClass(ChannelDispatcherIface); | ||||
|  | ||||
| const CHANNEL_REQUEST_NAME = TELEPATHY + '.ChannelRequest'; | ||||
| const ChannelRequestIface = { | ||||
|     name: CHANNEL_REQUEST_NAME, | ||||
|     methods: [ | ||||
|         { name: 'Proceed', | ||||
|           inSignature: '', | ||||
|           outSignature: '' } | ||||
|     ], | ||||
|     signals: [ | ||||
|         { name: 'Failed', | ||||
|           signature: 'ss' }, | ||||
|         { name: 'Succeeded', | ||||
|           signature: '' } | ||||
|     ] | ||||
| }; | ||||
| let ChannelRequest = DBus.makeProxyClass(ChannelRequestIface); | ||||
							
								
								
									
										234
									
								
								js/misc/util.js
									
									
									
									
									
								
							
							
						
						| @@ -1,234 +0,0 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Gdk = imports.gi.Gdk; | ||||
| const Gio = imports.gi.Gio; | ||||
| const GLib = imports.gi.GLib; | ||||
| const Shell = imports.gi.Shell; | ||||
|  | ||||
| const Main = imports.ui.main; | ||||
|  | ||||
| // http://daringfireball.net/2010/07/improved_regex_for_matching_urls | ||||
| const _balancedParens = '\\((?:[^\\s()<>]+|(?:\\(?:[^\\s()<>]+\\)))*\\)'; | ||||
| const _leadingJunk = '[\\s`(\\[{\'\\"<\u00AB\u201C\u2018]'; | ||||
| const _notTrailingJunk = '[^\\s`!()\\[\\]{};:\'\\".,<>?\u00AB\u00BB\u201C\u201D\u2018\u2019]'; | ||||
|  | ||||
| const _urlRegexp = new RegExp( | ||||
|     '(^|' + _leadingJunk + ')' + | ||||
|     '(' + | ||||
|         '(?:' + | ||||
|             '[a-z][\\w-]+://' +                   // scheme:// | ||||
|             '|' + | ||||
|             'www\\d{0,3}[.]' +                    // www. | ||||
|             '|' + | ||||
|             '[a-z0-9.\\-]+[.][a-z]{2,4}/' +       // foo.xx/ | ||||
|         ')' + | ||||
|         '(?:' +                                   // one or more: | ||||
|             '[^\\s()<>]+' +                       // run of non-space non-() | ||||
|             '|' +                                 // or | ||||
|             _balancedParens +                     // balanced parens | ||||
|         ')+' + | ||||
|         '(?:' +                                   // end with: | ||||
|             _balancedParens +                     // balanced parens | ||||
|             '|' +                                 // or | ||||
|             _notTrailingJunk +                    // last non-junk char | ||||
|         ')' + | ||||
|     ')', 'gi'); | ||||
|  | ||||
| // findUrls: | ||||
| // @str: string to find URLs in | ||||
| // | ||||
| // Searches @str for URLs and returns an array of objects with %url | ||||
| // properties showing the matched URL string, and %pos properties indicating | ||||
| // the position within @str where the URL was found. | ||||
| // | ||||
| // Return value: the list of match objects, as described above | ||||
| function findUrls(str) { | ||||
|     let res = [], match; | ||||
|     while ((match = _urlRegexp.exec(str))) | ||||
|         res.push({ url: match[2], pos: match.index + match[1].length }); | ||||
|     return res; | ||||
| } | ||||
|  | ||||
| // spawn: | ||||
| // @argv: an argv array | ||||
| // | ||||
| // Runs @argv in the background, handling any errors that occur | ||||
| // when trying to start the program. | ||||
| function spawn(argv) { | ||||
|     try { | ||||
|         trySpawn(argv); | ||||
|     } catch (err) { | ||||
|         _handleSpawnError(argv[0], err); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // spawnCommandLine: | ||||
| // @command_line: a command line | ||||
| // | ||||
| // Runs @command_line in the background, handling any errors that | ||||
| // occur when trying to parse or start the program. | ||||
| function spawnCommandLine(command_line) { | ||||
|     try { | ||||
|         let [success, argv] = GLib.shell_parse_argv(command_line); | ||||
|         trySpawn(argv); | ||||
|     } catch (err) { | ||||
|         _handleSpawnError(command_line, err); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // trySpawn: | ||||
| // @argv: an argv array | ||||
| // | ||||
| // Runs @argv in the background. If launching @argv fails, | ||||
| // this will throw an error. | ||||
| function trySpawn(argv) | ||||
| { | ||||
|     try { | ||||
|         GLib.spawn_async(null, argv, null, | ||||
|                          GLib.SpawnFlags.SEARCH_PATH, | ||||
|                          null, null); | ||||
|     } catch (err) { | ||||
|         if (err.code == GLib.SpawnError.G_SPAWN_ERROR_NOENT) { | ||||
|             err.message = _("Command not found"); | ||||
|         } else { | ||||
|             // The exception from gjs contains an error string like: | ||||
|             //   Error invoking GLib.spawn_command_line_async: Failed to | ||||
|             //   execute child process "foo" (No such file or directory) | ||||
|             // We are only interested in the part in the parentheses. (And | ||||
|             // we can't pattern match the text, since it gets localized.) | ||||
|             err.message = err.message.replace(/.*\((.+)\)/, '$1'); | ||||
|         } | ||||
|  | ||||
|         throw err; | ||||
|     } | ||||
| } | ||||
|  | ||||
| // trySpawnCommandLine: | ||||
| // @command_line: a command line | ||||
| // | ||||
| // Runs @command_line in the background. If launching @command_line | ||||
| // fails, this will throw an error. | ||||
| function trySpawnCommandLine(command_line) { | ||||
|     let success, argv; | ||||
|  | ||||
|     try { | ||||
|         [success, argv] = GLib.shell_parse_argv(command_line); | ||||
|     } catch (err) { | ||||
|         // Replace "Error invoking GLib.shell_parse_argv: " with | ||||
|         // something nicer | ||||
|         err.message = err.message.replace(/[^:]*: /, _("Could not parse command:") + "\n"); | ||||
|         throw err; | ||||
|     } | ||||
|  | ||||
|     trySpawn(argv); | ||||
| } | ||||
|  | ||||
| function _handleSpawnError(command, err) { | ||||
|     let title = _("Execution of '%s' failed:").format(command); | ||||
|     Main.notifyError(title, err.message); | ||||
| } | ||||
|  | ||||
| // killall: | ||||
| // @processName: a process name | ||||
| // | ||||
| // Kills @processName. If no process with the given name is found, | ||||
| // this will fail silently. | ||||
| function killall(processName) { | ||||
|     try { | ||||
|         // pkill is more portable than killall, but on Linux at least | ||||
|         // it won't match if you pass more than 15 characters of the | ||||
|         // process name... However, if you use the '-f' flag to match | ||||
|         // the entire command line, it will work, but we have to be | ||||
|         // careful in that case that we can match | ||||
|         // '/usr/bin/processName' but not 'gedit processName.c' or | ||||
|         // whatever... | ||||
|  | ||||
|         let argv = ['pkill', '-f', '^([^ ]*/)?' + processName + '($| )']; | ||||
|         GLib.spawn_sync(null, argv, null, GLib.SpawnFlags.SEARCH_PATH, null, null); | ||||
|         // It might be useful to return success/failure, but we'd need | ||||
|         // a wrapper around WIFEXITED and WEXITSTATUS. Since none of | ||||
|         // the current callers care, we don't bother. | ||||
|     } catch (e) { | ||||
|         logError(e, 'Failed to kill ' + processName); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // This was ported from network-manager-applet | ||||
| // Copyright 2007 - 2011 Red Hat, Inc. | ||||
| // Author: Dan Williams <dcbw@redhat.com> | ||||
|  | ||||
| const _IGNORED_WORDS = [ | ||||
|         'Semiconductor', | ||||
|         'Components', | ||||
|         'Corporation', | ||||
|         'Communications', | ||||
|         'Company', | ||||
|         'Corp.', | ||||
|         'Corp', | ||||
|         'Co.', | ||||
|         'Inc.', | ||||
|         'Inc', | ||||
|         'Incorporated', | ||||
|         'Ltd.', | ||||
|         'Limited.', | ||||
|         'Intel', | ||||
|         'chipset', | ||||
|         'adapter', | ||||
|         '[hex]', | ||||
|         'NDIS', | ||||
|         'Module' | ||||
| ]; | ||||
|  | ||||
| const _IGNORED_PHRASES = [ | ||||
|         'Multiprotocol MAC/baseband processor', | ||||
|         'Wireless LAN Controller', | ||||
|         'Wireless LAN Adapter', | ||||
|         'Wireless Adapter', | ||||
|         'Network Connection', | ||||
|         'Wireless Cardbus Adapter', | ||||
|         'Wireless CardBus Adapter', | ||||
|         '54 Mbps Wireless PC Card', | ||||
|         'Wireless PC Card', | ||||
|         'Wireless PC', | ||||
|         'PC Card with XJACK(r) Antenna', | ||||
|         'Wireless cardbus', | ||||
|         'Wireless LAN PC Card', | ||||
|         'Technology Group Ltd.', | ||||
|         'Communication S.p.A.', | ||||
|         'Business Mobile Networks BV', | ||||
|         'Mobile Broadband Minicard Composite Device', | ||||
|         'Mobile Communications AB', | ||||
|         '(PC-Suite Mode)' | ||||
| ]; | ||||
|  | ||||
| function fixupPCIDescription(desc) { | ||||
|     desc = desc.replace(/[_,]/, ' '); | ||||
|  | ||||
|     /* Attempt to shorten ID by ignoring certain phrases */ | ||||
|     for (let i = 0; i < _IGNORED_PHRASES.length; i++) { | ||||
|         let item = _IGNORED_PHRASES[i]; | ||||
|         let pos = desc.indexOf(item); | ||||
|         if (pos != -1) { | ||||
|             let before = desc.substring(0, pos); | ||||
|             let after = desc.substring(pos + item.length, desc.length); | ||||
|             desc = before + after; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* Attmept to shorten ID by ignoring certain individual words */ | ||||
|     let words = desc.split(' '); | ||||
|     let out = [ ]; | ||||
|     for (let i = 0; i < words.length; i++) { | ||||
|         let item = words[i]; | ||||
|  | ||||
|         // skip empty items (that come out from consecutive spaces) | ||||
|         if (item.length == 0) | ||||
|             continue; | ||||
|  | ||||
|         if (_IGNORED_WORDS.indexOf(item) == -1) { | ||||
|             out.push(item); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return out.join(' '); | ||||
| } | ||||
| @@ -21,77 +21,26 @@ let METRICS = { | ||||
|     overviewFpsSubsequent: | ||||
|     { description: "Frames rate when going to the overview, second time", | ||||
|       units: "frames / s" }, | ||||
|     overviewFps5Windows: | ||||
|     { description: "Frames rate when going to the overview, 5 windows open", | ||||
|       units: "frames / s" }, | ||||
|     overviewFps10Windows: | ||||
|     { description: "Frames rate when going to the overview, 10 windows open", | ||||
|       units: "frames / s" }, | ||||
|     overviewFps5Maximized: | ||||
|     { description: "Frames rate when going to the overview, 5 maximized windows open", | ||||
|       units: "frames / s" }, | ||||
|     overviewFps10Maximized: | ||||
|     { description: "Frames rate when going to the overview, 10 maximized windows open", | ||||
|       units: "frames / s" }, | ||||
|     overviewFps5Alpha: | ||||
|     { description: "Frames rate when going to the overview, 5 alpha-transparent windows open", | ||||
|       units: "frames / s" }, | ||||
|     overviewFps10Alpha: | ||||
|     { description: "Frames rate when going to the overview, 10 alpha-transparent windows open", | ||||
|       units: "frames / s" }, | ||||
|     usedAfterOverview: | ||||
|     { description: "Malloc'ed bytes after the overview is shown once", | ||||
|       units: "B" }, | ||||
|     leakedAfterOverview: | ||||
|     { description: "Additional malloc'ed bytes the second time the overview is shown", | ||||
|       units: "B" }, | ||||
|     applicationsShowTimeFirst: | ||||
|     { description: "Time to switch to applications view, first time", | ||||
|       units: "us" }, | ||||
|     applicationsShowTimeSubsequent: | ||||
|     { description: "Time to switch to applications view, second time", | ||||
|       units: "us"} | ||||
|       units: "B" } | ||||
| }; | ||||
|  | ||||
| let WINDOW_CONFIGS = [ | ||||
|     { width: 640, height: 480, alpha: false, maximized: false, count: 1,  metric: 'overviewFpsSubsequent' }, | ||||
|     { width: 640, height: 480, alpha: false, maximized: false, count: 5,  metric: 'overviewFps5Windows'  }, | ||||
|     { width: 640, height: 480, alpha: false, maximized: false, count: 10, metric: 'overviewFps10Windows'  }, | ||||
|     { width: 640, height: 480, alpha: false, maximized: true,  count: 5,  metric: 'overviewFps5Maximized' }, | ||||
|     { width: 640, height: 480, alpha: false, maximized: true,  count: 10, metric: 'overviewFps10Maximized' }, | ||||
|     { width: 640, height: 480, alpha: true,  maximized: false, count: 5,  metric: 'overviewFps5Alpha' }, | ||||
|     { width: 640, height: 480, alpha: true,  maximized: false, count: 10, metric: 'overviewFps10Alpha' } | ||||
| ]; | ||||
|  | ||||
| function run() { | ||||
|     Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview"); | ||||
|     Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing"); | ||||
|     Scripting.defineScriptEvent("afterShowHide", "After a show/hide cycle for the overview"); | ||||
|     Scripting.defineScriptEvent("applicationsShowStart", "Starting to switch to applications view"); | ||||
|     Scripting.defineScriptEvent("applicationsShowDone", "Done switching to applications view"); | ||||
|  | ||||
|     Main.overview.connect('shown', function() { | ||||
|                               Scripting.scriptEvent('overviewShowDone'); | ||||
|                           }); | ||||
|  | ||||
|     yield Scripting.sleep(1000); | ||||
|  | ||||
|     for (let i = 0; i < 2 * WINDOW_CONFIGS.length; i++) { | ||||
|         // We go to the overview twice for each configuration; the first time | ||||
|         // to calculate the mipmaps for the windows, the second time to get | ||||
|         // a clean set of numbers. | ||||
|         if ((i % 2) == 0) { | ||||
|             let config = WINDOW_CONFIGS[i / 2]; | ||||
|             yield Scripting.destroyTestWindows(); | ||||
|  | ||||
|             for (let k = 0; k < config.count; k++) | ||||
|                 yield Scripting.createTestWindow(config.width, config.height, config.alpha, config.maximized); | ||||
|  | ||||
|             yield Scripting.waitTestWindows(); | ||||
|             yield Scripting.sleep(1000); | ||||
|             yield Scripting.waitLeisure(); | ||||
|         } | ||||
|  | ||||
|     yield Scripting.waitLeisure(); | ||||
|     for (let i = 0; i < 2; i++) { | ||||
|         Scripting.scriptEvent('overviewShowStart'); | ||||
|         Main.overview.show(); | ||||
|  | ||||
| @@ -104,21 +53,6 @@ function run() { | ||||
|         Scripting.collectStatistics(); | ||||
|         Scripting.scriptEvent('afterShowHide'); | ||||
|     } | ||||
|  | ||||
|     yield Scripting.destroyTestWindows(); | ||||
|     yield Scripting.sleep(1000); | ||||
|  | ||||
|     Main.overview.show(); | ||||
|     yield Scripting.waitLeisure(); | ||||
|  | ||||
|     for (let i = 0; i < 2; i++) { | ||||
|         Scripting.scriptEvent('applicationsShowStart'); | ||||
|         Main.overview._viewSelector.switchTab('applications'); | ||||
|         yield Scripting.waitLeisure(); | ||||
|         Scripting.scriptEvent('applicationsShowDone'); | ||||
|         Main.overview._viewSelector.switchTab('windows'); | ||||
|         yield Scripting.waitLeisure(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| let showingOverview = false; | ||||
| @@ -130,8 +64,6 @@ let mallocUsedSize = 0; | ||||
| let overviewShowCount = 0; | ||||
| let firstOverviewUsedSize; | ||||
| let haveSwapComplete = false; | ||||
| let applicationsShowStart; | ||||
| let applicationsShowCount = 0; | ||||
|  | ||||
| function script_overviewShowStart(time) { | ||||
|     showingOverview = true; | ||||
| @@ -147,18 +79,6 @@ function script_overviewShowDone(time) { | ||||
|     finishedShowingOverview = true; | ||||
| } | ||||
|  | ||||
| function script_applicationsShowStart(time) { | ||||
|     applicationsShowStart = time; | ||||
| } | ||||
|  | ||||
| function script_applicationsShowDone(time) { | ||||
|     applicationsShowCount++; | ||||
|     if (applicationsShowCount == 1) | ||||
|         METRICS.applicationsShowTimeFirst.value = time - applicationsShowStart; | ||||
|     else | ||||
|         METRICS.applicationsShowTimeSubsequent.value = time - applicationsShowStart; | ||||
| } | ||||
|  | ||||
| function script_afterShowHide(time) { | ||||
|     if (overviewShowCount == 1) { | ||||
|         METRICS.usedAfterOverview.value = mallocUsedSize; | ||||
| @@ -193,15 +113,9 @@ function _frameDone(time) { | ||||
|         if (overviewShowCount == 1) { | ||||
|             METRICS.overviewLatencyFirst.value = overviewLatency; | ||||
|             METRICS.overviewFpsFirst.value = fps; | ||||
|         } else if (overviewShowCount == 2) { | ||||
|         } else { | ||||
|             METRICS.overviewLatencySubsequent.value = overviewLatency; | ||||
|         } | ||||
|  | ||||
|         // Other than overviewFpsFirst, we collect FPS metrics the second | ||||
|         // we show each window configuration. overviewShowCount is 1,2,3... | ||||
|         if (overviewShowCount % 2 == 0) { | ||||
|             let config = WINDOW_CONFIGS[(overviewShowCount / 2) - 1]; | ||||
|             METRICS[config.metric].value = fps; | ||||
|             METRICS.overviewFpsSubsequent.value = fps; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										97
									
								
								js/prefs/clockPreferences.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,97 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Gio = imports.gi.Gio; | ||||
| const GLib = imports.gi.GLib; | ||||
| const Gtk = imports.gi.Gtk; | ||||
|  | ||||
| const Lang = imports.lang; | ||||
| const Signals = imports.signals; | ||||
|  | ||||
| const Gettext = imports.gettext; | ||||
|  | ||||
| const FORMAT_KEY       = 'format'; | ||||
| const SHOW_DATE_KEY    = 'show-date'; | ||||
| const SHOW_SECONDS_KEY = 'show-seconds'; | ||||
|  | ||||
|  | ||||
| function ClockPreferences(uiFile) { | ||||
|     this._init(uiFile); | ||||
| }; | ||||
|  | ||||
| ClockPreferences.prototype = { | ||||
|     _init: function(uiFile) { | ||||
|         let builder = new Gtk.Builder(); | ||||
|         builder.add_from_file(uiFile); | ||||
|  | ||||
|         this._dialog = builder.get_object('prefs-dialog'); | ||||
|         this._dialog.connect('response', Lang.bind(this, this._onResponse)); | ||||
|  | ||||
|         this._12hrRadio = builder.get_object('12hr_radio'); | ||||
|         this._24hrRadio = builder.get_object('24hr_radio'); | ||||
|         this._dateCheck = builder.get_object('date_check'); | ||||
|         this._secondsCheck = builder.get_object('seconds_check'); | ||||
|  | ||||
|         delete builder; | ||||
|  | ||||
|         this._settings = new Gio.Settings({ schema: 'org.gnome.shell.clock' }); | ||||
|         this._notifyId = this._settings.connect('changed', | ||||
|                                                 Lang.bind(this, | ||||
|                                                           this._updateDialog)); | ||||
|  | ||||
|         this._12hrRadio.connect('toggled', Lang.bind(this, | ||||
|             function() { | ||||
|                 let format = this._12hrRadio.active ? '12-hour' : '24-hour'; | ||||
|                 this._settings.set_string(FORMAT_KEY, format); | ||||
|             })); | ||||
|         this._dateCheck.connect('toggled', Lang.bind(this, | ||||
|             function() { | ||||
|                 this._settings.set_boolean(SHOW_DATE_KEY, | ||||
|                                            this._dateCheck.active); | ||||
|             })); | ||||
|         this._secondsCheck.connect('toggled', Lang.bind(this, | ||||
|             function() { | ||||
|                 this._settings.set_boolean(SHOW_SECONDS_KEY, | ||||
|                                            this._secondsCheck.active); | ||||
|             })); | ||||
|  | ||||
|         this._updateDialog(); | ||||
|     }, | ||||
|  | ||||
|     show: function() { | ||||
|         this._dialog.show_all(); | ||||
|     }, | ||||
|  | ||||
|     _updateDialog: function() { | ||||
|         let format = this._settings.get_string(FORMAT_KEY); | ||||
|         this._12hrRadio.active = (format == "12-hour"); | ||||
|         this._24hrRadio.active = (format == "24-hour"); | ||||
|  | ||||
|         this._dateCheck.active = this._settings.get_boolean(SHOW_DATE_KEY); | ||||
|         this._secondsCheck.active = this._settings.get_boolean(SHOW_SECONDS_KEY); | ||||
|     }, | ||||
|  | ||||
|     _onResponse: function() { | ||||
|         this._dialog.destroy(); | ||||
|         this._settings.disconnect(this._notifyId); | ||||
|         this.emit('destroy'); | ||||
|     } | ||||
| }; | ||||
| Signals.addSignalMethods(ClockPreferences.prototype); | ||||
|  | ||||
| function main(params) { | ||||
|     if ('progName' in params) | ||||
|         GLib.set_prgname(params['progName']); | ||||
|     if ('localeDir' in params) | ||||
|         Gettext.bindtextdomain('gnome-shell', params['localeDir']); | ||||
|  | ||||
|     Gtk.init(null, null); | ||||
|  | ||||
|     let clockPrefs = new ClockPreferences(params['uiFile']); | ||||
|     clockPrefs.connect('destroy', | ||||
|                        function() { | ||||
|                            Gtk.main_quit(); | ||||
|                        }); | ||||
|     clockPrefs.show(); | ||||
|  | ||||
|     Gtk.main(); | ||||
| } | ||||
							
								
								
									
										332
									
								
								js/ui/altTab.js
									
									
									
									
									
								
							
							
						
						| @@ -4,7 +4,6 @@ const Clutter = imports.gi.Clutter; | ||||
| const Gdk = imports.gi.Gdk; | ||||
| const Lang = imports.lang; | ||||
| const Mainloop = imports.mainloop; | ||||
| const Meta = imports.gi.Meta; | ||||
| const Shell = imports.gi.Shell; | ||||
| const Signals = imports.signals; | ||||
| const St = imports.gi.St; | ||||
| @@ -14,10 +13,7 @@ const Tweener = imports.ui.tweener; | ||||
|  | ||||
| const POPUP_APPICON_SIZE = 96; | ||||
| const POPUP_SCROLL_TIME = 0.10; // seconds | ||||
| const POPUP_DELAY_TIMEOUT = 150; // milliseconds | ||||
| const POPUP_FADE_OUT_TIME = 0.1; // seconds | ||||
|  | ||||
| const APP_ICON_HOVER_TIMEOUT = 200; // milliseconds | ||||
| const POPUP_FADE_TIME = 0.1; // seconds | ||||
|  | ||||
| const DISABLE_HOVER_TIMEOUT = 500; // milliseconds | ||||
|  | ||||
| @@ -38,8 +34,7 @@ function AltTabPopup() { | ||||
| AltTabPopup.prototype = { | ||||
|     _init : function() { | ||||
|         this.actor = new Shell.GenericContainer({ name: 'altTabPopup', | ||||
|                                                   reactive: true, | ||||
|                                                   visible: false }); | ||||
|                                                     reactive: true }); | ||||
|  | ||||
|         this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth)); | ||||
|         this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight)); | ||||
| @@ -53,9 +48,6 @@ AltTabPopup.prototype = { | ||||
|         this._currentWindow = -1; | ||||
|         this._thumbnailTimeoutId = 0; | ||||
|         this._motionTimeoutId = 0; | ||||
|         this._initialDelayTimeoutId = 0; | ||||
|  | ||||
|         this.thumbnailsVisible = false; | ||||
|  | ||||
|         // Initially disable hover so we ignore the enter-event if | ||||
|         // the switcher appears underneath the current pointer location | ||||
| @@ -76,7 +68,7 @@ AltTabPopup.prototype = { | ||||
|  | ||||
|     _allocate: function (actor, box, flags) { | ||||
|         let childBox = new Clutter.ActorBox(); | ||||
|         let primary = Main.layoutManager.primaryMonitor; | ||||
|         let primary = global.get_primary_monitor(); | ||||
|  | ||||
|         let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT); | ||||
|         let rightPadding = this.actor.get_theme_node().get_padding(St.Side.RIGHT); | ||||
| @@ -89,7 +81,7 @@ AltTabPopup.prototype = { | ||||
|         let [childMinHeight, childNaturalHeight] = this._appSwitcher.actor.get_preferred_height(primary.width - hPadding); | ||||
|         let [childMinWidth, childNaturalWidth] = this._appSwitcher.actor.get_preferred_width(childNaturalHeight); | ||||
|         childBox.x1 = Math.max(primary.x + leftPadding, primary.x + Math.floor((primary.width - childNaturalWidth) / 2)); | ||||
|         childBox.x2 = Math.min(primary.x + primary.width - rightPadding, childBox.x1 + childNaturalWidth); | ||||
|         childBox.x2 = Math.min(childBox.x1 + primary.width - hPadding, childBox.x1 + childNaturalWidth); | ||||
|         childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2); | ||||
|         childBox.y2 = childBox.y1 + childNaturalHeight; | ||||
|         this._appSwitcher.actor.allocate(childBox, flags); | ||||
| @@ -99,6 +91,8 @@ AltTabPopup.prototype = { | ||||
|         // those calculations | ||||
|         if (this._thumbnails) { | ||||
|             let icon = this._appIcons[this._currentApp].actor; | ||||
|             // Force a stage relayout to make sure we get the correct position | ||||
|             global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, 0, 0); | ||||
|             let [posX, posY] = icon.get_transformed_position(); | ||||
|             let thumbnailCenter = posX + icon.width / 2; | ||||
|             let [childMinWidth, childNaturalWidth] = this._thumbnails.actor.get_preferred_width(-1); | ||||
| @@ -121,9 +115,9 @@ AltTabPopup.prototype = { | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     show : function(backward, binding) { | ||||
|         let appSys = Shell.AppSystem.get_default(); | ||||
|         let apps = appSys.get_running (); | ||||
|     show : function(backward) { | ||||
|         let tracker = Shell.WindowTracker.get_default(); | ||||
|         let apps = tracker.get_running_apps (''); | ||||
|  | ||||
|         if (!apps.length) | ||||
|             return false; | ||||
| @@ -132,45 +126,44 @@ AltTabPopup.prototype = { | ||||
|             return false; | ||||
|         this._haveModal = true; | ||||
|  | ||||
|         this.actor.connect('key-press-event', Lang.bind(this, this._keyPressEvent)); | ||||
|         this.actor.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent)); | ||||
|         this._keyPressEventId = global.stage.connect('key-press-event', Lang.bind(this, this._keyPressEvent)); | ||||
|         this._keyReleaseEventId = global.stage.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent)); | ||||
|  | ||||
|         this.actor.connect('button-press-event', Lang.bind(this, this._clickedOutside)); | ||||
|         this.actor.connect('scroll-event', Lang.bind(this, this._onScroll)); | ||||
|  | ||||
|         this._appSwitcher = new AppSwitcher(apps, this); | ||||
|         this._appSwitcher = new AppSwitcher(apps); | ||||
|         this.actor.add_actor(this._appSwitcher.actor); | ||||
|         this._appSwitcher.connect('item-activated', Lang.bind(this, this._appActivated)); | ||||
|         this._appSwitcher.connect('item-entered', Lang.bind(this, this._appEntered)); | ||||
|  | ||||
|         this._appIcons = this._appSwitcher.icons; | ||||
|  | ||||
|         // Need to force an allocation so we can figure out whether we | ||||
|         // need to scroll when selecting | ||||
|         this.actor.opacity = 0; | ||||
|         this.actor.show(); | ||||
|         this.actor.get_allocation_box(); | ||||
|  | ||||
|         // Make the initial selection | ||||
|         if (binding == 'switch_group') { | ||||
|             if (backward) { | ||||
|                 this._select(0, this._appIcons[0].cachedWindows.length - 1); | ||||
|             } else { | ||||
|                 if (this._appIcons[0].cachedWindows.length > 1) | ||||
|                     this._select(0, 1); | ||||
|                 else | ||||
|                     this._select(0, 0); | ||||
|             } | ||||
|         } else if (binding == 'switch_group_backward') { | ||||
|             this._select(0, this._appIcons[0].cachedWindows.length - 1); | ||||
|         } else if (binding == 'switch_windows_backward') { | ||||
|             this._select(this._appIcons.length - 1); | ||||
|         } else if (this._appIcons.length == 1) { | ||||
|             this._select(0); | ||||
|         if (this._appIcons.length == 1) { | ||||
|             if (!backward && this._appIcons[0].cachedWindows.length > 1) { | ||||
|                 // For compatibility with the multi-app case below | ||||
|                 this._select(0, 1, true); | ||||
|             } else | ||||
|                 this._select(0); | ||||
|         } else if (backward) { | ||||
|             this._select(this._appIcons.length - 1); | ||||
|         } else { | ||||
|             this._select(1); | ||||
|             let firstWindows = this._appIcons[0].cachedWindows; | ||||
|             if (firstWindows.length > 1) { | ||||
|                 let curAppNextWindow = firstWindows[1]; | ||||
|                 let nextAppWindow = this._appIcons[1].cachedWindows[0]; | ||||
|  | ||||
|                 // If the next window of the current app is more-recently-used | ||||
|                 // than the first window of the next app, then select it. | ||||
|                 if (curAppNextWindow.get_workspace() == global.screen.get_active_workspace() && | ||||
|                     curAppNextWindow.get_user_time() > nextAppWindow.get_user_time()) | ||||
|                     this._select(0, 1, true); | ||||
|                 else | ||||
|                     this._select(1); | ||||
|             } else { | ||||
|                 this._select(1); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // There's a race condition; if the user released Alt before | ||||
| @@ -184,13 +177,13 @@ AltTabPopup.prototype = { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         // We delay showing the popup so that fast Alt+Tab users aren't | ||||
|         // disturbed by the popup briefly flashing. | ||||
|         this._initialDelayTimeoutId = Mainloop.timeout_add(POPUP_DELAY_TIMEOUT, | ||||
|                                                            Lang.bind(this, function () { | ||||
|                                                                this.actor.opacity = 255; | ||||
|                                                                this._initialDelayTimeoutId = 0; | ||||
|                                                            })); | ||||
|         this.actor.opacity = 0; | ||||
|         this.actor.show(); | ||||
|         Tweener.addTween(this.actor, | ||||
|                          { opacity: 255, | ||||
|                            time: POPUP_FADE_TIME, | ||||
|                            transition: 'easeOutQuad' | ||||
|                          }); | ||||
|  | ||||
|         return true; | ||||
|     }, | ||||
| @@ -219,31 +212,42 @@ AltTabPopup.prototype = { | ||||
|  | ||||
|     _keyPressEvent : function(actor, event) { | ||||
|         let keysym = event.get_key_symbol(); | ||||
|         let event_state = Shell.get_event_state(event); | ||||
|         let backwards = event_state & Clutter.ModifierType.SHIFT_MASK; | ||||
|         let action = global.display.get_keybinding_action(event.get_key_code(), event_state); | ||||
|         let shift = (Shell.get_event_state(event) & Clutter.ModifierType.SHIFT_MASK); | ||||
|         // X allows servers to represent Shift+Tab in two different ways | ||||
|         if (shift && keysym == Clutter.Tab) | ||||
|             keysym = Clutter.ISO_Left_Tab; | ||||
|  | ||||
|         this._disableHover(); | ||||
|  | ||||
|         if (keysym == Clutter.Escape) { | ||||
|             this.destroy(); | ||||
|         } else if (action == Meta.KeyBindingAction.SWITCH_GROUP) { | ||||
|             this._select(this._currentApp, backwards ? this._previousWindow() : this._nextWindow()); | ||||
|         } else if (action == Meta.KeyBindingAction.SWITCH_GROUP_BACKWARD) { | ||||
|         if (keysym == Clutter.grave) | ||||
|             this._select(this._currentApp, this._nextWindow()); | ||||
|         else if (keysym == Clutter.asciitilde) | ||||
|             this._select(this._currentApp, this._previousWindow()); | ||||
|         } else if (action == Meta.KeyBindingAction.SWITCH_WINDOWS) { | ||||
|             this._select(backwards ? this._previousApp() : this._nextApp()); | ||||
|         } else if (action == Meta.KeyBindingAction.SWITCH_WINDOWS_BACKWARD) { | ||||
|             this._select(this._previousApp()); | ||||
|         } else if (this._thumbnailsFocused) { | ||||
|             if (keysym == Clutter.Left) | ||||
|         else if (keysym == Clutter.Escape) | ||||
|             this.destroy(); | ||||
|         else if (this._thumbnailsFocused) { | ||||
|             if (keysym == Clutter.Tab) { | ||||
|                 if (this._currentWindow == this._appIcons[this._currentApp].cachedWindows.length - 1) | ||||
|                     this._select(this._nextApp()); | ||||
|                 else | ||||
|                     this._select(this._currentApp, this._nextWindow()); | ||||
|             } else if (keysym == Clutter.ISO_Left_Tab) { | ||||
|                 if (this._currentWindow == 0 || this._currentWindow == -1) | ||||
|                     this._select(this._previousApp()); | ||||
|                 else | ||||
|                     this._select(this._currentApp, this._previousWindow()); | ||||
|             } else if (keysym == Clutter.Left) | ||||
|                 this._select(this._currentApp, this._previousWindow()); | ||||
|             else if (keysym == Clutter.Right) | ||||
|                 this._select(this._currentApp, this._nextWindow()); | ||||
|             else if (keysym == Clutter.Up) | ||||
|                 this._select(this._currentApp, null, true); | ||||
|         } else { | ||||
|             if (keysym == Clutter.Left) | ||||
|             if (keysym == Clutter.Tab) | ||||
|                 this._select(this._nextApp()); | ||||
|             else if (keysym == Clutter.ISO_Left_Tab) | ||||
|                 this._select(this._previousApp()); | ||||
|             else if (keysym == Clutter.Left) | ||||
|                 this._select(this._previousApp()); | ||||
|             else if (keysym == Clutter.Right) | ||||
|                 this._select(this._nextApp()); | ||||
| @@ -360,41 +364,34 @@ AltTabPopup.prototype = { | ||||
|         this.destroy(); | ||||
|     }, | ||||
|  | ||||
|     _popModal: function() { | ||||
|         if (this._haveModal) { | ||||
|             Main.popModal(this.actor); | ||||
|             this._haveModal = false; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     destroy : function() { | ||||
|         this._popModal(); | ||||
|         if (this.actor.visible) { | ||||
|             Tweener.addTween(this.actor, | ||||
|                              { opacity: 0, | ||||
|                                time: POPUP_FADE_OUT_TIME, | ||||
|                                transition: 'easeOutQuad', | ||||
|                                onComplete: Lang.bind(this, | ||||
|                                    function() { | ||||
|                                        this.actor.destroy(); | ||||
|                                    }) | ||||
|                              }); | ||||
|         } else | ||||
|             this.actor.destroy(); | ||||
|         Tweener.addTween(this.actor, | ||||
|                          { opacity: 0, | ||||
|                            time: POPUP_FADE_TIME, | ||||
|                            transition: 'easeOutQuad', | ||||
|                            onComplete: Lang.bind(this, | ||||
|                                function() { | ||||
|                                    this.actor.destroy(); | ||||
|                                }) | ||||
|                          }); | ||||
|     }, | ||||
|  | ||||
|     _onDestroy : function() { | ||||
|         this._popModal(); | ||||
|         if (this._haveModal) | ||||
|             Main.popModal(this.actor); | ||||
|  | ||||
|         if (this._thumbnails) | ||||
|             this._destroyThumbnails(); | ||||
|  | ||||
|         if (this._keyPressEventId) | ||||
|             global.stage.disconnect(this._keyPressEventId); | ||||
|         if (this._keyReleaseEventId) | ||||
|             global.stage.disconnect(this._keyReleaseEventId); | ||||
|  | ||||
|         if (this._motionTimeoutId != 0) | ||||
|             Mainloop.source_remove(this._motionTimeoutId); | ||||
|         if (this._thumbnailTimeoutId != 0) | ||||
|             Mainloop.source_remove(this._thumbnailTimeoutId); | ||||
|         if (this._initialDelayTimeoutId != 0) | ||||
|             Mainloop.source_remove(this._initialDelayTimeoutId); | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
| @@ -461,15 +458,11 @@ AltTabPopup.prototype = { | ||||
|     }, | ||||
|  | ||||
|     _destroyThumbnails : function() { | ||||
|         let thumbnailsActor = this._thumbnails.actor; | ||||
|         Tweener.addTween(thumbnailsActor, | ||||
|         Tweener.addTween(this._thumbnails.actor, | ||||
|                          { opacity: 0, | ||||
|                            time: THUMBNAIL_FADE_TIME, | ||||
|                            transition: 'easeOutQuad', | ||||
|                            onComplete: Lang.bind(this, function() { | ||||
|                                                             thumbnailsActor.destroy(); | ||||
|                                                             this.thumbnailsVisible = false; | ||||
|                                                         }) | ||||
|                            onComplete: function() { this.destroy(); } | ||||
|                          }); | ||||
|         this._thumbnails = null; | ||||
|     }, | ||||
| @@ -481,16 +474,11 @@ AltTabPopup.prototype = { | ||||
|  | ||||
|         this.actor.add_actor(this._thumbnails.actor); | ||||
|  | ||||
|         // Need to force an allocation so we can figure out whether we | ||||
|         // need to scroll when selecting | ||||
|         this._thumbnails.actor.get_allocation_box(); | ||||
|  | ||||
|         this._thumbnails.actor.opacity = 0; | ||||
|         Tweener.addTween(this._thumbnails.actor, | ||||
|                          { opacity: 255, | ||||
|                            time: THUMBNAIL_FADE_TIME, | ||||
|                            transition: 'easeOutQuad', | ||||
|                            onComplete: Lang.bind(this, function () { this.thumbnailsVisible = true; }) | ||||
|                            transition: 'easeOutQuad' | ||||
|                          }); | ||||
|     } | ||||
| }; | ||||
| @@ -531,11 +519,16 @@ SwitcherList.prototype = { | ||||
|         this._leftArrow = new St.DrawingArea({ style_class: 'switcher-arrow', | ||||
|                                                pseudo_class: 'highlighted' }); | ||||
|         this._leftArrow.connect('repaint', Lang.bind(this, | ||||
|             function() { _drawArrow(this._leftArrow, St.Side.LEFT); })); | ||||
|                                             function (area) { | ||||
|                                                 Shell.draw_box_pointer(area, Shell.PointerDirection.LEFT); | ||||
|                                             })); | ||||
|  | ||||
|         this._rightArrow = new St.DrawingArea({ style_class: 'switcher-arrow', | ||||
|                                                 pseudo_class: 'highlighted' }); | ||||
|         this._rightArrow.connect('repaint', Lang.bind(this, | ||||
|             function() { _drawArrow(this._rightArrow, St.Side.RIGHT); })); | ||||
|                                             function (area) { | ||||
|                                                 Shell.draw_box_pointer(area, Shell.PointerDirection.RIGHT); | ||||
|                                             })); | ||||
|  | ||||
|         this.actor.add_actor(this._leftArrow); | ||||
|         this.actor.add_actor(this._rightArrow); | ||||
| @@ -591,30 +584,24 @@ SwitcherList.prototype = { | ||||
|         this._rightArrow.opacity = this._rightGradient.opacity; | ||||
|     }, | ||||
|  | ||||
|     addItem : function(item, label) { | ||||
|         let bbox = new St.Button({ style_class: 'item-box', | ||||
|                                    reactive: true }); | ||||
|     addItem : function(item) { | ||||
|         let bbox = new St.Clickable({ style_class: 'item-box', | ||||
|                                       reactive: true }); | ||||
|  | ||||
|         bbox.set_child(item); | ||||
|         this._list.add_actor(bbox); | ||||
|  | ||||
|         let n = this._items.length; | ||||
|         bbox.connect('clicked', Lang.bind(this, function() { this._onItemClicked(n); })); | ||||
|         bbox.connect('enter-event', Lang.bind(this, function() { this._onItemEnter(n); })); | ||||
|  | ||||
|         bbox.label_actor = label; | ||||
|         bbox.connect('clicked', Lang.bind(this, function () { | ||||
|                                                this._itemActivated(n); | ||||
|                                           })); | ||||
|         bbox.connect('enter-event', Lang.bind(this, function () { | ||||
|                                                   this._itemEntered(n); | ||||
|                                               })); | ||||
|  | ||||
|         this._items.push(bbox); | ||||
|     }, | ||||
|  | ||||
|     _onItemClicked: function (index) { | ||||
|         this._itemActivated(index); | ||||
|     }, | ||||
|  | ||||
|     _onItemEnter: function (index) { | ||||
|         this._itemEntered(index); | ||||
|     }, | ||||
|  | ||||
|     addSeparator: function () { | ||||
|         let box = new St.Bin({ style_class: 'separator' }); | ||||
|         this._separator = box; | ||||
| @@ -622,21 +609,19 @@ SwitcherList.prototype = { | ||||
|     }, | ||||
|  | ||||
|     highlight: function(index, justOutline) { | ||||
|         if (this._highlighted != -1) { | ||||
|             this._items[this._highlighted].remove_style_pseudo_class('outlined'); | ||||
|             this._items[this._highlighted].remove_style_pseudo_class('selected'); | ||||
|         } | ||||
|         if (this._highlighted != -1) | ||||
|             this._items[this._highlighted].style_class = 'item-box'; | ||||
|  | ||||
|         this._highlighted = index; | ||||
|  | ||||
|         if (this._highlighted != -1) { | ||||
|             if (justOutline) | ||||
|                 this._items[this._highlighted].add_style_pseudo_class('outlined'); | ||||
|                 this._items[this._highlighted].style_class = 'outlined-item-box'; | ||||
|             else | ||||
|                 this._items[this._highlighted].add_style_pseudo_class('selected'); | ||||
|                 this._items[this._highlighted].style_class = 'selected-item-box'; | ||||
|         } | ||||
|  | ||||
|         let monitor = Main.layoutManager.primaryMonitor; | ||||
|         let monitor = global.get_primary_monitor(); | ||||
|         let itemSize = this._items[index].allocation.x2 - this._items[index].allocation.x1; | ||||
|         let [posX, posY] = this._items[index].get_transformed_position(); | ||||
|         posX += this.actor.x; | ||||
| @@ -664,7 +649,7 @@ SwitcherList.prototype = { | ||||
|  | ||||
|     _scrollToRight : function() { | ||||
|         this._scrollableLeft = true; | ||||
|         let monitor = Main.layoutManager.primaryMonitor; | ||||
|         let monitor = global.get_primary_monitor(); | ||||
|         let padding = this.actor.get_theme_node().get_horizontal_padding(); | ||||
|         let parentPadding = this.actor.get_parent().get_theme_node().get_horizontal_padding(); | ||||
|         let x = this._items[this._highlighted].allocation.x2 - monitor.width + padding + parentPadding; | ||||
| @@ -761,7 +746,7 @@ SwitcherList.prototype = { | ||||
|         let children = this._list.get_children(); | ||||
|         let childBox = new Clutter.ActorBox(); | ||||
|  | ||||
|         let primary = Main.layoutManager.primaryMonitor; | ||||
|         let primary = global.get_primary_monitor(); | ||||
|         let parentRightPadding = this.actor.get_parent().get_theme_node().get_padding(St.Side.RIGHT); | ||||
|         if (this.actor.allocation.x2 == primary.x + primary.width - parentRightPadding) { | ||||
|             if (this._squareItems) | ||||
| @@ -819,7 +804,7 @@ AppIcon.prototype = { | ||||
|         this.actor = new St.BoxLayout({ style_class: 'alt-tab-app', | ||||
|                                          vertical: true }); | ||||
|         this.icon = null; | ||||
|         this._iconBin = new St.Bin({ x_fill: true, y_fill: true }); | ||||
|         this._iconBin = new St.Bin(); | ||||
|  | ||||
|         this.actor.add(this._iconBin, { x_fill: false, y_fill: false } ); | ||||
|         this.label = new St.Label({ text: this.app.get_name() }); | ||||
| @@ -833,14 +818,14 @@ AppIcon.prototype = { | ||||
|     } | ||||
| }; | ||||
|  | ||||
| function AppSwitcher(apps, altTabPopup) { | ||||
|     this._init(apps, altTabPopup); | ||||
| function AppSwitcher(apps) { | ||||
|     this._init(apps); | ||||
| } | ||||
|  | ||||
| AppSwitcher.prototype = { | ||||
|     __proto__ : SwitcherList.prototype, | ||||
|  | ||||
|     _init : function(apps, altTabPopup) { | ||||
|     _init : function(apps) { | ||||
|         SwitcherList.prototype._init.call(this, true); | ||||
|  | ||||
|         // Construct the AppIcons, sort by time, add to the popup | ||||
| @@ -872,8 +857,6 @@ AppSwitcher.prototype = { | ||||
|  | ||||
|         this._curApp = -1; | ||||
|         this._iconSize = 0; | ||||
|         this._altTabPopup = altTabPopup; | ||||
|         this._mouseTimeOutId = 0; | ||||
|     }, | ||||
|  | ||||
|     _getPreferredHeight: function (actor, forWidth, alloc) { | ||||
| @@ -881,19 +864,17 @@ AppSwitcher.prototype = { | ||||
|         while(this._items.length > 1 && this._items[j].style_class != 'item-box') { | ||||
|                 j++; | ||||
|         } | ||||
|         let themeNode = this._items[j].get_theme_node(); | ||||
|         let iconPadding = themeNode.get_horizontal_padding(); | ||||
|         let iconBorder = themeNode.get_border_width(St.Side.LEFT) + themeNode.get_border_width(St.Side.RIGHT); | ||||
|         let iconPadding = this._items[j].get_theme_node().get_horizontal_padding(); | ||||
|         let [iconMinHeight, iconNaturalHeight] = this.icons[j].label.get_preferred_height(-1); | ||||
|         let iconSpacing = iconNaturalHeight + iconPadding + iconBorder; | ||||
|         let iconSpacing = iconNaturalHeight + iconPadding; | ||||
|         let totalSpacing = this._list.spacing * (this._items.length - 1); | ||||
|         if (this._separator) | ||||
|            totalSpacing += this._separator.width + this._list.spacing; | ||||
|  | ||||
|         // We just assume the whole screen here due to weirdness happing with the passed width | ||||
|         let primary = Main.layoutManager.primaryMonitor; | ||||
|         let focus = global.get_focus_monitor(); | ||||
|         let parentPadding = this.actor.get_parent().get_theme_node().get_horizontal_padding(); | ||||
|         let availWidth = primary.width - parentPadding - this.actor.get_theme_node().get_horizontal_padding(); | ||||
|         let availWidth = focus.width - parentPadding - this.actor.get_theme_node().get_horizontal_padding(); | ||||
|         let height = 0; | ||||
|  | ||||
|         for(let i =  0; i < iconSizes.length; i++) { | ||||
| @@ -938,29 +919,6 @@ AppSwitcher.prototype = { | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     // We override SwitcherList's _onItemEnter method to delay | ||||
|     // activation when the thumbnail list is open | ||||
|     _onItemEnter: function (index) { | ||||
|         if (this._mouseTimeOutId != 0) | ||||
|             Mainloop.source_remove(this._mouseTimeOutId); | ||||
|         if (this._altTabPopup.thumbnailsVisible) { | ||||
|             this._mouseTimeOutId = Mainloop.timeout_add(APP_ICON_HOVER_TIMEOUT, | ||||
|                                                         Lang.bind(this, function () { | ||||
|                                                                             this._enterItem(index); | ||||
|                                                                             this._mouseTimeOutId = 0; | ||||
|                                                                             return false; | ||||
|                                                         })); | ||||
|         } else | ||||
|            this._itemEntered(index); | ||||
|     }, | ||||
|  | ||||
|     _enterItem: function(index) { | ||||
|         let [x, y, mask] = global.get_pointer(); | ||||
|         let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y); | ||||
|         if (this._items[index].contains(pickedActor)) | ||||
|             this._itemEntered(index); | ||||
|     }, | ||||
|  | ||||
|     // We override SwitcherList's highlight() method to also deal with | ||||
|     // the AppSwitcher->ThumbnailList arrows. Apps with only 1 window | ||||
|     // will hide their arrows by default, but show them when their | ||||
| @@ -989,11 +947,14 @@ AppSwitcher.prototype = { | ||||
|  | ||||
|     _addIcon : function(appIcon) { | ||||
|         this.icons.push(appIcon); | ||||
|         this.addItem(appIcon.actor, appIcon.label); | ||||
|         this.addItem(appIcon.actor); | ||||
|  | ||||
|         let n = this._arrows.length; | ||||
|         let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' }); | ||||
|         arrow.connect('repaint', function() { _drawArrow(arrow, St.Side.BOTTOM); }); | ||||
|         arrow.connect('repaint', Lang.bind(this, | ||||
|             function (area) { | ||||
|                 Shell.draw_box_pointer(area, Shell.PointerDirection.DOWN); | ||||
|             })); | ||||
|         this._list.add_actor(arrow); | ||||
|         this._arrows.push(arrow); | ||||
|  | ||||
| @@ -1059,12 +1020,9 @@ ThumbnailList.prototype = { | ||||
|                 this._labels.push(bin); | ||||
|                 bin.add_actor(name); | ||||
|                 box.add_actor(bin); | ||||
|  | ||||
|                 this.addItem(box, name); | ||||
|             } else { | ||||
|                 this.addItem(box, null); | ||||
|             } | ||||
|  | ||||
|             this.addItem(box); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
| @@ -1082,9 +1040,6 @@ ThumbnailList.prototype = { | ||||
|  | ||||
|         for (let i = 0; i < this._thumbnailBins.length; i++) { | ||||
|             let mutterWindow = this._windows[i].get_compositor_private(); | ||||
|             if (!mutterWindow) | ||||
|                 continue; | ||||
|  | ||||
|             let windowTexture = mutterWindow.get_texture (); | ||||
|             let [width, height] = windowTexture.get_size(); | ||||
|             let scale = Math.min(1.0, THUMBNAIL_DEFAULT_SIZE / width, availHeight / height); | ||||
| @@ -1102,46 +1057,3 @@ ThumbnailList.prototype = { | ||||
|         this._thumbnailBins = new Array(); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| function _drawArrow(area, side) { | ||||
|     let themeNode = area.get_theme_node(); | ||||
|     let borderColor = themeNode.get_border_color(side); | ||||
|     let bodyColor = themeNode.get_foreground_color(); | ||||
|  | ||||
|     let [width, height] = area.get_surface_size (); | ||||
|     let cr = area.get_context(); | ||||
|  | ||||
|     cr.setLineWidth(1.0); | ||||
|     Clutter.cairo_set_source_color(cr, borderColor); | ||||
|  | ||||
|     switch (side) { | ||||
|     case St.Side.TOP: | ||||
|         cr.moveTo(0, height); | ||||
|         cr.lineTo(Math.floor(width * 0.5), 0); | ||||
|         cr.lineTo(width, height); | ||||
|         break; | ||||
|  | ||||
|     case St.Side.BOTTOM: | ||||
|         cr.moveTo(width, 0); | ||||
|         cr.lineTo(Math.floor(width * 0.5), height); | ||||
|         cr.lineTo(0, 0); | ||||
|         break; | ||||
|  | ||||
|     case St.Side.LEFT: | ||||
|         cr.moveTo(width, height); | ||||
|         cr.lineTo(0, Math.floor(height * 0.5)); | ||||
|         cr.lineTo(width, 0); | ||||
|         break; | ||||
|  | ||||
|     case St.Side.RIGHT: | ||||
|         cr.moveTo(0, 0); | ||||
|         cr.lineTo(width, Math.floor(height * 0.5)); | ||||
|         cr.lineTo(0, height); | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     cr.strokePreserve(); | ||||
|  | ||||
|     Clutter.cairo_set_source_color(cr, bodyColor); | ||||
|     cr.fill(); | ||||
| } | ||||
|   | ||||
| @@ -1,15 +1,14 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Clutter = imports.gi.Clutter; | ||||
| const GLib = imports.gi.GLib; | ||||
| const Gtk = imports.gi.Gtk; | ||||
| const GMenu = imports.gi.GMenu; | ||||
| const Shell = imports.gi.Shell; | ||||
| const Lang = imports.lang; | ||||
| const Signals = imports.signals; | ||||
| const Meta = imports.gi.Meta; | ||||
| const St = imports.gi.St; | ||||
| const Mainloop = imports.mainloop; | ||||
| const Gettext = imports.gettext.domain('gnome-shell'); | ||||
| const _ = Gettext.gettext; | ||||
|  | ||||
| const AppFavorites = imports.ui.appFavorites; | ||||
| const DND = imports.ui.dnd; | ||||
| @@ -22,9 +21,7 @@ const Tweener = imports.ui.tweener; | ||||
| const Workspace = imports.ui.workspace; | ||||
| const Params = imports.misc.params; | ||||
|  | ||||
| const MAX_APPLICATION_WORK_MILLIS = 75; | ||||
| const MENU_POPUP_TIMEOUT = 600; | ||||
| const SCROLL_TIME = 0.1; | ||||
|  | ||||
| function AlphabeticalView() { | ||||
|     this._init(); | ||||
| @@ -32,106 +29,49 @@ function AlphabeticalView() { | ||||
|  | ||||
| AlphabeticalView.prototype = { | ||||
|     _init: function() { | ||||
|         this._grid = new IconGrid.IconGrid({ xAlign: St.Align.START }); | ||||
|         this.actor = new St.BoxLayout({ vertical: true }); | ||||
|         this._grid = new IconGrid.IconGrid(); | ||||
|         this._appSystem = Shell.AppSystem.get_default(); | ||||
|  | ||||
|         this._pendingAppLaterId = 0; | ||||
|         this._appIcons = {}; // desktop file id | ||||
|  | ||||
|         let box = new St.BoxLayout({ vertical: true }); | ||||
|         box.add(this._grid.actor, { y_align: St.Align.START, expand: true }); | ||||
|  | ||||
|         this.actor = new St.ScrollView({ x_fill: true, | ||||
|                                          y_fill: false, | ||||
|                                          y_align: St.Align.START, | ||||
|                                          style_class: 'vfade' }); | ||||
|         this.actor.add_actor(box); | ||||
|         this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); | ||||
|         this.actor.connect('notify::mapped', Lang.bind(this, | ||||
|             function() { | ||||
|                 if (!this.actor.mapped) | ||||
|                     return; | ||||
|  | ||||
|                 let adjustment = this.actor.vscroll.adjustment; | ||||
|                 let direction = Overview.SwipeScrollDirection.VERTICAL; | ||||
|                 Main.overview.setScrollAdjustment(adjustment, direction); | ||||
|  | ||||
|                 // Reset scroll on mapping | ||||
|                 adjustment.value = 0; | ||||
|             })); | ||||
|         this.actor.add(this._grid.actor, { y_align: St.Align.START, expand: true }); | ||||
|     }, | ||||
|  | ||||
|     _removeAll: function() { | ||||
|         this._grid.removeAll(); | ||||
|         this._appIcons = {}; | ||||
|         this._apps = []; | ||||
|     }, | ||||
|  | ||||
|     _addApp: function(app) { | ||||
|         var id = app.get_id(); | ||||
|         let appIcon = new AppWellIcon(app); | ||||
|         let appIcon = new AppWellIcon(this._appSystem.get_app(app.get_id())); | ||||
|         appIcon.connect('launching', Lang.bind(this, function() { | ||||
|             this.emit('launching'); | ||||
|         })); | ||||
|         appIcon._draggable.connect('drag-begin', Lang.bind(this, function() { | ||||
|             this.emit('drag-begin'); | ||||
|         })); | ||||
|  | ||||
|         this._grid.addItem(appIcon.actor); | ||||
|         appIcon.actor.connect('key-focus-in', Lang.bind(this, this._ensureIconVisible)); | ||||
|  | ||||
|         this._appIcons[id] = appIcon; | ||||
|         this._apps.push(appIcon); | ||||
|     }, | ||||
|  | ||||
|     _ensureIconVisible: function(icon) { | ||||
|         let adjustment = this.actor.vscroll.adjustment; | ||||
|         let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values(); | ||||
|     refresh: function(apps) { | ||||
|         let ids = []; | ||||
|         for (let i in apps) | ||||
|             ids.push(i); | ||||
|         ids.sort(function(a, b) { | ||||
|             return apps[a].get_name().localeCompare(apps[b].get_name()); | ||||
|         }); | ||||
|  | ||||
|         let offset = 0; | ||||
|         let vfade = this.actor.get_effect("vfade"); | ||||
|         if (vfade) | ||||
|             offset = vfade.fade_offset; | ||||
|  | ||||
|         // If this gets called as part of a right-click, the actor | ||||
|         // will be needs_allocation, and so "icon.y" would return 0 | ||||
|         let box = icon.get_allocation_box(); | ||||
|  | ||||
|         if (box.y1 < value + offset) | ||||
|             value = Math.max(0, box.y1 - offset); | ||||
|         else if (box.y2 > value + pageSize - offset) | ||||
|             value = Math.min(upper, box.y2 + offset - pageSize); | ||||
|         else | ||||
|             return; | ||||
|  | ||||
|         Tweener.addTween(adjustment, | ||||
|                          { value: value, | ||||
|                            time: SCROLL_TIME, | ||||
|                            transition: 'easeOutQuad' }); | ||||
|     }, | ||||
|  | ||||
|     setVisibleApps: function(apps) { | ||||
|         if (apps == null) { // null implies "all" | ||||
|             for (var id in this._appIcons) { | ||||
|                 var icon = this._appIcons[id]; | ||||
|                 icon.actor.visible = true; | ||||
|             } | ||||
|         } else { | ||||
|             // Set everything to not-visible, then set to visible what we should see | ||||
|             for (var id in this._appIcons) { | ||||
|                 var icon = this._appIcons[id]; | ||||
|                 icon.actor.visible = false; | ||||
|             } | ||||
|             for (var i = 0; i < apps.length; i++) { | ||||
|                 var app = apps[i]; | ||||
|                 var id = app.get_id(); | ||||
|                 var icon = this._appIcons[id]; | ||||
|                 icon.actor.visible = true; | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     setAppList: function(apps) { | ||||
|         this._removeAll(); | ||||
|         for (var i = 0; i < apps.length; i++) { | ||||
|             var app = apps[i]; | ||||
|             this._addApp(app); | ||||
|          } | ||||
|  | ||||
|         for (let i = 0; i < ids.length; i++) { | ||||
|             this._addApp(apps[ids[i]]); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | ||||
| Signals.addSignalMethods(AlphabeticalView.prototype); | ||||
|  | ||||
| function ViewByCategories() { | ||||
|     this._init(); | ||||
| } | ||||
| @@ -139,150 +79,59 @@ function ViewByCategories() { | ||||
| ViewByCategories.prototype = { | ||||
|     _init: function() { | ||||
|         this._appSystem = Shell.AppSystem.get_default(); | ||||
|         this.actor = new St.BoxLayout({ style_class: 'all-app' }); | ||||
|         this.actor = new St.BoxLayout({ vertical: true }); | ||||
|         this.actor._delegate = this; | ||||
|  | ||||
|         this._view = new AlphabeticalView(); | ||||
|  | ||||
|         // categories can be -1 (the All view) or 0...n-1, where n | ||||
|         // is the number of sections | ||||
|         // -2 is a flag to indicate that nothing is selected | ||||
|         // (used only before the actor is mapped the first time) | ||||
|         this._currentCategory = -2; | ||||
|         this._categories = []; | ||||
|         this._apps = null; | ||||
|  | ||||
|         this._categoryBox = new St.BoxLayout({ vertical: true, reactive: true }); | ||||
|         this._categoryScroll = new St.ScrollView({ x_fill: false, | ||||
|                                                    y_fill: false, | ||||
|                                                    style_class: 'vfade' }); | ||||
|         this._categoryScroll.add_actor(this._categoryBox); | ||||
|         this.actor.add(this._view.actor, { expand: true, x_fill: true, y_fill: true }); | ||||
|         this.actor.add(this._categoryScroll, { expand: false, y_fill: false, y_align: St.Align.START }); | ||||
|  | ||||
|         // Always select the "All" filter when switching to the app view | ||||
|         this.actor.connect('notify::mapped', Lang.bind(this, | ||||
|             function() { | ||||
|                 if (this.actor.mapped && this._allCategoryButton) | ||||
|                     this._selectCategory(-1); | ||||
|             })); | ||||
|  | ||||
|         // We need a dummy actor to catch the keyboard focus if the | ||||
|         // user Ctrl-Alt-Tabs here before the deferred work creates | ||||
|         // our real contents | ||||
|         this._focusDummy = new St.Bin({ can_focus: true }); | ||||
|         this.actor.add(this._focusDummy); | ||||
|         this._sections = []; | ||||
|     }, | ||||
|  | ||||
|     _selectCategory: function(num) { | ||||
|         if (this._currentCategory == num) // nothing to do | ||||
|     _updateSections: function(apps) { | ||||
|         this._removeAll(); | ||||
|  | ||||
|         let sections = this._appSystem.get_sections(); | ||||
|         if (!sections) | ||||
|             return; | ||||
|         for (let i = 0; i < sections.length; i++) { | ||||
|             if (i) { | ||||
|                 let actor = new St.Bin({ style_class: 'app-section-divider' }); | ||||
|                 let divider = new St.Bin({ style_class: 'app-section-divider-container', | ||||
|                                            child: actor, | ||||
|                                            x_fill: true }); | ||||
|  | ||||
|         this._currentCategory = num; | ||||
|  | ||||
|         if (num != -1) { | ||||
|             var category = this._categories[num]; | ||||
|             this._allCategoryButton.remove_style_pseudo_class('selected'); | ||||
|             this._view.setVisibleApps(category.apps); | ||||
|         } else { | ||||
|             this._allCategoryButton.add_style_pseudo_class('selected'); | ||||
|             this._view.setVisibleApps(null); | ||||
|         } | ||||
|  | ||||
|         for (var i = 0; i < this._categories.length; i++) { | ||||
|             if (i == num) | ||||
|                 this._categories[i].button.add_style_pseudo_class('selected'); | ||||
|             else | ||||
|                 this._categories[i].button.remove_style_pseudo_class('selected'); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     // Recursively load a GMenuTreeDirectory; we could put this in ShellAppSystem too | ||||
|     _loadCategory: function(dir, appList) { | ||||
|         var iter = dir.iter(); | ||||
|         var nextType; | ||||
|         while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) { | ||||
|             if (nextType == GMenu.TreeItemType.ENTRY) { | ||||
|                 var entry = iter.get_entry(); | ||||
|                 var app = this._appSystem.lookup_app_by_tree_entry(entry); | ||||
|                 if (!entry.get_app_info().get_nodisplay()) | ||||
|                     appList.push(app); | ||||
|             } else if (nextType == GMenu.TreeItemType.DIRECTORY) { | ||||
|                 if (!dir.get_is_nodisplay()) | ||||
|                     this._loadCategory(iter.get_directory(), appList); | ||||
|                 this.actor.add(divider, { y_fill: false, expand: true }); | ||||
|             } | ||||
|             let _apps = apps.filter(function(app) { | ||||
|                 return app.get_section() == sections[i]; | ||||
|             }); | ||||
|             this._sections[i] = { view: new AlphabeticalView(), | ||||
|                                   apps: _apps, | ||||
|                                   name: sections[i] }; | ||||
|             this._sections[i].view.connect('launching', Lang.bind(this, function() { | ||||
|                 this.emit('launching'); | ||||
|             })); | ||||
|             this._sections[i].view.connect('drag-begin', Lang.bind(this, function() { | ||||
|                 this.emit('drag-begin'); | ||||
|             })); | ||||
|             this.actor.add(this._sections[i].view.actor, { y_align: St.Align.START, expand: true }); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _addCategory: function(name, index, dir, allApps) { | ||||
|         let button = new St.Button({ label: GLib.markup_escape_text (name, -1), | ||||
|                                      style_class: 'app-filter', | ||||
|                                      x_align: St.Align.START, | ||||
|                                      can_focus: true }); | ||||
|         button.connect('clicked', Lang.bind(this, function() { | ||||
|             this._selectCategory(index); | ||||
|         })); | ||||
|  | ||||
|         var apps; | ||||
|         if (dir == null) { | ||||
|             apps = allApps; | ||||
|             this._allCategoryButton = button; | ||||
|         } else { | ||||
|             apps = []; | ||||
|             this._loadCategory(dir, apps); | ||||
|             this._categories.push({ apps: apps, | ||||
|                                     name: name, | ||||
|                                     button: button }); | ||||
|         } | ||||
|  | ||||
|         this._categoryBox.add(button, { expand: true, x_fill: true, y_fill: false }); | ||||
|     }, | ||||
|  | ||||
|     _removeAll: function() { | ||||
|         this._categories = []; | ||||
|         this._categoryBox.destroy_children(); | ||||
|         this.actor.destroy_children(); | ||||
|         this._sections.forEach(function (section) { section.view.disconnectAll(); }); | ||||
|  | ||||
|         this._sections = []; | ||||
|     }, | ||||
|  | ||||
|     refresh: function() { | ||||
|         this._removeAll(); | ||||
|  | ||||
|         var allApps = Shell.AppSystem.get_default().get_all(); | ||||
|         allApps.sort(function(a, b) { | ||||
|             return a.compare_by_name(b); | ||||
|         }); | ||||
|  | ||||
|         /* Translators: Filter to display all applications */ | ||||
|         this._addCategory(_("All"), -1, null, allApps); | ||||
|  | ||||
|         var tree = this._appSystem.get_tree(); | ||||
|         var root = tree.get_root_directory(); | ||||
|  | ||||
|         var iter = root.iter(); | ||||
|         var nextType; | ||||
|         var i = 0; | ||||
|         while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) { | ||||
|             if (nextType == GMenu.TreeItemType.DIRECTORY) { | ||||
|                 var dir = iter.get_directory(); | ||||
|                 if (dir.get_is_nodisplay()) | ||||
|                     continue; | ||||
|                 this._addCategory(dir.get_name(), i, dir); | ||||
|                 i++; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         this._view.setAppList(allApps); | ||||
|         this._selectCategory(-1); | ||||
|  | ||||
|         if (this._focusDummy) { | ||||
|             let focused = this._focusDummy.has_key_focus(); | ||||
|             this._focusDummy.destroy(); | ||||
|             this._focusDummy = null; | ||||
|             if (focused) | ||||
|                 this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); | ||||
|     refresh: function(apps) { | ||||
|         this._updateSections(apps); | ||||
|         for (let i = 0; i < this._sections.length; i++) { | ||||
|             this._sections[i].view.refresh(this._sections[i].apps); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | ||||
| Signals.addSignalMethods(ViewByCategories.prototype); | ||||
|  | ||||
| /* This class represents a display containing a collection of application items. | ||||
|  * The applications are sorted based on their name. | ||||
|  */ | ||||
| @@ -297,14 +146,61 @@ AllAppDisplay.prototype = { | ||||
|             Main.queueDeferredWork(this._workId); | ||||
|         })); | ||||
|  | ||||
|         this._scrollView = new St.ScrollView({ x_fill: true, | ||||
|                                                y_fill: false, | ||||
|                                                vshadows: true }); | ||||
|         this.actor = new St.Bin({ style_class: 'all-app', | ||||
|                                   y_align: St.Align.START, | ||||
|                                   child: this._scrollView }); | ||||
|  | ||||
|         this._appView = new ViewByCategories(); | ||||
|         this.actor = new St.Bin({ child: this._appView.actor, x_fill: true, y_fill: true }); | ||||
|         this._scrollView.add_actor(this._appView.actor); | ||||
|  | ||||
|         this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); | ||||
|  | ||||
|         this._workId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay)); | ||||
|     }, | ||||
|  | ||||
|     _redisplay: function() { | ||||
|         this._appView.refresh(); | ||||
|         let apps = this._appSystem.get_flattened_apps().filter(function(app) { | ||||
|             return !app.get_is_nodisplay(); | ||||
|         }); | ||||
|  | ||||
|         this._appView.refresh(apps); | ||||
|     } | ||||
| }; | ||||
| Signals.addSignalMethods(AllAppDisplay.prototype); | ||||
|  | ||||
|  | ||||
| function BaseAppSearchProvider() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| BaseAppSearchProvider.prototype = { | ||||
|     __proto__: Search.SearchProvider.prototype, | ||||
|  | ||||
|     _init: function(name) { | ||||
|         Search.SearchProvider.prototype._init.call(this, name); | ||||
|         this._appSys = Shell.AppSystem.get_default(); | ||||
|     }, | ||||
|  | ||||
|     getResultMeta: function(resultId) { | ||||
|         let app = this._appSys.get_app(resultId); | ||||
|         if (!app) | ||||
|             return null; | ||||
|         return { 'id': resultId, | ||||
|                  'name': app.get_name(), | ||||
|                  'icon': app.create_icon_texture(Search.RESULT_ICON_SIZE)}; | ||||
|     }, | ||||
|  | ||||
|     activateResult: function(id) { | ||||
|         let app = this._appSys.get_app(id); | ||||
|         app.activate(); | ||||
|     }, | ||||
|  | ||||
|     dragActivateResult: function(id) { | ||||
|         let app = this._appSys.get_app(id); | ||||
|         app.open_new_window(); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| @@ -313,122 +209,72 @@ function AppSearchProvider() { | ||||
| } | ||||
|  | ||||
| AppSearchProvider.prototype = { | ||||
|     __proto__: Search.SearchProvider.prototype, | ||||
|     __proto__: BaseAppSearchProvider.prototype, | ||||
|  | ||||
|     _init: function() { | ||||
|         Search.SearchProvider.prototype._init.call(this, _("APPLICATIONS")); | ||||
|         this._appSys = Shell.AppSystem.get_default(); | ||||
|     }, | ||||
|  | ||||
|     getResultMeta: function(app) { | ||||
|         return { 'id': app, | ||||
|                  'name': app.get_name(), | ||||
|                  'createIcon': function(size) { | ||||
|                                    return app.create_icon_texture(size); | ||||
|                                } | ||||
|                }; | ||||
|          BaseAppSearchProvider.prototype._init.call(this, _("APPLICATIONS")); | ||||
|     }, | ||||
|  | ||||
|     getInitialResultSet: function(terms) { | ||||
|         return this._appSys.initial_search(terms); | ||||
|         return this._appSys.initial_search(false, terms); | ||||
|     }, | ||||
|  | ||||
|     getSubsearchResultSet: function(previousResults, terms) { | ||||
|         return this._appSys.subsearch(previousResults, terms); | ||||
|     }, | ||||
|  | ||||
|     activateResult: function(app, params) { | ||||
|         params = Params.parse(params, { workspace: -1, | ||||
|                                         timestamp: 0 }); | ||||
|  | ||||
|         let event = Clutter.get_current_event(); | ||||
|         let modifiers = event ? Shell.get_event_state(event) : 0; | ||||
|         let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK; | ||||
|  | ||||
|         if (openNewWindow) | ||||
|             app.open_new_window(params.workspace); | ||||
|         else | ||||
|             app.activate_full(params.workspace, params.timestamp); | ||||
|     }, | ||||
|  | ||||
|     dragActivateResult: function(id, params) { | ||||
|         params = Params.parse(params, { workspace: -1, | ||||
|                                         timestamp: 0 }); | ||||
|  | ||||
|         let app = this._appSys.lookup_app(id); | ||||
|         app.open_new_window(workspace); | ||||
|         return this._appSys.subsearch(false, previousResults, terms); | ||||
|     }, | ||||
|  | ||||
|     createResultActor: function (resultMeta, terms) { | ||||
|         let app = resultMeta['id']; | ||||
|         let app = this._appSys.get_app(resultMeta['id']); | ||||
|         let icon = new AppWellIcon(app); | ||||
|         return icon.actor; | ||||
|     }, | ||||
|  | ||||
|     expandSearch: function(terms) { | ||||
|         log('TODO expand search'); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| function SettingsSearchProvider() { | ||||
| function PrefsSearchProvider() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| SettingsSearchProvider.prototype = { | ||||
|     __proto__: Search.SearchProvider.prototype, | ||||
| PrefsSearchProvider.prototype = { | ||||
|     __proto__: BaseAppSearchProvider.prototype, | ||||
|  | ||||
|     _init: function() { | ||||
|         Search.SearchProvider.prototype._init.call(this, _("SETTINGS")); | ||||
|         this._appSys = Shell.AppSystem.get_default(); | ||||
|         this._gnomecc = this._appSys.lookup_app('gnome-control-center.desktop'); | ||||
|     }, | ||||
|  | ||||
|     getResultMeta: function(pref) { | ||||
|         return { 'id': pref, | ||||
|                  'name': pref.get_name(), | ||||
|                  'createIcon': function(size) { | ||||
|                                    return pref.create_icon_texture(size); | ||||
|                                } | ||||
|                }; | ||||
|         BaseAppSearchProvider.prototype._init.call(this, _("PREFERENCES")); | ||||
|     }, | ||||
|  | ||||
|     getInitialResultSet: function(terms) { | ||||
|         return this._appSys.search_settings(terms); | ||||
|         return this._appSys.initial_search(true, terms); | ||||
|     }, | ||||
|  | ||||
|     getSubsearchResultSet: function(previousResults, terms) { | ||||
|         return this._appSys.search_settings(terms); | ||||
|         return this._appSys.subsearch(true, previousResults, terms); | ||||
|     }, | ||||
|  | ||||
|     activateResult: function(pref, params) { | ||||
|         params = Params.parse(params, { workspace: -1, | ||||
|                                         timestamp: 0 }); | ||||
|  | ||||
|         pref.activate_full(params.workspace, params.timestamp); | ||||
|     }, | ||||
|  | ||||
|     dragActivateResult: function(pref, params) { | ||||
|         this.activateResult(pref, params); | ||||
|     }, | ||||
|  | ||||
|     createResultActor: function (resultMeta, terms) { | ||||
|         let app = resultMeta['id']; | ||||
|         let icon = new AppWellIcon(app); | ||||
|         return icon.actor; | ||||
|     expandSearch: function(terms) { | ||||
|         let controlCenter = this._appSys.load_from_desktop_file('gnomecc.desktop'); | ||||
|         controlCenter.launch(); | ||||
|         Main.overview.hide(); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| function AppIcon(app, params) { | ||||
|     this._init(app, params); | ||||
| function AppIcon(app) { | ||||
|     this._init(app); | ||||
| } | ||||
|  | ||||
| AppIcon.prototype = { | ||||
|     __proto__:  IconGrid.BaseIcon.prototype, | ||||
|  | ||||
|     _init : function(app, params) { | ||||
|     _init : function(app) { | ||||
|         this.app = app; | ||||
|  | ||||
|         let label = this.app.get_name(); | ||||
|  | ||||
|         IconGrid.BaseIcon.prototype._init.call(this, | ||||
|                                                label, | ||||
|                                                params); | ||||
|                                                { setSizeManually: true }); | ||||
|     }, | ||||
|  | ||||
|     createIcon: function(iconSize) { | ||||
| @@ -436,31 +282,23 @@ AppIcon.prototype = { | ||||
|     } | ||||
| }; | ||||
|  | ||||
| function AppWellIcon(app, iconParams, onActivateOverride) { | ||||
|     this._init(app, iconParams, onActivateOverride); | ||||
| function AppWellIcon(app) { | ||||
|     this._init(app); | ||||
| } | ||||
|  | ||||
| AppWellIcon.prototype = { | ||||
|     _init : function(app, iconParams, onActivateOverride) { | ||||
|     _init : function(app) { | ||||
|         this.app = app; | ||||
|         this.actor = new St.Button({ style_class: 'app-well-app', | ||||
|                                      reactive: true, | ||||
|                                      button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO, | ||||
|                                      can_focus: true, | ||||
|                                      x_fill: true, | ||||
|                                      y_fill: true }); | ||||
|         this.actor = new St.Clickable({ style_class: 'app-well-app', | ||||
|                                          reactive: true, | ||||
|                                          x_fill: true, | ||||
|                                          y_fill: true }); | ||||
|         this.actor._delegate = this; | ||||
|  | ||||
|         this.icon = new AppIcon(app, iconParams); | ||||
|         this.icon = new AppIcon(app); | ||||
|         this.actor.set_child(this.icon.actor); | ||||
|  | ||||
|         this.actor.label_actor = this.icon.label; | ||||
|  | ||||
|         // A function callback to override the default "app.activate()"; used by preferences | ||||
|         this._onActivateOverride = onActivateOverride; | ||||
|         this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress)); | ||||
|         this.actor.connect('clicked', Lang.bind(this, this._onClicked)); | ||||
|         this.actor.connect('popup-menu', Lang.bind(this, this._onKeyboardPopupMenu)); | ||||
|  | ||||
|         this._menu = null; | ||||
|         this._menuManager = new PopupMenu.PopupMenuManager(this); | ||||
| @@ -471,15 +309,12 @@ AppWellIcon.prototype = { | ||||
|                 this._removeMenuTimeout(); | ||||
|                 Main.overview.beginItemDrag(this); | ||||
|             })); | ||||
|         this._draggable.connect('drag-cancelled', Lang.bind(this, | ||||
|             function () { | ||||
|                 Main.overview.cancelledItemDrag(this); | ||||
|             })); | ||||
|         this._draggable.connect('drag-end', Lang.bind(this, | ||||
|             function () { | ||||
|                Main.overview.endItemDrag(this); | ||||
|             })); | ||||
|  | ||||
|         this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress)); | ||||
|         this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); | ||||
|  | ||||
|         this._menuTimeoutId = 0; | ||||
| @@ -518,34 +353,29 @@ AppWellIcon.prototype = { | ||||
|                 Lang.bind(this, function() { | ||||
|                     this.popupMenu(); | ||||
|                 })); | ||||
|         } else if (button == 3) { | ||||
|             this.popupMenu(); | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     }, | ||||
|  | ||||
|     _onClicked: function(actor, button) { | ||||
|     _onClicked: function(actor, event) { | ||||
|         this._removeMenuTimeout(); | ||||
|  | ||||
|         let button = event.get_button(); | ||||
|         if (button == 1) { | ||||
|             this._onActivate(Clutter.get_current_event()); | ||||
|             this._onActivate(event); | ||||
|         } else if (button == 2) { | ||||
|             // Last workspace is always empty | ||||
|             let launchWorkspace = global.screen.get_workspace_by_index(global.screen.n_workspaces - 1); | ||||
|             launchWorkspace.activate(global.get_current_time()); | ||||
|             this.emit('launching'); | ||||
|             this.app.open_new_window(-1); | ||||
|             Main.overview.hide(); | ||||
|             let newWorkspace = Main.overview.workspaces.addWorkspace(); | ||||
|             if (newWorkspace != null) { | ||||
|                 newWorkspace.activate(global.get_current_time()); | ||||
|                 this.emit('launching'); | ||||
|                 this.app.open_new_window(); | ||||
|                 Main.overview.hide(); | ||||
|             } | ||||
|         } else if (button == 3) { | ||||
|             this.popupMenu(); | ||||
|         } | ||||
|         return false; | ||||
|     }, | ||||
|  | ||||
|     _onKeyboardPopupMenu: function() { | ||||
|         this.popupMenu(); | ||||
|         this._menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); | ||||
|     }, | ||||
|  | ||||
|     getId: function() { | ||||
|         return this.app.get_id(); | ||||
|     }, | ||||
| @@ -556,63 +386,93 @@ AppWellIcon.prototype = { | ||||
|  | ||||
|         if (!this._menu) { | ||||
|             this._menu = new AppIconMenu(this); | ||||
|             this._menu.connect('highlight-window', Lang.bind(this, function (menu, window) { | ||||
|                 this.highlightWindow(window); | ||||
|             })); | ||||
|             this._menu.connect('activate-window', Lang.bind(this, function (menu, window) { | ||||
|                 this.activateWindow(window); | ||||
|             })); | ||||
|             this._menu.connect('popup', Lang.bind(this, function (menu, isPoppedUp) { | ||||
|                 if (!isPoppedUp) | ||||
|                 if (isPoppedUp) { | ||||
|                     this._onMenuPoppedUp(); | ||||
|                 } else { | ||||
|                     this._onMenuPoppedDown(); | ||||
|                 } | ||||
|             })); | ||||
|             Main.overview.connect('hiding', Lang.bind(this, function () { this._menu.close(); })); | ||||
|  | ||||
|             this._menuManager.addMenu(this._menu); | ||||
|         } | ||||
|  | ||||
|         this.actor.set_hover(true); | ||||
|         this.actor.show_tooltip(); | ||||
|         this._menu.popup(); | ||||
|  | ||||
|         return false; | ||||
|     }, | ||||
|  | ||||
|     highlightWindow: function(metaWindow) { | ||||
|         if (this._didActivateWindow) | ||||
|             return; | ||||
|         if (!this._getRunning()) | ||||
|             return; | ||||
|         Main.overview.getWorkspacesForWindow(metaWindow).setHighlightWindow(metaWindow); | ||||
|     }, | ||||
|  | ||||
|     activateWindow: function(metaWindow) { | ||||
|         if (metaWindow) { | ||||
|             this._didActivateWindow = true; | ||||
|             Main.activateWindow(metaWindow); | ||||
|         } else { | ||||
|             Main.overview.hide(); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _onMenuPoppedUp: function() { | ||||
|         if (this._getRunning()) { | ||||
|             Main.overview.getWorkspacesForWindow(null).setApplicationWindowSelection(this.app.get_id()); | ||||
|             this._setWindowSelection = true; | ||||
|             this._didActivateWindow = false; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _onMenuPoppedDown: function() { | ||||
|         this.actor.sync_hover(); | ||||
|  | ||||
|         if (this._didActivateWindow) | ||||
|             return; | ||||
|         if (!this._setWindowSelection) | ||||
|             return; | ||||
|  | ||||
|         Main.overview.getWorkspacesForWindow(null).setApplicationWindowSelection(null); | ||||
|         this._setWindowSelection = false; | ||||
|     }, | ||||
|  | ||||
|     _getRunning: function() { | ||||
|         return this.app.state != Shell.AppState.STOPPED; | ||||
|     }, | ||||
|  | ||||
|     _onActivate: function (event) { | ||||
|         this.emit('launching'); | ||||
|         let modifiers = Shell.get_event_state(event); | ||||
|  | ||||
|         if (this._onActivateOverride) { | ||||
|             this._onActivateOverride(event); | ||||
|         if (modifiers & Clutter.ModifierType.CONTROL_MASK | ||||
|             && this.app.state == Shell.AppState.RUNNING) { | ||||
|             this.app.open_new_window(); | ||||
|         } else { | ||||
|             if (modifiers & Clutter.ModifierType.CONTROL_MASK | ||||
|                 && this.app.state == Shell.AppState.RUNNING) { | ||||
|                 this.app.open_new_window(-1); | ||||
|             } else { | ||||
|                 this.app.activate(); | ||||
|             } | ||||
|             this.app.activate(); | ||||
|         } | ||||
|         Main.overview.hide(); | ||||
|     }, | ||||
|  | ||||
|     shellWorkspaceLaunch : function(params) { | ||||
|         params = Params.parse(params, { workspace: -1, | ||||
|                                         timestamp: 0 }); | ||||
|     // called by this._menuManager when it has the grab | ||||
|     menuEventFilter: function(event) { | ||||
|         return this._menu.menuEventFilter(event); | ||||
|     }, | ||||
|  | ||||
|         this.app.open_new_window(params.workspace); | ||||
|     shellWorkspaceLaunch : function() { | ||||
|         this.app.open_new_window(); | ||||
|     }, | ||||
|  | ||||
|     getDragActor: function() { | ||||
|         return this.app.create_icon_texture(Main.overview.dashIconSize); | ||||
|         return this.app.create_icon_texture(this.icon.iconSize); | ||||
|     }, | ||||
|  | ||||
|     // Returns the original actor that should align with the actor | ||||
| @@ -631,17 +491,11 @@ AppIconMenu.prototype = { | ||||
|     __proto__: PopupMenu.PopupMenu.prototype, | ||||
|  | ||||
|     _init: function(source) { | ||||
|         let side = St.Side.LEFT; | ||||
|         if (St.Widget.get_default_direction() == St.TextDirection.RTL) | ||||
|             side = St.Side.RIGHT; | ||||
|  | ||||
|         PopupMenu.PopupMenu.prototype._init.call(this, source.actor, 0.5, side); | ||||
|  | ||||
|         // We want to keep the item hovered while the menu is up | ||||
|         this.blockSourceEvents = true; | ||||
|         PopupMenu.PopupMenu.prototype._init.call(this, source.actor, St.Align.MIDDLE, St.Side.LEFT, 0); | ||||
|  | ||||
|         this._source = source; | ||||
|  | ||||
|         this.connect('active-changed', Lang.bind(this, this._onActiveChanged)); | ||||
|         this.connect('activate', Lang.bind(this, this._onActivate)); | ||||
|         this.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged)); | ||||
|  | ||||
| @@ -676,18 +530,19 @@ AppIconMenu.prototype = { | ||||
|             item._window = windows[i]; | ||||
|         } | ||||
|  | ||||
|         if (!this._source.app.is_window_backed()) { | ||||
|             if (windows.length > 0) | ||||
|                 this._appendSeparator(); | ||||
|  | ||||
|             let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id()); | ||||
|  | ||||
|             this._newWindowMenuItem = this._appendMenuItem(_("New Window")); | ||||
|         if (windows.length > 0) | ||||
|             this._appendSeparator(); | ||||
|  | ||||
|             this._toggleFavoriteMenuItem = this._appendMenuItem(isFavorite ? _("Remove from Favorites") | ||||
|                                                                 : _("Add to Favorites")); | ||||
|         } | ||||
|         let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id()); | ||||
|  | ||||
|         this._newWindowMenuItem = windows.length > 0 ? this._appendMenuItem(_("New Window")) : null; | ||||
|  | ||||
|         if (windows.length > 0) | ||||
|             this._appendSeparator(); | ||||
|         this._toggleFavoriteMenuItem = this._appendMenuItem(isFavorite ? _("Remove from Favorites") | ||||
|                                                                     : _("Add to Favorites")); | ||||
|  | ||||
|         this._highlightedItem = null; | ||||
|     }, | ||||
|  | ||||
|     _appendSeparator: function () { | ||||
| @@ -711,16 +566,74 @@ AppIconMenu.prototype = { | ||||
|         if (open) { | ||||
|             this.emit('popup', true); | ||||
|         } else { | ||||
|             this._updateHighlight(null); | ||||
|             this.emit('popup', false); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     // called by this._menuManager when it has the grab | ||||
|     menuEventFilter: function(event) { | ||||
|         let eventType = event.type(); | ||||
|  | ||||
|         // Check if the user is interacting with a window representation | ||||
|         // rather than interacting with the menu | ||||
|  | ||||
|         if (eventType == Clutter.EventType.BUTTON_RELEASE) { | ||||
|             let metaWindow = this._findMetaWindowForActor(event.get_source()); | ||||
|             if (metaWindow) | ||||
|                 this.emit('activate-window', metaWindow); | ||||
|         } else if (eventType == Clutter.EventType.ENTER) { | ||||
|             let metaWindow = this._findMetaWindowForActor(event.get_source()); | ||||
|             if (metaWindow) | ||||
|                 this._selectMenuItemForWindow(metaWindow, true); | ||||
|         } else if (eventType == Clutter.EventType.LEAVE) { | ||||
|             let metaWindow = this._findMetaWindowForActor(event.get_source()); | ||||
|             if (metaWindow) | ||||
|                 this._selectMenuItemForWindow(metaWindow, false); | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     }, | ||||
|  | ||||
|     _findMetaWindowForActor: function (actor) { | ||||
|         if (actor._delegate instanceof Workspace.WindowClone) | ||||
|             return actor._delegate.metaWindow; | ||||
|         else if (actor.get_meta_window) | ||||
|             return actor.get_meta_window(); | ||||
|         return null; | ||||
|     }, | ||||
|  | ||||
|     _updateHighlight: function (item) { | ||||
|         if (this._highlightedItem) | ||||
|             this.emit('highlight-window', null); | ||||
|         this._highlightedItem = item; | ||||
|         if (this._highlightedItem) { | ||||
|             let window = this._highlightedItem._window; | ||||
|             if (window) | ||||
|                 this.emit('highlight-window', window); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _selectMenuItemForWindow: function (metaWindow, selected) { | ||||
|         let items = this.getMenuItems(); | ||||
|         for (let i = 0; i < items.length; i++) { | ||||
|             let item = items[i]; | ||||
|             let menuMetaWindow = item._window; | ||||
|             if (menuMetaWindow == metaWindow) | ||||
|                 item.setActive(selected); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _onActiveChanged: function (menu, child) { | ||||
|         this._updateHighlight(child); | ||||
|     }, | ||||
|  | ||||
|     _onActivate: function (actor, child) { | ||||
|         if (child._window) { | ||||
|             let metaWindow = child._window; | ||||
|             this.emit('activate-window', metaWindow); | ||||
|         } else if (child == this._newWindowMenuItem) { | ||||
|             this._source.app.open_new_window(-1); | ||||
|             this._source.app.open_new_window(); | ||||
|             this.emit('activate-window', null); | ||||
|         } else if (child == this._toggleFavoriteMenuItem) { | ||||
|             let favs = AppFavorites.getAppFavorites(); | ||||
|   | ||||
| @@ -3,6 +3,8 @@ | ||||
| const Shell = imports.gi.Shell; | ||||
| const Lang = imports.lang; | ||||
| const Signals = imports.signals; | ||||
| const Gettext = imports.gettext.domain('gnome-shell'); | ||||
| const _ = Gettext.gettext; | ||||
|  | ||||
| const Main = imports.ui.main; | ||||
|  | ||||
| @@ -28,7 +30,7 @@ AppFavorites.prototype = { | ||||
|         let ids = global.settings.get_strv(this.FAVORITE_APPS_KEY); | ||||
|         let appSys = Shell.AppSystem.get_default(); | ||||
|         let apps = ids.map(function (id) { | ||||
|                 return appSys.lookup_app(id); | ||||
|                 return appSys.get_app(id); | ||||
|             }).filter(function (app) { | ||||
|                 return app != null; | ||||
|             }); | ||||
| @@ -65,7 +67,7 @@ AppFavorites.prototype = { | ||||
|         if (appId in this._favorites) | ||||
|             return false; | ||||
|  | ||||
|         let app = Shell.AppSystem.get_default().lookup_app(appId); | ||||
|         let app = Shell.AppSystem.get_default().get_app(appId); | ||||
|  | ||||
|         if (!app) | ||||
|             return false; | ||||
| @@ -84,9 +86,9 @@ AppFavorites.prototype = { | ||||
|         if (!this._addFavorite(appId, pos)) | ||||
|             return; | ||||
|  | ||||
|         let app = Shell.AppSystem.get_default().lookup_app(appId); | ||||
|         let app = Shell.AppSystem.get_default().get_app(appId); | ||||
|  | ||||
|         Main.overview.setMessage(_("%s has been added to your favorites.").format(app.get_name()), Lang.bind(this, function () { | ||||
|         Main.overview.shellInfo.setMessage(_("%s has been added to your favorites.").format(app.get_name()), Lang.bind(this, function () { | ||||
|             this._removeFavorite(appId); | ||||
|         })); | ||||
|     }, | ||||
| @@ -117,8 +119,8 @@ AppFavorites.prototype = { | ||||
|         if (!this._removeFavorite(appId)) | ||||
|             return; | ||||
|  | ||||
|         Main.overview.setMessage(_("%s has been removed from your favorites.").format(app.get_name()), | ||||
|                                  Lang.bind(this, function () { | ||||
|         Main.overview.shellInfo.setMessage(_("%s has been removed from your favorites.").format(app.get_name()), | ||||
|                                          Lang.bind(this, function () { | ||||
|             this._addFavorite(appId, pos); | ||||
|         })); | ||||
|     } | ||||
|   | ||||
| @@ -1,278 +0,0 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Lang = imports.lang; | ||||
| const DBus = imports.dbus; | ||||
| const Mainloop = imports.mainloop; | ||||
| const Gio = imports.gi.Gio; | ||||
| const Params = imports.misc.params; | ||||
|  | ||||
| const Main = imports.ui.main; | ||||
| const ShellMountOperation = imports.ui.shellMountOperation; | ||||
| const ScreenSaver = imports.misc.screenSaver; | ||||
|  | ||||
| // GSettings keys | ||||
| const SETTINGS_SCHEMA = 'org.gnome.desktop.media-handling'; | ||||
| const SETTING_ENABLE_AUTOMOUNT = 'automount'; | ||||
|  | ||||
| const AUTORUN_EXPIRE_TIMEOUT_SECS = 10; | ||||
|  | ||||
| const ConsoleKitSessionIface = { | ||||
|     name: 'org.freedesktop.ConsoleKit.Session', | ||||
|     methods: [{ name: 'IsActive', | ||||
|                 inSignature: '', | ||||
|                 outSignature: 'b' }], | ||||
|     signals: [{ name: 'ActiveChanged', | ||||
|                 inSignature: 'b' }] | ||||
| }; | ||||
|  | ||||
| const ConsoleKitSessionProxy = DBus.makeProxyClass(ConsoleKitSessionIface); | ||||
|  | ||||
| const ConsoleKitManagerIface = { | ||||
|     name: 'org.freedesktop.ConsoleKit.Manager', | ||||
|     methods: [{ name: 'GetCurrentSession', | ||||
|                 inSignature: '', | ||||
|                 outSignature: 'o' }] | ||||
| }; | ||||
|  | ||||
| function ConsoleKitManager() { | ||||
|     this._init(); | ||||
| }; | ||||
|  | ||||
| ConsoleKitManager.prototype = { | ||||
|     _init: function() { | ||||
|         this.sessionActive = true; | ||||
|  | ||||
|         DBus.system.proxifyObject(this, | ||||
|                                   'org.freedesktop.ConsoleKit', | ||||
|                                   '/org/freedesktop/ConsoleKit/Manager'); | ||||
|  | ||||
|         DBus.system.watch_name('org.freedesktop.ConsoleKit', | ||||
|                                false, // do not launch a name-owner if none exists | ||||
|                                Lang.bind(this, this._onManagerAppeared), | ||||
|                                Lang.bind(this, this._onManagerVanished)); | ||||
|     }, | ||||
|  | ||||
|     _onManagerAppeared: function(owner) { | ||||
|         this.GetCurrentSessionRemote(Lang.bind(this, this._onCurrentSession)); | ||||
|     }, | ||||
|  | ||||
|     _onManagerVanished: function(oldOwner) { | ||||
|         this.sessionActive = true; | ||||
|     }, | ||||
|  | ||||
|     _onCurrentSession: function(session) { | ||||
|         this._ckSession = new ConsoleKitSessionProxy(DBus.system, 'org.freedesktop.ConsoleKit', session); | ||||
|  | ||||
|         this._ckSession.connect | ||||
|             ('ActiveChanged', Lang.bind(this, function(object, isActive) { | ||||
|                 this.sessionActive = isActive;             | ||||
|             })); | ||||
|         this._ckSession.IsActiveRemote(Lang.bind(this, function(isActive) { | ||||
|             this.sessionActive = isActive;             | ||||
|         })); | ||||
|     } | ||||
| }; | ||||
| DBus.proxifyPrototype(ConsoleKitManager.prototype, ConsoleKitManagerIface); | ||||
|  | ||||
| function AutomountManager() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| AutomountManager.prototype = { | ||||
|     _init: function() { | ||||
|         this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA }); | ||||
|         this._volumeQueue = []; | ||||
|  | ||||
|         this.ckListener = new ConsoleKitManager(); | ||||
|  | ||||
|         this._ssProxy = new ScreenSaver.ScreenSaverProxy(); | ||||
|         this._ssProxy.connect('ActiveChanged', | ||||
|                               Lang.bind(this, | ||||
|                                         this._screenSaverActiveChanged)); | ||||
|  | ||||
|         this._volumeMonitor = Gio.VolumeMonitor.get(); | ||||
|  | ||||
|         this._volumeMonitor.connect('volume-added', | ||||
|                                     Lang.bind(this, | ||||
|                                               this._onVolumeAdded)); | ||||
|         this._volumeMonitor.connect('volume-removed', | ||||
|                                     Lang.bind(this, | ||||
|                                               this._onVolumeRemoved)); | ||||
|         this._volumeMonitor.connect('drive-connected', | ||||
|                                     Lang.bind(this, | ||||
|                                               this._onDriveConnected)); | ||||
|         this._volumeMonitor.connect('drive-disconnected', | ||||
|                                     Lang.bind(this, | ||||
|                                               this._onDriveDisconnected)); | ||||
|         this._volumeMonitor.connect('drive-eject-button', | ||||
|                                     Lang.bind(this, | ||||
|                                               this._onDriveEjectButton)); | ||||
|  | ||||
|         Mainloop.idle_add(Lang.bind(this, this._startupMountAll)); | ||||
|     }, | ||||
|  | ||||
|     _screenSaverActiveChanged: function(object, isActive) { | ||||
|         if (!isActive) { | ||||
|             this._volumeQueue.forEach(Lang.bind(this, function(volume) { | ||||
|                 this._checkAndMountVolume(volume); | ||||
|             })); | ||||
|         } | ||||
|  | ||||
|         // clear the queue anyway | ||||
|         this._volumeQueue = []; | ||||
|     }, | ||||
|  | ||||
|     _startupMountAll: function() { | ||||
|         let volumes = this._volumeMonitor.get_volumes(); | ||||
|         volumes.forEach(Lang.bind(this, function(volume) { | ||||
|             this._checkAndMountVolume(volume, { checkSession: false, | ||||
|                                                 useMountOp: false }); | ||||
|         })); | ||||
|  | ||||
|         return false; | ||||
|     }, | ||||
|  | ||||
|     _onDriveConnected: function() { | ||||
|         // if we're not in the current ConsoleKit session, | ||||
|         // or screensaver is active, don't play sounds | ||||
|         if (!this.ckListener.sessionActive) | ||||
|             return;         | ||||
|  | ||||
|         if (this._ssProxy.screenSaverActive) | ||||
|             return; | ||||
|  | ||||
|         global.play_theme_sound(0, 'device-added-media'); | ||||
|     }, | ||||
|  | ||||
|     _onDriveDisconnected: function() { | ||||
|         // if we're not in the current ConsoleKit session, | ||||
|         // or screensaver is active, don't play sounds | ||||
|         if (!this.ckListener.sessionActive) | ||||
|             return;         | ||||
|  | ||||
|         if (this._ssProxy.screenSaverActive) | ||||
|             return; | ||||
|  | ||||
|         global.play_theme_sound(0, 'device-removed-media');         | ||||
|     }, | ||||
|  | ||||
|     _onDriveEjectButton: function(monitor, drive) { | ||||
|         // TODO: this code path is not tested, as the GVfs volume monitor | ||||
|         // doesn't emit this signal just yet. | ||||
|         if (!this.ckListener.sessionActive) | ||||
|             return; | ||||
|  | ||||
|         // we force stop/eject in this case, so we don't have to pass a | ||||
|         // mount operation object | ||||
|         if (drive.can_stop()) { | ||||
|             drive.stop | ||||
|                 (Gio.MountUnmountFlags.FORCE, null, null, | ||||
|                  Lang.bind(this, function(drive, res) { | ||||
|                      try { | ||||
|                          drive.stop_finish(res); | ||||
|                      } catch (e) { | ||||
|                          log("Unable to stop the drive after drive-eject-button " + e.toString()); | ||||
|                      } | ||||
|                  })); | ||||
|         } else if (drive.can_eject()) { | ||||
|             drive.eject_with_operation  | ||||
|                 (Gio.MountUnmountFlags.FORCE, null, null, | ||||
|                  Lang.bind(this, function(drive, res) { | ||||
|                      try { | ||||
|                          drive.eject_with_operation_finish(res); | ||||
|                      } catch (e) { | ||||
|                          log("Unable to eject the drive after drive-eject-button " + e.toString()); | ||||
|                      } | ||||
|                  })); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _onVolumeAdded: function(monitor, volume) { | ||||
|         this._checkAndMountVolume(volume); | ||||
|     }, | ||||
|  | ||||
|     _checkAndMountVolume: function(volume, params) { | ||||
|         params = Params.parse(params, { checkSession: true, | ||||
|                                         useMountOp: true }); | ||||
|  | ||||
|         if (params.checkSession) { | ||||
|             // if we're not in the current ConsoleKit session, | ||||
|             // don't attempt automount | ||||
|             if (!this.ckListener.sessionActive) | ||||
|                 return; | ||||
|  | ||||
|             if (this._ssProxy.screenSaverActive) { | ||||
|                 if (this._volumeQueue.indexOf(volume) == -1) | ||||
|                     this._volumeQueue.push(volume); | ||||
|  | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (!this._settings.get_boolean(SETTING_ENABLE_AUTOMOUNT) || | ||||
|             !volume.should_automount() || | ||||
|             !volume.can_mount()) { | ||||
| 	    // allow the autorun to run anyway; this can happen if the | ||||
|             // mount gets added programmatically later, even if  | ||||
|             // should_automount() or can_mount() are false, like for | ||||
|             // blank optical media. | ||||
|             this._allowAutorun(volume); | ||||
|             this._allowAutorunExpire(volume); | ||||
|  | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (params.useMountOp) { | ||||
|             let operation = new ShellMountOperation.ShellMountOperation(volume); | ||||
|             this._mountVolume(volume, operation.mountOp); | ||||
|         } else { | ||||
|             this._mountVolume(volume, null); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _mountVolume: function(volume, operation) { | ||||
|         this._allowAutorun(volume); | ||||
|         volume.mount(0, operation, null, | ||||
|                      Lang.bind(this, this._onVolumeMounted)); | ||||
|     }, | ||||
|  | ||||
|     _onVolumeMounted: function(volume, res) { | ||||
|         this._allowAutorunExpire(volume); | ||||
|  | ||||
|         try { | ||||
|             volume.mount_finish(res); | ||||
|         } catch (e) { | ||||
|             let string = e.toString(); | ||||
|  | ||||
|             // FIXME: needs proper error code handling instead of this | ||||
|             // See https://bugzilla.gnome.org/show_bug.cgi?id=591480 | ||||
|             if (string.indexOf('No key available with this passphrase') != -1) | ||||
|                 this._reaskPassword(volume); | ||||
|             else | ||||
|                 log('Unable to mount volume ' + volume.get_name() + ': ' + string); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _onVolumeRemoved: function(monitor, volume) { | ||||
|         this._volumeQueue =  | ||||
|             this._volumeQueue.filter(function(element) { | ||||
|                 return (element != volume); | ||||
|             }); | ||||
|     }, | ||||
|  | ||||
|     _reaskPassword: function(volume) { | ||||
|         let operation = new ShellMountOperation.ShellMountOperation(volume, { reaskPassword: true }); | ||||
|         this._mountVolume(volume, operation.mountOp);         | ||||
|     }, | ||||
|  | ||||
|     _allowAutorun: function(volume) { | ||||
|         volume.allowAutorun = true; | ||||
|     }, | ||||
|  | ||||
|     _allowAutorunExpire: function(volume) { | ||||
|         Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, function() { | ||||
|             volume.allowAutorun = false; | ||||
|             return false; | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| @@ -1,635 +0,0 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Lang = imports.lang; | ||||
| const DBus = imports.dbus; | ||||
| const Gio = imports.gi.Gio; | ||||
| const St = imports.gi.St; | ||||
|  | ||||
| const Main = imports.ui.main; | ||||
| const MessageTray = imports.ui.messageTray; | ||||
| const ShellMountOperation = imports.ui.shellMountOperation; | ||||
|  | ||||
| // GSettings keys | ||||
| const SETTINGS_SCHEMA = 'org.gnome.desktop.media-handling'; | ||||
| const SETTING_DISABLE_AUTORUN = 'autorun-never'; | ||||
| const SETTING_START_APP = 'autorun-x-content-start-app'; | ||||
| const SETTING_IGNORE = 'autorun-x-content-ignore'; | ||||
| const SETTING_OPEN_FOLDER = 'autorun-x-content-open-folder'; | ||||
|  | ||||
| const AutorunSetting = { | ||||
|     RUN: 0, | ||||
|     IGNORE: 1, | ||||
|     FILES: 2, | ||||
|     ASK: 3 | ||||
| }; | ||||
|  | ||||
| const HOTPLUG_ICON_SIZE = 16; | ||||
|  | ||||
| // misc utils | ||||
| function ignoreAutorunForMount(mount) { | ||||
|     let root = mount.get_root(); | ||||
|     let volume = mount.get_volume(); | ||||
|  | ||||
|     if ((root.is_native() && !isMountRootHidden(root)) || | ||||
|         (volume && volume.allowAutorun && volume.should_automount())) | ||||
|         return false; | ||||
|  | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| function isMountRootHidden(root) { | ||||
|     let path = root.get_path(); | ||||
|  | ||||
|     // skip any mounts in hidden directory hierarchies | ||||
|     return (path.indexOf('/.') != -1); | ||||
| } | ||||
|  | ||||
| function startAppForMount(app, mount) { | ||||
|     let files = []; | ||||
|     let root = mount.get_root(); | ||||
|     let retval = false; | ||||
|  | ||||
|     files.push(root); | ||||
|  | ||||
|     try { | ||||
|         retval = app.launch(files,  | ||||
|                             global.create_app_launch_context()) | ||||
|     } catch (e) { | ||||
|         log('Unable to launch the application ' + app.get_name() | ||||
|             + ': ' + e.toString()); | ||||
|     } | ||||
|  | ||||
|     return retval; | ||||
| } | ||||
|  | ||||
| /******************************************/ | ||||
|  | ||||
| const HotplugSnifferIface = { | ||||
|     name: 'org.gnome.Shell.HotplugSniffer', | ||||
|     methods: [{ name: 'SniffURI', | ||||
|                 inSignature: 's', | ||||
|                 outSignature: 'as' }] | ||||
| }; | ||||
|  | ||||
| const HotplugSniffer = function() { | ||||
|     this._init(); | ||||
| }; | ||||
|  | ||||
| HotplugSniffer.prototype = { | ||||
|     _init: function() { | ||||
|         DBus.session.proxifyObject(this, | ||||
|                                    'org.gnome.Shell.HotplugSniffer', | ||||
|                                    '/org/gnome/Shell/HotplugSniffer'); | ||||
|     }, | ||||
| }; | ||||
| DBus.proxifyPrototype(HotplugSniffer.prototype, HotplugSnifferIface); | ||||
|  | ||||
| function ContentTypeDiscoverer(callback) { | ||||
|     this._init(callback); | ||||
| } | ||||
|  | ||||
| ContentTypeDiscoverer.prototype = { | ||||
|     _init: function(callback) { | ||||
|         this._callback = callback; | ||||
|     }, | ||||
|  | ||||
|     guessContentTypes: function(mount) { | ||||
|         // guess mount's content types using GIO | ||||
|         mount.guess_content_type(false, null, | ||||
|                                  Lang.bind(this, | ||||
|                                            this._onContentTypeGuessed)); | ||||
|     }, | ||||
|  | ||||
|     _onContentTypeGuessed: function(mount, res) { | ||||
|         let contentTypes = []; | ||||
|  | ||||
|         try { | ||||
|             contentTypes = mount.guess_content_type_finish(res); | ||||
|         } catch (e) { | ||||
|             log('Unable to guess content types on added mount ' + mount.get_name() | ||||
|                 + ': ' + e.toString()); | ||||
|         } | ||||
|  | ||||
|         if (contentTypes.length) { | ||||
|             this._emitCallback(mount, contentTypes); | ||||
|         } else { | ||||
|             let root = mount.get_root(); | ||||
|  | ||||
|             let hotplugSniffer = new HotplugSniffer(); | ||||
|             hotplugSniffer.SniffURIRemote | ||||
|                 (root.get_uri(), DBus.CALL_FLAG_START, | ||||
|                  Lang.bind(this, function(contentTypes) { | ||||
|                      this._emitCallback(mount, contentTypes); | ||||
|                  })); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _emitCallback: function(mount, contentTypes) { | ||||
|         if (!contentTypes) | ||||
|             contentTypes = []; | ||||
|  | ||||
|         // we're not interested in win32 software content types here | ||||
|         contentTypes = contentTypes.filter(function(type) { | ||||
|             return (type != 'x-content/win32-software'); | ||||
|         }); | ||||
|  | ||||
|         let apps = []; | ||||
|         contentTypes.forEach(function(type) { | ||||
|             let app = Gio.app_info_get_default_for_type(type, false); | ||||
|  | ||||
|             if (app) | ||||
|                 apps.push(app); | ||||
|         }); | ||||
|  | ||||
|         if (apps.length == 0) | ||||
|             apps.push(Gio.app_info_get_default_for_type('inode/directory', false)); | ||||
|  | ||||
|         this._callback(mount, apps, contentTypes); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function AutorunManager() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| AutorunManager.prototype = { | ||||
|     _init: function() { | ||||
|         this._volumeMonitor = Gio.VolumeMonitor.get(); | ||||
|  | ||||
|         this._volumeMonitor.connect('mount-added', | ||||
|                                     Lang.bind(this, | ||||
|                                               this._onMountAdded)); | ||||
|         this._volumeMonitor.connect('mount-removed', | ||||
|                                     Lang.bind(this, | ||||
|                                               this._onMountRemoved)); | ||||
|  | ||||
|         this._transDispatcher = new AutorunTransientDispatcher(); | ||||
|         this._createResidentSource(); | ||||
|  | ||||
|         let mounts = this._volumeMonitor.get_mounts(); | ||||
|  | ||||
|         mounts.forEach(Lang.bind(this, function (mount) { | ||||
|             let discoverer = new ContentTypeDiscoverer(Lang.bind (this,  | ||||
|                 function (mount, apps) { | ||||
|                     this._residentSource.addMount(mount, apps); | ||||
|                 })); | ||||
|  | ||||
|             discoverer.guessContentTypes(mount); | ||||
|         })); | ||||
|     }, | ||||
|  | ||||
|     _createResidentSource: function() { | ||||
|         this._residentSource = new AutorunResidentSource(); | ||||
|         this._residentSource.connect('destroy', | ||||
|                                      Lang.bind(this, | ||||
|                                                this._createResidentSource)); | ||||
|     }, | ||||
|  | ||||
|     _onMountAdded: function(monitor, mount) { | ||||
|         // don't do anything if our session is not the currently | ||||
|         // active one | ||||
|         if (!Main.automountManager.ckListener.sessionActive) | ||||
|             return; | ||||
|  | ||||
|         let discoverer = new ContentTypeDiscoverer(Lang.bind (this, | ||||
|             function (mount, apps, contentTypes) { | ||||
|                 this._transDispatcher.addMount(mount, apps, contentTypes); | ||||
|                 this._residentSource.addMount(mount, apps); | ||||
|             })); | ||||
|  | ||||
|         discoverer.guessContentTypes(mount); | ||||
|     }, | ||||
|  | ||||
|     _onMountRemoved: function(monitor, mount) { | ||||
|         this._transDispatcher.removeMount(mount); | ||||
|         this._residentSource.removeMount(mount); | ||||
|     }, | ||||
|  | ||||
|     ejectMount: function(mount) { | ||||
|         let mountOp = new ShellMountOperation.ShellMountOperation(mount); | ||||
|  | ||||
|         // first, see if we have a drive | ||||
|         let drive = mount.get_drive(); | ||||
|         let volume = mount.get_volume(); | ||||
|  | ||||
|         if (drive && | ||||
|             drive.get_start_stop_type() == Gio.DriveStartStopType.SHUTDOWN && | ||||
|             drive.can_stop()) { | ||||
|             drive.stop(0, mountOp.mountOp, null, | ||||
|                        Lang.bind(this, this._onStop)); | ||||
|         } else { | ||||
|             if (mount.can_eject()) { | ||||
|                 mount.eject_with_operation(0, mountOp.mountOp, null, | ||||
|                                            Lang.bind(this, this._onEject)); | ||||
|             } else if (volume && volume.can_eject()) { | ||||
|                 volume.eject_with_operation(0, mountOp.mountOp, null, | ||||
|                                             Lang.bind(this, this._onEject)); | ||||
|             } else if (drive && drive.can_eject()) { | ||||
|                 drive.eject_with_operation(0, mountOp.mountOp, null, | ||||
|                                            Lang.bind(this, this._onEject)); | ||||
|             } else if (mount.can_unmount()) { | ||||
|                 mount.unmount_with_operation(0, mountOp.mountOp, null, | ||||
|                                              Lang.bind(this, this._onUnmount)); | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _onUnmount: function(mount, res) { | ||||
|         try { | ||||
|             mount.unmount_with_operation_finish(res); | ||||
|         } catch (e) { | ||||
|             // FIXME: we need to ignore G_IO_ERROR_FAILED_HANDLED errors here | ||||
|             // but we can't access the error code from JS. | ||||
|             // See https://bugzilla.gnome.org/show_bug.cgi?id=591480 | ||||
|             log('Unable to eject the mount ' + mount.get_name()  | ||||
|                 + ': ' + e.toString()); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _onEject: function(source, res) { | ||||
|         try { | ||||
|             source.eject_with_operation_finish(res); | ||||
|         } catch (e) { | ||||
|             // FIXME: we need to ignore G_IO_ERROR_FAILED_HANDLED errors here | ||||
|             // but we can't access the error code from JS. | ||||
|             // See https://bugzilla.gnome.org/show_bug.cgi?id=591480 | ||||
|             log('Unable to eject the drive ' + source.get_name()  | ||||
|                 + ': ' + e.toString()); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _onStop: function(drive, res) { | ||||
|         try { | ||||
|             drive.stop_finish(res); | ||||
|         } catch (e) { | ||||
|             // FIXME: we need to ignore G_IO_ERROR_FAILED_HANDLED errors here | ||||
|             // but we can't access the error code from JS. | ||||
|             // See https://bugzilla.gnome.org/show_bug.cgi?id=591480 | ||||
|             log('Unable to stop the drive ' + drive.get_name()  | ||||
|                 + ': ' + e.toString()); | ||||
|         } | ||||
|     }, | ||||
| } | ||||
|  | ||||
| function AutorunResidentSource() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| AutorunResidentSource.prototype = { | ||||
|     __proto__: MessageTray.Source.prototype, | ||||
|  | ||||
|     _init: function() { | ||||
|         MessageTray.Source.prototype._init.call(this, _('Removable Devices')); | ||||
|  | ||||
|         this._mounts = []; | ||||
|  | ||||
|         this._notification = new AutorunResidentNotification(this); | ||||
|         this._setSummaryIcon(this.createNotificationIcon(HOTPLUG_ICON_SIZE)); | ||||
|     }, | ||||
|  | ||||
|     addMount: function(mount, apps) { | ||||
|         if (ignoreAutorunForMount(mount)) | ||||
|             return; | ||||
|  | ||||
|         let filtered = this._mounts.filter(function (element) { | ||||
|             return (element.mount == mount); | ||||
|         }); | ||||
|  | ||||
|         if (filtered.length != 0) | ||||
|             return; | ||||
|  | ||||
|         let element = { mount: mount, apps: apps }; | ||||
|         this._mounts.push(element); | ||||
|         this._redisplay(); | ||||
|     }, | ||||
|  | ||||
|     removeMount: function(mount) { | ||||
|         this._mounts = | ||||
|             this._mounts.filter(function (element) { | ||||
|                 return (element.mount != mount); | ||||
|             }); | ||||
|  | ||||
|         this._redisplay(); | ||||
|     }, | ||||
|  | ||||
|     _redisplay: function() { | ||||
|         if (this._mounts.length == 0) { | ||||
|             this._notification.destroy(); | ||||
|             this.destroy(); | ||||
|  | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         this._notification.updateForMounts(this._mounts); | ||||
|  | ||||
|         // add ourselves as a source, and push the notification | ||||
|         if (!Main.messageTray.contains(this)) { | ||||
|             Main.messageTray.add(this); | ||||
|             this.pushNotification(this._notification); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     createNotificationIcon: function(iconSize) { | ||||
|         return new St.Icon ({ icon_name: 'media-removable', | ||||
|                               icon_type: St.IconType.FULLCOLOR, | ||||
|                               icon_size: iconSize ? iconSize : this.ICON_SIZE }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function AutorunResidentNotification(source) { | ||||
|     this._init(source); | ||||
| } | ||||
|  | ||||
| AutorunResidentNotification.prototype = { | ||||
|     __proto__: MessageTray.Notification.prototype, | ||||
|  | ||||
|     _init: function(source) { | ||||
|         MessageTray.Notification.prototype._init.call(this, source, | ||||
|                                                       source.title, null, | ||||
|                                                       { customContent: true }); | ||||
|  | ||||
|         // set the notification as resident | ||||
|         this.setResident(true); | ||||
|  | ||||
|         this._layout = new St.BoxLayout ({ style_class: 'hotplug-resident-box', | ||||
|                                            vertical: true }); | ||||
|  | ||||
|         this.addActor(this._layout, | ||||
|                       { x_expand: true, | ||||
|                         x_fill: true }); | ||||
|     }, | ||||
|  | ||||
|     updateForMounts: function(mounts) { | ||||
|         // remove all the layout content | ||||
|         this._layout.destroy_children(); | ||||
|  | ||||
|         for (let idx = 0; idx < mounts.length; idx++) { | ||||
|             let element = mounts[idx]; | ||||
|  | ||||
|             let actor = this._itemForMount(element.mount, element.apps); | ||||
|             this._layout.add(actor, { x_fill: true, | ||||
|                                       expand: true }); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _itemForMount: function(mount, apps) { | ||||
|         let item = new St.BoxLayout(); | ||||
|  | ||||
|         // prepare the mount button content | ||||
|         let mountLayout = new St.BoxLayout(); | ||||
|  | ||||
|         let mountIcon = new St.Icon({ gicon: mount.get_icon(), | ||||
|                                       style_class: 'hotplug-resident-mount-icon' }); | ||||
|         mountLayout.add_actor(mountIcon); | ||||
|  | ||||
|         let labelBin = new St.Bin({ y_align: St.Align.MIDDLE }); | ||||
|         let mountLabel = | ||||
|             new St.Label({ text: mount.get_name(), | ||||
|                            style_class: 'hotplug-resident-mount-label', | ||||
|                            track_hover: true, | ||||
|                            reactive: true }); | ||||
|         labelBin.add_actor(mountLabel); | ||||
|         mountLayout.add_actor(labelBin); | ||||
|  | ||||
|         let mountButton = new St.Button({ child: mountLayout, | ||||
|                                           x_align: St.Align.START, | ||||
|                                           x_fill: true, | ||||
|                                           style_class: 'hotplug-resident-mount', | ||||
|                                           button_mask: St.ButtonMask.ONE }); | ||||
|         item.add(mountButton, { x_align: St.Align.START, | ||||
|                                 expand: true }); | ||||
|  | ||||
|         let ejectIcon =  | ||||
|             new St.Icon({ icon_name: 'media-eject', | ||||
|                           style_class: 'hotplug-resident-eject-icon' }); | ||||
|  | ||||
|         let ejectButton = | ||||
|             new St.Button({ style_class: 'hotplug-resident-eject-button', | ||||
|                             button_mask: St.ButtonMask.ONE, | ||||
|                             child: ejectIcon }); | ||||
|         item.add(ejectButton, { x_align: St.Align.END }); | ||||
|  | ||||
|         // now connect signals | ||||
|         mountButton.connect('clicked', Lang.bind(this, function(actor, event) { | ||||
|             startAppForMount(apps[0], mount); | ||||
|         })); | ||||
|  | ||||
|         ejectButton.connect('clicked', Lang.bind(this, function() { | ||||
|             Main.autorunManager.ejectMount(mount); | ||||
|         })); | ||||
|  | ||||
|         return item; | ||||
|     }, | ||||
| } | ||||
|  | ||||
| function AutorunTransientDispatcher() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| AutorunTransientDispatcher.prototype = { | ||||
|     _init: function() { | ||||
|         this._sources = []; | ||||
|         this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA }); | ||||
|     }, | ||||
|  | ||||
|     _getAutorunSettingForType: function(contentType) { | ||||
|         let runApp = this._settings.get_strv(SETTING_START_APP); | ||||
|         if (runApp.indexOf(contentType) != -1) | ||||
|             return AutorunSetting.RUN; | ||||
|  | ||||
|         let ignore = this._settings.get_strv(SETTING_IGNORE); | ||||
|         if (ignore.indexOf(contentType) != -1) | ||||
|             return AutorunSetting.IGNORE; | ||||
|  | ||||
|         let openFiles = this._settings.get_strv(SETTING_OPEN_FOLDER); | ||||
|         if (openFiles.indexOf(contentType) != -1) | ||||
|             return AutorunSetting.FILES; | ||||
|  | ||||
|         return AutorunSetting.ASK; | ||||
|     }, | ||||
|  | ||||
|     _getSourceForMount: function(mount) { | ||||
|         let filtered = | ||||
|             this._sources.filter(function (source) { | ||||
|                 return (source.mount == mount); | ||||
|             }); | ||||
|  | ||||
|         // we always make sure not to add two sources for the same | ||||
|         // mount in addMount(), so it's safe to assume filtered.length | ||||
|         // is always either 1 or 0. | ||||
|         if (filtered.length == 1) | ||||
|             return filtered[0]; | ||||
|  | ||||
|         return null; | ||||
|     }, | ||||
|  | ||||
|     _addSource: function(mount, apps) { | ||||
|         // if we already have a source showing for this  | ||||
|         // mount, return | ||||
|         if (this._getSourceForMount(mount)) | ||||
|             return; | ||||
|       | ||||
|         // add a new source | ||||
|         this._sources.push(new AutorunTransientSource(mount, apps)); | ||||
|     }, | ||||
|  | ||||
|     addMount: function(mount, apps, contentTypes) { | ||||
|         // if autorun is disabled globally, return | ||||
|         if (this._settings.get_boolean(SETTING_DISABLE_AUTORUN)) | ||||
|             return; | ||||
|  | ||||
|         // if the mount doesn't want to be autorun, return | ||||
|         if (ignoreAutorunForMount(mount)) | ||||
|             return; | ||||
|  | ||||
|         let setting = this._getAutorunSettingForType(contentTypes[0]); | ||||
|  | ||||
|         // check at the settings for the first content type | ||||
|         // to see whether we should ask | ||||
|         if (setting == AutorunSetting.IGNORE) | ||||
|             return; // return right away | ||||
|  | ||||
|         let success = false; | ||||
|         let app = null; | ||||
|  | ||||
|         if (setting == AutorunSetting.RUN) { | ||||
|             app = Gio.app_info_get_default_for_type(type, false); | ||||
|         } else if (setting == AutorunSetting.FILES) { | ||||
|             app = Gio.app_info_get_default_for_type('inode/directory', false); | ||||
|         } | ||||
|  | ||||
|         if (app) | ||||
|             success = startAppForMount(app, mount); | ||||
|  | ||||
|         // we fallback here also in case the settings did not specify 'ask', | ||||
|         // but we failed launching the default app or the default file manager | ||||
|         if (!success) | ||||
|             this._addSource(mount, apps); | ||||
|     }, | ||||
|  | ||||
|     removeMount: function(mount) { | ||||
|         let source = this._getSourceForMount(mount); | ||||
|          | ||||
|         // if we aren't tracking this mount, don't do anything | ||||
|         if (!source) | ||||
|             return; | ||||
|  | ||||
|         // destroy the notification source | ||||
|         source.destroy(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function AutorunTransientSource(mount, apps) { | ||||
|     this._init(mount, apps); | ||||
| } | ||||
|  | ||||
| AutorunTransientSource.prototype = { | ||||
|     __proto__: MessageTray.Source.prototype, | ||||
|  | ||||
|     _init: function(mount, apps) { | ||||
|         MessageTray.Source.prototype._init.call(this, mount.get_name()); | ||||
|  | ||||
|         this.mount = mount; | ||||
|         this.apps = apps; | ||||
|  | ||||
|         this._notification = new AutorunTransientNotification(this); | ||||
|         this._setSummaryIcon(this.createNotificationIcon(this.ICON_SIZE)); | ||||
|  | ||||
|         // add ourselves as a source, and popup the notification | ||||
|         Main.messageTray.add(this); | ||||
|         this.notify(this._notification); | ||||
|     }, | ||||
|  | ||||
|     createNotificationIcon: function(iconSize) { | ||||
|         return new St.Icon({ gicon: this.mount.get_icon(), | ||||
|                              icon_size: iconSize ? iconSize : this.ICON_SIZE }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function AutorunTransientNotification(source) { | ||||
|     this._init(source); | ||||
| } | ||||
|  | ||||
| AutorunTransientNotification.prototype = { | ||||
|     __proto__: MessageTray.Notification.prototype, | ||||
|  | ||||
|     _init: function(source) { | ||||
|         MessageTray.Notification.prototype._init.call(this, source, | ||||
|                                                       source.title, null, | ||||
|                                                       { customContent: true }); | ||||
|  | ||||
|         this._box = new St.BoxLayout({ style_class: 'hotplug-transient-box', | ||||
|                                        vertical: true }); | ||||
|         this.addActor(this._box); | ||||
|  | ||||
|         this._mount = source.mount; | ||||
|  | ||||
|         source.apps.forEach(Lang.bind(this, function (app) { | ||||
|             let actor = this._buttonForApp(app); | ||||
|  | ||||
|             if (actor) | ||||
|                 this._box.add(actor, { x_fill: true, | ||||
|                                        x_align: St.Align.START }); | ||||
|         })); | ||||
|  | ||||
|         this._box.add(this._buttonForEject(), { x_fill: true, | ||||
|                                                 x_align: St.Align.START }); | ||||
|  | ||||
|         // set the notification to transient and urgent, so that it | ||||
|         // expands out | ||||
|         this.setTransient(true); | ||||
|         this.setUrgency(MessageTray.Urgency.CRITICAL); | ||||
|     }, | ||||
|  | ||||
|     _buttonForApp: function(app) { | ||||
|         let box = new St.BoxLayout(); | ||||
|         let icon = new St.Icon({ gicon: app.get_icon(), | ||||
|                                  style_class: 'hotplug-notification-item-icon' }); | ||||
|         box.add(icon); | ||||
|  | ||||
|         let label = new St.Bin({ y_align: St.Align.MIDDLE, | ||||
|                                  child: new St.Label | ||||
|                                  ({ text: _("Open with %s").format(app.get_display_name()) }) | ||||
|                                }); | ||||
|         box.add(label); | ||||
|  | ||||
|         let button = new St.Button({ child: box, | ||||
|                                      x_fill: true, | ||||
|                                      x_align: St.Align.START, | ||||
|                                      button_mask: St.ButtonMask.ONE, | ||||
|                                      style_class: 'hotplug-notification-item' }); | ||||
|  | ||||
|         button.connect('clicked', Lang.bind(this, function() { | ||||
|             startAppForMount(app, this._mount); | ||||
|             this.destroy(); | ||||
|         })); | ||||
|  | ||||
|         return button; | ||||
|     }, | ||||
|  | ||||
|     _buttonForEject: function() { | ||||
|         let box = new St.BoxLayout(); | ||||
|         let icon = new St.Icon({ icon_name: 'media-eject', | ||||
|                                  style_class: 'hotplug-notification-item-icon' }); | ||||
|         box.add(icon); | ||||
|  | ||||
|         let label = new St.Bin({ y_align: St.Align.MIDDLE, | ||||
|                                  child: new St.Label | ||||
|                                  ({ text: _("Eject") }) | ||||
|                                }); | ||||
|         box.add(label); | ||||
|  | ||||
|         let button = new St.Button({ child: box, | ||||
|                                      x_fill: true, | ||||
|                                      x_align: St.Align.START, | ||||
|                                      button_mask: St.ButtonMask.ONE, | ||||
|                                      style_class: 'hotplug-notification-item' }); | ||||
|  | ||||
|         button.connect('clicked', Lang.bind(this, function() { | ||||
|             Main.autorunManager.ejectMount(this._mount); | ||||
|         })); | ||||
|  | ||||
|         return button; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -2,18 +2,16 @@ | ||||
|  | ||||
| const Clutter = imports.gi.Clutter; | ||||
| const Lang = imports.lang; | ||||
| const Meta = imports.gi.Meta; | ||||
| const St = imports.gi.St; | ||||
| const Shell = imports.gi.Shell; | ||||
|  | ||||
| const Main = imports.ui.main; | ||||
| const Tweener = imports.ui.tweener; | ||||
|  | ||||
| const POPUP_ANIMATION_TIME = 0.15; | ||||
|  | ||||
| /** | ||||
|  * BoxPointer: | ||||
|  * @side: side to draw the arrow on | ||||
|  * @side: A St.Side type; currently only St.Side.TOP is implemented | ||||
|  * @binProperties: Properties to set on contained bin | ||||
|  * | ||||
|  * An actor which displays a triangle "arrow" pointing to a given | ||||
| @@ -42,80 +40,76 @@ BoxPointer.prototype = { | ||||
|         this._border.connect('repaint', Lang.bind(this, this._drawBorder)); | ||||
|         this._container.add_actor(this._border); | ||||
|         this.bin.raise(this._border); | ||||
|         this._xOffset = 0; | ||||
|         this._yOffset = 0; | ||||
|         this._xPosition = 0; | ||||
|         this._yPosition = 0; | ||||
|     }, | ||||
|  | ||||
|     show: function(animate, onComplete) { | ||||
|     animateAppear: function(onComplete) { | ||||
|         let x = this.actor.x; | ||||
|         let y = this.actor.y; | ||||
|         let themeNode = this.actor.get_theme_node(); | ||||
|         let rise = themeNode.get_length('-arrow-rise'); | ||||
|  | ||||
|         this.opacity = 0; | ||||
|         this.actor.opacity = 0; | ||||
|         this.actor.show(); | ||||
|  | ||||
|         if (animate) { | ||||
|             switch (this._arrowSide) { | ||||
|                 case St.Side.TOP: | ||||
|                     this.yOffset = -rise; | ||||
|                     break; | ||||
|                 case St.Side.BOTTOM: | ||||
|                     this.yOffset = rise; | ||||
|                     break; | ||||
|                 case St.Side.LEFT: | ||||
|                     this.xOffset = -rise; | ||||
|                     break; | ||||
|                 case St.Side.RIGHT: | ||||
|                     this.xOffset = rise; | ||||
|                     break; | ||||
|             } | ||||
|         switch (this._arrowSide) { | ||||
|             case St.Side.TOP: | ||||
|                 this.actor.y -= rise; | ||||
|                 break; | ||||
|             case St.Side.BOTTOM: | ||||
|                 this.actor.y += rise; | ||||
|                 break; | ||||
|             case St.Side.LEFT: | ||||
|                 this.actor.x -= rise; | ||||
|                 break; | ||||
|             case St.Side.RIGHT: | ||||
|                 this.actor.x += rise; | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         Tweener.addTween(this, { opacity: 255, | ||||
|                                  xOffset: 0, | ||||
|                                  yOffset: 0, | ||||
|                                  transition: "linear", | ||||
|                                  onComplete: onComplete, | ||||
|                                  time: POPUP_ANIMATION_TIME }); | ||||
|         Tweener.addTween(this.actor, { opacity: 255, | ||||
|                                        x: x, | ||||
|                                        y: y, | ||||
|                                        transition: "linear", | ||||
|                                        onComplete: onComplete, | ||||
|                                        time: POPUP_ANIMATION_TIME }); | ||||
|     }, | ||||
|  | ||||
|     hide: function(animate, onComplete) { | ||||
|         let xOffset = 0; | ||||
|         let yOffset = 0; | ||||
|     animateDisappear: function(onComplete) { | ||||
|         let x = this.actor.x; | ||||
|         let y = this.actor.y; | ||||
|         let originalX = this.actor.x; | ||||
|         let originalY = this.actor.y; | ||||
|         let themeNode = this.actor.get_theme_node(); | ||||
|         let rise = themeNode.get_length('-arrow-rise'); | ||||
|  | ||||
|         if (animate) { | ||||
|             switch (this._arrowSide) { | ||||
|                 case St.Side.TOP: | ||||
|                     yOffset = rise; | ||||
|                     break; | ||||
|                 case St.Side.BOTTOM: | ||||
|                     yOffset = -rise; | ||||
|                     break; | ||||
|                 case St.Side.LEFT: | ||||
|                     xOffset = rise; | ||||
|                     break; | ||||
|                 case St.Side.RIGHT: | ||||
|                     xOffset = -rise; | ||||
|                     break; | ||||
|             } | ||||
|         switch (this._arrowSide) { | ||||
|             case St.Side.TOP: | ||||
|                 y += rise; | ||||
|                 break; | ||||
|             case St.Side.BOTTOM: | ||||
|                 y -= rise; | ||||
|                 break; | ||||
|             case St.Side.LEFT: | ||||
|                 x += rise; | ||||
|                 break; | ||||
|             case St.Side.RIGHT: | ||||
|                 x -= rise; | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         Tweener.addTween(this, { opacity: 0, | ||||
|                                  xOffset: xOffset, | ||||
|                                  yOffset: yOffset, | ||||
|                                  transition: "linear", | ||||
|                                  time: POPUP_ANIMATION_TIME, | ||||
|                                  onComplete: Lang.bind(this, function () { | ||||
|                                      this.actor.hide(); | ||||
|                                      this.xOffset = 0; | ||||
|                                      this.yOffset = 0; | ||||
|                                      if (onComplete) | ||||
|                                          onComplete(); | ||||
|                                  }) | ||||
|                                }); | ||||
|         Tweener.addTween(this.actor, { opacity: 0, | ||||
|                                        x: x, | ||||
|                                        y: y, | ||||
|                                        transition: "linear", | ||||
|                                        time: POPUP_ANIMATION_TIME, | ||||
|                                        onComplete: Lang.bind(this, function () { | ||||
|                                            this.actor.hide(); | ||||
|                                            this.actor.x = originalX; | ||||
|                                            this.actor.y = originalY; | ||||
|                                            if (onComplete) | ||||
|                                                onComplete(); | ||||
|                                        }) | ||||
|                                      }); | ||||
|     }, | ||||
|  | ||||
|     _adjustAllocationForArrow: function(isWidth, alloc) { | ||||
| @@ -178,9 +172,6 @@ BoxPointer.prototype = { | ||||
|                 break; | ||||
|         } | ||||
|         this.bin.allocate(childBox, flags); | ||||
|  | ||||
|         if (this._sourceActor && this._sourceActor.mapped) | ||||
|             this._reposition(this._sourceActor, this._alignment); | ||||
|     }, | ||||
|  | ||||
|     _drawBorder: function(area) { | ||||
| @@ -194,8 +185,10 @@ BoxPointer.prototype = { | ||||
|         let halfBorder = borderWidth / 2; | ||||
|         let halfBase = Math.floor(base/2); | ||||
|  | ||||
|         let borderColor = themeNode.get_color('-arrow-border-color'); | ||||
|         let backgroundColor = themeNode.get_color('-arrow-background-color'); | ||||
|         let borderColor = new Clutter.Color(); | ||||
|         themeNode.get_color('-arrow-border-color', borderColor); | ||||
|         let backgroundColor = new Clutter.Color(); | ||||
|         themeNode.get_color('-arrow-background-color', backgroundColor); | ||||
|  | ||||
|         let [width, height] = area.get_surface_size(); | ||||
|         let [boxWidth, boxHeight] = [width, height]; | ||||
| @@ -215,88 +208,46 @@ BoxPointer.prototype = { | ||||
|             cr.translate(rise, 0); | ||||
|         } | ||||
|  | ||||
|         let [x1, y1] = [halfBorder, halfBorder]; | ||||
|         let [x2, y2] = [boxWidth - halfBorder, boxHeight - halfBorder]; | ||||
|         cr.moveTo(borderRadius, halfBorder); | ||||
|  | ||||
|         cr.moveTo(x1 + borderRadius, y1); | ||||
|         if (this._arrowSide == St.Side.TOP) { | ||||
|             if (this._arrowOrigin < (x1 + (borderRadius + halfBase))) { | ||||
|                 cr.lineTo(this._arrowOrigin, y1 - rise); | ||||
|                 cr.lineTo(Math.max(x1 + borderRadius, this._arrowOrigin) + halfBase, y1); | ||||
|             } else if (this._arrowOrigin > (x2 - (borderRadius + halfBase))) { | ||||
|                 cr.lineTo(Math.min(x2 - borderRadius, this._arrowOrigin) - halfBase, y1); | ||||
|                 cr.lineTo(this._arrowOrigin, y1 - rise); | ||||
|             } else { | ||||
|                 cr.lineTo(this._arrowOrigin - halfBase, y1); | ||||
|                 cr.lineTo(this._arrowOrigin, y1 - rise); | ||||
|                 cr.lineTo(this._arrowOrigin + halfBase, y1); | ||||
|             } | ||||
|             cr.lineTo(this._arrowOrigin - halfBase, halfBorder); | ||||
|             cr.lineTo(this._arrowOrigin, halfBorder - rise); | ||||
|             cr.lineTo(this._arrowOrigin + halfBase, halfBorder); | ||||
|         } | ||||
|         cr.lineTo(boxWidth - borderRadius, halfBorder); | ||||
|  | ||||
|         cr.lineTo(x2 - borderRadius, y1); | ||||
|  | ||||
|         // top-right corner | ||||
|         cr.arc(x2 - borderRadius, y1 + borderRadius, borderRadius, | ||||
|         cr.arc(boxWidth - borderRadius - halfBorder, borderRadius + halfBorder, borderRadius, | ||||
|                3*Math.PI/2, Math.PI*2); | ||||
|  | ||||
|         if (this._arrowSide == St.Side.RIGHT) { | ||||
|             if (this._arrowOrigin < (y1 + (borderRadius + halfBase))) { | ||||
|                 cr.lineTo(x2 + rise, this._arrowOrigin); | ||||
|                 cr.lineTo(x2, Math.max(y1 + borderRadius, this._arrowOrigin) + halfBase); | ||||
|             } else if (this._arrowOrigin > (y2 - (borderRadius + halfBase))) { | ||||
|                 cr.lineTo(x2, Math.min(y2 - borderRadius, this._arrowOrigin) - halfBase); | ||||
|                 cr.lineTo(x2 + rise, this._arrowOrigin); | ||||
|             } else { | ||||
|                 cr.lineTo(x2, this._arrowOrigin - halfBase); | ||||
|                 cr.lineTo(x2 + rise, this._arrowOrigin); | ||||
|                 cr.lineTo(x2, this._arrowOrigin + halfBase); | ||||
|             } | ||||
|             cr.lineTo(boxWidth - halfBorder, this._arrowOrigin - halfBase); | ||||
|             cr.lineTo(boxWidth - halfBorder + rise, this._arrowOrigin); | ||||
|             cr.lineTo(boxWidth - halfBorder, this._arrowOrigin + halfBase); | ||||
|         } | ||||
|         cr.lineTo(boxWidth - halfBorder, boxHeight - borderRadius); | ||||
|  | ||||
|         cr.lineTo(x2, y2 - borderRadius); | ||||
|  | ||||
|         // bottom-right corner | ||||
|         cr.arc(x2 - borderRadius, y2 - borderRadius, borderRadius, | ||||
|         cr.arc(boxWidth - borderRadius - halfBorder, boxHeight - borderRadius - halfBorder, borderRadius, | ||||
|                0, Math.PI/2); | ||||
|  | ||||
|         if (this._arrowSide == St.Side.BOTTOM) { | ||||
|             if (this._arrowOrigin < (x1 + (borderRadius + halfBase))) { | ||||
|                 cr.lineTo(Math.max(x1 + borderRadius, this._arrowOrigin) + halfBase, y2); | ||||
|                 cr.lineTo(this._arrowOrigin, y2 + rise); | ||||
|             } else if (this._arrowOrigin > (x2 - (borderRadius + halfBase))) { | ||||
|                 cr.lineTo(this._arrowOrigin, y2 + rise); | ||||
|                 cr.lineTo(Math.min(x2 - borderRadius, this._arrowOrigin) - halfBase, y2); | ||||
|             } else { | ||||
|                 cr.lineTo(this._arrowOrigin + halfBase, y2); | ||||
|                 cr.lineTo(this._arrowOrigin, y2 + rise); | ||||
|                 cr.lineTo(this._arrowOrigin - halfBase, y2); | ||||
|             } | ||||
|             cr.lineTo(this._arrowOrigin + halfBase, boxHeight - halfBorder); | ||||
|             cr.lineTo(this._arrowOrigin, boxHeight - halfBorder + rise); | ||||
|             cr.lineTo(this._arrowOrigin - halfBase, boxHeight - halfBorder); | ||||
|         } | ||||
|         cr.lineTo(borderRadius, boxHeight - halfBorder); | ||||
|  | ||||
|         cr.lineTo(x1 + borderRadius, y2); | ||||
|  | ||||
|         // bottom-left corner | ||||
|         cr.arc(x1 + borderRadius, y2 - borderRadius, borderRadius, | ||||
|         cr.arc(borderRadius + halfBorder, boxHeight - borderRadius - halfBorder, borderRadius, | ||||
|                Math.PI/2, Math.PI); | ||||
|  | ||||
|         if (this._arrowSide == St.Side.LEFT) { | ||||
|             if (this._arrowOrigin < (y1 + (borderRadius + halfBase))) { | ||||
|                 cr.lineTo(x1, Math.max(y1 + borderRadius, this._arrowOrigin) + halfBase); | ||||
|                 cr.lineTo(x1 - rise, this._arrowOrigin); | ||||
|             } else if (this._arrowOrigin > (y2 - (borderRadius + halfBase))) { | ||||
|                 cr.lineTo(x1 - rise, this._arrowOrigin); | ||||
|                 cr.lineTo(x1, Math.min(y2 - borderRadius, this._arrowOrigin) - halfBase); | ||||
|             } else { | ||||
|                 cr.lineTo(x1, this._arrowOrigin + halfBase); | ||||
|                 cr.lineTo(x1 - rise, this._arrowOrigin); | ||||
|                 cr.lineTo(x1, this._arrowOrigin - halfBase); | ||||
|             } | ||||
|             cr.lineTo(halfBorder, this._arrowOrigin + halfBase); | ||||
|             cr.lineTo(halfBorder - rise, this._arrowOrigin); | ||||
|             cr.lineTo(halfBorder, this._arrowOrigin - halfBase); | ||||
|         } | ||||
|         cr.lineTo(halfBorder, borderRadius); | ||||
|  | ||||
|         cr.lineTo(x1, y1 + borderRadius); | ||||
|  | ||||
|         // top-left corner | ||||
|         cr.arc(x1 + borderRadius, y1 + borderRadius, borderRadius, | ||||
|         cr.arc(borderRadius + halfBorder, borderRadius + halfBorder, borderRadius, | ||||
|                Math.PI, 3*Math.PI/2); | ||||
|  | ||||
|         Clutter.cairo_set_source_color(cr, backgroundColor); | ||||
| @@ -306,54 +257,37 @@ BoxPointer.prototype = { | ||||
|         cr.stroke(); | ||||
|     }, | ||||
|  | ||||
|     setPosition: function(sourceActor, alignment) { | ||||
|     setPosition: function(sourceActor, gap, alignment) { | ||||
|         // We need to show it now to force an allocation, | ||||
|         // so that we can query the correct size. | ||||
|         this.actor.show(); | ||||
|  | ||||
|         this._sourceActor = sourceActor; | ||||
|         this._alignment = alignment; | ||||
|  | ||||
|         this._reposition(sourceActor, alignment); | ||||
|     }, | ||||
|  | ||||
|     _reposition: function(sourceActor, alignment) { | ||||
|         // Position correctly relative to the sourceActor | ||||
|         let sourceNode = sourceActor.get_theme_node(); | ||||
|         let sourceContentBox = sourceNode.get_content_box(sourceActor.get_allocation_box()); | ||||
|         let sourceAllocation = Shell.util_get_transformed_allocation(sourceActor); | ||||
|         let sourceCenterX = sourceAllocation.x1 + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) / 2; | ||||
|         let sourceCenterY = sourceAllocation.y1 + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) / 2; | ||||
|         let [sourceX, sourceY] = sourceActor.get_transformed_position(); | ||||
|         let [sourceWidth, sourceHeight] = sourceActor.get_transformed_size(); | ||||
|  | ||||
|         let [minWidth, minHeight, natWidth, natHeight] = this.actor.get_preferred_size(); | ||||
|  | ||||
|         // We also want to keep it onscreen, and separated from the | ||||
|         // edge by the same distance as the main part of the box is | ||||
|         // separated from its sourceActor | ||||
|         let primary = Main.layoutManager.primaryMonitor; | ||||
|         let themeNode = this.actor.get_theme_node(); | ||||
|         let borderWidth = themeNode.get_length('-arrow-border-width'); | ||||
|         let arrowBase = themeNode.get_length('-arrow-base'); | ||||
|         let borderRadius = themeNode.get_length('-arrow-border-radius'); | ||||
|         let margin = (4 * borderRadius + borderWidth + arrowBase); | ||||
|         let halfMargin = margin / 2; | ||||
|  | ||||
|         let themeNode = this.actor.get_theme_node(); | ||||
|         let gap = themeNode.get_length('-boxpointer-gap'); | ||||
|         let primary = global.get_primary_monitor(); | ||||
|         let arrowRise = this.actor.get_theme_node().get_length('-arrow-rise'); | ||||
|  | ||||
|         let resX, resY; | ||||
|  | ||||
|         switch (this._arrowSide) { | ||||
|         case St.Side.TOP: | ||||
|             resY = sourceAllocation.y2 + gap; | ||||
|             resY = sourceY + sourceHeight + gap; | ||||
|             break; | ||||
|         case St.Side.BOTTOM: | ||||
|             resY = sourceAllocation.y1 - natHeight - gap; | ||||
|             resY = sourceY - natHeight - gap; | ||||
|             break; | ||||
|         case St.Side.LEFT: | ||||
|             resX = sourceAllocation.x2 + gap; | ||||
|             resX = sourceX + sourceWidth + gap; | ||||
|             break; | ||||
|         case St.Side.RIGHT: | ||||
|             resX = sourceAllocation.x1 - natWidth - gap; | ||||
|             resX = sourceX - natWidth - gap; | ||||
|             break; | ||||
|         } | ||||
|  | ||||
| @@ -362,21 +296,42 @@ BoxPointer.prototype = { | ||||
|         switch (this._arrowSide) { | ||||
|         case St.Side.TOP: | ||||
|         case St.Side.BOTTOM: | ||||
|             resX = sourceCenterX - (halfMargin + (natWidth - margin) * alignment); | ||||
|             switch (alignment) { | ||||
|             case St.Align.START: | ||||
|                 resX = sourceX; | ||||
|                 break; | ||||
|             case St.Align.MIDDLE: | ||||
|                 resX = sourceX - Math.floor((natWidth - sourceWidth) / 2); | ||||
|                 break; | ||||
|             case St.Align.END: | ||||
|                 resX = sourceX - (natWidth - sourceWidth); | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             resX = Math.max(resX, primary.x + 10); | ||||
|             resX = Math.min(resX, primary.x + primary.width - (10 + natWidth)); | ||||
|             this.setArrowOrigin(sourceCenterX - resX); | ||||
|             resX = Math.min(resX, primary.x + primary.width - natWidth - arrowRise - gap); | ||||
|             resX = Math.max(resX, primary.x); | ||||
|  | ||||
|             this.setArrowOrigin((sourceX - resX) + Math.floor(sourceWidth / 2)); | ||||
|             break; | ||||
|  | ||||
|         case St.Side.LEFT: | ||||
|         case St.Side.RIGHT: | ||||
|             resY = sourceCenterY - (halfMargin + (natHeight - margin) * alignment); | ||||
|             switch (alignment) { | ||||
|             case St.Align.START: | ||||
|                 resY = sourceY; | ||||
|                 break; | ||||
|             case St.Align.MIDDLE: | ||||
|                 resY = sourceY - Math.floor((natHeight - sourceHeight) / 2); | ||||
|                 break; | ||||
|             case St.Align.END: | ||||
|                 resY = sourceY - (natHeight - sourceHeight); | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             resY = Math.max(resY, primary.y + 10); | ||||
|             resY = Math.min(resY, primary.y + primary.height - (10 + natHeight)); | ||||
|             resY = Math.min(resY, primary.y + primary.height - natHeight - arrowRise - gap); | ||||
|             resY = Math.max(resY, primary.y); | ||||
|  | ||||
|             this.setArrowOrigin(sourceCenterY - resY); | ||||
|             this.setArrowOrigin((sourceY - resY) + Math.floor(sourceHeight / 2)); | ||||
|             break; | ||||
|         } | ||||
|  | ||||
| @@ -387,9 +342,9 @@ BoxPointer.prototype = { | ||||
|             parent = parent.get_parent(); | ||||
|         } | ||||
|  | ||||
|         this._xPosition = Math.floor(x); | ||||
|         this._yPosition = Math.floor(y); | ||||
|         this._shiftActor(); | ||||
|         // Actually set the position | ||||
|         this.actor.x = Math.floor(x); | ||||
|         this.actor.y = Math.floor(y); | ||||
|     }, | ||||
|  | ||||
|     // @origin: Coordinate specifying middle of the arrow, along | ||||
| @@ -400,42 +355,5 @@ BoxPointer.prototype = { | ||||
|             this._arrowOrigin = origin; | ||||
|             this._border.queue_repaint(); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _shiftActor : function() { | ||||
|         // Since the position of the BoxPointer depends on the allocated size | ||||
|         // of the BoxPointer and the position of the source actor, trying | ||||
|         // to position the BoxPoiner via the x/y properties will result in | ||||
|         // allocation loops and warnings. Instead we do the positioning via | ||||
|         // the anchor point, which is independent of allocation, and leave | ||||
|         // x == y == 0. | ||||
|         this.actor.set_anchor_point(-(this._xPosition + this._xOffset), | ||||
|                                     -(this._yPosition + this._yOffset)); | ||||
|     }, | ||||
|  | ||||
|     set xOffset(offset) { | ||||
|         this._xOffset = offset; | ||||
|         this._shiftActor(); | ||||
|     }, | ||||
|  | ||||
|     get xOffset() { | ||||
|         return this._xOffset; | ||||
|     }, | ||||
|  | ||||
|     set yOffset(offset) { | ||||
|         this._yOffset = offset; | ||||
|         this._shiftActor(); | ||||
|     }, | ||||
|  | ||||
|     get yOffset() { | ||||
|         return this._yOffset; | ||||
|     }, | ||||
|  | ||||
|     set opacity(opacity) { | ||||
|         this.actor.opacity = opacity; | ||||
|     }, | ||||
|  | ||||
|     get opacity() { | ||||
|         return this.actor.opacity; | ||||
|     } | ||||
| }; | ||||
|   | ||||
| @@ -1,84 +1,22 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const DBus = imports.dbus; | ||||
| const Clutter = imports.gi.Clutter; | ||||
| const Gio = imports.gi.Gio; | ||||
| const Lang = imports.lang; | ||||
| const St = imports.gi.St; | ||||
| const Signals = imports.signals; | ||||
| const Pango = imports.gi.Pango; | ||||
| const Gettext_gtk30 = imports.gettext.domain('gtk30'); | ||||
| const Mainloop = imports.mainloop; | ||||
| const Shell = imports.gi.Shell; | ||||
| const Gettext_gtk20 = imports.gettext.domain('gtk20'); | ||||
|  | ||||
| const MSECS_IN_DAY = 24 * 60 * 60 * 1000; | ||||
| const WEEKDATE_HEADER_WIDTH_DIGITS = 3; | ||||
| const SHOW_WEEKDATE_KEY = 'show-weekdate'; | ||||
|  | ||||
| // in org.gnome.desktop.interface | ||||
| const CLOCK_FORMAT_KEY        = 'clock-format'; | ||||
|  | ||||
| function _sameDay(dateA, dateB) { | ||||
|     return (dateA.getDate() == dateB.getDate() && | ||||
|             dateA.getMonth() == dateB.getMonth() && | ||||
|             dateA.getYear() == dateB.getYear()); | ||||
| } | ||||
|  | ||||
| function _sameYear(dateA, dateB) { | ||||
|     return (dateA.getYear() == dateB.getYear()); | ||||
| } | ||||
|  | ||||
| /* TODO: maybe needs config - right now we assume that Saturday and | ||||
|  * Sunday are non-work days (not true in e.g. Israel, it's Sunday and | ||||
|  * Monday there) | ||||
|  */ | ||||
| function _isWorkDay(date) { | ||||
|     return date.getDay() != 0 && date.getDay() != 6; | ||||
| } | ||||
|  | ||||
| function _getBeginningOfDay(date) { | ||||
|     let ret = new Date(date.getTime()); | ||||
|     ret.setHours(0); | ||||
|     ret.setMinutes(0); | ||||
|     ret.setSeconds(0); | ||||
|     ret.setMilliseconds(0); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| function _getEndOfDay(date) { | ||||
|     let ret = new Date(date.getTime()); | ||||
|     ret.setHours(23); | ||||
|     ret.setMinutes(59); | ||||
|     ret.setSeconds(59); | ||||
|     ret.setMilliseconds(999); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| function _formatEventTime(event, clockFormat) { | ||||
|     let ret; | ||||
|     if (event.allDay) { | ||||
|         /* Translators: Shown in calendar event list for all day events | ||||
|          * Keep it short, best if you can use less then 10 characters | ||||
|          */ | ||||
|         ret = C_("event list time", "All Day"); | ||||
|     } else { | ||||
|         switch (clockFormat) { | ||||
|         case '24h': | ||||
|             /* Translators: Shown in calendar event list, if 24h format */ | ||||
|             ret = event.date.toLocaleFormat(C_("event list time", "%H:%M")); | ||||
|             break; | ||||
|  | ||||
|         default: | ||||
|             /* explicit fall-through */ | ||||
|         case '12h': | ||||
|             /* Transators: Shown in calendar event list, if 12h format */ | ||||
|             ret = event.date.toLocaleFormat(C_("event list time", "%l:%M %p")); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| function _getCalendarWeekForDate(date) { | ||||
|     // Based on the algorithms found here: | ||||
|     // http://en.wikipedia.org/wiki/Talk:ISO_week_date | ||||
| @@ -105,262 +43,16 @@ function _getDigitWidth(actor){ | ||||
|     return width; | ||||
| } | ||||
|  | ||||
| function _getCalendarDayAbbreviation(dayNumber) { | ||||
|     let abbreviations = [ | ||||
|         /* Translators: Calendar grid abbreviation for Sunday. | ||||
|          * | ||||
|          * NOTE: These grid abbreviations are always shown together | ||||
|          * and in order, e.g. "S M T W T F S". | ||||
|          */ | ||||
|         C_("grid sunday", "S"), | ||||
|         /* Translators: Calendar grid abbreviation for Monday */ | ||||
|         C_("grid monday", "M"), | ||||
|         /* Translators: Calendar grid abbreviation for Tuesday */ | ||||
|         C_("grid tuesday", "T"), | ||||
|         /* Translators: Calendar grid abbreviation for Wednesday */ | ||||
|         C_("grid wednesday", "W"), | ||||
|         /* Translators: Calendar grid abbreviation for Thursday */ | ||||
|         C_("grid thursday", "T"), | ||||
|         /* Translators: Calendar grid abbreviation for Friday */ | ||||
|         C_("grid friday", "F"), | ||||
|         /* Translators: Calendar grid abbreviation for Saturday */ | ||||
|         C_("grid saturday", "S") | ||||
|     ]; | ||||
|     return abbreviations[dayNumber]; | ||||
| } | ||||
|  | ||||
| function _getEventDayAbbreviation(dayNumber) { | ||||
|     let abbreviations = [ | ||||
|         /* Translators: Event list abbreviation for Sunday. | ||||
|          * | ||||
|          * NOTE: These list abbreviations are normally not shown together | ||||
|          * so they need to be unique (e.g. Tuesday and Thursday cannot | ||||
|          * both be 'T'). | ||||
|          */ | ||||
|         C_("list sunday", "Su"), | ||||
|         /* Translators: Event list abbreviation for Monday */ | ||||
|         C_("list monday", "M"), | ||||
|         /* Translators: Event list abbreviation for Tuesday */ | ||||
|         C_("list tuesday", "T"), | ||||
|         /* Translators: Event list abbreviation for Wednesday */ | ||||
|         C_("list wednesday", "W"), | ||||
|         /* Translators: Event list abbreviation for Thursday */ | ||||
|         C_("list thursday", "Th"), | ||||
|         /* Translators: Event list abbreviation for Friday */ | ||||
|         C_("list friday", "F"), | ||||
|         /* Translators: Event list abbreviation for Saturday */ | ||||
|         C_("list saturday", "S") | ||||
|     ]; | ||||
|     return abbreviations[dayNumber]; | ||||
| } | ||||
|  | ||||
| // Abstraction for an appointment/event in a calendar | ||||
|  | ||||
| function CalendarEvent(date, end, summary, allDay) { | ||||
|     this._init(date, end, summary, allDay); | ||||
| } | ||||
|  | ||||
| CalendarEvent.prototype = { | ||||
|     _init: function(date, end, summary, allDay) { | ||||
|         this.date = date; | ||||
|         this.end = end; | ||||
|         this.summary = summary; | ||||
|         this.allDay = allDay; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| // Interface for appointments/events - e.g. the contents of a calendar | ||||
| // | ||||
|  | ||||
| // First, an implementation with no events | ||||
| function EmptyEventSource() { | ||||
| function Calendar() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| EmptyEventSource.prototype = { | ||||
|     _init: function() { | ||||
|     }, | ||||
|  | ||||
|     requestRange: function(begin, end) { | ||||
|     }, | ||||
|  | ||||
|     getEvents: function(begin, end) { | ||||
|         let result = []; | ||||
|         return result; | ||||
|     }, | ||||
|  | ||||
|     hasEvents: function(day) { | ||||
|         return false; | ||||
|     } | ||||
| }; | ||||
| Signals.addSignalMethods(EmptyEventSource.prototype); | ||||
|  | ||||
| const CalendarServerIface = { | ||||
|     name: 'org.gnome.Shell.CalendarServer', | ||||
|     methods: [{ name: 'GetEvents', | ||||
|                 inSignature: 'xxb', | ||||
|                 outSignature: 'a(sssbxxa{sv})' }], | ||||
|     signals: [{ name: 'Changed', | ||||
|                 inSignature: '' }] | ||||
| }; | ||||
|  | ||||
| const CalendarServer = function () { | ||||
|     this._init(); | ||||
| }; | ||||
|  | ||||
| CalendarServer.prototype = { | ||||
|      _init: function() { | ||||
|          DBus.session.proxifyObject(this, 'org.gnome.Shell.CalendarServer', '/org/gnome/Shell/CalendarServer'); | ||||
|      } | ||||
| }; | ||||
|  | ||||
| DBus.proxifyPrototype(CalendarServer.prototype, CalendarServerIface); | ||||
|  | ||||
| // an implementation that reads data from a session bus service | ||||
| function DBusEventSource(owner) { | ||||
|     this._init(owner); | ||||
| } | ||||
|  | ||||
| function _datesEqual(a, b) { | ||||
|     if (a < b) | ||||
|         return false; | ||||
|     else if (a > b) | ||||
|         return false; | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| function _dateIntervalsOverlap(a0, a1, b0, b1) | ||||
| { | ||||
|     if (a1 <= b0) | ||||
|         return false; | ||||
|     else if (b1 <= a0) | ||||
|         return false; | ||||
|     else | ||||
|         return true; | ||||
| } | ||||
|  | ||||
|  | ||||
| DBusEventSource.prototype = { | ||||
|     _init: function(owner) { | ||||
|         this._resetCache(); | ||||
|  | ||||
|         this._dbusProxy = new CalendarServer(owner); | ||||
|         this._dbusProxy.connect('Changed', Lang.bind(this, this._onChanged)); | ||||
|  | ||||
|         DBus.session.watch_name('org.gnome.Shell.CalendarServer', | ||||
|                                 false, // do not launch a name-owner if none exists | ||||
|                                 Lang.bind(this, this._onNameAppeared), | ||||
|                                 Lang.bind(this, this._onNameVanished)); | ||||
|     }, | ||||
|  | ||||
|     _resetCache: function() { | ||||
|         this._events = []; | ||||
|         this._lastRequestBegin = null; | ||||
|         this._lastRequestEnd = null; | ||||
|     }, | ||||
|  | ||||
|     _onNameAppeared: function(owner) { | ||||
|         this._resetCache(); | ||||
|         this._loadEvents(true); | ||||
|     }, | ||||
|  | ||||
|     _onNameVanished: function(oldOwner) { | ||||
|         this._resetCache(); | ||||
|         this.emit('changed'); | ||||
|     }, | ||||
|  | ||||
|     _onChanged: function() { | ||||
|         this._loadEvents(false); | ||||
|     }, | ||||
|  | ||||
|     _onEventsReceived: function(appointments) { | ||||
|         let newEvents = []; | ||||
|         if (appointments != null) { | ||||
|             for (let n = 0; n < appointments.length; n++) { | ||||
|                 let a = appointments[n]; | ||||
|                 let date = new Date(a[4] * 1000); | ||||
|                 let end = new Date(a[5] * 1000); | ||||
|                 let summary = a[1]; | ||||
|                 let allDay = a[3]; | ||||
|                 let event = new CalendarEvent(date, end, summary, allDay); | ||||
|                 newEvents.push(event); | ||||
|             } | ||||
|             newEvents.sort(function(event1, event2) { | ||||
|                 return event1.date.getTime() - event2.date.getTime(); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         this._events = newEvents; | ||||
|         this.emit('changed'); | ||||
|     }, | ||||
|  | ||||
|     _loadEvents: function(forceReload) { | ||||
|         if (this._curRequestBegin && this._curRequestEnd){ | ||||
|             let callFlags = 0; | ||||
|             if (forceReload) | ||||
|                 callFlags |= DBus.CALL_FLAG_START; | ||||
|             this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000, | ||||
|                                             this._curRequestEnd.getTime() / 1000, | ||||
|                                             forceReload, | ||||
|                                             Lang.bind(this, this._onEventsReceived), | ||||
|                                             callFlags); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     requestRange: function(begin, end, forceReload) { | ||||
|         if (forceReload || !(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) { | ||||
|             this._lastRequestBegin = begin; | ||||
|             this._lastRequestEnd = end; | ||||
|             this._curRequestBegin = begin; | ||||
|             this._curRequestEnd = end; | ||||
|             this._loadEvents(forceReload); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     getEvents: function(begin, end) { | ||||
|         let result = []; | ||||
|         for(let n = 0; n < this._events.length; n++) { | ||||
|             let event = this._events[n]; | ||||
|             if (_dateIntervalsOverlap (event.date, event.end, begin, end)) { | ||||
|                 result.push(event); | ||||
|             } | ||||
|         } | ||||
|         return result; | ||||
|     }, | ||||
|  | ||||
|     hasEvents: function(day) { | ||||
|         let dayBegin = _getBeginningOfDay(day); | ||||
|         let dayEnd = _getEndOfDay(day); | ||||
|  | ||||
|         let events = this.getEvents(dayBegin, dayEnd); | ||||
|  | ||||
|         if (events.length == 0) | ||||
|             return false; | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
| }; | ||||
| Signals.addSignalMethods(DBusEventSource.prototype); | ||||
|  | ||||
| // Calendar: | ||||
| // @eventSource: is an object implementing the EventSource API, e.g. the | ||||
| // requestRange(), getEvents(), hasEvents() methods and the ::changed signal. | ||||
| function Calendar(eventSource) { | ||||
|     this._init(eventSource); | ||||
| } | ||||
|  | ||||
| Calendar.prototype = { | ||||
|     _init: function(eventSource) { | ||||
|         if (eventSource) { | ||||
|             this._eventSource = eventSource; | ||||
|  | ||||
|             this._eventSource.connect('changed', Lang.bind(this, | ||||
|                                                            function() { | ||||
|                                                                this._update(false); | ||||
|                                                            })); | ||||
|         } | ||||
|  | ||||
|         this._weekStart = Shell.util_get_week_start(); | ||||
|     _init: function() { | ||||
|         // FIXME: This is actually the fallback method for GTK+ for the week start; | ||||
|         // GTK+ by preference uses nl_langinfo (NL_TIME_FIRST_WEEKDAY). We probably | ||||
|         // should add a C function so we can do the full handling. | ||||
|         this._weekStart = NaN; | ||||
|         this._weekdate = NaN; | ||||
|         this._digitWidth = NaN; | ||||
|         this._settings = new Gio.Settings({ schema: 'org.gnome.shell.calendar' }); | ||||
| @@ -368,9 +60,18 @@ Calendar.prototype = { | ||||
|         this._settings.connect('changed::' + SHOW_WEEKDATE_KEY, Lang.bind(this, this._onSettingsChange)); | ||||
|         this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY); | ||||
|  | ||||
|         let weekStartString = Gettext_gtk20.gettext('calendar:week_start:0'); | ||||
|         if (weekStartString.indexOf('calendar:week_start:') == 0) { | ||||
|             this._weekStart = parseInt(weekStartString.substring(20)); | ||||
|         } | ||||
|  | ||||
|         if (isNaN(this._weekStart) || this._weekStart < 0 || this._weekStart > 6) { | ||||
|             log('Translation of "calendar:week_start:0" in GTK+ is not correct'); | ||||
|             this._weekStart = 0; | ||||
|         } | ||||
|  | ||||
|         // Find the ordering for month/year in the calendar heading | ||||
|         this._headerFormatWithoutYear = '%B'; | ||||
|         switch (Gettext_gtk30.gettext('calendar:MY')) { | ||||
|         switch (Gettext_gtk20.gettext('calendar:MY')) { | ||||
|         case 'calendar:MY': | ||||
|             this._headerFormat = '%B %Y'; | ||||
|             break; | ||||
| @@ -384,7 +85,7 @@ Calendar.prototype = { | ||||
|         } | ||||
|  | ||||
|         // Start off with the current date | ||||
|         this._selectedDate = new Date(); | ||||
|         this.date = new Date(); | ||||
|  | ||||
|         this.actor = new St.Table({ homogeneous: false, | ||||
|                                     style_class: 'calendar', | ||||
| @@ -394,17 +95,14 @@ Calendar.prototype = { | ||||
|                            Lang.bind(this, this._onScroll)); | ||||
|  | ||||
|         this._buildHeader (); | ||||
|         this._update(); | ||||
|     }, | ||||
|  | ||||
|     // Sets the calendar to show a specific date | ||||
|     setDate: function(date, forceReload) { | ||||
|         if (!_sameDay(date, this._selectedDate)) { | ||||
|             this._selectedDate = date; | ||||
|             this._update(forceReload); | ||||
|             this.emit('selected-date-changed', new Date(this._selectedDate)); | ||||
|         } else { | ||||
|             if (forceReload) | ||||
|                 this._update(forceReload); | ||||
|     setDate: function(date) { | ||||
|         if (!_sameDay(date, this.date)) { | ||||
|             this.date = date; | ||||
|             this._update(); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
| @@ -418,36 +116,45 @@ Calendar.prototype = { | ||||
|                        { row: 0, col: 0, col_span: offsetCols + 7 }); | ||||
|  | ||||
|         this.actor.connect('style-changed', Lang.bind(this, this._onStyleChange)); | ||||
|         let [backlabel, forwardlabel] = ['<', '>']; | ||||
|         if (St.Widget.get_default_direction () == St.TextDirection.RTL) { | ||||
|             [backlabel, forwardlabel] = [forwardlabel, backlabel]; | ||||
|         } | ||||
|  | ||||
|         let back = new St.Button({ style_class: 'calendar-change-month-back' }); | ||||
|         let back = new St.Button({ label: backlabel, style_class: 'calendar-change-month'  }); | ||||
|         this._topBox.add(back); | ||||
|         back.connect('clicked', Lang.bind(this, this._onPrevMonthButtonClicked)); | ||||
|         back.connect('clicked', Lang.bind(this, this._prevMonth)); | ||||
|  | ||||
|         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 }); | ||||
|         this._dateLabel = new St.Label(); | ||||
|         this._topBox.add(this._dateLabel, { expand: true, x_fill: false, x_align: St.Align.MIDDLE }); | ||||
|  | ||||
|         let forward = new St.Button({ style_class: 'calendar-change-month-forward' }); | ||||
|         let forward = new St.Button({ label: forwardlabel, style_class: 'calendar-change-month' }); | ||||
|         this._topBox.add(forward); | ||||
|         forward.connect('clicked', Lang.bind(this, this._onNextMonthButtonClicked)); | ||||
|         forward.connect('clicked', Lang.bind(this, this._nextMonth)); | ||||
|  | ||||
|         // Add weekday labels... | ||||
|         // | ||||
|         // We need to figure out the abbreviated localized names for the days of the week; | ||||
|         // we do this by just getting the next 7 days starting from right now and then putting | ||||
|         // them in the right cell in the table. It doesn't matter if we add them in order | ||||
|         let iter = new Date(this._selectedDate); | ||||
|         let iter = new Date(this.date); | ||||
|         iter.setSeconds(0); // Leap second protection. Hah! | ||||
|         iter.setHours(12); | ||||
|  | ||||
|         if (this._useWeekdate) { | ||||
|             this._weekdateHeader = new St.Label(); | ||||
|             this.actor.add(this._weekdateHeader, | ||||
|                               { row: 1, | ||||
|                                 col: 0, | ||||
|                                 x_fill: false, x_align: St.Align.MIDDLE }); | ||||
|             this._setWeekdateHeaderWidth(); | ||||
|         } else { | ||||
|             this._weekdateHeader = null; | ||||
|         } | ||||
|  | ||||
|         for (let i = 0; i < 7; i++) { | ||||
|             // Could use iter.toLocaleFormat('%a') but that normally gives three characters | ||||
|             // and we want, ideally, a single character for e.g. S M T W T F S | ||||
|             let customDayAbbrev = _getCalendarDayAbbreviation(iter.getDay()); | ||||
|             let label = new St.Label({ style_class: 'calendar-day-base calendar-day-heading', | ||||
|                                        text: customDayAbbrev }); | ||||
|             this.actor.add(label, | ||||
|             this.actor.add(new St.Label({ text: iter.toLocaleFormat('%a') }), | ||||
|                            { row: 1, | ||||
|                              col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7, | ||||
|                              x_fill: false, x_align: St.Align.MIDDLE }); | ||||
|                              x_fill: false, x_align: St.Align.END }); | ||||
|             iter.setTime(iter.getTime() + MSECS_IN_DAY); | ||||
|         } | ||||
|  | ||||
| @@ -471,72 +178,43 @@ Calendar.prototype = { | ||||
|         switch (event.get_scroll_direction()) { | ||||
|         case Clutter.ScrollDirection.UP: | ||||
|         case Clutter.ScrollDirection.LEFT: | ||||
|             this._onPrevMonthButtonClicked(); | ||||
|             this._prevMonth(); | ||||
|             break; | ||||
|         case Clutter.ScrollDirection.DOWN: | ||||
|         case Clutter.ScrollDirection.RIGHT: | ||||
|             this._onNextMonthButtonClicked(); | ||||
|             this._nextMonth(); | ||||
|             break; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _onPrevMonthButtonClicked: function() { | ||||
|         let newDate = new Date(this._selectedDate); | ||||
|         let oldMonth = newDate.getMonth(); | ||||
|         if (oldMonth == 0) { | ||||
|             newDate.setMonth(11); | ||||
|             newDate.setFullYear(newDate.getFullYear() - 1); | ||||
|             if (newDate.getMonth() != 11) { | ||||
|                 let day = 32 - new Date(newDate.getFullYear() - 1, 11, 32).getDate(); | ||||
|                 newDate = new Date(newDate.getFullYear() - 1, 11, day); | ||||
|             } | ||||
|     _prevMonth: function() { | ||||
|         if (this.date.getMonth() == 0) { | ||||
|             this.date.setMonth(11); | ||||
|             this.date.setFullYear(this.date.getFullYear() - 1); | ||||
|         } else { | ||||
|             this.date.setMonth(this.date.getMonth() - 1); | ||||
|         } | ||||
|         else { | ||||
|             newDate.setMonth(oldMonth - 1); | ||||
|             if (newDate.getMonth() != oldMonth - 1) { | ||||
|                 let day = 32 - new Date(newDate.getFullYear(), oldMonth - 1, 32).getDate(); | ||||
|                 newDate = new Date(newDate.getFullYear(), oldMonth - 1, day); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         this.setDate(newDate, false); | ||||
|         this._update(); | ||||
|    }, | ||||
|  | ||||
|    _onNextMonthButtonClicked: function() { | ||||
|         let newDate = new Date(this._selectedDate); | ||||
|         let oldMonth = newDate.getMonth(); | ||||
|         if (oldMonth == 11) { | ||||
|             newDate.setMonth(0); | ||||
|             newDate.setFullYear(newDate.getFullYear() + 1); | ||||
|             if (newDate.getMonth() != 0) { | ||||
|                 let day = 32 - new Date(newDate.getFullYear() + 1, 0, 32).getDate(); | ||||
|                 newDate = new Date(newDate.getFullYear() + 1, 0, day); | ||||
|             } | ||||
|     _nextMonth: function() { | ||||
|         if (this.date.getMonth() == 11) { | ||||
|             this.date.setMonth(0); | ||||
|             this.date.setFullYear(this.date.getFullYear() + 1); | ||||
|         } else { | ||||
|             this.date.setMonth(this.date.getMonth() + 1); | ||||
|         } | ||||
|         else { | ||||
|             newDate.setMonth(oldMonth + 1); | ||||
|             if (newDate.getMonth() != oldMonth + 1) { | ||||
|                 let day = 32 - new Date(newDate.getFullYear(), oldMonth + 1, 32).getDate(); | ||||
|                 newDate = new Date(newDate.getFullYear(), oldMonth + 1, day); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|        this.setDate(newDate, false); | ||||
|         this._update(); | ||||
|     }, | ||||
|  | ||||
|     _onSettingsChange: function() { | ||||
|         this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY); | ||||
|         this._buildHeader(); | ||||
|         this._update(false); | ||||
|         this._update(); | ||||
|     }, | ||||
|  | ||||
|     _update: function(forceReload) { | ||||
|         let now = new Date(); | ||||
|  | ||||
|         if (_sameYear(this._selectedDate, now)) | ||||
|             this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormatWithoutYear); | ||||
|         else | ||||
|             this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormat); | ||||
|     _update: function() { | ||||
|         this._dateLabel.text = this.date.toLocaleFormat(this._headerFormat); | ||||
|  | ||||
|         // Remove everything but the topBox and the weekday labels | ||||
|         let children = this.actor.get_children(); | ||||
| @@ -544,214 +222,45 @@ Calendar.prototype = { | ||||
|             children[i].destroy(); | ||||
|  | ||||
|         // Start at the beginning of the week before the start of the month | ||||
|         let beginDate = new Date(this._selectedDate); | ||||
|         beginDate.setDate(1); | ||||
|         beginDate.setSeconds(0); | ||||
|         beginDate.setHours(12); | ||||
|         let daysToWeekStart = (7 + beginDate.getDay() - this._weekStart) % 7; | ||||
|         beginDate.setTime(beginDate.getTime() - daysToWeekStart * MSECS_IN_DAY); | ||||
|         let iter = new Date(this.date); | ||||
|         iter.setDate(1); | ||||
|         iter.setSeconds(0); | ||||
|         iter.setHours(12); | ||||
|         let daysToWeekStart = (7 + iter.getDay() - this._weekStart) % 7; | ||||
|         iter.setTime(iter.getTime() - daysToWeekStart * MSECS_IN_DAY); | ||||
|  | ||||
|         let now = new Date(); | ||||
|  | ||||
|         let iter = new Date(beginDate); | ||||
|         let row = 2; | ||||
|         while (true) { | ||||
|             let button = new St.Button({ label: iter.getDate().toString() }); | ||||
|  | ||||
|             if (!this._eventSource) | ||||
|                 button.reactive = false; | ||||
|  | ||||
|             let iterStr = iter.toUTCString(); | ||||
|             button.connect('clicked', Lang.bind(this, function() { | ||||
|                 let newlySelectedDate = new Date(iterStr); | ||||
|                 this.setDate(newlySelectedDate, false); | ||||
|             })); | ||||
|  | ||||
|             let hasEvents = this._eventSource && this._eventSource.hasEvents(iter); | ||||
|             let styleClass = 'calendar-day-base calendar-day'; | ||||
|             if (_isWorkDay(iter)) | ||||
|                 styleClass += ' calendar-work-day' | ||||
|             else | ||||
|                 styleClass += ' calendar-nonwork-day' | ||||
|  | ||||
|             // Hack used in lieu of border-collapse - see gnome-shell.css | ||||
|             if (row == 2) | ||||
|                 styleClass = 'calendar-day-top ' + styleClass; | ||||
|             if (iter.getDay() == this._weekStart) | ||||
|                 styleClass = 'calendar-day-left ' + styleClass; | ||||
|  | ||||
|             let label = new St.Label({ text: iter.getDate().toString() }); | ||||
|             if (_sameDay(now, iter)) | ||||
|                 styleClass += ' calendar-today'; | ||||
|             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' | ||||
|  | ||||
|             button.style_class = styleClass; | ||||
|                 label.style_class = 'calendar-day calendar-today'; | ||||
|             else if (iter.getMonth() != this.date.getMonth()) | ||||
|                 label.style_class = 'calendar-day calendar-other-month-day'; | ||||
|             else | ||||
|                 label.style_class = 'calendar-day'; | ||||
|  | ||||
|             let offsetCols = this._useWeekdate ? 1 : 0; | ||||
|             this.actor.add(button, | ||||
|                            { row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7 }); | ||||
|             this.actor.add(label, | ||||
|                            { row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7, | ||||
|                              x_fill: false, x_align: St.Align.END }); | ||||
|  | ||||
|             if (this._useWeekdate && iter.getDay() == 4) { | ||||
|                 let label = new St.Label({ text: _getCalendarWeekForDate(iter).toString(), | ||||
|                                            style_class: 'calendar-day-base calendar-week-number'}); | ||||
|                                            style_class: 'calendar-day calendar-calendarweek'}); | ||||
|                 this.actor.add(label, | ||||
|                                { row: row, col: 0, y_align: St.Align.MIDDLE }); | ||||
|                               { row: row, col: 0, | ||||
| 		                        x_fill: false, x_align: St.Align.MIDDLE }); | ||||
|             } | ||||
|  | ||||
|             iter.setTime(iter.getTime() + MSECS_IN_DAY); | ||||
|             if (iter.getDay() == this._weekStart) { | ||||
|                 // We stop on the first "first day of the week" after the month we are displaying | ||||
|                 if (iter.getMonth() > this._selectedDate.getMonth() || iter.getYear() > this._selectedDate.getYear()) | ||||
|                 if (iter.getMonth() > this.date.getMonth() || iter.getYear() > this.date.getYear()) | ||||
|                     break; | ||||
|                 row++; | ||||
|             } | ||||
|         } | ||||
|         // Signal to the event source that we are interested in events | ||||
|         // only from this date range | ||||
|         if (this._eventSource) | ||||
|             this._eventSource.requestRange(beginDate, iter, forceReload); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| Signals.addSignalMethods(Calendar.prototype); | ||||
|  | ||||
| function EventsList(eventSource) { | ||||
|     this._init(eventSource); | ||||
| } | ||||
|  | ||||
| EventsList.prototype = { | ||||
|     _init: function(eventSource) { | ||||
|         this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'}); | ||||
|         this._date = new Date(); | ||||
|         this._eventSource = eventSource; | ||||
|         this._eventSource.connect('changed', Lang.bind(this, this._update)); | ||||
|         this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' }); | ||||
|         this._desktopSettings.connect('changed', Lang.bind(this, this._update)); | ||||
|         this._weekStart = Shell.util_get_week_start(); | ||||
|  | ||||
|         this._update(); | ||||
|     }, | ||||
|  | ||||
|     _addEvent: function(dayNameBox, timeBox, eventTitleBox, includeDayName, day, time, desc) { | ||||
|         if (includeDayName) { | ||||
|             dayNameBox.add(new St.Label( { style_class: 'events-day-dayname', | ||||
|                                            text: day } ), | ||||
|                            { x_fill: true } ); | ||||
|         } | ||||
|         timeBox.add(new St.Label( { style_class: 'events-day-time', | ||||
|                                     text: time} ), | ||||
|                     { x_fill: true } ); | ||||
|         eventTitleBox.add(new St.Label( { style_class: 'events-day-task', | ||||
|                                           text: desc} )); | ||||
|     }, | ||||
|  | ||||
|     _addPeriod: function(header, begin, end, includeDayName, showNothingScheduled) { | ||||
|         if (!this._eventSource) | ||||
|             return; | ||||
|  | ||||
|         let events = this._eventSource.getEvents(begin, end); | ||||
|  | ||||
|         let clockFormat = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);; | ||||
|  | ||||
|         if (events.length == 0 && !showNothingScheduled) | ||||
|             return; | ||||
|  | ||||
|         let vbox = new St.BoxLayout( {vertical: true} ); | ||||
|         this.actor.add(vbox); | ||||
|  | ||||
|         vbox.add(new St.Label({ style_class: 'events-day-header', text: header })); | ||||
|         let box = new St.BoxLayout({style_class: 'events-header-hbox'}); | ||||
|         let dayNameBox = new St.BoxLayout({ vertical: true, style_class: 'events-day-name-box' }); | ||||
|         let timeBox = new St.BoxLayout({ vertical: true, style_class: 'events-time-box' }); | ||||
|         let eventTitleBox = new St.BoxLayout({ vertical: true, style_class: 'events-event-box' }); | ||||
|         box.add(dayNameBox, {x_fill: false}); | ||||
|         box.add(timeBox, {x_fill: false}); | ||||
|         box.add(eventTitleBox, {expand: true}); | ||||
|         vbox.add(box); | ||||
|  | ||||
|         for (let n = 0; n < events.length; n++) { | ||||
|             let event = events[n]; | ||||
|             let dayString = _getEventDayAbbreviation(event.date.getDay()); | ||||
|             let timeString = _formatEventTime(event, clockFormat); | ||||
|             let summaryString = event.summary; | ||||
|             this._addEvent(dayNameBox, timeBox, eventTitleBox, includeDayName, dayString, timeString, summaryString); | ||||
|         } | ||||
|  | ||||
|         if (events.length == 0 && showNothingScheduled) { | ||||
|             let now = new Date(); | ||||
|             /* Translators: Text to show if there are no events */ | ||||
|             let nothingEvent = new CalendarEvent(now, now, _("Nothing Scheduled"), true); | ||||
|             let timeString = _formatEventTime(nothingEvent, clockFormat); | ||||
|             this._addEvent(dayNameBox, timeBox, eventTitleBox, false, "", timeString, nothingEvent.summary); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _showOtherDay: function(day) { | ||||
|         this.actor.destroy_children(); | ||||
|  | ||||
|         let dayBegin = _getBeginningOfDay(day); | ||||
|         let dayEnd = _getEndOfDay(day); | ||||
|  | ||||
|         let dayString; | ||||
|         let now = new Date(); | ||||
|         if (_sameYear(day, now)) | ||||
|             /* Translators: Shown on calendar heading when selected day occurs on current year */ | ||||
|             dayString = day.toLocaleFormat(C_("calendar heading", "%A, %B %d")); | ||||
|         else | ||||
|             /* Translators: Shown on calendar heading when selected day occurs on different year */ | ||||
|             dayString = day.toLocaleFormat(C_("calendar heading", "%A, %B %d, %Y")); | ||||
|         this._addPeriod(dayString, dayBegin, dayEnd, false, true); | ||||
|     }, | ||||
|  | ||||
|     _showToday: function() { | ||||
|         this.actor.destroy_children(); | ||||
|  | ||||
|         let now = new Date(); | ||||
|         let dayBegin = _getBeginningOfDay(now); | ||||
|         let dayEnd = _getEndOfDay(now); | ||||
|         this._addPeriod(_("Today"), dayBegin, dayEnd, false, true); | ||||
|  | ||||
|         let tomorrowBegin = new Date(dayBegin.getTime() + 86400 * 1000); | ||||
|         let tomorrowEnd = new Date(dayEnd.getTime() + 86400 * 1000); | ||||
|         this._addPeriod(_("Tomorrow"), tomorrowBegin, tomorrowEnd, false, true); | ||||
|  | ||||
|         if (dayEnd.getDay() <= 4 + this._weekStart) { | ||||
|             /* If now is within the first 5 days we show "This week" and | ||||
|              * include events up until and including Saturday/Sunday | ||||
|              * (depending on whether a week starts on Sunday/Monday). | ||||
|              */ | ||||
|             let thisWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000); | ||||
|             let thisWeekEnd = new Date(dayEnd.getTime() + (6 + this._weekStart - dayEnd.getDay()) * 86400 * 1000); | ||||
|             this._addPeriod(_("This week"), thisWeekBegin, thisWeekEnd, true, false); | ||||
|         } else { | ||||
|             /* otherwise it's one of the two last days of the week ... show | ||||
|              * "Next week" and include events up until and including *next* | ||||
|              * Saturday/Sunday | ||||
|              */ | ||||
|             let nextWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000); | ||||
|             let nextWeekEnd = new Date(dayEnd.getTime() + (13 + this._weekStart - dayEnd.getDay()) * 86400 * 1000); | ||||
|             this._addPeriod(_("Next week"), nextWeekBegin, nextWeekEnd, true, false); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     // Sets the event list to show events from a specific date | ||||
|     setDate: function(date) { | ||||
|         if (!_sameDay(date, this._date)) { | ||||
|             this._date = date; | ||||
|             this._update(); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _update: function() { | ||||
|         let today = new Date(); | ||||
|         if (_sameDay (this._date, today)) { | ||||
|             this._showToday(); | ||||
|         } else { | ||||
|             this._showOtherDay(this._date); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|   | ||||
							
								
								
									
										364
									
								
								js/ui/chrome.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,364 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Lang = imports.lang; | ||||
| const Mainloop = imports.mainloop; | ||||
| const Meta = imports.gi.Meta; | ||||
| const Shell = imports.gi.Shell; | ||||
| const Signals = imports.signals; | ||||
|  | ||||
| const Main = imports.ui.main; | ||||
| const Params = imports.misc.params; | ||||
|  | ||||
| // This manages the shell "chrome"; the UI that's visible in the | ||||
| // normal mode (ie, outside the Overview), that surrounds the main | ||||
| // workspace content. | ||||
|  | ||||
| const Visibility = { | ||||
|     FULL:       1, | ||||
|     FULLSCREEN: 2, | ||||
|     OVERVIEW:   3 | ||||
| }; | ||||
|  | ||||
| const defaultParams = { | ||||
|     visibleInOverview: false, | ||||
|     visibleInFullscreen: false, | ||||
|     affectsStruts: true, | ||||
|     affectsInputRegion: true | ||||
| }; | ||||
|  | ||||
| function Chrome() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| Chrome.prototype = { | ||||
|     _init: function() { | ||||
|         // The group itself has zero size so it doesn't interfere with DND | ||||
|         this.actor = new Shell.GenericContainer({ width: 0, height: 0 }); | ||||
|         Main.uiGroup.add_actor(this.actor); | ||||
|         this.actor.connect('allocate', Lang.bind(this, this._allocated)); | ||||
|  | ||||
|         this._inFullscreen = false; | ||||
|         this._inOverview = false; | ||||
|         this.visibility = Visibility.FULL; | ||||
|  | ||||
|         this._trackedActors = []; | ||||
|  | ||||
|         global.screen.connect('restacked', | ||||
|                               Lang.bind(this, this._windowsRestacked)); | ||||
|  | ||||
|         // Need to update struts on new workspaces when they are added | ||||
|         global.screen.connect('notify::n-workspaces', | ||||
|                               Lang.bind(this, this._queueUpdateRegions)); | ||||
|  | ||||
|         Main.overview.connect('showing', | ||||
|                              Lang.bind(this, this._overviewShowing)); | ||||
|         Main.overview.connect('hidden', | ||||
|                              Lang.bind(this, this._overviewHidden)); | ||||
|  | ||||
|         this._queueUpdateRegions(); | ||||
|     }, | ||||
|  | ||||
|     _allocated: function(actor, box, flags) { | ||||
|         let children = this.actor.get_children(); | ||||
|         for (let i = 0; i < children.length; i++) | ||||
|             children[i].allocate_preferred_size(flags); | ||||
|     }, | ||||
|  | ||||
|     // addActor: | ||||
|     // @actor: an actor to add to the chrome layer | ||||
|     // @params: (optional) additional params | ||||
|     // | ||||
|     // Adds @actor to the chrome layer and extends the input region | ||||
|     // and window manager struts to include it. (Window manager struts | ||||
|     // will only be affected if @actor is touching a screen edge.) | ||||
|     // Changes in @actor's size and position will automatically result | ||||
|     // in appropriate changes to the input region and struts. Changes | ||||
|     // in its visibility will affect the input region, but NOT the | ||||
|     // struts. | ||||
|     // | ||||
|     // If %visibleInOverview is %true in @params, @actor will remain | ||||
|     // visible when the overview is brought up. Otherwise it will | ||||
|     // automatically be hidden. Likewise, if %visibleInFullscreen is | ||||
|     // %true, the actor will be visible even when a fullscreen window | ||||
|     // should be covering it. | ||||
|     // | ||||
|     // If %affectsStruts or %affectsInputRegion is %false, the actor | ||||
|     // will not have the indicated effect. | ||||
|     addActor: function(actor, params) { | ||||
|         this.actor.add_actor(actor); | ||||
|         this._trackActor(actor, params); | ||||
|     }, | ||||
|  | ||||
|     // trackActor: | ||||
|     // @actor: a descendant of the chrome to begin tracking | ||||
|     // @params: parameters describing how to track @actor | ||||
|     // | ||||
|     // Tells the chrome to track @actor, which must be a descendant | ||||
|     // of an actor added via addActor(). This can be used to extend the | ||||
|     // struts or input region to cover specific children. | ||||
|     // | ||||
|     // @params can have any of the same values as in addActor(), though | ||||
|     // some possibilities don't make sense (eg, trying to have a | ||||
|     // %visibleInOverview child of a non-%visibleInOverview parent). | ||||
|     // By default, @actor has the same params as its chrome ancestor. | ||||
|     trackActor: function(actor, params) { | ||||
|         let ancestor = actor.get_parent(); | ||||
|         let index = this._findActor(ancestor); | ||||
|         while (ancestor && index == -1) { | ||||
|             ancestor = ancestor.get_parent(); | ||||
|             index = this._findActor(ancestor); | ||||
|         } | ||||
|         if (!ancestor) | ||||
|             throw new Error('actor is not a descendent of the chrome layer'); | ||||
|  | ||||
|         let ancestorData = this._trackedActors[index]; | ||||
|         if (!params) | ||||
|             params = {}; | ||||
|         // We can't use Params.parse here because we want to drop | ||||
|         // the extra values like ancestorData.actor | ||||
|         for (let prop in defaultParams) { | ||||
|             if (!params[prop]) | ||||
|                 params[prop] = ancestorData[prop]; | ||||
|         } | ||||
|  | ||||
|         this._trackActor(actor, params); | ||||
|     }, | ||||
|  | ||||
|     // untrackActor: | ||||
|     // @actor: an actor previously tracked via trackActor() | ||||
|     // | ||||
|     // Undoes the effect of trackActor() | ||||
|     untrackActor: function(actor) { | ||||
|         this._untrackActor(actor); | ||||
|     }, | ||||
|  | ||||
|     // removeActor: | ||||
|     // @actor: a child of the chrome layer | ||||
|     // | ||||
|     // Removes @actor from the chrome layer | ||||
|     removeActor: function(actor) { | ||||
|         this.actor.remove_actor(actor); | ||||
|         this._untrackActor(actor); | ||||
|     }, | ||||
|  | ||||
|     _findActor: function(actor) { | ||||
|         for (let i = 0; i < this._trackedActors.length; i++) { | ||||
|             let actorData = this._trackedActors[i]; | ||||
|             if (actorData.actor == actor) | ||||
|                 return i; | ||||
|         } | ||||
|         return -1; | ||||
|     }, | ||||
|  | ||||
|     _trackActor: function(actor, params) { | ||||
|         if (this._findActor(actor) != -1) | ||||
|             throw new Error('trying to re-track existing chrome actor'); | ||||
|  | ||||
|         let actorData = Params.parse(params, defaultParams); | ||||
|         actorData.actor = actor; | ||||
|         actorData.visibleId = actor.connect('notify::visible', | ||||
|                                             Lang.bind(this, this._queueUpdateRegions)); | ||||
|         actorData.allocationId = actor.connect('notify::allocation', | ||||
|                                                Lang.bind(this, this._queueUpdateRegions)); | ||||
|         actorData.parentSetId = actor.connect('parent-set', | ||||
|                                               Lang.bind(this, this._actorReparented)); | ||||
|         // Note that destroying actor will unset its parent, so we don't | ||||
|         // need to connect to 'destroy' too. | ||||
|  | ||||
|         this._trackedActors.push(actorData); | ||||
|         this._queueUpdateRegions(); | ||||
|     }, | ||||
|  | ||||
|     _untrackActor: function(actor) { | ||||
|         let i = this._findActor(actor); | ||||
|  | ||||
|         if (i == -1) | ||||
|             return; | ||||
|         let actorData = this._trackedActors[i]; | ||||
|  | ||||
|         this._trackedActors.splice(i, 1); | ||||
|         actor.disconnect(actorData.visibleId); | ||||
|         actor.disconnect(actorData.allocationId); | ||||
|         actor.disconnect(actorData.parentSetId); | ||||
|  | ||||
|         this._queueUpdateRegions(); | ||||
|     }, | ||||
|  | ||||
|     _actorReparented: function(actor, oldParent) { | ||||
|         if (!this.actor.contains(actor)) | ||||
|             this._untrackActor(actor); | ||||
|     }, | ||||
|  | ||||
|     _updateVisibility: function() { | ||||
|         for (let i = 0; i < this._trackedActors.length; i++) { | ||||
|             let actorData = this._trackedActors[i]; | ||||
|             if (this._inOverview && !actorData.visibleInOverview) | ||||
|                 this.actor.set_skip_paint(actorData.actor, true); | ||||
|             else if (!this._inOverview && this._inFullscreen && !actorData.visibleInFullscreen) | ||||
|                 this.actor.set_skip_paint(actorData.actor, true); | ||||
|             else | ||||
|                 this.actor.set_skip_paint(actorData.actor, false); | ||||
|         } | ||||
|  | ||||
|         let newVisibility; | ||||
|         if (this._inOverview) | ||||
|             newVisibility = Visibility.OVERVIEW; | ||||
|         else if (this._inFullscreen) | ||||
|             newVisibility = Visibility.FULLSCREEN; | ||||
|         else | ||||
|             newVisibility = Visibility.FULL; | ||||
|  | ||||
|         if (newVisibility != this.visibility) { | ||||
|             this.visibility = newVisibility; | ||||
|             this.emit('visibility-changed', this.visibility); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _overviewShowing: function() { | ||||
|         this._inOverview = true; | ||||
|         this._updateVisibility(); | ||||
|         this._queueUpdateRegions(); | ||||
|     }, | ||||
|  | ||||
|     _overviewHidden: function() { | ||||
|         this._inOverview = false; | ||||
|         this._updateVisibility(); | ||||
|         this._queueUpdateRegions(); | ||||
|     }, | ||||
|  | ||||
|     _queueUpdateRegions: function() { | ||||
|         if (!this._updateRegionIdle) | ||||
|             this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this._updateRegions), | ||||
|                                                        Meta.PRIORITY_BEFORE_REDRAW); | ||||
|     }, | ||||
|  | ||||
|     _windowsRestacked: function() { | ||||
|         let windows = global.get_window_actors(); | ||||
|         let primary = global.get_primary_monitor(); | ||||
|  | ||||
|         // The chrome layer should be visible unless there is a window | ||||
|         // with layer FULLSCREEN, or a window with layer | ||||
|         // OVERRIDE_REDIRECT that covers the whole screen. | ||||
|         // ('override_redirect' is not actually a layer above all | ||||
|         // other windows, but this seems to be how mutter treats it | ||||
|         // currently...) If we wanted to be extra clever, we could | ||||
|         // figure out when an OVERRIDE_REDIRECT window was trying to | ||||
|         // partially overlap us, and then adjust the input region and | ||||
|         // our clip region accordingly... | ||||
|  | ||||
|         // @windows is sorted bottom to top. | ||||
|  | ||||
|         let wasInFullscreen = this._inFullscreen; | ||||
|         this._inFullscreen = false; | ||||
|         for (let i = windows.length - 1; i > -1; i--) { | ||||
|             let layer = windows[i].get_meta_window().get_layer(); | ||||
|  | ||||
|             // There are 3 cases we check here for: | ||||
|             // 1.) Monitor sized window | ||||
|             // 2.) Window with a position somewhere on the primary screen having the _NET_WM_FULLSCREEN flag set | ||||
|             // 3.) Window that is partly off screen (tries to hide its decorations) which might have negative coords | ||||
|             // We check for 1.) and 2.) by checking if the upper right corner is on the primary monitor, but avoid the case | ||||
|             // where it overlaps with the secondary screen (like window.x + window.width == primary.x + primary.width) | ||||
|             // For 3.) we just ignore negative values as they don't really make sense | ||||
|  | ||||
|             if (layer == Meta.StackLayer.FULLSCREEN) { | ||||
|                 if (Math.max(windows[i].x, 0) >= primary.x && Math.max(windows[i].x, 0) < primary.x + primary.width && | ||||
|                     Math.max(windows[i].y, 0) >= primary.y && Math.max(windows[i].y, 0) < primary.y + primary.height) { | ||||
|                         this._inFullscreen = true; | ||||
|                         break; | ||||
|                 } | ||||
|             } | ||||
|             if (layer == Meta.StackLayer.OVERRIDE_REDIRECT) { | ||||
|                 if (windows[i].x <= primary.x && | ||||
|                     windows[i].x + windows[i].width >= primary.x + primary.width && | ||||
|                     windows[i].y <= primary.y && | ||||
|                     windows[i].y + windows[i].height >= primary.y + primary.height) { | ||||
|                     this._inFullscreen = true; | ||||
|                     break; | ||||
|                 } | ||||
|             } else | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         if (this._inFullscreen != wasInFullscreen) { | ||||
|             this._updateVisibility(); | ||||
|             this._queueUpdateRegions(); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _updateRegions: function() { | ||||
|         let rects = [], struts = [], i; | ||||
|  | ||||
|         delete this._updateRegionIdle; | ||||
|  | ||||
|         for (i = 0; i < this._trackedActors.length; i++) { | ||||
|             let actorData = this._trackedActors[i]; | ||||
|             if (!actorData.affectsInputRegion && !actorData.affectsStruts) | ||||
|                 continue; | ||||
|  | ||||
|             let [x, y] = actorData.actor.get_transformed_position(); | ||||
|             let [w, h] = actorData.actor.get_transformed_size(); | ||||
|             x = Math.round(x); | ||||
|             y = Math.round(y); | ||||
|             w = Math.round(w); | ||||
|             h = Math.round(h); | ||||
|             let rect = new Meta.Rectangle({ x: x, y: y, width: w, height: h}); | ||||
|  | ||||
|             if (actorData.affectsInputRegion && | ||||
|                 actorData.actor.get_paint_visibility() && | ||||
|                 !this.actor.get_skip_paint(actorData.actor)) | ||||
|                 rects.push(rect); | ||||
|  | ||||
|             if (!actorData.affectsStruts) | ||||
|                 continue; | ||||
|  | ||||
|             // Metacity wants to know what side of the screen the | ||||
|             // strut is considered to be attached to. If the actor is | ||||
|             // only touching one edge, or is touching the entire | ||||
|             // width/height of one edge, then it's obvious which side | ||||
|             // to call it. If it's in a corner, we pick a side | ||||
|             // arbitrarily. If it doesn't touch any edges, or it spans | ||||
|             // the width/height across the middle of the screen, then | ||||
|             // we don't create a strut for it at all. | ||||
|             let side; | ||||
|             if (w >= global.screen_width) { | ||||
|                 if (y <= 0) | ||||
|                     side = Meta.Side.TOP; | ||||
|                 else if (y + h >= global.screen_height) | ||||
|                     side = Meta.Side.BOTTOM; | ||||
|                 else | ||||
|                     continue; | ||||
|             } else if (h >= global.screen_height) { | ||||
|                 if (x <= 0) | ||||
|                     side = Meta.Side.LEFT; | ||||
|                 else if (x + w >= global.screen_width) | ||||
|                     side = Meta.Side.RIGHT; | ||||
|                 else | ||||
|                     continue; | ||||
|             } else if (x <= 0) | ||||
|                 side = Meta.Side.LEFT; | ||||
|             else if (y <= 0) | ||||
|                 side = Meta.Side.TOP; | ||||
|             else if (x + w >= global.screen_width) | ||||
|                 side = Meta.Side.RIGHT; | ||||
|             else if (y + h >= global.screen_height) | ||||
|                 side = Meta.Side.BOTTOM; | ||||
|             else | ||||
|                 continue; | ||||
|  | ||||
|             let strut = new Meta.Strut({ rect: rect, side: side }); | ||||
|             struts.push(strut); | ||||
|         } | ||||
|  | ||||
|         global.set_stage_input_region(rects); | ||||
|  | ||||
|         let screen = global.screen; | ||||
|         for (let w = 0; w < screen.n_workspaces; w++) { | ||||
|             let workspace = screen.get_workspace_by_index(w); | ||||
|             workspace.set_builtin_struts(struts); | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
| }; | ||||
| Signals.addSignalMethods(Chrome.prototype); | ||||
| @@ -1,179 +0,0 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Folks = imports.gi.Folks | ||||
| const Lang = imports.lang; | ||||
| const Meta = imports.gi.Meta; | ||||
| const Shell = imports.gi.Shell; | ||||
| const St = imports.gi.St; | ||||
|  | ||||
| const Util = imports.misc.util; | ||||
| const IconGrid = imports.ui.iconGrid; | ||||
| const Search = imports.ui.search; | ||||
| const SearchDisplay = imports.ui.searchDisplay; | ||||
|  | ||||
| const MAX_SEARCH_RESULTS_ROWS = 1; | ||||
| const ICON_SIZE = 81; | ||||
|  | ||||
| function launchContact(id) { | ||||
|     Util.spawn(['gnome-contacts', '-i', id]); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* This class represents a shown contact search result in the overview */ | ||||
| function Contact(id) { | ||||
|     this._init(id); | ||||
| } | ||||
|  | ||||
| Contact.prototype = { | ||||
|     _init: function(id) { | ||||
|         this.individual = Shell.ContactSystem.get_default().get_individual(id); | ||||
|  | ||||
|         this.actor = new St.Bin({ style_class: 'contact', | ||||
|                                   reactive: true, | ||||
|                                   track_hover: true }); | ||||
|  | ||||
|         let content = new St.BoxLayout( { style_class: 'contact-content', | ||||
|                                           vertical: false }); | ||||
|         this.actor.set_child(content); | ||||
|  | ||||
|         let icon = new St.Icon({ icon_type: St.IconType.FULLCOLOR, | ||||
|                                  icon_size: ICON_SIZE, | ||||
|                                  style_class: 'contact-icon' }); | ||||
|         if (this.individual.avatar != null) | ||||
|             icon.gicon = this.individual.avatar; | ||||
|         else | ||||
|             icon.icon_name = 'avatar-default'; | ||||
|  | ||||
|         content.add(icon, { x_fill: true, | ||||
|                             y_fill: false, | ||||
|                             x_align: St.Align.START, | ||||
|                             y_align: St.Align.MIDDLE }); | ||||
|  | ||||
|         let details = new St.BoxLayout({ style_class: 'contact-details', | ||||
|                                          vertical: true }); | ||||
|         content.add(details, { x_fill: true, | ||||
|                                y_fill: false, | ||||
|                                x_align: St.Align.START, | ||||
|                                y_align: St.Align.MIDDLE }); | ||||
|  | ||||
|         let aliasText = this.individual.alias || _("Unknown"); | ||||
|         let aliasLabel = new St.Label({ text: aliasText, | ||||
|                                         style_class: 'contact-details-alias' }); | ||||
|         details.add(aliasLabel, { x_fill: true, | ||||
|                                   y_fill: false, | ||||
|                                   x_align: St.Align.START, | ||||
|                                   y_align: St.Align.START }); | ||||
|  | ||||
|         let presence = this._createPresence(this.individual.presence_type); | ||||
|         details.add(presence, { x_fill: false, | ||||
|                                 y_fill: true, | ||||
|                                 x_align: St.Align.START, | ||||
|                                 y_align: St.Align.END }); | ||||
|     }, | ||||
|  | ||||
|     _createPresence: function(presence) { | ||||
|         let text; | ||||
|         let iconName; | ||||
|  | ||||
|         switch(presence) { | ||||
|           case Folks.PresenceType.AVAILABLE: | ||||
|             text = _("Available"); | ||||
|             iconName = 'user-available'; | ||||
|             break; | ||||
|           case Folks.PresenceType.AWAY: | ||||
|           case Folks.PresenceType.EXTENDED_AWAY: | ||||
|             text = _("Away"); | ||||
|             iconName = 'user-away'; | ||||
|             break; | ||||
|           case Folks.PresenceType.BUSY: | ||||
|             text = _("Busy"); | ||||
|             iconName = 'user-busy'; | ||||
|             break; | ||||
|           default: | ||||
|             text = _("Offline"); | ||||
|             iconName = 'user-offline'; | ||||
|           } | ||||
|  | ||||
|         let icon = new St.Icon({ icon_name: iconName, | ||||
|                                  icon_type: St.IconType.FULLCOLOR, | ||||
|                                  icon_size: 16, | ||||
|                                  style_class: 'contact-details-status-icon' }); | ||||
|         let label = new St.Label({ text: text }); | ||||
|  | ||||
|         let box = new St.BoxLayout({ vertical: false, | ||||
|                                      style_class: 'contact-details-status' }); | ||||
|         box.add(icon, { x_fill: true, | ||||
|                         y_fill: false, | ||||
|                         x_align: St.Align.START, | ||||
|                         y_align: St.Align.START }); | ||||
|  | ||||
|         box.add(label, { x_fill: true, | ||||
|                          y_fill: false, | ||||
|                          x_align: St.Align.END, | ||||
|                          y_align: St.Align.START }); | ||||
|  | ||||
|         return box; | ||||
|     }, | ||||
|  | ||||
|     createIcon: function(size) { | ||||
|         let tc = St.TextureCache.get_default(); | ||||
|         let icon = this.individual.avatar; | ||||
|  | ||||
|         if (icon != null) { | ||||
|             return tc.load_gicon(null, icon, size); | ||||
|         } else { | ||||
|             return tc.load_icon_name(null, 'avatar-default', St.IconType.FULLCOLOR, size); | ||||
|         } | ||||
|     }, | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* Searches for and returns contacts */ | ||||
| function ContactSearchProvider() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| ContactSearchProvider.prototype = { | ||||
|     __proto__: Search.SearchProvider.prototype, | ||||
|  | ||||
|     _init: function() { | ||||
|         Search.SearchProvider.prototype._init.call(this, _("CONTACTS")); | ||||
|         this._contactSys = Shell.ContactSystem.get_default(); | ||||
|     }, | ||||
|  | ||||
|     getResultMeta: function(id) { | ||||
|         let contact = new Contact(id); | ||||
|         return { 'id': id, | ||||
|                  'name': contact.alias, | ||||
|                  'createIcon': function(size) { | ||||
|                          return contact.createIcon(size); | ||||
|                  } | ||||
|         }; | ||||
|     }, | ||||
|  | ||||
|     getInitialResultSet: function(terms) { | ||||
|         return this._contactSys.initial_search(terms); | ||||
|     }, | ||||
|  | ||||
|     getSubsearchResultSet: function(previousResults, terms) { | ||||
|         return this._contactSys.subsearch(previousResults, terms); | ||||
|     }, | ||||
|  | ||||
|     createResultActor: function(resultMeta, terms) { | ||||
|         let contact = new Contact(resultMeta.id); | ||||
|         return contact.actor; | ||||
|     }, | ||||
|  | ||||
|     createResultContainerActor: function() { | ||||
|         let grid = new IconGrid.IconGrid({ rowLimit: MAX_SEARCH_RESULTS_ROWS, | ||||
|                                              xAlign: St.Align.START }); | ||||
|         grid.actor.style_class = 'contact-grid'; | ||||
|  | ||||
|         let actor = new SearchDisplay.GridSearchResults(this, grid); | ||||
|         return actor; | ||||
|     }, | ||||
|  | ||||
|     activateResult: function(id, params) { | ||||
|         launchContact(id); | ||||
|     } | ||||
| }; | ||||
| @@ -1,328 +0,0 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Clutter = imports.gi.Clutter; | ||||
| const Gdk = imports.gi.Gdk; | ||||
| const Gtk = imports.gi.Gtk; | ||||
| const Lang = imports.lang; | ||||
| const Meta = imports.gi.Meta; | ||||
| const Shell = imports.gi.Shell; | ||||
| const St = imports.gi.St; | ||||
|  | ||||
| const AltTab = imports.ui.altTab; | ||||
| const Main = imports.ui.main; | ||||
| const Params = imports.misc.params; | ||||
| const Tweener = imports.ui.tweener; | ||||
|  | ||||
| const POPUP_APPICON_SIZE = 96; | ||||
| const POPUP_FADE_TIME = 0.1; // seconds | ||||
|  | ||||
| const SortGroup = { | ||||
|     TOP:    0, | ||||
|     MIDDLE: 1, | ||||
|     BOTTOM: 2 | ||||
| }; | ||||
|  | ||||
| function CtrlAltTabManager() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| CtrlAltTabManager.prototype = { | ||||
|     _init: function() { | ||||
|         this._items = []; | ||||
|         this._focusManager = St.FocusManager.get_for_stage(global.stage); | ||||
|     }, | ||||
|  | ||||
|     addGroup: function(root, name, icon, params) { | ||||
|         let item = Params.parse(params, { sortGroup: SortGroup.MIDDLE, | ||||
|                                           proxy: root, | ||||
|                                           focusCallback: null }); | ||||
|  | ||||
|         item.root = root; | ||||
|         item.name = name; | ||||
|         item.iconName = icon; | ||||
|  | ||||
|         this._items.push(item); | ||||
|         root.connect('destroy', Lang.bind(this, function() { this.removeGroup(root); })); | ||||
|         this._focusManager.add_group(root); | ||||
|     }, | ||||
|  | ||||
|     removeGroup: function(root) { | ||||
|         this._focusManager.remove_group(root); | ||||
|         for (let i = 0; i < this._items.length; i++) { | ||||
|             if (this._items[i].root == root) { | ||||
|                 this._items.splice(i, 1); | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     focusGroup: function(item) { | ||||
|         if (global.stage_input_mode == Shell.StageInputMode.NONREACTIVE || | ||||
|             global.stage_input_mode == Shell.StageInputMode.NORMAL) | ||||
|             global.set_stage_input_mode(Shell.StageInputMode.FOCUSED); | ||||
|  | ||||
|         if (item.window) | ||||
|             Main.activateWindow(item.window); | ||||
|         else if (item.focusCallback) | ||||
|             item.focusCallback(); | ||||
|         else | ||||
|             item.root.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); | ||||
|     }, | ||||
|  | ||||
|     // Sort the items into a consistent order; panel first, tray last, | ||||
|     // and everything else in between, sorted by X coordinate, so that | ||||
|     // they will have the same left-to-right ordering in the | ||||
|     // Ctrl-Alt-Tab dialog as they do onscreen. | ||||
|     _sortItems: function(a, b) { | ||||
|         if (a.sortGroup != b.sortGroup) | ||||
|             return a.sortGroup - b.sortGroup; | ||||
|  | ||||
|         let y; | ||||
|         if (a.x == undefined) { | ||||
|             if (a.window) | ||||
|                 a.x = a.window.get_compositor_private().x; | ||||
|             else | ||||
|                 [a.x, y] = a.proxy.get_transformed_position(); | ||||
|         } | ||||
|         if (b.x == undefined) { | ||||
|             if (b.window) | ||||
|                 b.x = b.window.get_compositor_private().x; | ||||
|             else | ||||
|                 [b.x, y] = b.proxy.get_transformed_position(); | ||||
|         } | ||||
|  | ||||
|         return a.x - b.x; | ||||
|     }, | ||||
|  | ||||
|     popup: function(backwards) { | ||||
|         // Start with the set of focus groups that are currently mapped | ||||
|         let items = this._items.filter(function (item) { return item.proxy.mapped; }); | ||||
|  | ||||
|         // And add the windows metacity would show in its Ctrl-Alt-Tab list | ||||
|         if (!Main.overview.visible) { | ||||
|             let screen = global.screen; | ||||
|             let display = screen.get_display(); | ||||
|             let windows = display.get_tab_list(Meta.TabList.DOCKS, screen, screen.get_active_workspace ()); | ||||
|             let windowTracker = Shell.WindowTracker.get_default(); | ||||
|             let textureCache = St.TextureCache.get_default(); | ||||
|             for (let i = 0; i < windows.length; i++) { | ||||
|                 let icon; | ||||
|                 let app = windowTracker.get_window_app(windows[i]); | ||||
|                 if (app) | ||||
|                     icon = app.create_icon_texture(POPUP_APPICON_SIZE); | ||||
|                 else | ||||
|                     icon = textureCache.bind_pixbuf_property(windows[i], 'icon'); | ||||
|                 items.push({ window: windows[i], | ||||
|                              name: windows[i].title, | ||||
|                              iconActor: icon, | ||||
|                              sortGroup: SortGroup.MIDDLE }); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (!items.length) | ||||
|             return; | ||||
|  | ||||
|         items.sort(Lang.bind(this, this._sortItems)); | ||||
|         new CtrlAltTabPopup().show(items, backwards); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| function mod(a, b) { | ||||
|     return (a + b) % b; | ||||
| } | ||||
|  | ||||
| function CtrlAltTabPopup() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| CtrlAltTabPopup.prototype = { | ||||
|     _init : function() { | ||||
|         this.actor = new Shell.GenericContainer({ name: 'ctrlAltTabPopup', | ||||
|                                                   reactive: true }); | ||||
|  | ||||
|         this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth)); | ||||
|         this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight)); | ||||
|         this.actor.connect('allocate', Lang.bind(this, this._allocate)); | ||||
|  | ||||
|         this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); | ||||
|  | ||||
|         this._haveModal = false; | ||||
|         this._selection = 0; | ||||
|  | ||||
|         Main.uiGroup.add_actor(this.actor); | ||||
|     }, | ||||
|  | ||||
|     _getPreferredWidth: function (actor, forHeight, alloc) { | ||||
|         let primary = Main.layoutManager.primaryMonitor; | ||||
|  | ||||
|         alloc.min_size = primary.width; | ||||
|         alloc.natural_size = primary.width; | ||||
|     }, | ||||
|  | ||||
|     _getPreferredHeight: function (actor, forWidth, alloc) { | ||||
|         let primary = Main.layoutManager.primaryMonitor; | ||||
|  | ||||
|         alloc.min_size = primary.height; | ||||
|         alloc.natural_size = primary.height; | ||||
|     }, | ||||
|  | ||||
|     _allocate: function (actor, box, flags) { | ||||
|         let childBox = new Clutter.ActorBox(); | ||||
|         let primary = Main.layoutManager.primaryMonitor; | ||||
|  | ||||
|         let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT); | ||||
|         let vPadding = this.actor.get_theme_node().get_vertical_padding(); | ||||
|         let hPadding = this.actor.get_theme_node().get_horizontal_padding(); | ||||
|  | ||||
|         let [childMinHeight, childNaturalHeight] = this._switcher.actor.get_preferred_height(primary.width - hPadding); | ||||
|         let [childMinWidth, childNaturalWidth] = this._switcher.actor.get_preferred_width(childNaturalHeight); | ||||
|         childBox.x1 = Math.max(primary.x + leftPadding, primary.x + Math.floor((primary.width - childNaturalWidth) / 2)); | ||||
|         childBox.x2 = Math.min(primary.width - hPadding, childBox.x1 + childNaturalWidth); | ||||
|         childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2); | ||||
|         childBox.y2 = childBox.y1 + childNaturalHeight; | ||||
|         this._switcher.actor.allocate(childBox, flags); | ||||
|     }, | ||||
|  | ||||
|     show : function(items, startBackwards) { | ||||
|         if (!Main.pushModal(this.actor)) | ||||
|             return false; | ||||
|         this._haveModal = true; | ||||
|  | ||||
|         this._keyPressEventId = this.actor.connect('key-press-event', Lang.bind(this, this._keyPressEvent)); | ||||
|         this._keyReleaseEventId = this.actor.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent)); | ||||
|  | ||||
|         this._items = items; | ||||
|         this._switcher = new CtrlAltTabSwitcher(items); | ||||
|         this.actor.add_actor(this._switcher.actor); | ||||
|  | ||||
|         if (startBackwards) | ||||
|             this._selection = this._items.length - 1; | ||||
|         this._select(this._selection); | ||||
|  | ||||
|         let [x, y, mods] = global.get_pointer(); | ||||
|         if (!(mods & Gdk.ModifierType.MOD1_MASK)) { | ||||
|             this._finish(); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         this.actor.opacity = 0; | ||||
|         this.actor.show(); | ||||
|         Tweener.addTween(this.actor, | ||||
|                          { opacity: 255, | ||||
|                            time: POPUP_FADE_TIME, | ||||
|                            transition: 'easeOutQuad' | ||||
|                          }); | ||||
|  | ||||
|         return true; | ||||
|     }, | ||||
|  | ||||
|     _next : function() { | ||||
|         return mod(this._selection + 1, this._items.length); | ||||
|     }, | ||||
|  | ||||
|     _previous : function() { | ||||
|         return mod(this._selection - 1, this._items.length); | ||||
|     }, | ||||
|  | ||||
|     _keyPressEvent : function(actor, event) { | ||||
|         let keysym = event.get_key_symbol(); | ||||
|         let shift = (Shell.get_event_state(event) & Clutter.ModifierType.SHIFT_MASK); | ||||
|         if (shift && keysym == Clutter.KEY_Tab) | ||||
|             keysym = Clutter.ISO_Left_Tab; | ||||
|  | ||||
|         if (keysym == Clutter.KEY_Escape) | ||||
|             this.destroy(); | ||||
|         else if (keysym == Clutter.KEY_Tab) | ||||
|             this._select(this._next()); | ||||
|         else if (keysym == Clutter.KEY_ISO_Left_Tab) | ||||
|             this._select(this._previous()); | ||||
|         else if (keysym == Clutter.KEY_Left) | ||||
|             this._select(this._previous()); | ||||
|         else if (keysym == Clutter.KEY_Right) | ||||
|             this._select(this._next()); | ||||
|  | ||||
|         return true; | ||||
|     }, | ||||
|  | ||||
|     _keyReleaseEvent : function(actor, event) { | ||||
|         let [x, y, mods] = global.get_pointer(); | ||||
|         let state = mods & Clutter.ModifierType.MOD1_MASK; | ||||
|  | ||||
|         if (state == 0) | ||||
|             this._finish(); | ||||
|  | ||||
|         return true; | ||||
|     }, | ||||
|  | ||||
|     _finish : function() { | ||||
|         this.destroy(); | ||||
|  | ||||
|         Main.ctrlAltTabManager.focusGroup(this._items[this._selection]); | ||||
|     }, | ||||
|  | ||||
|     _popModal: function() { | ||||
|         if (this._haveModal) { | ||||
|             Main.popModal(this.actor); | ||||
|             this._haveModal = false; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     destroy : function() { | ||||
|         this._popModal(); | ||||
|         Tweener.addTween(this.actor, | ||||
|                          { opacity: 0, | ||||
|                            time: POPUP_FADE_TIME, | ||||
|                            transition: 'easeOutQuad', | ||||
|                            onComplete: Lang.bind(this, | ||||
|                                function() { | ||||
|                                    this.actor.destroy(); | ||||
|                                }) | ||||
|                          }); | ||||
|     }, | ||||
|  | ||||
|     _onDestroy : function() { | ||||
|         this._popModal(); | ||||
|         if (this._keyPressEventId) | ||||
|             this.actor.disconnect(this._keyPressEventId); | ||||
|         if (this._keyReleaseEventId) | ||||
|             this.actor.disconnect(this._keyReleaseEventId); | ||||
|     }, | ||||
|  | ||||
|     _select : function(num) { | ||||
|         this._selection = num; | ||||
|         this._switcher.highlight(num); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| function CtrlAltTabSwitcher(items) { | ||||
|     this._init(items); | ||||
| } | ||||
|  | ||||
| CtrlAltTabSwitcher.prototype = { | ||||
|     __proto__ : AltTab.SwitcherList.prototype, | ||||
|  | ||||
|     _init : function(items) { | ||||
|         AltTab.SwitcherList.prototype._init.call(this, true); | ||||
|  | ||||
|         for (let i = 0; i < items.length; i++) | ||||
|             this._addIcon(items[i]); | ||||
|     }, | ||||
|  | ||||
|     _addIcon : function(item) { | ||||
|         let box = new St.BoxLayout({ style_class: 'alt-tab-app', | ||||
|                                      vertical: true }); | ||||
|  | ||||
|         let icon = item.iconActor; | ||||
|         if (!icon) { | ||||
|             icon = new St.Icon({ icon_name: item.iconName, | ||||
|                                  icon_type: St.IconType.SYMBOLIC, | ||||
|                                  icon_size: POPUP_APPICON_SIZE }); | ||||
|         } | ||||
|         box.add(icon, { x_fill: false, y_fill: false } ); | ||||
|  | ||||
|         let text = new St.Label({ text: item.name }); | ||||
|         box.add(text, { x_fill: false }); | ||||
|  | ||||
|         this.addItem(box, text); | ||||
|     } | ||||
| }; | ||||
							
								
								
									
										580
									
								
								js/ui/dash.js
									
									
									
									
									
								
							
							
						
						| @@ -1,188 +1,34 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Clutter = imports.gi.Clutter; | ||||
| const Signals = imports.signals; | ||||
| const Lang = imports.lang; | ||||
| const Meta = imports.gi.Meta; | ||||
| const Shell = imports.gi.Shell; | ||||
| const St = imports.gi.St; | ||||
| const Gettext = imports.gettext.domain('gnome-shell'); | ||||
| const _ = Gettext.gettext; | ||||
|  | ||||
| const AppDisplay = imports.ui.appDisplay; | ||||
| const AppFavorites = imports.ui.appFavorites; | ||||
| const DND = imports.ui.dnd; | ||||
| const IconGrid = imports.ui.iconGrid; | ||||
| const Main = imports.ui.main; | ||||
| const Tweener = imports.ui.tweener; | ||||
| const Workspace = imports.ui.workspace; | ||||
|  | ||||
| const DASH_ANIMATION_TIME = 0.2; | ||||
|  | ||||
| // A container like StBin, but taking the child's scale into account | ||||
| // when requesting a size | ||||
| function DashItemContainer() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| DashItemContainer.prototype = { | ||||
|     _init: function() { | ||||
|         this.actor = new Shell.GenericContainer({ style_class: 'dash-item-container' }); | ||||
|         this.actor.connect('get-preferred-width', | ||||
|                            Lang.bind(this, this._getPreferredWidth)); | ||||
|         this.actor.connect('get-preferred-height', | ||||
|                            Lang.bind(this, this._getPreferredHeight)); | ||||
|         this.actor.connect('allocate', | ||||
|                            Lang.bind(this, this._allocate)); | ||||
|         this.actor._delegate = this; | ||||
|  | ||||
|         this.child = null; | ||||
|         this._childScale = 1; | ||||
|         this._childOpacity = 255; | ||||
|     }, | ||||
|  | ||||
|     _allocate: function(actor, box, flags) { | ||||
|         if (this.child == null) | ||||
|             return; | ||||
|  | ||||
|         let availWidth = box.x2 - box.x1; | ||||
|         let availHeight = box.y2 - box.y1; | ||||
|         let [minChildWidth, minChildHeight, natChildWidth, natChildHeight] = | ||||
|             this.child.get_preferred_size(); | ||||
|         let [childScaleX, childScaleY] = this.child.get_scale(); | ||||
|  | ||||
|         let childWidth = Math.min(natChildWidth * childScaleX, availWidth); | ||||
|         let childHeight = Math.min(natChildHeight * childScaleY, availHeight); | ||||
|  | ||||
|         let childBox = new Clutter.ActorBox(); | ||||
|         childBox.x1 = (availWidth - childWidth) / 2; | ||||
|         childBox.y1 = (availHeight - childHeight) / 2; | ||||
|         childBox.x2 = childBox.x1 + childWidth; | ||||
|         childBox.y2 = childBox.y1 + childHeight; | ||||
|  | ||||
|         this.child.allocate(childBox, flags); | ||||
|     }, | ||||
|  | ||||
|     _getPreferredHeight: function(actor, forWidth, alloc) { | ||||
|         alloc.min_size = 0; | ||||
|         alloc.natural_size = 0; | ||||
|  | ||||
|         if (this.child == null) | ||||
|             return; | ||||
|  | ||||
|         let [minHeight, natHeight] = this.child.get_preferred_height(forWidth); | ||||
|         alloc.min_size += minHeight * this.child.scale_y; | ||||
|         alloc.natural_size += natHeight * this.child.scale_y; | ||||
|     }, | ||||
|  | ||||
|     _getPreferredWidth: function(actor, forHeight, alloc) { | ||||
|         alloc.min_size = 0; | ||||
|         alloc.natural_size = 0; | ||||
|  | ||||
|         if (this.child == null) | ||||
|             return; | ||||
|  | ||||
|         let [minWidth, natWidth] = this.child.get_preferred_width(forHeight); | ||||
|         alloc.min_size = minWidth * this.child.scale_y; | ||||
|         alloc.natural_size = natWidth * this.child.scale_y; | ||||
|     }, | ||||
|  | ||||
|     setChild: function(actor) { | ||||
|         if (this.child == actor) | ||||
|             return; | ||||
|  | ||||
|         this.actor.destroy_children(); | ||||
|  | ||||
|         this.child = actor; | ||||
|         this.actor.add_actor(this.child); | ||||
|     }, | ||||
|  | ||||
|     animateIn: function() { | ||||
|         if (this.child == null) | ||||
|             return; | ||||
|  | ||||
|         this.childScale = 0; | ||||
|         this.childOpacity = 0; | ||||
|         Tweener.addTween(this, | ||||
|                          { childScale: 1.0, | ||||
|                            childOpacity: 255, | ||||
|                            time: DASH_ANIMATION_TIME, | ||||
|                            transition: 'easeOutQuad' | ||||
|                          }); | ||||
|     }, | ||||
|  | ||||
|     animateOutAndDestroy: function() { | ||||
|         if (this.child == null) { | ||||
|             this.actor.destroy(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         this.childScale = 1.0; | ||||
|         Tweener.addTween(this, | ||||
|                          { childScale: 0.0, | ||||
|                            childOpacity: 0, | ||||
|                            time: DASH_ANIMATION_TIME, | ||||
|                            transition: 'easeOutQuad', | ||||
|                            onComplete: Lang.bind(this, function() { | ||||
|                                this.actor.destroy(); | ||||
|                            }) | ||||
|                          }); | ||||
|     }, | ||||
|  | ||||
|     set childScale(scale) { | ||||
|         this._childScale = scale; | ||||
|  | ||||
|         if (this.child == null) | ||||
|             return; | ||||
|  | ||||
|         this.child.set_scale_with_gravity(scale, scale, | ||||
|                                           Clutter.Gravity.CENTER); | ||||
|         this.actor.queue_relayout(); | ||||
|     }, | ||||
|  | ||||
|     get childScale() { | ||||
|         return this._childScale; | ||||
|     }, | ||||
|  | ||||
|     set childOpacity(opacity) { | ||||
|         this._childOpacity = opacity; | ||||
|  | ||||
|         if (this.child == null) | ||||
|             return; | ||||
|  | ||||
|         this.child.set_opacity(opacity); | ||||
|         this.actor.queue_redraw(); | ||||
|     }, | ||||
|  | ||||
|     get childOpacity() { | ||||
|         return this._childOpacity; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| function RemoveFavoriteIcon() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| RemoveFavoriteIcon.prototype = { | ||||
|     __proto__: DashItemContainer.prototype, | ||||
|  | ||||
|     _init: function() { | ||||
|         DashItemContainer.prototype._init.call(this); | ||||
|  | ||||
|         this._iconBin = new St.Bin({ style_class: 'remove-favorite' }); | ||||
|         this.actor = new St.Bin({ style_class: 'remove-favorite' }); | ||||
|         this._iconActor = null; | ||||
|         this.icon = new IconGrid.BaseIcon(_("Remove"), | ||||
|                                            { setSizeManually: true, | ||||
|                                              showLabel: false, | ||||
|                                              createIcon: Lang.bind(this, this._createIcon) }); | ||||
|         this._iconBin.set_child(this.icon.actor); | ||||
|         this._iconBin._delegate = this; | ||||
|  | ||||
|         this.setChild(this._iconBin); | ||||
|         this.hiding = false; | ||||
|     }, | ||||
|  | ||||
|     animateOutAndDestroy: function() { | ||||
|         DashItemContainer.prototype.animateOutAndDestroy.call(this); | ||||
|         this.hiding = true; | ||||
|         this.actor.set_child(this.icon.actor); | ||||
|         this.actor._delegate = this; | ||||
|     }, | ||||
|  | ||||
|     _createIcon: function(size) { | ||||
| @@ -193,7 +39,7 @@ RemoveFavoriteIcon.prototype = { | ||||
|     }, | ||||
|  | ||||
|     setHover: function(hovered) { | ||||
|         this._iconBin.set_hover(hovered); | ||||
|         this.actor.set_hover(hovered); | ||||
|         if (this._iconActor) | ||||
|             this._iconActor.set_hover(hovered); | ||||
|     }, | ||||
| @@ -207,8 +53,8 @@ RemoveFavoriteIcon.prototype = { | ||||
|         let app = null; | ||||
|         if (source instanceof AppDisplay.AppWellIcon) { | ||||
|             let appSystem = Shell.AppSystem.get_default(); | ||||
|             app = appSystem.lookup_app(source.getId()); | ||||
|         } else if (source.metaWindow) { | ||||
|             app = appSystem.get_app(source.getId()); | ||||
|         } else if (source instanceof Workspace.WindowClone) { | ||||
|             let tracker = Shell.WindowTracker.get_default(); | ||||
|             app = tracker.get_window_app(source.metaWindow); | ||||
|         } | ||||
| @@ -226,35 +72,24 @@ RemoveFavoriteIcon.prototype = { | ||||
| }; | ||||
|  | ||||
|  | ||||
| function DragPlaceholderItem() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| DragPlaceholderItem.prototype = { | ||||
|     __proto__: DashItemContainer.prototype, | ||||
|  | ||||
|     _init: function() { | ||||
|         DashItemContainer.prototype._init.call(this); | ||||
|         this.setChild(new St.Bin({ style_class: 'dash-placeholder' })); | ||||
|     } | ||||
| }; | ||||
|  | ||||
|  | ||||
| function Dash() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| Dash.prototype = { | ||||
|     _init : function() { | ||||
|         this._placeholderText = null; | ||||
|         this._menus = []; | ||||
|         this._menuDisplays = []; | ||||
|         this._maxHeight = -1; | ||||
|         this.iconSize = 64; | ||||
|         this._shownInitially = false; | ||||
|         this._iconSize = 48; | ||||
|  | ||||
|         this._dragPlaceholder = null; | ||||
|         this._dragPlaceholderPos = -1; | ||||
|         this._animatingPlaceholdersCount = 0; | ||||
|         this._favRemoveTarget = null; | ||||
|  | ||||
|         this._favorites = []; | ||||
|  | ||||
|         this._box = new St.BoxLayout({ name: 'dash', | ||||
|                                        vertical: true, | ||||
|                                        clip_to_allocation: true }); | ||||
| @@ -275,63 +110,48 @@ Dash.prototype = { | ||||
|  | ||||
|         this._appSystem.connect('installed-changed', Lang.bind(this, this._queueRedisplay)); | ||||
|         AppFavorites.getAppFavorites().connect('changed', Lang.bind(this, this._queueRedisplay)); | ||||
|         this._appSystem.connect('app-state-changed', Lang.bind(this, this._queueRedisplay)); | ||||
|         this._tracker.connect('app-state-changed', Lang.bind(this, this._queueRedisplay)); | ||||
|     }, | ||||
|  | ||||
|         Main.overview.connect('item-drag-begin', | ||||
|                               Lang.bind(this, this._onDragBegin)); | ||||
|         Main.overview.connect('item-drag-end', | ||||
|                               Lang.bind(this, this._onDragEnd)); | ||||
|         Main.overview.connect('item-drag-cancelled', | ||||
|                               Lang.bind(this, this._onDragCancelled)); | ||||
|         Main.overview.connect('window-drag-begin', | ||||
|                               Lang.bind(this, this._onDragBegin)); | ||||
|         Main.overview.connect('window-drag-cancelled', | ||||
|                               Lang.bind(this, this._onDragCancelled)); | ||||
|         Main.overview.connect('window-drag-end', | ||||
|                               Lang.bind(this, this._onDragEnd)); | ||||
|     show: function() { | ||||
|         this._itemDragBeginId = Main.overview.connect('item-drag-begin', | ||||
|             Lang.bind(this, this._onDragBegin)); | ||||
|         this._itemDragEndId = Main.overview.connect('item-drag-end', | ||||
|             Lang.bind(this, this._onDragEnd)); | ||||
|         this._windowDragBeginId = Main.overview.connect('window-drag-begin', | ||||
|             Lang.bind(this, this._onDragBegin)); | ||||
|         this._windowDragEndId = Main.overview.connect('window-drag-end', | ||||
|             Lang.bind(this, this._onDragEnd)); | ||||
|     }, | ||||
|  | ||||
|     hide: function() { | ||||
|         Main.overview.disconnect(this._itemDragBeginId); | ||||
|         Main.overview.disconnect(this._itemDragEndId); | ||||
|         Main.overview.disconnect(this._windowDragBeginId); | ||||
|         Main.overview.disconnect(this._windowDragEndId); | ||||
|     }, | ||||
|  | ||||
|     _onDragBegin: function() { | ||||
|         this._dragCancelled = false; | ||||
|         this._dragMonitor = { | ||||
|             dragMotion: Lang.bind(this, this._onDragMotion) | ||||
|         }; | ||||
|         DND.addDragMonitor(this._dragMonitor); | ||||
|     }, | ||||
|  | ||||
|     _onDragCancelled: function() { | ||||
|         this._dragCancelled = true; | ||||
|         this._endDrag(); | ||||
|     }, | ||||
|  | ||||
|     _onDragEnd: function() { | ||||
|         if (this._dragCancelled) | ||||
|             return; | ||||
|  | ||||
|         this._endDrag(); | ||||
|     }, | ||||
|  | ||||
|     _endDrag: function() { | ||||
|         this._clearDragPlaceholder(); | ||||
|         if (this._favRemoveTarget) { | ||||
|             this._favRemoveTarget.actor.hide(); | ||||
|             this._adjustIconSize(); | ||||
|             this._favRemoveTarget.actor.show(); | ||||
|  | ||||
|             this._favRemoveTarget.animateOutAndDestroy(); | ||||
|             this._favRemoveTarget.actor.connect('destroy', Lang.bind(this, | ||||
|                 function() { | ||||
|                     this._favRemoveTarget = null; | ||||
|                 })); | ||||
|             this._favRemoveTarget.actor.destroy(); | ||||
|             this._favRemoveTarget = null; | ||||
|         } | ||||
|         DND.removeDragMonitor(this._dragMonitor); | ||||
|         DND.removeMonitor(this._dragMonitor); | ||||
|     }, | ||||
|  | ||||
|     _onDragMotion: function(dragEvent) { | ||||
|         let app = null; | ||||
|         if (dragEvent.source instanceof AppDisplay.AppWellIcon) | ||||
|             app = this._appSystem.lookup_app(dragEvent.source.getId()); | ||||
|         else if (dragEvent.source.metaWindow) | ||||
|             app = this._appSystem.get_app(dragEvent.source.getId()); | ||||
|         else if (dragEvent.source instanceof Workspace.WindowClone) | ||||
|             app = this._tracker.get_window_app(dragEvent.source.metaWindow); | ||||
|         else | ||||
|             return DND.DragMotionResult.CONTINUE; | ||||
| @@ -342,15 +162,10 @@ Dash.prototype = { | ||||
|  | ||||
|         let srcIsFavorite = (id in favorites); | ||||
|  | ||||
|         if (srcIsFavorite && | ||||
|             dragEvent.source.actor && | ||||
|             this.actor.contains (dragEvent.source.actor) && | ||||
|             this._favRemoveTarget == null) { | ||||
|         if (srcIsFavorite && this._favRemoveTarget == null) { | ||||
|                 this._favRemoveTarget = new RemoveFavoriteIcon(); | ||||
|                 this._favRemoveTarget.icon.setIconSize(this.iconSize); | ||||
|                 this._favRemoveTarget.icon.setIconSize(this._iconSize); | ||||
|                 this._box.add(this._favRemoveTarget.actor); | ||||
|                 this._adjustIconSize(); | ||||
|                 this._favRemoveTarget.animateIn(); | ||||
|         } | ||||
|  | ||||
|         let favRemoveHovered = false; | ||||
| @@ -378,10 +193,8 @@ Dash.prototype = { | ||||
|         Main.queueDeferredWork(this._workId); | ||||
|     }, | ||||
|  | ||||
|     _createAppItem: function(app) { | ||||
|         let display = new AppDisplay.AppWellIcon(app, | ||||
|                                                  { setSizeManually: true, | ||||
|                                                    showLabel: false }); | ||||
|     _addApp: function(app) { | ||||
|         let display = new AppDisplay.AppWellIcon(app); | ||||
|         display._draggable.connect('drag-begin', | ||||
|                                    Lang.bind(this, function() { | ||||
|                                        display.actor.opacity = 50; | ||||
| @@ -390,225 +203,63 @@ Dash.prototype = { | ||||
|                                    Lang.bind(this, function() { | ||||
|                                        display.actor.opacity = 255; | ||||
|                                    })); | ||||
|         display.actor.set_tooltip_text(app.get_name()); | ||||
|  | ||||
|         let item = new DashItemContainer(); | ||||
|         item.setChild(display.actor); | ||||
|  | ||||
|         display.icon.setIconSize(this.iconSize); | ||||
|  | ||||
|         return item; | ||||
|     }, | ||||
|  | ||||
|     _adjustIconSize: function() { | ||||
|         let children = this._box.get_children(); | ||||
|         if (children.length == 0) { | ||||
|             this._box.add_style_pseudo_class('empty'); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         this._box.remove_style_pseudo_class('empty'); | ||||
|  | ||||
|         if (this._maxHeight == -1) | ||||
|             return; | ||||
|  | ||||
|         let iconChildren = children.filter(function(actor) { | ||||
|             return actor.visible && | ||||
|                    actor._delegate.child && | ||||
|                    actor._delegate.child._delegate && | ||||
|                    actor._delegate.child._delegate.icon; | ||||
|         }); | ||||
|  | ||||
|         // Compute the amount of extra space (or missing space) we have | ||||
|         // per icon with the current icon size | ||||
|         let [minHeight, natHeight] = this.actor.get_preferred_height(-1); | ||||
|         let diff = (this._maxHeight - natHeight) / iconChildren.length; | ||||
|  | ||||
|         let iconSizes = [ 16, 22, 24, 32, 48, 64 ]; | ||||
|  | ||||
|         let newIconSize = 16; | ||||
|         for (let i = 0; i < iconSizes.length; i++) { | ||||
|             if (iconSizes[i] < this.iconSize + diff) | ||||
|                 newIconSize = iconSizes[i]; | ||||
|         } | ||||
|  | ||||
|         if (newIconSize == this.iconSize) | ||||
|             return; | ||||
|  | ||||
|         let oldIconSize = this.iconSize; | ||||
|         this.iconSize = newIconSize; | ||||
|         this.emit('icon-size-changed'); | ||||
|  | ||||
|         let scale = oldIconSize / newIconSize; | ||||
|         for (let i = 0; i < iconChildren.length; i++) { | ||||
|             let icon = iconChildren[i]._delegate.child._delegate.icon; | ||||
|  | ||||
|             // Set the new size immediately, to keep the icons' sizes | ||||
|             // in sync with this.iconSize | ||||
|             icon.setIconSize(this.iconSize); | ||||
|  | ||||
|             // Don't animate the icon size change when the overview | ||||
|             // is not visible or when initially filling the dash | ||||
|             if (!Main.overview.visible || !this._shownInitially) | ||||
|                 continue; | ||||
|  | ||||
|             let [targetWidth, targetHeight] = icon.icon.get_size(); | ||||
|  | ||||
|             // Scale the icon's texture to the previous size and | ||||
|             // tween to the new size | ||||
|             icon.icon.set_size(icon.icon.width * scale, | ||||
|                                icon.icon.height * scale); | ||||
|  | ||||
|             Tweener.addTween(icon.icon, | ||||
|                              { width: targetWidth, | ||||
|                                height: targetHeight, | ||||
|                                time: DASH_ANIMATION_TIME, | ||||
|                                transition: 'easeOutQuad' | ||||
|                              }); | ||||
|         } | ||||
|         this._box.add(display.actor); | ||||
|     }, | ||||
|  | ||||
|     _redisplay: function () { | ||||
|         this._box.hide(); | ||||
|         this._box.remove_all(); | ||||
|  | ||||
|         let favorites = AppFavorites.getAppFavorites().getFavoriteMap(); | ||||
|  | ||||
|         let running = this._appSystem.get_running(); | ||||
|         /* hardcode here pending some design about how exactly desktop contexts behave */ | ||||
|         let contextId = ''; | ||||
|  | ||||
|         let children = this._box.get_children().filter(function(actor) { | ||||
|                 return actor._delegate.child && | ||||
|                        actor._delegate.child._delegate && | ||||
|                        actor._delegate.child._delegate.app; | ||||
|             }); | ||||
|         // Apps currently in the dash | ||||
|         let oldApps = children.map(function(actor) { | ||||
|                 return actor._delegate.child._delegate.app; | ||||
|             }); | ||||
|         // Apps supposed to be in the dash | ||||
|         let newApps = []; | ||||
|         let running = this._tracker.get_running_apps(contextId); | ||||
|         let runningIds = this._appIdListToHash(running); | ||||
|  | ||||
|         for (let id in favorites) | ||||
|             newApps.push(favorites[id]); | ||||
|         for (let id in favorites) { | ||||
|             let app = favorites[id]; | ||||
|             this._addApp(app); | ||||
|         } | ||||
|  | ||||
|         for (let i = 0; i < running.length; i++) { | ||||
|             let app = running[i]; | ||||
|             if (app.get_id() in favorites) | ||||
|                 continue; | ||||
|             newApps.push(app); | ||||
|             this._addApp(app); | ||||
|         } | ||||
|         if (this._placeholderText) { | ||||
|             this._placeholderText.destroy(); | ||||
|             this._placeholderText = null; | ||||
|         } | ||||
|  | ||||
|         // Figure out the actual changes to the list of items; we iterate | ||||
|         // over both the list of items currently in the dash and the list | ||||
|         // of items expected there, and collect additions and removals. | ||||
|         // Moves are both an addition and a removal, where the order of | ||||
|         // the operations depends on whether we encounter the position | ||||
|         // where the item has been added first or the one from where it | ||||
|         // was removed. | ||||
|         // There is an assumption that only one item is moved at a given | ||||
|         // time; when moving several items at once, everything will still | ||||
|         // end up at the right position, but there might be additional | ||||
|         // additions/removals (e.g. it might remove all the launchers | ||||
|         // and add them back in the new order even if a smaller set of | ||||
|         // additions and removals is possible). | ||||
|         // If above assumptions turns out to be a problem, we might need | ||||
|         // to use a more sophisticated algorithm, e.g. Longest Common | ||||
|         // Subsequence as used by diff. | ||||
|         let addedItems = []; | ||||
|         let removedActors = []; | ||||
|         let children = this._box.get_children(); | ||||
|         if (children.length == 0) { | ||||
|             this._placeholderText = new St.Label({ text: _("Drag here to add favorites") }); | ||||
|             this._box.add_actor(this._placeholderText); | ||||
|         } else if (this._maxHeight > -1) { | ||||
|             let iconSizes = [ 48, 32, 24, 22, 16 ]; | ||||
|  | ||||
|         let newIndex = 0; | ||||
|         let oldIndex = 0; | ||||
|         while (newIndex < newApps.length || oldIndex < oldApps.length) { | ||||
|             // No change at oldIndex/newIndex | ||||
|             if (oldApps[oldIndex] == newApps[newIndex]) { | ||||
|                 oldIndex++; | ||||
|                 newIndex++; | ||||
|                 continue; | ||||
|             } | ||||
|             for (let i = 0; i < iconSizes.length; i++) { | ||||
|                 let minHeight, natHeight; | ||||
|  | ||||
|             // App removed at oldIndex | ||||
|             if (oldApps[oldIndex] && | ||||
|                 newApps.indexOf(oldApps[oldIndex]) == -1) { | ||||
|                 removedActors.push(children[oldIndex]); | ||||
|                 oldIndex++; | ||||
|                 continue; | ||||
|             } | ||||
|                 this._iconSize = iconSizes[i]; | ||||
|                 for (let j = 0; j < children.length; j++) | ||||
|                     children[j]._delegate.icon.setIconSize(this._iconSize); | ||||
|  | ||||
|             // App added at newIndex | ||||
|             if (newApps[newIndex] && | ||||
|                 oldApps.indexOf(newApps[newIndex]) == -1) { | ||||
|                 addedItems.push({ app: newApps[newIndex], | ||||
|                                   item: this._createAppItem(newApps[newIndex]), | ||||
|                                   pos: newIndex }); | ||||
|                 newIndex++; | ||||
|                 continue; | ||||
|             } | ||||
|                 [minHeight, natHeight] = this.actor.get_preferred_height(-1); | ||||
|  | ||||
|             // App moved | ||||
|             let insertHere = newApps[newIndex + 1] && | ||||
|                              newApps[newIndex + 1] == oldApps[oldIndex]; | ||||
|             let alreadyRemoved = removedActors.reduce(function(result, actor) { | ||||
|                 let removedApp = actor._delegate.child._delegate.app; | ||||
|                 return result || removedApp == newApps[newIndex]; | ||||
|             }, false); | ||||
|  | ||||
|             if (insertHere || alreadyRemoved) { | ||||
|                 let newItem = this._createAppItem(newApps[newIndex]); | ||||
|                 addedItems.push({ app: newApps[newIndex], | ||||
|                                   item: newItem, | ||||
|                                   pos: newIndex + removedActors.length }); | ||||
|                 newIndex++; | ||||
|             } else { | ||||
|                 removedActors.push(children[oldIndex]); | ||||
|                 oldIndex++; | ||||
|                 if (natHeight <= this._maxHeight) | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         for (let i = 0; i < addedItems.length; i++) | ||||
|             this._box.insert_actor(addedItems[i].item.actor, | ||||
|                                    addedItems[i].pos); | ||||
|  | ||||
|         // Hide removed actors to not take them into account | ||||
|         // when adjusting the icon size ... | ||||
|         for (let i = 0; i < removedActors.length; i++) | ||||
|             removedActors[i].hide(); | ||||
|  | ||||
|         // ... and do the same for the remove target if necessary | ||||
|         if (this._favRemoveTarget && this._favRemoveTarget.hiding) | ||||
|             this._favRemoveTarget.actor.hide(); | ||||
|  | ||||
|         this._adjustIconSize(); | ||||
|  | ||||
|         if (this._favRemoveTarget && this._favRemoveTarget.hiding) | ||||
|             this._favRemoveTarget.actor.show(); | ||||
|  | ||||
|         // Skip animations on first run when adding the initial set | ||||
|         // of items, to avoid all items zooming in at once | ||||
|         if (!this._shownInitially) { | ||||
|             this._shownInitially = true; | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         for (let i = 0; i < removedActors.length; i++) { | ||||
|             removedActors[i].show(); | ||||
|             let item = removedActors[i]._delegate; | ||||
|  | ||||
|             // Don't animate item removal when the overview is hidden | ||||
|             if (Main.overview.visible) | ||||
|                 item.animateOutAndDestroy(); | ||||
|             else | ||||
|                 item.actor.destroy(); | ||||
|         } | ||||
|  | ||||
|         // Don't animate item addition when the overview is hidden | ||||
|         if (!Main.overview.visible) | ||||
|             return; | ||||
|  | ||||
|         for (let i = 0; i < addedItems.length; i++) | ||||
|             addedItems[i].item.animateIn(); | ||||
|         this._box.show(); | ||||
|     }, | ||||
|  | ||||
|     _clearDragPlaceholder: function() { | ||||
|         if (this._dragPlaceholder) { | ||||
|             this._dragPlaceholder.animateOutAndDestroy(); | ||||
|             this._dragPlaceholder.destroy(); | ||||
|             this._dragPlaceholder = null; | ||||
|             this._dragPlaceholderPos = -1; | ||||
|         } | ||||
| @@ -617,80 +268,41 @@ Dash.prototype = { | ||||
|     handleDragOver : function(source, actor, x, y, time) { | ||||
|         let app = null; | ||||
|         if (source instanceof AppDisplay.AppWellIcon) | ||||
|             app = this._appSystem.lookup_app(source.getId()); | ||||
|         else if (source.metaWindow) | ||||
|             app = this._appSystem.get_app(source.getId()); | ||||
|         else if (source instanceof Workspace.WindowClone) | ||||
|             app = this._tracker.get_window_app(source.metaWindow); | ||||
|  | ||||
|         // Don't allow favoriting of transient apps | ||||
|         if (app == null || app.is_window_backed()) | ||||
|         if (app == null || app.is_transient()) | ||||
|             return DND.DragMotionResult.NO_DROP; | ||||
|  | ||||
|         let favorites = AppFavorites.getAppFavorites().getFavorites(); | ||||
|         let numFavorites = favorites.length; | ||||
|  | ||||
|         let favPos = favorites.indexOf(app); | ||||
|  | ||||
|         let children = this._box.get_children(); | ||||
|         let numChildren = children.length; | ||||
|         let numFavorites = AppFavorites.getAppFavorites().getFavorites().length; | ||||
|         let numChildren = this._box.get_children().length; | ||||
|         let boxHeight = this._box.height; | ||||
|  | ||||
|         // Keep the placeholder out of the index calculation; assuming that | ||||
|         // the remove target has the same size as "normal" items, we don't | ||||
|         // need to do the same adjustment there. | ||||
|         if (this._dragPlaceholder) { | ||||
|             boxHeight -= this._dragPlaceholder.actor.height; | ||||
|             boxHeight -= this._dragPlaceholder.height; | ||||
|             numChildren--; | ||||
|         } | ||||
|  | ||||
|         let pos = Math.round(y * numChildren / boxHeight); | ||||
|  | ||||
|         if (pos != this._dragPlaceholderPos && pos <= numFavorites) { | ||||
|             if (this._animatingPlaceholdersCount > 0) { | ||||
|                 let appChildren = children.filter(function(actor) { | ||||
|                     return actor._delegate && | ||||
|                            actor._delegate.child && | ||||
|                            actor._delegate.child._delegate && | ||||
|                            actor._delegate.child._delegate.app; | ||||
|                 }); | ||||
|                 this._dragPlaceholderPos = children.indexOf(appChildren[pos]); | ||||
|             } else { | ||||
|                 this._dragPlaceholderPos = pos; | ||||
|             } | ||||
|  | ||||
|             // Don't allow positioning before or after self | ||||
|             if (favPos != -1 && (pos == favPos || pos == favPos + 1)) { | ||||
|                 if (this._dragPlaceholder) { | ||||
|                     this._dragPlaceholder.animateOutAndDestroy(); | ||||
|                     this._animatingPlaceholdersCount++; | ||||
|                     this._dragPlaceholder.actor.connect('destroy', | ||||
|                         Lang.bind(this, function() { | ||||
|                             this._animatingPlaceholdersCount--; | ||||
|                         })); | ||||
|                 } | ||||
|                 this._dragPlaceholder = null; | ||||
|  | ||||
|                 return DND.DragMotionResult.CONTINUE; | ||||
|             } | ||||
|  | ||||
|             // If the placeholder already exists, we just move | ||||
|             // it, but if we are adding it, expand its size in | ||||
|             // an animation | ||||
|             let fadeIn; | ||||
|             if (this._dragPlaceholder) { | ||||
|                 this._dragPlaceholder.actor.destroy(); | ||||
|                 fadeIn = false; | ||||
|             } else { | ||||
|                 fadeIn = true; | ||||
|             } | ||||
|  | ||||
|             this._dragPlaceholder = new DragPlaceholderItem(); | ||||
|             this._box.insert_actor(this._dragPlaceholder.actor, | ||||
|                                    this._dragPlaceholderPos); | ||||
|             if (fadeIn) | ||||
|                 this._dragPlaceholder.animateIn(); | ||||
|             this._dragPlaceholderPos = pos; | ||||
|             if (this._dragPlaceholder) | ||||
|                 this._dragPlaceholder.destroy(); | ||||
|             this._dragPlaceholder = new St.Bin({ style_class: 'dash-placeholder' }); | ||||
|             this._box.insert_actor(this._dragPlaceholder, pos); | ||||
|         } | ||||
|  | ||||
|         let srcIsFavorite = (favPos != -1); | ||||
|         let id = app.get_id(); | ||||
|  | ||||
|         let favorites = AppFavorites.getAppFavorites().getFavoriteMap(); | ||||
|  | ||||
|         let srcIsFavorite = (id in favorites); | ||||
|  | ||||
|         if (srcIsFavorite) | ||||
|             return DND.DragMotionResult.MOVE_DROP; | ||||
| @@ -702,13 +314,13 @@ Dash.prototype = { | ||||
|     acceptDrop : function(source, actor, x, y, time) { | ||||
|         let app = null; | ||||
|         if (source instanceof AppDisplay.AppWellIcon) { | ||||
|             app = this._appSystem.lookup_app(source.getId()); | ||||
|         } else if (source.metaWindow) { | ||||
|             app = this._appSystem.get_app(source.getId()); | ||||
|         } else if (source instanceof Workspace.WindowClone) { | ||||
|             app = this._tracker.get_window_app(source.metaWindow); | ||||
|         } | ||||
|  | ||||
|         // Don't allow favoriting of transient apps | ||||
|         if (app == null || app.is_window_backed()) { | ||||
|         if (app == null || app.is_transient()) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
| @@ -721,11 +333,7 @@ Dash.prototype = { | ||||
|         let favPos = 0; | ||||
|         let children = this._box.get_children(); | ||||
|         for (let i = 0; i < this._dragPlaceholderPos; i++) { | ||||
|             if (this._dragPlaceholder && | ||||
|                 children[i] == this._dragPlaceholder.actor) | ||||
|                 continue; | ||||
|  | ||||
|             let childId = children[i]._delegate.child._delegate.app.get_id(); | ||||
|             let childId = children[i]._delegate.app.get_id(); | ||||
|             if (childId == id) | ||||
|                 continue; | ||||
|             if (childId in favorites) | ||||
|   | ||||
| @@ -1,242 +0,0 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const GLib = imports.gi.GLib; | ||||
| const Gio = imports.gi.Gio; | ||||
| const Lang = imports.lang; | ||||
| const Mainloop = imports.mainloop; | ||||
| const Cairo = imports.cairo; | ||||
| const Clutter = imports.gi.Clutter; | ||||
| const Shell = imports.gi.Shell; | ||||
| const St = imports.gi.St; | ||||
|  | ||||
| const Params = imports.misc.params; | ||||
| const Util = imports.misc.util; | ||||
| const Main = imports.ui.main; | ||||
| const PanelMenu = imports.ui.panelMenu; | ||||
| const PopupMenu = imports.ui.popupMenu; | ||||
| const Calendar = imports.ui.calendar; | ||||
| const UPowerGlib = imports.gi.UPowerGlib; | ||||
|  | ||||
| // in org.gnome.desktop.interface | ||||
| const CLOCK_FORMAT_KEY        = 'clock-format'; | ||||
|  | ||||
| // in org.gnome.shell.clock | ||||
| const CLOCK_SHOW_DATE_KEY     = 'show-date'; | ||||
| const CLOCK_SHOW_SECONDS_KEY  = 'show-seconds'; | ||||
|  | ||||
| function _onVertSepRepaint (area) | ||||
| { | ||||
|     let cr = area.get_context(); | ||||
|     let themeNode = area.get_theme_node(); | ||||
|     let [width, height] = area.get_surface_size(); | ||||
|     let stippleColor = themeNode.get_color('-stipple-color'); | ||||
|     let stippleWidth = themeNode.get_length('-stipple-width'); | ||||
|     let x = Math.floor(width/2) + 0.5; | ||||
|     cr.moveTo(x, 0); | ||||
|     cr.lineTo(x, height); | ||||
|     Clutter.cairo_set_source_color(cr, stippleColor); | ||||
|     cr.setDash([1, 3], 1); // Hard-code for now | ||||
|     cr.setLineWidth(stippleWidth); | ||||
|     cr.stroke(); | ||||
| }; | ||||
|  | ||||
| function DateMenuButton() { | ||||
|     this._init.apply(this, arguments); | ||||
| } | ||||
|  | ||||
| DateMenuButton.prototype = { | ||||
|     __proto__: PanelMenu.Button.prototype, | ||||
|  | ||||
|     _init: function(params) { | ||||
|         params = Params.parse(params, { showEvents: true }); | ||||
|  | ||||
|         let item; | ||||
|         let hbox; | ||||
|         let vbox; | ||||
|  | ||||
|         let menuAlignment = 0.25; | ||||
|         if (St.Widget.get_default_direction() == St.TextDirection.RTL) | ||||
|             menuAlignment = 1.0 - menuAlignment; | ||||
|         PanelMenu.Button.prototype._init.call(this, menuAlignment); | ||||
|  | ||||
|         this._clock = new St.Label(); | ||||
|         this.actor.set_child(this._clock); | ||||
|  | ||||
|         hbox = new St.BoxLayout({name: 'calendarArea' }); | ||||
|         this.menu.addActor(hbox); | ||||
|  | ||||
|         // Fill up the first column | ||||
|  | ||||
|         vbox = new St.BoxLayout({vertical: true}); | ||||
|         hbox.add(vbox); | ||||
|  | ||||
|         // Date | ||||
|         this._date = new St.Label(); | ||||
|         this._date.style_class = 'datemenu-date-label'; | ||||
|         vbox.add(this._date); | ||||
|  | ||||
|         if (params.showEvents) { | ||||
|             this._eventSource = new Calendar.DBusEventSource(); | ||||
|             this._eventList = new Calendar.EventsList(this._eventSource); | ||||
|         } else { | ||||
|             this._eventSource = null; | ||||
|             this._eventList = null; | ||||
|         } | ||||
|  | ||||
|         // Calendar | ||||
|         this._calendar = new Calendar.Calendar(this._eventSource); | ||||
|  | ||||
|         this._calendar.connect('selected-date-changed', | ||||
|                                Lang.bind(this, function(calendar, date) { | ||||
|                                   // we know this._eventList is defined here, because selected-data-changed | ||||
|                                   // only gets emitted when the user clicks a date in the calendar, | ||||
|                                   // and the calender makes those dates unclickable when instantiated with | ||||
|                                   // a null event source | ||||
|                                    this._eventList.setDate(date); | ||||
|                                })); | ||||
|         vbox.add(this._calendar.actor); | ||||
|  | ||||
|         item = this.menu.addSettingsAction(_("Date and Time Settings"), 'gnome-datetime-panel.desktop'); | ||||
|         if (item) { | ||||
|             let separator = new PopupMenu.PopupSeparatorMenuItem(); | ||||
|             separator.setColumnWidths(1); | ||||
|             vbox.add(separator.actor, {y_align: St.Align.END, expand: true, y_fill: false}); | ||||
|  | ||||
|             item.actor.can_focus = false; | ||||
|             item.actor.reparent(vbox); | ||||
|         } | ||||
|  | ||||
|         if (params.showEvents) { | ||||
|             // Add vertical separator | ||||
|  | ||||
|             item = new St.DrawingArea({ style_class: 'calendar-vertical-separator', | ||||
|                                         pseudo_class: 'highlighted' }); | ||||
|             item.connect('repaint', Lang.bind(this, _onVertSepRepaint)); | ||||
|             hbox.add(item); | ||||
|  | ||||
|             // Fill up the second column | ||||
|             vbox = new St.BoxLayout({name:     'calendarEventsArea', | ||||
|                                      vertical: true}); | ||||
|             hbox.add(vbox, { expand: true }); | ||||
|  | ||||
|             // Event list | ||||
|             vbox.add(this._eventList.actor, { expand: true }); | ||||
|  | ||||
|             item = new PopupMenu.PopupMenuItem(_("Open Calendar")); | ||||
|             item.connect('activate', Lang.bind(this, this._onOpenCalendarActivate)); | ||||
|             item.actor.can_focus = false; | ||||
|             vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false}); | ||||
|         } | ||||
|  | ||||
|         // Whenever the menu is opened, select today | ||||
|         this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) { | ||||
|             if (isOpen) { | ||||
|                 let now = new Date(); | ||||
|                 /* Passing true to setDate() forces events to be reloaded. We | ||||
|                  * want this behavior, because | ||||
|                  * | ||||
|                  *   o It will cause activation of the calendar server which is | ||||
|                  *     useful if it has crashed | ||||
|                  * | ||||
|                  *   o It will cause the calendar server to reload events which | ||||
|                  *     is useful if dynamic updates are not supported or not | ||||
|                  *     properly working | ||||
|                  * | ||||
|                  * Since this only happens when the menu is opened, the cost | ||||
|                  * isn't very big. | ||||
|                  */ | ||||
|                 this._calendar.setDate(now, true); | ||||
|                 // No need to update this._eventList as ::selected-date-changed | ||||
|                 // signal will fire | ||||
|             } | ||||
|         })); | ||||
|  | ||||
|         // Done with hbox for calendar and event list | ||||
|  | ||||
|         // Track changes to clock settings | ||||
|         this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' }); | ||||
|         this._clockSettings = new Gio.Settings({ schema: 'org.gnome.shell.clock' }); | ||||
|         this._desktopSettings.connect('changed', Lang.bind(this, this._updateClockAndDate)); | ||||
|         this._clockSettings.connect('changed', Lang.bind(this, this._updateClockAndDate)); | ||||
|  | ||||
|         // https://bugzilla.gnome.org/show_bug.cgi?id=655129 | ||||
|         this._upClient = new UPowerGlib.Client(); | ||||
|         this._upClient.connect('notify-resume', Lang.bind(this, this._updateClockAndDate)); | ||||
|  | ||||
|         // Start the clock | ||||
|         this._updateClockAndDate(); | ||||
|     }, | ||||
|  | ||||
|     _updateClockAndDate: function() { | ||||
|         let format = this._desktopSettings.get_string(CLOCK_FORMAT_KEY); | ||||
|         let showDate = this._clockSettings.get_boolean(CLOCK_SHOW_DATE_KEY); | ||||
|         let showSeconds = this._clockSettings.get_boolean(CLOCK_SHOW_SECONDS_KEY); | ||||
|  | ||||
|         let clockFormat; | ||||
|         let dateFormat; | ||||
|  | ||||
|         switch (format) { | ||||
|             case '24h': | ||||
|                 if (showDate) | ||||
|                     /* Translators: This is the time format with date used | ||||
|                        in 24-hour mode. */ | ||||
|                     clockFormat = showSeconds ? _("%a %b %e, %R:%S") | ||||
|                                               : _("%a %b %e, %R"); | ||||
|                 else | ||||
|                     /* Translators: This is the time format without date used | ||||
|                        in 24-hour mode. */ | ||||
|                     clockFormat = showSeconds ? _("%a %R:%S") | ||||
|                                               : _("%a %R"); | ||||
|                 break; | ||||
|             case '12h': | ||||
|             default: | ||||
|                 if (showDate) | ||||
|                     /* Translators: This is a time format with date used | ||||
|                        for AM/PM. */ | ||||
|                     clockFormat = showSeconds ? _("%a %b %e, %l:%M:%S %p") | ||||
|                                               : _("%a %b %e, %l:%M %p"); | ||||
|                 else | ||||
|                     /* Translators: This is a time format without date used | ||||
|                        for AM/PM. */ | ||||
|                     clockFormat = showSeconds ? _("%a %l:%M:%S %p") | ||||
|                                               : _("%a %l:%M %p"); | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         let displayDate = new Date(); | ||||
|  | ||||
|         this._clock.set_text(displayDate.toLocaleFormat(clockFormat)); | ||||
|  | ||||
|         /* Translators: This is the date format to use when the calendar popup is | ||||
|          * shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM"). | ||||
|          */ | ||||
|         dateFormat = _("%A %B %e, %Y"); | ||||
|         this._date.set_text(displayDate.toLocaleFormat(dateFormat)); | ||||
|  | ||||
|         Mainloop.timeout_add_seconds(1, Lang.bind(this, this._updateClockAndDate)); | ||||
|         return false; | ||||
|     }, | ||||
|  | ||||
|     _onOpenCalendarActivate: function() { | ||||
|         this.menu.close(); | ||||
|         let calendarSettings = new Gio.Settings({ schema: 'org.gnome.desktop.default-applications.office.calendar' }); | ||||
|         let tool = calendarSettings.get_string('exec'); | ||||
|         if (tool.length == 0 || tool == 'evolution') { | ||||
|             // TODO: pass the selected day | ||||
|             Util.spawn(['evolution', '-c', 'calendar']); | ||||
|         } else { | ||||
|             let needTerm = calendarSettings.get_boolean('needs-term'); | ||||
|             if (needTerm) { | ||||
|                 let terminalSettings = new Gio.Settings({ schema: 'org.gnome.desktop.default-applications.terminal' }); | ||||
|                 let term = terminalSettings.get_string('exec'); | ||||
|                 let arg = terminalSettings.get_string('exec-arg'); | ||||
|                 if (arg != '') | ||||
|                     Util.spawn([term, arg, tool]); | ||||
|                 else | ||||
|                     Util.spawn([term, tool]); | ||||
|             } else { | ||||
|                 Util.spawnCommandLine(tool) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| }; | ||||
							
								
								
									
										141
									
								
								js/ui/dnd.js
									
									
									
									
									
								
							
							
						
						| @@ -26,9 +26,9 @@ const DragMotionResult = { | ||||
| }; | ||||
|  | ||||
| const DRAG_CURSOR_MAP = { | ||||
|     0: Shell.Cursor.DND_UNSUPPORTED_TARGET, | ||||
|     1: Shell.Cursor.DND_COPY, | ||||
|     2: Shell.Cursor.DND_MOVE | ||||
|     0: Shell.Cursor.UNSUPPORTED_TARGET, | ||||
|     1: Shell.Cursor.COPY, | ||||
|     2: Shell.Cursor.MOVE | ||||
| }; | ||||
|  | ||||
| const DragDropResult = { | ||||
| @@ -61,7 +61,7 @@ function addDragMonitor(monitor) { | ||||
|     dragMonitors.push(monitor); | ||||
| } | ||||
|  | ||||
| function removeDragMonitor(monitor) { | ||||
| function removeMonitor(monitor) { | ||||
|     for (let i = 0; i < dragMonitors.length; i++) | ||||
|         if (dragMonitors[i] == monitor) { | ||||
|             dragMonitors.splice(i, 1); | ||||
| @@ -87,10 +87,6 @@ _Draggable.prototype = { | ||||
|  | ||||
|         this.actor.connect('destroy', Lang.bind(this, function() { | ||||
|             this._actorDestroyed = true; | ||||
|             // If the drag actor is destroyed and we were going to fix | ||||
|             // up its hover state, fix up the parent hover state instead | ||||
|             if (this.actor == this._firstLeaveActor) | ||||
|                 this._firstLeaveActor = this._dragOrigParent; | ||||
|             if (this._dragInProgress) | ||||
|                 this._cancelDrag(global.get_current_time()); | ||||
|             this.disconnectAll(); | ||||
| @@ -104,14 +100,6 @@ _Draggable.prototype = { | ||||
|         this._buttonDown = false; // The mouse button has been pressed and has not yet been released. | ||||
|         this._dragInProgress = false; // The drag has been started, and has not been dropped or cancelled yet. | ||||
|         this._animationInProgress = false; // The drag is over and the item is in the process of animating to its original position (snapping back or reverting). | ||||
|  | ||||
|         // During the drag, we eat enter/leave events so that actors don't prelight or show | ||||
|         // tooltips. But we remember the actors that we first left/last entered so we can | ||||
|         // fix up the hover state after the drag ends. | ||||
|         this._firstLeaveActor = null; | ||||
|         this._lastEnterActor = null; | ||||
|  | ||||
|         this._eventsGrabbed = false; | ||||
|     }, | ||||
|  | ||||
|     _onButtonPress : function (actor, event) { | ||||
| @@ -122,11 +110,11 @@ _Draggable.prototype = { | ||||
|             return false; | ||||
|  | ||||
|         this._buttonDown = true; | ||||
|         // special case St.Button: grabbing the pointer would mess up the | ||||
|         // special case St.Clickable: grabbing the pointer would mess up the | ||||
|         // internal state, so we start the drag manually on hover change | ||||
|         if (this.actor instanceof St.Button) | ||||
|         if (this.actor instanceof St.Clickable) | ||||
|             this.actor.connect('notify::hover', | ||||
|                                Lang.bind(this, this._onButtonHoverChanged)); | ||||
|                                Lang.bind(this, this._onClickableHoverChanged)); | ||||
|         else | ||||
|             this._grabActor(); | ||||
|  | ||||
| @@ -137,8 +125,8 @@ _Draggable.prototype = { | ||||
|         return false; | ||||
|     }, | ||||
|  | ||||
|     _onButtonHoverChanged: function(button) { | ||||
|         if (button.hover || !button.pressed) | ||||
|     _onClickableHoverChanged: function(button) { | ||||
|         if (button.hover || !button.held) | ||||
|             return; | ||||
|  | ||||
|         button.fake_release(); | ||||
| @@ -154,26 +142,18 @@ _Draggable.prototype = { | ||||
|  | ||||
|     _ungrabActor: function() { | ||||
|         Clutter.ungrab_pointer(); | ||||
|         if (!this._onEventId) | ||||
|             return; | ||||
|         this.actor.disconnect(this._onEventId); | ||||
|         this._onEventId = null; | ||||
|     }, | ||||
|  | ||||
|     _grabEvents: function() { | ||||
|         if (!this._eventsGrabbed) { | ||||
|             Clutter.grab_pointer(_getEventHandlerActor()); | ||||
|             Clutter.grab_keyboard(_getEventHandlerActor()); | ||||
|             this._eventsGrabbed = true; | ||||
|         } | ||||
|         Clutter.grab_pointer(_getEventHandlerActor()); | ||||
|         Clutter.grab_keyboard(_getEventHandlerActor()); | ||||
|     }, | ||||
|  | ||||
|     _ungrabEvents: function() { | ||||
|         if (this._eventsGrabbed) { | ||||
|             Clutter.ungrab_pointer(); | ||||
|             Clutter.ungrab_keyboard(); | ||||
|             this._eventsGrabbed = false; | ||||
|         } | ||||
|         Clutter.ungrab_pointer(); | ||||
|         Clutter.ungrab_keyboard(); | ||||
|     }, | ||||
|  | ||||
|     _onEvent: function(actor, event) { | ||||
| @@ -210,11 +190,6 @@ _Draggable.prototype = { | ||||
|                 this._cancelDrag(event.get_time()); | ||||
|                 return true; | ||||
|             } | ||||
|         } else if (event.type() == Clutter.EventType.LEAVE) { | ||||
|             if (this._firstLeaveActor == null) | ||||
|                 this._firstLeaveActor = event.get_source(); | ||||
|         } else if (event.type() == Clutter.EventType.ENTER) { | ||||
|             this._lastEnterActor = event.get_source(); | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
| @@ -238,7 +213,7 @@ _Draggable.prototype = { | ||||
|         if (this._onEventId) | ||||
|             this._ungrabActor(); | ||||
|         this._grabEvents(); | ||||
|         global.set_cursor(Shell.Cursor.DND_IN_DRAG); | ||||
|         global.set_cursor(Shell.Cursor.IN_DRAG); | ||||
|  | ||||
|         this._dragX = this._dragStartX = stageX; | ||||
|         this._dragY = this._dragStartY = stageY; | ||||
| @@ -284,13 +259,13 @@ _Draggable.prototype = { | ||||
|             this._dragOffsetY = actorStageY - this._dragStartY; | ||||
|  | ||||
|             // Set the actor's scale such that it will keep the same | ||||
|             // transformed size when it's reparented to the uiGroup | ||||
|             // transformed size when it's reparented to the stage | ||||
|             let [scaledWidth, scaledHeight] = this.actor.get_transformed_size(); | ||||
|             this.actor.set_scale(scaledWidth / this.actor.width, | ||||
|                                  scaledHeight / this.actor.height); | ||||
|         } | ||||
|  | ||||
|         this._dragActor.reparent(Main.uiGroup); | ||||
|         this._dragActor.reparent(this.actor.get_stage()); | ||||
|         this._dragActor.raise_top(); | ||||
|         Shell.util_set_hidden_from_pick(this._dragActor, true); | ||||
|  | ||||
| @@ -399,7 +374,7 @@ _Draggable.prototype = { | ||||
|                 } | ||||
|                 target = target.get_parent(); | ||||
|             } | ||||
|             global.set_cursor(Shell.Cursor.DND_IN_DRAG); | ||||
|             global.set_cursor(Shell.Cursor.IN_DRAG); | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
| @@ -442,7 +417,7 @@ _Draggable.prototype = { | ||||
|                         return true; | ||||
|                     // If it accepted the drop without taking the actor, | ||||
|                     // handle it ourselves. | ||||
|                     if (this._dragActor.get_parent() == Main.uiGroup) { | ||||
|                     if (this._dragActor.get_parent() == this._dragActor.get_stage()) { | ||||
|                         if (this._restoreOnSuccess) { | ||||
|                             this._restoreDragActor(event.get_time()); | ||||
|                             return true; | ||||
| @@ -465,51 +440,25 @@ _Draggable.prototype = { | ||||
|         return true; | ||||
|     }, | ||||
|  | ||||
|     // Get position of the drag actor's source if the source is still around, | ||||
|     // or return the original location if the actor itself was being dragged | ||||
|     // or the source is no longer around. | ||||
|     _getRestoreLocation: function() { | ||||
|         let x, y, scale; | ||||
|         let locX = this._snapBackX; | ||||
|         let locY = this._snapBackY; | ||||
|  | ||||
|         if (this._dragActorSource && this._dragActorSource.visible) { | ||||
|             // Snap the clone back to its source | ||||
|             [x, y] = this._dragActorSource.get_transformed_position(); | ||||
|             let [sourceScaledWidth, sourceScaledHeight] = this._dragActorSource.get_transformed_size(); | ||||
|             scale = this._dragActor.width / sourceScaledWidth; | ||||
|         } else if (this._dragOrigParent) { | ||||
|             // Snap the actor back to its original position within | ||||
|             // its parent, adjusting for the fact that the parent | ||||
|             // may have been moved or scaled | ||||
|             let [parentX, parentY] = this._dragOrigParent.get_transformed_position(); | ||||
|             let [parentWidth, parentHeight] = this._dragOrigParent.get_size(); | ||||
|             let [parentScaledWidth, parentScaledHeight] = this._dragOrigParent.get_transformed_size(); | ||||
|             let parentScale = 1.0; | ||||
|             if (parentWidth != 0) | ||||
|                 parentScale = parentScaledWidth / parentWidth; | ||||
|  | ||||
|             x = parentX + parentScale * this._dragOrigX; | ||||
|             y = parentY + parentScale * this._dragOrigY; | ||||
|             scale = this._dragOrigScale * parentScale; | ||||
|         } else { | ||||
|             // Snap back actor to its original stage position | ||||
|             x = this._snapBackX; | ||||
|             y = this._snapBackY; | ||||
|             scale = this._snapBackScale; | ||||
|         } | ||||
|  | ||||
|         return [x, y, scale]; | ||||
|         if (this._dragActorSource && this._dragActorSource.visible) | ||||
|             [locX, locY] = this._dragActorSource.get_transformed_position(); | ||||
|         return [locX, locY]; | ||||
|     }, | ||||
|  | ||||
|     _cancelDrag: function(eventTime) { | ||||
|         this.emit('drag-cancelled', eventTime); | ||||
|         this._dragInProgress = false; | ||||
|         let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation(); | ||||
|         let [snapBackX, snapBackY] = this._getRestoreLocation(); | ||||
|  | ||||
|         if (this._actorDestroyed) { | ||||
|             global.unset_cursor(); | ||||
|             if (!this._buttonDown) | ||||
|                 this._dragComplete(); | ||||
|             this.emit('drag-end', eventTime, false); | ||||
|             if (!this._dragOrigParent) | ||||
|                 this._dragActor.destroy(); | ||||
|  | ||||
|             return; | ||||
|         } | ||||
|  | ||||
| @@ -518,8 +467,8 @@ _Draggable.prototype = { | ||||
|         Tweener.addTween(this._dragActor, | ||||
|                          { x: snapBackX, | ||||
|                            y: snapBackY, | ||||
|                            scale_x: snapBackScale, | ||||
|                            scale_y: snapBackScale, | ||||
|                            scale_x: this._snapBackScale, | ||||
|                            scale_y: this._snapBackScale, | ||||
|                            opacity: this._dragOrigOpacity, | ||||
|                            time: SNAP_BACK_ANIMATION_TIME, | ||||
|                            transition: 'easeOutQuad', | ||||
| @@ -531,11 +480,11 @@ _Draggable.prototype = { | ||||
|  | ||||
|     _restoreDragActor: function(eventTime) { | ||||
|         this._dragInProgress = false; | ||||
|         [restoreX, restoreY, restoreScale] = this._getRestoreLocation(); | ||||
|         [restoreX, restoreY] = this._getRestoreLocation(); | ||||
|  | ||||
|         // fade the actor back in at its original location | ||||
|         this._dragActor.set_position(restoreX, restoreY); | ||||
|         this._dragActor.set_scale(restoreScale, restoreScale); | ||||
|         this._dragActor.set_scale(this._snapBackScale, this._snapBackScale); | ||||
|         this._dragActor.opacity = 0; | ||||
|  | ||||
|         this._animationInProgress = true; | ||||
| @@ -565,36 +514,12 @@ _Draggable.prototype = { | ||||
|             this._dragComplete(); | ||||
|     }, | ||||
|  | ||||
|     // Actor is an actor we have entered or left during the drag; call | ||||
|     // st_widget_sync_hover on all StWidget ancestors | ||||
|     _syncHover: function(actor) { | ||||
|         while (actor) { | ||||
|             let parent = actor.get_parent(); | ||||
|             if (actor instanceof St.Widget) | ||||
|                 actor.sync_hover(); | ||||
|  | ||||
|             actor = parent; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _dragComplete: function() { | ||||
|         if (!this._actorDestroyed) | ||||
|             Shell.util_set_hidden_from_pick(this._dragActor, false); | ||||
|  | ||||
|         this._ungrabEvents(); | ||||
|  | ||||
|         if (this._firstLeaveActor) { | ||||
|             this._syncHover(this._firstLeaveActor); | ||||
|             this._firstLeaveActor = null; | ||||
|         } | ||||
|  | ||||
|         if (this._lastEnterActor) { | ||||
|             this._syncHover(this._lastEnterActor); | ||||
|             this._lastEnterActor = null; | ||||
|         } | ||||
|         Shell.util_set_hidden_from_pick(this._dragActor, false); | ||||
|  | ||||
|         this._dragActor = undefined; | ||||
|         currentDraggable = null; | ||||
|         this._ungrabEvents(); | ||||
|     } | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -1,9 +1,487 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Clutter = imports.gi.Clutter; | ||||
| const Lang = imports.lang; | ||||
| const Shell = imports.gi.Shell; | ||||
| const Signals = imports.signals; | ||||
| const St = imports.gi.St; | ||||
| const Mainloop = imports.mainloop; | ||||
| const Gettext = imports.gettext.domain('gnome-shell'); | ||||
| const _ = Gettext.gettext; | ||||
|  | ||||
| const DocInfo = imports.misc.docInfo; | ||||
| const Params = imports.misc.params; | ||||
| const DND = imports.ui.dnd; | ||||
| const GenericDisplay = imports.ui.genericDisplay; | ||||
| const Main = imports.ui.main; | ||||
| const Search = imports.ui.search; | ||||
|  | ||||
| const MAX_DASH_DOCS = 50; | ||||
| const DASH_DOCS_ICON_SIZE = 16; | ||||
|  | ||||
| const DEFAULT_SPACING = 4; | ||||
|  | ||||
| /* This class represents a single display item containing information about a document. | ||||
|  * We take the current number of seconds in the constructor to avoid looking up the current | ||||
|  * time for every item when they are created in a batch. | ||||
|  * | ||||
|  * docInfo - DocInfo object containing information about the document | ||||
|  * currentSeconds - current number of seconds since the epoch | ||||
|  */ | ||||
| function DocDisplayItem(docInfo, currentSecs) { | ||||
|     this._init(docInfo, currentSecs); | ||||
| } | ||||
|  | ||||
| DocDisplayItem.prototype = { | ||||
|     __proto__:  GenericDisplay.GenericDisplayItem.prototype, | ||||
|  | ||||
|     _init : function(docInfo, currentSecs) { | ||||
|         GenericDisplay.GenericDisplayItem.prototype._init.call(this); | ||||
|         this._docInfo = docInfo; | ||||
|  | ||||
|         this._setItemInfo(docInfo.name, ''); | ||||
|  | ||||
|         this._timeoutTime = -1; | ||||
|         this._resetTimeDisplay(currentSecs); | ||||
|     }, | ||||
|  | ||||
|     //// Public methods //// | ||||
|  | ||||
|     getUpdateTimeoutTime: function() { | ||||
|         return this._timeoutTime; | ||||
|     }, | ||||
|  | ||||
|     // Update any relative-time based displays for this item. | ||||
|     redisplay: function(currentSecs) { | ||||
|         this._resetTimeDisplay(currentSecs); | ||||
|     }, | ||||
|  | ||||
|     //// Public method overrides //// | ||||
|  | ||||
|     // Opens a document represented by this display item. | ||||
|     launch : function() { | ||||
|         this._docInfo.launch(); | ||||
|     }, | ||||
|  | ||||
|     //// Protected method overrides //// | ||||
|  | ||||
|     // Returns an icon for the item. | ||||
|     _createIcon : function() { | ||||
|         return this._docInfo.createIcon(GenericDisplay.ITEM_DISPLAY_ICON_SIZE); | ||||
|     }, | ||||
|  | ||||
|     // Returns a preview icon for the item. | ||||
|     _createPreviewIcon : function() { | ||||
|         return this._docInfo.createIcon(GenericDisplay.PREVIEW_ICON_SIZE); | ||||
|     }, | ||||
|  | ||||
|     // Creates and returns a large preview icon, but only if this._docInfo is an image file | ||||
|     // and we were able to generate a pixbuf from it successfully. | ||||
|     _createLargePreviewIcon : function() { | ||||
|         if (this._docInfo.mimeType == null || this._docInfo.mimeType.indexOf('image/') != 0) | ||||
|             return null; | ||||
|  | ||||
|         try { | ||||
|             return St.TextureCache.get_default().load_uri_sync(St.TextureCachePolicy.NONE, | ||||
|                                                                this._docInfo.uri, -1, -1); | ||||
|         } catch (e) { | ||||
|             // An exception will be raised when the image format isn't know | ||||
|             /* FIXME: http://bugzilla.gnome.org/show_bug.cgi?id=591480: should | ||||
|              *        only ignore GDK_PIXBUF_ERROR_UNKNOWN_TYPE. */ | ||||
|             return null; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     //// Drag and Drop //// | ||||
|  | ||||
|     shellWorkspaceLaunch: function() { | ||||
|         this.launch(); | ||||
|     }, | ||||
|  | ||||
|     //// Private Methods //// | ||||
|  | ||||
|     // Updates the last visited time displayed in the description text for the item. | ||||
|     _resetTimeDisplay: function(currentSecs) { | ||||
|         let lastSecs = this._docInfo.timestamp; | ||||
|         let timeDelta = currentSecs - lastSecs; | ||||
|         let [text, nextUpdate] = global.format_time_relative_pretty(timeDelta); | ||||
|         this._timeoutTime = currentSecs + nextUpdate; | ||||
|         this._setDescriptionText(text); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /* This class represents a display containing a collection of document items. | ||||
|  * The documents are sorted by how recently they were last visited. | ||||
|  */ | ||||
| function DocDisplay() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| DocDisplay.prototype = { | ||||
|     __proto__:  GenericDisplay.GenericDisplay.prototype, | ||||
|  | ||||
|     _init : function() { | ||||
|         GenericDisplay.GenericDisplay.prototype._init.call(this); | ||||
|         // We keep a single timeout callback for updating last visited times | ||||
|         // for all the items in the display. This avoids creating individual | ||||
|         // callbacks for each item in the display. So proper time updates | ||||
|         // for individual items and item details depend on the item being | ||||
|         // associated with one of the displays. | ||||
|         this._updateTimeoutTargetTime = -1; | ||||
|         this._updateTimeoutId = 0; | ||||
|  | ||||
|         this._docManager = DocInfo.getDocManager(); | ||||
|         this._docsStale = true; | ||||
|         this._docManager.connect('changed', Lang.bind(this, function(mgr, userData) { | ||||
|             this._docsStale = true; | ||||
|             // Changes in local recent files should not happen when we are in the Overview mode, | ||||
|             // but redisplaying right away is cool when we use Zephyr. | ||||
|             // Also, we might be displaying remote documents, like Google Docs, in the future | ||||
|             // which might be edited by someone else. | ||||
|             this._redisplay(GenericDisplay.RedisplayFlags.NONE); | ||||
|         })); | ||||
|  | ||||
|         this.connect('destroy', Lang.bind(this, function (o) { | ||||
|             if (this._updateTimeoutId > 0) | ||||
|                 Mainloop.source_remove(this._updateTimeoutId); | ||||
|         })); | ||||
|     }, | ||||
|  | ||||
|     //// Protected method overrides //// | ||||
|  | ||||
|     // Gets the list of recent items from the recent items manager. | ||||
|     _refreshCache : function() { | ||||
|         if (!this._docsStale) | ||||
|             return true; | ||||
|         this._allItems = {}; | ||||
|         Lang.copyProperties(this._docManager.getInfosByUri(), this._allItems); | ||||
|         this._docsStale = false; | ||||
|         return false; | ||||
|     }, | ||||
|  | ||||
|     // Sets the list of the displayed items based on how recently they were last visited. | ||||
|     _setDefaultList : function() { | ||||
|         // It seems to be an implementation detail of the Mozilla JavaScript that object | ||||
|         // properties are returned during the iteration in the same order in which they were | ||||
|         // defined, but it is not a guarantee according to this  | ||||
|         // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Statements/for...in | ||||
|         // While this._allItems associative array seems to always be ordered by last added, | ||||
|         // as the results of this._recentManager.get_items() based on which it is constructed are, | ||||
|         // we should do the sorting manually because we want the order to be based on last visited. | ||||
|         // | ||||
|         // This function is called each time the search string is set back to '' or we display | ||||
|         // the Overview, so we are doing the sorting over the same items multiple times if the list | ||||
|         // of recent items didn't change. We could store an additional array of doc ids and sort | ||||
|         // them once when they are returned by this._recentManager.get_items() to avoid having to do  | ||||
|         // this sorting each time, but the sorting seems to be very fast anyway, so there is no need | ||||
|         // to introduce an additional class variable. | ||||
|         this._matchedItems = {}; | ||||
|         this._matchedItemKeys = []; | ||||
|         let docIdsToRemove = []; | ||||
|         for (docId in this._allItems) { | ||||
|             this._matchedItems[docId] = 1; | ||||
|             this._matchedItemKeys.push(docId); | ||||
|         } | ||||
|  | ||||
|         for (docId in docIdsToRemove) { | ||||
|             delete this._allItems[docId]; | ||||
|         } | ||||
|  | ||||
|         this._matchedItemKeys.sort(Lang.bind(this, this._compareItems)); | ||||
|     }, | ||||
|  | ||||
|     // Compares items associated with the item ids based on how recently the items | ||||
|     // were last visited. | ||||
|     // Returns an integer value indicating the result of the comparison. | ||||
|    _compareItems : function(itemIdA, itemIdB) { | ||||
|         let docA = this._allItems[itemIdA]; | ||||
|         let docB = this._allItems[itemIdB]; | ||||
|  | ||||
|         return docB.timestamp - docA.timestamp; | ||||
|     }, | ||||
|  | ||||
|     // Checks if the item info can be a match for the search string by checking | ||||
|     // the name of the document. Item info is expected to be GtkRecentInfo. | ||||
|     // Returns a boolean flag indicating if itemInfo is a match. | ||||
|     _isInfoMatching : function(itemInfo, search) { | ||||
|         if (!itemInfo.exists()) | ||||
|             return false; | ||||
|   | ||||
|         if (search == null || search == '') | ||||
|             return true; | ||||
|  | ||||
|         let name = itemInfo.name.toLowerCase(); | ||||
|         if (name.indexOf(search) >= 0) | ||||
|             return true; | ||||
|         // TODO: we can also check doc URIs, so that | ||||
|         // if you search for a directory name, we display recent files from it | ||||
|         return false; | ||||
|     }, | ||||
|  | ||||
|     // Creates a DocDisplayItem based on itemInfo, which is expected to be a DocInfo object. | ||||
|     _createDisplayItem: function(itemInfo) { | ||||
|         let currentSecs = new Date().getTime() / 1000; | ||||
|         let docDisplayItem = new DocDisplayItem(itemInfo, currentSecs); | ||||
|         this._updateTimeoutCallback(docDisplayItem, currentSecs); | ||||
|         return docDisplayItem; | ||||
|     }, | ||||
|  | ||||
|     //// Private Methods //// | ||||
|  | ||||
|     // A callback function that redisplays the items, updating their descriptions, | ||||
|     // and sets up a new timeout callback. | ||||
|     _docTimeout: function () { | ||||
|         let currentSecs = new Date().getTime() / 1000; | ||||
|         this._updateTimeoutId = 0; | ||||
|         this._updateTimeoutTargetTime = -1; | ||||
|         for (let docId in this._displayedItems) { | ||||
|             let docDisplayItem = this._displayedItems[docId]; | ||||
|             docDisplayItem.redisplay(currentSecs);           | ||||
|             this._updateTimeoutCallback(docDisplayItem, currentSecs); | ||||
|         } | ||||
|         return false; | ||||
|     }, | ||||
|  | ||||
|     // Updates the timeout callback if the timeout time for the docDisplayItem  | ||||
|     // is earlier than the target time for the current timeout callback. | ||||
|     _updateTimeoutCallback: function (docDisplayItem, currentSecs) { | ||||
|         let timeoutTime = docDisplayItem.getUpdateTimeoutTime(); | ||||
|         if (this._updateTimeoutTargetTime < 0 || timeoutTime < this._updateTimeoutTargetTime) { | ||||
|             if (this._updateTimeoutId > 0) | ||||
|                 Mainloop.source_remove(this._updateTimeoutId); | ||||
|             this._updateTimeoutId = Mainloop.timeout_add_seconds(timeoutTime - currentSecs, Lang.bind(this, this._docTimeout)); | ||||
|             this._updateTimeoutTargetTime = timeoutTime; | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | ||||
| Signals.addSignalMethods(DocDisplay.prototype); | ||||
|  | ||||
| function DashDocDisplayItem(docInfo) { | ||||
|     this._init(docInfo); | ||||
| } | ||||
|  | ||||
| DashDocDisplayItem.prototype = { | ||||
|     _init: function(docInfo) { | ||||
|         this._info = docInfo; | ||||
|         this._icon = docInfo.createIcon(DASH_DOCS_ICON_SIZE); | ||||
|  | ||||
|         this.actor = new St.Clickable({ style_class: 'recent-docs-item', | ||||
|                                         reactive: true, | ||||
|                                         x_align: St.Align.START }); | ||||
|  | ||||
|         let box = new St.BoxLayout({ style_class: 'recent-docs-item-box' }); | ||||
|         this.actor.set_child(box); | ||||
|  | ||||
|         box.add(this._icon); | ||||
|  | ||||
|         let text = new St.Label({ text: docInfo.name }); | ||||
|         box.add(text); | ||||
|  | ||||
|         this.actor.connect('clicked', Lang.bind(this, function () { | ||||
|             docInfo.launch(); | ||||
|             Main.overview.hide(); | ||||
|         })); | ||||
|  | ||||
|         this.actor._delegate = this; | ||||
|         let draggable = DND.makeDraggable(this.actor); | ||||
|         draggable.connect('drag-begin', | ||||
|                           Lang.bind(this, function() { | ||||
|                               Main.overview.beginItemDrag(this); | ||||
|                           })); | ||||
|         draggable.connect('drag-end', | ||||
|                           Lang.bind(this, function() { | ||||
|                               Main.overview.endItemDrag(this); | ||||
|                           })); | ||||
|     }, | ||||
|  | ||||
|     getUri: function() { | ||||
|         return this._info.uri; | ||||
|     }, | ||||
|  | ||||
|     getDragActorSource: function() { | ||||
|         return this._icon; | ||||
|     }, | ||||
|  | ||||
|     getDragActor: function(stageX, stageY) { | ||||
|         this.dragActor = this._info.createIcon(DASH_DOCS_ICON_SIZE); | ||||
|         return this.dragActor; | ||||
|     }, | ||||
|  | ||||
|     //// Drag and drop functions //// | ||||
|  | ||||
|     shellWorkspaceLaunch: function () { | ||||
|         this._info.launch(); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Class used to display two column recent documents in the dash | ||||
|  */ | ||||
| function DashDocDisplay() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| DashDocDisplay.prototype = { | ||||
|     _init: function() { | ||||
|         this.actor = new Shell.GenericContainer(); | ||||
|         this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth)); | ||||
|         this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight)); | ||||
|         this.actor.connect('allocate', Lang.bind(this, this._allocate)); | ||||
|         this._workId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay)); | ||||
|  | ||||
|         this._actorsByUri = {}; | ||||
|  | ||||
|         this._docManager = DocInfo.getDocManager(); | ||||
|         this._docManager.connect('changed', Lang.bind(this, this._onDocsChanged)); | ||||
|         this._pendingDocsChange = true; | ||||
|         this._checkDocExistence = false; | ||||
|     }, | ||||
|  | ||||
|     _getPreferredWidth: function(actor, forHeight, alloc) { | ||||
|         let children = actor.get_children(); | ||||
|  | ||||
|         // We use two columns maximum.  Just take the min and natural size of the | ||||
|         // first two items, even though strictly speaking it's not correct; we'd | ||||
|         // need to calculate how many items we could fit for the height, then | ||||
|         // take the biggest preferred width for each column. | ||||
|         // In practice the dash gets a fixed width anyways. | ||||
|  | ||||
|         // If we have one child, add its minimum and natural size | ||||
|         if (children.length > 0) { | ||||
|             let [minSize, naturalSize] = children[0].get_preferred_width(forHeight); | ||||
|             alloc.min_size += minSize; | ||||
|             alloc.natural_size += naturalSize; | ||||
|         } | ||||
|         // If we have two, add its size, plus DEFAULT_SPACING | ||||
|         if (children.length > 1) { | ||||
|             let [minSize, naturalSize] = children[1].get_preferred_width(forHeight); | ||||
|             alloc.min_size += DEFAULT_SPACING + minSize; | ||||
|             alloc.natural_size += DEFAULT_SPACING + naturalSize; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _getPreferredHeight: function(actor, forWidth, alloc) { | ||||
|         let children = actor.get_children(); | ||||
|  | ||||
|         // The width of an item is our allocated width, minus spacing, divided in half. | ||||
|         this._itemWidth = Math.floor((forWidth - DEFAULT_SPACING) / 2); | ||||
|  | ||||
|         let maxNatural = 0; | ||||
|         for (let i = 0; i < children.length; i++) { | ||||
|             let child = children[i]; | ||||
|             let [minSize, naturalSize] = child.get_preferred_height(this._itemWidth); | ||||
|             maxNatural = Math.max(maxNatural, naturalSize); | ||||
|         } | ||||
|  | ||||
|         this._itemHeight = maxNatural; | ||||
|  | ||||
|         let firstColumnChildren = Math.ceil(children.length / 2); | ||||
|         alloc.natural_size = (firstColumnChildren * maxNatural + | ||||
|                               (firstColumnChildren - 1) * DEFAULT_SPACING); | ||||
|     }, | ||||
|  | ||||
|     _allocate: function(actor, box, flags) { | ||||
|         let width = box.x2 - box.x1; | ||||
|         let height = box.y2 - box.y1; | ||||
|  | ||||
|         // Make sure this._itemWidth/Height have been computed, even | ||||
|         // if the parent actor didn't check our size before allocating. | ||||
|         // (Not clear if that is required or not as a Clutter | ||||
|         // invariant; this is safe and cheap because of caching.) | ||||
|         actor.get_preferred_height(width); | ||||
|  | ||||
|         let children = actor.get_children(); | ||||
|  | ||||
|         let x = 0; | ||||
|         let y = 0; | ||||
|         let columnIndex = 0; | ||||
|         let i = 0; | ||||
|         // Loop over the children, going vertically down first.  When we run | ||||
|         // out of vertical space (our y variable is bigger than box.y2), switch | ||||
|         // to the second column. | ||||
|         while (i < children.length) { | ||||
|             let child = children[i]; | ||||
|  | ||||
|             if (y + this._itemHeight > box.y2) { | ||||
|                 // Is this the second column, or we're in | ||||
|                 // the first column and can't even fit one | ||||
|                 // item?  In that case, break. | ||||
|                 if (columnIndex == 1 || i == 0) { | ||||
|                     break; | ||||
|                 } | ||||
|                 // Set x to the halfway point. | ||||
|                 columnIndex += 1; | ||||
|                 x = x + this._itemWidth + DEFAULT_SPACING; | ||||
|                 // And y is back to the top. | ||||
|                 y = 0; | ||||
|                 // Retry this same item, now that we're in the second column. | ||||
|                 // By looping back to the top here, we re-test the size | ||||
|                 // again for the second column. | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             let childBox = new Clutter.ActorBox(); | ||||
|             childBox.x1 = x; | ||||
|             childBox.y1 = y; | ||||
|             childBox.x2 = childBox.x1 + this._itemWidth; | ||||
|             childBox.y2 = y + this._itemHeight; | ||||
|  | ||||
|             y = childBox.y2 + DEFAULT_SPACING; | ||||
|  | ||||
|             child.allocate(childBox, flags); | ||||
|             this.actor.set_skip_paint(child, false); | ||||
|  | ||||
|             i++; | ||||
|         } | ||||
|  | ||||
|         if (this._checkDocExistence) { | ||||
|             // Now we know how many docs we are displaying, queue a check to see if any of them | ||||
|             // have been deleted. If they are deleted, then we'll get a 'changed' signal; since | ||||
|             // we'll now be displaying items we weren't previously, we'll check again to see | ||||
|             // if they were deleted, and so forth and so on. | ||||
|             // TODO: We should change this to ask for as many as we can fit in the given space: | ||||
|             // https://bugzilla.gnome.org/show_bug.cgi?id=603522#c23 | ||||
|             this._docManager.queueExistenceCheck(i); | ||||
|             this._checkDocExistence = false; | ||||
|         } | ||||
|  | ||||
|         for (; i < children.length; i++) | ||||
|             this.actor.set_skip_paint(children[i], true); | ||||
|     }, | ||||
|  | ||||
|     _onDocsChanged: function() { | ||||
|         this._checkDocExistence = true; | ||||
|         Main.queueDeferredWork(this._workId); | ||||
|     }, | ||||
|  | ||||
|     _redisplay: function() { | ||||
|         // Should be kept alive by the _actorsByUri | ||||
|         this.actor.remove_all(); | ||||
|         let docs = this._docManager.getTimestampOrderedInfos(); | ||||
|         for (let i = 0; i < docs.length && i < MAX_DASH_DOCS; i++) { | ||||
|             let doc = docs[i]; | ||||
|             let display = this._actorsByUri[doc.uri]; | ||||
|             if (display) { | ||||
|                 this.actor.add_actor(display.actor); | ||||
|             } else { | ||||
|                 let display = new DashDocDisplayItem(doc); | ||||
|                 this.actor.add_actor(display.actor); | ||||
|                 this._actorsByUri[doc.uri] = display; | ||||
|             } | ||||
|         } | ||||
|         // Any unparented actors must have been deleted | ||||
|         for (let uri in this._actorsByUri) { | ||||
|             let display = this._actorsByUri[uri]; | ||||
|             if (display.actor.get_parent() == null) { | ||||
|                 display.actor.destroy(); | ||||
|                 delete this._actorsByUri[uri]; | ||||
|             } | ||||
|         } | ||||
|         this.emit('changed'); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| Signals.addSignalMethods(DashDocDisplay.prototype); | ||||
|  | ||||
| function DocSearchProvider() { | ||||
|     this._init(); | ||||
| @@ -23,18 +501,12 @@ DocSearchProvider.prototype = { | ||||
|             return null; | ||||
|         return { 'id': resultId, | ||||
|                  'name': docInfo.name, | ||||
|                  'createIcon': function(size) { | ||||
|                                    return docInfo.createIcon(size); | ||||
|                                } | ||||
|                }; | ||||
|                  'icon': docInfo.createIcon(Search.RESULT_ICON_SIZE)}; | ||||
|     }, | ||||
|  | ||||
|     activateResult: function(id, params) { | ||||
|         params = Params.parse(params, { workspace: -1, | ||||
|                                         timestamp: 0 }); | ||||
|  | ||||
|     activateResult: function(id) { | ||||
|         let docInfo = this._docManager.lookupByUri(id); | ||||
|         docInfo.launch(params.workspace); | ||||
|         docInfo.launch(); | ||||
|     }, | ||||
|  | ||||
|     getInitialResultSet: function(terms) { | ||||
| @@ -43,5 +515,9 @@ DocSearchProvider.prototype = { | ||||
|  | ||||
|     getSubsearchResultSet: function(previousResults, terms) { | ||||
|         return this._docManager.subsearch(previousResults, terms); | ||||
|     }, | ||||
|  | ||||
|     expandSearch: function(terms) { | ||||
|         log('TODO expand docs search'); | ||||
|     } | ||||
| }; | ||||
|   | ||||
| @@ -1,548 +0,0 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- | ||||
|  * | ||||
|  * Copyright 2010 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 DBus = imports.dbus; | ||||
| const Lang = imports.lang; | ||||
| const Signals = imports.signals; | ||||
|  | ||||
| const AccountsService = imports.gi.AccountsService; | ||||
| const Clutter = imports.gi.Clutter; | ||||
| const GLib = imports.gi.GLib; | ||||
| const Gtk = imports.gi.Gtk; | ||||
| const Pango = imports.gi.Pango; | ||||
| const St = imports.gi.St; | ||||
| const Shell = imports.gi.Shell; | ||||
|  | ||||
| const GnomeSession = imports.misc.gnomeSession | ||||
| const Lightbox = imports.ui.lightbox; | ||||
| const Main = imports.ui.main; | ||||
| const ModalDialog = imports.ui.modalDialog; | ||||
| const Tweener = imports.ui.tweener; | ||||
|  | ||||
| let _endSessionDialog = null; | ||||
|  | ||||
| const _ITEM_ICON_SIZE = 48; | ||||
| const _DIALOG_ICON_SIZE = 32; | ||||
|  | ||||
| const GSM_SESSION_MANAGER_LOGOUT_FORCE = 2; | ||||
|  | ||||
| const EndSessionDialogIface = { | ||||
|     name: 'org.gnome.SessionManager.EndSessionDialog', | ||||
|     methods: [{ name: 'Open', | ||||
|                 inSignature: 'uuuao', | ||||
|                 outSignature: '' | ||||
|               } | ||||
|              ], | ||||
|     signals: [{ name: 'Canceled', | ||||
|                 inSignature: '', | ||||
|               }], | ||||
|     properties: [] | ||||
| }; | ||||
|  | ||||
| const logoutDialogContent = { | ||||
|     subjectWithUser: _("Log Out %s"), | ||||
|     subject: _("Log Out"), | ||||
|     inhibitedDescription: _("Click Log Out to quit these applications and log out of the system."), | ||||
|     uninhibitedDescriptionWithUser: function(user, seconds) { | ||||
|         return ngettext("%s will be logged out automatically in %d second.", | ||||
|                         "%s will be logged out automatically in %d seconds.", | ||||
|                         seconds).format(user, seconds); | ||||
|     }, | ||||
|     uninhibitedDescription: function(seconds) { | ||||
|         return ngettext("You will be logged out automatically in %d second.", | ||||
|                         "You will be logged out automatically in %d seconds.", | ||||
|                         seconds).format(seconds); | ||||
|     }, | ||||
|     endDescription: _("Logging out of the system."), | ||||
|     confirmButtons: [{ signal: 'ConfirmedLogout', | ||||
|                        label:  _("Log Out") }], | ||||
|     iconStyleClass: 'end-session-dialog-logout-icon' | ||||
| }; | ||||
|  | ||||
| const shutdownDialogContent = { | ||||
|     subject: _("Power Off"), | ||||
|     inhibitedDescription: _("Click Power Off to quit these applications and power off the system."), | ||||
|     uninhibitedDescription: function(seconds) { | ||||
|         return ngettext("The system will power off automatically in %d second.", | ||||
|                         "The system will power off automatically in %d seconds.", | ||||
|                         seconds).format(seconds); | ||||
|     }, | ||||
|     endDescription: _("Powering off the system."), | ||||
|     confirmButtons: [{ signal: 'ConfirmedReboot', | ||||
|                        label:  _("Restart") }, | ||||
|                      { signal: 'ConfirmedShutdown', | ||||
|                        label:  _("Power Off") }], | ||||
|     iconName: 'system-shutdown', | ||||
|     iconStyleClass: 'end-session-dialog-shutdown-icon' | ||||
| }; | ||||
|  | ||||
| const restartDialogContent = { | ||||
|     subject: _("Restart"), | ||||
|     inhibitedDescription: _("Click Restart to quit these applications and restart the system."), | ||||
|     uninhibitedDescription: function(seconds) { | ||||
|         return ngettext("The system will restart automatically in %d second.", | ||||
|                         "The system will restart automatically in %d seconds.", | ||||
|                         seconds).format(seconds); | ||||
|     }, | ||||
|     endDescription: _("Restarting the system."), | ||||
|     confirmButtons: [{ signal: 'ConfirmedReboot', | ||||
|                        label:  _("Restart") }], | ||||
|     iconName: 'system-shutdown', | ||||
|     iconStyleClass: 'end-session-dialog-shutdown-icon' | ||||
| }; | ||||
|  | ||||
| const DialogContent = { | ||||
|     0 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_LOGOUT */: logoutDialogContent, | ||||
|     1 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_SHUTDOWN */: shutdownDialogContent, | ||||
|     2 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_RESTART */: restartDialogContent | ||||
| }; | ||||
|  | ||||
| function findAppFromInhibitor(inhibitor) { | ||||
|     let desktopFile = inhibitor.app_id; | ||||
|  | ||||
|     if (!GLib.str_has_suffix(desktopFile, '.desktop')) | ||||
|       desktopFile += '.desktop'; | ||||
|  | ||||
|     let candidateDesktopFiles = []; | ||||
|  | ||||
|     candidateDesktopFiles.push(desktopFile); | ||||
|     candidateDesktopFiles.push('gnome-' + desktopFile); | ||||
|  | ||||
|     let appSystem = Shell.AppSystem.get_default(); | ||||
|     let app = null; | ||||
|     for (let i = 0; i < candidateDesktopFiles.length; i++) { | ||||
|         try { | ||||
|             app = appSystem.lookup_app(candidateDesktopFiles[i]); | ||||
|  | ||||
|             if (app) | ||||
|                 break; | ||||
|         } catch(e) { | ||||
|             // ignore errors | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return app; | ||||
| } | ||||
|  | ||||
| function ListItem(app, reason) { | ||||
|     this._init(app, reason); | ||||
| } | ||||
|  | ||||
| ListItem.prototype = { | ||||
|     _init: function(app, reason) { | ||||
|         this._app = app; | ||||
|         this._reason = reason; | ||||
|  | ||||
|         if (this._reason == null) | ||||
|           this._reason = ''; | ||||
|  | ||||
|         let layout = new St.BoxLayout({ vertical: false}); | ||||
|  | ||||
|         this.actor = new St.Button({ style_class: 'end-session-dialog-app-list-item', | ||||
|                                      can_focus:   true, | ||||
|                                      child:       layout, | ||||
|                                      reactive:    true, | ||||
|                                      x_align:     St.Align.START, | ||||
|                                      x_fill:      true }); | ||||
|  | ||||
|         this._icon = this._app.create_icon_texture(_ITEM_ICON_SIZE); | ||||
|  | ||||
|         let iconBin = new St.Bin({ style_class: 'end-session-dialog-app-list-item-icon', | ||||
|                                    child:       this._icon }); | ||||
|         layout.add(iconBin); | ||||
|  | ||||
|         let textLayout = new St.BoxLayout({ style_class: 'end-session-dialog-app-list-item-text-box', | ||||
|                                             vertical:    true }); | ||||
|         layout.add(textLayout); | ||||
|  | ||||
|         this._nameLabel = new St.Label({ text:        this._app.get_name(), | ||||
|                                          style_class: 'end-session-dialog-app-list-item-name' }); | ||||
|         textLayout.add(this._nameLabel, | ||||
|                        { expand: false, | ||||
|                          x_fill: true }); | ||||
|  | ||||
|         this._descriptionLabel = new St.Label({ text:        this._reason, | ||||
|                                                 style_class: 'end-session-dialog-app-list-item-description' }); | ||||
|         textLayout.add(this._descriptionLabel, | ||||
|                        { expand: true, | ||||
|                          x_fill: true }); | ||||
|  | ||||
|         this.actor.connect('clicked', Lang.bind(this, this._onClicked)); | ||||
|     }, | ||||
|  | ||||
|     _onClicked: function() { | ||||
|         this.emit('activate'); | ||||
|         this._app.activate(); | ||||
|     } | ||||
| }; | ||||
| Signals.addSignalMethods(ListItem.prototype); | ||||
|  | ||||
| // The logout timer only shows updates every 10 seconds | ||||
| // until the last 10 seconds, then it shows updates every | ||||
| // second.  This function takes a given time and returns | ||||
| // what we should show to the user for that time. | ||||
| function _roundSecondsToInterval(totalSeconds, secondsLeft, interval) { | ||||
|     let time; | ||||
|  | ||||
|     time = Math.ceil(secondsLeft); | ||||
|  | ||||
|     // Final count down is in decrements of 1 | ||||
|     if (time <= interval) | ||||
|         return time; | ||||
|  | ||||
|     // Round up higher than last displayable time interval | ||||
|     time += interval - 1; | ||||
|  | ||||
|     // Then round down to that time interval | ||||
|     if (time > totalSeconds) | ||||
|         time = Math.ceil(totalSeconds); | ||||
|     else | ||||
|         time -= time % interval; | ||||
|  | ||||
|     return time; | ||||
| } | ||||
|  | ||||
| function _setLabelText(label, text) { | ||||
|     if (text) { | ||||
|         label.set_text(text); | ||||
|         label.show(); | ||||
|     } else { | ||||
|         label.set_text(''); | ||||
|         label.hide(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function EndSessionDialog() { | ||||
|     if (_endSessionDialog == null) { | ||||
|         this._init(); | ||||
|         DBus.session.exportObject('/org/gnome/SessionManager/EndSessionDialog', | ||||
|                                   this); | ||||
|         _endSessionDialog = this; | ||||
|     } | ||||
|  | ||||
|     return _endSessionDialog; | ||||
| } | ||||
|  | ||||
| function init() { | ||||
|     // This always returns the same singleton object | ||||
|     // By instantiating it initially, we register the | ||||
|     // bus object, etc. | ||||
|     let dialog = new EndSessionDialog(); | ||||
| } | ||||
|  | ||||
| EndSessionDialog.prototype = { | ||||
|     __proto__: ModalDialog.ModalDialog.prototype, | ||||
|  | ||||
|     _init: function() { | ||||
|         ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'end-session-dialog' }); | ||||
|  | ||||
|         this._user = AccountsService.UserManager.get_default().get_user(GLib.get_user_name()); | ||||
|  | ||||
|         this._secondsLeft = 0; | ||||
|         this._totalSecondsToStayOpen = 0; | ||||
|         this._inhibitors = []; | ||||
|  | ||||
|         this.connect('destroy', | ||||
|                      Lang.bind(this, this._onDestroy)); | ||||
|         this.connect('opened', | ||||
|                      Lang.bind(this, this._onOpened)); | ||||
|  | ||||
|         this._userLoadedId = this._user.connect('notify::is_loaded', | ||||
|                                                 Lang.bind(this, this._updateContent)); | ||||
|  | ||||
|         this._userChangedId = this._user.connect('changed', | ||||
|                                                  Lang.bind(this, this._updateContent)); | ||||
|  | ||||
|         let mainContentLayout = new St.BoxLayout({ vertical: false }); | ||||
|         this.contentLayout.add(mainContentLayout, | ||||
|                                { x_fill: true, | ||||
|                                  y_fill: false }); | ||||
|  | ||||
|         this._iconBin = new St.Bin(); | ||||
|         mainContentLayout.add(this._iconBin, | ||||
|                               { x_fill:  true, | ||||
|                                 y_fill:  false, | ||||
|                                 x_align: St.Align.END, | ||||
|                                 y_align: St.Align.START }); | ||||
|  | ||||
|         let messageLayout = new St.BoxLayout({ vertical: true }); | ||||
|         mainContentLayout.add(messageLayout, | ||||
|                               { y_align: St.Align.START }); | ||||
|  | ||||
|         this._subjectLabel = new St.Label({ style_class: 'end-session-dialog-subject' }); | ||||
|  | ||||
|         messageLayout.add(this._subjectLabel, | ||||
|                           { y_fill:  false, | ||||
|                             y_align: St.Align.START }); | ||||
|  | ||||
|         this._descriptionLabel = new St.Label({ style_class: 'end-session-dialog-description' }); | ||||
|         this._descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; | ||||
|         this._descriptionLabel.clutter_text.line_wrap = true; | ||||
|  | ||||
|         messageLayout.add(this._descriptionLabel, | ||||
|                           { y_fill:  true, | ||||
|                             y_align: St.Align.START }); | ||||
|  | ||||
|         let scrollView = new St.ScrollView({ style_class: 'end-session-dialog-app-list'}); | ||||
|         scrollView.set_policy(Gtk.PolicyType.NEVER, | ||||
|                               Gtk.PolicyType.AUTOMATIC); | ||||
|         this.contentLayout.add(scrollView, | ||||
|                                { x_fill: true, | ||||
|                                  y_fill: true }); | ||||
|         scrollView.hide(); | ||||
|  | ||||
|         this._applicationList = new St.BoxLayout({ vertical: true }); | ||||
|         scrollView.add_actor(this._applicationList, | ||||
|                              { x_fill:  true, | ||||
|                                y_fill:  true, | ||||
|                                x_align: St.Align.START, | ||||
|                                y_align: St.Align.MIDDLE }); | ||||
|  | ||||
|         this._applicationList.connect('actor-added', | ||||
|                                       Lang.bind(this, function() { | ||||
|                                           if (this._applicationList.get_children().length == 1) | ||||
|                                               scrollView.show(); | ||||
|                                       })); | ||||
|  | ||||
|         this._applicationList.connect('actor-removed', | ||||
|                                       Lang.bind(this, function() { | ||||
|                                           if (this._applicationList.get_children().length == 0) | ||||
|                                               scrollView.hide(); | ||||
|                                       })); | ||||
|     }, | ||||
|  | ||||
|     _onDestroy: function() { | ||||
|         this._user.disconnect(this._userLoadedId); | ||||
|         this._user.disconnect(this._userChangedId); | ||||
|     }, | ||||
|  | ||||
|     _setIconFromFile: function(iconFile, styleClass) { | ||||
|         if (styleClass) | ||||
|             this._iconBin.set_style_class_name(styleClass); | ||||
|         this._iconBin.set_style(null); | ||||
|  | ||||
|         this._iconBin.child = null; | ||||
|         if (iconFile) { | ||||
|             this._iconBin.show(); | ||||
|             this._iconBin.set_style('background-image: url("' + iconFile + '");'); | ||||
|         } else { | ||||
|             this._iconBin.hide(); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _setIconFromName: function(iconName, styleClass) { | ||||
|         if (styleClass) | ||||
|             this._iconBin.set_style_class_name(styleClass); | ||||
|         this._iconBin.set_style(null); | ||||
|  | ||||
|         if (iconName != null) { | ||||
|             let textureCache = St.TextureCache.get_default(); | ||||
|             let icon = textureCache.load_icon_name(this._iconBin.get_theme_node(), | ||||
|                                                    iconName, | ||||
|                                                    St.IconType.SYMBOLIC, | ||||
|                                                    _DIALOG_ICON_SIZE); | ||||
|  | ||||
|             this._iconBin.child = icon; | ||||
|             this._iconBin.show(); | ||||
|         } else { | ||||
|             this._iconBin.child = null; | ||||
|             this._iconBin.hide(); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _updateContent: function() { | ||||
|         if (this.state != ModalDialog.State.OPENING && | ||||
|             this.state != ModalDialog.State.OPENED) | ||||
|             return; | ||||
|  | ||||
|         let dialogContent = DialogContent[this._type]; | ||||
|  | ||||
|         let subject = dialogContent.subject; | ||||
|         let description; | ||||
|  | ||||
|         if (this._user.is_loaded && !dialogContent.iconName) { | ||||
|             let iconFile = this._user.get_icon_file(); | ||||
|             if (GLib.file_test(iconFile, GLib.FileTest.EXISTS)) | ||||
|                 this._setIconFromFile(iconFile, dialogContent.iconStyleClass); | ||||
|             else | ||||
|                 this._setIconFromName('avatar-default', dialogContent.iconStyleClass); | ||||
|         } else if (dialogContent.iconName) { | ||||
|             this._setIconFromName(dialogContent.iconName, | ||||
|                                   dialogContent.iconStyleClass); | ||||
|         } | ||||
|  | ||||
|         if (this._inhibitors.length > 0) { | ||||
|             this._stopTimer(); | ||||
|             description = dialogContent.inhibitedDescription; | ||||
|         } else if (this._secondsLeft > 0 && this._inhibitors.length == 0) { | ||||
|             let displayTime = _roundSecondsToInterval(this._totalSecondsToStayOpen, | ||||
|                                                       this._secondsLeft, | ||||
|                                                       10); | ||||
|  | ||||
|             if (this._user.is_loaded) { | ||||
|                 let realName = this._user.get_real_name(); | ||||
|  | ||||
|                 if (realName != null) { | ||||
|                     if (dialogContent.subjectWithUser) | ||||
|                         subject = dialogContent.subjectWithUser.format(realName); | ||||
|  | ||||
|                     if (dialogContent.uninhibitedDescriptionWithUser) | ||||
|                         description = dialogContent.uninhibitedDescriptionWithUser(realName, displayTime); | ||||
|                     else | ||||
|                         description = dialogContent.uninhibitedDescription(displayTime); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (!description) | ||||
|                 description = dialogContent.uninhibitedDescription(displayTime); | ||||
|         } else { | ||||
|             description = dialogContent.endDescription; | ||||
|         } | ||||
|  | ||||
|         _setLabelText(this._subjectLabel, subject); | ||||
|         _setLabelText(this._descriptionLabel, description); | ||||
|     }, | ||||
|  | ||||
|     _updateButtons: function() { | ||||
|         let dialogContent = DialogContent[this._type]; | ||||
|         let buttons = [{ action: Lang.bind(this, this.cancel), | ||||
|                          label:  _("Cancel"), | ||||
|                          key:    Clutter.Escape }]; | ||||
|  | ||||
|         for (let i = 0; i < dialogContent.confirmButtons.length; i++) { | ||||
|             let signal = dialogContent.confirmButtons[i].signal; | ||||
|             let label = dialogContent.confirmButtons[i].label; | ||||
|             buttons.push({ action: Lang.bind(this, function() { | ||||
|                                        this._confirm(signal); | ||||
|                                    }), | ||||
|                            label: label }); | ||||
|         } | ||||
|  | ||||
|         this.setButtons(buttons); | ||||
|     }, | ||||
|  | ||||
|     close: function() { | ||||
|         ModalDialog.ModalDialog.prototype.close.call(this); | ||||
|         DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog', | ||||
|                                  'org.gnome.SessionManager.EndSessionDialog', | ||||
|                                  'Closed', '', []); | ||||
|     }, | ||||
|  | ||||
|     cancel: function() { | ||||
|         this._stopTimer(); | ||||
|         DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog', | ||||
|                                  'org.gnome.SessionManager.EndSessionDialog', | ||||
|                                  'Canceled', '', []); | ||||
|         this.close(global.get_current_time()); | ||||
|     }, | ||||
|  | ||||
|     _confirm: function(signal) { | ||||
|         this._fadeOutDialog(); | ||||
|         this._stopTimer(); | ||||
|         DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog', | ||||
|                                  'org.gnome.SessionManager.EndSessionDialog', | ||||
|                                  signal, '', []); | ||||
|     }, | ||||
|  | ||||
|     _onOpened: function() { | ||||
|         if (this._inhibitors.length == 0) | ||||
|             this._startTimer(); | ||||
|     }, | ||||
|  | ||||
|     _startTimer: function() { | ||||
|         this._secondsLeft = this._totalSecondsToStayOpen; | ||||
|         Tweener.addTween(this, | ||||
|                          { _secondsLeft: 0, | ||||
|                            time: this._secondsLeft, | ||||
|                            transition: 'linear', | ||||
|                            onUpdate: Lang.bind(this, this._updateContent), | ||||
|                            onComplete: Lang.bind(this, function() { | ||||
|                                            let dialogContent = DialogContent[this._type]; | ||||
|                                            let button = dialogContent.confirmButtons[dialogContent.confirmButtons.length - 1]; | ||||
|                                            this._confirm(button.signal); | ||||
|                                        }), | ||||
|                          }); | ||||
|     }, | ||||
|  | ||||
|     _stopTimer: function() { | ||||
|         Tweener.removeTweens(this); | ||||
|         this._secondsLeft = 0; | ||||
|     }, | ||||
|  | ||||
|     _onInhibitorLoaded: function(inhibitor) { | ||||
|         if (this._inhibitors.indexOf(inhibitor) < 0) { | ||||
|             // Stale inhibitor | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         let app = findAppFromInhibitor(inhibitor); | ||||
|  | ||||
|         if (app) { | ||||
|             let item = new ListItem(app, inhibitor.reason); | ||||
|             item.connect('activate', | ||||
|                          Lang.bind(this, function() { | ||||
|                              this.close(global.get_current_time()); | ||||
|                          })); | ||||
|             this._applicationList.add(item.actor, { x_fill: true }); | ||||
|             this._stopTimer(); | ||||
|         } else { | ||||
|             // inhibiting app is a service, not an application | ||||
|             this._inhibitors.splice(this._inhibitors.indexOf(inhibitor), 1); | ||||
|         } | ||||
|  | ||||
|         this._updateContent(); | ||||
|     }, | ||||
|  | ||||
|     OpenAsync: function(type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths, callback) { | ||||
|         this._totalSecondsToStayOpen = totalSecondsToStayOpen; | ||||
|         this._inhibitors = []; | ||||
|         this._applicationList.destroy_children(); | ||||
|         this._type = type; | ||||
|  | ||||
|         if (!(this._type in DialogContent)) | ||||
|             throw new DBus.DBusError('org.gnome.Shell.ModalDialog.TypeError', | ||||
|                                      "Unknown dialog type requested"); | ||||
|  | ||||
|         for (let i = 0; i < inhibitorObjectPaths.length; i++) { | ||||
|             let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i]); | ||||
|  | ||||
|             inhibitor.connect('is-loaded', | ||||
|                               Lang.bind(this, function() { | ||||
|                                   this._onInhibitorLoaded(inhibitor); | ||||
|                               })); | ||||
|             this._inhibitors.push(inhibitor); | ||||
|         } | ||||
|  | ||||
|         this._updateButtons(); | ||||
|  | ||||
|         if (!this.open(timestamp)) | ||||
|             throw new DBus.DBusError('org.gnome.Shell.ModalDialog.GrabError', | ||||
|                                      "Cannot grab pointer and keyboard"); | ||||
|  | ||||
|         this._updateContent(); | ||||
|  | ||||
|         let signalId = this.connect('opened', | ||||
|                                     Lang.bind(this, function() { | ||||
|                                         callback(); | ||||
|                                         this.disconnect(signalId); | ||||
|                                     })); | ||||
|     } | ||||
| }; | ||||
| DBus.conformExport(EndSessionDialog.prototype, EndSessionDialogIface); | ||||
| @@ -1,22 +1,14 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| imports.gi.versions.Clutter = '1.0'; | ||||
| imports.gi.versions.Gio = '2.0'; | ||||
| imports.gi.versions.Gdk = '3.0'; | ||||
| imports.gi.versions.GdkPixbuf = '2.0'; | ||||
| imports.gi.versions.Gtk = '3.0'; | ||||
|  | ||||
| const Clutter = imports.gi.Clutter;; | ||||
| const Gettext = imports.gettext; | ||||
| const GLib = imports.gi.GLib; | ||||
| const Gtk = imports.gi.Gtk; | ||||
| const Shell = imports.gi.Shell; | ||||
| const St = imports.gi.St; | ||||
| const Gettext_gtk20 = imports.gettext.domain('gtk20'); | ||||
|  | ||||
| // We can't import shell JS modules yet, because they may have | ||||
| // variable initializations, etc, that depend on init() already having | ||||
| // been run. | ||||
| const Tweener = imports.ui.tweener; | ||||
|  | ||||
| const Format = imports.misc.format; | ||||
|  | ||||
| // "monkey patch" in some varargs ClutterContainer methods; we need | ||||
| // to do this per-container class since there is no representation | ||||
| @@ -25,7 +17,7 @@ function _patchContainerClass(containerClass) { | ||||
|     // This one is a straightforward mapping of the C method | ||||
|     containerClass.prototype.child_set = function(actor, props) { | ||||
|         let meta = this.get_child_meta(actor); | ||||
|         for (let prop in props) | ||||
|         for (prop in props) | ||||
|             meta[prop] = props[prop]; | ||||
|     }; | ||||
|  | ||||
| @@ -39,42 +31,44 @@ function _patchContainerClass(containerClass) { | ||||
|     }; | ||||
| } | ||||
|  | ||||
| function init() { | ||||
|     // Add some bindings to the global JS namespace; (gjs keeps the web | ||||
|     // browser convention of having that namespace be called 'window'.) | ||||
|     window.global = Shell.Global.get(); | ||||
| // Replace @method with something that throws an error instead | ||||
| function _blockMethod(method, replacement, reason) { | ||||
|     let match = method.match(/^(.+)\.([^.]+)$/); | ||||
|     if (!match) | ||||
|         throw new Error('Bad method name "' + method + '"'); | ||||
|     let proto = 'imports.gi.' + match[1] + '.prototype'; | ||||
|     let property = match[2]; | ||||
|  | ||||
|     window._ = Gettext.gettext; | ||||
|     window.C_ = Gettext.pgettext; | ||||
|     window.ngettext = Gettext.ngettext; | ||||
|     if (!global.set_property_mutable(proto, property, true)) | ||||
|         throw new Error('Bad method name "' + method + '"'); | ||||
|  | ||||
|     // eval() is evil in general, but we know it's safe here since | ||||
|     // set_property_mutable() would have failed if proto was | ||||
|     // malformed. | ||||
|     let node = eval(proto); | ||||
|  | ||||
|     let msg = 'Do not use "' + method + '".'; | ||||
|     if (replacement) | ||||
|         msg += ' Use "' + replacement + '" instead.'; | ||||
|     if (reason) | ||||
|         msg += ' (' + reason + ')'; | ||||
|  | ||||
|     node[property] = function() { | ||||
|         throw new Error(msg); | ||||
|     }; | ||||
|  | ||||
|     global.set_property_mutable(proto, property, false); | ||||
| } | ||||
|  | ||||
| function init() { | ||||
|     Tweener.init(); | ||||
|     String.prototype.format = Format.format; | ||||
|  | ||||
|     // Set the default direction for St widgets (this needs to be done before any use of St) | ||||
|     if (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL) { | ||||
|     if (Gettext_gtk20.gettext('default:LTR') == 'default:RTL') { | ||||
|         St.Widget.set_default_direction(St.TextDirection.RTL); | ||||
|     } | ||||
|  | ||||
|     // Miscellaneous monkeypatching | ||||
|     _patchContainerClass(St.BoxLayout); | ||||
|     _patchContainerClass(St.Table); | ||||
|  | ||||
|     Clutter.Actor.prototype.toString = function() { | ||||
|         return St.describe_actor(this); | ||||
|     }; | ||||
|  | ||||
|     let origToString = Object.prototype.toString; | ||||
|     Object.prototype.toString = function() { | ||||
|         let base = origToString.call(this); | ||||
|         if ('actor' in this && this.actor instanceof Clutter.Actor) | ||||
|             return base.replace(/\]$/, ' delegate for ' + this.actor.toString().substring(1)); | ||||
|         else | ||||
|             return base; | ||||
|     }; | ||||
|  | ||||
|     // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=508783 | ||||
|     Date.prototype.toLocaleFormat = function(format) { | ||||
|         return Shell.util_format_date(format, this.getTime()); | ||||
|     }; | ||||
|  | ||||
|     let slowdownEnv = GLib.getenv('GNOME_SHELL_SLOWDOWN_FACTOR'); | ||||
|     if (slowdownEnv) { | ||||
|         let factor = parseFloat(slowdownEnv); | ||||
| @@ -82,10 +76,26 @@ function init() { | ||||
|             St.set_slow_down_factor(factor); | ||||
|     } | ||||
|  | ||||
|     // OK, now things are initialized enough that we can import shell JS | ||||
|     const Format = imports.misc.format; | ||||
|     const Tweener = imports.ui.tweener; | ||||
|     _patchContainerClass(St.BoxLayout); | ||||
|     _patchContainerClass(St.Table); | ||||
|  | ||||
|     Tweener.init(); | ||||
|     String.prototype.format = Format.format; | ||||
|     Clutter.Actor.prototype.toString = function() { | ||||
|         return St.describe_actor(this); | ||||
|     }; | ||||
|  | ||||
|     if (window.global === undefined) // test environment | ||||
|         return; | ||||
|  | ||||
|     _blockMethod('Clutter.Event.get_state', 'Shell.get_event_state', | ||||
|                  'gjs\'s handling of Clutter.ModifierType is broken. See bug 597292.'); | ||||
|     _blockMethod('Gdk.Display.get_device_state', 'global.get_pointer', | ||||
|                  'gjs\'s handling of Gdk.ModifierType is broken. See bug 597292.'); | ||||
|     _blockMethod('Gdk.Window.get_device_position', 'global.get_pointer', | ||||
|                  'gjs\'s handling of Gdk.ModifierType is broken. See bug 597292.'); | ||||
|  | ||||
|     // Now close the back door to prevent extensions from trying to | ||||
|     // abuse it. We can't actually delete it since | ||||
|     // Shell.Global.prototype itself is read-only. | ||||
|     global.set_property_mutable('imports.gi.Shell.Global.prototype', 'set_property_mutable', true); | ||||
|     Shell.Global.prototype.set_property_mutable = undefined; | ||||
| } | ||||
|   | ||||
| @@ -1,31 +1,14 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Lang = imports.lang; | ||||
| const Signals = imports.signals; | ||||
|  | ||||
| const Clutter = imports.gi.Clutter; | ||||
| const GLib = imports.gi.GLib; | ||||
| const Gio = imports.gi.Gio; | ||||
| const St = imports.gi.St; | ||||
| const Shell = imports.gi.Shell; | ||||
| const Soup = imports.gi.Soup; | ||||
|  | ||||
| const Config = imports.misc.config; | ||||
| const FileUtils = imports.misc.fileUtils; | ||||
| const ModalDialog = imports.ui.modalDialog; | ||||
|  | ||||
| const API_VERSION = 1; | ||||
|  | ||||
| const ExtensionState = { | ||||
|     ENABLED: 1, | ||||
|     DISABLED: 2, | ||||
|     ERROR: 3, | ||||
|     OUT_OF_DATE: 4, | ||||
|     DOWNLOADING: 5, | ||||
|  | ||||
|     // Used as an error state for operations on unknown extensions, | ||||
|     // should never be in a real extensionMeta object. | ||||
|     UNINSTALLED: 99 | ||||
|     OUT_OF_DATE: 4 | ||||
| }; | ||||
|  | ||||
| const ExtensionType = { | ||||
| @@ -33,300 +16,72 @@ const ExtensionType = { | ||||
|     PER_USER: 2 | ||||
| }; | ||||
|  | ||||
| const REPOSITORY_URL_BASE = 'https://extensions.gnome.org'; | ||||
| const REPOSITORY_URL_DOWNLOAD = REPOSITORY_URL_BASE + '/download-extension/%s.shell-extension.zip'; | ||||
| const REPOSITORY_URL_INFO =     REPOSITORY_URL_BASE + '/extension-info/'; | ||||
|  | ||||
| const _httpSession = new Soup.SessionAsync(); | ||||
|  | ||||
| // The unfortunate state of gjs, gobject-introspection and libsoup | ||||
| // means that I have to do a hack to add a feature. | ||||
| // See: https://bugzilla.gnome.org/show_bug.cgi?id=655189 for context. | ||||
|  | ||||
| if (Soup.Session.prototype.add_feature != null) | ||||
|     Soup.Session.prototype.add_feature.call(_httpSession, new Soup.ProxyResolverDefault()); | ||||
|  | ||||
| function _getCertFile() { | ||||
|     let localCert = GLib.build_filenamev([global.userdatadir, 'extensions.gnome.org.crt']); | ||||
|     if (GLib.file_test(localCert, GLib.FileTest.EXISTS)) | ||||
|         return localCert; | ||||
|     else | ||||
|         return Config.SHELL_SYSTEM_CA_FILE; | ||||
| } | ||||
|  | ||||
| _httpSession.ssl_ca_file = _getCertFile(); | ||||
|  | ||||
| // Maps uuid -> metadata object | ||||
| const extensionMeta = {}; | ||||
| // Maps uuid -> importer object (extension directory tree) | ||||
| const extensions = {}; | ||||
| // Maps uuid -> extension state object (returned from init()) | ||||
| const extensionStateObjs = {}; | ||||
| // Arrays of uuids | ||||
| var enabledExtensions; | ||||
| // Array of uuids | ||||
| var disabledExtensions; | ||||
| // GFile for user extensions | ||||
| var userExtensionsDir = null; | ||||
|  | ||||
| // We don't really have a class to add signals on. So, create | ||||
| // a simple dummy object, add the signal methods, and export those | ||||
| // publically. | ||||
| var _signals = {}; | ||||
| Signals.addSignalMethods(_signals); | ||||
|  | ||||
| const connect = Lang.bind(_signals, _signals.connect); | ||||
| const disconnect = Lang.bind(_signals, _signals.disconnect); | ||||
|  | ||||
| // UUID => Array of error messages | ||||
| var errors = {}; | ||||
|  | ||||
| const ENABLED_EXTENSIONS_KEY = 'enabled-extensions'; | ||||
|  | ||||
| /** | ||||
|  * versionCheck: | ||||
|  * @required: an array of versions we're compatible with | ||||
|  * @current: the version we have | ||||
|  * | ||||
|  * Check if a component is compatible for an extension. | ||||
|  * @required is an array, and at least one version must match. | ||||
|  * @current must be in the format <major>.<minor>.<point>.<micro> | ||||
|  * <micro> is always ignored | ||||
|  * <point> is ignored if <minor> is even (so you can target the | ||||
|  * whole stable release) | ||||
|  * <minor> and <major> must match | ||||
|  * Each target version must be at least <major> and <minor> | ||||
|  */ | ||||
| function versionCheck(required, current) { | ||||
|     let currentArray = current.split('.'); | ||||
|     let major = currentArray[0]; | ||||
|     let minor = currentArray[1]; | ||||
|     let point = currentArray[2]; | ||||
|     for (let i = 0; i < required.length; i++) { | ||||
|         let requiredArray = required[i].split('.'); | ||||
|         if (requiredArray[0] == major && | ||||
|             requiredArray[1] == minor && | ||||
|             (requiredArray[2] == point || | ||||
|              (requiredArray[2] == undefined && parseInt(minor) % 2 == 0))) | ||||
|             return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| function installExtensionFromUUID(uuid, version_tag) { | ||||
|     let params = { uuid: uuid, | ||||
|                    version_tag: version_tag, | ||||
|                    shell_version: Config.PACKAGE_VERSION, | ||||
|                    api_version: API_VERSION.toString() }; | ||||
|  | ||||
|     let message = Soup.form_request_new_from_hash('GET', REPOSITORY_URL_INFO, params); | ||||
|  | ||||
|     _httpSession.queue_message(message, | ||||
|                                function(session, message) { | ||||
|                                    let info = JSON.parse(message.response_body.data); | ||||
|                                    let dialog = new InstallExtensionDialog(uuid, version_tag, info.name); | ||||
|                                    dialog.open(global.get_current_time()); | ||||
|                                }); | ||||
| } | ||||
|  | ||||
| function uninstallExtensionFromUUID(uuid) { | ||||
|     let meta = extensionMeta[uuid]; | ||||
|     if (!meta) | ||||
|         return false; | ||||
|  | ||||
|     // Try to disable it -- if it's ERROR'd, we can't guarantee that, | ||||
|     // but it will be removed on next reboot, and hopefully nothing | ||||
|     // broke too much. | ||||
|     disableExtension(uuid); | ||||
|  | ||||
|     // Don't try to uninstall system extensions | ||||
|     if (meta.type != ExtensionType.PER_USER) | ||||
|         return false; | ||||
|  | ||||
|     meta.state = ExtensionState.UNINSTALLED; | ||||
|     _signals.emit('extension-state-changed', meta); | ||||
|  | ||||
|     delete extensionMeta[uuid]; | ||||
|  | ||||
|     // Importers are marked as PERMANENT, so we can't do this. | ||||
|     // delete extensions[uuid]; | ||||
|     extensions[uuid] = undefined; | ||||
|  | ||||
|     delete extensionStateObjs[uuid]; | ||||
|     delete errors[uuid]; | ||||
|  | ||||
|     FileUtils.recursivelyDeleteDir(Gio.file_new_for_path(meta.path)); | ||||
|  | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| function gotExtensionZipFile(session, message, uuid) { | ||||
|     if (message.status_code != Soup.KnownStatusCode.OK) { | ||||
|         logExtensionError(uuid, 'downloading extension: ' + message.status_code); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // FIXME: use a GFile mkstemp-type method once one exists | ||||
|     let fd, tmpzip; | ||||
|     try { | ||||
|         [fd, tmpzip] = GLib.file_open_tmp('XXXXXX.shell-extension.zip'); | ||||
|     } catch (e) { | ||||
|         logExtensionError(uuid, 'tempfile: ' + e.toString()); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     let stream = new Gio.UnixOutputStream({ fd: fd }); | ||||
|     let dir = userExtensionsDir.get_child(uuid); | ||||
|     Shell.write_soup_message_to_stream(stream, message); | ||||
|     stream.close(null); | ||||
|     let [success, pid] = GLib.spawn_async(null, | ||||
|                                           ['unzip', '-uod', dir.get_path(), '--', tmpzip], | ||||
|                                           null, | ||||
|                                           GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD, | ||||
|                                           null); | ||||
|  | ||||
|     if (!success) { | ||||
|         logExtensionError(uuid, 'extract: could not extract'); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function(pid, status) { | ||||
|         GLib.spawn_close_pid(pid); | ||||
|  | ||||
|         // Add extension to 'enabled-extensions' for the user, always... | ||||
|         let enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY); | ||||
|         if (enabledExtensions.indexOf(uuid) == -1) { | ||||
|             enabledExtensions.push(uuid); | ||||
|             global.settings.set_strv(ENABLED_EXTENSIONS_KEY, enabledExtensions); | ||||
|         } | ||||
|  | ||||
|         loadExtension(dir, true, ExtensionType.PER_USER); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function disableExtension(uuid) { | ||||
|     let meta = extensionMeta[uuid]; | ||||
|     if (!meta) | ||||
|         return; | ||||
|  | ||||
|     if (meta.state != ExtensionState.ENABLED) | ||||
|         return; | ||||
|  | ||||
|     let extensionState = extensionStateObjs[uuid]; | ||||
|  | ||||
|     try { | ||||
|         extensionState.disable(); | ||||
|     } catch(e) { | ||||
|         logExtensionError(uuid, e.toString()); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     meta.state = ExtensionState.DISABLED; | ||||
|     _signals.emit('extension-state-changed', meta); | ||||
| } | ||||
|  | ||||
| function enableExtension(uuid) { | ||||
|     let meta = extensionMeta[uuid]; | ||||
|     if (!meta) | ||||
|         return; | ||||
|  | ||||
|     if (meta.state != ExtensionState.DISABLED) | ||||
|         return; | ||||
|  | ||||
|     let extensionState = extensionStateObjs[uuid]; | ||||
|  | ||||
|     try { | ||||
|         extensionState.enable(); | ||||
|     } catch(e) { | ||||
|         logExtensionError(uuid, e.toString()); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     meta.state = ExtensionState.ENABLED; | ||||
|     _signals.emit('extension-state-changed', meta); | ||||
| } | ||||
|  | ||||
| function logExtensionError(uuid, message, state) { | ||||
|     if (!errors[uuid]) errors[uuid] = []; | ||||
|     errors[uuid].push(message); | ||||
|     global.logError('Extension "%s" had error: %s'.format(uuid, message)); | ||||
|     state = state || ExtensionState.ERROR; | ||||
|     _signals.emit('extension-state-changed', { uuid: uuid, | ||||
|                                                error: message, | ||||
|                                                state: state }); | ||||
| } | ||||
|  | ||||
| function loadExtension(dir, enabled, type) { | ||||
|     let info; | ||||
|     let uuid = dir.get_basename(); | ||||
|     let baseErrorString = 'While loading extension from "' + dir.get_parse_name() + '": '; | ||||
|  | ||||
|     let metadataFile = dir.get_child('metadata.json'); | ||||
|     if (!metadataFile.query_exists(null)) { | ||||
|         logExtensionError(uuid, 'Missing metadata.json'); | ||||
|         global.logError(baseErrorString + 'Missing metadata.json'); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     let metadataContents; | ||||
|     try { | ||||
|         metadataContents = Shell.get_file_contents_utf8_sync(metadataFile.get_path()); | ||||
|     } catch (e) { | ||||
|         logExtensionError(uuid, 'Failed to load metadata.json: ' + e); | ||||
|         return; | ||||
|     } | ||||
|     let [success, metadataContents, len, etag] = metadataFile.load_contents(null); | ||||
|     let meta; | ||||
|     try { | ||||
|         meta = JSON.parse(metadataContents); | ||||
|     } catch (e) { | ||||
|         logExtensionError(uuid, 'Failed to parse metadata.json: ' + e); | ||||
|         global.logError(baseErrorString + 'Failed to parse metadata.json: ' + e); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     let requiredProperties = ['uuid', 'name', 'description', 'shell-version']; | ||||
|     for (let i = 0; i < requiredProperties.length; i++) { | ||||
|     let requiredProperties = ['uuid', 'name', 'description']; | ||||
|     for (let i = 0; i < requiredProperties; i++) { | ||||
|         let prop = requiredProperties[i]; | ||||
|         if (!meta[prop]) { | ||||
|             logExtensionError(uuid, 'missing "' + prop + '" property in metadata.json'); | ||||
|             global.logError(baseErrorString + 'missing "' + prop + '" property in metadata.json'); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (extensions[uuid] != undefined) { | ||||
|         logExtensionError(uuid, "extension already loaded"); | ||||
|     if (extensions[meta.uuid] != undefined) { | ||||
|         global.logError(baseErrorString + "extension already loaded"); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // Encourage people to add this | ||||
|     if (!meta['url']) { | ||||
|         global.log('Warning: Missing "url" property in metadata.json'); | ||||
|         global.log(baseErrorString + 'Warning: Missing "url" property in metadata.json'); | ||||
|     } | ||||
|  | ||||
|     if (uuid != meta.uuid) { | ||||
|         logExtensionError(uuid, 'uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"'); | ||||
|     let base = dir.get_basename(); | ||||
|     if (base != meta.uuid) { | ||||
|         global.logError(baseErrorString + 'uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + base + '"'); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (!versionCheck(meta['shell-version'], Config.PACKAGE_VERSION) || | ||||
|         (meta['js-version'] && !versionCheck(meta['js-version'], Config.GJS_VERSION))) { | ||||
|         logExtensionError(uuid, 'extension is not compatible with current GNOME Shell and/or GJS version'); | ||||
|     extensionMeta[meta.uuid] = meta; | ||||
|     extensionMeta[meta.uuid].type = type; | ||||
|     extensionMeta[meta.uuid].path = dir.get_path(); | ||||
|     if (!enabled) { | ||||
|         extensionMeta[meta.uuid].state = ExtensionState.DISABLED; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     extensionMeta[uuid] = meta; | ||||
|     meta.type = type; | ||||
|     meta.path = dir.get_path(); | ||||
|     meta.error = ''; | ||||
|  | ||||
|     // Default to error, we set success as the last step | ||||
|     meta.state = ExtensionState.ERROR; | ||||
|  | ||||
|     if (!versionCheck(meta['shell-version'], Config.PACKAGE_VERSION) || | ||||
|         (meta['js-version'] && !versionCheck(meta['js-version'], Config.GJS_VERSION))) { | ||||
|         logExtensionError(uuid, 'extension is not compatible with current GNOME Shell and/or GJS version', ExtensionState.OUT_OF_DATE); | ||||
|         meta.state = ExtensionState.OUT_OF_DATE; | ||||
|         return; | ||||
|     } | ||||
|     extensionMeta[meta.uuid].state = ExtensionState.ERROR; | ||||
|  | ||||
|     let extensionJs = dir.get_child('extension.js'); | ||||
|     if (!extensionJs.query_exists(null)) { | ||||
|         logExtensionError(uuid, 'Missing extension.js'); | ||||
|         global.logError(baseErrorString + 'Missing extension.js'); | ||||
|         return; | ||||
|     } | ||||
|     let stylesheetPath = null; | ||||
| @@ -337,113 +92,59 @@ function loadExtension(dir, enabled, type) { | ||||
|         try { | ||||
|             theme.load_stylesheet(stylesheetFile.get_path()); | ||||
|         } catch (e) { | ||||
|             logExtensionError(uuid, 'Stylesheet parse error: ' + e); | ||||
|             global.logError(baseErrorString + 'Stylesheet parse error: ' + e); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     let extensionModule; | ||||
|     let extensionState = null; | ||||
|     try { | ||||
|         global.add_extension_importer('imports.ui.extensionSystem.extensions', meta.uuid, dir.get_path()); | ||||
|         extensionModule = extensions[meta.uuid].extension; | ||||
|     } catch (e) { | ||||
|         if (stylesheetPath != null) | ||||
|             theme.unload_stylesheet(stylesheetPath); | ||||
|         logExtensionError(uuid, e); | ||||
|         global.logError(baseErrorString + e); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (!extensionModule.init) { | ||||
|         logExtensionError(uuid, 'missing \'init\' function'); | ||||
|     if (!extensionModule.main) { | ||||
|         global.logError(baseErrorString + 'missing \'main\' function'); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     try { | ||||
|         extensionState = extensionModule.init(meta); | ||||
|         extensionModule.main(); | ||||
|     } catch (e) { | ||||
|         if (stylesheetPath != null) | ||||
|             theme.unload_stylesheet(stylesheetPath); | ||||
|         logExtensionError(uuid, 'Failed to evaluate init function:' + e); | ||||
|         global.logError(baseErrorString + 'Failed to evaluate main function:' + e); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (!extensionState) | ||||
|         extensionState = extensionModule; | ||||
|     extensionStateObjs[uuid] = extensionState; | ||||
|  | ||||
|     if (!extensionState.enable) { | ||||
|         logExtensionError(uuid, 'missing \'enable\' function'); | ||||
|         return; | ||||
|     } | ||||
|     if (!extensionState.disable) { | ||||
|         logExtensionError(uuid, 'missing \'disable\' function'); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     meta.state = ExtensionState.DISABLED; | ||||
|  | ||||
|     if (enabled) | ||||
|         enableExtension(uuid); | ||||
|  | ||||
|     _signals.emit('extension-loaded', meta.uuid); | ||||
|     _signals.emit('extension-state-changed', meta); | ||||
|     extensionMeta[meta.uuid].state = ExtensionState.ENABLED; | ||||
|     global.log('Loaded extension ' + meta.uuid); | ||||
| } | ||||
|  | ||||
| function onEnabledExtensionsChanged() { | ||||
|     let newEnabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY); | ||||
|  | ||||
|     // Find and enable all the newly enabled extensions: UUIDs found in the | ||||
|     // new setting, but not in the old one. | ||||
|     newEnabledExtensions.filter(function(uuid) { | ||||
|         return enabledExtensions.indexOf(uuid) == -1; | ||||
|     }).forEach(function(uuid) { | ||||
|         enableExtension(uuid); | ||||
|     }); | ||||
|  | ||||
|     // Find and disable all the newly disabled extensions: UUIDs found in the | ||||
|     // old setting, but not in the new one. | ||||
|     enabledExtensions.filter(function(item) { | ||||
|         return newEnabledExtensions.indexOf(item) == -1; | ||||
|     }).forEach(function(uuid) { | ||||
|         disableExtension(uuid); | ||||
|     }); | ||||
|  | ||||
|     enabledExtensions = newEnabledExtensions; | ||||
| } | ||||
|  | ||||
| function init() { | ||||
|     let userExtensionsPath = GLib.build_filenamev([global.userdatadir, 'extensions']); | ||||
|     userExtensionsDir = Gio.file_new_for_path(userExtensionsPath); | ||||
|     try { | ||||
|         if (!userExtensionsDir.query_exists(null)) | ||||
|             userExtensionsDir.make_directory_with_parents(null); | ||||
|         userExtensionsDir.make_directory_with_parents(null); | ||||
|     } catch (e) { | ||||
|         global.logError('' + e); | ||||
|     } | ||||
|  | ||||
|     global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged); | ||||
|     enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY); | ||||
|     disabledExtensions = global.settings.get_strv('disabled-extensions', -1); | ||||
| } | ||||
|  | ||||
| function _loadExtensionsIn(dir, type) { | ||||
|     let fileEnum; | ||||
|     let fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null); | ||||
|     let file, info; | ||||
|     try { | ||||
|         fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null); | ||||
|     } catch (e) { | ||||
|         global.logError('' + e); | ||||
|        return; | ||||
|     } | ||||
|  | ||||
|     while ((info = fileEnum.next_file(null)) != null) { | ||||
|         let fileType = info.get_file_type(); | ||||
|         if (fileType != Gio.FileType.DIRECTORY) | ||||
|             continue; | ||||
|         let name = info.get_name(); | ||||
|         let enabled = disabledExtensions.indexOf(name) < 0; | ||||
|         let child = dir.get_child(name); | ||||
|         let enabled = enabledExtensions.indexOf(name) != -1; | ||||
|         loadExtension(child, enabled, type); | ||||
|     } | ||||
|     fileEnum.close(null); | ||||
| @@ -459,73 +160,3 @@ function loadExtensions() { | ||||
|             _loadExtensionsIn(dir, ExtensionType.SYSTEM); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function InstallExtensionDialog(uuid, version_tag, name) { | ||||
|     this._init(uuid, version_tag, name); | ||||
| } | ||||
|  | ||||
| InstallExtensionDialog.prototype = { | ||||
|     __proto__: ModalDialog.ModalDialog.prototype, | ||||
|  | ||||
|     _init: function(uuid, version_tag, name) { | ||||
|         ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'extension-dialog' }); | ||||
|  | ||||
|         this._uuid = uuid; | ||||
|         this._version_tag = version_tag; | ||||
|         this._name = name; | ||||
|  | ||||
|         this.setButtons([{ label: _("Cancel"), | ||||
|                            action: Lang.bind(this, this._onCancelButtonPressed), | ||||
|                            key:    Clutter.Escape | ||||
|                          }, | ||||
|                          { label:  _("Install"), | ||||
|                            action: Lang.bind(this, this._onInstallButtonPressed) | ||||
|                          }]); | ||||
|  | ||||
|         let message = _("Download and install '%s' from extensions.gnome.org?").format(name); | ||||
|  | ||||
|         this._descriptionLabel = new St.Label({ text: message }); | ||||
|  | ||||
|         this.contentLayout.add(this._descriptionLabel, | ||||
|                                { y_fill:  true, | ||||
|                                  y_align: St.Align.START }); | ||||
|     }, | ||||
|  | ||||
|     _onCancelButtonPressed: function(button, event) { | ||||
|         this.close(global.get_current_time()); | ||||
|  | ||||
|         // Even though the extension is already "uninstalled", send through | ||||
|         // a state-changed signal for any users who want to know if the install | ||||
|         // went through correctly -- using proper async DBus would block more | ||||
|         // traditional clients like the plugin | ||||
|         let meta = { uuid: this._uuid, | ||||
|                      state: ExtensionState.UNINSTALLED, | ||||
|                      error: '' }; | ||||
|  | ||||
|         _signals.emit('extension-state-changed', meta); | ||||
|     }, | ||||
|  | ||||
|     _onInstallButtonPressed: function(button, event) { | ||||
|         let meta = { uuid: this._uuid, | ||||
|                      state: ExtensionState.DOWNLOADING, | ||||
|                      error: '' }; | ||||
|  | ||||
|         extensionMeta[this._uuid] = meta; | ||||
|  | ||||
|         _signals.emit('extension-state-changed', meta); | ||||
|  | ||||
|         let params = { version_tag: this._version_tag, | ||||
|                        shell_version: Config.PACKAGE_VERSION, | ||||
|                        api_version: API_VERSION.toString() }; | ||||
|  | ||||
|         let url = REPOSITORY_URL_DOWNLOAD.format(this._uuid); | ||||
|         let message = Soup.form_request_new_from_hash('GET', url, params); | ||||
|  | ||||
|         _httpSession.queue_message(message, | ||||
|                                    Lang.bind(this, function(session, message) { | ||||
|                                        gotExtensionZipFile(session, message, this._uuid); | ||||
|                                    })); | ||||
|  | ||||
|         this.close(global.get_current_time()); | ||||
|     } | ||||
| }; | ||||
|   | ||||
							
								
								
									
										693
									
								
								js/ui/genericDisplay.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,693 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Gtk = imports.gi.Gtk; | ||||
| const Lang = imports.lang; | ||||
| const Signals = imports.signals; | ||||
| const St = imports.gi.St; | ||||
|  | ||||
| const DND = imports.ui.dnd; | ||||
| const Main = imports.ui.main; | ||||
|  | ||||
| const RedisplayFlags = { NONE: 0, | ||||
|                          FULL: 1 << 1, | ||||
|                          SUBSEARCH: 1 << 2, | ||||
|                          IMMEDIATE: 1 << 3 }; | ||||
|  | ||||
| // Used by subclasses | ||||
| const ITEM_DISPLAY_ICON_SIZE = 48; | ||||
| const PREVIEW_ICON_SIZE = 96; | ||||
|  | ||||
| /* This is a virtual class that represents a single display item containing | ||||
|  * a name, a description, and an icon. It allows selecting an item and represents | ||||
|  * it by highlighting it with a different background color than the default. | ||||
|  */ | ||||
| function GenericDisplayItem() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| GenericDisplayItem.prototype = { | ||||
|     _init: function() { | ||||
|         this.actor = new St.BoxLayout({ style_class: 'generic-display-item', | ||||
|                                          reactive: true }); | ||||
|  | ||||
|         this.actor._delegate = this; | ||||
|         this.actor.connect('button-release-event', | ||||
|                            Lang.bind(this, | ||||
|                                      function() { | ||||
|                                          // Activates the item by launching it | ||||
|                                          this.emit('activate'); | ||||
|                                          return true;   | ||||
|                                      })); | ||||
|  | ||||
|         let draggable = DND.makeDraggable(this.actor); | ||||
|         draggable.connect('drag-begin', | ||||
|                           Lang.bind(this, function() { | ||||
|                               Main.overview.beginItemDrag(this); | ||||
|                           })); | ||||
|         draggable.connect('drag-end', | ||||
|                           Lang.bind(this, function() { | ||||
|                               Main.overview.endItemDrag(this); | ||||
|                           })); | ||||
|  | ||||
|         this._iconBin = new St.Bin(); | ||||
|         this.actor.add(this._iconBin); | ||||
|  | ||||
|         this._infoText = new St.BoxLayout({ style_class: 'generic-display-item-text', | ||||
|                                              vertical: true }); | ||||
|         this.actor.add(this._infoText, { expand: true, y_fill: false }); | ||||
|  | ||||
|         this._name = null; | ||||
|         this._description = null; | ||||
|         this._icon = null; | ||||
|  | ||||
|         this._initialLoadComplete = false; | ||||
|  | ||||
|         // An array of details description actors that we create over time for the item. | ||||
|         // It is used for updating the description text inside the details actor when | ||||
|         // the description text for the item is updated. | ||||
|         this._detailsDescriptions = []; | ||||
|     }, | ||||
|  | ||||
|     //// Draggable object interface //// | ||||
|  | ||||
|     // Returns a cloned texture of the item's icon to represent the item as it  | ||||
|     // is being dragged.  | ||||
|     getDragActor: function(stageX, stageY) { | ||||
|         return this._createIcon(); | ||||
|     }, | ||||
|  | ||||
|     // Returns the item icon, a separate copy of which is used to | ||||
|     // represent the item as it is being dragged. This is used to | ||||
|     // determine a snap-back location for the drag icon if it does | ||||
|     // not get accepted by any drop target. | ||||
|     getDragActorSource: function() { | ||||
|         return this._icon; | ||||
|     }, | ||||
|  | ||||
|     //// Public methods //// | ||||
|  | ||||
|     // Highlights the item by setting a different background color than the default  | ||||
|     // if isSelected is true, removes the highlighting otherwise. | ||||
|     markSelected: function(isSelected) { | ||||
|         if (isSelected) | ||||
|             this.actor.add_style_pseudo_class('selected'); | ||||
|         else | ||||
|             this.actor.remove_style_pseudo_class('selected'); | ||||
|     }, | ||||
|  | ||||
|     /* | ||||
|      * Returns an actor containing item details. In the future details can have more information than what | ||||
|      * the preview pop-up has and be item-type specific. | ||||
|      */ | ||||
|     createDetailsActor: function() { | ||||
|  | ||||
|         let details = new St.BoxLayout({ style_class: 'generic-display-container', | ||||
|                                          vertical: true }); | ||||
|  | ||||
|         let mainDetails = new St.BoxLayout({ style_class: 'generic-display-container' }); | ||||
|  | ||||
|         // Inner box with name and description | ||||
|         let textDetails = new St.BoxLayout({ style_class: 'generic-display-details', | ||||
|                                              vertical: true }); | ||||
|         let detailsName = new St.Label({ style_class: 'generic-display-details-name', | ||||
|                                           text: this._name.text }); | ||||
|         textDetails.add(detailsName); | ||||
|  | ||||
|         let detailsDescription = new St.Label({ text: this._description.text }); | ||||
|         textDetails.add(detailsDescription); | ||||
|  | ||||
|         this._detailsDescriptions.push(detailsDescription); | ||||
|  | ||||
|         mainDetails.add(textDetails, { expand: true }); | ||||
|  | ||||
|         let previewIcon = this._createPreviewIcon(); | ||||
|         let largePreviewIcon = this._createLargePreviewIcon(); | ||||
|  | ||||
|         if (previewIcon != null && largePreviewIcon == null) { | ||||
|             mainDetails.insert_actor(previewIcon, 0); | ||||
|         } | ||||
|  | ||||
|         details.add(mainDetails); | ||||
|  | ||||
|         if (largePreviewIcon != null) { | ||||
|             details.add(largePreviewIcon); | ||||
|         } | ||||
|     | ||||
|         return details; | ||||
|     }, | ||||
|  | ||||
|     // Destroys the item. | ||||
|     destroy: function() { | ||||
|         this.actor.destroy(); | ||||
|     }, | ||||
|  | ||||
|     //// Pure virtual public methods //// | ||||
|  | ||||
|     // Performes an action associated with launching this item, such as opening a file or an application. | ||||
|     launch: function() { | ||||
|         throw new Error('Not implemented'); | ||||
|     }, | ||||
|  | ||||
|     //// Protected methods //// | ||||
|  | ||||
|     /* | ||||
|      * Creates the graphical elements for the item based on the item information. | ||||
|      * | ||||
|      * nameText - name of the item | ||||
|      * descriptionText - short description of the item | ||||
|      */ | ||||
|     _setItemInfo: function(nameText, descriptionText) { | ||||
|         if (this._name != null) { | ||||
|             // this also removes this._name from the parent container, | ||||
|             // so we don't need to call this.actor.remove_actor(this._name) directly | ||||
|             this._name.destroy(); | ||||
|             this._name = null; | ||||
|         }  | ||||
|         if (this._description != null) { | ||||
|             this._description.destroy(); | ||||
|             this._description = null; | ||||
|         }  | ||||
|         if (this._icon != null) { | ||||
|             // though we get the icon from elsewhere, we assume its ownership here, | ||||
|             // and therefore should be responsible for distroying it | ||||
|             this._icon.destroy(); | ||||
|             this._icon = null; | ||||
|         } | ||||
|  | ||||
|         this._icon = this._createIcon(); | ||||
|         this._iconBin.set_child(this._icon); | ||||
|  | ||||
|         this._name = new St.Label({ style_class: 'generic-display-item-name', | ||||
|                                      text: nameText }); | ||||
|         this._infoText.add(this._name); | ||||
|  | ||||
|         this._description = new St.Label({ style_class: 'generic-display-item-description', | ||||
|                                             text: descriptionText ? descriptionText : '' }); | ||||
|         this._infoText.add(this._description); | ||||
|     }, | ||||
|  | ||||
|     // Sets the description text for the item, including the description text | ||||
|     // in the details actors that have been created for the item. | ||||
|     _setDescriptionText: function(text) { | ||||
|         this._description.text = text; | ||||
|         for (let i = 0; i < this._detailsDescriptions.length; i++) { | ||||
|             let detailsDescription = this._detailsDescriptions[i]; | ||||
|             if (detailsDescription != null) { | ||||
|                 detailsDescription.text = text; | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     //// Virtual protected methods //// | ||||
|  | ||||
|     // Creates and returns a large preview icon, but only if we have a detailed image. | ||||
|     _createLargePreviewIcon : function() { | ||||
|         return null; | ||||
|     }, | ||||
|  | ||||
|     //// Pure virtual protected methods //// | ||||
|  | ||||
|     // Returns an icon for the item. | ||||
|     _createIcon: function() { | ||||
|         throw new Error('Not implemented'); | ||||
|     }, | ||||
|  | ||||
|     // Returns a preview icon for the item. | ||||
|     _createPreviewIcon: function() { | ||||
|         throw new Error('Not implemented'); | ||||
|     } | ||||
|  | ||||
|     //// Private methods //// | ||||
| }; | ||||
|  | ||||
| Signals.addSignalMethods(GenericDisplayItem.prototype); | ||||
|  | ||||
| /* This is a virtual class that represents a display containing a collection of items | ||||
|  * that can be filtered with a search string. | ||||
|  */ | ||||
| function GenericDisplay() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| GenericDisplay.prototype = { | ||||
|     _init : function() { | ||||
|         this._search = ''; | ||||
|         this._expanded = false; | ||||
|  | ||||
|         this.actor = new St.ScrollView({ x_fill: true, | ||||
|                                          y_fill: false, | ||||
|                                          vshadows: true }); | ||||
|         this._list = new St.BoxLayout({ style_class: 'generic-display-container', | ||||
|                                          vertical: true }); | ||||
|         this.actor.add_actor(this._list); | ||||
|         this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); | ||||
|  | ||||
|         this._pendingRedisplay = RedisplayFlags.NONE; | ||||
|         this.actor.connect('notify::mapped', Lang.bind(this, this._onMappedNotify)); | ||||
|  | ||||
|         // map<itemId, Object> where Object represents the item info | ||||
|         this._allItems = {}; | ||||
|         // set<itemId> | ||||
|         this._matchedItems = {}; | ||||
|         // sorted array of items matched by search | ||||
|         this._matchedItemKeys = []; | ||||
|         // map<itemId, GenericDisplayItem> | ||||
|         this._displayedItems = {}; | ||||
|         this._openDetailIndex = -1; | ||||
|         this._selectedIndex = -1; | ||||
|     }, | ||||
|  | ||||
|     //// Public methods //// | ||||
|  | ||||
|     // Sets the search string and displays the matching items. | ||||
|     setSearch: function(text) { | ||||
|         let lowertext = text.toLowerCase(); | ||||
|         if (lowertext == this._search) { | ||||
|             return; | ||||
|         } | ||||
|         let flags = RedisplayFlags.IMMEDIATE; | ||||
|         if (this._search != '') { | ||||
|             // Because we combine search terms with OR, we have to be sure that no new term | ||||
|             // was introduced before deciding that the new search results will be a subset of | ||||
|             // the existing search results. | ||||
|             if (lowertext.indexOf(this._search) == 0 && | ||||
|                 lowertext.split(/\s+/).length == this._search.split(/\s+/).length) { | ||||
|                 flags |= RedisplayFlags.SUBSEARCH; | ||||
|             } | ||||
|         } | ||||
|         this._search = lowertext; | ||||
|         this._redisplay(flags); | ||||
|     }, | ||||
|  | ||||
|     // Launches the item that is currently selected, closing the Overview | ||||
|     activateSelected: function() { | ||||
|         if (this._selectedIndex != -1) { | ||||
|             let selected = this._findDisplayedByIndex(this._selectedIndex); | ||||
|             selected.launch(); | ||||
|             this.unsetSelected(); | ||||
|             Main.overview.hide(); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     // Moves the selection one up. If the selection was already on the top item, it's moved | ||||
|     // to the bottom one. Returns true if the selection actually moved up, false if it wrapped  | ||||
|     // around to the bottom. | ||||
|     selectUp: function() { | ||||
|         let count = this._getVisibleCount(); | ||||
|         let selectedUp = true; | ||||
|         let prev = this._selectedIndex - 1; | ||||
|         if (this._selectedIndex <= 0) { | ||||
|             prev = count - 1; | ||||
|             selectedUp = false;  | ||||
|         } | ||||
|         this._selectIndex(prev); | ||||
|         return selectedUp; | ||||
|     }, | ||||
|  | ||||
|     // Moves the selection one down. If the selection was already on the bottom item, it's moved | ||||
|     // to the top one. Returns true if the selection actually moved down, false if it wrapped  | ||||
|     // around to the top. | ||||
|     selectDown: function() { | ||||
|         let count = this._getVisibleCount(); | ||||
|         let selectedDown = true; | ||||
|         let next = this._selectedIndex + 1; | ||||
|         if (this._selectedIndex == count - 1) { | ||||
|             next = 0; | ||||
|             selectedDown = false; | ||||
|         } | ||||
|         this._selectIndex(next); | ||||
|         return selectedDown; | ||||
|     }, | ||||
|  | ||||
|     // Selects the first item among the displayed items. | ||||
|     selectFirstItem: function() { | ||||
|         if (this.hasItems()) | ||||
|             this._selectIndex(0); | ||||
|     }, | ||||
|  | ||||
|     // Selects the last item among the displayed items. | ||||
|     selectLastItem: function() { | ||||
|         let count = this._getVisibleCount(); | ||||
|         if (this.hasItems()) | ||||
|             this._selectIndex(count - 1); | ||||
|     }, | ||||
|  | ||||
|     // Returns true if the display has some item selected. | ||||
|     hasSelected: function() { | ||||
|         return this._selectedIndex != -1; | ||||
|     }, | ||||
|  | ||||
|     // Removes selection if some display item is selected. | ||||
|     unsetSelected: function() { | ||||
|         this._selectIndex(-1); | ||||
|     }, | ||||
|  | ||||
|     // Returns true if the display has any displayed items. | ||||
|     hasItems: function() { | ||||
|         // TODO: figure out why this._list.displayedCount is returning a | ||||
|         // positive number when this._mathedItems.length is 0 | ||||
|         // This can be triggered if a search string is entered for which there are no matches. | ||||
|         // log('this._mathedItems.length: ' + this._matchedItems.length + ' this._list.displayedCount ' + this._list.displayedCount); | ||||
|         return this._matchedItemKeys.length > 0; | ||||
|     }, | ||||
|  | ||||
|     getMatchedItemsCount: function() { | ||||
|         return this._matchedItemKeys.length; | ||||
|     }, | ||||
|  | ||||
|     // Load the initial state | ||||
|     load: function() { | ||||
|         this._redisplay(RedisplayFlags.FULL); | ||||
|     }, | ||||
|  | ||||
|     // Should be called when the display is closed | ||||
|     resetState: function() { | ||||
|         this._filterReset(); | ||||
|         this._openDetailIndex = -1; | ||||
|         this.actor.get_vscroll_bar().get_adjustment().value = 0; | ||||
|     }, | ||||
|  | ||||
|     // Returns an actor which acts as a sidebar; this is used for | ||||
|     // the applications category view | ||||
|     getNavigationArea: function () { | ||||
|         return null; | ||||
|     }, | ||||
|  | ||||
|     createDetailsForIndex: function(index) { | ||||
|         let item = this._findDisplayedByIndex(index); | ||||
|         return item.createDetailsActor(); | ||||
|     }, | ||||
|  | ||||
|     //// Protected methods //// | ||||
|  | ||||
|     _recreateDisplayItems: function() { | ||||
|         this._removeAllDisplayItems(); | ||||
|         this._setDefaultList(); | ||||
|         for (let itemId in this._allItems) { | ||||
|             this._addDisplayItem(itemId); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     // Creates a display item based on the information associated with itemId | ||||
|     // and adds it to the list of displayed items, but does not yet display it. | ||||
|     _addDisplayItem : function(itemId) { | ||||
|         if (this._displayedItems.hasOwnProperty(itemId)) { | ||||
|             log('Tried adding a display item for ' + itemId + ', but an item with this item id is already among displayed items.'); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         let itemInfo = this._allItems[itemId]; | ||||
|         let displayItem = this._createDisplayItem(itemInfo); | ||||
|  | ||||
|         displayItem.connect('activate', | ||||
|                             Lang.bind(this, | ||||
|                                       function() { | ||||
|                                           // update the selection | ||||
|                                           this._selectIndex(this._list.get_children().indexOf(displayItem.actor)); | ||||
|                                           this.activateSelected(); | ||||
|                                       })); | ||||
|  | ||||
|         displayItem.connect('show-details', | ||||
|                             Lang.bind(this, | ||||
|                                       function() { | ||||
|                                           let index = this._list.get_children().indexOf(displayItem.actor); | ||||
|                                           /* Close the details pane if already open */ | ||||
|                                           if (index == this._openDetailIndex) { | ||||
|                                               this._openDetailIndex = -1; | ||||
|                                               this.emit('show-details', -1); | ||||
|                                           } else { | ||||
|                                               this._openDetailIndex = index; | ||||
|                                               this.emit('show-details', index); | ||||
|                                           } | ||||
|                                       })); | ||||
|         this._displayedItems[itemId] = displayItem; | ||||
|     }, | ||||
|  | ||||
|     // Removes an item identifed by the itemId from the displayed items. | ||||
|     _removeDisplayItem: function(itemId) { | ||||
|         let children = this._list.get_children(); | ||||
|         let count = children.length; | ||||
|         let displayItem = this._displayedItems[itemId]; | ||||
|         let displayItemIndex = children.indexOf(displayItem.actor); | ||||
|  | ||||
|         if (this.hasSelected() && count == 1) { | ||||
|             this.unsetSelected(); | ||||
|         } else if (this.hasSelected() && displayItemIndex < this._selectedIndex) { | ||||
|             this.selectUp(); | ||||
|         } | ||||
|  | ||||
|         displayItem.destroy(); | ||||
|  | ||||
|         delete this._displayedItems[itemId]; | ||||
|     }, | ||||
|  | ||||
|     // Removes all displayed items. | ||||
|     _removeAllDisplayItems: function() { | ||||
|         this.unsetSelected(); | ||||
|         for (itemId in this._displayedItems) | ||||
|             this._removeDisplayItem(itemId); | ||||
|      }, | ||||
|  | ||||
|     // Return true if there's an active search or other constraint | ||||
|     // on the list | ||||
|     _filterActive: function() { | ||||
|         return this._search != ''; | ||||
|     }, | ||||
|  | ||||
|     // Called when we are resetting state | ||||
|     _filterReset: function() { | ||||
|         this.unsetSelected(); | ||||
|     }, | ||||
|  | ||||
|     _compareSearchMatch: function(a, b) { | ||||
|         let countA = this._matchedItems[a]; | ||||
|         let countB = this._matchedItems[b]; | ||||
|         if (countA > countB) | ||||
|             return -1; | ||||
|         else if (countA < countB) | ||||
|             return 1; | ||||
|         else | ||||
|             return this._compareItems(a, b); | ||||
|     }, | ||||
|  | ||||
|     _setMatches: function(matches) { | ||||
|         this._matchedItems = matches; | ||||
|         this._matchedItemKeys = []; | ||||
|         for (let itemId in this._matchedItems) { | ||||
|             this._matchedItemKeys.push(itemId); | ||||
|         } | ||||
|         this._matchedItemKeys.sort(Lang.bind(this, this._compareSearchMatch)); | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|      * _redisplaySubSearch: | ||||
|      * A somewhat more optimized function called when we know | ||||
|      * that we're going to be displaying a subset of the items | ||||
|      * we already had, in the same order.  In that case, we can | ||||
|      * just hide the actors that shouldn't be shown. | ||||
|      */ | ||||
|     _redisplaySubSearch: function() { | ||||
|         let matches = this._getSearchMatchedItems(true); | ||||
|  | ||||
|         // Just hide all from the old set, | ||||
|         // we'll show the ones we want below | ||||
|         for (let itemId in this._displayedItems) { | ||||
|             let item = this._displayedItems[itemId]; | ||||
|             item.actor.hide(); | ||||
|         } | ||||
|  | ||||
|         this._setMatches(matches); | ||||
|  | ||||
|         for (let itemId in matches) { | ||||
|             let item = this._displayedItems[itemId]; | ||||
|             item.actor.show(); | ||||
|         } | ||||
|         this._list.queue_relayout(); | ||||
|     }, | ||||
|  | ||||
|     _redisplayReordering: function() { | ||||
|         if (!this._filterActive()) { | ||||
|             this._setDefaultList(); | ||||
|         } else { | ||||
|             this._setMatches(this._getSearchMatchedItems(false)); | ||||
|         } | ||||
|         this._list.remove_all(); | ||||
|         for (let i = 0; i < this._matchedItemKeys.length; i++) { | ||||
|             let itemId = this._matchedItemKeys[i]; | ||||
|             let item = this._displayedItems[itemId]; | ||||
|             item.actor.show(); | ||||
|             this._list.add_actor(item.actor); | ||||
|        } | ||||
|     }, | ||||
|  | ||||
|     /* | ||||
|      * Updates the displayed items, applying the search string if one exists. | ||||
|      * @flags: Flags controlling redisplay behavior as follows: | ||||
|      *  SUBSEARCH - Indicates that the current _search is a superstring of the previous | ||||
|      *  one, which implies we only need to re-search through previous results. | ||||
|      *  FULL - Indicates that we need recreate all displayed items. | ||||
|      *  IMMEDIATE - Do the full redisplay even if we're not mapped.  This is useful | ||||
|      *  if you want to get the number of matched items and show/hide a section based on | ||||
|      *  that number. | ||||
|      */ | ||||
|     _redisplay: function(flags) { | ||||
|         let immediate = (flags & RedisplayFlags.IMMEDIATE) != 0; | ||||
|         if (!immediate && !this.actor.mapped) { | ||||
|             this._pendingRedisplay |= flags; | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         let isSubSearch = (flags & RedisplayFlags.SUBSEARCH) != 0; | ||||
|         let fullReload = (flags & RedisplayFlags.FULL) != 0; | ||||
|  | ||||
|         let hadSelected = this.hasSelected(); | ||||
|         this.unsetSelected(); | ||||
|  | ||||
|         if (!this._initialLoadComplete) | ||||
|             fullReload = true; | ||||
|  | ||||
|         if (!this._refreshCache()) | ||||
|             fullReload = true; | ||||
|  | ||||
|         if (fullReload) { | ||||
|             this._recreateDisplayItems(); | ||||
|             this._initialLoadComplete = true; | ||||
|         } | ||||
|  | ||||
|         if (isSubSearch) { | ||||
|             this._redisplaySubSearch(); | ||||
|         } else { | ||||
|             this._redisplayReordering(); | ||||
|         } | ||||
|  | ||||
|         if (hadSelected) { | ||||
|             this._selectedIndex = -1; | ||||
|             this.selectFirstItem(); | ||||
|         } | ||||
|  | ||||
|         this.emit('redisplayed'); | ||||
|     }, | ||||
|  | ||||
|     //// Pure virtual protected methods //// | ||||
|  | ||||
|     // Performs the steps needed to have the latest information about the items. | ||||
|     // Implementation should return %true if we are up to date, and %false | ||||
|     // if a full reload occurred. | ||||
|     _refreshCache: function() { | ||||
|         throw new Error('Not implemented'); | ||||
|     }, | ||||
|  | ||||
|     // Sets the list of the displayed items based on the default sorting order. | ||||
|     // The default sorting order is specific to each implementing class. | ||||
|     _setDefaultList: function() { | ||||
|         throw new Error('Not implemented'); | ||||
|     }, | ||||
|  | ||||
|     // Compares items associated with the item ids based on the order in which the | ||||
|     // items should be displayed. | ||||
|     // Intended to be used as a compareFunction for array.sort(). | ||||
|     // Returns an integer value indicating the result of the comparison. | ||||
|     _compareItems: function(itemIdA, itemIdB) { | ||||
|         throw new Error('Not implemented'); | ||||
|     }, | ||||
|  | ||||
|     // Checks if the item info can be a match for the search string.  | ||||
|     // Returns a boolean flag indicating if that's the case. | ||||
|     _isInfoMatching: function(itemInfo, search) { | ||||
|         throw new Error('Not implemented'); | ||||
|     }, | ||||
|  | ||||
|     // Creates a display item based on itemInfo. | ||||
|     _createDisplayItem: function(itemInfo) { | ||||
|         throw new Error('Not implemented'); | ||||
|     }, | ||||
|  | ||||
|     //// Private methods //// | ||||
|  | ||||
|     _getItemSearchScore: function(itemId, terms) { | ||||
|         let item = this._allItems[itemId]; | ||||
|         let score = 0; | ||||
|         for (let i = 0; i < terms.length; i++) { | ||||
|             let term = terms[i]; | ||||
|             if (this._isInfoMatching(item, term)) { | ||||
|                 score++; | ||||
|             } | ||||
|         } | ||||
|         return score; | ||||
|     }, | ||||
|  | ||||
|     _getSearchMatchedItems: function(isSubSearch) { | ||||
|         // Break the search up into terms, and search for each | ||||
|         // individual term.  Keep track of the number of terms | ||||
|         // each item matched. | ||||
|         let terms = this._search.split(/\s+/); | ||||
|         let matchScores = {}; | ||||
|  | ||||
|         if (isSubSearch) { | ||||
|             for (let i = 0; i < this._matchedItemKeys.length; i++) { | ||||
|                 let itemId = this._matchedItemKeys[i]; | ||||
|                 let score = this._getItemSearchScore(itemId, terms); | ||||
|                 if (score > 0) | ||||
|                     matchScores[itemId] = score; | ||||
|             } | ||||
|         } else { | ||||
|             for (let itemId in this._displayedItems) { | ||||
|                 let score = this._getItemSearchScore(itemId, terms); | ||||
|                 if (score > 0) | ||||
|                     matchScores[itemId] = score; | ||||
|             } | ||||
|         } | ||||
|         return matchScores; | ||||
|     }, | ||||
|  | ||||
|     // Returns a display item based on its index in the ordering of the | ||||
|     // display children. | ||||
|     _findDisplayedByIndex: function(index) { | ||||
|         let actor = this._list.get_children()[index]; | ||||
|         return this._findDisplayedByActor(actor); | ||||
|     }, | ||||
|  | ||||
|     // Returns a display item based on the actor that represents it in  | ||||
|     // the display. | ||||
|     _findDisplayedByActor: function(actor) { | ||||
|         for (itemId in this._displayedItems) { | ||||
|             let item = this._displayedItems[itemId]; | ||||
|             if (item.actor == actor) { | ||||
|                 return item; | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     }, | ||||
|  | ||||
|     // Selects (e.g. highlights) a display item at the provided index, | ||||
|     // updates this.selectedItemDetails actor, and emits 'selected' signal. | ||||
|     _selectIndex: function(index) { | ||||
|         // Cleanup from the previous item | ||||
|         if (this.hasSelected()) { | ||||
|             this._findDisplayedByIndex(this._selectedIndex).markSelected(false); | ||||
|         } | ||||
|  | ||||
|         this._selectedIndex = index; | ||||
|         if (index < 0) | ||||
|             return; | ||||
|  | ||||
|         // Mark the new item as selected and create its details pane | ||||
|         let item = this._findDisplayedByIndex(index); | ||||
|         item.markSelected(true); | ||||
|         this.emit('selected'); | ||||
|     }, | ||||
|  | ||||
|     _getVisibleCount: function() { | ||||
|         return this._list.get_n_children(); | ||||
|     }, | ||||
|  | ||||
|     _onMappedNotify: function () { | ||||
|         let mapped = this.actor.mapped; | ||||
|         if (mapped && this._pendingRedisplay > RedisplayFlags.NONE) | ||||
|             this._redisplay(this._pendingRedisplay); | ||||
|  | ||||
|         this._pendingRedisplay = RedisplayFlags.NONE; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| Signals.addSignalMethods(GenericDisplay.prototype); | ||||
| @@ -17,8 +17,7 @@ function BaseIcon(label, createIcon) { | ||||
| BaseIcon.prototype = { | ||||
|     _init : function(label, params) { | ||||
|         params = Params.parse(params, { createIcon: null, | ||||
|                                         setSizeManually: false, | ||||
|                                         showLabel: true }); | ||||
|                                         setSizeManually: false }); | ||||
|         this.actor = new St.Bin({ style_class: 'overview-icon', | ||||
|                                   x_fill: true, | ||||
|                                   y_fill: true }); | ||||
| @@ -41,52 +40,42 @@ BaseIcon.prototype = { | ||||
|  | ||||
|         box.add_actor(this._iconBin); | ||||
|  | ||||
|         if (params.showLabel) { | ||||
|             this.label = new St.Label({ text: label }); | ||||
|             box.add_actor(this.label); | ||||
|         } else { | ||||
|             this.label = null; | ||||
|         } | ||||
|         this._name = new St.Label({ text: label }); | ||||
|         box.add_actor(this._name); | ||||
|  | ||||
|         if (params.createIcon) | ||||
|             this.createIcon = params.createIcon; | ||||
|         this._setSizeManually = params.setSizeManually; | ||||
|  | ||||
|         this.icon = null; | ||||
|         this.icon = this.createIcon(this.iconSize); | ||||
|         this._iconBin.set_child(this.icon); | ||||
|     }, | ||||
|  | ||||
|     _allocate: function(actor, box, flags) { | ||||
|         let availWidth = box.x2 - box.x1; | ||||
|         let availHeight = box.y2 - box.y1; | ||||
|  | ||||
|         let iconSize = availHeight; | ||||
|  | ||||
|         let [labelMinHeight, labelNatHeight] = this._name.get_preferred_height(-1); | ||||
|         let [iconMinHeight, iconNatHeight] = this._iconBin.get_preferred_height(-1); | ||||
|         let [iconMinWidth, iconNatWidth] = this._iconBin.get_preferred_width(-1); | ||||
|         let preferredHeight = iconNatHeight; | ||||
|         let preferredHeight = labelNatHeight + this._spacing + iconNatHeight; | ||||
|         let labelHeight = availHeight >= preferredHeight ? labelNatHeight | ||||
|                                                          : labelMinHeight; | ||||
|         let iconSize = availHeight - this._spacing - labelHeight; | ||||
|         let iconPadding = (availWidth - iconSize) / 2; | ||||
|  | ||||
|         let childBox = new Clutter.ActorBox(); | ||||
|  | ||||
|         if (this.label) { | ||||
|             let [labelMinHeight, labelNatHeight] = this.label.get_preferred_height(-1); | ||||
|             preferredHeight += this._spacing + labelNatHeight; | ||||
|  | ||||
|             let labelHeight = availHeight >= preferredHeight ? labelNatHeight | ||||
|                                                              : labelMinHeight; | ||||
|             iconSize -= this._spacing + labelHeight; | ||||
|  | ||||
|             childBox.x1 = 0; | ||||
|             childBox.x2 = availWidth; | ||||
|             childBox.y1 = iconSize + this._spacing; | ||||
|             childBox.y2 = childBox.y1 + labelHeight; | ||||
|             this.label.allocate(childBox, flags); | ||||
|         } | ||||
|  | ||||
|         childBox.x1 = Math.floor((availWidth - iconNatWidth) / 2); | ||||
|         childBox.y1 = Math.floor((iconSize - iconNatHeight) / 2); | ||||
|         childBox.x2 = childBox.x1 + iconNatWidth; | ||||
|         childBox.y2 = childBox.y1 + iconNatHeight; | ||||
|         childBox.x1 = iconPadding; | ||||
|         childBox.y1 = 0; | ||||
|         childBox.x2 = availWidth - iconPadding; | ||||
|         childBox.y2 = iconSize; | ||||
|         this._iconBin.allocate(childBox, flags); | ||||
|  | ||||
|         childBox.x1 = 0; | ||||
|         childBox.x2 = availWidth; | ||||
|         childBox.y1 = iconSize + this._spacing; | ||||
|         childBox.y2 = childBox.y1 + labelHeight; | ||||
|         this._name.allocate(childBox, flags); | ||||
|     }, | ||||
|  | ||||
|     _getPreferredWidth: function(actor, forHeight, alloc) { | ||||
| @@ -95,14 +84,9 @@ BaseIcon.prototype = { | ||||
|  | ||||
|     _getPreferredHeight: function(actor, forWidth, alloc) { | ||||
|         let [iconMinHeight, iconNatHeight] = this._iconBin.get_preferred_height(forWidth); | ||||
|         alloc.min_size = iconMinHeight; | ||||
|         alloc.natural_size = iconNatHeight; | ||||
|  | ||||
|         if (this.label) { | ||||
|             let [labelMinHeight, labelNatHeight] = this.label.get_preferred_height(forWidth); | ||||
|             alloc.min_size += this._spacing + labelMinHeight; | ||||
|             alloc.natural_size += this._spacing + labelNatHeight; | ||||
|         } | ||||
|         let [labelMinHeight, labelNatHeight] = this._name.get_preferred_height(forWidth); | ||||
|         alloc.min_size = iconMinHeight + this._spacing + labelMinHeight; | ||||
|         alloc.natural_size = iconNatHeight + this._spacing + labelNatHeight; | ||||
|     }, | ||||
|  | ||||
|     // This can be overridden by a subclass, or by the createIcon | ||||
| @@ -115,23 +99,16 @@ BaseIcon.prototype = { | ||||
|         if (!this._setSizeManually) | ||||
|             throw new Error('setSizeManually has to be set to use setIconsize'); | ||||
|  | ||||
|         this._setIconSize(size); | ||||
|     }, | ||||
|  | ||||
|     _setIconSize: function(size) { | ||||
|         if (size == this.iconSize) | ||||
|             return; | ||||
|  | ||||
|         this._createIconTexture(size); | ||||
|     }, | ||||
|  | ||||
|     _createIconTexture: function(size) { | ||||
|         if (this.icon) | ||||
|             this.icon.destroy(); | ||||
|         this.icon.destroy(); | ||||
|         this.iconSize = size; | ||||
|         this.icon = this.createIcon(this.iconSize); | ||||
|  | ||||
|         // The icon returned by createIcon() might actually be smaller than | ||||
|         // the requested icon size (for instance StTextureCache does this | ||||
|         // for fallback icons), so set the size explicitly. | ||||
|         this.icon.set_size(this.iconSize, this.iconSize); | ||||
|  | ||||
|         this._iconBin.child = this.icon; | ||||
|     }, | ||||
|  | ||||
| @@ -139,15 +116,12 @@ BaseIcon.prototype = { | ||||
|         let node = this.actor.get_theme_node(); | ||||
|         this._spacing = node.get_length('spacing'); | ||||
|  | ||||
|         let size; | ||||
|         if (this._setSizeManually) { | ||||
|             size = this.iconSize; | ||||
|         } else { | ||||
|             let [found, len] = node.lookup_length('icon-size', false); | ||||
|             size = found ? len : ICON_SIZE; | ||||
|         } | ||||
|         if (this._setSizeManually) | ||||
|             return; | ||||
|  | ||||
|         this._createIconTexture(size); | ||||
|         let len = node.get_length('icon-size'); | ||||
|         if (len > 0) | ||||
|             this._setIconSize(len); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| @@ -191,16 +165,8 @@ IconGrid.prototype = { | ||||
|         alloc.natural_size = nColumns * this._item_size + totalSpacing; | ||||
|     }, | ||||
|  | ||||
|     _getVisibleChildren: function() { | ||||
|         let children = this._grid.get_children(); | ||||
|         children = children.filter(function(actor) { | ||||
|             return actor.visible; | ||||
|         }); | ||||
|         return children; | ||||
|     }, | ||||
|  | ||||
|     _getPreferredHeight: function (grid, forWidth, alloc) { | ||||
|         let children = this._getVisibleChildren(); | ||||
|         let children = this._grid.get_children(); | ||||
|         let [nColumns, usedWidth] = this._computeLayout(forWidth); | ||||
|         let nRows; | ||||
|         if (nColumns > 0) | ||||
| @@ -216,7 +182,7 @@ IconGrid.prototype = { | ||||
|     }, | ||||
|  | ||||
|     _allocate: function (grid, box, flags) { | ||||
|         let children = this._getVisibleChildren(); | ||||
|         let children = this._grid.get_children(); | ||||
|         let availWidth = box.x2 - box.x1; | ||||
|         let availHeight = box.y2 - box.y1; | ||||
|  | ||||
| @@ -281,11 +247,8 @@ IconGrid.prototype = { | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     childrenInRow: function(rowWidth) { | ||||
|         return this._computeLayout(rowWidth)[0]; | ||||
|     }, | ||||
|  | ||||
|     _computeLayout: function (forWidth) { | ||||
|         let children = this._grid.get_children(); | ||||
|         let nColumns = 0; | ||||
|         let usedWidth = 0; | ||||
|         while ((this._colLimit == null || nColumns < this._colLimit) && | ||||
|   | ||||
| @@ -1,536 +0,0 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Caribou = imports.gi.Caribou; | ||||
| const Clutter = imports.gi.Clutter; | ||||
| const DBus = imports.dbus; | ||||
| const Gdk = imports.gi.Gdk; | ||||
| const Gio = imports.gi.Gio; | ||||
| const GLib = imports.gi.GLib; | ||||
| const Lang = imports.lang; | ||||
| const Shell = imports.gi.Shell; | ||||
| const St = imports.gi.St; | ||||
|  | ||||
| const BoxPointer = imports.ui.boxpointer; | ||||
| const Main = imports.ui.main; | ||||
| const MessageTray = imports.ui.messageTray; | ||||
|  | ||||
| const KEYBOARD_SCHEMA = 'org.gnome.shell.keyboard'; | ||||
| const SHOW_KEYBOARD = 'show-keyboard'; | ||||
| const KEYBOARD_TYPE = 'keyboard-type'; | ||||
|  | ||||
| // Key constants taken from Antler | ||||
| // FIXME: ought to be moved into libcaribou | ||||
| const PRETTY_KEYS = { | ||||
|     'BackSpace': '\u232b', | ||||
|     'space': ' ', | ||||
|     'Return': '\u23ce', | ||||
|     'Caribou_Prefs': '\u2328', | ||||
|     'Caribou_ShiftUp': '\u2b06', | ||||
|     'Caribou_ShiftDown': '\u2b07', | ||||
|     'Caribou_Emoticons': '\u263a', | ||||
|     'Caribou_Symbols': '123', | ||||
|     'Caribou_Symbols_More': '{#*', | ||||
|     'Caribou_Alpha': 'Abc', | ||||
|     'Tab': 'Tab', | ||||
|     'Escape': 'Esc', | ||||
|     'Control_L': 'Ctrl', | ||||
|     'Alt_L': 'Alt' | ||||
| }; | ||||
|  | ||||
| const CaribouKeyboardIface = { | ||||
|     name: 'org.gnome.Caribou.Keyboard', | ||||
|     methods:    [ { name: 'Show', | ||||
|                     inSignature: 'u', | ||||
|                     outSignature: '' | ||||
|                   }, | ||||
|                   { name: 'Hide', | ||||
|                     inSignature: 'u', | ||||
|                     outSignature: '' | ||||
|                   }, | ||||
|                   { name: 'SetCursorLocation', | ||||
|                     inSignature: 'iiii', | ||||
|                     outSignature: '' | ||||
|                   }, | ||||
|                   { name: 'SetEntryLocation', | ||||
|                     inSignature: 'iiii', | ||||
|                     outSignature: '' | ||||
|                   } ], | ||||
|     properties: [ { name: 'Name', | ||||
|                     signature: 's', | ||||
|                     access: 'read' } ] | ||||
| }; | ||||
|  | ||||
| function Key() { | ||||
|     this._init.apply(this, arguments); | ||||
| } | ||||
|  | ||||
| Key.prototype = { | ||||
|     _init : function(key) { | ||||
|         this._key = key; | ||||
|  | ||||
|         this.actor = this._makeKey(); | ||||
|  | ||||
|         this._extended_keys = this._key.get_extended_keys(); | ||||
|         this._extended_keyboard = null; | ||||
|  | ||||
|         if (this._key.name == "Control_L" || this._key.name == "Alt_L") | ||||
|             this._key.latch = true; | ||||
|  | ||||
|         this._key.connect('key-pressed', Lang.bind(this, function () | ||||
|                                                    { this.actor.checked = true })); | ||||
|         this._key.connect('key-released', Lang.bind(this, function () | ||||
|                                                     { this.actor.checked = false; })); | ||||
|  | ||||
|         if (this._extended_keys.length > 0) { | ||||
|             this._grabbed = false; | ||||
|             this._eventCaptureId = 0; | ||||
|             this._key.connect('notify::show-subkeys', Lang.bind(this, this._onShowSubkeysChanged)); | ||||
|             this._boxPointer = new BoxPointer.BoxPointer(St.Side.BOTTOM, | ||||
|                                                          { x_fill: true, | ||||
|                                                            y_fill: true, | ||||
|                                                            x_align: St.Align.START }); | ||||
|             // Adds style to existing keyboard style to avoid repetition | ||||
|             this._boxPointer.actor.add_style_class_name('keyboard-subkeys'); | ||||
|             this._getExtendedKeys(); | ||||
|             this.actor._extended_keys = this._extended_keyboard; | ||||
|             this._boxPointer.actor.hide(); | ||||
|             Main.layoutManager.addChrome(this._boxPointer.actor, { visibleInFullscreen: true }); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _makeKey: function () { | ||||
|         let label = this._key.name; | ||||
|  | ||||
|         if (label.length > 1) { | ||||
|             let pretty = PRETTY_KEYS[label]; | ||||
|             if (pretty) | ||||
|                 label = pretty; | ||||
|             else | ||||
|                 label = this._getUnichar(this._key); | ||||
|         } | ||||
|  | ||||
|         label = GLib.markup_escape_text(label, -1); | ||||
|         let button = new St.Button ({ label: label, | ||||
|                                       style_class: 'keyboard-key' }); | ||||
|  | ||||
|         button.key_width = this._key.width; | ||||
|         button.connect('button-press-event', Lang.bind(this, function () { this._key.press(); })); | ||||
|         button.connect('button-release-event', Lang.bind(this, function () { this._key.release(); })); | ||||
|  | ||||
|         return button; | ||||
|     }, | ||||
|  | ||||
|     _getUnichar: function(key) { | ||||
|         let keyval = key.keyval; | ||||
|         let unichar = Gdk.keyval_to_unicode(keyval); | ||||
|         if (unichar) { | ||||
|             return String.fromCharCode(unichar); | ||||
|         } else { | ||||
|             return key.name; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _getExtendedKeys: function () { | ||||
|         this._extended_keyboard = new St.BoxLayout({ style_class: 'keyboard-layout', | ||||
|                                                      vertical: false }); | ||||
|         for (let i = 0; i < this._extended_keys.length; ++i) { | ||||
|             let extended_key = this._extended_keys[i]; | ||||
|             let label = this._getUnichar(extended_key); | ||||
|             let key = new St.Button({ label: label, style_class: 'keyboard-key' }); | ||||
|             key.extended_key = extended_key; | ||||
|             key.connect('button-press-event', Lang.bind(this, function () { extended_key.press(); })); | ||||
|             key.connect('button-release-event', Lang.bind(this, function () { extended_key.release(); })); | ||||
|             this._extended_keyboard.add(key); | ||||
|         } | ||||
|         this._boxPointer.bin.add_actor(this._extended_keyboard); | ||||
|     }, | ||||
|  | ||||
|     _onEventCapture: function (actor, event) { | ||||
|         let source = event.get_source(); | ||||
|         let type = event.type(); | ||||
|  | ||||
|         if ((type == Clutter.EventType.BUTTON_PRESS || | ||||
|              type == Clutter.EventType.BUTTON_RELEASE) && | ||||
|             this._extended_keyboard.contains(source)) { | ||||
|             source.extended_key.press(); | ||||
|             source.extended_key.release(); | ||||
|             return false; | ||||
|         } | ||||
|         if (type == Clutter.EventType.BUTTON_PRESS) { | ||||
|             this._boxPointer.actor.hide(); | ||||
|             this._ungrab(); | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     }, | ||||
|  | ||||
|     _ungrab: function () { | ||||
|         global.stage.disconnect(this._eventCaptureId); | ||||
|         this._eventCaptureId = 0; | ||||
|         this._grabbed = false; | ||||
|         Main.popModal(this.actor); | ||||
|     }, | ||||
|  | ||||
|     _onShowSubkeysChanged: function () { | ||||
|         if (this._key.show_subkeys) { | ||||
|             this.actor.fake_release(); | ||||
|             this._boxPointer.actor.raise_top(); | ||||
|             this._boxPointer.setPosition(this.actor, 0.5); | ||||
|             this._boxPointer.show(true); | ||||
|             this.actor.set_hover(false); | ||||
|             if (!this._grabbed) { | ||||
|                  Main.pushModal(this.actor); | ||||
|                  this._eventCaptureId = global.stage.connect('captured-event', Lang.bind(this, this._onEventCapture)); | ||||
|                  this._grabbed = true; | ||||
|             } | ||||
|             this._key.release(); | ||||
|         } else { | ||||
|             if (this._grabbed) | ||||
|                 this._ungrab(); | ||||
|             this._boxPointer.hide(true); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | ||||
| function Keyboard() { | ||||
|     this._init.apply(this, arguments); | ||||
| } | ||||
|  | ||||
| Keyboard.prototype = { | ||||
|     _init: function () { | ||||
|         DBus.session.exportObject('/org/gnome/Caribou/Keyboard', this); | ||||
|  | ||||
|         this.actor = null; | ||||
|  | ||||
|         this._timestamp = global.get_current_time(); | ||||
|         Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._redraw)); | ||||
|  | ||||
|         this._keyboardSettings = new Gio.Settings({ schema: KEYBOARD_SCHEMA }); | ||||
|         this._keyboardSettings.connect('changed', Lang.bind(this, this._settingsChanged)); | ||||
|         this._settingsChanged(); | ||||
|     }, | ||||
|  | ||||
|     init: function () { | ||||
|         this._redraw(); | ||||
|     }, | ||||
|  | ||||
|     _settingsChanged: function () { | ||||
|         this._enableKeyboard = this._keyboardSettings.get_boolean(SHOW_KEYBOARD); | ||||
|         if (!this._enableKeyboard && !this._keyboard) | ||||
|             return; | ||||
|         if (this._enableKeyboard && this._keyboard && | ||||
|             this._keyboard.keyboard_type == this._keyboardSettings.get_string(KEYBOARD_TYPE)) | ||||
|             return; | ||||
|  | ||||
|         if (this._keyboard) | ||||
|             this._destroyKeyboard(); | ||||
|         if (this._enableKeyboard) | ||||
|             this._setupKeyboard(); | ||||
|         else | ||||
|             Main.layoutManager.hideKeyboard(true); | ||||
|     }, | ||||
|  | ||||
|     _destroyKeyboard: function() { | ||||
|         if (this._keyboardNotifyId) | ||||
|             this._keyboard.disconnect(this._keyboardNotifyId); | ||||
|         if (this._focusNotifyId) | ||||
|             global.stage.disconnect(this._focusNotifyId); | ||||
|         this._keyboard = null; | ||||
|         this.actor.destroy(); | ||||
|         this.actor = null; | ||||
|  | ||||
|         this._destroySource(); | ||||
|     }, | ||||
|  | ||||
|     _setupKeyboard: function() { | ||||
|         this.actor = new St.BoxLayout({ name: 'keyboard', vertical: true, reactive: true }); | ||||
|         Main.layoutManager.keyboardBox.add_actor(this.actor); | ||||
|         Main.layoutManager.trackChrome(this.actor); | ||||
|  | ||||
|         this._keyboard = new Caribou.KeyboardModel({ keyboard_type: this._keyboardSettings.get_string(KEYBOARD_TYPE) }); | ||||
|         this._groups = {}; | ||||
|         this._current_page = null; | ||||
|  | ||||
|         // Initialize keyboard key measurements | ||||
|         this._numOfHorizKeys = 0; | ||||
|         this._numOfVertKeys = 0; | ||||
|  | ||||
|         this._addKeys(); | ||||
|  | ||||
|         this._keyboardNotifyId = this._keyboard.connect('notify::active-group', Lang.bind(this, this._onGroupChanged)); | ||||
|         this._focusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged)); | ||||
|         this._createSource(); | ||||
|     }, | ||||
|  | ||||
|     _onKeyFocusChanged: function () { | ||||
|         let focus = global.stage.key_focus; | ||||
|  | ||||
|         // Showing an extended key popup will grab focus, but ignore that | ||||
|         if (focus && focus._extended_keys) | ||||
|             return; | ||||
|  | ||||
|         if (focus instanceof Clutter.Text) | ||||
|             this.show(); | ||||
|         else | ||||
|             this.hide(); | ||||
|     }, | ||||
|  | ||||
|     _addKeys: function () { | ||||
|         let groups = this._keyboard.get_groups(); | ||||
|         for (let i = 0; i < groups.length; ++i) { | ||||
|              let gname = groups[i]; | ||||
|              let group = this._keyboard.get_group(gname); | ||||
|              group.connect('notify::active-level', Lang.bind(this, this._onLevelChanged)); | ||||
|              let layers = {}; | ||||
|              let levels = group.get_levels(); | ||||
|              for (let j = 0; j < levels.length; ++j) { | ||||
|                  let lname = levels[j]; | ||||
|                  let level = group.get_level(lname); | ||||
|                  let layout = new St.BoxLayout({ style_class: 'keyboard-layout', | ||||
|                                                  vertical: true }); | ||||
|                  this._loadRows(level, layout); | ||||
|                  layers[lname] = layout; | ||||
|                  this.actor.add(layout, { x_fill: false }); | ||||
|  | ||||
|                  layout.hide(); | ||||
|              } | ||||
|              this._groups[gname] = layers; | ||||
|         } | ||||
|  | ||||
|         this._setActiveLayer(); | ||||
|     }, | ||||
|  | ||||
|     _getTrayIcon: function () { | ||||
|         let trayButton = new St.Button ({ label: "tray", style_class: 'keyboard-key' }); | ||||
|         trayButton.key_width = 1; | ||||
|         trayButton.connect('button-press-event', Lang.bind(this, function () { | ||||
|             Main.messageTray.toggle(); | ||||
|         })); | ||||
|  | ||||
|         Main.overview.connect('showing', Lang.bind(this, function () { | ||||
|             trayButton.reactive = false; | ||||
|             trayButton.add_style_pseudo_class('grayed'); | ||||
|         })); | ||||
|         Main.overview.connect('hiding', Lang.bind(this, function () { | ||||
|             trayButton.reactive = true; | ||||
|             trayButton.remove_style_pseudo_class('grayed'); | ||||
|         })); | ||||
|  | ||||
|         return trayButton; | ||||
|     }, | ||||
|  | ||||
|     _addRows : function (keys, layout) { | ||||
|         let keyboard_row = new St.BoxLayout(); | ||||
|         for (let i = 0; i < keys.length; ++i) { | ||||
|             let children = keys[i].get_children(); | ||||
|             let right_box = new St.BoxLayout({ style_class: 'keyboard-row' }); | ||||
|             let left_box = new St.BoxLayout({ style_class: 'keyboard-row' }); | ||||
|             for (let j = 0; j < children.length; ++j) { | ||||
|                 if (this._numOfHorizKeys == 0) | ||||
|                     this._numOfHorizKeys = children.length; | ||||
|                 let key = children[j]; | ||||
|                 let button = new Key(key); | ||||
|  | ||||
|                 if (key.align == 'right') | ||||
|                     right_box.add(button.actor); | ||||
|                 else | ||||
|                     left_box.add(button.actor); | ||||
|                 if (key.name == "Caribou_Prefs") { | ||||
|                     key.connect('key-released', Lang.bind(this, this.hide)); | ||||
|  | ||||
|                     // Add new key for hiding message tray | ||||
|                     right_box.add(this._getTrayIcon()); | ||||
|                 } | ||||
|             } | ||||
|             keyboard_row.add(left_box, { expand: true, x_fill: false, x_align: St.Align.START }); | ||||
|             keyboard_row.add(right_box, { expand: true, x_fill: false, x_align: St.Align.END }); | ||||
|         } | ||||
|         layout.add(keyboard_row); | ||||
|     }, | ||||
|  | ||||
|     _loadRows : function (level, layout) { | ||||
|         let rows = level.get_rows(); | ||||
|         for (let i = 0; i < rows.length; ++i) { | ||||
|             let row = rows[i]; | ||||
|             if (this._numOfVertKeys == 0) | ||||
|                 this._numOfVertKeys = rows.length; | ||||
|             this._addRows(row.get_columns(), layout); | ||||
|         } | ||||
|  | ||||
|     }, | ||||
|  | ||||
|     _redraw: function () { | ||||
|         if (!this._enableKeyboard) | ||||
|             return; | ||||
|  | ||||
|         let monitor = Main.layoutManager.bottomMonitor; | ||||
|         let maxHeight = monitor.height / 3; | ||||
|         this.actor.width = monitor.width; | ||||
|  | ||||
|         let layout = this._current_page; | ||||
|         let verticalSpacing = layout.get_theme_node().get_length('spacing'); | ||||
|         let padding = layout.get_theme_node().get_length('padding'); | ||||
|  | ||||
|         let box = layout.get_children()[0].get_children()[0]; | ||||
|         let horizontalSpacing = box.get_theme_node().get_length('spacing'); | ||||
|         let allHorizontalSpacing = (this._numOfHorizKeys - 1) * horizontalSpacing; | ||||
|         let keyWidth = Math.floor((this.actor.width - allHorizontalSpacing - 2 * padding) / this._numOfHorizKeys); | ||||
|  | ||||
|         let allVerticalSpacing = (this._numOfVertKeys - 1) * verticalSpacing; | ||||
|         let keyHeight = Math.floor((maxHeight - allVerticalSpacing - 2 * padding) / this._numOfVertKeys); | ||||
|  | ||||
|         let keySize = Math.min(keyWidth, keyHeight); | ||||
|         this.actor.height = keySize * this._numOfVertKeys + allVerticalSpacing + 2 * padding; | ||||
|  | ||||
|         let rows = this._current_page.get_children(); | ||||
|         for (let i = 0; i < rows.length; ++i) { | ||||
|             let keyboard_row = rows[i]; | ||||
|             let boxes = keyboard_row.get_children(); | ||||
|             for (let j = 0; j < boxes.length; ++j) { | ||||
|                 let keys = boxes[j].get_children(); | ||||
|                 for (let k = 0; k < keys.length; ++k) { | ||||
|                     let child = keys[k]; | ||||
|                     child.width = keySize * child.key_width; | ||||
|                     child.height = keySize; | ||||
|                     if (child._extended_keys) { | ||||
|                         let extended_keys = child._extended_keys.get_children(); | ||||
|                         for (let n = 0; n < extended_keys.length; ++n) { | ||||
|                             let extended_key = extended_keys[n]; | ||||
|                             extended_key.width = keySize; | ||||
|                             extended_key.height = keySize; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _onLevelChanged: function () { | ||||
|         this._setActiveLayer(); | ||||
|         this._redraw(); | ||||
|     }, | ||||
|  | ||||
|     _onGroupChanged: function () { | ||||
|         this._setActiveLayer(); | ||||
|         this._redraw(); | ||||
|     }, | ||||
|  | ||||
|     _setActiveLayer: function () { | ||||
|         let active_group_name = this._keyboard.active_group; | ||||
|         let active_group = this._keyboard.get_group(active_group_name); | ||||
|         let active_level = active_group.active_level; | ||||
|         let layers = this._groups[active_group_name]; | ||||
|  | ||||
|         if (this._current_page != null) { | ||||
|             this._current_page.hide(); | ||||
|         } | ||||
|  | ||||
|         this._current_page = layers[active_level]; | ||||
|         this._current_page.show(); | ||||
|     }, | ||||
|  | ||||
|     _createSource: function () { | ||||
|         if (this._source == null) { | ||||
|             this._source = new KeyboardSource(this); | ||||
|             this._source.setTransient(true); | ||||
|             Main.messageTray.add(this._source); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _destroySource: function () { | ||||
|         if (this._source) { | ||||
|             this._source.destroy(); | ||||
|             this._source = null; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     show: function () { | ||||
|         this._redraw(); | ||||
|  | ||||
|         Main.layoutManager.showKeyboard(); | ||||
|         this._destroySource(); | ||||
|     }, | ||||
|  | ||||
|     hide: function () { | ||||
|         Main.layoutManager.hideKeyboard(); | ||||
|         this._createSource(); | ||||
|     }, | ||||
|  | ||||
|     _moveTemporarily: function () { | ||||
|         let currentWindow = global.screen.get_display().focus_window; | ||||
|         let rect = currentWindow.get_outer_rect(); | ||||
|  | ||||
|         let newX = rect.x; | ||||
|         let newY = 3 * this.actor.height / 2; | ||||
|         currentWindow.move_frame(true, newX, newY); | ||||
|     }, | ||||
|  | ||||
|     _setLocation: function (x, y) { | ||||
|         if (y >= 2 * this.actor.height) | ||||
|             this._moveTemporarily(); | ||||
|     }, | ||||
|  | ||||
|     // D-Bus methods | ||||
|     Show: function(timestamp) { | ||||
|         if (timestamp - this._timestamp < 0) | ||||
|             return; | ||||
|  | ||||
|         this._timestamp = timestamp; | ||||
|         this.show(); | ||||
|     }, | ||||
|  | ||||
|     Hide: function(timestamp) { | ||||
|         if (timestamp - this._timestamp < 0) | ||||
|             return; | ||||
|  | ||||
|         this._timestamp = timestamp; | ||||
|         this.hide(); | ||||
|     }, | ||||
|  | ||||
|     SetCursorLocation: function(x, y, w, h) { | ||||
|         this._setLocation(x, y); | ||||
|     }, | ||||
|  | ||||
|     SetEntryLocation: function(x, y, w, h) { | ||||
|         this._setLocation(x, y); | ||||
|     }, | ||||
|  | ||||
|     get Name() { | ||||
|         return 'gnome-shell'; | ||||
|     } | ||||
| }; | ||||
| DBus.conformExport(Keyboard.prototype, CaribouKeyboardIface); | ||||
|  | ||||
| function KeyboardSource() { | ||||
|     this._init.apply(this, arguments); | ||||
| } | ||||
|  | ||||
| KeyboardSource.prototype = { | ||||
|     __proto__: MessageTray.Source.prototype, | ||||
|  | ||||
|     _init: function(keyboard) { | ||||
|         this._keyboard = keyboard; | ||||
|         MessageTray.Source.prototype._init.call(this, _("Keyboard")); | ||||
|  | ||||
|         this._setSummaryIcon(this.createNotificationIcon()); | ||||
|     }, | ||||
|  | ||||
|     createNotificationIcon: function() { | ||||
|         return new St.Icon({ icon_name: 'input-keyboard', | ||||
|                              icon_type: St.IconType.SYMBOLIC, | ||||
|                              icon_size: this.ICON_SIZE }); | ||||
|     }, | ||||
|  | ||||
|      handleSummaryClick: function() { | ||||
|         let event = Clutter.get_current_event(); | ||||
|         if (event.type() != Clutter.EventType.BUTTON_RELEASE) | ||||
|             return false; | ||||
|  | ||||
|         this.open(); | ||||
|         return true; | ||||
|     }, | ||||
|  | ||||
|     open: function() { | ||||
|         this._keyboard.show(); | ||||
|     } | ||||
| }; | ||||
							
								
								
									
										965
									
								
								js/ui/layout.js
									
									
									
									
									
								
							
							
						
						| @@ -1,965 +0,0 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Clutter = imports.gi.Clutter; | ||||
| const Lang = imports.lang; | ||||
| const Mainloop = imports.mainloop; | ||||
| const Meta = imports.gi.Meta; | ||||
| const Shell = imports.gi.Shell; | ||||
| const Signals = imports.signals; | ||||
| const St = imports.gi.St; | ||||
|  | ||||
| const Main = imports.ui.main; | ||||
| const Params = imports.misc.params; | ||||
| const ScreenSaver = imports.misc.screenSaver; | ||||
| const Tweener = imports.ui.tweener; | ||||
|  | ||||
| const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5; | ||||
| const STARTUP_ANIMATION_TIME = 0.2; | ||||
| const KEYBOARD_ANIMATION_TIME = 0.5; | ||||
|  | ||||
| function LayoutManager() { | ||||
|     this._init.apply(this, arguments); | ||||
| } | ||||
|  | ||||
| LayoutManager.prototype = { | ||||
|     _init: function () { | ||||
|         this._rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL); | ||||
|         this.monitors = []; | ||||
|         this.primaryMonitor = null; | ||||
|         this.primaryIndex = -1; | ||||
|         this._hotCorners = []; | ||||
|         this._leftPanelBarrier = 0; | ||||
|         this._rightPanelBarrier = 0; | ||||
|         this._trayBarrier = 0; | ||||
|  | ||||
|         this._chrome = new Chrome(this); | ||||
|  | ||||
|         this.panelBox = new St.BoxLayout({ name: 'panelBox', | ||||
|                                            vertical: true }); | ||||
|         this.addChrome(this.panelBox, { affectsStruts: true }); | ||||
|         this.panelBox.connect('allocation-changed', | ||||
|                               Lang.bind(this, this._updatePanelBarriers)); | ||||
|  | ||||
|         this.trayBox = new St.BoxLayout({ name: 'trayBox' });  | ||||
|         this.addChrome(this.trayBox, { visibleInFullscreen: true }); | ||||
|         this.trayBox.connect('allocation-changed', | ||||
|                              Lang.bind(this, this._updateTrayBarrier)); | ||||
|  | ||||
|         this.keyboardBox = new St.BoxLayout({ name: 'keyboardBox' }); | ||||
|         this.addChrome(this.keyboardBox, { visibleInFullscreen: true }); | ||||
|         this._keyboardHeightNotifyId = 0; | ||||
|  | ||||
|         global.screen.connect('monitors-changed', | ||||
|                               Lang.bind(this, this._monitorsChanged)); | ||||
|         this._monitorsChanged(); | ||||
|     }, | ||||
|  | ||||
|     // This is called by Main after everything else is constructed; | ||||
|     // Chrome.init() needs access to Main.overview, which didn't exist | ||||
|     // yet when the LayoutManager was constructed. | ||||
|     init: function() { | ||||
|         this._chrome.init(); | ||||
|  | ||||
|         this._startupAnimation(); | ||||
|     }, | ||||
|  | ||||
|     _updateMonitors: function() { | ||||
|         let screen = global.screen; | ||||
|  | ||||
|         this.monitors = []; | ||||
|         let nMonitors = screen.get_n_monitors(); | ||||
|         for (let i = 0; i < nMonitors; i++) | ||||
|             this.monitors.push(screen.get_monitor_geometry(i)); | ||||
|  | ||||
|         if (nMonitors == 1) { | ||||
|             this.primaryIndex = this.bottomIndex = 0; | ||||
|         } else { | ||||
|             // If there are monitors below the primary, then we need | ||||
|             // to split primary from bottom. | ||||
|             this.primaryIndex = this.bottomIndex = screen.get_primary_monitor(); | ||||
|             for (let i = 0; i < this.monitors.length; i++) { | ||||
|                 let monitor = this.monitors[i]; | ||||
|                 if (this._isAboveOrBelowPrimary(monitor)) { | ||||
|                     if (monitor.y > this.monitors[this.bottomIndex].y) | ||||
|                         this.bottomIndex = i; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         this.primaryMonitor = this.monitors[this.primaryIndex]; | ||||
|         this.bottomMonitor = this.monitors[this.bottomIndex]; | ||||
|     }, | ||||
|  | ||||
|     _updateHotCorners: function() { | ||||
|         // destroy old hot corners | ||||
|         for (let i = 0; i < this._hotCorners.length; i++) | ||||
|             this._hotCorners[i].destroy(); | ||||
|         this._hotCorners = []; | ||||
|  | ||||
|         // build new hot corners | ||||
|         for (let i = 0; i < this.monitors.length; i++) { | ||||
|             if (i == this.primaryIndex) | ||||
|                 continue; | ||||
|  | ||||
|             let monitor = this.monitors[i]; | ||||
|             let cornerX = this._rtl ? monitor.x + monitor.width : monitor.x; | ||||
|             let cornerY = monitor.y; | ||||
|  | ||||
|             let haveTopLeftCorner = true; | ||||
|  | ||||
|             // Check if we have a top left (right for RTL) corner. | ||||
|             // I.e. if there is no monitor directly above or to the left(right) | ||||
|             let besideX = this._rtl ? monitor.x + 1 : cornerX - 1; | ||||
|             let besideY = cornerY; | ||||
|             let aboveX = cornerX; | ||||
|             let aboveY = cornerY - 1; | ||||
|  | ||||
|             for (let j = 0; j < this.monitors.length; j++) { | ||||
|                 if (i == j) | ||||
|                     continue; | ||||
|                 let otherMonitor = this.monitors[j]; | ||||
|                 if (besideX >= otherMonitor.x && | ||||
|                     besideX < otherMonitor.x + otherMonitor.width && | ||||
|                     besideY >= otherMonitor.y && | ||||
|                     besideY < otherMonitor.y + otherMonitor.height) { | ||||
|                     haveTopLeftCorner = false; | ||||
|                     break; | ||||
|                 } | ||||
|                 if (aboveX >= otherMonitor.x && | ||||
|                     aboveX < otherMonitor.x + otherMonitor.width && | ||||
|                     aboveY >= otherMonitor.y && | ||||
|                     aboveY < otherMonitor.y + otherMonitor.height) { | ||||
|                     haveTopLeftCorner = false; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (!haveTopLeftCorner) | ||||
|                 continue; | ||||
|  | ||||
|             let corner = new HotCorner(); | ||||
|             this._hotCorners.push(corner); | ||||
|             corner.actor.set_position(cornerX, cornerY); | ||||
|             this._chrome.addActor(corner.actor); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _updateBoxes: function() { | ||||
|         this.panelBox.set_position(this.primaryMonitor.x, this.primaryMonitor.y); | ||||
|         this.panelBox.set_size(this.primaryMonitor.width, -1); | ||||
|  | ||||
|         this.keyboardBox.set_position(this.bottomMonitor.x, | ||||
|                                       this.bottomMonitor.y + this.bottomMonitor.height); | ||||
|         this.keyboardBox.set_size(this.bottomMonitor.width, -1); | ||||
|  | ||||
|         this.trayBox.set_position(this.bottomMonitor.x, | ||||
|                                   this.bottomMonitor.y + this.bottomMonitor.height); | ||||
|         this.trayBox.set_size(this.bottomMonitor.width, -1); | ||||
|  | ||||
|         // Set trayBox's clip to show things above it, but not below | ||||
|         // it (so it's not visible behind the keyboard). The exact | ||||
|         // height of the clip doesn't matter, as long as it's taller | ||||
|         // than any Notification.actor. | ||||
|         this.trayBox.set_clip(0, -this.bottomMonitor.height, | ||||
|                               this.bottomMonitor.width, this.bottomMonitor.height); | ||||
|     }, | ||||
|  | ||||
|     _updatePanelBarriers: function() { | ||||
|         if (this._leftPanelBarrier) | ||||
|             global.destroy_pointer_barrier(this._leftPanelBarrier); | ||||
|         if (this._rightPanelBarrier) | ||||
|             global.destroy_pointer_barrier(this._rightPanelBarrier); | ||||
|  | ||||
|         if (this.panelBox.height) { | ||||
|             let primary = this.primaryMonitor; | ||||
|             this._leftPanelBarrier = | ||||
|                 global.create_pointer_barrier(primary.x, primary.y, | ||||
|                                               primary.x, primary.y + this.panelBox.height, | ||||
|                                               1 /* BarrierPositiveX */); | ||||
|             this._rightPanelBarrier = | ||||
|                 global.create_pointer_barrier(primary.x + primary.width, primary.y, | ||||
|                                               primary.x + primary.width, primary.y + this.panelBox.height, | ||||
|                                               4 /* BarrierNegativeX */); | ||||
|         } else { | ||||
|             this._leftPanelBarrier = 0; | ||||
|             this._rightPanelBarrier = 0; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _updateTrayBarrier: function() { | ||||
|         let monitor = this.bottomMonitor; | ||||
|  | ||||
|         if (this._trayBarrier) | ||||
|             global.destroy_pointer_barrier(this._trayBarrier); | ||||
|  | ||||
|         if (Main.messageTray) { | ||||
|             this._trayBarrier = | ||||
|                 global.create_pointer_barrier(monitor.x + monitor.width, monitor.y + monitor.height - Main.messageTray.actor.height, | ||||
|                                               monitor.x + monitor.width, monitor.y + monitor.height, | ||||
|                                               4 /* BarrierNegativeX */); | ||||
|         } else { | ||||
|             this._trayBarrier = 0; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _monitorsChanged: function() { | ||||
|         this._updateMonitors(); | ||||
|         this._updateBoxes(); | ||||
|         this._updateHotCorners(); | ||||
|  | ||||
|         this.emit('monitors-changed'); | ||||
|     }, | ||||
|  | ||||
|     _isAboveOrBelowPrimary: function(monitor) { | ||||
|         let primary = this.monitors[this.primaryIndex]; | ||||
|         let monitorLeft = monitor.x, monitorRight = monitor.x + monitor.width; | ||||
|         let primaryLeft = primary.x, primaryRight = primary.x + primary.width; | ||||
|  | ||||
|         if ((monitorLeft >= primaryLeft && monitorLeft <= primaryRight) || | ||||
|             (monitorRight >= primaryLeft && monitorRight <= primaryRight) || | ||||
|             (primaryLeft >= monitorLeft && primaryLeft <= monitorRight) || | ||||
|             (primaryRight >= monitorLeft && primaryRight <= monitorRight)) | ||||
|             return true; | ||||
|  | ||||
|         return false; | ||||
|     }, | ||||
|  | ||||
|     get focusIndex() { | ||||
|         let focusWindow = global.display.focus_window; | ||||
|  | ||||
|         if (focusWindow) { | ||||
|             let wrect = focusWindow.get_outer_rect(); | ||||
|             for (let i = 0; i < this.monitors.length; i++) { | ||||
|                 let monitor = this.monitors[i]; | ||||
|  | ||||
|                 if (monitor.x <= wrect.x && monitor.y <= wrect.y && | ||||
|                     monitor.x + monitor.width > wrect.x && | ||||
|                     monitor.y + monitor.height > wrect.y) | ||||
|                     return i; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return this.primaryIndex; | ||||
|     }, | ||||
|  | ||||
|     get focusMonitor() { | ||||
|         return this.monitors[this.focusIndex]; | ||||
|     }, | ||||
|  | ||||
|     _startupAnimation: function() { | ||||
|         // Don't animate the strut | ||||
|         this._chrome.freezeUpdateRegions(); | ||||
|  | ||||
|         this.panelBox.anchor_y = this.panelBox.height; | ||||
|         Tweener.addTween(this.panelBox, | ||||
|                          { anchor_y: 0, | ||||
|                            time: STARTUP_ANIMATION_TIME, | ||||
|                            transition: 'easeOutQuad', | ||||
|                            onComplete: this._startupAnimationComplete, | ||||
|                            onCompleteScope: this | ||||
|                          }); | ||||
|     }, | ||||
|  | ||||
|     _startupAnimationComplete: function() { | ||||
|         this._chrome.thawUpdateRegions(); | ||||
|     }, | ||||
|  | ||||
|     showKeyboard: function () { | ||||
|         Main.messageTray.hide(); | ||||
|         this.keyboardBox.raise_top(); | ||||
|         Tweener.addTween(this.keyboardBox, | ||||
|                          { anchor_y: this.keyboardBox.height, | ||||
|                            time: KEYBOARD_ANIMATION_TIME, | ||||
|                            transition: 'easeOutQuad', | ||||
|                            onComplete: this._showKeyboardComplete, | ||||
|                            onCompleteScope: this | ||||
|                          }); | ||||
|         Tweener.addTween(this.trayBox, | ||||
|                          { anchor_y: this.keyboardBox.height, | ||||
|                            time: KEYBOARD_ANIMATION_TIME, | ||||
|                            transition: 'easeOutQuad' | ||||
|                          }); | ||||
|     }, | ||||
|  | ||||
|     _showKeyboardComplete: function() { | ||||
|         // Poke Chrome to update the input shape; it doesn't notice | ||||
|         // anchor point changes | ||||
|         this._chrome.updateRegions(); | ||||
|  | ||||
|         this._keyboardHeightNotifyId = this.keyboardBox.connect('notify::height', Lang.bind(this, function () { | ||||
|             this.keyboardBox.anchor_y = this.keyboardBox.height; | ||||
|             this.trayBox.anchor_y = this.keyboardBox.height; | ||||
|         })); | ||||
|     }, | ||||
|  | ||||
|     hideKeyboard: function (immediate) { | ||||
|         Main.messageTray.hide(); | ||||
|         if (this._keyboardHeightNotifyId) { | ||||
|             this.keyboardBox.disconnect(this._keyboardHeightNotifyId); | ||||
|             this._keyboardHeightNotifyId = 0; | ||||
|         } | ||||
|         Tweener.addTween(this.keyboardBox, | ||||
|                          { anchor_y: 0, | ||||
|                            time: immediate ? 0 : KEYBOARD_ANIMATION_TIME, | ||||
|                            transition: 'easeOutQuad', | ||||
|                            onComplete: this._hideKeyboardComplete, | ||||
|                            onCompleteScope: this | ||||
|                          }); | ||||
|         Tweener.addTween(this.trayBox, | ||||
|                          { anchor_y: 0, | ||||
|                            time: immediate ? 0 : KEYBOARD_ANIMATION_TIME, | ||||
|                            transition: 'easeOutQuad' | ||||
|                          }); | ||||
|     }, | ||||
|  | ||||
|     _hideKeyboardComplete: function() { | ||||
|         this._chrome.updateRegions(); | ||||
|     }, | ||||
|  | ||||
|     // addChrome: | ||||
|     // @actor: an actor to add to the chrome | ||||
|     // @params: (optional) additional params | ||||
|     // | ||||
|     // Adds @actor to the chrome, and (unless %affectsInputRegion in | ||||
|     // @params is %false) extends the input region to include it. | ||||
|     // Changes in @actor's size, position, and visibility will | ||||
|     // automatically result in appropriate changes to the input | ||||
|     // region. | ||||
|     // | ||||
|     // If %affectsStruts in @params is %true (and @actor is along a | ||||
|     // screen edge), then @actor's size and position will also affect | ||||
|     // the window manager struts. Changes to @actor's visibility will | ||||
|     // NOT affect whether or not the strut is present, however. | ||||
|     // | ||||
|     // If %visibleInFullscreen in @params is %true, the actor will be | ||||
|     // visible even when a fullscreen window should be covering it. | ||||
|     addChrome: function(actor, params) { | ||||
|         this._chrome.addActor(actor, params); | ||||
|     }, | ||||
|  | ||||
|     // trackChrome: | ||||
|     // @actor: a descendant of the chrome to begin tracking | ||||
|     // @params: parameters describing how to track @actor | ||||
|     // | ||||
|     // Tells the chrome to track @actor, which must be a descendant | ||||
|     // of an actor added via addChrome(). This can be used to extend the | ||||
|     // struts or input region to cover specific children. | ||||
|     // | ||||
|     // @params can have any of the same values as in addChrome(), | ||||
|     // though some possibilities don't make sense (eg, trying to have | ||||
|     // a %visibleInFullscreen child of a non-%visibleInFullscreen | ||||
|     // parent). By default, @actor has the same params as its chrome | ||||
|     // ancestor. | ||||
|     trackChrome: function(actor, params) { | ||||
|         this._chrome.trackActor(actor, params); | ||||
|     }, | ||||
|  | ||||
|     // untrackChrome: | ||||
|     // @actor: an actor previously tracked via trackChrome() | ||||
|     // | ||||
|     // Undoes the effect of trackChrome() | ||||
|     untrackChrome: function(actor) { | ||||
|         this._chrome.untrackActor(actor); | ||||
|     }, | ||||
|  | ||||
|     // removeChrome: | ||||
|     // @actor: a chrome actor | ||||
|     // | ||||
|     // Removes @actor from the chrome | ||||
|     removeChrome: function(actor) { | ||||
|         this._chrome.removeActor(actor); | ||||
|     } | ||||
| }; | ||||
| Signals.addSignalMethods(LayoutManager.prototype); | ||||
|  | ||||
|  | ||||
| // HotCorner: | ||||
| // | ||||
| // This class manages a "hot corner" that can toggle switching to | ||||
| // overview. | ||||
| function HotCorner() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| HotCorner.prototype = { | ||||
|     _init : function() { | ||||
|         // We use this flag to mark the case where the user has entered the | ||||
|         // hot corner and has not left both the hot corner and a surrounding | ||||
|         // guard area (the "environs"). This avoids triggering the hot corner | ||||
|         // multiple times due to an accidental jitter. | ||||
|         this._entered = false; | ||||
|  | ||||
|         this.actor = new Clutter.Group({ name: 'hot-corner-environs', | ||||
|                                          width: 3, | ||||
|                                          height: 3, | ||||
|                                          reactive: true }); | ||||
|  | ||||
|         this._corner = new Clutter.Rectangle({ name: 'hot-corner', | ||||
|                                                width: 1, | ||||
|                                                height: 1, | ||||
|                                                opacity: 0, | ||||
|                                                reactive: true }); | ||||
|         this._corner._delegate = this; | ||||
|  | ||||
|         this.actor.add_actor(this._corner); | ||||
|  | ||||
|         if (St.Widget.get_default_direction() == St.TextDirection.RTL) { | ||||
|             this._corner.set_position(this.actor.width - this._corner.width, 0); | ||||
|             this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST); | ||||
|         } else { | ||||
|             this._corner.set_position(0, 0); | ||||
|         } | ||||
|  | ||||
|         this._activationTime = 0; | ||||
|  | ||||
|         this.actor.connect('leave-event', | ||||
|                            Lang.bind(this, this._onEnvironsLeft)); | ||||
|  | ||||
|         // Clicking on the hot corner environs should result in the | ||||
|         // same behavior as clicking on the hot corner. | ||||
|         this.actor.connect('button-release-event', | ||||
|                            Lang.bind(this, this._onCornerClicked)); | ||||
|  | ||||
|         // In addition to being triggered by the mouse enter event, | ||||
|         // the hot corner can be triggered by clicking on it. This is | ||||
|         // useful if the user wants to undo the effect of triggering | ||||
|         // the hot corner once in the hot corner. | ||||
|         this._corner.connect('enter-event', | ||||
|                              Lang.bind(this, this._onCornerEntered)); | ||||
|         this._corner.connect('button-release-event', | ||||
|                              Lang.bind(this, this._onCornerClicked)); | ||||
|         this._corner.connect('leave-event', | ||||
|                              Lang.bind(this, this._onCornerLeft)); | ||||
|  | ||||
|         // Cache the three ripples instead of dynamically creating and destroying them. | ||||
|         this._ripple1 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0 }); | ||||
|         this._ripple2 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0 }); | ||||
|         this._ripple3 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0 }); | ||||
|  | ||||
|         Main.uiGroup.add_actor(this._ripple1); | ||||
|         Main.uiGroup.add_actor(this._ripple2); | ||||
|         Main.uiGroup.add_actor(this._ripple3); | ||||
|     }, | ||||
|  | ||||
|     destroy: function() { | ||||
|         this.actor.destroy(); | ||||
|     }, | ||||
|  | ||||
|     _animRipple : function(ripple, delay, time, startScale, startOpacity, finalScale) { | ||||
|         // We draw a ripple by using a source image and animating it scaling | ||||
|         // outwards and fading away. We want the ripples to move linearly | ||||
|         // or it looks unrealistic, but if the opacity of the ripple goes | ||||
|         // linearly to zero it fades away too quickly, so we use Tweener's | ||||
|         // 'onUpdate' to give a non-linear curve to the fade-away and make | ||||
|         // it more visible in the middle section. | ||||
|  | ||||
|         ripple._opacity = startOpacity; | ||||
|  | ||||
|         if (ripple.get_direction() == St.TextDirection.RTL) | ||||
|             ripple.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST); | ||||
|  | ||||
|         ripple.visible = true; | ||||
|         ripple.opacity = 255 * Math.sqrt(startOpacity); | ||||
|         ripple.scale_x = ripple.scale_y = startScale; | ||||
|  | ||||
|         let [x, y] = this._corner.get_transformed_position(); | ||||
|         ripple.x = x; | ||||
|         ripple.y = y; | ||||
|  | ||||
|         Tweener.addTween(ripple, { _opacity: 0, | ||||
|                                    scale_x: finalScale, | ||||
|                                    scale_y: finalScale, | ||||
|                                    delay: delay, | ||||
|                                    time: time, | ||||
|                                    transition: 'linear', | ||||
|                                    onUpdate: function() { ripple.opacity = 255 * Math.sqrt(ripple._opacity); }, | ||||
|                                    onComplete: function() { ripple.visible = false; } }); | ||||
|     }, | ||||
|  | ||||
|     rippleAnimation: function() { | ||||
|         // Show three concentric ripples expanding outwards; the exact | ||||
|         // parameters were found by trial and error, so don't look | ||||
|         // for them to make perfect sense mathematically | ||||
|  | ||||
|         //                              delay  time  scale opacity => scale | ||||
|         this._animRipple(this._ripple1, 0.0,   0.83,  0.25,  1.0,     1.5); | ||||
|         this._animRipple(this._ripple2, 0.05,  1.0,   0.0,   0.7,     1.25); | ||||
|         this._animRipple(this._ripple3, 0.35,  1.0,   0.0,   0.3,     1); | ||||
|     }, | ||||
|  | ||||
|     handleDragOver: function(source, actor, x, y, time) { | ||||
|         if (source != Main.xdndHandler) | ||||
|             return; | ||||
|  | ||||
|         if (!Main.overview.visible && !Main.overview.animationInProgress) { | ||||
|             this.rippleAnimation(); | ||||
|             Main.overview.showTemporarily(); | ||||
|             Main.overview.beginItemDrag(actor); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _onCornerEntered : function() { | ||||
|         if (!this._entered) { | ||||
|             this._entered = true; | ||||
|             if (!Main.overview.animationInProgress) { | ||||
|                 this._activationTime = Date.now() / 1000; | ||||
|  | ||||
|                 this.rippleAnimation(); | ||||
|                 Main.overview.toggle(); | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     }, | ||||
|  | ||||
|     _onCornerClicked : function() { | ||||
|         if (this.shouldToggleOverviewOnClick()) | ||||
|             Main.overview.toggle(); | ||||
|         return true; | ||||
|     }, | ||||
|  | ||||
|     _onCornerLeft : function(actor, event) { | ||||
|         if (event.get_related() != this.actor) | ||||
|             this._entered = false; | ||||
|         // Consume event, otherwise this will confuse onEnvironsLeft | ||||
|         return true; | ||||
|     }, | ||||
|  | ||||
|     _onEnvironsLeft : function(actor, event) { | ||||
|         if (event.get_related() != this._corner) | ||||
|             this._entered = false; | ||||
|         return false; | ||||
|     }, | ||||
|  | ||||
|     // Checks if the Activities button is currently sensitive to | ||||
|     // clicks. The first call to this function within the | ||||
|     // HOT_CORNER_ACTIVATION_TIMEOUT time of the hot corner being | ||||
|     // triggered will return false. This avoids opening and closing | ||||
|     // the overview if the user both triggered the hot corner and | ||||
|     // clicked the Activities button. | ||||
|     shouldToggleOverviewOnClick: function() { | ||||
|         if (Main.overview.animationInProgress) | ||||
|             return false; | ||||
|         if (this._activationTime == 0 || Date.now() / 1000 - this._activationTime > HOT_CORNER_ACTIVATION_TIMEOUT) | ||||
|             return true; | ||||
|         return false; | ||||
|     } | ||||
| }; | ||||
|  | ||||
|  | ||||
| // This manages the shell "chrome"; the UI that's visible in the | ||||
| // normal mode (ie, outside the Overview), that surrounds the main | ||||
| // workspace content. | ||||
|  | ||||
| const defaultParams = { | ||||
|     visibleInFullscreen: false, | ||||
|     affectsStruts: false, | ||||
|     affectsInputRegion: true | ||||
| }; | ||||
|  | ||||
| function Chrome() { | ||||
|     this._init.apply(this, arguments); | ||||
| } | ||||
|  | ||||
| Chrome.prototype = { | ||||
|     _init: function(layoutManager) { | ||||
|         this._layoutManager = layoutManager; | ||||
|  | ||||
|         this._monitors = []; | ||||
|         this._inOverview = false; | ||||
|         this._updateRegionIdle = 0; | ||||
|         this._freezeUpdateCount = 0; | ||||
|  | ||||
|         this._trackedActors = []; | ||||
|  | ||||
|         this._layoutManager.connect('monitors-changed', | ||||
|                                     Lang.bind(this, this._relayout)); | ||||
|         global.screen.connect('restacked', | ||||
|                               Lang.bind(this, this._windowsRestacked)); | ||||
|  | ||||
|         // Need to update struts on new workspaces when they are added | ||||
|         global.screen.connect('notify::n-workspaces', | ||||
|                               Lang.bind(this, this._queueUpdateRegions)); | ||||
|  | ||||
|         this._screenSaverActive = false; | ||||
|         this._screenSaverProxy = new ScreenSaver.ScreenSaverProxy(); | ||||
|         this._screenSaverProxy.connect('ActiveChanged', Lang.bind(this, this._onScreenSaverActiveChanged)); | ||||
|         this._screenSaverProxy.GetActiveRemote(Lang.bind(this, | ||||
|             function(result, err) { | ||||
|                 if (!err) | ||||
|                     this._onScreenSaverActiveChanged(this._screenSaverProxy, result); | ||||
|             })); | ||||
|  | ||||
|         this._relayout(); | ||||
|     }, | ||||
|  | ||||
|     init: function() { | ||||
|         Main.overview.connect('showing', | ||||
|                              Lang.bind(this, this._overviewShowing)); | ||||
|         Main.overview.connect('hidden', | ||||
|                              Lang.bind(this, this._overviewHidden)); | ||||
|     }, | ||||
|  | ||||
|     addActor: function(actor, params) { | ||||
|         Main.uiGroup.add_actor(actor); | ||||
|         this._trackActor(actor, params); | ||||
|     }, | ||||
|  | ||||
|     trackActor: function(actor, params) { | ||||
|         let ancestor = actor.get_parent(); | ||||
|         let index = this._findActor(ancestor); | ||||
|         while (ancestor && index == -1) { | ||||
|             ancestor = ancestor.get_parent(); | ||||
|             index = this._findActor(ancestor); | ||||
|         } | ||||
|         if (!ancestor) | ||||
|             throw new Error('actor is not a descendent of a chrome actor'); | ||||
|  | ||||
|         let ancestorData = this._trackedActors[index]; | ||||
|         if (!params) | ||||
|             params = {}; | ||||
|         // We can't use Params.parse here because we want to drop | ||||
|         // the extra values like ancestorData.actor | ||||
|         for (let prop in defaultParams) { | ||||
|             if (!params[prop]) | ||||
|                 params[prop] = ancestorData[prop]; | ||||
|         } | ||||
|  | ||||
|         this._trackActor(actor, params); | ||||
|     }, | ||||
|  | ||||
|     untrackActor: function(actor) { | ||||
|         this._untrackActor(actor); | ||||
|     }, | ||||
|  | ||||
|     removeActor: function(actor) { | ||||
|         Main.uiGroup.remove_actor(actor); | ||||
|         this._untrackActor(actor); | ||||
|     }, | ||||
|  | ||||
|     _findActor: function(actor) { | ||||
|         for (let i = 0; i < this._trackedActors.length; i++) { | ||||
|             let actorData = this._trackedActors[i]; | ||||
|             if (actorData.actor == actor) | ||||
|                 return i; | ||||
|         } | ||||
|         return -1; | ||||
|     }, | ||||
|  | ||||
|     _trackActor: function(actor, params) { | ||||
|         if (this._findActor(actor) != -1) | ||||
|             throw new Error('trying to re-track existing chrome actor'); | ||||
|  | ||||
|         let actorData = Params.parse(params, defaultParams); | ||||
|         actorData.actor = actor; | ||||
|         actorData.isToplevel = actor.get_parent() == Main.uiGroup; | ||||
|         actorData.visibleId = actor.connect('notify::visible', | ||||
|                                             Lang.bind(this, this._queueUpdateRegions)); | ||||
|         actorData.allocationId = actor.connect('notify::allocation', | ||||
|                                                Lang.bind(this, this._queueUpdateRegions)); | ||||
|         actorData.parentSetId = actor.connect('parent-set', | ||||
|                                               Lang.bind(this, this._actorReparented)); | ||||
|         // Note that destroying actor will unset its parent, so we don't | ||||
|         // need to connect to 'destroy' too. | ||||
|  | ||||
|         this._trackedActors.push(actorData); | ||||
|         this._queueUpdateRegions(); | ||||
|     }, | ||||
|  | ||||
|     _untrackActor: function(actor) { | ||||
|         let i = this._findActor(actor); | ||||
|  | ||||
|         if (i == -1) | ||||
|             return; | ||||
|         let actorData = this._trackedActors[i]; | ||||
|  | ||||
|         this._trackedActors.splice(i, 1); | ||||
|         actor.disconnect(actorData.visibleId); | ||||
|         actor.disconnect(actorData.allocationId); | ||||
|         actor.disconnect(actorData.parentSetId); | ||||
|  | ||||
|         this._queueUpdateRegions(); | ||||
|     }, | ||||
|  | ||||
|     _actorReparented: function(actor, oldParent) { | ||||
|         let newParent = actor.get_parent(); | ||||
|         if (!newParent) | ||||
|             this._untrackActor(actor); | ||||
|         else | ||||
|             actorData.isToplevel = (newParent == Main.uiGroup); | ||||
|     }, | ||||
|  | ||||
|     _updateVisibility: function() { | ||||
|         for (let i = 0; i < this._trackedActors.length; i++) { | ||||
|             let actorData = this._trackedActors[i], visible; | ||||
|             if (!actorData.isToplevel) | ||||
|                 continue; | ||||
|  | ||||
|             if (this._screenSaverActive) | ||||
|                 visible = false; | ||||
|             else if (this._inOverview) | ||||
|                 visible = true; | ||||
|             else if (!actorData.visibleInFullscreen && | ||||
|                      this._findMonitorForActor(actorData.actor).inFullscreen) | ||||
|                 visible = false; | ||||
|             else | ||||
|                 visible = true; | ||||
|             Main.uiGroup.set_skip_paint(actorData.actor, !visible); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _overviewShowing: function() { | ||||
|         this._inOverview = true; | ||||
|         this._updateVisibility(); | ||||
|         this._queueUpdateRegions(); | ||||
|     }, | ||||
|  | ||||
|     _overviewHidden: function() { | ||||
|         this._inOverview = false; | ||||
|         this._updateVisibility(); | ||||
|         this._queueUpdateRegions(); | ||||
|     }, | ||||
|  | ||||
|     _relayout: function() { | ||||
|         this._monitors = this._layoutManager.monitors; | ||||
|         this._primaryMonitor = this._layoutManager.primaryMonitor; | ||||
|  | ||||
|         this._updateFullscreen(); | ||||
|         this._updateVisibility(); | ||||
|         this._queueUpdateRegions(); | ||||
|     }, | ||||
|  | ||||
|     _onScreenSaverActiveChanged: function(proxy, screenSaverActive) { | ||||
|         this._screenSaverActive = screenSaverActive; | ||||
|         this._updateVisibility(); | ||||
|         this._queueUpdateRegions(); | ||||
|     }, | ||||
|  | ||||
|     _findMonitorForRect: function(x, y, w, h) { | ||||
|         // First look at what monitor the center of the rectangle is at | ||||
|         let cx = x + w/2; | ||||
|         let cy = y + h/2; | ||||
|         for (let i = 0; i < this._monitors.length; i++) { | ||||
|             let monitor = this._monitors[i]; | ||||
|             if (cx >= monitor.x && cx < monitor.x + monitor.width && | ||||
|                 cy >= monitor.y && cy < monitor.y + monitor.height) | ||||
|                 return monitor; | ||||
|         } | ||||
|         // If the center is not on a monitor, return the first overlapping monitor | ||||
|         for (let i = 0; i < this._monitors.length; i++) { | ||||
|             let monitor = this._monitors[i]; | ||||
|             if (x + w > monitor.x && x < monitor.x + monitor.width && | ||||
|                 y + h > monitor.y && y < monitor.y + monitor.height) | ||||
|                 return monitor; | ||||
|         } | ||||
|         // otherwise on no monitor | ||||
|         return null; | ||||
|     }, | ||||
|  | ||||
|     _findMonitorForWindow: function(window) { | ||||
|         return this._findMonitorForRect(window.x, window.y, window.width, window.height); | ||||
|     }, | ||||
|  | ||||
|     // This call guarantees that we return some monitor to simplify usage of it | ||||
|     // In practice all tracked actors should be visible on some monitor anyway | ||||
|     _findMonitorForActor: function(actor) { | ||||
|         let [x, y] = actor.get_transformed_position(); | ||||
|         let [w, h] = actor.get_transformed_size(); | ||||
|         let monitor = this._findMonitorForRect(x, y, w, h); | ||||
|         if (monitor) | ||||
|             return monitor; | ||||
|         return this._primaryMonitor; // Not on any monitor, pretend its on the primary | ||||
|     }, | ||||
|  | ||||
|     _queueUpdateRegions: function() { | ||||
|         if (!this._updateRegionIdle && !this._freezeUpdateCount) | ||||
|             this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this.updateRegions), | ||||
|                                                        Meta.PRIORITY_BEFORE_REDRAW); | ||||
|     }, | ||||
|  | ||||
|     freezeUpdateRegions: function() { | ||||
|         if (this._updateRegionIdle) | ||||
|             this.updateRegions(); | ||||
|         this._freezeUpdateCount++; | ||||
|     }, | ||||
|  | ||||
|     thawUpdateRegions: function() { | ||||
|         this._freezeUpdateCount--; | ||||
|         this._queueUpdateRegions(); | ||||
|     }, | ||||
|  | ||||
|     _updateFullscreen: function() { | ||||
|         let windows = Main.getWindowActorsForWorkspace(global.screen.get_active_workspace_index()); | ||||
|  | ||||
|         // Reset all monitors to not fullscreen | ||||
|         for (let i = 0; i < this._monitors.length; i++) | ||||
|             this._monitors[i].inFullscreen = false; | ||||
|  | ||||
|         // Ordinary chrome should be visible unless there is a window | ||||
|         // with layer FULLSCREEN, or a window with layer | ||||
|         // OVERRIDE_REDIRECT that covers the whole screen. | ||||
|         // ('override_redirect' is not actually a layer above all | ||||
|         // other windows, but this seems to be how mutter treats it | ||||
|         // currently...) If we wanted to be extra clever, we could | ||||
|         // figure out when an OVERRIDE_REDIRECT window was trying to | ||||
|         // partially overlap us, and then adjust the input region and | ||||
|         // our clip region accordingly... | ||||
|  | ||||
|         // @windows is sorted bottom to top. | ||||
|  | ||||
|         for (let i = windows.length - 1; i > -1; i--) { | ||||
|             let window = windows[i]; | ||||
|             let layer = window.get_meta_window().get_layer(); | ||||
|  | ||||
|             // Skip minimized windows | ||||
|             if (!window.showing_on_its_workspace()) | ||||
|                 continue; | ||||
|  | ||||
|             if (layer == Meta.StackLayer.FULLSCREEN) { | ||||
|                 let monitor = this._findMonitorForWindow(window); | ||||
|                 if (monitor) | ||||
|                     monitor.inFullscreen = true; | ||||
|             } | ||||
|             if (layer == Meta.StackLayer.OVERRIDE_REDIRECT) { | ||||
|                 let monitor = this._findMonitorForWindow(window); | ||||
|                 if (monitor && | ||||
|                     window.x <= monitor.x && | ||||
|                     window.x + window.width >= monitor.x + monitor.width && | ||||
|                     window.y <= monitor.y && | ||||
|                     window.y + window.height >= monitor.y + monitor.height) | ||||
|                     monitor.inFullscreen = true; | ||||
|             } else | ||||
|                 break; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _windowsRestacked: function() { | ||||
|         let wasInFullscreen = []; | ||||
|         for (let i = 0; i < this._monitors.length; i++) | ||||
|             wasInFullscreen[i] = this._monitors[i].inFullscreen; | ||||
|  | ||||
|         this._updateFullscreen(); | ||||
|  | ||||
|         let changed = false; | ||||
|         for (let i = 0; i < wasInFullscreen.length; i++) { | ||||
|             if (wasInFullscreen[i] != this._monitors[i].inFullscreen) { | ||||
|                 changed = true; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         if (changed) { | ||||
|             this._updateVisibility(); | ||||
|             this._queueUpdateRegions(); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     updateRegions: function() { | ||||
|         let rects = [], struts = [], i; | ||||
|  | ||||
|         if (this._updateRegionIdle) { | ||||
|             Mainloop.source_remove(this._updateRegionIdle); | ||||
|             delete this._updateRegionIdle; | ||||
|         } | ||||
|  | ||||
|         for (i = 0; i < this._trackedActors.length; i++) { | ||||
|             let actorData = this._trackedActors[i]; | ||||
|             if (!actorData.affectsInputRegion && !actorData.affectsStruts) | ||||
|                 continue; | ||||
|  | ||||
|             let [x, y] = actorData.actor.get_transformed_position(); | ||||
|             let [w, h] = actorData.actor.get_transformed_size(); | ||||
|             x = Math.round(x); | ||||
|             y = Math.round(y); | ||||
|             w = Math.round(w); | ||||
|             h = Math.round(h); | ||||
|             let rect = new Meta.Rectangle({ x: x, y: y, width: w, height: h}); | ||||
|  | ||||
|             if (actorData.affectsInputRegion && | ||||
|                 actorData.actor.get_paint_visibility() && | ||||
|                 !Main.uiGroup.get_skip_paint(actorData.actor)) | ||||
|                 rects.push(rect); | ||||
|  | ||||
|             if (!actorData.affectsStruts) | ||||
|                 continue; | ||||
|  | ||||
|             // Limit struts to the size of the screen | ||||
|             let x1 = Math.max(x, 0); | ||||
|             let x2 = Math.min(x + w, global.screen_width); | ||||
|             let y1 = Math.max(y, 0); | ||||
|             let y2 = Math.min(y + h, global.screen_height); | ||||
|  | ||||
|             // NetWM struts are not really powerful enought to handle | ||||
|             // a multi-monitor scenario, they only describe what happens | ||||
|             // around the outer sides of the full display region. However | ||||
|             // it can describe a partial region along each side, so | ||||
|             // we can support having the struts only affect the | ||||
|             // primary monitor. This should be enough as we only have | ||||
|             // chrome affecting the struts on the primary monitor so | ||||
|             // far. | ||||
|             // | ||||
|             // Metacity wants to know what side of the screen the | ||||
|             // strut is considered to be attached to. If the actor is | ||||
|             // only touching one edge, or is touching the entire | ||||
|             // border of the primary monitor, then it's obvious which | ||||
|             // side to call it. If it's in a corner, we pick a side | ||||
|             // arbitrarily. If it doesn't touch any edges, or it spans | ||||
|             // the width/height across the middle of the screen, then | ||||
|             // we don't create a strut for it at all. | ||||
|             let side; | ||||
|             let primary = this._primaryMonitor; | ||||
|             if (x1 <= primary.x && x2 >= primary.x + primary.width) { | ||||
|                 if (y1 <= primary.y) | ||||
|                     side = Meta.Side.TOP; | ||||
|                 else if (y2 >= primary.y + primary.height) | ||||
|                     side = Meta.Side.BOTTOM; | ||||
|                 else | ||||
|                     continue; | ||||
|             } else if (y1 <= primary.y && y2 >= primary.y + primary.height) { | ||||
|                 if (x1 <= 0) | ||||
|                     side = Meta.Side.LEFT; | ||||
|                 else if (x2 >= global.screen_width) | ||||
|                     side = Meta.Side.RIGHT; | ||||
|                 else | ||||
|                     continue; | ||||
|             } else if (x1 <= 0) | ||||
|                 side = Meta.Side.LEFT; | ||||
|             else if (y1 <= 0) | ||||
|                 side = Meta.Side.TOP; | ||||
|             else if (x2 >= global.screen_width) | ||||
|                 side = Meta.Side.RIGHT; | ||||
|             else if (y2 >= global.screen_height) | ||||
|                 side = Meta.Side.BOTTOM; | ||||
|             else | ||||
|                 continue; | ||||
|  | ||||
|             // Ensure that the strut rects goes all the way to the screen edge, | ||||
|             // as this really what mutter expects. | ||||
|             switch (side) { | ||||
|             case Meta.Side.TOP: | ||||
|                 y1 = 0; | ||||
|                 break; | ||||
|             case Meta.Side.BOTTOM: | ||||
|                 y2 = global.screen_height; | ||||
|                 break; | ||||
|             case Meta.Side.LEFT: | ||||
|                 x1 = 0; | ||||
|                 break; | ||||
|             case Meta.Side.RIGHT: | ||||
|                 x2 = global.screen_width; | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             let strutRect = new Meta.Rectangle({ x: x1, y: y1, width: x2 - x1, height: y2 - y1}); | ||||
|             let strut = new Meta.Strut({ rect: strutRect, side: side }); | ||||
|             struts.push(strut); | ||||
|         } | ||||
|  | ||||
|         global.set_stage_input_region(rects); | ||||
|  | ||||
|         let screen = global.screen; | ||||
|         for (let w = 0; w < screen.n_workspaces; w++) { | ||||
|             let workspace = screen.get_workspace_by_index(w); | ||||
|             workspace.set_builtin_struts(struts); | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
| }; | ||||
| @@ -1,20 +1,18 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Clutter = imports.gi.Clutter; | ||||
| const Cogl = imports.gi.Cogl; | ||||
| const GConf = imports.gi.GConf; | ||||
| const GLib = imports.gi.GLib; | ||||
| const Gio = imports.gi.Gio; | ||||
| const Gtk = imports.gi.Gtk; | ||||
| const Meta = imports.gi.Meta; | ||||
| const Pango = imports.gi.Pango; | ||||
| const St = imports.gi.St; | ||||
| const Shell = imports.gi.Shell; | ||||
| const Signals = imports.signals; | ||||
| const Lang = imports.lang; | ||||
| const Mainloop = imports.mainloop; | ||||
| const Gettext = imports.gettext.domain('gnome-shell'); | ||||
| const _ = Gettext.gettext; | ||||
|  | ||||
| const History = imports.misc.history; | ||||
| const ExtensionSystem = imports.ui.extensionSystem; | ||||
| const Link = imports.ui.link; | ||||
| const Tweener = imports.ui.tweener; | ||||
| @@ -27,7 +25,6 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' + | ||||
|                     'const Mainloop = imports.mainloop; ' + | ||||
|                     'const Meta = imports.gi.Meta; ' + | ||||
|                     'const Shell = imports.gi.Shell; ' + | ||||
|                     'const Tp = imports.gi.TelepathyGLib; ' + | ||||
|                     'const Main = imports.ui.main; ' + | ||||
|                     'const Lang = imports.lang; ' + | ||||
|                     'const Tweener = imports.ui.tweener; ' + | ||||
| @@ -39,8 +36,6 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' + | ||||
|                        'const it = Main.lookingGlass.getIt(); ' + | ||||
|                     'const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); '; | ||||
|  | ||||
| const HISTORY_KEY = 'looking-glass-history'; | ||||
|  | ||||
| function Notebook() { | ||||
|     this._init(); | ||||
| } | ||||
| @@ -100,19 +95,12 @@ Notebook.prototype = { | ||||
|     selectIndex: function(index) { | ||||
|         if (index == this._selectedIndex) | ||||
|             return; | ||||
|         this._unselect(); | ||||
|         if (index < 0) { | ||||
|             this._unselect(); | ||||
|             this.emit('selection', null); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Focus the new tab before unmapping the old one | ||||
|         let tabData = this._tabs[index]; | ||||
|         if (!tabData.scrollView.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false)) | ||||
|             this.actor.grab_key_focus(); | ||||
|  | ||||
|         this._unselect(); | ||||
|  | ||||
|         tabData.labelBox.add_style_pseudo_class('selected'); | ||||
|         tabData.scrollView.show(); | ||||
|         this._selectedIndex = index; | ||||
| @@ -223,9 +211,10 @@ function WindowList() { | ||||
| WindowList.prototype = { | ||||
|     _init : function () { | ||||
|         this.actor = new St.BoxLayout({ name: 'Windows', vertical: true, style: 'spacing: 8px' }); | ||||
|         let display = global.screen.get_display(); | ||||
|         let tracker = Shell.WindowTracker.get_default(); | ||||
|         this._updateId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._updateWindowList)); | ||||
|         global.display.connect('window-created', Lang.bind(this, this._updateWindowList)); | ||||
|         display.connect('window-created', Lang.bind(this, this._updateWindowList)); | ||||
|         tracker.connect('tracked-windows-changed', Lang.bind(this, this._updateWindowList)); | ||||
|     }, | ||||
|  | ||||
| @@ -248,7 +237,7 @@ WindowList.prototype = { | ||||
|             box.add(propsBox); | ||||
|             propsBox.add(new St.Label({ text: 'wmclass: ' + metaWindow.get_wm_class() })); | ||||
|             let app = tracker.get_window_app(metaWindow); | ||||
|             if (app != null && !app.is_window_backed()) { | ||||
|             if (app != null && !app.is_transient()) { | ||||
|                 let icon = app.create_icon_texture(22); | ||||
|                 let propBox = new St.BoxLayout({ style: 'spacing: 6px; ' }); | ||||
|                 propsBox.add(propBox); | ||||
| @@ -370,30 +359,6 @@ ObjInspector.prototype = { | ||||
|     } | ||||
| }; | ||||
|  | ||||
| function addBorderPaintHook(actor) { | ||||
|     let signalId = actor.connect_after('paint', | ||||
|         function () { | ||||
|             let color = new Cogl.Color(); | ||||
|             color.init_from_4ub(0xff, 0, 0, 0xc4); | ||||
|             Cogl.set_source_color(color); | ||||
|  | ||||
|             let geom = actor.get_allocation_geometry(); | ||||
|             let width = 2; | ||||
|  | ||||
|             // clockwise order | ||||
|             Cogl.rectangle(0, 0, geom.width, width); | ||||
|             Cogl.rectangle(geom.width - width, width, | ||||
|                            geom.width, geom.height); | ||||
|             Cogl.rectangle(0, geom.height, | ||||
|                            geom.width - width, geom.height - width); | ||||
|             Cogl.rectangle(0, geom.height - width, | ||||
|                            width, width); | ||||
|         }); | ||||
|  | ||||
|     actor.queue_redraw(); | ||||
|     return signalId; | ||||
| } | ||||
|  | ||||
| function Inspector() { | ||||
|     this._init(); | ||||
| } | ||||
| @@ -433,10 +398,7 @@ Inspector.prototype = { | ||||
|     }, | ||||
|  | ||||
|     _allocate: function(actor, box, flags) { | ||||
|         if (!this._eventHandler) | ||||
|             return; | ||||
|  | ||||
|         let primary = Main.layoutManager.primaryMonitor; | ||||
|         let primary = global.get_primary_monitor(); | ||||
|  | ||||
|         let [minWidth, minHeight, natWidth, natHeight] = | ||||
|             this._eventHandler.get_preferred_size(); | ||||
| @@ -453,7 +415,6 @@ Inspector.prototype = { | ||||
|         Clutter.ungrab_pointer(this._eventHandler); | ||||
|         Clutter.ungrab_keyboard(this._eventHandler); | ||||
|         this._eventHandler.destroy(); | ||||
|         this._eventHandler = null; | ||||
|         this.emit('closed'); | ||||
|     }, | ||||
|  | ||||
| @@ -529,13 +490,10 @@ Inspector.prototype = { | ||||
|         let position = '[inspect x: ' + stageX + ' y: ' + stageY + ']'; | ||||
|         this._displayText.text = ''; | ||||
|         this._displayText.text = position + ' ' + this._target; | ||||
|  | ||||
|         if (this._borderPaintTarget != this._target) { | ||||
|             if (this._borderPaintTarget != null) | ||||
|                 this._borderPaintTarget.disconnect(this._borderPaintId); | ||||
|             this._borderPaintTarget = this._target; | ||||
|             this._borderPaintId = addBorderPaintHook(this._target); | ||||
|         } | ||||
|         if (this._borderPaintTarget != null) | ||||
|             this._borderPaintTarget.disconnect(this._borderPaintId); | ||||
|         this._borderPaintTarget = this._target; | ||||
|         this._borderPaintId = Shell.add_hook_paint_red_border(this._target); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| @@ -582,53 +540,6 @@ ErrorLog.prototype = { | ||||
|     } | ||||
| }; | ||||
|  | ||||
| function Memory() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| Memory.prototype = { | ||||
|     _init: function() { | ||||
|         this.actor = new St.BoxLayout({ vertical: true }); | ||||
|         this._glibc_uordblks = new St.Label(); | ||||
|         this.actor.add(this._glibc_uordblks); | ||||
|  | ||||
|         this._js_bytes = new St.Label(); | ||||
|         this.actor.add(this._js_bytes); | ||||
|  | ||||
|         this._gjs_boxed = new St.Label(); | ||||
|         this.actor.add(this._gjs_boxed); | ||||
|  | ||||
|         this._gjs_gobject = new St.Label(); | ||||
|         this.actor.add(this._gjs_gobject); | ||||
|  | ||||
|         this._gjs_function = new St.Label(); | ||||
|         this.actor.add(this._gjs_function); | ||||
|  | ||||
|         this._gjs_closure = new St.Label(); | ||||
|         this.actor.add(this._gjs_closure); | ||||
|  | ||||
|         this._gcbutton = new St.Button({ label: 'Full GC', | ||||
|                                          style_class: 'lg-obj-inspector-button' }); | ||||
|         this._gcbutton.connect('clicked', Lang.bind(this, function () { global.gc(); this._renderText(); })); | ||||
|         this.actor.add(this._gcbutton, { x_align: St.Align.START, | ||||
|                                          x_fill: false }); | ||||
|  | ||||
|         this.actor.connect('notify::mapped', Lang.bind(this, this._renderText)); | ||||
|     }, | ||||
|  | ||||
|     _renderText: function() { | ||||
|         if (!this.actor.mapped) | ||||
|             return; | ||||
|         let memInfo = global.get_memory_info(); | ||||
|         this._glibc_uordblks.text = 'glibc_uordblks: ' + memInfo.glibc_uordblks; | ||||
|         this._js_bytes.text = 'js bytes: ' + memInfo.js_bytes; | ||||
|         this._gjs_boxed.text = 'gjs_boxed: ' + memInfo.gjs_boxed; | ||||
|         this._gjs_gobject.text = 'gjs_gobject: ' + memInfo.gjs_gobject; | ||||
|         this._gjs_function.text = 'gjs_function: ' + memInfo.gjs_function; | ||||
|         this._gjs_closure.text = 'gjs_closure: ' + memInfo.gjs_closure; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| function Extensions() { | ||||
|     this._init(); | ||||
| } | ||||
| @@ -639,32 +550,23 @@ Extensions.prototype = { | ||||
|                                         name: 'lookingGlassExtensions' }); | ||||
|         this._noExtensions = new St.Label({ style_class: 'lg-extensions-none', | ||||
|                                              text: _("No extensions installed") }); | ||||
|         this._numExtensions = 0; | ||||
|         this._extensionsList = new St.BoxLayout({ vertical: true, | ||||
|                                                   style_class: 'lg-extensions-list' }); | ||||
|         this._extensionsList.add(this._noExtensions); | ||||
|         this.actor.add(this._extensionsList); | ||||
|  | ||||
|         for (let uuid in ExtensionSystem.extensionMeta) | ||||
|             this._loadExtension(null, uuid); | ||||
|  | ||||
|         ExtensionSystem.connect('extension-loaded', | ||||
|                                 Lang.bind(this, this._loadExtension)); | ||||
|         this._loadExtensionList(); | ||||
|     }, | ||||
|  | ||||
|     _loadExtension: function(o, uuid) { | ||||
|         let extension = ExtensionSystem.extensionMeta[uuid]; | ||||
|         // There can be cases where we create dummy extension metadata | ||||
|         // that's not really a proper extension. Don't bother with these. | ||||
|         if (!extension.name) | ||||
|             return; | ||||
|  | ||||
|         let extensionDisplay = this._createExtensionDisplay(extension); | ||||
|         if (this._numExtensions == 0) | ||||
|             this._extensionsList.remove_actor(this._noExtensions); | ||||
|  | ||||
|         this._numExtensions ++; | ||||
|         this._extensionsList.add(extensionDisplay); | ||||
|     _loadExtensionList: function() { | ||||
|         let extensions = ExtensionSystem.extensionMeta; | ||||
|         let totalExtensions = 0; | ||||
|         for (let uuid in extensions) { | ||||
|             let extensionDisplay = this._createExtensionDisplay(extensions[uuid]); | ||||
|             this._extensionsList.add(extensionDisplay); | ||||
|             totalExtensions++; | ||||
|         } | ||||
|         if (totalExtensions == 0) { | ||||
|             this._extensionsList.add(this._noExtensions); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _onViewSource: function (actor) { | ||||
| @@ -691,8 +593,6 @@ Extensions.prototype = { | ||||
|                 return _("Error"); | ||||
|             case ExtensionSystem.ExtensionState.OUT_OF_DATE: | ||||
|                 return _("Out of date"); | ||||
|             case ExtensionSystem.ExtensionState.DOWNLOADING: | ||||
|                 return _("Downloading"); | ||||
|         } | ||||
|         return 'Unknown'; // Not translated, shouldn't appear | ||||
|     }, | ||||
| @@ -703,7 +603,7 @@ Extensions.prototype = { | ||||
|                                    text: meta.name }); | ||||
|         box.add(name, { expand: true }); | ||||
|         let description = new St.Label({ style_class: 'lg-extension-description', | ||||
|                                          text: meta.description || 'No description' }); | ||||
|                                          text: meta.description }); | ||||
|         box.add(description, { expand: true }); | ||||
|  | ||||
|         let metaBox = new St.BoxLayout(); | ||||
| @@ -739,10 +639,18 @@ function LookingGlass() { | ||||
|  | ||||
| LookingGlass.prototype = { | ||||
|     _init : function() { | ||||
|         this._idleHistorySaveId = 0; | ||||
|         let historyPath = global.userdatadir + '/lookingglass-history.txt'; | ||||
|         this._historyFile = Gio.file_new_for_path(historyPath); | ||||
|         this._savedText = null; | ||||
|         this._historyNavIndex = -1; | ||||
|         this._history = []; | ||||
|         this._borderPaintTarget = null; | ||||
|         this._borderPaintId = 0; | ||||
|         this._borderDestroyId = 0; | ||||
|  | ||||
|         this._readHistory(); | ||||
|  | ||||
|         this._open = false; | ||||
|  | ||||
|         this._offset = 0; | ||||
| @@ -755,20 +663,14 @@ LookingGlass.prototype = { | ||||
|                                         style_class: 'lg-dialog', | ||||
|                                         vertical: true, | ||||
|                                         visible: false }); | ||||
|         this.actor.connect('key-press-event', Lang.bind(this, this._globalKeyPressEvent)); | ||||
|  | ||||
|         this._interfaceSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' }); | ||||
|         this._interfaceSettings.connect('changed::monospace-font-name', | ||||
|                                         Lang.bind(this, this._updateFont)); | ||||
|         let gconf = GConf.Client.get_default(); | ||||
|         gconf.add_dir('/desktop/gnome/interface', GConf.ClientPreloadType.PRELOAD_NONE); | ||||
|         gconf.notify_add('/desktop/gnome/interface/monospace_font_name', | ||||
|                          Lang.bind(this, this._updateFont)); | ||||
|         this._updateFont(); | ||||
|  | ||||
|         // We want it to appear to slide out from underneath the panel | ||||
|         Main.layoutManager.panelBox.add_actor(this.actor); | ||||
|         this.actor.lower_bottom(); | ||||
|         Main.layoutManager.panelBox.connect('allocation-changed', | ||||
|                                             Lang.bind(this, this._queueResize)); | ||||
|         Main.layoutManager.keyboardBox.connect('allocation-changed', | ||||
|                                                Lang.bind(this, this._queueResize)); | ||||
|         Main.uiGroup.add_actor(this.actor); | ||||
|  | ||||
|         this._objInspector = new ObjInspector(); | ||||
|         Main.uiGroup.add_actor(this._objInspector.actor); | ||||
| @@ -777,7 +679,6 @@ LookingGlass.prototype = { | ||||
|         let toolbar = new St.BoxLayout({ name: 'Toolbar' }); | ||||
|         this.actor.add_actor(toolbar); | ||||
|         let inspectIcon = new St.Icon({ icon_name: 'gtk-color-picker', | ||||
|                                         icon_type: St.IconType.FULLCOLOR, | ||||
|                                         icon_size: 24 }); | ||||
|         toolbar.add_actor(inspectIcon); | ||||
|         inspectIcon.reactive = true; | ||||
| @@ -815,7 +716,12 @@ LookingGlass.prototype = { | ||||
|         let label = new St.Label({ text: 'js>>> ' }); | ||||
|         entryArea.add(label); | ||||
|  | ||||
|         this._entry = new St.Entry({ can_focus: true }); | ||||
|         this._entry = new St.Entry(); | ||||
|         /* unmapping the edit box will un-focus it, undo that */ | ||||
|         notebook.connect('selection', Lang.bind(this, function (nb, child) { | ||||
|             if (child == this._evalBox) | ||||
|                 global.stage.set_key_focus(this._entry); | ||||
|         })); | ||||
|         entryArea.add(this._entry, { expand: true }); | ||||
|  | ||||
|         this._windowList = new WindowList(); | ||||
| @@ -828,9 +734,6 @@ LookingGlass.prototype = { | ||||
|         this._errorLog = new ErrorLog(); | ||||
|         notebook.appendPage('Errors', this._errorLog.actor); | ||||
|  | ||||
|         this._memory = new Memory(); | ||||
|         notebook.appendPage('Memory', this._memory.actor); | ||||
|  | ||||
|         this._extensions = new Extensions(); | ||||
|         notebook.appendPage('Extensions', this._extensions.actor); | ||||
|  | ||||
| @@ -844,17 +747,39 @@ LookingGlass.prototype = { | ||||
|             if (text == '') | ||||
|                 return true; | ||||
|             this._evaluate(text); | ||||
|             this._historyNavIndex = -1; | ||||
|             return true; | ||||
|         })); | ||||
|  | ||||
|         this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY,  | ||||
|                                                      entry: this._entry.clutter_text }); | ||||
|  | ||||
|         this._resize(); | ||||
|         this._entry.clutter_text.connect('key-press-event', Lang.bind(this, function(o, e) { | ||||
|             let symbol = e.get_key_symbol(); | ||||
|             if (symbol == Clutter.Up) { | ||||
|                 if (this._historyNavIndex >= this._history.length - 1) | ||||
|                     return true; | ||||
|                 this._historyNavIndex++; | ||||
|                 if (this._historyNavIndex == 0) | ||||
|                     this._savedText = this._entry.text; | ||||
|                 this._entry.text = this._history[this._history.length - this._historyNavIndex - 1]; | ||||
|                 return true; | ||||
|             } else if (symbol == Clutter.Down) { | ||||
|                 if (this._historyNavIndex <= 0) | ||||
|                     return true; | ||||
|                 this._historyNavIndex--; | ||||
|                 if (this._historyNavIndex < 0) | ||||
|                     this._entry.text = this._savedText; | ||||
|                 else | ||||
|                     this._entry.text = this._history[this._history.length - this._historyNavIndex - 1]; | ||||
|                 return true; | ||||
|             } else { | ||||
|                 this._historyNavIndex = -1; | ||||
|                 this._savedText = null; | ||||
|                 return false; | ||||
|             } | ||||
|         })); | ||||
|     }, | ||||
|  | ||||
|     _updateFont: function() { | ||||
|         let fontName = this._interfaceSettings.get_string('monospace-font-name'); | ||||
|         let gconf = GConf.Client.get_default(); | ||||
|         let fontName = gconf.get_string('/desktop/gnome/interface/monospace_font_name'); | ||||
|         // This is mishandled by the scanner - should by Pango.FontDescription_from_string(fontName); | ||||
|         // https://bugzilla.gnome.org/show_bug.cgi?id=595889 | ||||
|         let fontDesc = Pango.font_description_from_string(fontName); | ||||
| @@ -865,6 +790,29 @@ LookingGlass.prototype = { | ||||
|             + 'font-family: "' + fontDesc.get_family() + '";'; | ||||
|     }, | ||||
|  | ||||
|     _readHistory: function () { | ||||
|         if (!this._historyFile.query_exists(null)) | ||||
|             return; | ||||
|         let [result, contents, length, etag] = this._historyFile.load_contents(null); | ||||
|         this._history = contents.split('\n').filter(function (e) { return e != ''; }); | ||||
|     }, | ||||
|  | ||||
|     _queueHistorySave: function() { | ||||
|         if (this._idleHistorySaveId > 0) | ||||
|             return; | ||||
|         this._idleHistorySaveId = Mainloop.timeout_add_seconds(5, Lang.bind(this, this._doSaveHistory)); | ||||
|     }, | ||||
|  | ||||
|     _doSaveHistory: function () { | ||||
|         this._idleHistorySaveId = false; | ||||
|         let output = this._historyFile.replace(null, true, Gio.FileCreateFlags.NONE, null); | ||||
|         let dataOut = new Gio.DataOutputStream({ base_stream: output }); | ||||
|         dataOut.put_string(this._history.join('\n'), null); | ||||
|         dataOut.put_string('\n', null); | ||||
|         dataOut.close(null); | ||||
|         return false; | ||||
|     }, | ||||
|  | ||||
|     _pushResult: function(command, obj) { | ||||
|         let index = this._results.length + this._offset; | ||||
|         let result = new Result('>>> ' + command, obj, index); | ||||
| @@ -876,7 +824,7 @@ LookingGlass.prototype = { | ||||
|         } | ||||
|         if (obj instanceof Clutter.Actor) { | ||||
|             this._borderPaintTarget = obj; | ||||
|             this._borderPaintId = addBorderPaintHook(obj); | ||||
|             this._borderPaintId = Shell.add_hook_paint_red_border(obj); | ||||
|             this._borderDestroyId = obj.connect('destroy', Lang.bind(this, function () { | ||||
|                 this._borderDestroyId = 0; | ||||
|                 this._borderPaintTarget = null; | ||||
| @@ -895,7 +843,8 @@ LookingGlass.prototype = { | ||||
|     }, | ||||
|  | ||||
|     _evaluate : function(command) { | ||||
|         this._history.addItem(command); | ||||
|         this._history.push(command); | ||||
|         this._queueHistorySave(); | ||||
|  | ||||
|         let fullCmd = commandHeader + command; | ||||
|  | ||||
| @@ -925,18 +874,13 @@ LookingGlass.prototype = { | ||||
|             this.open(); | ||||
|     }, | ||||
|  | ||||
|     _queueResize: function() { | ||||
|         Meta.later_add(Meta.LaterType.BEFORE_REDRAW, | ||||
|                        Lang.bind(this, function () { this._resize(); })); | ||||
|     }, | ||||
|  | ||||
|     _resize: function() { | ||||
|         let primary = Main.layoutManager.primaryMonitor; | ||||
|     _resizeTo: function(actor) { | ||||
|         let primary = global.get_primary_monitor(); | ||||
|         let myWidth = primary.width * 0.7; | ||||
|         let availableHeight = primary.height - Main.layoutManager.keyboardBox.height; | ||||
|         let myHeight = Math.min(primary.height * 0.7, availableHeight * 0.9); | ||||
|         this.actor.x = (primary.width - myWidth) / 2; | ||||
|         this._hiddenY = this.actor.get_parent().height - myHeight - 4; // -4 to hide the top corners | ||||
|         let myHeight = primary.height * 0.7; | ||||
|         let [srcX, srcY] = actor.get_transformed_position(); | ||||
|         this.actor.x = srcX + (primary.width - myWidth) / 2; | ||||
|         this._hiddenY = srcY + actor.height - myHeight - 4; // -4 to hide the top corners | ||||
|         this._targetY = this._hiddenY + myHeight; | ||||
|         this.actor.y = this._hiddenY; | ||||
|         this.actor.width = myWidth; | ||||
| @@ -946,6 +890,14 @@ LookingGlass.prototype = { | ||||
|                                               this._targetY + Math.floor(myHeight * 0.1)); | ||||
|     }, | ||||
|  | ||||
|     slaveTo: function(actor) { | ||||
|         this._slaveTo = actor; | ||||
|         actor.connect('notify::allocation', Lang.bind(this, function () { | ||||
|             this._resizeTo(actor); | ||||
|         })); | ||||
|         this._resizeTo(actor); | ||||
|     }, | ||||
|  | ||||
|     insertObject: function(obj) { | ||||
|         this._pushResult('<insert>', obj); | ||||
|     }, | ||||
| @@ -973,16 +925,20 @@ LookingGlass.prototype = { | ||||
|         if (this._open) | ||||
|             return; | ||||
|  | ||||
|         if (!Main.pushModal(this._entry)) | ||||
|         if (!Main.pushModal(this.actor)) | ||||
|             return; | ||||
|  | ||||
|         this._notebook.selectIndex(0); | ||||
|         this._keyPressEventId = global.stage.connect('key-press-event', | ||||
|             Lang.bind(this, this._globalKeyPressEvent)); | ||||
|  | ||||
|         this.actor.show(); | ||||
|         this.actor.lower(Main.chrome.actor); | ||||
|         this._open = true; | ||||
|         this._history.lastItem(); | ||||
|  | ||||
|         Tweener.removeTweens(this.actor); | ||||
|  | ||||
|         global.stage.set_key_focus(this._entry); | ||||
|  | ||||
|         // We inverse compensate for the slow-down so you can change the factor | ||||
|         // through LookingGlass without long waits. | ||||
|         Tweener.addTween(this.actor, { time: 0.5 / St.get_slow_down_factor(), | ||||
| @@ -995,8 +951,12 @@ LookingGlass.prototype = { | ||||
|         if (!this._open) | ||||
|             return; | ||||
|  | ||||
|         if (this._keyPressEventId) | ||||
|             global.stage.disconnect(this._keyPressEventId); | ||||
|  | ||||
|         this._objInspector.actor.hide(); | ||||
|  | ||||
|         this._historyNavIndex = -1; | ||||
|         this._open = false; | ||||
|         Tweener.removeTweens(this.actor); | ||||
|  | ||||
| @@ -1006,7 +966,7 @@ LookingGlass.prototype = { | ||||
|             this._borderPaintTarget = null; | ||||
|         } | ||||
|  | ||||
|         Main.popModal(this._entry); | ||||
|         Main.popModal(this.actor); | ||||
|  | ||||
|         Tweener.addTween(this.actor, { time: 0.5 / St.get_slow_down_factor(), | ||||
|                                        transition: 'easeOutQuad', | ||||
|   | ||||
| @@ -112,11 +112,6 @@ ShellMagnifier.prototype = { | ||||
|      *                  [left, top, right, bottom]. | ||||
|      * @viewPort        Array of integers, [left, top, right, bottom] that defines | ||||
|      *                  the position of the ZoomRegion on screen. | ||||
|      * | ||||
|      * FIXME: The arguments here are redundant, since the width and height of | ||||
|      *   the ROI are determined by the viewport and magnification factors. | ||||
|      *   We ignore the passed in width and height. | ||||
|      * | ||||
|      * @return          The newly created ZoomRegion. | ||||
|      */ | ||||
|     createZoomRegion: function(xMagFactor, yMagFactor, roi, viewPort) { | ||||
|   | ||||
							
								
								
									
										696
									
								
								js/ui/main.js
									
									
									
									
									
								
							
							
						
						| @@ -1,5 +1,11 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| imports.gi.versions.Clutter = '1.0'; | ||||
| imports.gi.versions.Gio = '2.0'; | ||||
| imports.gi.versions.Gdk = '3.0'; | ||||
| imports.gi.versions.GdkPixbuf = '2.0'; | ||||
| imports.gi.versions.Gtk = '3.0'; | ||||
|  | ||||
| const Clutter = imports.gi.Clutter; | ||||
| const DBus = imports.dbus; | ||||
| const Gdk = imports.gi.Gdk; | ||||
| @@ -12,22 +18,15 @@ const Meta = imports.gi.Meta; | ||||
| const Shell = imports.gi.Shell; | ||||
| const St = imports.gi.St; | ||||
|  | ||||
| const AutomountManager = imports.ui.automountManager; | ||||
| const AutorunManager = imports.ui.autorunManager; | ||||
| const CtrlAltTab = imports.ui.ctrlAltTab; | ||||
| const EndSessionDialog = imports.ui.endSessionDialog; | ||||
| const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent; | ||||
| const Chrome = imports.ui.chrome; | ||||
| const Environment = imports.ui.environment; | ||||
| const ExtensionSystem = imports.ui.extensionSystem; | ||||
| const Keyboard = imports.ui.keyboard; | ||||
| const MessageTray = imports.ui.messageTray; | ||||
| const Overview = imports.ui.overview; | ||||
| const Panel = imports.ui.panel; | ||||
| const PlaceDisplay = imports.ui.placeDisplay; | ||||
| const RunDialog = imports.ui.runDialog; | ||||
| const Layout = imports.ui.layout; | ||||
| const LookingGlass = imports.ui.lookingGlass; | ||||
| const NetworkAgent = imports.ui.networkAgent; | ||||
| const NotificationDaemon = imports.ui.notificationDaemon; | ||||
| const WindowAttentionHandler = imports.ui.windowAttentionHandler; | ||||
| const Scripting = imports.ui.scripting; | ||||
| @@ -35,17 +34,13 @@ const ShellDBus = imports.ui.shellDBus; | ||||
| const TelepathyClient = imports.ui.telepathyClient; | ||||
| const WindowManager = imports.ui.windowManager; | ||||
| const Magnifier = imports.ui.magnifier; | ||||
| const XdndHandler = imports.ui.xdndHandler; | ||||
| const StatusIconDispatcher = imports.ui.statusIconDispatcher; | ||||
| const Util = imports.misc.util; | ||||
|  | ||||
| const DEFAULT_BACKGROUND_COLOR = new Clutter.Color(); | ||||
| DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff); | ||||
|  | ||||
| let automountManager = null; | ||||
| let autorunManager = null; | ||||
| let chrome = null; | ||||
| let panel = null; | ||||
| let hotCorners = []; | ||||
| let placesManager = null; | ||||
| let overview = null; | ||||
| let runDialog = null; | ||||
| @@ -55,115 +50,33 @@ let messageTray = null; | ||||
| let notificationDaemon = null; | ||||
| let windowAttentionHandler = null; | ||||
| let telepathyClient = null; | ||||
| let ctrlAltTabManager = null; | ||||
| let recorder = null; | ||||
| let shellDBusService = null; | ||||
| let modalCount = 0; | ||||
| let modalActorFocusStack = []; | ||||
| let uiGroup = null; | ||||
| let magnifier = null; | ||||
| let xdndHandler = null; | ||||
| let statusIconDispatcher = null; | ||||
| let keyboard = null; | ||||
| let layoutManager = null; | ||||
| let networkAgent = null; | ||||
| let _errorLogStack = []; | ||||
| let _startDate; | ||||
| let _defaultCssStylesheet = null; | ||||
| let _cssStylesheet = null; | ||||
| let _gdmCssStylesheet = null; | ||||
|  | ||||
| let background = null; | ||||
|  | ||||
| function _createUserSession() { | ||||
|     // Load the calendar server. Note that we are careful about | ||||
|     // not loading any events until the user presses the clock | ||||
|     global.launch_calendar_server(); | ||||
|  | ||||
|     placesManager = new PlaceDisplay.PlacesManager(); | ||||
|     telepathyClient = new TelepathyClient.Client(); | ||||
|     automountManager = new AutomountManager.AutomountManager(); | ||||
|     autorunManager = new AutorunManager.AutorunManager(); | ||||
|     networkAgent = new NetworkAgent.NetworkAgent(); | ||||
| } | ||||
|  | ||||
| function _createGDMSession() { | ||||
|     // We do this this here instead of at the top to prevent GDM | ||||
|     // related code from getting loaded in normal user sessions | ||||
|     const LoginDialog = imports.gdm.loginDialog; | ||||
|  | ||||
|     let loginDialog = new LoginDialog.LoginDialog(); | ||||
|     loginDialog.connect('loaded', function() { | ||||
|                             loginDialog.open(); | ||||
|                         }); | ||||
| } | ||||
|  | ||||
| function _initRecorder() { | ||||
|     let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' }); | ||||
|  | ||||
|     global.screen.connect('toggle-recording', function() { | ||||
|         if (recorder == null) { | ||||
|             recorder = new Shell.Recorder({ stage: global.stage }); | ||||
|         } | ||||
|  | ||||
|         if (recorder.is_recording()) { | ||||
|             recorder.pause(); | ||||
|             Meta.enable_unredirect_for_screen(global.screen); | ||||
|         } else { | ||||
|             // read the parameters from GSettings always in case they have changed | ||||
|             recorder.set_framerate(recorderSettings.get_int('framerate')); | ||||
|             recorder.set_filename('shell-%d%u-%c.' + recorderSettings.get_string('file-extension')); | ||||
|             let pipeline = recorderSettings.get_string('pipeline'); | ||||
|  | ||||
|             if (!pipeline.match(/^\s*$/)) | ||||
|                 recorder.set_pipeline(pipeline); | ||||
|             else | ||||
|                 recorder.set_pipeline(null); | ||||
|  | ||||
|             Meta.disable_unredirect_for_screen(global.screen); | ||||
|             recorder.record(); | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function _initUserSession() { | ||||
|     _initRecorder(); | ||||
|  | ||||
|     keyboard.init(); | ||||
|  | ||||
|     global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT, false, -1, 1); | ||||
|  | ||||
|     ExtensionSystem.init(); | ||||
|     ExtensionSystem.loadExtensions(); | ||||
|  | ||||
|     let shellwm = global.window_manager; | ||||
|  | ||||
|     shellwm.takeover_keybinding('panel_run_dialog'); | ||||
|     shellwm.connect('keybinding::panel_run_dialog', function () { | ||||
|        getRunDialog().open(); | ||||
|     }); | ||||
|  | ||||
|     shellwm.takeover_keybinding('panel_main_menu'); | ||||
|     shellwm.connect('keybinding::panel_main_menu', function () { | ||||
|         overview.toggle(); | ||||
|     }); | ||||
|  | ||||
|     global.display.connect('overlay-key', Lang.bind(overview, overview.toggle)); | ||||
|  | ||||
| } | ||||
|  | ||||
| function start() { | ||||
|     // Monkey patch utility functions into the global proxy; | ||||
|     // Add a binding for 'global' in the global JS namespace; (gjs | ||||
|     // keeps the web browser convention of having that namespace be | ||||
|     // called 'window'.) | ||||
|     window.global = Shell.Global.get(); | ||||
|  | ||||
|     // Now monkey patch utility functions into the global proxy; | ||||
|     // This is easier and faster than indirecting down into global | ||||
|     // if we want to call back up into JS. | ||||
|     global.logError = _logError; | ||||
|     global.log = _logDebug; | ||||
|  | ||||
|     // Chain up async errors reported from C | ||||
|     global.connect('notify-error', function (global, msg, detail) { notifyError(msg, detail); }); | ||||
|  | ||||
|     Gio.DesktopAppInfo.set_desktop_env('GNOME'); | ||||
|  | ||||
|     global.grab_dbus_service(); | ||||
|     shellDBusService = new ShellDBus.GnomeShell(); | ||||
|     // Force a connection now; dbus.js will do this internally | ||||
|     // if we use its name acquisition stuff but we aren't right | ||||
| @@ -171,6 +84,8 @@ function start() { | ||||
|     // back into sync ones. | ||||
|     DBus.session.flush(); | ||||
|  | ||||
|     Environment.init(); | ||||
|  | ||||
|     // Ensure ShellWindowTracker and ShellAppUsage are initialized; this will | ||||
|     // also initialize ShellAppSystem first.  ShellAppSystem | ||||
|     // needs to load all the .desktop files, and ShellWindowTracker | ||||
| @@ -188,319 +103,91 @@ function start() { | ||||
|     global.stage.color = DEFAULT_BACKGROUND_COLOR; | ||||
|     global.stage.no_clear_hint = true; | ||||
|  | ||||
|     _defaultCssStylesheet = global.datadir + '/theme/gnome-shell.css'; | ||||
|     _gdmCssStylesheet = global.datadir + '/theme/gdm.css'; | ||||
|     loadTheme(); | ||||
|     let themeContext = St.ThemeContext.get_for_stage (global.stage); | ||||
|     let stylesheetPath = global.datadir + '/theme/gnome-shell.css'; | ||||
|     let theme = new St.Theme ({ application_stylesheet: stylesheetPath }); | ||||
|     themeContext.set_theme (theme); | ||||
|  | ||||
|     let shellwm = global.window_manager; | ||||
|     shellwm.takeover_keybinding('panel_main_menu'); | ||||
|     shellwm.connect('keybinding::panel_main_menu', function () { | ||||
|         overview.toggle(); | ||||
|     }); | ||||
|     shellwm.takeover_keybinding('panel_run_dialog'); | ||||
|     shellwm.connect('keybinding::panel_run_dialog', function () { | ||||
|        getRunDialog().open(); | ||||
|     }); | ||||
|  | ||||
|     // Set up stage hierarchy to group all UI actors under one container. | ||||
|     uiGroup = new Shell.GenericContainer({ name: 'uiGroup' }); | ||||
|     uiGroup.connect('allocate', | ||||
|                     function (actor, box, flags) { | ||||
|                         let children = uiGroup.get_children(); | ||||
|                         for (let i = 0; i < children.length; i++) | ||||
|                             children[i].allocate_preferred_size(flags); | ||||
|                     }); | ||||
|     St.set_ui_root(global.stage, uiGroup); | ||||
|     uiGroup = new Clutter.Group(); | ||||
|     global.window_group.reparent(uiGroup); | ||||
|     global.overlay_group.reparent(uiGroup); | ||||
|     global.stage.add_actor(uiGroup); | ||||
|  | ||||
|     layoutManager = new Layout.LayoutManager(); | ||||
|     xdndHandler = new XdndHandler.XdndHandler(); | ||||
|     ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager(); | ||||
|     // This overview object is just a stub for non-user sessions | ||||
|     overview = new Overview.Overview({ isDummy: global.session_type != Shell.SessionType.USER }); | ||||
|     placesManager = new PlaceDisplay.PlacesManager(); | ||||
|     overview = new Overview.Overview(); | ||||
|     chrome = new Chrome.Chrome(); | ||||
|     magnifier = new Magnifier.Magnifier(); | ||||
|     statusIconDispatcher = new StatusIconDispatcher.StatusIconDispatcher(); | ||||
|     panel = new Panel.Panel(); | ||||
|     wm = new WindowManager.WindowManager(); | ||||
|     messageTray = new MessageTray.MessageTray(); | ||||
|     keyboard = new Keyboard.Keyboard(); | ||||
|     notificationDaemon = new NotificationDaemon.NotificationDaemon(); | ||||
|     windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler(); | ||||
|  | ||||
|     if (global.session_type == Shell.SessionType.USER) | ||||
|         _createUserSession(); | ||||
|     else if (global.session_type == Shell.SessionType.GDM) | ||||
|         _createGDMSession(); | ||||
|  | ||||
|     panel.startStatusArea(); | ||||
|  | ||||
|     layoutManager.init(); | ||||
|     keyboard.init(); | ||||
|     overview.init(); | ||||
|  | ||||
|     if (global.session_type == Shell.SessionType.USER) | ||||
|         _initUserSession(); | ||||
|     statusIconDispatcher.start(messageTray.actor); | ||||
|  | ||||
|     // Provide the bus object for gnome-session to | ||||
|     // initiate logouts. | ||||
|     EndSessionDialog.init(); | ||||
|  | ||||
|     // Attempt to become a PolicyKit authentication agent | ||||
|     PolkitAuthenticationAgent.init() | ||||
|     telepathyClient = new TelepathyClient.Client(); | ||||
|  | ||||
|     _startDate = new Date(); | ||||
|  | ||||
|     let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' }); | ||||
|  | ||||
|     global.screen.connect('toggle-recording', function() { | ||||
|         if (recorder == null) { | ||||
|             recorder = new Shell.Recorder({ stage: global.stage }); | ||||
|         } | ||||
|  | ||||
|         if (recorder.is_recording()) { | ||||
|             recorder.pause(); | ||||
|         } else { | ||||
|             // read the parameters from GSettings always in case they have changed | ||||
|             recorder.set_framerate(recorderSettings.get_int('framerate')); | ||||
|             recorder.set_filename('shell-%d%u-%c.' + recorderSettings.get_string('file-extension')); | ||||
|             let pipeline = recorderSettings.get_string('pipeline'); | ||||
|  | ||||
|             if (!pipeline.match(/^\s*$/)) | ||||
|                 recorder.set_pipeline(pipeline); | ||||
|             else | ||||
|                 recorder.set_pipeline(null); | ||||
|  | ||||
|             recorder.record(); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     global.gdk_screen.connect('monitors-changed', _relayout); | ||||
|  | ||||
|     ExtensionSystem.init(); | ||||
|     ExtensionSystem.loadExtensions(); | ||||
|  | ||||
|     panel.startupAnimation(); | ||||
|  | ||||
|     let display = global.screen.get_display(); | ||||
|     display.connect('overlay-key', Lang.bind(overview, overview.toggle)); | ||||
|  | ||||
|     global.stage.connect('captured-event', _globalKeyPressHandler); | ||||
|  | ||||
|     // Perform initial relayout here | ||||
|     _relayout(); | ||||
|  | ||||
|     _log('info', 'loaded at ' + _startDate); | ||||
|     log('GNOME Shell started at ' + _startDate); | ||||
|  | ||||
|     Mainloop.idle_add(_removeUnusedWorkspaces); | ||||
|  | ||||
|     let perfModuleName = GLib.getenv("SHELL_PERF_MODULE"); | ||||
|     if (perfModuleName) { | ||||
|         let perfOutput = GLib.getenv("SHELL_PERF_OUTPUT"); | ||||
|         let module = eval('imports.perf.' + perfModuleName + ';'); | ||||
|         Scripting.runPerfScript(module, perfOutput); | ||||
|     } | ||||
|  | ||||
|     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(); | ||||
| } | ||||
|  | ||||
| let _workspaces = []; | ||||
| let _checkWorkspacesId = 0; | ||||
|  | ||||
| /* | ||||
|  * When the last window closed on a workspace is a dialog or splash | ||||
|  * screen, we assume that it might be an initial window shown before | ||||
|  * the main window of an application, and give the app a grace period | ||||
|  * where it can map another window before we remove the workspace. | ||||
|  */ | ||||
| const LAST_WINDOW_GRACE_TIME = 1000; | ||||
|  | ||||
| function _checkWorkspaces() { | ||||
|     let i; | ||||
|     let emptyWorkspaces = []; | ||||
|  | ||||
|     for (i = 0; i < _workspaces.length; i++) { | ||||
|         let lastRemoved = _workspaces[i]._lastRemovedWindow; | ||||
|         if (lastRemoved && | ||||
|             (lastRemoved.get_window_type() == Meta.WindowType.SPLASHSCREEN || | ||||
|              lastRemoved.get_window_type() == Meta.WindowType.DIALOG || | ||||
|              lastRemoved.get_window_type() == Meta.WindowType.MODAL_DIALOG)) | ||||
|                 emptyWorkspaces[i] = false; | ||||
|         else | ||||
|             emptyWorkspaces[i] = true; | ||||
|     } | ||||
|  | ||||
|     let windows = global.get_window_actors(); | ||||
|     for (i = 0; i < windows.length; i++) { | ||||
|         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 _windowRemoved(workspace, window) { | ||||
|     workspace._lastRemovedWindow = window; | ||||
|     _queueCheckWorkspaces(); | ||||
|     Mainloop.timeout_add(LAST_WINDOW_GRACE_TIME, function() { | ||||
|         if (workspace._lastRemovedWindow == window) { | ||||
|             workspace._lastRemovedWindow = null; | ||||
|             _queueCheckWorkspaces(); | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function _windowLeftMonitor(metaScreen, monitorIndex, metaWin) { | ||||
|     // If the window left the primary monitor, that | ||||
|     // might make that workspace empty | ||||
|     if (monitorIndex == layoutManager.primaryIndex) | ||||
|         _queueCheckWorkspaces(); | ||||
| } | ||||
|  | ||||
| function _windowEnteredMonitor(metaScreen, monitorIndex, metaWin) { | ||||
|     // If the window entered the primary monitor, that | ||||
|     // might make that workspace non-empty | ||||
|     if (monitorIndex == layoutManager.primaryIndex) | ||||
|         _queueCheckWorkspaces(); | ||||
| } | ||||
|  | ||||
| function _windowsRestacked() { | ||||
|     // Figure out where the pointer is in case we lost track of | ||||
|     // it during a grab. (In particular, if a trayicon popup menu | ||||
|     // is dismissed, see if we need to close the message tray.) | ||||
|     global.sync_pointer(); | ||||
| } | ||||
|  | ||||
| function _queueCheckWorkspaces() { | ||||
|     if (_checkWorkspacesId == 0) | ||||
|         _checkWorkspacesId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, _checkWorkspaces); | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * getThemeStylesheet: | ||||
|  * | ||||
|  * Get the theme CSS file that the shell will load | ||||
|  * | ||||
|  * Returns: A file path that contains the theme CSS, | ||||
|  *          null if using the default | ||||
|  */ | ||||
| function getThemeStylesheet() | ||||
| { | ||||
|     return _cssStylesheet; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * setThemeStylesheet: | ||||
|  * @cssStylesheet: A file path that contains the theme CSS, | ||||
|  *                  set it to null to use the default | ||||
|  * | ||||
|  * Set the theme CSS file that the shell will load | ||||
|  */ | ||||
| function setThemeStylesheet(cssStylesheet) | ||||
| { | ||||
|     _cssStylesheet = cssStylesheet; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * loadTheme: | ||||
|  * | ||||
|  * Reloads the theme CSS file | ||||
|  */ | ||||
| function loadTheme() { | ||||
|     let themeContext = St.ThemeContext.get_for_stage (global.stage); | ||||
|     let previousTheme = themeContext.get_theme(); | ||||
|  | ||||
|     let cssStylesheet = _defaultCssStylesheet; | ||||
|     if (_cssStylesheet != null) | ||||
|         cssStylesheet = _cssStylesheet; | ||||
|  | ||||
|     let theme = new St.Theme ({ application_stylesheet: cssStylesheet }); | ||||
|  | ||||
|     if (global.session_type == Shell.SessionType.GDM) | ||||
|         theme.load_stylesheet(_gdmCssStylesheet); | ||||
|  | ||||
|     if (previousTheme) { | ||||
|         let customStylesheets = previousTheme.get_custom_stylesheets(); | ||||
|  | ||||
|         for (let i = 0; i < customStylesheets.length; i++) | ||||
|             theme.load_stylesheet(customStylesheets[i]); | ||||
|     } | ||||
|  | ||||
|     themeContext.set_theme (theme); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * notify: | ||||
|  * @msg: A message | ||||
|  * @details: Additional information | ||||
|  */ | ||||
| function notify(msg, details) { | ||||
|     let source = new MessageTray.SystemNotificationSource(); | ||||
|     messageTray.add(source); | ||||
|     let notification = new MessageTray.Notification(source, msg, details); | ||||
|     notification.setTransient(true); | ||||
|     source.notify(notification); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * notifyError: | ||||
|  * @msg: An error message | ||||
|  * @details: Additional information | ||||
|  * | ||||
|  * See shell_global_notify_problem(). | ||||
|  */ | ||||
| function notifyError(msg, details) { | ||||
|     // Also print to stderr so it's logged somewhere | ||||
|     if (details) | ||||
|         log("error: " + msg + ": " + details); | ||||
|     else | ||||
|         log("error: " + msg) | ||||
|  | ||||
|     notify(msg, details); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -544,27 +231,46 @@ function _getAndClearErrorStack() { | ||||
|     return errors; | ||||
| } | ||||
|  | ||||
| function logStackTrace(msg) { | ||||
|     try { | ||||
|         throw new Error(); | ||||
|     } catch (e) { | ||||
|         // e.stack must have at least two lines, with the first being | ||||
|         // logStackTrace() (which we strip off), and the second being | ||||
|         // our caller. | ||||
|         let trace = e.stack.substr(e.stack.indexOf('\n') + 1); | ||||
|         log(msg ? (msg + '\n' + trace) : trace); | ||||
| function _relayout() { | ||||
|     let primary = global.get_primary_monitor(); | ||||
|     panel.actor.set_position(primary.x, primary.y); | ||||
|     panel.actor.set_size(primary.width, Panel.PANEL_HEIGHT); | ||||
|     overview.relayout(); | ||||
|  | ||||
|     // To avoid updating the position and size of the workspaces | ||||
|     // in the overview, we just hide the overview. The positions | ||||
|     // will be updated when it is next shown. We do the same for | ||||
|     // the calendar popdown. | ||||
|     overview.hide(); | ||||
|     panel.hideCalendar(); | ||||
| } | ||||
|  | ||||
| // metacity-clutter currently uses the same prefs as plain metacity, | ||||
| // which probably means we'll be starting out with multiple workspaces; | ||||
| // remove any unused ones. (We do this from an idle handler, because | ||||
| // global.get_window_actors() still returns NULL at the point when start() | ||||
| // is called.) | ||||
| function _removeUnusedWorkspaces() { | ||||
|  | ||||
|     let windows = global.get_window_actors(); | ||||
|     let maxWorkspace = 0; | ||||
|     for (let i = 0; i < windows.length; i++) { | ||||
|         let win = windows[i]; | ||||
|  | ||||
|         if (!win.get_meta_window().is_on_all_workspaces() && | ||||
|             win.get_workspace() > maxWorkspace) { | ||||
|             maxWorkspace = win.get_workspace(); | ||||
|         } | ||||
|     } | ||||
|     let screen = global.screen; | ||||
|     if (screen.n_workspaces > maxWorkspace) { | ||||
|         for (let w = screen.n_workspaces - 1; w > maxWorkspace; w--) { | ||||
|             let workspace = screen.get_workspace_by_index(w); | ||||
|             screen.remove_workspace(workspace, 0); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| function isWindowActorDisplayedOnWorkspace(win, workspaceIndex) { | ||||
|     return win.get_workspace() == workspaceIndex || | ||||
|         (win.get_meta_window() && win.get_meta_window().is_on_all_workspaces()); | ||||
| } | ||||
|  | ||||
| function getWindowActorsForWorkspace(workspaceIndex) { | ||||
|     return global.get_window_actors().filter(function (win) { | ||||
|         return isWindowActorDisplayedOnWorkspace(win, workspaceIndex); | ||||
|     }); | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| // This function encapsulates hacks to make certain global keybindings | ||||
| @@ -572,72 +278,57 @@ function getWindowActorsForWorkspace(workspaceIndex) { | ||||
| // are disabled with a global grab. (When there is a global grab, then | ||||
| // all key events will be delivered to the stage, so ::captured-event | ||||
| // on the stage can be used for global keybindings.) | ||||
| // | ||||
| // We expect to need to conditionally enable just a few keybindings | ||||
| // depending on circumstance; the main hackiness here is that we are | ||||
| // assuming that keybindings have their default values; really we | ||||
| // should be asking Mutter to resolve the key into an action and then | ||||
| // base our handling based on the action. | ||||
| function _globalKeyPressHandler(actor, event) { | ||||
|     if (modalCount == 0) | ||||
|         return false; | ||||
|     if (event.type() != Clutter.EventType.KEY_PRESS) | ||||
|     if (event.type() != Clutter.EventType.KEY_RELEASE) | ||||
|         return false; | ||||
|  | ||||
|     let symbol = event.get_key_symbol(); | ||||
|     let keyCode = event.get_key_code(); | ||||
|     let modifierState = Shell.get_event_state(event); | ||||
|     // Check the overview key first, this isn't a Meta.KeyBindingAction yet | ||||
|     if (symbol == Clutter.Super_L || symbol == Clutter.Super_R) { | ||||
|         // The super key is the default for triggering the overview, and should | ||||
|         // get us out of the overview when we are already in it. | ||||
|         if (overview.visible) | ||||
|             overview.hide(); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     // Whitelist some of the Metacity actions | ||||
|     let display = global.screen.get_display(); | ||||
|     let activeWorkspaceIndex = global.screen.get_active_workspace_index(); | ||||
|  | ||||
|     // This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType | ||||
|     let action = global.display.get_keybinding_action(keyCode, modifierState); | ||||
|  | ||||
|     // The screenshot action should always be available (even if a | ||||
|     // modal dialog is present) | ||||
|     if (action == Meta.KeyBindingAction.COMMAND_SCREENSHOT) { | ||||
|         let gconf = GConf.Client.get_default(); | ||||
|         let command = gconf.get_string('/apps/metacity/keybinding_commands/command_screenshot'); | ||||
|         if (command != null && command != '') | ||||
|             Util.spawnCommandLine(command); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     // Other bindings are only available when the overview is up and | ||||
|     // no modal dialog is present. | ||||
|     if (!overview.visible || modalCount > 1) | ||||
|         return false; | ||||
|  | ||||
|     // This isn't a Meta.KeyBindingAction yet | ||||
|     if (symbol == Clutter.Super_L || symbol == Clutter.Super_R) { | ||||
|         overview.hide(); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     if (action == Meta.KeyBindingAction.SWITCH_PANELS) { | ||||
|         ctrlAltTabManager.popup(modifierState & Clutter.ModifierType.SHIFT_MASK); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     // None of the other bindings are relevant outside of the user's session | ||||
|     if (global.session_type != Shell.SessionType.USER) | ||||
|         return false; | ||||
|  | ||||
|     let action = display.get_keybinding_action(keyCode, modifierState); | ||||
|     switch (action) { | ||||
|         // left/right would effectively act as synonyms for up/down if we enabled them; | ||||
|         // but that could be considered confusing; we also disable them in the main view. | ||||
|         // | ||||
|         // case Meta.KeyBindingAction.WORKSPACE_LEFT: | ||||
|         //     wm.actionMoveWorkspaceLeft(); | ||||
|         //     return true; | ||||
|         // case Meta.KeyBindingAction.WORKSPACE_RIGHT: | ||||
|         //     wm.actionMoveWorkspaceRight(); | ||||
|         //     return true; | ||||
|         case Meta.KeyBindingAction.WORKSPACE_UP: | ||||
|             wm.actionMoveWorkspaceUp(); | ||||
|         case Meta.KeyBindingAction.COMMAND_SCREENSHOT: | ||||
|             let gconf = GConf.Client.get_default(); | ||||
|             let command = gconf.get_string('/apps/metacity/keybinding_commands/command_screenshot'); | ||||
|             if (command != null && command != '') { | ||||
|                 let [ok, len, args] = GLib.shell_parse_argv(command); | ||||
|                 let p = new Shell.Process({'args' : args}); | ||||
|                 p.run(); | ||||
|             } | ||||
|             return true; | ||||
|         case Meta.KeyBindingAction.WORKSPACE_DOWN: | ||||
|             wm.actionMoveWorkspaceDown(); | ||||
|         case Meta.KeyBindingAction.WORKSPACE_LEFT: | ||||
|             wm.actionMoveWorkspaceLeft(); | ||||
|             return true; | ||||
|         case Meta.KeyBindingAction.WORKSPACE_RIGHT: | ||||
|             wm.actionMoveWorkspaceRight(); | ||||
|             return true; | ||||
|         case Meta.KeyBindingAction.PANEL_RUN_DIALOG: | ||||
|         case Meta.KeyBindingAction.COMMAND_2: | ||||
|             getRunDialog().open(); | ||||
|             return true; | ||||
|         case Meta.KeyBindingAction.PANEL_MAIN_MENU: | ||||
|             overview.hide(); | ||||
|             return true; | ||||
|     } | ||||
|  | ||||
|     return false; | ||||
| @@ -645,8 +336,10 @@ function _globalKeyPressHandler(actor, event) { | ||||
|  | ||||
| function _findModal(actor) { | ||||
|     for (let i = 0; i < modalActorFocusStack.length; i++) { | ||||
|         if (modalActorFocusStack[i].actor == actor) | ||||
|         let [stackActor, stackFocus] = modalActorFocusStack[i]; | ||||
|         if (stackActor == actor) { | ||||
|             return i; | ||||
|         } | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
| @@ -654,29 +347,21 @@ function _findModal(actor) { | ||||
| /** | ||||
|  * pushModal: | ||||
|  * @actor: #ClutterActor which will be given keyboard focus | ||||
|  * @timestamp: optional timestamp | ||||
|  * | ||||
|  * Ensure we are in a mode where all keyboard and mouse input goes to | ||||
|  * the stage, and focus @actor. Multiple calls to this function act in | ||||
|  * a stacking fashion; the effect will be undone when an equal number | ||||
|  * of popModal() invocations have been made. | ||||
|  * the stage.  Multiple calls to this function act in a stacking fashion; | ||||
|  * the effect will be undone when an equal number of popModal() invocations | ||||
|  * have been made. | ||||
|  * | ||||
|  * Next, record the current Clutter keyboard focus on a stack. If the | ||||
|  * modal stack returns to this actor, reset the focus to the actor | ||||
|  * which was focused at the time pushModal() was invoked. | ||||
|  * | ||||
|  * @timestamp is optionally used to associate the call with a specific user | ||||
|  * initiated event.  If not provided then the value of | ||||
|  * global.get_current_time() is assumed. | ||||
|  * Next, record the current Clutter keyboard focus on a stack.  If the modal stack | ||||
|  * returns to this actor, reset the focus to the actor which was focused | ||||
|  * at the time pushModal() was invoked. | ||||
|  * | ||||
|  * Returns: true iff we successfully acquired a grab or already had one | ||||
|  */ | ||||
| function pushModal(actor, timestamp) { | ||||
|     if (timestamp == undefined) | ||||
|         timestamp = global.get_current_time(); | ||||
|  | ||||
| function pushModal(actor) { | ||||
|     if (modalCount == 0) { | ||||
|         if (!global.begin_modal(timestamp)) { | ||||
|         if (!global.begin_modal(global.get_current_time())) { | ||||
|             log('pushModal: invocation of begin_modal failed'); | ||||
|             return false; | ||||
|         } | ||||
| @@ -685,86 +370,59 @@ function pushModal(actor, timestamp) { | ||||
|     global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN); | ||||
|  | ||||
|     modalCount += 1; | ||||
|     let actorDestroyId = actor.connect('destroy', function() { | ||||
|     actor.connect('destroy', function() { | ||||
|         let index = _findModal(actor); | ||||
|         if (index >= 0) | ||||
|             modalActorFocusStack.splice(index, 1); | ||||
|     }); | ||||
|     let curFocus = global.stage.get_key_focus(); | ||||
|     let curFocusDestroyId; | ||||
|     if (curFocus != null) { | ||||
|         curFocusDestroyId = curFocus.connect('destroy', function() { | ||||
|         curFocus.connect('destroy', function() { | ||||
|             let index = _findModal(actor); | ||||
|             if (index >= 0) | ||||
|                 modalActorFocusStack[index].actor = null; | ||||
|                 modalActorFocusStack[index][1] = null; | ||||
|         }); | ||||
|     } | ||||
|     modalActorFocusStack.push({ actor: actor, | ||||
|                                 focus: curFocus, | ||||
|                                 destroyId: actorDestroyId, | ||||
|                                 focusDestroyId: curFocusDestroyId }); | ||||
|     modalActorFocusStack.push([actor, curFocus]); | ||||
|  | ||||
|     global.stage.set_key_focus(actor); | ||||
|     global.stage.set_key_focus(null); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * popModal: | ||||
|  * @actor: #ClutterActor passed to original invocation of pushModal(). | ||||
|  * @timestamp: optional timestamp | ||||
|  * | ||||
|  * Reverse the effect of pushModal().  If this invocation is undoing | ||||
|  * the topmost invocation, then the focus will be restored to the | ||||
|  * previous focus at the time when pushModal() was invoked. | ||||
|  * | ||||
|  * @timestamp is optionally used to associate the call with a specific user | ||||
|  * initiated event.  If not provided then the value of | ||||
|  * global.get_current_time() is assumed. | ||||
|  */ | ||||
| function popModal(actor, timestamp) { | ||||
|     if (timestamp == undefined) | ||||
|         timestamp = global.get_current_time(); | ||||
|  | ||||
|     let focusIndex = _findModal(actor); | ||||
|     if (focusIndex < 0) { | ||||
|         global.stage.set_key_focus(null); | ||||
|         global.end_modal(timestamp); | ||||
|         global.set_stage_input_mode(Shell.StageInputMode.NORMAL); | ||||
|  | ||||
|         throw new Error('incorrect pop'); | ||||
|     } | ||||
|  | ||||
| function popModal(actor) { | ||||
|     modalCount -= 1; | ||||
|  | ||||
|     let record = modalActorFocusStack[focusIndex]; | ||||
|     record.actor.disconnect(record.destroyId); | ||||
|  | ||||
|     if (focusIndex == modalActorFocusStack.length - 1) { | ||||
|         if (record.focus) | ||||
|             record.focus.disconnect(record.focusDestroyId); | ||||
|         global.stage.set_key_focus(record.focus); | ||||
|     } else { | ||||
|         let t = modalActorFocusStack[modalActorFocusStack.length - 1]; | ||||
|         if (t.focus) | ||||
|             t.focus.disconnect(t.focusDestroyId); | ||||
|         // Remove from the middle, shift the focus chain up | ||||
|         for (let i = modalActorFocusStack.length - 1; i > focusIndex; i--) { | ||||
|             modalActorFocusStack[i].focus = modalActorFocusStack[i - 1].focus; | ||||
|             modalActorFocusStack[i].focusDestroyId = modalActorFocusStack[i - 1].focusDestroyId; | ||||
|     let focusIndex = _findModal(actor); | ||||
|     if (focusIndex >= 0) { | ||||
|         if (focusIndex == modalActorFocusStack.length - 1) { | ||||
|             let [stackActor, stackFocus] = modalActorFocusStack[focusIndex]; | ||||
|             global.stage.set_key_focus(stackFocus); | ||||
|         } else { | ||||
|             // Remove from the middle, shift the focus chain up | ||||
|             for (let i = focusIndex; i < modalActorFocusStack.length - 1; i++) { | ||||
|                 modalActorFocusStack[i + 1][1] = modalActorFocusStack[i][1]; | ||||
|             } | ||||
|         } | ||||
|         modalActorFocusStack.splice(focusIndex, 1); | ||||
|     } | ||||
|     modalActorFocusStack.splice(focusIndex, 1); | ||||
|  | ||||
|     if (modalCount > 0) | ||||
|         return; | ||||
|  | ||||
|     global.end_modal(timestamp); | ||||
|     global.end_modal(global.get_current_time()); | ||||
|     global.set_stage_input_mode(Shell.StageInputMode.NORMAL); | ||||
| } | ||||
|  | ||||
| function createLookingGlass() { | ||||
|     if (lookingGlass == null) { | ||||
|         lookingGlass = new LookingGlass.LookingGlass(); | ||||
|         lookingGlass.slaveTo(panel.actor); | ||||
|     } | ||||
|     return lookingGlass; | ||||
| } | ||||
|   | ||||
							
								
								
									
										1765
									
								
								js/ui/messageTray.js
									
									
									
									
									
								
							
							
						
						| @@ -1,307 +0,0 @@ | ||||
| /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ | ||||
|  | ||||
| const Clutter = imports.gi.Clutter; | ||||
| const Gdk = imports.gi.Gdk; | ||||
| const Gio = imports.gi.Gio; | ||||
| const GLib = imports.gi.GLib; | ||||
| const Lang = imports.lang; | ||||
| const Meta = imports.gi.Meta; | ||||
| const Pango = imports.gi.Pango; | ||||
| const St = imports.gi.St; | ||||
| const Shell = imports.gi.Shell; | ||||
| const Signals = imports.signals; | ||||
|  | ||||
| const Params = imports.misc.params; | ||||
|  | ||||
| const Lightbox = imports.ui.lightbox; | ||||
| const Main = imports.ui.main; | ||||
| const Tweener = imports.ui.tweener; | ||||
|  | ||||
| const OPEN_AND_CLOSE_TIME = 0.1; | ||||
| const FADE_IN_BUTTONS_TIME = 0.33; | ||||
| const FADE_OUT_DIALOG_TIME = 1.0; | ||||
|  | ||||
| const State = { | ||||
|     OPENED: 0, | ||||
|     CLOSED: 1, | ||||
|     OPENING: 2, | ||||
|     CLOSING: 3, | ||||
|     FADED_OUT: 4 | ||||
| }; | ||||
|  | ||||
| function ModalDialog() { | ||||
|     this._init(); | ||||
| } | ||||
|  | ||||
| ModalDialog.prototype = { | ||||
|     _init: function(params) { | ||||
|         params = Params.parse(params, { shellReactive: false, | ||||
|                                         styleClass: null }); | ||||
|  | ||||
|         this.state = State.CLOSED; | ||||
|         this._hasModal = false; | ||||
|         this._shellReactive = params.shellReactive; | ||||
|  | ||||
|         this._group = new St.Group({ visible: false, | ||||
|                                      x: 0, | ||||
|                                      y: 0 }); | ||||
|         Main.uiGroup.add_actor(this._group); | ||||
|  | ||||
|         let constraint = new Clutter.BindConstraint({ source: global.stage, | ||||
|                                                       coordinate: Clutter.BindCoordinate.POSITION | Clutter.BindCoordinate.SIZE }); | ||||
|         this._group.add_constraint(constraint); | ||||
|  | ||||
|         this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy)); | ||||
|  | ||||
|         this._actionKeys = {}; | ||||
|         this._group.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent)); | ||||
|  | ||||
|         this._backgroundBin = new St.Bin(); | ||||
|         this._group.add_actor(this._backgroundBin); | ||||
|  | ||||
|         this._dialogLayout = new St.BoxLayout({ style_class: 'modal-dialog', | ||||
|                                                 vertical:    true }); | ||||
|         if (params.styleClass != null) { | ||||
|             this._dialogLayout.add_style_class_name(params.styleClass); | ||||
|         } | ||||
|  | ||||
|         if (!this._shellReactive) { | ||||
|             this._lightbox = new Lightbox.Lightbox(this._group, | ||||
|                                                    { inhibitEvents: true }); | ||||
|             this._lightbox.highlight(this._backgroundBin); | ||||
|  | ||||
|             let stack = new Shell.Stack(); | ||||
|             this._backgroundBin.child = stack; | ||||
|  | ||||
|             this._eventBlocker = new Clutter.Group({ reactive: true }); | ||||
|             stack.add_actor(this._eventBlocker); | ||||
|             stack.add_actor(this._dialogLayout); | ||||
|         } else { | ||||
|             this._backgroundBin.child = this._dialogLayout; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         this.contentLayout = new St.BoxLayout({ vertical: true }); | ||||
|         this._dialogLayout.add(this.contentLayout, | ||||
|                                { x_fill:  true, | ||||
|                                  y_fill:  true, | ||||
|                                  x_align: St.Align.MIDDLE, | ||||
|                                  y_align: St.Align.START }); | ||||
|  | ||||
|         this._buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box', | ||||
|                                                 vertical:    false }); | ||||
|         this._dialogLayout.add(this._buttonLayout, | ||||
|                                { expand:  true, | ||||
|                                  x_align: St.Align.MIDDLE, | ||||
|                                  y_align: St.Align.END }); | ||||
|  | ||||
|         global.focus_manager.add_group(this._dialogLayout); | ||||
|         this._initialKeyFocus = this._dialogLayout; | ||||
|         this._savedKeyFocus = null; | ||||
|     }, | ||||
|  | ||||
|     destroy: function() { | ||||
|         this._group.destroy(); | ||||
|     }, | ||||
|  | ||||
|     setButtons: function(buttons) { | ||||
|         let hadChildren = this._buttonLayout.get_children() > 0; | ||||
|  | ||||
|         this._buttonLayout.destroy_children(); | ||||
|         this._actionKeys = {}; | ||||
|  | ||||
|         let i = 0; | ||||
|         for (let index in buttons) { | ||||
|             let buttonInfo = buttons[index]; | ||||
|             let label = buttonInfo['label']; | ||||
|             let action = buttonInfo['action']; | ||||
|             let key = buttonInfo['key']; | ||||
|  | ||||
|             buttonInfo.button = new St.Button({ style_class: 'modal-dialog-button', | ||||
|                                                 reactive:    true, | ||||
|                                                 can_focus:   true, | ||||
|                                                 label:       label }); | ||||
|  | ||||
|             let x_alignment; | ||||
|             if (buttons.length == 1) | ||||
|                 x_alignment = St.Align.END; | ||||
|             else if (i == 0) | ||||
|                 x_alignment = St.Align.START; | ||||
|             else if (i == buttons.length - 1) | ||||
|                 x_alignment = St.Align.END; | ||||
|             else | ||||
|                 x_alignment = St.Align.MIDDLE; | ||||
|  | ||||
|             this._initialKeyFocus = buttonInfo.button; | ||||
|             this._buttonLayout.add(buttonInfo.button, | ||||
|                                    { expand: true, | ||||
|                                      x_fill: false, | ||||
|                                      y_fill: false, | ||||
|                                      x_align: x_alignment, | ||||
|                                      y_align: St.Align.MIDDLE }); | ||||
|  | ||||
|             buttonInfo.button.connect('clicked', action); | ||||
|  | ||||
|             if (key) | ||||
|                 this._actionKeys[key] = action; | ||||
|             i++; | ||||
|         } | ||||
|  | ||||
|         // Fade in buttons if there weren't any before | ||||
|         if (!hadChildren && i > 0) { | ||||
|             this._buttonLayout.opacity = 0; | ||||
|             Tweener.addTween(this._buttonLayout, | ||||
|                              { opacity: 255, | ||||
|                                time: FADE_IN_BUTTONS_TIME, | ||||
|                                transition: 'easeOutQuad', | ||||
|                                onComplete: Lang.bind(this, function() { | ||||
|                                    this.emit('buttons-set'); | ||||
|                                }) | ||||
|                              }); | ||||
|         } else { | ||||
|             this.emit('buttons-set'); | ||||
|         } | ||||
|  | ||||
|     }, | ||||
|  | ||||
|     _onKeyPressEvent: function(object, keyPressEvent) { | ||||
|         let symbol = keyPressEvent.get_key_symbol(); | ||||
|         let action = this._actionKeys[symbol]; | ||||
|  | ||||
|         if (action) | ||||
|             action(); | ||||
|     }, | ||||
|  | ||||
|     _onGroupDestroy: function() { | ||||
|         this.emit('destroy'); | ||||
|     }, | ||||
|  | ||||
|     _fadeOpen: function() { | ||||
|         let monitor = Main.layoutManager.focusMonitor; | ||||
|  | ||||
|         this._backgroundBin.set_position(monitor.x, monitor.y); | ||||
|         this._backgroundBin.set_size(monitor.width, monitor.height); | ||||
|  | ||||
|         this.state = State.OPENING; | ||||
|  | ||||
|         this._dialogLayout.opacity = 255; | ||||
|         if (this._lightbox) | ||||
|             this._lightbox.show(); | ||||
|         this._group.opacity = 0; | ||||
|         this._group.show(); | ||||
|         Tweener.addTween(this._group, | ||||
|                          { opacity: 255, | ||||
|                            time: OPEN_AND_CLOSE_TIME, | ||||
|                            transition: 'easeOutQuad', | ||||
|                            onComplete: Lang.bind(this, | ||||
|                                function() { | ||||
|                                    this.state = State.OPENED; | ||||
|                                    this.emit('opened'); | ||||
|                                }) | ||||
|                          }); | ||||
|     }, | ||||
|  | ||||
|     setInitialKeyFocus: function(actor) { | ||||
|         this._initialKeyFocus = actor; | ||||
|     }, | ||||
|  | ||||
|     open: function(timestamp) { | ||||
|         if (this.state == State.OPENED || this.state == State.OPENING) | ||||
|             return true; | ||||
|  | ||||
|         if (!this.pushModal(timestamp)) | ||||
|             return false; | ||||
|  | ||||
|         this._fadeOpen(); | ||||
|         return true; | ||||
|     }, | ||||
|  | ||||
|     close: function(timestamp) { | ||||
|         if (this.state == State.CLOSED || this.state == State.CLOSING) | ||||
|             return; | ||||
|  | ||||
|         this.state = State.CLOSING; | ||||
|         this.popModal(timestamp); | ||||
|         this._savedKeyFocus = null; | ||||
|  | ||||
|         Tweener.addTween(this._group, | ||||
|                          { opacity: 0, | ||||
|                            time: OPEN_AND_CLOSE_TIME, | ||||
|                            transition: 'easeOutQuad', | ||||
|                            onComplete: Lang.bind(this, | ||||
|                                function() { | ||||
|                                    this.state = State.CLOSED; | ||||
|                                    this._group.hide(); | ||||
|                                }) | ||||
|                          }); | ||||
|     }, | ||||
|  | ||||
|     // Drop modal status without closing the dialog; this makes the | ||||
|     // dialog insensitive as well, so it needs to be followed shortly | ||||
|     // by either a close() or a pushModal() | ||||
|     popModal: function(timestamp) { | ||||
|         if (!this._hasModal) | ||||
|             return; | ||||
|  | ||||
|         let focus = global.stage.key_focus; | ||||
|         if (focus && this._group.contains(focus)) | ||||
|             this._savedKeyFocus = focus; | ||||
|         else | ||||
|             this._savedKeyFocus = null; | ||||
|         Main.popModal(this._group, timestamp); | ||||
|         global.gdk_screen.get_display().sync(); | ||||
|         this._hasModal = false; | ||||
|  | ||||
|         if (!this._shellReactive) | ||||
|             this._eventBlocker.raise_top(); | ||||
|     }, | ||||
|  | ||||
|     pushModal: function (timestamp) { | ||||
|         if (this._hasModal) | ||||
|             return true; | ||||
|         if (!Main.pushModal(this._group, timestamp)) | ||||
|             return false; | ||||
|  | ||||
|         this._hasModal = true; | ||||
|         if (this._savedKeyFocus) { | ||||
|             this._savedKeyFocus.grab_key_focus(); | ||||
|             this._savedKeyFocus = null; | ||||
|         } else | ||||
|             this._initialKeyFocus.grab_key_focus(); | ||||
|  | ||||
|         if (!this._shellReactive) | ||||
|             this._eventBlocker.lower_bottom(); | ||||
|         return true; | ||||
|     }, | ||||
|  | ||||
|     // This method is like close, but fades the dialog out much slower, | ||||
|     // and leaves the lightbox in place. Once in the faded out state, | ||||
|     // the dialog can be brought back by an open call, or the lightbox | ||||
|     // can be dismissed by a close call. | ||||
|     // | ||||
|     // The main point of this method is to give some indication to the user | ||||
|     // that the dialog reponse has been acknowledged but will take a few | ||||
|     // moments before being processed. | ||||
|     // e.g., if a user clicked "Log Out" then the dialog should go away | ||||
|     // imediately, but the lightbox should remain until the logout is | ||||
|     // complete. | ||||
|     _fadeOutDialog: function(timestamp) { | ||||
|         if (this.state == State.CLOSED || this.state == State.CLOSING) | ||||
|             return; | ||||
|  | ||||
|         if (this.state == State.FADED_OUT) | ||||
|             return; | ||||
|  | ||||
|         this.popModal(timestamp); | ||||
|         Tweener.addTween(this._dialogLayout, | ||||
|                          { opacity: 0, | ||||
|                            time:    FADE_OUT_DIALOG_TIME, | ||||
|                            transition: 'easeOutQuad', | ||||
|                            onComplete: Lang.bind(this, | ||||
|                                function() { | ||||
|                                    this.state = State.FADED_OUT; | ||||
|                                }) | ||||
|                          }); | ||||
|     } | ||||
| }; | ||||
| Signals.addSignalMethods(ModalDialog.prototype); | ||||