Compare commits
3 Commits
screen-shi
...
wip/gdbus
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
986afdc0c5 | ||
|
|
e6dc843786 | ||
|
|
9eb671bb08 |
9
.gitignore
vendored
@@ -18,13 +18,9 @@ config
|
|||||||
configure
|
configure
|
||||||
data/gnome-shell.desktop
|
data/gnome-shell.desktop
|
||||||
data/gnome-shell.desktop.in
|
data/gnome-shell.desktop.in
|
||||||
data/gnome-shell-extension-prefs.desktop
|
|
||||||
data/gnome-shell-extension-prefs.desktop.in
|
|
||||||
data/gschemas.compiled
|
data/gschemas.compiled
|
||||||
data/org.gnome.shell.gschema.xml
|
data/org.gnome.shell.gschema.xml
|
||||||
data/org.gnome.shell.gschema.valid
|
data/org.gnome.shell.gschema.valid
|
||||||
data/org.gnome.shell.evolution.calendar.gschema.xml
|
|
||||||
data/org.gnome.shell.evolution.calendar.gschema.valid
|
|
||||||
docs/reference/*/*.args
|
docs/reference/*/*.args
|
||||||
docs/reference/*/*.bak
|
docs/reference/*/*.bak
|
||||||
docs/reference/*/*.hierarchy
|
docs/reference/*/*.hierarchy
|
||||||
@@ -50,7 +46,6 @@ po/gnome-shell.pot
|
|||||||
po/*.header
|
po/*.header
|
||||||
po/*.sed
|
po/*.sed
|
||||||
po/*.sin
|
po/*.sin
|
||||||
po/.intltool-merge-cache
|
|
||||||
po/Makefile.in.in
|
po/Makefile.in.in
|
||||||
po/Makevars.template
|
po/Makevars.template
|
||||||
po/POTFILES
|
po/POTFILES
|
||||||
@@ -63,17 +58,13 @@ src/*-enum-types.[ch]
|
|||||||
src/*-marshal.[ch]
|
src/*-marshal.[ch]
|
||||||
src/Makefile
|
src/Makefile
|
||||||
src/Makefile.in
|
src/Makefile.in
|
||||||
src/calendar-server/evolution-calendar.desktop
|
|
||||||
src/calendar-server/evolution-calendar.desktop.in
|
|
||||||
src/calendar-server/org.gnome.Shell.CalendarServer.service
|
src/calendar-server/org.gnome.Shell.CalendarServer.service
|
||||||
src/gnome-shell
|
src/gnome-shell
|
||||||
src/gnome-shell-calendar-server
|
src/gnome-shell-calendar-server
|
||||||
src/gnome-shell-extension-tool
|
src/gnome-shell-extension-tool
|
||||||
src/gnome-shell-extension-prefs
|
|
||||||
src/gnome-shell-hotplug-sniffer
|
src/gnome-shell-hotplug-sniffer
|
||||||
src/gnome-shell-jhbuild
|
src/gnome-shell-jhbuild
|
||||||
src/gnome-shell-perf-helper
|
src/gnome-shell-perf-helper
|
||||||
src/gnome-shell-perf-tool
|
|
||||||
src/gnome-shell-real
|
src/gnome-shell-real
|
||||||
src/hotplug-sniffer/org.gnome.Shell.HotplugSniffer.service
|
src/hotplug-sniffer/org.gnome.Shell.HotplugSniffer.service
|
||||||
src/run-js-test
|
src/run-js-test
|
||||||
|
|||||||
545
NEWS
@@ -1,546 +1,3 @@
|
|||||||
3.5.4
|
|
||||||
=====
|
|
||||||
* Fix wrong result handling of remote calls [Florian; #678852]
|
|
||||||
* dateMenu: Fix regression that caused no date to be displayed [Colin]
|
|
||||||
* WindowTracker: Fix refcounting bug in get_app_for_window() [Giovanni; #678992]
|
|
||||||
* Show the workspace switcher for move-to-workspace keybinding
|
|
||||||
[Giovanni, Jasper; #674104, #660839, #679005]
|
|
||||||
* userMenu: Move "Power off" item to the bottom [Florian; #678887]
|
|
||||||
* Remove contacts search provider [Florian, Rui; #677442]
|
|
||||||
* network: don't ask for always-ask secrets when interaction isn't allowed
|
|
||||||
[Dan; #679091]
|
|
||||||
* PolkitAgent: Look for the right password prompt [Matthias; #675300]
|
|
||||||
* Implement extension updates [Jasper; #679099]
|
|
||||||
* userMenu: Don't disconnect account signals when disabled [Guillaume; #669112]
|
|
||||||
* Fix startup notification when opening calendar [Florian; #677907]
|
|
||||||
* networkAgent: use absolute path if configured [Clemens; #679212]
|
|
||||||
* recorder: Port to GStreamer-1.0 API [Florian; #679445]
|
|
||||||
* telepathyClient: don't add log messages on presence changes [Ana; #669508]
|
|
||||||
* lookingGlass: Don't use a signal callback on 'paint' to draw the border
|
|
||||||
[Jasper; #679464]
|
|
||||||
* Add support for inhibiting automount [Hans; #678597]
|
|
||||||
* Implemented banner support for the login screen [Matthias, Marius; #665346]
|
|
||||||
* boxpointer: Flip side if we would end outside the monitor [Rui; #678164]
|
|
||||||
* boxpointer: Change 'animate' parameter on show/hide to a bitmask
|
|
||||||
[Rui; #678337]
|
|
||||||
* Add a grayscale effect [Matthias, Jasper, Florian: #676782, #674499]
|
|
||||||
* UserMenu: show "Install Updates & Restart" when appropriate
|
|
||||||
[Giovanni; #677394, #680080]
|
|
||||||
* messageTray: don't show the message tray when a new notification is shown
|
|
||||||
[Ana; #677210]
|
|
||||||
* panel: don't break when indicator has no menu [Jean-Philippe; #678694]
|
|
||||||
* appMenu: Disable app menu during startup animations [Florian; #672322]
|
|
||||||
* autorun: Add a notification when unmounting drives [Cosimo; #676125]
|
|
||||||
* st-icon: Fix potential crash involving shadows [Jasper; #679776]
|
|
||||||
* Remove manual garbage collection on tweeners end [Cosimo; #679832]
|
|
||||||
* dash: hide tooltips when overview begins hiding [Stefano; #674241]
|
|
||||||
* Update modal dialog animation for new centered position [Florian; #674499]
|
|
||||||
* calendar: Fix grid lines in RTL locales [Florian; #679879]
|
|
||||||
* Integrate IBus with keyboard indicator [Rui; #641531]
|
|
||||||
* Move ibus status icon under keyboard [Matthias]
|
|
||||||
* gdm: port from libgdmgreeter to libgdm [Ray; #676401]
|
|
||||||
* Misc bug fixes and cleanups [Antoine, Cosimo, Giovanni, Jasper, Rico;
|
|
||||||
#678978, #672790, #679847, #679944]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Jean-Philippe Braun, Clemens Buchacher, Giovanni Campagna, Cosimo Cecchi,
|
|
||||||
Matthias Clasen, Hans de Goede, Guillaume Desmottes, Stefano Facchini,
|
|
||||||
Antoine Jacoutot, Rui Matos, Florian Müllner, Marius Rieder, Ana Risteska,
|
|
||||||
Jasper St. Pierre, Rico Tzschichholz, Colin Walters, Dan Williams
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
Matej Urbančič [sl], Khaled Hosny [ar], Nguyễn Thái Ngọc Duy [vi],
|
|
||||||
Nilamdyuti Goswami [as], Alexander Shopov [bg], Ivaylo Valkov [bg],
|
|
||||||
Daniel Mustieles [es], Kjartan Maraas [nb,nn], Yaron Shahrabani [he],
|
|
||||||
Nilamdyuti Goswami [as], Chao-Hsiung Liao [zh_HK, zh_TW], Ihar Hrachyshka [be],
|
|
||||||
Praveen Illa [te]
|
|
||||||
|
|
||||||
3.5.3
|
|
||||||
=====
|
|
||||||
* calendar: Adapt to Evolution-Data-Server API changes [Matthew; #677402]
|
|
||||||
* messageTray: Don't show non urgent notifications while in fullscreen
|
|
||||||
[Adel; #677590]
|
|
||||||
* modalDialog: show dialogs on monitor with the mouse pointer [Tim; #642591]
|
|
||||||
* extensionSystem: Prepare for extension updating system [Jasper; #677586]
|
|
||||||
* appDisplay: Don't show apps in NoDisplay categories in the All view
|
|
||||||
[Jasper; #658176]
|
|
||||||
* st: Trigger theme updates on resolution changes [Florian; #677975]
|
|
||||||
* Always enable a11y [Bastien; #678095]
|
|
||||||
* telepathyClient: ignore invalidated channels [Guillaume; #677457]
|
|
||||||
* shell-app: Update app menu if necessary [Florian; #676238]
|
|
||||||
* Enable the Screen Reader menu item [Matthias; #663256]
|
|
||||||
* Disable unredirection when a modal operation is active [Giovanni]
|
|
||||||
* Make folks optional [Colin]
|
|
||||||
* Improve mount-operation support [Cosimo]
|
|
||||||
- Fix exception when showing password entry [#678428]
|
|
||||||
- Close the password entry on operation abort [#673787]
|
|
||||||
- autorun: Don't allow autorun for things we mount on startup [#660595]
|
|
||||||
- Turn passphrase prompt into a dialog [#674962]
|
|
||||||
- Implement org.Gtk.MountOperationHandler [#678516]
|
|
||||||
* Network menu improvements
|
|
||||||
- Sort Wifi networks by strength [Giovanni; #658946]
|
|
||||||
- Prefer wifi/3g over VPN in the panel [Cosimo; #672591]
|
|
||||||
* clock: Switch to using GnomeWallClock [Colin; #657074]
|
|
||||||
* remoteSearch: Allow to reference .desktop file for Title/Icon
|
|
||||||
[Florian; #678816]
|
|
||||||
* Fix memory leaks [Jasper, Pavel; #678079, #678406, #678737]
|
|
||||||
* Misc fixes [Florian, Giovanni, Guillaume, Jasper, Kjartan, Piotr, Rui;
|
|
||||||
#658955, #677497, #678396, #678502]
|
|
||||||
* Misc cleanups [Bastien, Florian, Jasper; #677426, #677515, #678096, #678416]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Matthew Barnes, Giovanni Campagna, Cosimo Cecchi, Matthias Clasen,
|
|
||||||
Guillaume Desmottes, Piotr Drąg, Adel Gadllah, Tim L, Kjartan Maraas,
|
|
||||||
Rui Matos, Florian Müllner, Bastien Nocera, Jasper St. Pierre, Colin Walters
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
Matej Urbančič [sl], Yuri Kozlov [ru], Tom Tryfonidis [el],
|
|
||||||
Kjartan Maraas [nb], Žygimantas Beručka [lt], Luca Ferretti [it],
|
|
||||||
Khaled Hosny [ar], Daniel Mustieles [es], Fran Diéguez [gl], A S Alam [pa]
|
|
||||||
|
|
||||||
3.5.2
|
|
||||||
=====
|
|
||||||
* main: Move 'toggle-recording' binding into the shell [Florian; #674377]
|
|
||||||
* popupMenu: make sure to break the grab when the slider is not visible
|
|
||||||
[Stefano; #672713]
|
|
||||||
* st-theme-node-drawing: Don't use GL types [Neil; #672711]
|
|
||||||
* Mirror Evolution calendar settings into our own schema [Owen; #674424]
|
|
||||||
* shell-network-agent: don't crash if a request isn't found [Dan; #674961]
|
|
||||||
* notificationDaemon: Match app based on WM_CLASS [Jasper; #673761]
|
|
||||||
* NetworkMenu: use network-offline while loading [Giovanni; #674426]
|
|
||||||
* lookingGlass: Remove the Errors tab [Jasper; #675104]
|
|
||||||
* searchDisplay: Reset keyboard focus after displaying async results
|
|
||||||
[Rui; #675078]
|
|
||||||
* gdm: don't fail if fprintd is unavailable [Ray; #675006]
|
|
||||||
* messageTray: Fix scrolling up [Jasper; #661615]
|
|
||||||
* main: Close the recorder instead of pausing it [Rui; #675128]
|
|
||||||
* Accessibility [Alejandro]
|
|
||||||
- Use the proper label_actor for date menu on top panel [#675307]
|
|
||||||
- Set the proper role/label_actor for SearchResult.content [#672242]
|
|
||||||
- do not expose a label text if 'hidden' style class is used [#675341]
|
|
||||||
* Magnifier: Add brightness and contrast functionality [Joseph; #639851]
|
|
||||||
* theme: use a smaller border-radius for top bar [Jakub; #672430]
|
|
||||||
* placeDisplay: use new bookmark file location [Matthias; #675443]
|
|
||||||
* port all synchronous search providers to the async API [Jasper, Rui; #675328]
|
|
||||||
* NetworkAgent: disallow multiple requests for the same connection/setting
|
|
||||||
[Giovanni; #674961]
|
|
||||||
* userMenu: Update to latest mockups [Florian; #675802]
|
|
||||||
* util: Don't double-fork when spawning from Alt-F2 [Colin; #675789]
|
|
||||||
* messageTray: Make Source usable without subclassing [Jasper; #661236]
|
|
||||||
* panel: Check for appMenu button's reactivity before opening [Florian; #676316]
|
|
||||||
* Fix formatting of bluetooth passkey [Florian; #651251]
|
|
||||||
* notificationDaemon: Filter out file-transfer notifications [Jasper; #676175]
|
|
||||||
* Don't use global.log() [Jasper; #675790]
|
|
||||||
* Fix broken extension loading in some distributions [Owen, Alexandre; #670477]
|
|
||||||
* shell-app: Raise windows in reverse order to preserve the stacking
|
|
||||||
[Rui; #676371]
|
|
||||||
* Generalize gdm-mode [Florian; #676156]
|
|
||||||
* Switch string formatting to the one inside gjs [Jasper; #675479]
|
|
||||||
* extensionUtils: Support subdirectories in getCurrentExtension
|
|
||||||
[Jasper; #677001]
|
|
||||||
* panel: Refuse to add (legacy) status icons not part of the session mode
|
|
||||||
[Florian; #677058]
|
|
||||||
* Add an initial-setup mode [Matthias; #676697]
|
|
||||||
* status/keyboard: Port to the new input sources settings [Rui; #641531]
|
|
||||||
* NetworkMenu: show notifications for failed VPN connections [Giovanni; #676330]
|
|
||||||
* userMenu: Indicate progress on status changes [Florian; #659067]
|
|
||||||
* recorder: Honor "disable-save-to-disk" lockdown key [Rūdolfs; #673630]
|
|
||||||
* searchDisplay: Use the rowLimit we pass to the IconGrid [Christian; #675527]
|
|
||||||
* endSessionDialog: Factor out _updateDescription from _updateContent
|
|
||||||
[Alejandro; #674210]
|
|
||||||
* Fix empathy's appMenu freezing the shell [Alban; #676447]
|
|
||||||
* Code cleanups [Florian, Giovanni, Jasper; #672807, #672413, #676837, #676850,
|
|
||||||
#672272]
|
|
||||||
* Misc bug fixes [Alban, Florian, Giovanni, Guillaume, Jasper, Piotr, Rico,
|
|
||||||
Ron, Rui, Stefano; #659968, #672192, #673177, #673198, #674323, #675301,
|
|
||||||
#675370, #676347, #676806, #677097]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Alban Browaeys, Giovanni Campagna, Matthias Clasen, Guillaume Desmottes,
|
|
||||||
Piotr Drąg, Stefano Facchini, Rui Matos, Rūdolfs Mazurs, Florian Müllner,
|
|
||||||
Alejandro Piñeiro, Neil Roberts, Alexandre Rostovtsev, Joseph Scheuhammer,
|
|
||||||
Jakub Steiner, Jasper St. Pierre, Ray Strode, Owen Taylor, Rico Tzschichholz,
|
|
||||||
Colin Walters, Dan Winship, Ron Yorston
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
OKANO Takayoshi [ja], Daniel Mustieles [es], Changwoo Ryu [ko],
|
|
||||||
Yaron Shahrabani [he], Fran Diéguez [gl], Jonh Wendell [pt_BR],
|
|
||||||
Kjartan Maraas [nb], Luca Ferretti [it], Tom Tryfonidis [el],
|
|
||||||
Sandeep Sheshrao Shedmake [mr], Takanori MATSUURA [ja], Dirgita [id],
|
|
||||||
Mantas Kriaučiūnas [lt], Matej Urbančič [sl], Jiro Matsuzawa [ja]
|
|
||||||
|
|
||||||
3.4.1
|
|
||||||
=====
|
|
||||||
* Fix crash that occurred when an icon theme change caused unexpected
|
|
||||||
reentrancy in the icon loading code [Jasper; #673512]
|
|
||||||
* Don't show system and other disabled users in the GDM user list
|
|
||||||
[Adel; #673784]
|
|
||||||
* Make gnome-shell-calendar-server initialize GTK+ so it can display
|
|
||||||
password prompts if needed [#673608; Owen, Rico]
|
|
||||||
* Adapt to Mutter API change for keybinding addition [Florian; #673014]
|
|
||||||
* Fix crash when an extension was installed as both a user extension
|
|
||||||
and a system extension [#673613; Jasper]
|
|
||||||
* Fix bug where chat entry could end up partially offscreen [Joost, 661944]
|
|
||||||
* Fix problem where icons weren't updating when theme was changed
|
|
||||||
[#672941; Florian]
|
|
||||||
* Look for Evolution calendar settings in GSettings, not GConf [#673610; Owen]
|
|
||||||
* Add <super>F10 for the application menu [#672909; Florian]
|
|
||||||
* Fix %Id format characters to work in translations [#673106; Cosimo]
|
|
||||||
(were already used in fa translation)
|
|
||||||
* Fix error when NetworkManager restarts [#673043; Giovanni]
|
|
||||||
* Improve efficiency of overview redraws by working around Clutter issue
|
|
||||||
[Stefano; #670636]
|
|
||||||
* Misc bug fixes [Florian, Giovanni, Jasper, Rui, Stefano;
|
|
||||||
#672592, #672641, #672719, #673187, #673233, #673656]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Giovanni Campagna, Cosimo Cecchi, Stefano Facchini, Adel Gadllah, Rui Matos,
|
|
||||||
Florian Müllner, Jasper St. Pierre, Owen Taylor, Rico Tzschichholz,
|
|
||||||
Joost Verdoorn
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
Khaled Hosny [ar], Ihar Hrachyshka [be], Alexander Shopov [bg], Gil Forcada,
|
|
||||||
Jordi Serratosa [ca], Petr Kovar [cs], Bruce Cowan [en_GB],
|
|
||||||
Carles Ferrando [ca@valencia], Wolfgang Stöggl [de], Daniel Mustieles [es],
|
|
||||||
Arash Mousavi [fa], Bruno Brouard [fr], Fran Diéguez [gl],
|
|
||||||
Sweta Kothari [gu], Yaron Shahrabani [he], Gabor Kelemen [hu],
|
|
||||||
Shankar Prasad [kn], Žygimantas Beručka [lt], Rudolfs Mazurs [lv],
|
|
||||||
Sandeep Sheshrao Shedmake [mr], Kjartan Maraas [nb], Piotr Drąg [pl],
|
|
||||||
Yuri Myasoedov [ru], Daniel Nylander [se], Matej Urbančič [sl],
|
|
||||||
Miroslav Nikolić [sr], Sasi Bhushan, Praveen Illa [te], Yinghua Wang [zh_CN]
|
|
||||||
|
|
||||||
3.4.0
|
|
||||||
=====
|
|
||||||
* Don't crash when taking screenshots [Jasper; #672775]
|
|
||||||
* Fix dialog-resizing problem [Florian; #672543]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Florian Müllner, Jasper St. Pierre
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
Khaled Hosny, Abderrahim Kitouni [ar], Ihar Hrachyshka [be],
|
|
||||||
Alexander Shopov [bg], Marek Černocký [cs], Jiri Grönroos, Timo Jyrinki [fi],
|
|
||||||
Bruno Brouard [fr], Fran Diéguez [gl], Yaron Shahrabani [he],
|
|
||||||
Gabor Kelemen [hu], Jiro Matsuzawa [ja], Kenneth Nielsen [dk],
|
|
||||||
Mattias Põldaru [et], Changwoo Ryu [ko], Rudolfs Mazurs [lv],
|
|
||||||
Jonh Wendell [pt_BR], Yuri Myasoedov[ru], Daniel Korostil [uk],
|
|
||||||
Nguyễn Thái Ngọc Duy [vi], Chao-Hsiung Liao [zh_HK, zh_TW]
|
|
||||||
|
|
||||||
3.3.92
|
|
||||||
======
|
|
||||||
* Add shell-dialogs for GNOME Keyring prompts [Stef; #652459, #652460, #671034]
|
|
||||||
* When the user returns from idle, bring up the message tray if there were
|
|
||||||
messages while they were away [Marina; #643014]
|
|
||||||
* https://live.gnome.org/EveryDetailMatters
|
|
||||||
- Make the workspace thumbnails clickable all the way to the edge of the
|
|
||||||
screen [Stefano; #643319]
|
|
||||||
- Don't slide out the workspace thumbnails if the mouse is over them when
|
|
||||||
entering the overview [Joost, #651092]
|
|
||||||
- Fix placeholder jumps while dragging a dash item [Joost; #651842]
|
|
||||||
- Don't favorite apps if they are dropped back at the same position
|
|
||||||
[Jean-Philippe; #656333]
|
|
||||||
- To avoid confusion, don't allow removing running apps from favorites
|
|
||||||
[Florian; #644853]
|
|
||||||
- Fix creation of new workspaces by dragging application launchers
|
|
||||||
[Stefano; #664202]
|
|
||||||
- Make it easier to drag dash items without triggering the menu
|
|
||||||
[Florian; #637103]
|
|
||||||
* Accessibility [Alejandro]
|
|
||||||
- Add StWidget API for easily adding accessible states and setting roles,
|
|
||||||
names [#668366, #667432, #671378]
|
|
||||||
- Set accessibility information on UI elements
|
|
||||||
[#644255, #667432, #668361, #672047, #670308, #670312, #670719, #671404]
|
|
||||||
* Improve key-navigation in the overview [Rui, Florian; #663901]
|
|
||||||
* Key navigation bug fixes [Rui, Florian; #662493, #663437, #665215, #671998]
|
|
||||||
* Honor a 'org.gnome.shell.overrides.dynamic-workspaces' setting that
|
|
||||||
determines whether the workspace count is dynamic and unsaved in GSettings
|
|
||||||
or static and saved. [Florian; #671568]
|
|
||||||
* Avoid saving user presence to GSettings when not necessary
|
|
||||||
[Florian; #665701, #668214]
|
|
||||||
* Save screencasts in the users Videos/ directory [Adel; #670749]
|
|
||||||
Use a "human readable" filename [Florian, Adel, Ray; #670753]
|
|
||||||
* Allow dragging from the empty part of the top panel to unmaximize a window
|
|
||||||
[Florian; #666359]
|
|
||||||
* Fix hangs that could occur when switching away to a VT [Ray; #653833]
|
|
||||||
* Fix problems with installing from extensions.gnome.org [Giovanni; #671134]
|
|
||||||
* Fix locking the screen when suspending via menu [David, Gert; #670820]
|
|
||||||
* Fix browser plugin with Konqueror and Opera [Jasper]
|
|
||||||
* Fix shell restart not to bring up failure screen [Giovanni; #648384]
|
|
||||||
* Reorganize and clean up CSS theming [Allan; #668209]
|
|
||||||
* Improve appearance of modal dialogs [Allan, Florian; #670227, #668209]
|
|
||||||
* Update the calendar code to use ECalClient [Giovanni; #671177]
|
|
||||||
* Update jhbuild script to use the main moduleset [Owen, Will; #668440]
|
|
||||||
* StTextureCache: code cleanup, evict unused icons, merge together
|
|
||||||
simulataneous requests for the same icon [Jasper; #670771, #671656, #672273]
|
|
||||||
* Clean up St for recent Clutter changes and fix bugs. StContainer and
|
|
||||||
StGroup are removed [Jasper, Florian; #670034, #670640, #670904]
|
|
||||||
* Code cleanup [Adel, Jasper, Rui; #613194, #671086, #671103]
|
|
||||||
* Misc bug fixes
|
|
||||||
[Adel, Colin G, Cosimo, Florian, Giovanni, Jasper, Marius, Rui, Stefano;
|
|
||||||
#651130, #658946, #667552, #670076, #671001, #670979, #671410, #671411,
|
|
||||||
#671556, #671656, #671657, #672011, #672024, #672240, #672265, #672270,
|
|
||||||
#672321, #672326, #672413, #672471]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Jean-Philippe Braun, Giovanni Campagna, Cosimo Cecchi, Allan Day,
|
|
||||||
Stefano Facchini, David Foerster, Adel Gadllah, Marius Gedminas,
|
|
||||||
Colin Guthrie, Gert Michael Kulyk, William Lachance, Rui Matos,
|
|
||||||
Florian Müllner, Alejandro Piñeiro, Jan Alexander Steffens,
|
|
||||||
Jasper St. Pierre, Ray Strode, Owen Taylor, Joost Verdoorn, Stef Walter,
|
|
||||||
Marina Zhurakhinskaya
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
Nilamdyuti Goswami [as], Ihar Hrachyshka, Kasia Bondarava [be],
|
|
||||||
Alexander Shopov, Ivaylo Valkov [bg], Gil Forcada [ca], Marek Černocký [cs],
|
|
||||||
Mario Blättermann [de], Kris Thomsen [dk], Bruce Cowan [en_GB],
|
|
||||||
Kristjan Schmidt [eo], Daniel Mustieles [es], Mattias Põldaru [et],
|
|
||||||
Inaki Larranaga Murgoitio [eu], Arash Mousavi [fa], Timo Jyrinki [fi],
|
|
||||||
Bruno Brouard [fr], Fran Diéguez [gl], Sweta Kothari [gu],
|
|
||||||
Yaron Shahrabani [he], Gabor Kelemen [hu], Jiro Matsuzawa [ja],
|
|
||||||
Baurzhan Muftakhidinov [kk], Seong-ho Cho [ko], Žygimantas Beručka [lt],
|
|
||||||
Anita Reitere [lv], Anish A, Praveen Arimbrathodiyil, Mohammed Sadiq [ml],
|
|
||||||
fKjartan Maraas [nb], Wouter Bolsterlee [nl], A S Alam [pa], Piotr Drąg [pl],
|
|
||||||
Duarte Loreto [pt], Jonh Wendell [pt_BR], Yuri Myasoedov [ru],
|
|
||||||
Matej Urbančič [sl], Miroslav Nikolić [sr], Tirumurti Vasudevan [ta],
|
|
||||||
Sasi Bhushan, Krishnababu Krothapalli [te], Daniel Korostil [uk],
|
|
||||||
Nguyễn Thái Ngọc Duy [vi], YunQiang Su, Yinghua Wang [zh_CN],
|
|
||||||
Chao-Hsiung Liao [zh_HK, zh_TW]
|
|
||||||
|
|
||||||
3.3.90
|
|
||||||
======
|
|
||||||
|
|
||||||
* Allow other applications to implement search providers via D-Bus
|
|
||||||
[Florian; #663125, #670148]
|
|
||||||
* Remove "Recent Items" search, as replaced by Documents search
|
|
||||||
[Florian; #663125]
|
|
||||||
* Allow NetworkManager VPN plugins to use a shell-themed dialog
|
|
||||||
[Giovanni; #658484]
|
|
||||||
* Port away from deprecated Clutter API [Jasper, Florian, Adel; #670034]
|
|
||||||
- StTooltip is removed
|
|
||||||
- StWidget is now a concrete class and can be instantiated
|
|
||||||
- st_container_destroy_children(), st_box_layout_insert_actor(),
|
|
||||||
and other functions removed in favor of new replacements in Clutter.
|
|
||||||
* Use systemd for console/session handling when available [Lennart]
|
|
||||||
* Visual improvements to contact search, padding, top panel, checkboxes
|
|
||||||
[Allan, Florian, Jakub; #669489, #669811, #669993]
|
|
||||||
* Add a include_cursor parameter to Screenshot and ScreenshotWindow
|
|
||||||
D-Bus methods [Adel; #670086]
|
|
||||||
* Add a "FlashArea" D-Bus method to do the screenshot flash without a
|
|
||||||
screenshot [Adel; #669660]
|
|
||||||
* Build fixes [Adel, Giovanni, Jasper; #658484, #669637]
|
|
||||||
* Misc bug fixes [Adel, Florian, Giovanni, Guillaume, Jasper, Jeff,
|
|
||||||
Marc-Antoine, Stef, Stefano, Will; #642135, #658484, #658908, #667694,
|
|
||||||
#669098, #669921, #669662, #669694, #669776, #669887, #669921, #670005,
|
|
||||||
#670006, #670319, #670418, #670489]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Giovanni Campagna, Cosimo Cecchi, Allan Day, Guillaume Desmottes, Jeff Epler,
|
|
||||||
Stefano Facchini, Adel Gadllah, Florian Müllner, Marc-Antoine Perennou,
|
|
||||||
Jasper St. Pierre, Lennart Poettering, Jakub Steiner, Jasper St. Pierre,
|
|
||||||
Will Thompson, Stef Walter
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
Ihar Hrachyshka [be], Marek Černocký, Adam Matoušek [cs],
|
|
||||||
Kenneth Nielsen [dk], Daniel Mustieles [es], Mattias Põldaru [et],
|
|
||||||
Fran Diéguez [gl], Yaron Shahrabani [he], Luca Ferretti [it],
|
|
||||||
Baurzhan Muftakhidinov [kk], Aurimas Černius [lt], Kjartan Maraas [nb],
|
|
||||||
A S Alam [pa], Matej Urbančič [sl], Miroslav Nikolić [sr],
|
|
||||||
Praveen Illa [te], Chao-Hsiung Liao [zh_HK, zh_TW]
|
|
||||||
|
|
||||||
3.3.5
|
|
||||||
=====
|
|
||||||
|
|
||||||
* Extension system: [Jasper; #668429]
|
|
||||||
http://blog.mecheye.net/2012/02/more-extension-api-breaks/
|
|
||||||
- Add a 'gnome-shell-extension-prefs' application for displaying extension
|
|
||||||
preferences as provided by the extension in a prefs.js file.
|
|
||||||
- Allow launching gnome-shell-extension-prefs from extensions.gnome.org
|
|
||||||
throuhg the browser plugin.
|
|
||||||
- Add ExtensionUtils.getCurrentExtension() for an extension to get a
|
|
||||||
handle to an extension object, to get local imports or paths.
|
|
||||||
- Add an onshellrestart callback to the browser plugin [Jasper; #668517]
|
|
||||||
* Screenshots:
|
|
||||||
- Move the screenshot "flash" to the shell [Cosimo; #668618]
|
|
||||||
- Move saving screenshots to a thread [Adel; #652952]
|
|
||||||
- Correctly screenshot rounded decorations [Jasper; #662486]
|
|
||||||
* Screen recorder:
|
|
||||||
- Change the default pipeline to favor speed over quality [Owen; #669066]
|
|
||||||
- Drop frames to keep from running the user out of memory [Owen; #669066]
|
|
||||||
* Work around a slow implementation of glReadPixels() in the Intel drivers,
|
|
||||||
improving performance for screenshots and the screen recorder.
|
|
||||||
[Owen; #669065]
|
|
||||||
* Use Keywords: field in desktop files when search for applications
|
|
||||||
[Florian; #609702]
|
|
||||||
* Strip debian- when matching desktop file names [Jasper; #665647]
|
|
||||||
* Fix up various problems from CSS background size-addition
|
|
||||||
[Florian, Jasper; #668430, #633462]
|
|
||||||
* UI tweaks and behavior fixes
|
|
||||||
[Florian, Giovanni, Stefano; #643867, #666197, #664622]
|
|
||||||
* Some improvements to exported accessibility information [Alejando; #667376]
|
|
||||||
* Don't show contacts without IM information as offline [Florian; #662685]
|
|
||||||
* Don't change status from hidden to extended_away when going idle
|
|
||||||
[Florian; #642408]
|
|
||||||
* Cleanups [Emmanuele, Jasper; #662152, #669239]
|
|
||||||
* Misc bug fixes [Cosimo, Dan, Florian, Jasper, Rui, Stefano;
|
|
||||||
#633462, #643867, #662213, #662386, #662747, #665000, #665017, #665322,
|
|
||||||
#667371, #667860, #668020, #668517, #668541, #669236]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Emmanuele Bassi, Giovanni Campagna, Cosimo Cecchi, Stefano Facchini,
|
|
||||||
Adel Gadllah, Rui Matos, Florian Müllner, Alejandro Piñeiro,
|
|
||||||
Jasper St. Pierre, Owen Taylor, Dan Winship
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
Daniel Mustieles [es], Timo Jyrinki [fi], Seán de Búrca [ga],
|
|
||||||
Fran Diéguez [gl], Kjartan Maraas [nb], Wouter Bolsterlee [nl],
|
|
||||||
Danishka Navin [si], Yaron Shahrabani [he], Matej Urbančič [sl],
|
|
||||||
Chao-Hsiung Liao [zh_HK, zh_TW]
|
|
||||||
|
|
||||||
3.3.4
|
|
||||||
=====
|
|
||||||
* https://live.gnome.org/EveryDetailMatters
|
|
||||||
- Add "browse" for labels for dash items - once a tooltip is
|
|
||||||
showing, switch to other items without a delay [Seif; #666170]
|
|
||||||
- Always scale down windows in the overview at least to 70% [Vit; #646704]
|
|
||||||
- Fix the new-workspace drop indicator sometimes getting stuck
|
|
||||||
[Stefano; #664201]
|
|
||||||
- Delay rearranging windows in the overview as long as the pointer
|
|
||||||
is over a window [Vit; #645325]
|
|
||||||
* Add a GConf => DConf migration file for overriden Mutter settings
|
|
||||||
[Florian; #667636]
|
|
||||||
* When a VPN connection is active, show that as the network icon
|
|
||||||
[Giovanni; #665115]
|
|
||||||
* Handle the "ExtendedAway" IM status as away, not offline [Guillaume; #667813]
|
|
||||||
* Improve the appearance of the labels in "Applications" [Alex; #642392]
|
|
||||||
* Adjust for GTK+ and Mutter API changes for application menu [Ryan; #668118]
|
|
||||||
* Add section label support to the application menu [Giovanni; #666681]
|
|
||||||
* Fix screenshot methods to work again [Cosimo; #667662]
|
|
||||||
* Fix several crashers related to updating workspace thumbnails [Owen; #667652]
|
|
||||||
* Fix memory management error causing gnome-shell-hotplug-sniffer to crash
|
|
||||||
[Owen; #667378]
|
|
||||||
* Build fixes [Emmanuele, Rico; #667864]
|
|
||||||
* Code cleanups [Adel; #668087]
|
|
||||||
* Misc bug fixes [Colin, Florian, Giovanni, Owen, Xavier; #633028, #658817,
|
|
||||||
#664138, #667881, #668048, #668050]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Emmanuele Bassi, Giovanni Campagna, Cosimo Cecchi, Xavier Claessens,
|
|
||||||
Guillaume Desmottes, Stefano Facchini, Adel Gadllah, Alex Hultman,
|
|
||||||
Ryan Lortie, Seif Lotfy, Florian Müllner, Vit Stanislav, Owen Taylor,
|
|
||||||
Rico Tzschichholz, Colin Walters
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
Ihar Hrachyshka [be], Alexander Shopov [bg], Arash Mousavi [fa],
|
|
||||||
Jiri Grönroos, Timo Jyrinki [fi], Fran Diéguez [gl], Kjartan Maraas [nb],
|
|
||||||
Yuri Myasoedov [ru], Matej Urbančič [sl], Nguyễn Thái Ngọc Duy [vi]
|
|
||||||
|
|
||||||
3.3.3
|
|
||||||
=====
|
|
||||||
* https://live.gnome.org/EveryDetailMatters
|
|
||||||
- Stop flashing the window labels on actions in overview [Zan; #644861]
|
|
||||||
- Improve the look of window captions in the overview [Marc; #664487]
|
|
||||||
- Move dash tooltips beside the icon [Seif, Stefano; #666166]
|
|
||||||
* Support application menus exported from applications via new GLib API
|
|
||||||
and D-Bus protocol. [Giovanni, Colin, Matthias, Cosimo]
|
|
||||||
* For removable device prompts, show "Open with Rhythmbox], rather
|
|
||||||
than "Open with Rhythmbox Music Player' [Florian; #664561]
|
|
||||||
* Switch to activating the message tray only with a hot corner rather
|
|
||||||
than a full row of pixels, allowing mouse events to apps [Rui; #663366]
|
|
||||||
* Fully handle the case where the workspaces-only-on-primary
|
|
||||||
GSetting is set to false [Florian; #652580]
|
|
||||||
* Add support for background-size CSS property to St [Quentin; #633462]
|
|
||||||
* Port to new GJS Lang.Class framework [Giovanni; #664436]
|
|
||||||
* Finish port to GDBus [Giovanni; #664436]
|
|
||||||
* Stop using the deprecated Clutter default stage [Florian, Jasper; #664052]
|
|
||||||
* Fix bugs that kept browser plugin from working in WebKit-based browser
|
|
||||||
[Jasper; #666444]
|
|
||||||
* Fix typo that made uninstalling extensions not work [Jasper]
|
|
||||||
* Fix crash in browser plugin if shell is not run [Jürg]
|
|
||||||
* Reintroduce piscine paschal ovum [Giovanni; #666606]
|
|
||||||
* Network menu bug fixes
|
|
||||||
Giovanni; #664124, #665194, #665680, #666429, #666614]
|
|
||||||
* Misc bug fixes [Florian, Jasper, Jonny, Marina, Ron; #647587, #659272,
|
|
||||||
#664138, #665261, #666020, #666243]
|
|
||||||
* Build fixes [Owen]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Jürg Billeter, Giovanni Campagna, Stefano Candori, Cosimo Cecchi,
|
|
||||||
Matthias Clasen, Zan Dobersek, Quentin Glidic, Jonny Lamb, Ryan Lortie,
|
|
||||||
Seif Lotfy, Rui Matos, Florian Müllner, Bastien Nocera, Jasper St. Pierre,
|
|
||||||
Marc Plano-Lesay, Owen Taylor, Colin Walters, Ron Yorsten,
|
|
||||||
Marina Zhurakhinskaya
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
Petr Kovar [cs], Kris Thomsen [dk], Daniel Mustieles [es],
|
|
||||||
Ville-Pekka Vainio [fi], Yaron Shahrabani [he], Luca Ferretti [it],
|
|
||||||
Hideki Yamane [ja], Žygimantas Beručka [lt], Jovan Naumovski [mk],
|
|
||||||
Kjartan Maraas [nb], "Andreas N" [nn], Lucian Adrian Grijincu [ro],
|
|
||||||
Matej Urbančič [sl], Praveen Illa [te], Muhammet Kara [tr],
|
|
||||||
Daniel Korostil [uk], Aron Xu [zh_CN]
|
|
||||||
|
|
||||||
3.3.2
|
|
||||||
=====
|
|
||||||
* Port D-Bus usage in the shell to GDBus [Giovanni, Marc-Antoine, Florian,
|
|
||||||
Jasper, Matthias; #648651, #658078, #663902, #663941]
|
|
||||||
* Message tray
|
|
||||||
- Add right-click option to chats to mute the conversation [Ana; #659962]
|
|
||||||
- Don't steal the focus when popping up under the pointer [Rui; #661358]
|
|
||||||
* Looking Glass
|
|
||||||
- Add alt-Tab completion [Jason; #661054]
|
|
||||||
- Show errors from extensions in the extensions tab [Jasper; #660546]
|
|
||||||
- Allow switching tabs with <Control>PageUp/PageDown
|
|
||||||
- Theme consistently with the rest of the shell [Jason; 650900]
|
|
||||||
* Extension system
|
|
||||||
- Don't try to load disabled extensions at all [Jasper; #661815, #662704]
|
|
||||||
- Enable and disable plugins in a consistent order [Jasper; #661815, #662704]
|
|
||||||
- Add options to enable/disable extensions to gnome-shell-extension-tool
|
|
||||||
[Jasper; #661815]
|
|
||||||
* Adapt to Mutter change to GSettings [Florian, Matthias; #663429]
|
|
||||||
* Allow creating a new workspace by dragging a window or launcher in the
|
|
||||||
middle of two existing ones [Jasper; #646409]
|
|
||||||
* Allow using Alt-Tab while during drag-and-drop and other operations
|
|
||||||
that grab the pointer [Adel; #660457]
|
|
||||||
* Do a better job of finding the right user to authenticate
|
|
||||||
as when showing a PolKit dialog [Matthias; #651547]
|
|
||||||
* Control the D-Bus Eval() method by the developer-tools GSetting which
|
|
||||||
is used for looking glass and screen recorder. [Jasper; #662891]
|
|
||||||
* Fix browser plugin to work under WebKit-based browser [Jasper; #663823]
|
|
||||||
* Fix certain stacking issues with alt-Tab [Jasper; #660650]
|
|
||||||
* Fixes for GLib deprecations [Jasper; #662011]p
|
|
||||||
* Fixes for GTK+ deprecations [Florian, Rico; #662245]p
|
|
||||||
* Fixes for Clutter deprecations [Jasper; #662627]
|
|
||||||
* Visual improvements and UI tweaks [Florian, Jakub, Jasper;
|
|
||||||
#662800, #658096, #662226]
|
|
||||||
* Hard-code "Home" as the name for the home dir, rather than looking
|
|
||||||
it up via GSettings; avoids schema dependency [Cosimo; #559895]
|
|
||||||
* Don't show "Switch User" on single user machines [Florian; #657011]
|
|
||||||
* Generate documentation for St toolkit [Florian]
|
|
||||||
* Improve marking of strings for translation [Matthias, Piotr; #658664]
|
|
||||||
* Networking menu bug fixes [Giovanni; #650007, #651378, #659277, #663278]
|
|
||||||
* Code cleanups and leak fixes to StTextureCache
|
|
||||||
[Jasper, Florian; #660968, #662998]
|
|
||||||
* Code cleanups [Adel, Florian, Jasper; #662238, #663584]
|
|
||||||
* Build fixes [Adel, Colin, Florian, Ming Han]
|
|
||||||
* Misc bug fixes [Adel, Florian, "Fry", Jasper, Giovanni, Ray, Rui, Stefan;
|
|
||||||
#660520, #661029, #661231, #661623, #661921, #662235, #662236, #662502,
|
|
||||||
#662394, #662799, #662969, #663175, #663277, #663815, #663891, #662967]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Giovanni Campagna, Cosimo Cecchi, Matthias Clasen, Piotr Drąg, Adel Gadllah,
|
|
||||||
Rui Matos, Florian Müllner, Marc-Antoine Perennou, Ana Risteska,
|
|
||||||
Jason Siefken, Jakub Steiner, Ray Strode, Jasper St. Pierre, Ming Han Teh,
|
|
||||||
Rico Tzschichholz, Colin Walters, Stefan Zwanenburg
|
|
||||||
|
|
||||||
Translation:
|
|
||||||
Alexander Shopov [bg], Marek Černocký [cs], Mario Blättermann [de],
|
|
||||||
Kostas Papadimas [el], Bruce Cowan [en_GB], Kristjan Schmidt [eo],
|
|
||||||
Jorge González, Daniel Mustieles, Benjamín Valero Espinosa [es],
|
|
||||||
Mattias Põldaru [et], Arash Mousavi [fa], Ville-Pekka Vainio [fi],
|
|
||||||
Fran Diéguez [gl], Yaron Shahrabani [he], Hideki Yamane [ja],
|
|
||||||
Algimantas Margevičius [lt], Kjartan Maraas [nb], Daniel Nylander [se],
|
|
||||||
Matej Urbančič [sl], Praveen Illa [te], Muhammet Kara [tr],
|
|
||||||
Nguyễn Thái Ngọc Duy [vi], Cheng-Chia Tseng [zh_HK, zh_TW]
|
|
||||||
|
|
||||||
3.2.1
|
3.2.1
|
||||||
=====
|
=====
|
||||||
* Restore the IM state on startup - if you were available in when you logged
|
* Restore the IM state on startup - if you were available in when you logged
|
||||||
@@ -634,7 +91,7 @@ Contributors:
|
|||||||
Translations:
|
Translations:
|
||||||
Friedel Wolff [af], Nilamdyuti Goswami [as], Ihar Hrachyshka [be],
|
Friedel Wolff [af], Nilamdyuti Goswami [as], Ihar Hrachyshka [be],
|
||||||
Ivaylo Valkov [bg], Gil Forcada [ca], Carles Ferrando [ca@valencia],
|
Ivaylo Valkov [bg], Gil Forcada [ca], Carles Ferrando [ca@valencia],
|
||||||
Petr Kovar [cs], Mario Blättermann [de], Kris Thomsen [dk],
|
Petr Kovar [cz], Mario Blättermann [de], Kris Thomsen [dk],
|
||||||
Tiffany Antopolski, Kristjan Schmidt [eo], Daniel Mustieles [es],
|
Tiffany Antopolski, Kristjan Schmidt [eo], Daniel Mustieles [es],
|
||||||
Inaki Larranaga Murgoitio [eu], Tommi Vainikainen [fi], Bruno Brouard [fr],
|
Inaki Larranaga Murgoitio [eu], Tommi Vainikainen [fi], Bruno Brouard [fr],
|
||||||
Fran Dieguez [gl], Yaron Shahrabani [he], Gabor Kelemen [hu],
|
Fran Dieguez [gl], Yaron Shahrabani [he], Gabor Kelemen [hu],
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
"It can be used only by extensions.gnome.org"
|
"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_MIME_STRING "application/x-gnome-shell-integration::Gnome Shell Integration Dummy Content-Type";
|
||||||
|
|
||||||
#define PLUGIN_API_VERSION 5
|
#define PLUGIN_API_VERSION 1
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
GDBusProxy *proxy;
|
GDBusProxy *proxy;
|
||||||
@@ -104,7 +104,7 @@ check_origin_and_protocol (NPP instance)
|
|||||||
&location))
|
&location))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!NPVARIANT_IS_OBJECT (location))
|
if (!NPVARIANT_IS_OBJECT (document))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
hostname = get_string_property (instance,
|
hostname = get_string_property (instance,
|
||||||
@@ -153,8 +153,6 @@ NP_Initialize(NPNetscapeFuncs *pfuncs, NPPluginFuncs *plugin)
|
|||||||
/* global initialization routine, called once when plugin
|
/* global initialization routine, called once when plugin
|
||||||
is loaded */
|
is loaded */
|
||||||
|
|
||||||
g_type_init ();
|
|
||||||
|
|
||||||
g_debug ("plugin loaded");
|
g_debug ("plugin loaded");
|
||||||
|
|
||||||
memcpy (&funcs, pfuncs, sizeof (funcs));
|
memcpy (&funcs, pfuncs, sizeof (funcs));
|
||||||
@@ -163,7 +161,6 @@ NP_Initialize(NPNetscapeFuncs *pfuncs, NPPluginFuncs *plugin)
|
|||||||
plugin->newp = NPP_New;
|
plugin->newp = NPP_New;
|
||||||
plugin->destroy = NPP_Destroy;
|
plugin->destroy = NPP_Destroy;
|
||||||
plugin->getvalue = NPP_GetValue;
|
plugin->getvalue = NPP_GetValue;
|
||||||
plugin->setwindow = NPP_SetWindow;
|
|
||||||
|
|
||||||
return NPERR_NO_ERROR;
|
return NPERR_NO_ERROR;
|
||||||
}
|
}
|
||||||
@@ -225,7 +222,7 @@ NPP_New(NPMIMEType mimetype,
|
|||||||
NULL, /* interface info */
|
NULL, /* interface info */
|
||||||
"org.gnome.Shell",
|
"org.gnome.Shell",
|
||||||
"/org/gnome/Shell",
|
"/org/gnome/Shell",
|
||||||
"org.gnome.Shell.Extensions",
|
"org.gnome.Shell",
|
||||||
NULL, /* GCancellable */
|
NULL, /* GCancellable */
|
||||||
&error);
|
&error);
|
||||||
if (!data->proxy)
|
if (!data->proxy)
|
||||||
@@ -268,11 +265,8 @@ typedef struct {
|
|||||||
NPObject parent;
|
NPObject parent;
|
||||||
NPP instance;
|
NPP instance;
|
||||||
GDBusProxy *proxy;
|
GDBusProxy *proxy;
|
||||||
GSettings *settings;
|
|
||||||
NPObject *listener;
|
NPObject *listener;
|
||||||
NPObject *restart_listener;
|
|
||||||
gint signal_id;
|
gint signal_id;
|
||||||
guint watch_name_id;
|
|
||||||
} PluginObject;
|
} PluginObject;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -290,7 +284,7 @@ on_shell_signal (GDBusProxy *proxy,
|
|||||||
gint32 status;
|
gint32 status;
|
||||||
gchar *error;
|
gchar *error;
|
||||||
NPVariant args[3];
|
NPVariant args[3];
|
||||||
NPVariant result = { NPVariantType_Void };
|
NPVariant result;
|
||||||
|
|
||||||
g_variant_get (parameters, "(sis)", &uuid, &status, &error);
|
g_variant_get (parameters, "(sis)", &uuid, &status, &error);
|
||||||
STRINGZ_TO_NPVARIANT (uuid, args[0]);
|
STRINGZ_TO_NPVARIANT (uuid, args[0]);
|
||||||
@@ -306,28 +300,6 @@ on_shell_signal (GDBusProxy *proxy,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
on_shell_appeared (GDBusConnection *connection,
|
|
||||||
const gchar *name,
|
|
||||||
const gchar *name_owner,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
PluginObject *obj = (PluginObject*) user_data;
|
|
||||||
|
|
||||||
if (obj->restart_listener)
|
|
||||||
{
|
|
||||||
NPVariant result = { NPVariantType_Void };
|
|
||||||
|
|
||||||
funcs.invokeDefault (obj->instance, obj->restart_listener,
|
|
||||||
NULL, 0, &result);
|
|
||||||
|
|
||||||
funcs.releasevariantvalue (&result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SHELL_SCHEMA "org.gnome.shell"
|
|
||||||
#define ENABLED_EXTENSIONS_KEY "enabled-extensions"
|
|
||||||
|
|
||||||
static NPObject *
|
static NPObject *
|
||||||
plugin_object_allocate (NPP instance,
|
plugin_object_allocate (NPP instance,
|
||||||
NPClass *klass)
|
NPClass *klass)
|
||||||
@@ -337,18 +309,9 @@ plugin_object_allocate (NPP instance,
|
|||||||
|
|
||||||
obj->instance = instance;
|
obj->instance = instance;
|
||||||
obj->proxy = g_object_ref (data->proxy);
|
obj->proxy = g_object_ref (data->proxy);
|
||||||
obj->settings = g_settings_new (SHELL_SCHEMA);
|
|
||||||
obj->signal_id = g_signal_connect (obj->proxy, "g-signal",
|
obj->signal_id = g_signal_connect (obj->proxy, "g-signal",
|
||||||
G_CALLBACK (on_shell_signal), obj);
|
G_CALLBACK (on_shell_signal), obj);
|
||||||
|
|
||||||
obj->watch_name_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
|
||||||
"org.gnome.Shell",
|
|
||||||
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
|
||||||
on_shell_appeared,
|
|
||||||
NULL,
|
|
||||||
obj,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
g_debug ("plugin object created");
|
g_debug ("plugin object created");
|
||||||
|
|
||||||
return (NPObject*)obj;
|
return (NPObject*)obj;
|
||||||
@@ -365,22 +328,41 @@ plugin_object_deallocate (NPObject *npobj)
|
|||||||
if (obj->listener)
|
if (obj->listener)
|
||||||
funcs.releaseobject (obj->listener);
|
funcs.releaseobject (obj->listener);
|
||||||
|
|
||||||
if (obj->watch_name_id)
|
|
||||||
g_bus_unwatch_name (obj->watch_name_id);
|
|
||||||
|
|
||||||
g_debug ("plugin object destroyed");
|
g_debug ("plugin object destroyed");
|
||||||
|
|
||||||
g_slice_free (PluginObject, obj);
|
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
|
static inline gboolean
|
||||||
uuid_is_valid (NPString string)
|
uuid_is_valid (const gchar *uuid)
|
||||||
{
|
{
|
||||||
gsize i;
|
gsize i;
|
||||||
|
|
||||||
for (i = 0; i < string.UTF8Length; i++)
|
for (i = 0; uuid[i]; i ++)
|
||||||
{
|
{
|
||||||
gchar c = string.UTF8Characters[i];
|
gchar c = uuid[i];
|
||||||
if (c < 32 || c >= 127)
|
if (c < 32 || c >= 127)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
@@ -443,73 +425,8 @@ jsonify_variant (GVariant *variant,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
parse_args (const gchar *format_str,
|
|
||||||
uint32_t argc,
|
|
||||||
const NPVariant *argv,
|
|
||||||
...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
gsize i;
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
|
|
||||||
if (strlen (format_str) != argc)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
va_start (args, argv);
|
|
||||||
|
|
||||||
for (i = 0; format_str[i]; i++)
|
|
||||||
{
|
|
||||||
gpointer arg_location;
|
|
||||||
const NPVariant arg = argv[i];
|
|
||||||
|
|
||||||
arg_location = va_arg (args, gpointer);
|
|
||||||
|
|
||||||
switch (format_str[i])
|
|
||||||
{
|
|
||||||
case 'u':
|
|
||||||
{
|
|
||||||
NPString string;
|
|
||||||
|
|
||||||
if (!NPVARIANT_IS_STRING (arg))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
string = NPVARIANT_TO_STRING (arg);
|
|
||||||
|
|
||||||
if (!uuid_is_valid (string))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
*(gchar **) arg_location = g_strndup (string.UTF8Characters, string.UTF8Length);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'b':
|
|
||||||
if (!NPVARIANT_IS_BOOLEAN (arg))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
*(gboolean *) arg_location = NPVARIANT_TO_BOOLEAN (arg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'o':
|
|
||||||
if (!NPVARIANT_IS_OBJECT (arg))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
*(NPObject **) arg_location = NPVARIANT_TO_OBJECT (arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
|
|
||||||
out:
|
|
||||||
va_end (args);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
plugin_list_extensions (PluginObject *obj,
|
plugin_list_extensions (PluginObject *obj,
|
||||||
uint32_t argc,
|
|
||||||
const NPVariant *args,
|
|
||||||
NPVariant *result)
|
NPVariant *result)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
@@ -535,159 +452,70 @@ plugin_list_extensions (PluginObject *obj,
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
plugin_enable_extension (PluginObject *obj,
|
plugin_enable_extension (PluginObject *obj,
|
||||||
uint32_t argc,
|
NPString uuid,
|
||||||
const NPVariant *argv,
|
gboolean enabled)
|
||||||
NPVariant *result)
|
|
||||||
{
|
{
|
||||||
gboolean ret;
|
const gchar *uuid_str = uuid.UTF8Characters;
|
||||||
gchar *uuid;
|
if (!uuid_is_valid (uuid_str))
|
||||||
gboolean enabled;
|
|
||||||
gsize length;
|
|
||||||
gchar **uuids;
|
|
||||||
const gchar **new_uuids;
|
|
||||||
|
|
||||||
if (!parse_args ("ub", argc, argv, &uuid, &enabled))
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
uuids = g_settings_get_strv (obj->settings, ENABLED_EXTENSIONS_KEY);
|
g_dbus_proxy_call (obj->proxy,
|
||||||
length = g_strv_length (uuids);
|
(enabled ? "EnableExtension" : "DisableExtension"),
|
||||||
|
g_variant_new ("(s)", uuid_str),
|
||||||
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
-1, /* timeout */
|
||||||
|
NULL, /* cancellable */
|
||||||
|
NULL, /* callback */
|
||||||
|
NULL /* user_data */);
|
||||||
|
|
||||||
if (enabled)
|
return TRUE;
|
||||||
{
|
|
||||||
new_uuids = g_new (const gchar *, length + 2); /* New key, NULL */
|
|
||||||
memcpy (new_uuids, uuids, length * sizeof (*new_uuids));
|
|
||||||
new_uuids[length] = uuid;
|
|
||||||
new_uuids[length + 1] = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gsize i = 0, j = 0;
|
|
||||||
new_uuids = g_new (const gchar *, length);
|
|
||||||
for (i = 0; i < length; i ++)
|
|
||||||
{
|
|
||||||
if (g_str_equal (uuids[i], uuid))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
new_uuids[j] = uuids[i];
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_uuids[j] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = g_settings_set_strv (obj->settings,
|
|
||||||
ENABLED_EXTENSIONS_KEY,
|
|
||||||
new_uuids);
|
|
||||||
|
|
||||||
g_strfreev (uuids);
|
|
||||||
g_free (new_uuids);
|
|
||||||
g_free (uuid);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct _AsyncClosure AsyncClosure;
|
|
||||||
|
|
||||||
struct _AsyncClosure {
|
|
||||||
PluginObject *obj;
|
|
||||||
NPObject *callback;
|
|
||||||
NPObject *errback;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
install_extension_cb (GObject *proxy,
|
|
||||||
GAsyncResult *async_res,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
AsyncClosure *async_closure = (AsyncClosure *) user_data;
|
|
||||||
GError *error = NULL;
|
|
||||||
GVariant *res;
|
|
||||||
NPVariant args[1];
|
|
||||||
NPVariant result = { NPVariantType_Void };
|
|
||||||
NPObject *callback;
|
|
||||||
|
|
||||||
res = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), async_res, &error);
|
|
||||||
|
|
||||||
if (res == NULL)
|
|
||||||
{
|
|
||||||
if (g_dbus_error_is_remote_error (error))
|
|
||||||
g_dbus_error_strip_remote_error (error);
|
|
||||||
STRINGZ_TO_NPVARIANT (error->message, args[0]);
|
|
||||||
callback = async_closure->errback;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
char *string_result;
|
|
||||||
g_variant_get (res, "(&s)", &string_result);
|
|
||||||
STRINGZ_TO_NPVARIANT (string_result, args[0]);
|
|
||||||
callback = async_closure->callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
funcs.invokeDefault (async_closure->obj->instance,
|
|
||||||
callback, args, 1, &result);
|
|
||||||
|
|
||||||
funcs.releasevariantvalue (&result);
|
|
||||||
|
|
||||||
funcs.releaseobject (async_closure->callback);
|
|
||||||
funcs.releaseobject (async_closure->errback);
|
|
||||||
g_slice_free (AsyncClosure, async_closure);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
plugin_install_extension (PluginObject *obj,
|
plugin_install_extension (PluginObject *obj,
|
||||||
uint32_t argc,
|
NPString uuid,
|
||||||
const NPVariant *argv,
|
NPString version_tag)
|
||||||
NPVariant *result)
|
|
||||||
{
|
{
|
||||||
gchar *uuid;
|
const gchar *uuid_str = uuid.UTF8Characters;
|
||||||
NPObject *callback, *errback;
|
if (!uuid_is_valid (uuid_str))
|
||||||
AsyncClosure *async_closure;
|
|
||||||
|
|
||||||
if (!parse_args ("uoo", argc, argv, &uuid, &callback, &errback))
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
async_closure = g_slice_new (AsyncClosure);
|
|
||||||
async_closure->obj = obj;
|
|
||||||
async_closure->callback = funcs.retainobject (callback);
|
|
||||||
async_closure->errback = funcs.retainobject (errback);
|
|
||||||
|
|
||||||
g_dbus_proxy_call (obj->proxy,
|
g_dbus_proxy_call (obj->proxy,
|
||||||
"InstallRemoteExtension",
|
"InstallRemoteExtension",
|
||||||
g_variant_new ("(s)", uuid),
|
g_variant_new ("(ss)",
|
||||||
|
uuid_str,
|
||||||
|
version_tag.UTF8Characters),
|
||||||
G_DBUS_CALL_FLAGS_NONE,
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
-1, /* timeout */
|
-1, /* timeout */
|
||||||
NULL, /* cancellable */
|
NULL, /* cancellable */
|
||||||
install_extension_cb,
|
NULL, /* callback */
|
||||||
async_closure);
|
NULL /* user_data */);
|
||||||
|
|
||||||
g_free (uuid);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
plugin_uninstall_extension (PluginObject *obj,
|
plugin_uninstall_extension (PluginObject *obj,
|
||||||
uint32_t argc,
|
NPString uuid,
|
||||||
const NPVariant *argv,
|
|
||||||
NPVariant *result)
|
NPVariant *result)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GVariant *res;
|
GVariant *res;
|
||||||
gchar *uuid;
|
const gchar *uuid_str;
|
||||||
|
|
||||||
if (!parse_args ("u", argc, argv, &uuid))
|
uuid_str = uuid.UTF8Characters;
|
||||||
|
if (!uuid_is_valid (uuid_str))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
res = g_dbus_proxy_call_sync (obj->proxy,
|
res = g_dbus_proxy_call_sync (obj->proxy,
|
||||||
"UninstallExtension",
|
"UninstallExtension",
|
||||||
g_variant_new ("(s)", uuid),
|
g_variant_new ("(s)",
|
||||||
|
uuid_str),
|
||||||
G_DBUS_CALL_FLAGS_NONE,
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
-1, /* timeout */
|
-1, /* timeout */
|
||||||
NULL, /* cancellable */
|
NULL, /* cancellable */
|
||||||
&error);
|
&error);
|
||||||
|
|
||||||
g_free (uuid);
|
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
g_warning ("Failed to uninstall extension: %s", error->message);
|
g_warning ("Failed to uninstall extension: %s", error->message);
|
||||||
@@ -700,27 +528,25 @@ plugin_uninstall_extension (PluginObject *obj,
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
plugin_get_info (PluginObject *obj,
|
plugin_get_info (PluginObject *obj,
|
||||||
uint32_t argc,
|
NPString uuid,
|
||||||
const NPVariant *argv,
|
|
||||||
NPVariant *result)
|
NPVariant *result)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GVariant *res;
|
GVariant *res;
|
||||||
gchar *uuid;
|
const gchar *uuid_str;
|
||||||
|
|
||||||
if (!parse_args ("u", argc, argv, &uuid))
|
uuid_str = uuid.UTF8Characters;
|
||||||
|
if (!uuid_is_valid (uuid_str))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
res = g_dbus_proxy_call_sync (obj->proxy,
|
res = g_dbus_proxy_call_sync (obj->proxy,
|
||||||
"GetExtensionInfo",
|
"GetExtensionInfo",
|
||||||
g_variant_new ("(s)", uuid),
|
g_variant_new ("(s)", uuid_str),
|
||||||
G_DBUS_CALL_FLAGS_NONE,
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
-1, /* timeout */
|
-1, /* timeout */
|
||||||
NULL, /* cancellable */
|
NULL, /* cancellable */
|
||||||
&error);
|
&error);
|
||||||
|
|
||||||
g_free (uuid);
|
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
g_warning ("Failed to retrieve extension metadata: %s", error->message);
|
g_warning ("Failed to retrieve extension metadata: %s", error->message);
|
||||||
@@ -733,20 +559,20 @@ plugin_get_info (PluginObject *obj,
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
plugin_get_errors (PluginObject *obj,
|
plugin_get_errors (PluginObject *obj,
|
||||||
uint32_t argc,
|
NPString uuid,
|
||||||
const NPVariant *argv,
|
|
||||||
NPVariant *result)
|
NPVariant *result)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GVariant *res;
|
GVariant *res;
|
||||||
gchar *uuid;
|
const gchar *uuid_str;
|
||||||
|
|
||||||
if (!parse_args ("u", argc, argv, &uuid))
|
uuid_str = uuid.UTF8Characters;
|
||||||
|
if (!uuid_is_valid (uuid_str))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
res = g_dbus_proxy_call_sync (obj->proxy,
|
res = g_dbus_proxy_call_sync (obj->proxy,
|
||||||
"GetExtensionErrors",
|
"GetExtensionErrors",
|
||||||
g_variant_new ("(s)", uuid),
|
g_variant_new ("(s)", uuid_str),
|
||||||
G_DBUS_CALL_FLAGS_NONE,
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
-1, /* timeout */
|
-1, /* timeout */
|
||||||
NULL, /* cancellable */
|
NULL, /* cancellable */
|
||||||
@@ -762,29 +588,6 @@ plugin_get_errors (PluginObject *obj,
|
|||||||
return jsonify_variant (res, result);
|
return jsonify_variant (res, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
plugin_launch_extension_prefs (PluginObject *obj,
|
|
||||||
uint32_t argc,
|
|
||||||
const NPVariant *argv,
|
|
||||||
NPVariant *result)
|
|
||||||
{
|
|
||||||
gchar *uuid;
|
|
||||||
|
|
||||||
if (!parse_args ("u", argc, argv, &uuid))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
g_dbus_proxy_call (obj->proxy,
|
|
||||||
"LaunchExtensionPrefs",
|
|
||||||
g_variant_new ("(s)", uuid),
|
|
||||||
G_DBUS_CALL_FLAGS_NONE,
|
|
||||||
-1, /* timeout */
|
|
||||||
NULL, /* cancellable */
|
|
||||||
NULL, /* callback */
|
|
||||||
NULL /* user_data */);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
plugin_get_api_version (PluginObject *obj,
|
plugin_get_api_version (PluginObject *obj,
|
||||||
NPVariant *result)
|
NPVariant *result)
|
||||||
@@ -830,45 +633,14 @@ plugin_get_shell_version (PluginObject *obj,
|
|||||||
STRINGN_TO_NPVARIANT (buffer, length, *result);
|
STRINGN_TO_NPVARIANT (buffer, length, *result);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (res)
|
|
||||||
g_variant_unref (res);
|
g_variant_unref (res);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define METHODS \
|
|
||||||
METHOD (list_extensions) \
|
|
||||||
METHOD (get_info) \
|
|
||||||
METHOD (enable_extension) \
|
|
||||||
METHOD (install_extension) \
|
|
||||||
METHOD (uninstall_extension) \
|
|
||||||
METHOD (get_errors) \
|
|
||||||
METHOD (launch_extension_prefs) \
|
|
||||||
/* */
|
|
||||||
|
|
||||||
#define METHOD(x) \
|
|
||||||
static NPIdentifier x##_id;
|
|
||||||
METHODS
|
|
||||||
#undef METHOD
|
|
||||||
|
|
||||||
static NPIdentifier api_version_id;
|
|
||||||
static NPIdentifier shell_version_id;
|
|
||||||
static NPIdentifier onextension_changed_id;
|
|
||||||
static NPIdentifier onrestart_id;
|
|
||||||
|
|
||||||
static bool
|
|
||||||
plugin_object_has_method (NPObject *npobj,
|
|
||||||
NPIdentifier name)
|
|
||||||
{
|
|
||||||
#define METHOD(x) (name == (x##_id)) ||
|
|
||||||
/* expands to (name == list_extensions_id) || FALSE; */
|
|
||||||
return METHODS FALSE;
|
|
||||||
#undef METHOD
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
plugin_object_invoke (NPObject *npobj,
|
plugin_object_invoke (NPObject *npobj,
|
||||||
NPIdentifier name,
|
NPIdentifier name,
|
||||||
const NPVariant *argv,
|
const NPVariant *args,
|
||||||
uint32_t argc,
|
uint32_t argc,
|
||||||
NPVariant *result)
|
NPVariant *result)
|
||||||
{
|
{
|
||||||
@@ -880,13 +652,53 @@ plugin_object_invoke (NPObject *npobj,
|
|||||||
|
|
||||||
VOID_TO_NPVARIANT (*result);
|
VOID_TO_NPVARIANT (*result);
|
||||||
|
|
||||||
#define METHOD(x) \
|
if (!plugin_object_has_method (npobj, name))
|
||||||
if (name == x##_id) \
|
|
||||||
return plugin_##x (obj, argc, argv, result);
|
|
||||||
METHODS
|
|
||||||
#undef METHOD
|
|
||||||
|
|
||||||
return FALSE;
|
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
|
static bool
|
||||||
@@ -894,7 +706,6 @@ plugin_object_has_property (NPObject *npobj,
|
|||||||
NPIdentifier name)
|
NPIdentifier name)
|
||||||
{
|
{
|
||||||
return (name == onextension_changed_id ||
|
return (name == onextension_changed_id ||
|
||||||
name == onrestart_id ||
|
|
||||||
name == api_version_id ||
|
name == api_version_id ||
|
||||||
name == shell_version_id);
|
name == shell_version_id);
|
||||||
}
|
}
|
||||||
@@ -921,33 +732,6 @@ plugin_object_get_property (NPObject *npobj,
|
|||||||
else
|
else
|
||||||
NULL_TO_NPVARIANT (*result);
|
NULL_TO_NPVARIANT (*result);
|
||||||
}
|
}
|
||||||
else if (name == onrestart_id)
|
|
||||||
{
|
|
||||||
if (obj->restart_listener)
|
|
||||||
OBJECT_TO_NPVARIANT (obj->restart_listener, *result);
|
|
||||||
else
|
|
||||||
NULL_TO_NPVARIANT (*result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
plugin_object_set_callback (NPObject **listener,
|
|
||||||
const NPVariant *value)
|
|
||||||
{
|
|
||||||
if (!NPVARIANT_IS_OBJECT (*value) && !NPVARIANT_IS_NULL (*value))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (*listener)
|
|
||||||
funcs.releaseobject (*listener);
|
|
||||||
*listener = NULL;
|
|
||||||
|
|
||||||
if (NPVARIANT_IS_OBJECT (*value))
|
|
||||||
{
|
|
||||||
*listener = NPVARIANT_TO_OBJECT (*value);
|
|
||||||
funcs.retainobject (*listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -959,13 +743,25 @@ plugin_object_set_property (NPObject *npobj,
|
|||||||
{
|
{
|
||||||
PluginObject *obj;
|
PluginObject *obj;
|
||||||
|
|
||||||
obj = (PluginObject *)npobj;
|
if (!plugin_object_has_property (npobj, name))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
if (name == onextension_changed_id)
|
if (name == onextension_changed_id)
|
||||||
return plugin_object_set_callback (&obj->listener, value);
|
{
|
||||||
|
obj = (PluginObject*) npobj;
|
||||||
|
if (obj->listener)
|
||||||
|
funcs.releaseobject (obj->listener);
|
||||||
|
|
||||||
if (name == onrestart_id)
|
obj->listener = NULL;
|
||||||
return plugin_object_set_callback (&obj->restart_listener, value);
|
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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -999,9 +795,7 @@ init_methods_and_properties (void)
|
|||||||
install_extension_id = funcs.getstringidentifier ("installExtension");
|
install_extension_id = funcs.getstringidentifier ("installExtension");
|
||||||
uninstall_extension_id = funcs.getstringidentifier ("uninstallExtension");
|
uninstall_extension_id = funcs.getstringidentifier ("uninstallExtension");
|
||||||
get_errors_id = funcs.getstringidentifier ("getExtensionErrors");
|
get_errors_id = funcs.getstringidentifier ("getExtensionErrors");
|
||||||
launch_extension_prefs_id = funcs.getstringidentifier ("launchExtensionPrefs");
|
|
||||||
|
|
||||||
onrestart_id = funcs.getstringidentifier ("onshellrestart");
|
|
||||||
onextension_changed_id = funcs.getstringidentifier ("onchange");
|
onextension_changed_id = funcs.getstringidentifier ("onchange");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1030,12 +824,3 @@ NPP_GetValue(NPP instance,
|
|||||||
|
|
||||||
return NPERR_NO_ERROR;
|
return NPERR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opera tries to call NPP_SetWindow without checking the
|
|
||||||
* NULL pointer beforehand. */
|
|
||||||
NPError
|
|
||||||
NPP_SetWindow(NPP instance,
|
|
||||||
NPWindow *window)
|
|
||||||
{
|
|
||||||
return NPERR_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|||||||
114
configure.ac
@@ -1,5 +1,5 @@
|
|||||||
AC_PREREQ(2.63)
|
AC_PREREQ(2.63)
|
||||||
AC_INIT([gnome-shell],[3.5.4],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
AC_INIT([gnome-shell],[3.2.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||||
|
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
AC_CONFIG_SRCDIR([src/shell-global.c])
|
AC_CONFIG_SRCDIR([src/shell-global.c])
|
||||||
@@ -44,50 +44,46 @@ AC_SUBST(PYTHON)
|
|||||||
|
|
||||||
# We need at least this, since gst_plugin_register_static() was added
|
# We need at least this, since gst_plugin_register_static() was added
|
||||||
# in 0.10.16, but nothing older than 0.10.21 has been tested.
|
# in 0.10.16, but nothing older than 0.10.21 has been tested.
|
||||||
GSTREAMER_MIN_VERSION=0.11.92
|
GSTREAMER_MIN_VERSION=0.10.16
|
||||||
|
|
||||||
recorder_modules=
|
recorder_modules=
|
||||||
build_recorder=false
|
build_recorder=false
|
||||||
AC_MSG_CHECKING([for GStreamer (needed for recording functionality)])
|
AC_MSG_CHECKING([for GStreamer (needed for recording functionality)])
|
||||||
if $PKG_CONFIG --exists gstreamer-1.0 '>=' $GSTREAMER_MIN_VERSION ; then
|
if $PKG_CONFIG --exists gstreamer-0.10 '>=' $GSTREAMER_MIN_VERSION ; then
|
||||||
AC_MSG_RESULT(yes)
|
AC_MSG_RESULT(yes)
|
||||||
build_recorder=true
|
build_recorder=true
|
||||||
recorder_modules="gstreamer-1.0 gstreamer-base-1.0 x11"
|
recorder_modules="gstreamer-0.10 gstreamer-base-0.10 x11"
|
||||||
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0 xfixes gl)
|
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0 xfixes)
|
||||||
else
|
else
|
||||||
AC_MSG_RESULT(no)
|
AC_MSG_RESULT(no)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
||||||
|
|
||||||
CLUTTER_MIN_VERSION=1.9.16
|
CLUTTER_MIN_VERSION=1.7.5
|
||||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
||||||
GJS_MIN_VERSION=1.33.2
|
GJS_MIN_VERSION=1.29.18
|
||||||
MUTTER_MIN_VERSION=3.5.4
|
MUTTER_MIN_VERSION=3.2.1
|
||||||
GTK_MIN_VERSION=3.3.9
|
FOLKS_MIN_VERSION=0.5.2
|
||||||
GIO_MIN_VERSION=2.31.6
|
GTK_MIN_VERSION=3.0.0
|
||||||
LIBECAL_MIN_VERSION=3.5.3
|
GIO_MIN_VERSION=2.31.0
|
||||||
LIBEDATASERVER_MIN_VERSION=3.5.3
|
LIBECAL_MIN_VERSION=2.32.0
|
||||||
LIBEDATASERVERUI_MIN_VERSION=3.5.3
|
LIBEDATASERVER_MIN_VERSION=1.2.0
|
||||||
TELEPATHY_GLIB_MIN_VERSION=0.17.5
|
LIBEDATASERVERUI_MIN_VERSION=2.91.6
|
||||||
|
TELEPATHY_GLIB_MIN_VERSION=0.15.5
|
||||||
TELEPATHY_LOGGER_MIN_VERSION=0.2.4
|
TELEPATHY_LOGGER_MIN_VERSION=0.2.4
|
||||||
POLKIT_MIN_VERSION=0.100
|
POLKIT_MIN_VERSION=0.100
|
||||||
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
||||||
GCR_MIN_VERSION=3.3.90
|
|
||||||
GNOME_DESKTOP_REQUIRED_VERSION=3.5.1
|
|
||||||
GNOME_MENUS_REQUIRED_VERSION=3.5.3
|
|
||||||
|
|
||||||
# Collect more than 20 libraries for a prize!
|
# Collect more than 20 libraries for a prize!
|
||||||
PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
|
PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
|
||||||
libxml-2.0
|
libxml-2.0
|
||||||
gtk+-3.0 >= $GTK_MIN_VERSION
|
gtk+-3.0 >= $GTK_MIN_VERSION
|
||||||
atk-bridge-2.0
|
folks >= $FOLKS_MIN_VERSION
|
||||||
libmutter >= $MUTTER_MIN_VERSION
|
libmutter >= $MUTTER_MIN_VERSION
|
||||||
gjs-internals-1.0 >= $GJS_MIN_VERSION
|
gjs-internals-1.0 >= $GJS_MIN_VERSION
|
||||||
libgnome-menu-3.0 >= $GNOME_MENUS_REQUIRED_VERSION
|
libgnome-menu-3.0 $recorder_modules gconf-2.0
|
||||||
$recorder_modules
|
|
||||||
gdk-x11-3.0 libsoup-2.4
|
gdk-x11-3.0 libsoup-2.4
|
||||||
gl
|
|
||||||
clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
|
clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
|
||||||
clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
|
clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
|
||||||
libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION
|
libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION
|
||||||
@@ -96,9 +92,7 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
|
|||||||
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
|
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
|
||||||
telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION
|
telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION
|
||||||
polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes
|
polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes
|
||||||
libnm-glib libnm-util gnome-keyring-1
|
libnm-glib libnm-util gnome-keyring-1)
|
||||||
gcr-3 >= $GCR_MIN_VERSION
|
|
||||||
gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION)
|
|
||||||
|
|
||||||
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
|
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
|
||||||
|
|
||||||
@@ -106,7 +100,13 @@ 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)
|
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])
|
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
|
||||||
|
JHBUILD_TYPELIBDIR="$INTROSPECTION_TYPELIBDIR"
|
||||||
|
AC_SUBST(JHBUILD_TYPELIBDIR)
|
||||||
|
|
||||||
saved_CFLAGS=$CFLAGS
|
saved_CFLAGS=$CFLAGS
|
||||||
saved_LIBS=$LIBS
|
saved_LIBS=$LIBS
|
||||||
@@ -116,11 +116,11 @@ AC_CHECK_FUNCS(JS_NewGlobalObject XFixesCreatePointerBarrier)
|
|||||||
CFLAGS=$saved_CFLAGS
|
CFLAGS=$saved_CFLAGS
|
||||||
LIBS=$saved_LIBS
|
LIBS=$saved_LIBS
|
||||||
|
|
||||||
PKG_CHECK_MODULES(GNOME_SHELL_JS, gio-2.0 gjs-internals-1.0 >= $GJS_MIN_VERSION)
|
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.2 gnome-desktop-3.0 >= 2.90.0 x11)
|
||||||
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.2 x11)
|
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-3.0)
|
||||||
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
|
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
|
||||||
PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
|
PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
|
||||||
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.5.4)
|
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 0.1.7)
|
||||||
|
|
||||||
AC_MSG_CHECKING([for bluetooth support])
|
AC_MSG_CHECKING([for bluetooth support])
|
||||||
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0],
|
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0],
|
||||||
@@ -140,33 +140,6 @@ PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedatas
|
|||||||
AC_SUBST(CALENDAR_SERVER_CFLAGS)
|
AC_SUBST(CALENDAR_SERVER_CFLAGS)
|
||||||
AC_SUBST(CALENDAR_SERVER_LIBS)
|
AC_SUBST(CALENDAR_SERVER_LIBS)
|
||||||
|
|
||||||
AC_ARG_WITH(systemd,
|
|
||||||
AS_HELP_STRING([--with-systemd],
|
|
||||||
[Add systemd support]),
|
|
||||||
[with_systemd=$withval], [with_systemd=auto])
|
|
||||||
|
|
||||||
PKG_CHECK_MODULES(SYSTEMD,
|
|
||||||
[libsystemd-login libsystemd-daemon],
|
|
||||||
[have_systemd=yes], [have_systemd=no])
|
|
||||||
|
|
||||||
if test "x$with_systemd" = "xauto" ; then
|
|
||||||
if test x$have_systemd = xno ; then
|
|
||||||
use_systemd=no
|
|
||||||
else
|
|
||||||
use_systemd=yes
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
use_systemd=$with_systemd
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "x$use_systemd" = "xyes"; then
|
|
||||||
if test "x$have_systemd" = "xno"; then
|
|
||||||
AC_MSG_ERROR([Systemd support explicitly required, but systemd not found])
|
|
||||||
fi
|
|
||||||
|
|
||||||
AC_DEFINE(WITH_SYSTEMD, 1, [systemd support])
|
|
||||||
fi
|
|
||||||
|
|
||||||
MUTTER_GIR_DIR=`$PKG_CONFIG --variable=girdir libmutter`
|
MUTTER_GIR_DIR=`$PKG_CONFIG --variable=girdir libmutter`
|
||||||
MUTTER_TYPELIB_DIR=`$PKG_CONFIG --variable=typelibdir libmutter`
|
MUTTER_TYPELIB_DIR=`$PKG_CONFIG --variable=typelibdir libmutter`
|
||||||
AC_SUBST(MUTTER_GIR_DIR)
|
AC_SUBST(MUTTER_GIR_DIR)
|
||||||
@@ -209,7 +182,7 @@ GTK_DOC_CHECK([1.15], [--flavour no-tmpl])
|
|||||||
# minimum/yes/maximum are the same, however.
|
# minimum/yes/maximum are the same, however.
|
||||||
AC_ARG_ENABLE(compile_warnings,
|
AC_ARG_ENABLE(compile_warnings,
|
||||||
AS_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@],[Turn on compiler warnings]),,
|
AS_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@],[Turn on compiler warnings]),,
|
||||||
enable_compile_warnings=error)
|
enable_compile_warnings=maximum)
|
||||||
|
|
||||||
changequote(,)dnl
|
changequote(,)dnl
|
||||||
if test "$enable_compile_warnings" != no ; then
|
if test "$enable_compile_warnings" != no ; then
|
||||||
@@ -225,7 +198,7 @@ if test "$enable_compile_warnings" != no ; then
|
|||||||
if test "$enable_compile_warnings" = error ; then
|
if test "$enable_compile_warnings" = error ; then
|
||||||
case " $CFLAGS " in
|
case " $CFLAGS " in
|
||||||
*[\ \ ]-Werror[\ \ ]*) ;;
|
*[\ \ ]-Werror[\ \ ]*) ;;
|
||||||
*) CFLAGS="$CFLAGS -Werror -Wno-error=deprecated-declarations" ;;
|
*) CFLAGS="$CFLAGS -Werror" ;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -233,9 +206,34 @@ fi
|
|||||||
changequote([,])dnl
|
changequote([,])dnl
|
||||||
|
|
||||||
AC_ARG_ENABLE(jhbuild-wrapper-script,
|
AC_ARG_ENABLE(jhbuild-wrapper-script,
|
||||||
AS_HELP_STRING([--enable-jhbuild-wrapper-script],[Make "gnome-shell" script work for jhbuild]),,enable_jhbuild_wrapper_script=no)
|
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)
|
AM_CONDITIONAL(USE_JHBUILD_WRAPPER_SCRIPT, test "x$enable_jhbuild_wrapper_script" = xyes)
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([location of system Certificate Authority list])
|
||||||
|
AC_ARG_WITH(ca-certificates,
|
||||||
|
[AC_HELP_STRING([--with-ca-certificates=@<:@path@:>@],
|
||||||
|
[path to system Certificate Authority list])])
|
||||||
|
|
||||||
|
if test "$with_ca_certificates" = "no"; then
|
||||||
|
AC_MSG_RESULT([disabled])
|
||||||
|
else
|
||||||
|
if test -z "$with_ca_certificates"; then
|
||||||
|
for f in /etc/pki/tls/certs/ca-bundle.crt \
|
||||||
|
/etc/ssl/certs/ca-certificates.crt; do
|
||||||
|
if test -f "$f"; then
|
||||||
|
with_ca_certificates="$f"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -z "$with_ca_certificates"; then
|
||||||
|
AC_MSG_ERROR([could not find. Use --with-ca-certificates=path to set, or --without-ca-certificates to disable])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_RESULT($with_ca_certificates)
|
||||||
|
AC_DEFINE_UNQUOTED(SHELL_SYSTEM_CA_FILE, ["$with_ca_certificates"], [The system TLS CA list])
|
||||||
|
fi
|
||||||
|
AC_SUBST(SHELL_SYSTEM_CA_FILE,["$with_ca_certificates"])
|
||||||
|
|
||||||
BROWSER_PLUGIN_DIR="${BROWSER_PLUGIN_DIR:-"\${libdir}/mozilla/plugins"}"
|
BROWSER_PLUGIN_DIR="${BROWSER_PLUGIN_DIR:-"\${libdir}/mozilla/plugins"}"
|
||||||
AC_ARG_VAR([BROWSER_PLUGIN_DIR],[Where to install the plugin to])
|
AC_ARG_VAR([BROWSER_PLUGIN_DIR],[Where to install the plugin to])
|
||||||
|
|
||||||
@@ -249,7 +247,7 @@ AC_CONFIG_FILES([
|
|||||||
docs/reference/st/Makefile
|
docs/reference/st/Makefile
|
||||||
docs/reference/st/st-docs.sgml
|
docs/reference/st/st-docs.sgml
|
||||||
js/Makefile
|
js/Makefile
|
||||||
src/calendar-server/evolution-calendar.desktop.in
|
js/misc/config.js
|
||||||
src/Makefile
|
src/Makefile
|
||||||
browser-plugin/Makefile
|
browser-plugin/Makefile
|
||||||
tests/Makefile
|
tests/Makefile
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
desktopdir=$(datadir)/applications
|
desktopdir=$(datadir)/applications
|
||||||
desktop_DATA = gnome-shell.desktop gnome-shell-extension-prefs.desktop
|
desktop_DATA = gnome-shell.desktop
|
||||||
|
|
||||||
# We substitute in bindir so it works as an autostart
|
# We substitute in bindir so it works as an autostart
|
||||||
# file when built in a non-system prefix
|
# file when built in a non-system prefix
|
||||||
@@ -8,25 +8,20 @@ desktop_DATA = gnome-shell.desktop gnome-shell-extension-prefs.desktop
|
|||||||
-e "s|@VERSION[@]|$(VERSION)|" \
|
-e "s|@VERSION[@]|$(VERSION)|" \
|
||||||
$< > $@ || rm $@
|
$< > $@ || rm $@
|
||||||
|
|
||||||
@INTLTOOL_DESKTOP_RULE@
|
# Placeholder until we add intltool
|
||||||
|
%.desktop:%.desktop.in
|
||||||
|
$(AM_V_GEN) sed s/^_// < $< > $@ || rm $@
|
||||||
|
|
||||||
searchprovidersdir = $(pkgdatadir)/open-search-providers
|
searchprovidersdir = $(pkgdatadir)/search_providers
|
||||||
dist_searchproviders_DATA = \
|
dist_searchproviders_DATA = \
|
||||||
open-search-providers/google.xml \
|
search_providers/google.xml \
|
||||||
open-search-providers/wikipedia.xml
|
search_providers/wikipedia.xml
|
||||||
|
|
||||||
introspectiondir = $(datadir)/dbus-1/interfaces
|
|
||||||
introspection_DATA = org.gnome.ShellSearchProvider.xml
|
|
||||||
|
|
||||||
themedir = $(pkgdatadir)/theme
|
themedir = $(pkgdatadir)/theme
|
||||||
dist_theme_DATA = \
|
dist_theme_DATA = \
|
||||||
theme/calendar-arrow-left.svg \
|
theme/calendar-arrow-left.svg \
|
||||||
theme/calendar-arrow-right.svg \
|
theme/calendar-arrow-right.svg \
|
||||||
theme/calendar-today.svg \
|
theme/calendar-today.svg \
|
||||||
theme/checkbox-focused.svg \
|
|
||||||
theme/checkbox-off-focused.svg \
|
|
||||||
theme/checkbox-off.svg \
|
|
||||||
theme/checkbox.svg \
|
|
||||||
theme/close-window.svg \
|
theme/close-window.svg \
|
||||||
theme/close.svg \
|
theme/close.svg \
|
||||||
theme/corner-ripple-ltr.png \
|
theme/corner-ripple-ltr.png \
|
||||||
@@ -34,14 +29,16 @@ dist_theme_DATA = \
|
|||||||
theme/dash-placeholder.svg \
|
theme/dash-placeholder.svg \
|
||||||
theme/filter-selected-ltr.svg \
|
theme/filter-selected-ltr.svg \
|
||||||
theme/filter-selected-rtl.svg \
|
theme/filter-selected-rtl.svg \
|
||||||
|
theme/gdm.css \
|
||||||
theme/gnome-shell.css \
|
theme/gnome-shell.css \
|
||||||
theme/logged-in-indicator.svg \
|
theme/panel-border.svg \
|
||||||
theme/noise-texture.png \
|
|
||||||
theme/panel-button-border.svg \
|
theme/panel-button-border.svg \
|
||||||
theme/panel-button-highlight-narrow.svg \
|
theme/panel-button-highlight-narrow.svg \
|
||||||
theme/panel-button-highlight-wide.svg \
|
theme/panel-button-highlight-wide.svg \
|
||||||
theme/process-working.svg \
|
theme/process-working.svg \
|
||||||
theme/running-indicator.svg \
|
theme/running-indicator.svg \
|
||||||
|
theme/scroll-hhandle.svg \
|
||||||
|
theme/scroll-vhandle.svg \
|
||||||
theme/source-button-border.svg \
|
theme/source-button-border.svg \
|
||||||
theme/toggle-off-us.svg \
|
theme/toggle-off-us.svg \
|
||||||
theme/toggle-off-intl.svg \
|
theme/toggle-off-intl.svg \
|
||||||
@@ -53,11 +50,6 @@ dist_theme_DATA = \
|
|||||||
gsettings_SCHEMAS = org.gnome.shell.gschema.xml
|
gsettings_SCHEMAS = org.gnome.shell.gschema.xml
|
||||||
|
|
||||||
@INTLTOOL_XML_NOMERGE_RULE@
|
@INTLTOOL_XML_NOMERGE_RULE@
|
||||||
|
|
||||||
%.gschema.xml.in: %.gschema.xml.in.in Makefile
|
|
||||||
$(AM_V_GEN) sed -e 's|@GETTEXT_PACKAGE[@]|$(GETTEXT_PACKAGE)|g' \
|
|
||||||
$< > $@ || rm $@
|
|
||||||
|
|
||||||
@GSETTINGS_RULES@
|
@GSETTINGS_RULES@
|
||||||
|
|
||||||
# We need to compile schemas at make time
|
# We need to compile schemas at make time
|
||||||
@@ -67,22 +59,21 @@ gschemas.compiled: $(gsettings_SCHEMAS:.xml=.valid)
|
|||||||
|
|
||||||
all-local: gschemas.compiled
|
all-local: gschemas.compiled
|
||||||
|
|
||||||
convertdir = $(datadir)/GConf/gsettings
|
|
||||||
convert_DATA = gnome-shell-overrides.convert
|
shadersdir = $(pkgdatadir)/shaders
|
||||||
|
shaders_DATA = \
|
||||||
|
shaders/dim-window.glsl
|
||||||
|
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
gnome-shell.desktop.in.in \
|
gnome-shell.desktop.in.in \
|
||||||
gnome-shell-extension-prefs.desktop.in.in \
|
|
||||||
$(introspection_DATA) \
|
|
||||||
$(menu_DATA) \
|
$(menu_DATA) \
|
||||||
$(convert_DATA) \
|
$(shaders_DATA) \
|
||||||
org.gnome.shell.gschema.xml.in.in
|
org.gnome.shell.gschema.xml.in
|
||||||
|
|
||||||
CLEANFILES = \
|
CLEANFILES = \
|
||||||
gnome-shell.desktop.in \
|
gnome-shell.desktop.in \
|
||||||
gnome-shell-extension-prefs.in \
|
|
||||||
$(desktop_DATA) \
|
$(desktop_DATA) \
|
||||||
$(gsettings_SCHEMAS) \
|
$(gsettings_SCHEMAS) \
|
||||||
gschemas.compiled \
|
gschemas.compiled
|
||||||
org.gnome.shell.gschema.valid \
|
|
||||||
org.gnome.shell.gschema.xml.in
|
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Type=Application
|
|
||||||
_Name=GNOME Shell Extension Preferences
|
|
||||||
_Comment=Configure GNOME Shell Extensions
|
|
||||||
Exec=@bindir@/gnome-shell-extension-prefs %u
|
|
||||||
X-GNOME-Bugzilla-Bugzilla=GNOME
|
|
||||||
X-GNOME-Bugzilla-Product=gnome-shell
|
|
||||||
X-GNOME-Bugzilla-Component=extensions
|
|
||||||
X-GNOME-Bugzilla-Version=@VERSION@
|
|
||||||
Categories=GNOME;GTK;
|
|
||||||
OnlyShowIn=GNOME;
|
|
||||||
NoDisplay=true
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
[org.gnome.shell.overrides]
|
|
||||||
attach-modal-dialogs = /desktop/gnome/shell/windows/attach_modal_dialogs
|
|
||||||
button-layout = /desktop/gnome/shell/windows/button_layout
|
|
||||||
edge-tiling = /desktop/gnome/shell/windows/edge_tiling
|
|
||||||
workspaces-only-on-primary = /desktop/gnome/shell/windows/workspaces_only_on_primary
|
|
||||||
@@ -13,4 +13,4 @@ NoDisplay=true
|
|||||||
X-GNOME-Autostart-Phase=WindowManager
|
X-GNOME-Autostart-Phase=WindowManager
|
||||||
X-GNOME-Provides=panel;windowmanager;
|
X-GNOME-Provides=panel;windowmanager;
|
||||||
X-GNOME-Autostart-Notify=true
|
X-GNOME-Autostart-Notify=true
|
||||||
X-GNOME-AutoRestart=false
|
X-GNOME-AutoRestart=true
|
||||||
|
|||||||
@@ -1,147 +0,0 @@
|
|||||||
<!DOCTYPE node PUBLIC
|
|
||||||
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
|
|
||||||
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
|
|
||||||
<node>
|
|
||||||
<interface name="org.gnome.Shell.SearchProvider">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
The interface used for integrating into GNOME Shell's search
|
|
||||||
interface.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
</doc:doc>
|
|
||||||
|
|
||||||
<method name="GetInitialResultSet">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Called when the user first begins a search.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
</doc:doc>
|
|
||||||
<arg type="as" direction="in">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:summary>
|
|
||||||
<doc:para>
|
|
||||||
Array of search terms, which the provider should treat as
|
|
||||||
logical AND.
|
|
||||||
</doc:para>
|
|
||||||
</doc:summary>
|
|
||||||
</doc:doc>
|
|
||||||
</arg>
|
|
||||||
<arg type="as" direction="out">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:summary>
|
|
||||||
<doc:para>
|
|
||||||
An array of result identifier strings representing items which
|
|
||||||
match the given search terms. Identifiers must be unique within
|
|
||||||
the provider's domain, but other than that may be chosen freely
|
|
||||||
by the provider.
|
|
||||||
</doc:para>
|
|
||||||
</doc:summary>
|
|
||||||
</doc:doc>
|
|
||||||
</arg>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="GetSubsearchResultSet">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Called when a search is performed which is a "subsearch" of
|
|
||||||
the previous search, e.g. the method may return less results, but
|
|
||||||
not more or different results.
|
|
||||||
|
|
||||||
This allows search providers to only search through the previous
|
|
||||||
result set, rather than possibly performing a full re-query.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
</doc:doc>
|
|
||||||
<arg type="as" direction="in">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:summary>
|
|
||||||
<doc:para>
|
|
||||||
Array of item identifiers
|
|
||||||
</doc:para>
|
|
||||||
</doc:summary>
|
|
||||||
</doc:doc>
|
|
||||||
</arg>
|
|
||||||
<arg type="as" direction="in">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:summary>
|
|
||||||
<doc:para>
|
|
||||||
Array of updated search terms, which the provider should treat as
|
|
||||||
logical AND.
|
|
||||||
</doc:para>
|
|
||||||
</doc:summary>
|
|
||||||
</doc:doc>
|
|
||||||
</arg>
|
|
||||||
<arg type="as" direction="out">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:summary>
|
|
||||||
<doc:para>
|
|
||||||
An array of result identifier strings representing items which
|
|
||||||
match the given search terms. Identifiers must be unique within
|
|
||||||
the provider's domain, but other than that may be chosen freely
|
|
||||||
by the provider.
|
|
||||||
</doc:para>
|
|
||||||
</doc:summary>
|
|
||||||
</doc:doc>
|
|
||||||
</arg>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="GetResultMetas">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Return an array of meta data used to display each given result
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
</doc:doc>
|
|
||||||
<arg type="as" direction="in">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:summary>
|
|
||||||
<doc:para>
|
|
||||||
An array of result identifiers as returned by
|
|
||||||
GetInitialResultSet() or GetSubsearchResultSet()
|
|
||||||
</doc:para>
|
|
||||||
</doc:summary>
|
|
||||||
</doc:doc>
|
|
||||||
</arg>
|
|
||||||
<arg type="a{sv}" direction="out">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:summary>
|
|
||||||
<doc:para>
|
|
||||||
A dictionary describing the given search result, containing
|
|
||||||
'id', 'name' (both strings) and either 'icon' (a serialized
|
|
||||||
GIcon) or 'icon-data' (raw image data as (iiibiiay) - width,
|
|
||||||
height, rowstride, has-alpha, bits per sample, channels, data)
|
|
||||||
</doc:para>
|
|
||||||
</doc:summary>
|
|
||||||
</doc:doc>
|
|
||||||
</arg>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="ActivateResult">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Called when the users chooses a given result. The result should
|
|
||||||
be displayed in the application associated with the corresponding
|
|
||||||
provider.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
</doc:doc>
|
|
||||||
<arg type="s" direction="in">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:summary>
|
|
||||||
<doc:para>
|
|
||||||
A result identifier as returned by GetInitialResultSet() or
|
|
||||||
GetSubsearchResultSet()
|
|
||||||
</doc:para>
|
|
||||||
</doc:summary>
|
|
||||||
</doc:doc>
|
|
||||||
</arg>
|
|
||||||
</method>
|
|
||||||
</interface>
|
|
||||||
</node>
|
|
||||||
@@ -53,17 +53,15 @@
|
|||||||
</key>
|
</key>
|
||||||
<key name="saved-im-presence" type="i">
|
<key name="saved-im-presence" type="i">
|
||||||
<default>1</default>
|
<default>1</default>
|
||||||
<_summary>Internally used to store the last IM presence explicitly set by the user. The
|
<_summary></_summary>
|
||||||
value here is from the TpConnectionPresenceType enumeration.</_summary>
|
|
||||||
</key>
|
</key>
|
||||||
<key name="saved-session-presence" type="i">
|
<key name="saved-session-presence" type="i">
|
||||||
<default>0</default>
|
<default>0</default>
|
||||||
<_summary>Internally used to store the last session presence status for the user. The
|
<_summary></_summary>
|
||||||
value here is from the GsmPresenceStatus enumeration.</_summary>
|
|
||||||
</key>
|
</key>
|
||||||
|
<child name="clock" schema="org.gnome.shell.clock"/>
|
||||||
<child name="calendar" schema="org.gnome.shell.calendar"/>
|
<child name="calendar" schema="org.gnome.shell.calendar"/>
|
||||||
<child name="recorder" schema="org.gnome.shell.recorder"/>
|
<child name="recorder" schema="org.gnome.shell.recorder"/>
|
||||||
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
|
|
||||||
<child name="keyboard" schema="org.gnome.shell.keyboard"/>
|
<child name="keyboard" schema="org.gnome.shell.keyboard"/>
|
||||||
</schema>
|
</schema>
|
||||||
|
|
||||||
@@ -78,24 +76,6 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
|
|||||||
</key>
|
</key>
|
||||||
</schema>
|
</schema>
|
||||||
|
|
||||||
<schema id="org.gnome.shell.keybindings" path="/org/gnome/shell/keybindings/"
|
|
||||||
gettext-domain="@GETTEXT_PACKAGE@">
|
|
||||||
<key name="open-application-menu" type="as">
|
|
||||||
<default>["<Super>F10"]</default>
|
|
||||||
<_summary>Keybinding to open the application menu</_summary>
|
|
||||||
<_description>
|
|
||||||
Keybinding to open the application menu.
|
|
||||||
</_description>
|
|
||||||
</key>
|
|
||||||
<key name="toggle-recording" type="as">
|
|
||||||
<default><![CDATA[['<Control><Shift><Alt>r']]]></default>
|
|
||||||
<_summary>Keybinding to toggle the screen recorder</_summary>
|
|
||||||
<_description>
|
|
||||||
Keybinding to start/stop the builtin screen recorder.
|
|
||||||
</_description>
|
|
||||||
</key>
|
|
||||||
</schema>
|
|
||||||
|
|
||||||
<schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/"
|
<schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/"
|
||||||
gettext-domain="@GETTEXT_PACKAGE@">
|
gettext-domain="@GETTEXT_PACKAGE@">
|
||||||
<key name="keyboard-type" type="s">
|
<key name="keyboard-type" type="s">
|
||||||
@@ -107,10 +87,28 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
|
|||||||
</key>
|
</key>
|
||||||
</schema>
|
</schema>
|
||||||
|
|
||||||
|
<schema id="org.gnome.shell.clock" path="/org/gnome/shell/clock/"
|
||||||
|
gettext-domain="@GETTEXT_PACKAGE@">
|
||||||
|
<key name="show-seconds" type="b">
|
||||||
|
<default>false</default>
|
||||||
|
<_summary>Show time with seconds</_summary>
|
||||||
|
<_description>
|
||||||
|
If true, display seconds in time.
|
||||||
|
</_description>
|
||||||
|
</key>
|
||||||
|
<key name="show-date" type="b">
|
||||||
|
<default>false</default>
|
||||||
|
<_summary>Show date in clock</_summary>
|
||||||
|
<_description>
|
||||||
|
If true, display date in the clock, in addition to time.
|
||||||
|
</_description>
|
||||||
|
</key>
|
||||||
|
</schema>
|
||||||
|
|
||||||
<schema id="org.gnome.shell.recorder" path="/org/gnome/shell/recorder/"
|
<schema id="org.gnome.shell.recorder" path="/org/gnome/shell/recorder/"
|
||||||
gettext-domain="@GETTEXT_PACKAGE@">
|
gettext-domain="@GETTEXT_PACKAGE@">
|
||||||
<key name="framerate" type="i">
|
<key name="framerate" type="i">
|
||||||
<default>30</default>
|
<default>15</default>
|
||||||
<_summary>Framerate used for recording screencasts.</_summary>
|
<_summary>Framerate used for recording screencasts.</_summary>
|
||||||
<_description>
|
<_description>
|
||||||
The framerate of the resulting screencast recordered
|
The framerate of the resulting screencast recordered
|
||||||
@@ -129,7 +127,7 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
|
|||||||
take care of its own output - this might be used to send the output
|
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 icecast server via shout2send or similar. When unset or set
|
||||||
to an empty value, the default pipeline will be used. This is currently
|
to an empty value, the default pipeline will be used. This is currently
|
||||||
'vp8enc quality=8 speed=6 threads=%T ! queue ! webmmux'
|
'videorate ! vp8enc quality=10 speed=2 threads=%T ! queue ! webmmux'
|
||||||
and records to WEBM using the VP8 codec. %T is used as a placeholder
|
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.
|
for a guess at the optimal thread count on the system.
|
||||||
</_description>
|
</_description>
|
||||||
@@ -172,14 +170,6 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
|
|||||||
</description>
|
</description>
|
||||||
</key>
|
</key>
|
||||||
|
|
||||||
<key name="dynamic-workspaces" type="b">
|
|
||||||
<default>true</default>
|
|
||||||
<summary>Workspaces are managed dynamically</summary>
|
|
||||||
<description>
|
|
||||||
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
|
||||||
</description>
|
|
||||||
</key>
|
|
||||||
|
|
||||||
<key name="workspaces-only-on-primary" type="b">
|
<key name="workspaces-only-on-primary" type="b">
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
<summary>Workspaces only on primary monitor</summary>
|
<summary>Workspaces only on primary monitor</summary>
|
||||||
27
data/shaders/dim-window.glsl
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#version 110
|
||||||
|
uniform sampler2D tex;
|
||||||
|
uniform float fraction;
|
||||||
|
uniform float height;
|
||||||
|
const float c = -0.2;
|
||||||
|
const float border_max_height = 60.0;
|
||||||
|
|
||||||
|
mat4 contrast = mat4 (1.0 + c, 0.0, 0.0, 0.0,
|
||||||
|
0.0, 1.0 + c, 0.0, 0.0,
|
||||||
|
0.0, 0.0, 1.0 + c, 0.0,
|
||||||
|
0.0, 0.0, 0.0, 1.0);
|
||||||
|
vec4 off = vec4(0.633, 0.633, 0.633, 0);
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 color = texture2D(tex, cogl_tex_coord_in[0].xy);
|
||||||
|
float y = height * cogl_tex_coord_in[0].y;
|
||||||
|
|
||||||
|
// To reduce contrast, blend with a mid gray
|
||||||
|
cogl_color_out = color * contrast - off * c * color.a;
|
||||||
|
|
||||||
|
// We only fully dim at a distance of BORDER_MAX_HEIGHT from the top and
|
||||||
|
// when the fraction is 1.0. For other locations and fractions we linearly
|
||||||
|
// interpolate back to the original undimmed color, so the top of the window
|
||||||
|
// is at full color.
|
||||||
|
cogl_color_out = color + (cogl_color_out - color) * max(min(y / border_max_height, 1.0), 0.0);
|
||||||
|
cogl_color_out = color + (cogl_color_out - color) * fraction;
|
||||||
|
}
|
||||||
@@ -10,11 +10,11 @@
|
|||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
width="29"
|
width="28"
|
||||||
height="29"
|
height="25"
|
||||||
id="svg10621"
|
id="svg10621"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
inkscape:version="0.48.2 r9819"
|
inkscape:version="0.48.1 r9760"
|
||||||
sodipodi:docname="calendar-today.svg">
|
sodipodi:docname="calendar-today.svg">
|
||||||
<defs
|
<defs
|
||||||
id="defs10623">
|
id="defs10623">
|
||||||
@@ -118,17 +118,6 @@
|
|||||||
fx="51"
|
fx="51"
|
||||||
fy="30"
|
fy="30"
|
||||||
r="42" />
|
r="42" />
|
||||||
<radialGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
xlink:href="#linearGradient34508-1-3"
|
|
||||||
id="radialGradient3113"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
|
||||||
cx="51"
|
|
||||||
cy="30"
|
|
||||||
fx="51"
|
|
||||||
fy="30"
|
|
||||||
r="42" />
|
|
||||||
</defs>
|
</defs>
|
||||||
<sodipodi:namedview
|
<sodipodi:namedview
|
||||||
id="base"
|
id="base"
|
||||||
@@ -138,29 +127,20 @@
|
|||||||
inkscape:pageopacity="0"
|
inkscape:pageopacity="0"
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:zoom="15.839192"
|
inkscape:zoom="15.839192"
|
||||||
inkscape:cx="20.652108"
|
inkscape:cx="8.3750933"
|
||||||
inkscape:cy="11.839084"
|
inkscape:cy="8.0837211"
|
||||||
inkscape:document-units="px"
|
inkscape:document-units="px"
|
||||||
inkscape:current-layer="layer1"
|
inkscape:current-layer="layer1"
|
||||||
showgrid="true"
|
showgrid="false"
|
||||||
fit-margin-top="0"
|
fit-margin-top="0"
|
||||||
fit-margin-left="0"
|
fit-margin-left="0"
|
||||||
fit-margin-right="0"
|
fit-margin-right="0"
|
||||||
fit-margin-bottom="0"
|
fit-margin-bottom="0"
|
||||||
inkscape:window-width="1280"
|
inkscape:window-width="1440"
|
||||||
inkscape:window-height="741"
|
inkscape:window-height="843"
|
||||||
inkscape:window-x="0"
|
inkscape:window-x="0"
|
||||||
inkscape:window-y="27"
|
inkscape:window-y="26"
|
||||||
inkscape:window-maximized="1"
|
inkscape:window-maximized="1" />
|
||||||
borderlayer="true">
|
|
||||||
<inkscape:grid
|
|
||||||
type="xygrid"
|
|
||||||
id="grid3109"
|
|
||||||
empspacing="5"
|
|
||||||
visible="true"
|
|
||||||
enabled="true"
|
|
||||||
snapvisiblegridlinesonly="true" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<metadata
|
<metadata
|
||||||
id="metadata10626">
|
id="metadata10626">
|
||||||
<rdf:RDF>
|
<rdf:RDF>
|
||||||
@@ -177,28 +157,31 @@
|
|||||||
inkscape:label="Layer 1"
|
inkscape:label="Layer 1"
|
||||||
inkscape:groupmode="layer"
|
inkscape:groupmode="layer"
|
||||||
id="layer1"
|
id="layer1"
|
||||||
transform="translate(-469.08263,-532.99307)">
|
transform="translate(-469.08263,-536.99307)">
|
||||||
|
<g
|
||||||
|
id="g3003">
|
||||||
<path
|
<path
|
||||||
sodipodi:type="arc"
|
inkscape:export-ydpi="90"
|
||||||
style="opacity:0.4625;color:#000000;fill:url(#radialGradient3113);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
|
||||||
id="path34506-3"
|
|
||||||
sodipodi:cx="51"
|
|
||||||
sodipodi:cy="30"
|
|
||||||
sodipodi:rx="42"
|
|
||||||
sodipodi:ry="16"
|
|
||||||
d="M 9,29.999999 A 42,16 0 0 1 93,30 l -42,0 z"
|
|
||||||
sodipodi:start="3.1415927"
|
|
||||||
sodipodi:end="6.2831853"
|
|
||||||
transform="matrix(0.43692393,0,0,1.3783114,461.29951,517.6437)"
|
|
||||||
inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/motion/textures/panel.png"
|
|
||||||
inkscape:export-xdpi="90"
|
inkscape:export-xdpi="90"
|
||||||
inkscape:export-ydpi="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
|
<rect
|
||||||
style="fill:#ffffff;fill-opacity:0.50196078;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none"
|
y="558.85046"
|
||||||
|
x="468.96878"
|
||||||
|
height="3.1425927"
|
||||||
|
width="28.149134"
|
||||||
id="rect2996"
|
id="rect2996"
|
||||||
width="31"
|
style="fill:#ffffff;fill-opacity:0.50196078;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||||
height="3"
|
</g>
|
||||||
x="468.08264"
|
|
||||||
y="558.99304" />
|
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 5.7 KiB |
@@ -1,289 +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="24"
|
|
||||||
height="22"
|
|
||||||
id="svg3199"
|
|
||||||
version="1.1"
|
|
||||||
inkscape:version="0.48.1 r9760"
|
|
||||||
sodipodi:docname="checkbox.svg">
|
|
||||||
<defs
|
|
||||||
id="defs3201">
|
|
||||||
<linearGradient
|
|
||||||
id="linearGradient15404"
|
|
||||||
inkscape:collect="always">
|
|
||||||
<stop
|
|
||||||
id="stop15406"
|
|
||||||
offset="0"
|
|
||||||
style="stop-color:#515151;stop-opacity:1" />
|
|
||||||
<stop
|
|
||||||
id="stop15408"
|
|
||||||
offset="1"
|
|
||||||
style="stop-color:#292929;stop-opacity:1" />
|
|
||||||
</linearGradient>
|
|
||||||
<inkscape:perspective
|
|
||||||
sodipodi:type="inkscape:persp3d"
|
|
||||||
inkscape:vp_x="0 : 526.18109 : 1"
|
|
||||||
inkscape:vp_y="0 : 1000 : 0"
|
|
||||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
|
||||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
|
||||||
id="perspective3207" />
|
|
||||||
<inkscape:perspective
|
|
||||||
id="perspective3187"
|
|
||||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
|
||||||
inkscape:vp_z="1 : 0.5 : 1"
|
|
||||||
inkscape:vp_y="0 : 1000 : 0"
|
|
||||||
inkscape:vp_x="0 : 0.5 : 1"
|
|
||||||
sodipodi:type="inkscape:persp3d" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
xlink:href="#linearGradient5872-5-1"
|
|
||||||
id="linearGradient5891-0-4"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
x1="205.84143"
|
|
||||||
y1="246.7094"
|
|
||||||
x2="206.74803"
|
|
||||||
y2="231.24142" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
id="linearGradient5872-5-1">
|
|
||||||
<stop
|
|
||||||
style="stop-color:#0b2e52;stop-opacity:1"
|
|
||||||
offset="0"
|
|
||||||
id="stop5874-4-4" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#1862af;stop-opacity:1"
|
|
||||||
offset="1"
|
|
||||||
id="stop5876-0-5" />
|
|
||||||
</linearGradient>
|
|
||||||
<inkscape:path-effect
|
|
||||||
effect="spiro"
|
|
||||||
id="path-effect5837-4-6"
|
|
||||||
is_visible="true" />
|
|
||||||
<inkscape:path-effect
|
|
||||||
effect="spiro"
|
|
||||||
id="path-effect14768"
|
|
||||||
is_visible="true" />
|
|
||||||
<inkscape:path-effect
|
|
||||||
effect="spiro"
|
|
||||||
id="path-effect5884-4-7"
|
|
||||||
is_visible="true" />
|
|
||||||
<linearGradient
|
|
||||||
y2="-388.72955"
|
|
||||||
x2="-93.031357"
|
|
||||||
y1="-396.34738"
|
|
||||||
x1="-93.031357"
|
|
||||||
gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.685418)"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
id="linearGradient14219"
|
|
||||||
xlink:href="#linearGradient15404"
|
|
||||||
inkscape:collect="always" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
id="linearGradient10013-4-63-6">
|
|
||||||
<stop
|
|
||||||
style="stop-color:#333333;stop-opacity:1;"
|
|
||||||
offset="0"
|
|
||||||
id="stop10015-2-76-1" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#292929;stop-opacity:1"
|
|
||||||
offset="1"
|
|
||||||
id="stop10017-46-15-8" />
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
id="linearGradient10597-5">
|
|
||||||
<stop
|
|
||||||
style="stop-color:#16191a;stop-opacity:1;"
|
|
||||||
offset="0"
|
|
||||||
id="stop10599-2" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#2b3133;stop-opacity:1"
|
|
||||||
offset="1"
|
|
||||||
id="stop10601-5" />
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient
|
|
||||||
y2="-322.16354"
|
|
||||||
x2="921.22498"
|
|
||||||
y1="-330.05121"
|
|
||||||
x1="921.32812"
|
|
||||||
gradientTransform="matrix(1.5918367,0,0,0.85714285,-1456.5464,275.45191)"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
id="linearGradient15374"
|
|
||||||
xlink:href="#linearGradient10013-4-63-6"
|
|
||||||
inkscape:collect="always" />
|
|
||||||
<linearGradient
|
|
||||||
gradientTransform="translate(-1199.9852,216.38048)"
|
|
||||||
y2="-227.07961"
|
|
||||||
x2="1203.9177"
|
|
||||||
y1="-217.56708"
|
|
||||||
x1="1203.9177"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
id="linearGradient15376"
|
|
||||||
xlink:href="#linearGradient10597-5"
|
|
||||||
inkscape:collect="always" />
|
|
||||||
<linearGradient
|
|
||||||
y2="-388.72955"
|
|
||||||
x2="-93.031357"
|
|
||||||
y1="-396.34738"
|
|
||||||
x1="-93.031357"
|
|
||||||
gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.685418)"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
id="linearGradient14219-6"
|
|
||||||
xlink:href="#linearGradient15404-9"
|
|
||||||
inkscape:collect="always" />
|
|
||||||
<linearGradient
|
|
||||||
id="linearGradient15404-9"
|
|
||||||
inkscape:collect="always">
|
|
||||||
<stop
|
|
||||||
id="stop15406-6"
|
|
||||||
offset="0"
|
|
||||||
style="stop-color:#515151;stop-opacity:1" />
|
|
||||||
<stop
|
|
||||||
id="stop15408-7"
|
|
||||||
offset="1"
|
|
||||||
style="stop-color:#292929;stop-opacity:1" />
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#000000"
|
|
||||||
bordercolor="#2d2d2d"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:pageopacity="1"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="1"
|
|
||||||
inkscape:cx="71.516955"
|
|
||||||
inkscape:cy="5.8710559"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:window-width="1412"
|
|
||||||
inkscape:window-height="1067"
|
|
||||||
inkscape:window-x="2635"
|
|
||||||
inkscape:window-y="226"
|
|
||||||
inkscape:window-maximized="0"
|
|
||||||
borderlayer="true"
|
|
||||||
inkscape:showpageshadow="false"
|
|
||||||
inkscape:snap-nodes="false"
|
|
||||||
inkscape:snap-bbox="true"
|
|
||||||
showborder="false">
|
|
||||||
<inkscape:grid
|
|
||||||
type="xygrid"
|
|
||||||
id="grid14843"
|
|
||||||
empspacing="5"
|
|
||||||
visible="true"
|
|
||||||
enabled="true"
|
|
||||||
snapvisiblegridlinesonly="true" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<metadata
|
|
||||||
id="metadata3204">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title></dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(-342.5,-521.36218)">
|
|
||||||
<g
|
|
||||||
transform="matrix(0.80230061,0,0,0.80230061,-87.624044,-453.10297)"
|
|
||||||
id="g14586-0"
|
|
||||||
style="stroke-width:2.3714385;stroke-miterlimit:4;stroke-dasharray:none">
|
|
||||||
<g
|
|
||||||
inkscape:export-ydpi="90"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
|
||||||
transform="matrix(1.9969286,0,0,1.9969286,-397.05491,877.00482)"
|
|
||||||
id="g15291-9-6"
|
|
||||||
style="stroke-width:1.18754292;stroke-miterlimit:4;stroke-dasharray:none;display:inline;enable-background:new">
|
|
||||||
<g
|
|
||||||
transform="translate(877.50354,-102.83507)"
|
|
||||||
id="g16853-4-9"
|
|
||||||
style="stroke-width:1.18754292;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new">
|
|
||||||
<rect
|
|
||||||
transform="scale(1,-1)"
|
|
||||||
style="color:#000000;fill:url(#linearGradient14219-6);fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:1.24833274;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new"
|
|
||||||
id="rect6506-6"
|
|
||||||
width="11.281681"
|
|
||||||
height="11.26221"
|
|
||||||
x="-409.59354"
|
|
||||||
y="-284.40115"
|
|
||||||
rx="1.0052766"
|
|
||||||
ry="1.0052764" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
inkscape:export-ydpi="90"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
|
||||||
transform="translate(343.99999,987.99997)"
|
|
||||||
id="g5886-5"
|
|
||||||
style="stroke-width:2.3714385;stroke-miterlimit:4;stroke-dasharray:none;display:inline;enable-background:new" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
transform="matrix(0.84337,0,0,0.84337,-110.16632,-503.56182)"
|
|
||||||
id="g14586">
|
|
||||||
<g
|
|
||||||
inkscape:export-ydpi="90"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
|
||||||
transform="matrix(1.9969286,0,0,1.9969286,-397.05491,877.00482)"
|
|
||||||
id="g15291-9"
|
|
||||||
style="display:inline;enable-background:new">
|
|
||||||
<g
|
|
||||||
transform="translate(877.50354,-102.83507)"
|
|
||||||
id="g16853-4"
|
|
||||||
style="enable-background:new" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
inkscape:export-ydpi="90"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
|
||||||
transform="translate(343.99999,987.99997)"
|
|
||||||
id="g5886"
|
|
||||||
style="display:inline;enable-background:new">
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:url(#linearGradient5891-0-4);stroke-width:7.11431503;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 198.5,240 5.25,5.25 13.98616,-14.43081"
|
|
||||||
id="path5835"
|
|
||||||
inkscape:path-effect="#path-effect5837-4-6"
|
|
||||||
inkscape:original-d="m 198.5,240 5.25,5.25 13.98616,-14.43081"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="ccc" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
inkscape:original-d="m 198.5,240 5.25,5.25 13.91205,-14.31964"
|
|
||||||
inkscape:path-effect="#path-effect5837-4-6"
|
|
||||||
id="path5880"
|
|
||||||
d="m 198.5,240 5.25,5.25 13.91205,-14.31964"
|
|
||||||
style="fill:none;stroke:#4787c8;stroke-width:3.55715752;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
sodipodi:nodetypes="ccc" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#7ea7d3;stroke-width:1.18571913px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="m 197.45937,240.47455 c -0.17828,-0.29362 -0.20087,-0.67548 -0.0603,-0.98892 0.14055,-0.31344 0.43739,-0.54812 0.77144,-0.62817 0.33405,-0.08 0.69314,-0.01 0.99635,0.15175 0.30321,0.16144 0.55146,0.40727 0.79165,0.65284 l 3.66429,3.74643 12.87946,-12.98973 c 0.20796,-0.20974 0.42306,-0.41969 0.68548,-0.55522 0.26242,-0.13553 0.57293,-0.19052 0.85827,-0.11426 0.14267,0.0381 0.27708,0.10787 0.38874,0.20452 0.11167,0.0966 0.20021,0.22004 0.25479,0.35726 0.0546,0.13722 0.075,0.28793 0.0585,0.43468 -0.0165,0.14674 -0.07,0.28919 -0.15422,0.41052"
|
|
||||||
id="path5882"
|
|
||||||
inkscape:path-effect="#path-effect5884-4-7"
|
|
||||||
inkscape:original-d="m 197.45937,240.47455 c 0.65604,-0.56057 2.02485,-1.34847 2.49911,-0.8125 l 3.66429,3.74643 12.87946,-12.98973 c 0.6875,-0.6875 2.09152,0.7375 2.09152,0.7375"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="csccc" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 11 KiB |
@@ -1,198 +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="24"
|
|
||||||
height="22"
|
|
||||||
id="svg3199"
|
|
||||||
version="1.1"
|
|
||||||
inkscape:version="0.48.1 r9760"
|
|
||||||
sodipodi:docname="checkbox-off.svg">
|
|
||||||
<defs
|
|
||||||
id="defs3201">
|
|
||||||
<linearGradient
|
|
||||||
id="linearGradient15404"
|
|
||||||
inkscape:collect="always">
|
|
||||||
<stop
|
|
||||||
id="stop15406"
|
|
||||||
offset="0"
|
|
||||||
style="stop-color:#515151;stop-opacity:1" />
|
|
||||||
<stop
|
|
||||||
id="stop15408"
|
|
||||||
offset="1"
|
|
||||||
style="stop-color:#292929;stop-opacity:1" />
|
|
||||||
</linearGradient>
|
|
||||||
<inkscape:perspective
|
|
||||||
sodipodi:type="inkscape:persp3d"
|
|
||||||
inkscape:vp_x="0 : 526.18109 : 1"
|
|
||||||
inkscape:vp_y="0 : 1000 : 0"
|
|
||||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
|
||||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
|
||||||
id="perspective3207" />
|
|
||||||
<inkscape:perspective
|
|
||||||
id="perspective3187"
|
|
||||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
|
||||||
inkscape:vp_z="1 : 0.5 : 1"
|
|
||||||
inkscape:vp_y="0 : 1000 : 0"
|
|
||||||
inkscape:vp_x="0 : 0.5 : 1"
|
|
||||||
sodipodi:type="inkscape:persp3d" />
|
|
||||||
<inkscape:path-effect
|
|
||||||
effect="spiro"
|
|
||||||
id="path-effect5837-4-6"
|
|
||||||
is_visible="true" />
|
|
||||||
<inkscape:path-effect
|
|
||||||
effect="spiro"
|
|
||||||
id="path-effect14768"
|
|
||||||
is_visible="true" />
|
|
||||||
<inkscape:path-effect
|
|
||||||
effect="spiro"
|
|
||||||
id="path-effect5884-4-7"
|
|
||||||
is_visible="true" />
|
|
||||||
<linearGradient
|
|
||||||
y2="-388.72955"
|
|
||||||
x2="-93.031357"
|
|
||||||
y1="-396.34738"
|
|
||||||
x1="-93.031357"
|
|
||||||
gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.685418)"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
id="linearGradient14219"
|
|
||||||
xlink:href="#linearGradient15404"
|
|
||||||
inkscape:collect="always" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
id="linearGradient10013-4-63-6">
|
|
||||||
<stop
|
|
||||||
style="stop-color:#333333;stop-opacity:1;"
|
|
||||||
offset="0"
|
|
||||||
id="stop10015-2-76-1" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#292929;stop-opacity:1"
|
|
||||||
offset="1"
|
|
||||||
id="stop10017-46-15-8" />
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
id="linearGradient10597-5">
|
|
||||||
<stop
|
|
||||||
style="stop-color:#16191a;stop-opacity:1;"
|
|
||||||
offset="0"
|
|
||||||
id="stop10599-2" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#2b3133;stop-opacity:1"
|
|
||||||
offset="1"
|
|
||||||
id="stop10601-5" />
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient
|
|
||||||
y2="-322.16354"
|
|
||||||
x2="921.22498"
|
|
||||||
y1="-330.05121"
|
|
||||||
x1="921.32812"
|
|
||||||
gradientTransform="matrix(1.5918367,0,0,0.85714285,-1456.5464,275.45191)"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
id="linearGradient15374"
|
|
||||||
xlink:href="#linearGradient10013-4-63-6"
|
|
||||||
inkscape:collect="always" />
|
|
||||||
<linearGradient
|
|
||||||
gradientTransform="translate(-1199.9852,216.38048)"
|
|
||||||
y2="-227.07961"
|
|
||||||
x2="1203.9177"
|
|
||||||
y1="-217.56708"
|
|
||||||
x1="1203.9177"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
id="linearGradient15376"
|
|
||||||
xlink:href="#linearGradient10597-5"
|
|
||||||
inkscape:collect="always" />
|
|
||||||
</defs>
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#000000"
|
|
||||||
bordercolor="#2d2d2d"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:pageopacity="1"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="1"
|
|
||||||
inkscape:cx="6.1225392"
|
|
||||||
inkscape:cy="3.6003241"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:window-width="1412"
|
|
||||||
inkscape:window-height="1067"
|
|
||||||
inkscape:window-x="2116"
|
|
||||||
inkscape:window-y="261"
|
|
||||||
inkscape:window-maximized="0"
|
|
||||||
borderlayer="true"
|
|
||||||
inkscape:showpageshadow="false"
|
|
||||||
inkscape:snap-nodes="false"
|
|
||||||
inkscape:snap-bbox="true"
|
|
||||||
showborder="false">
|
|
||||||
<inkscape:grid
|
|
||||||
type="xygrid"
|
|
||||||
id="grid14843"
|
|
||||||
empspacing="5"
|
|
||||||
visible="true"
|
|
||||||
enabled="true"
|
|
||||||
snapvisiblegridlinesonly="true" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<metadata
|
|
||||||
id="metadata3204">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title></dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(-342.5,-521.36218)">
|
|
||||||
<g
|
|
||||||
transform="matrix(0.80230061,0,0,0.80230061,-87.624044,-453.10297)"
|
|
||||||
id="g14586"
|
|
||||||
style="stroke-width:2.3714385;stroke-miterlimit:4;stroke-dasharray:none">
|
|
||||||
<g
|
|
||||||
inkscape:export-ydpi="90"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
|
||||||
transform="matrix(1.9969286,0,0,1.9969286,-397.05491,877.00482)"
|
|
||||||
id="g15291-9"
|
|
||||||
style="stroke-width:1.18754292;stroke-miterlimit:4;stroke-dasharray:none;display:inline;enable-background:new">
|
|
||||||
<g
|
|
||||||
transform="translate(877.50354,-102.83507)"
|
|
||||||
id="g16853-4"
|
|
||||||
style="stroke-width:1.18754292;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new">
|
|
||||||
<rect
|
|
||||||
transform="scale(1,-1)"
|
|
||||||
style="color:#000000;fill:url(#linearGradient14219);fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:1.24833274;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new"
|
|
||||||
id="rect6506-6"
|
|
||||||
width="11.281681"
|
|
||||||
height="11.26221"
|
|
||||||
x="-409.59354"
|
|
||||||
y="-284.40115"
|
|
||||||
rx="1.0052766"
|
|
||||||
ry="1.0052764" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
inkscape:export-ydpi="90"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
|
||||||
transform="translate(343.99999,987.99997)"
|
|
||||||
id="g5886"
|
|
||||||
style="stroke-width:2.3714385;stroke-miterlimit:4;stroke-dasharray:none;display:inline;enable-background:new" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 6.5 KiB |
@@ -1,218 +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="24"
|
|
||||||
height="22"
|
|
||||||
id="svg3199"
|
|
||||||
version="1.1"
|
|
||||||
inkscape:version="0.48.1 r9760"
|
|
||||||
sodipodi:docname="checkbox.svg">
|
|
||||||
<defs
|
|
||||||
id="defs3201">
|
|
||||||
<linearGradient
|
|
||||||
id="linearGradient15404"
|
|
||||||
inkscape:collect="always">
|
|
||||||
<stop
|
|
||||||
id="stop15406"
|
|
||||||
offset="0"
|
|
||||||
style="stop-color:#515151;stop-opacity:1" />
|
|
||||||
<stop
|
|
||||||
id="stop15408"
|
|
||||||
offset="1"
|
|
||||||
style="stop-color:#292929;stop-opacity:1" />
|
|
||||||
</linearGradient>
|
|
||||||
<inkscape:perspective
|
|
||||||
sodipodi:type="inkscape:persp3d"
|
|
||||||
inkscape:vp_x="0 : 526.18109 : 1"
|
|
||||||
inkscape:vp_y="0 : 1000 : 0"
|
|
||||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
|
||||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
|
||||||
id="perspective3207" />
|
|
||||||
<inkscape:perspective
|
|
||||||
id="perspective3187"
|
|
||||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
|
||||||
inkscape:vp_z="1 : 0.5 : 1"
|
|
||||||
inkscape:vp_y="0 : 1000 : 0"
|
|
||||||
inkscape:vp_x="0 : 0.5 : 1"
|
|
||||||
sodipodi:type="inkscape:persp3d" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
xlink:href="#linearGradient5872-5-1"
|
|
||||||
id="linearGradient5891-0-4"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
x1="205.84143"
|
|
||||||
y1="246.7094"
|
|
||||||
x2="206.74803"
|
|
||||||
y2="231.24142" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
id="linearGradient5872-5-1">
|
|
||||||
<stop
|
|
||||||
style="stop-color:#0b2e52;stop-opacity:1"
|
|
||||||
offset="0"
|
|
||||||
id="stop5874-4-4" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#1862af;stop-opacity:1"
|
|
||||||
offset="1"
|
|
||||||
id="stop5876-0-5" />
|
|
||||||
</linearGradient>
|
|
||||||
<inkscape:path-effect
|
|
||||||
effect="spiro"
|
|
||||||
id="path-effect5837-4-6"
|
|
||||||
is_visible="true" />
|
|
||||||
<inkscape:path-effect
|
|
||||||
effect="spiro"
|
|
||||||
id="path-effect14768"
|
|
||||||
is_visible="true" />
|
|
||||||
<inkscape:path-effect
|
|
||||||
effect="spiro"
|
|
||||||
id="path-effect5884-4-7"
|
|
||||||
is_visible="true" />
|
|
||||||
<linearGradient
|
|
||||||
y2="-388.72955"
|
|
||||||
x2="-93.031357"
|
|
||||||
y1="-396.34738"
|
|
||||||
x1="-93.031357"
|
|
||||||
gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.685418)"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
id="linearGradient14219"
|
|
||||||
xlink:href="#linearGradient15404"
|
|
||||||
inkscape:collect="always" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
id="linearGradient10013-4-63-6">
|
|
||||||
<stop
|
|
||||||
style="stop-color:#333333;stop-opacity:1;"
|
|
||||||
offset="0"
|
|
||||||
id="stop10015-2-76-1" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#292929;stop-opacity:1"
|
|
||||||
offset="1"
|
|
||||||
id="stop10017-46-15-8" />
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
id="linearGradient10597-5">
|
|
||||||
<stop
|
|
||||||
style="stop-color:#16191a;stop-opacity:1;"
|
|
||||||
offset="0"
|
|
||||||
id="stop10599-2" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#2b3133;stop-opacity:1"
|
|
||||||
offset="1"
|
|
||||||
id="stop10601-5" />
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient
|
|
||||||
y2="-322.16354"
|
|
||||||
x2="921.22498"
|
|
||||||
y1="-330.05121"
|
|
||||||
x1="921.32812"
|
|
||||||
gradientTransform="matrix(1.5918367,0,0,0.85714285,-1456.5464,275.45191)"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
id="linearGradient15374"
|
|
||||||
xlink:href="#linearGradient10013-4-63-6"
|
|
||||||
inkscape:collect="always" />
|
|
||||||
<linearGradient
|
|
||||||
gradientTransform="translate(-1199.9852,216.38048)"
|
|
||||||
y2="-227.07961"
|
|
||||||
x2="1203.9177"
|
|
||||||
y1="-217.56708"
|
|
||||||
x1="1203.9177"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
id="linearGradient15376"
|
|
||||||
xlink:href="#linearGradient10597-5"
|
|
||||||
inkscape:collect="always" />
|
|
||||||
</defs>
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#000000"
|
|
||||||
bordercolor="#2d2d2d"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:pageopacity="1"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="4"
|
|
||||||
inkscape:cx="71.247925"
|
|
||||||
inkscape:cy="33.339093"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:window-width="1412"
|
|
||||||
inkscape:window-height="1067"
|
|
||||||
inkscape:window-x="2116"
|
|
||||||
inkscape:window-y="261"
|
|
||||||
inkscape:window-maximized="0"
|
|
||||||
borderlayer="true"
|
|
||||||
inkscape:showpageshadow="false"
|
|
||||||
inkscape:snap-nodes="false"
|
|
||||||
inkscape:snap-bbox="true"
|
|
||||||
showborder="false">
|
|
||||||
<inkscape:grid
|
|
||||||
type="xygrid"
|
|
||||||
id="grid14843"
|
|
||||||
empspacing="5"
|
|
||||||
visible="true"
|
|
||||||
enabled="true"
|
|
||||||
snapvisiblegridlinesonly="true" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<metadata
|
|
||||||
id="metadata3204">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title></dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(-342.5,-521.36218)">
|
|
||||||
<g
|
|
||||||
transform="matrix(0.84337,0,0,0.84337,-110.16632,-503.56182)"
|
|
||||||
id="g14586">
|
|
||||||
<g
|
|
||||||
inkscape:export-ydpi="90"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
|
||||||
transform="matrix(1.9969286,0,0,1.9969286,-397.05491,877.00482)"
|
|
||||||
id="g15291-9"
|
|
||||||
style="display:inline;enable-background:new">
|
|
||||||
<g
|
|
||||||
transform="translate(877.50354,-102.83507)"
|
|
||||||
id="g16853-4"
|
|
||||||
style="enable-background:new">
|
|
||||||
<rect
|
|
||||||
transform="scale(1,-1)"
|
|
||||||
style="color:#000000;fill:url(#linearGradient14219);fill-opacity:1;fill-rule:nonzero;stroke:#868686;stroke-width:0.59377144999999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new"
|
|
||||||
id="rect6506-6"
|
|
||||||
width="11.281681"
|
|
||||||
height="11.26221"
|
|
||||||
x="-409.59354"
|
|
||||||
y="-284.40115"
|
|
||||||
rx="0.95632279"
|
|
||||||
ry="0.95632273" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
inkscape:export-ydpi="90"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
|
||||||
transform="translate(343.99999,987.99997)"
|
|
||||||
id="g5886"
|
|
||||||
style="display:inline;enable-background:new" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 6.8 KiB |
@@ -1,243 +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="24"
|
|
||||||
height="22"
|
|
||||||
id="svg3199"
|
|
||||||
version="1.1"
|
|
||||||
inkscape:version="0.48.1 r9760"
|
|
||||||
sodipodi:docname="checkbox-focused.svg">
|
|
||||||
<defs
|
|
||||||
id="defs3201">
|
|
||||||
<linearGradient
|
|
||||||
id="linearGradient15404"
|
|
||||||
inkscape:collect="always">
|
|
||||||
<stop
|
|
||||||
id="stop15406"
|
|
||||||
offset="0"
|
|
||||||
style="stop-color:#515151;stop-opacity:1" />
|
|
||||||
<stop
|
|
||||||
id="stop15408"
|
|
||||||
offset="1"
|
|
||||||
style="stop-color:#292929;stop-opacity:1" />
|
|
||||||
</linearGradient>
|
|
||||||
<inkscape:perspective
|
|
||||||
sodipodi:type="inkscape:persp3d"
|
|
||||||
inkscape:vp_x="0 : 526.18109 : 1"
|
|
||||||
inkscape:vp_y="0 : 1000 : 0"
|
|
||||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
|
||||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
|
||||||
id="perspective3207" />
|
|
||||||
<inkscape:perspective
|
|
||||||
id="perspective3187"
|
|
||||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
|
||||||
inkscape:vp_z="1 : 0.5 : 1"
|
|
||||||
inkscape:vp_y="0 : 1000 : 0"
|
|
||||||
inkscape:vp_x="0 : 0.5 : 1"
|
|
||||||
sodipodi:type="inkscape:persp3d" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
xlink:href="#linearGradient5872-5-1"
|
|
||||||
id="linearGradient5891-0-4"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
x1="205.84143"
|
|
||||||
y1="246.7094"
|
|
||||||
x2="206.74803"
|
|
||||||
y2="231.24142" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
id="linearGradient5872-5-1">
|
|
||||||
<stop
|
|
||||||
style="stop-color:#0b2e52;stop-opacity:1"
|
|
||||||
offset="0"
|
|
||||||
id="stop5874-4-4" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#1862af;stop-opacity:1"
|
|
||||||
offset="1"
|
|
||||||
id="stop5876-0-5" />
|
|
||||||
</linearGradient>
|
|
||||||
<inkscape:path-effect
|
|
||||||
effect="spiro"
|
|
||||||
id="path-effect5837-4-6"
|
|
||||||
is_visible="true" />
|
|
||||||
<inkscape:path-effect
|
|
||||||
effect="spiro"
|
|
||||||
id="path-effect14768"
|
|
||||||
is_visible="true" />
|
|
||||||
<inkscape:path-effect
|
|
||||||
effect="spiro"
|
|
||||||
id="path-effect5884-4-7"
|
|
||||||
is_visible="true" />
|
|
||||||
<linearGradient
|
|
||||||
y2="-388.72955"
|
|
||||||
x2="-93.031357"
|
|
||||||
y1="-396.34738"
|
|
||||||
x1="-93.031357"
|
|
||||||
gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.685418)"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
id="linearGradient14219"
|
|
||||||
xlink:href="#linearGradient15404"
|
|
||||||
inkscape:collect="always" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
id="linearGradient10013-4-63-6">
|
|
||||||
<stop
|
|
||||||
style="stop-color:#333333;stop-opacity:1;"
|
|
||||||
offset="0"
|
|
||||||
id="stop10015-2-76-1" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#292929;stop-opacity:1"
|
|
||||||
offset="1"
|
|
||||||
id="stop10017-46-15-8" />
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
id="linearGradient10597-5">
|
|
||||||
<stop
|
|
||||||
style="stop-color:#16191a;stop-opacity:1;"
|
|
||||||
offset="0"
|
|
||||||
id="stop10599-2" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#2b3133;stop-opacity:1"
|
|
||||||
offset="1"
|
|
||||||
id="stop10601-5" />
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient
|
|
||||||
y2="-322.16354"
|
|
||||||
x2="921.22498"
|
|
||||||
y1="-330.05121"
|
|
||||||
x1="921.32812"
|
|
||||||
gradientTransform="matrix(1.5918367,0,0,0.85714285,-1456.5464,275.45191)"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
id="linearGradient15374"
|
|
||||||
xlink:href="#linearGradient10013-4-63-6"
|
|
||||||
inkscape:collect="always" />
|
|
||||||
<linearGradient
|
|
||||||
gradientTransform="translate(-1199.9852,216.38048)"
|
|
||||||
y2="-227.07961"
|
|
||||||
x2="1203.9177"
|
|
||||||
y1="-217.56708"
|
|
||||||
x1="1203.9177"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
id="linearGradient15376"
|
|
||||||
xlink:href="#linearGradient10597-5"
|
|
||||||
inkscape:collect="always" />
|
|
||||||
</defs>
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#000000"
|
|
||||||
bordercolor="#2d2d2d"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:pageopacity="1"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="1"
|
|
||||||
inkscape:cx="64.516955"
|
|
||||||
inkscape:cy="13.871056"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:window-width="1412"
|
|
||||||
inkscape:window-height="1067"
|
|
||||||
inkscape:window-x="2635"
|
|
||||||
inkscape:window-y="226"
|
|
||||||
inkscape:window-maximized="0"
|
|
||||||
borderlayer="true"
|
|
||||||
inkscape:showpageshadow="false"
|
|
||||||
inkscape:snap-nodes="false"
|
|
||||||
inkscape:snap-bbox="true"
|
|
||||||
showborder="false">
|
|
||||||
<inkscape:grid
|
|
||||||
type="xygrid"
|
|
||||||
id="grid14843"
|
|
||||||
empspacing="5"
|
|
||||||
visible="true"
|
|
||||||
enabled="true"
|
|
||||||
snapvisiblegridlinesonly="true" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<metadata
|
|
||||||
id="metadata3204">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title></dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(-342.5,-521.36218)">
|
|
||||||
<g
|
|
||||||
transform="matrix(0.84337,0,0,0.84337,-110.16632,-503.56182)"
|
|
||||||
id="g14586">
|
|
||||||
<g
|
|
||||||
inkscape:export-ydpi="90"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
|
||||||
transform="matrix(1.9969286,0,0,1.9969286,-397.05491,877.00482)"
|
|
||||||
id="g15291-9"
|
|
||||||
style="display:inline;enable-background:new">
|
|
||||||
<g
|
|
||||||
transform="translate(877.50354,-102.83507)"
|
|
||||||
id="g16853-4"
|
|
||||||
style="enable-background:new">
|
|
||||||
<rect
|
|
||||||
transform="scale(1,-1)"
|
|
||||||
style="color:#000000;fill:url(#linearGradient14219);fill-opacity:1;fill-rule:nonzero;stroke:#868686;stroke-width:0.59377144999999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new"
|
|
||||||
id="rect6506-6"
|
|
||||||
width="11.281681"
|
|
||||||
height="11.26221"
|
|
||||||
x="-409.59354"
|
|
||||||
y="-284.40115"
|
|
||||||
rx="0.95632279"
|
|
||||||
ry="0.95632273" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
inkscape:export-ydpi="90"
|
|
||||||
inkscape:export-xdpi="90"
|
|
||||||
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
|
||||||
transform="translate(343.99999,987.99997)"
|
|
||||||
id="g5886"
|
|
||||||
style="display:inline;enable-background:new">
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:url(#linearGradient5891-0-4);stroke-width:7.11431503;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
d="m 198.5,240 5.25,5.25 13.98616,-14.43081"
|
|
||||||
id="path5835"
|
|
||||||
inkscape:path-effect="#path-effect5837-4-6"
|
|
||||||
inkscape:original-d="m 198.5,240 5.25,5.25 13.98616,-14.43081"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="ccc" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
inkscape:original-d="m 198.5,240 5.25,5.25 13.91205,-14.31964"
|
|
||||||
inkscape:path-effect="#path-effect5837-4-6"
|
|
||||||
id="path5880"
|
|
||||||
d="m 198.5,240 5.25,5.25 13.91205,-14.31964"
|
|
||||||
style="fill:none;stroke:#4787c8;stroke-width:3.55715752;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
sodipodi:nodetypes="ccc" />
|
|
||||||
<path
|
|
||||||
style="fill:none;stroke:#7ea7d3;stroke-width:1.18571913px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="m 197.45937,240.47455 c -0.17828,-0.29362 -0.20087,-0.67548 -0.0603,-0.98892 0.14055,-0.31344 0.43739,-0.54812 0.77144,-0.62817 0.33405,-0.08 0.69314,-0.01 0.99635,0.15175 0.30321,0.16144 0.55146,0.40727 0.79165,0.65284 l 3.66429,3.74643 12.87946,-12.98973 c 0.20796,-0.20974 0.42306,-0.41969 0.68548,-0.55522 0.26242,-0.13553 0.57293,-0.19052 0.85827,-0.11426 0.14267,0.0381 0.27708,0.10787 0.38874,0.20452 0.11167,0.0966 0.20021,0.22004 0.25479,0.35726 0.0546,0.13722 0.075,0.28793 0.0585,0.43468 -0.0165,0.14674 -0.07,0.28919 -0.15422,0.41052"
|
|
||||||
id="path5882"
|
|
||||||
inkscape:path-effect="#path-effect5884-4-7"
|
|
||||||
inkscape:original-d="m 197.45937,240.47455 c 0.65604,-0.56057 2.02485,-1.34847 2.49911,-0.8125 l 3.66429,3.74643 12.87946,-12.98973 c 0.6875,-0.6875 2.09152,0.7375 2.09152,0.7375"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="csccc" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 8.8 KiB |
180
data/theme/gdm.css
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
/* Copyright 2011, Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU Lesser General Public License,
|
||||||
|
* version 2.1, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Login Dialog */
|
||||||
|
|
||||||
|
.login-dialog-title {
|
||||||
|
font-size: 14pt;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #666666;
|
||||||
|
padding-bottom: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog {
|
||||||
|
border-radius: 16px;
|
||||||
|
min-height: 150px;
|
||||||
|
max-height: 700px;
|
||||||
|
min-width: 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-prompt-fingerprint-message {
|
||||||
|
font-size: 10.5pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-user-list-view {
|
||||||
|
-st-vfade-offset: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-user-list {
|
||||||
|
spacing: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-user-list-item {
|
||||||
|
color: #666666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-user-list-item:ltr {
|
||||||
|
padding-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-user-list-item:rtl {
|
||||||
|
padding-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-user-list-item .login-dialog-user-list-item-name {
|
||||||
|
font-size: 20pt;
|
||||||
|
padding-left: 1em;
|
||||||
|
color: #666666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-user-list-item:hover .login-dialog-user-list-item-name {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-user-list-item:focus .login-dialog-user-list-item-name {
|
||||||
|
color: white;
|
||||||
|
text-shadow: black 0px 2px 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-user-list-item-vertical-layout {
|
||||||
|
spacing: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-user-list-item .login-dialog-user-list-item-focus-bin {
|
||||||
|
background-color: rgba(0,0,0,0.0);
|
||||||
|
height: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-user-list-item:focus .login-dialog-user-list-item-focus-bin {
|
||||||
|
background-color: #666666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-user-list-item-icon {
|
||||||
|
border: 2px solid #8b8b8b;
|
||||||
|
border-radius: 8px;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-not-listed-button {
|
||||||
|
padding-top: 2em;
|
||||||
|
}
|
||||||
|
.login-dialog-not-listed-label {
|
||||||
|
font-size: 14pt;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #666666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-not-listed-button:hover .login-dialog-not-listed-label {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-prompt-layout {
|
||||||
|
padding-bottom: 32px;
|
||||||
|
}
|
||||||
|
.login-dialog-prompt-label {
|
||||||
|
color: white;
|
||||||
|
font-size: 20pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-prompt-entry {
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 2px solid #5656cc;
|
||||||
|
color: black;
|
||||||
|
background-color: white;
|
||||||
|
caret-color: black;
|
||||||
|
caret-size: 1px;
|
||||||
|
width: 15em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-prompt-entry .capslock-warning {
|
||||||
|
icon-size: 16px;
|
||||||
|
warning-color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-prompt-entry:insensitive {
|
||||||
|
color: rgba(0,0,0,0.7);
|
||||||
|
border: 2px solid #565656;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-session-list {
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 10.5pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-session-list-button {
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-session-list-button:focus {
|
||||||
|
background-color: #4c4c4c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-session-list-button:active {
|
||||||
|
background-color: #4c4c4c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-session-list-button:hover {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-session-list-scroll-view {
|
||||||
|
background-gradient-start: rgba(80,80,80,0.3);
|
||||||
|
background-gradient-end: rgba(80,80,80,0.7);
|
||||||
|
background-gradient-direction: vertical;
|
||||||
|
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9);
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid rgba(80,80,80,1.0);
|
||||||
|
padding: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-session-list-item:focus {
|
||||||
|
background-color: #666666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-session-list-triangle {
|
||||||
|
padding-right: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-session-list-item-box {
|
||||||
|
spacing: .25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-session-list-item-dot {
|
||||||
|
width: .75em;
|
||||||
|
height: .75em;
|
||||||
|
}
|
||||||
@@ -1,130 +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="300"
|
|
||||||
height="80"
|
|
||||||
id="svg7355"
|
|
||||||
version="1.1"
|
|
||||||
inkscape:version="0.48.2 r9819"
|
|
||||||
sodipodi:docname="logged-in-indicator.svg">
|
|
||||||
<metadata
|
|
||||||
id="metadata4175">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<sodipodi:namedview
|
|
||||||
pagecolor="#2c1cff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1"
|
|
||||||
objecttolerance="10"
|
|
||||||
gridtolerance="10"
|
|
||||||
guidetolerance="10"
|
|
||||||
inkscape:pageopacity="1"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:window-width="1440"
|
|
||||||
inkscape:window-height="843"
|
|
||||||
id="namedview4173"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="2.8760889"
|
|
||||||
inkscape:cx="106.00403"
|
|
||||||
inkscape:cy="80.68078"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="27"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="g30864" />
|
|
||||||
<defs
|
|
||||||
id="defs7357">
|
|
||||||
<radialGradient
|
|
||||||
xlink:href="#linearGradient36429"
|
|
||||||
id="radialGradient7461"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
gradientTransform="matrix(2.5919312,0,0,0.57582113,-20.687059,48.400487)"
|
|
||||||
cx="47.428951"
|
|
||||||
cy="167.16817"
|
|
||||||
fx="47.428951"
|
|
||||||
fy="167.16817"
|
|
||||||
r="37" />
|
|
||||||
<linearGradient
|
|
||||||
id="linearGradient36429">
|
|
||||||
<stop
|
|
||||||
id="stop36431"
|
|
||||||
offset="0"
|
|
||||||
style="stop-color:#ffffff;stop-opacity:1;" />
|
|
||||||
<stop
|
|
||||||
id="stop36433"
|
|
||||||
offset="1"
|
|
||||||
style="stop-color:#ffffff;stop-opacity:0;" />
|
|
||||||
</linearGradient>
|
|
||||||
<radialGradient
|
|
||||||
xlink:href="#linearGradient36471"
|
|
||||||
id="radialGradient7463"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
gradientTransform="matrix(1.1891549,0,0,0.55513246,-9.281289,36.12653)"
|
|
||||||
cx="49.067139"
|
|
||||||
cy="242.50381"
|
|
||||||
fx="49.067139"
|
|
||||||
fy="242.50381"
|
|
||||||
r="37.00671" />
|
|
||||||
<linearGradient
|
|
||||||
id="linearGradient36471">
|
|
||||||
<stop
|
|
||||||
id="stop36473"
|
|
||||||
offset="0"
|
|
||||||
style="stop-color:#ffffff;stop-opacity:1;" />
|
|
||||||
<stop
|
|
||||||
id="stop36475"
|
|
||||||
offset="1"
|
|
||||||
style="stop-color:#ffffff;stop-opacity:0;" />
|
|
||||||
</linearGradient>
|
|
||||||
<radialGradient
|
|
||||||
r="37.00671"
|
|
||||||
fy="242.50381"
|
|
||||||
fx="49.067139"
|
|
||||||
cy="242.50381"
|
|
||||||
cx="49.067139"
|
|
||||||
gradientTransform="matrix(3.4218418,0,0,0.03365337,-61.309005,138.5071)"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
id="radialGradient7488"
|
|
||||||
xlink:href="#linearGradient36471" />
|
|
||||||
</defs>
|
|
||||||
<g
|
|
||||||
id="layer1"
|
|
||||||
transform="matrix(1.6213276,0,0,1.6213276,-431.6347,-272.5745)">
|
|
||||||
<g
|
|
||||||
style="display:inline"
|
|
||||||
id="g30864"
|
|
||||||
transform="translate(255.223,70.118091)">
|
|
||||||
<rect
|
|
||||||
ry="3.4593496"
|
|
||||||
rx="8.8641119"
|
|
||||||
y="76.159348"
|
|
||||||
x="12.596948"
|
|
||||||
height="71.116341"
|
|
||||||
width="182.22595"
|
|
||||||
id="rect14000"
|
|
||||||
style="opacity:0.371875;fill:url(#radialGradient7461);fill-opacity:1;stroke:none" />
|
|
||||||
<path
|
|
||||||
id="rect34520"
|
|
||||||
d="m 194.80022,146.83551 -182.559919,0"
|
|
||||||
style="opacity:0.35;fill:none;stroke:url(#radialGradient7488);stroke-width:0.61184424;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
|
||||||
connector-curvature="0"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="cc" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 78 KiB |
33
data/theme/panel-border.svg
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="3"
|
||||||
|
height="10"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
id="layer1">
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;fill-opacity:1;stroke-width:0.43599999000000000;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
id="rect3779"
|
||||||
|
width="3"
|
||||||
|
height="10"
|
||||||
|
x="0"
|
||||||
|
y="0" />
|
||||||
|
<rect
|
||||||
|
style="fill:#536272;fill-opacity:1;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
id="rect3796"
|
||||||
|
width="3"
|
||||||
|
height="1"
|
||||||
|
x="0"
|
||||||
|
y="9" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 787 B |
@@ -9,7 +9,7 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
width="17"
|
width="21"
|
||||||
height="10"
|
height="10"
|
||||||
id="svg2"
|
id="svg2"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
@@ -66,9 +66,9 @@
|
|||||||
<rect
|
<rect
|
||||||
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none"
|
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
id="rect3796"
|
id="rect3796"
|
||||||
width="7"
|
width="3"
|
||||||
height="2"
|
height="2"
|
||||||
x="5"
|
x="9"
|
||||||
y="8" />
|
y="8" />
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
64
data/theme/scroll-hhandle.svg
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="10"
|
||||||
|
height="4"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.47 r22583"
|
||||||
|
sodipodi:docname="scroll-hhandle.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
</defs>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<rect
|
||||||
|
style="fill:#323232;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||||
|
id="rect3592"
|
||||||
|
width="2"
|
||||||
|
height="4"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
rx="0"
|
||||||
|
ry="0" />
|
||||||
|
<use
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
xlink:href="#rect3592"
|
||||||
|
id="use2825"
|
||||||
|
transform="translate(8,0)"
|
||||||
|
width="10"
|
||||||
|
height="4" />
|
||||||
|
<use
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
xlink:href="#use2825"
|
||||||
|
id="use2827"
|
||||||
|
transform="translate(-4,0)"
|
||||||
|
width="10"
|
||||||
|
height="4" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
62
data/theme/scroll-vhandle.svg
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="4"
|
||||||
|
height="10"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.47 r22583"
|
||||||
|
sodipodi:docname="scroll-hhandle.svg">
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<rect
|
||||||
|
style="fill:#323232;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||||
|
id="rect3592"
|
||||||
|
width="2"
|
||||||
|
height="4"
|
||||||
|
x="0"
|
||||||
|
y="-4"
|
||||||
|
rx="0"
|
||||||
|
ry="0"
|
||||||
|
transform="matrix(0,1,-1,0,0,0)" />
|
||||||
|
<use
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
xlink:href="#rect3592"
|
||||||
|
id="use3705"
|
||||||
|
transform="translate(0,4)"
|
||||||
|
width="4"
|
||||||
|
height="10" />
|
||||||
|
<use
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
xlink:href="#use3705"
|
||||||
|
id="use3707"
|
||||||
|
transform="translate(0,4)"
|
||||||
|
width="4"
|
||||||
|
height="10" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -9,7 +9,7 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
width="65"
|
width="64"
|
||||||
height="22"
|
height="22"
|
||||||
id="svg3273"
|
id="svg3273"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
@@ -9,7 +9,7 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
width="65"
|
width="64"
|
||||||
height="22"
|
height="22"
|
||||||
id="svg3012"
|
id="svg3012"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
@@ -18,10 +18,11 @@ DOC_MODULE=shell
|
|||||||
# The top-level SGML file. You can change this if you want to.
|
# The top-level SGML file. You can change this if you want to.
|
||||||
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
|
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
|
||||||
|
|
||||||
# Directories containing the source code
|
# Directories containing the source code, relative to $(srcdir).
|
||||||
# gtk-doc will search all .c and .h files beneath these paths
|
# gtk-doc will search all .c and .h files beneath these paths
|
||||||
# for inline comments documenting functions and macros.
|
# for inline comments documenting functions and macros.
|
||||||
DOC_SOURCE_DIR=$(top_srcdir)/src
|
# e.g. DOC_SOURCE_DIR=../../../gtk ../../../gdk
|
||||||
|
DOC_SOURCE_DIR=../../../src
|
||||||
|
|
||||||
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
|
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
|
||||||
SCANGOBJ_OPTIONS=
|
SCANGOBJ_OPTIONS=
|
||||||
@@ -57,20 +58,7 @@ EXTRA_HFILES=
|
|||||||
|
|
||||||
# Header files or dirs to ignore when scanning. Use base file/dir names
|
# Header files or dirs to ignore when scanning. Use base file/dir names
|
||||||
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
|
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
|
||||||
IGNORE_HFILES= \
|
IGNORE_HFILES=calendar-server gvc hotplug-sniffer st tray
|
||||||
calendar-server \
|
|
||||||
gvc \
|
|
||||||
hotplug-sniffer \
|
|
||||||
st \
|
|
||||||
tray \
|
|
||||||
gactionmuxer.h \
|
|
||||||
gactionobservable.h \
|
|
||||||
gactionobserver.h \
|
|
||||||
shell-recorder-src.h
|
|
||||||
|
|
||||||
if !BUILD_RECORDER
|
|
||||||
IGNORE_HFILES += shell-recorder.h
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Images to copy into HTML directory.
|
# Images to copy into HTML directory.
|
||||||
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
|
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
|
||||||
@@ -91,7 +79,7 @@ expand_content_files=
|
|||||||
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
|
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
|
||||||
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
|
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
|
||||||
GTKDOC_CFLAGS=$(GNOME_SHELL_CFLAGS)
|
GTKDOC_CFLAGS=$(GNOME_SHELL_CFLAGS)
|
||||||
GTKDOC_LIBS=$(GNOME_SHELL_LIBS) $(BLUETOOTH_LIBS) $(top_builddir)/src/libgnome-shell.la
|
GTKDOC_LIBS=$(GNOME_SHELL_LIBS) $(top_builddir)/src/libgnome-shell.la
|
||||||
|
|
||||||
# This includes the standard gtk-doc make rules, copied by gtkdocize.
|
# This includes the standard gtk-doc make rules, copied by gtkdocize.
|
||||||
include $(top_srcdir)/gtk-doc.make
|
include $(top_srcdir)/gtk-doc.make
|
||||||
|
|||||||
@@ -18,10 +18,11 @@ DOC_MODULE=st
|
|||||||
# The top-level SGML file. You can change this if you want to.
|
# The top-level SGML file. You can change this if you want to.
|
||||||
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
|
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
|
||||||
|
|
||||||
# Directories containing the source code
|
# Directories containing the source code, relative to $(srcdir).
|
||||||
# gtk-doc will search all .c and .h files beneath these paths
|
# gtk-doc will search all .c and .h files beneath these paths
|
||||||
# for inline comments documenting functions and macros.
|
# for inline comments documenting functions and macros.
|
||||||
DOC_SOURCE_DIR=$(top_srcdir)/src/st
|
# e.g. DOC_SOURCE_DIR=../../../gtk ../../../gdk
|
||||||
|
DOC_SOURCE_DIR=../../../src/st
|
||||||
|
|
||||||
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
|
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
|
||||||
SCANGOBJ_OPTIONS=
|
SCANGOBJ_OPTIONS=
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
<title>Abstract classes and Interfaces</title>
|
<title>Abstract classes and Interfaces</title>
|
||||||
<xi:include href="xml/st-widget.xml"/>
|
<xi:include href="xml/st-widget.xml"/>
|
||||||
<xi:include href="xml/st-widget-accessible.xml"/>
|
<xi:include href="xml/st-widget-accessible.xml"/>
|
||||||
|
<xi:include href="xml/st-container.xml"/>
|
||||||
<xi:include href="xml/st-scrollable.xml"/>
|
<xi:include href="xml/st-scrollable.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
<chapter id="widgets">
|
<chapter id="widgets">
|
||||||
@@ -29,11 +30,14 @@
|
|||||||
<xi:include href="xml/st-entry.xml"/>
|
<xi:include href="xml/st-entry.xml"/>
|
||||||
<xi:include href="xml/st-icon.xml"/>
|
<xi:include href="xml/st-icon.xml"/>
|
||||||
<xi:include href="xml/st-label.xml"/>
|
<xi:include href="xml/st-label.xml"/>
|
||||||
|
<xi:include href="xml/st-tooltip.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
<chapter id="containers">
|
<chapter id="containers">
|
||||||
<title>Containers</title>
|
<title>Containers</title>
|
||||||
<xi:include href="xml/st-bin.xml"/>
|
<xi:include href="xml/st-bin.xml"/>
|
||||||
<xi:include href="xml/st-box-layout.xml"/>
|
<xi:include href="xml/st-box-layout.xml"/>
|
||||||
|
<xi:include href="xml/st-group.xml"/>
|
||||||
|
<xi:include href="xml/st-overflow-box.xml"/>
|
||||||
<xi:include href="xml/st-scroll-view.xml"/>
|
<xi:include href="xml/st-scroll-view.xml"/>
|
||||||
<xi:include href="xml/st-table.xml"/>
|
<xi:include href="xml/st-table.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|||||||
@@ -66,11 +66,4 @@ its dependencies to build from tarballs.</description>
|
|||||||
<gnome:userid>marinaz</gnome:userid>
|
<gnome:userid>marinaz</gnome:userid>
|
||||||
</foaf:Person>
|
</foaf:Person>
|
||||||
</maintainer>
|
</maintainer>
|
||||||
<maintainer>
|
|
||||||
<foaf:Person>
|
|
||||||
<foaf:name>Florian Müllner</foaf:name>
|
|
||||||
<foaf:mbox rdf:resource="mailto:fmuellner@gnome.org" />
|
|
||||||
<gnome:userid>fmuellner</gnome:userid>
|
|
||||||
</foaf:Person>
|
|
||||||
</maintainer>
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,18 +1,4 @@
|
|||||||
|
|
||||||
EXTRA_DIST = misc/config.js.in
|
|
||||||
CLEANFILES = misc/config.js
|
|
||||||
|
|
||||||
misc/config.js: misc/config.js.in Makefile
|
|
||||||
[ -d $(@D) ] || $(mkdir_p) $(@D) ; \
|
|
||||||
sed -e "s|[@]PACKAGE_NAME@|$(PACKAGE_NAME)|g" \
|
|
||||||
-e "s|[@]PACKAGE_VERSION@|$(PACKAGE_VERSION)|g" \
|
|
||||||
-e "s|[@]HAVE_BLUETOOTH@|$(HAVE_BLUETOOTH)|g" \
|
|
||||||
-e "s|[@]GETTEXT_PACKAGE@|$(GETTEXT_PACKAGE)|g" \
|
|
||||||
-e "s|[@]datadir@|$(datadir)|g" \
|
|
||||||
-e "s|[@]libexecdir@|$(libexecdir)|g" \
|
|
||||||
-e "s|[@]sysconfdir@|$(sysconfdir)|g" \
|
|
||||||
$< > $@
|
|
||||||
|
|
||||||
jsdir = $(pkgdatadir)/js
|
jsdir = $(pkgdatadir)/js
|
||||||
|
|
||||||
nobase_dist_js_DATA = \
|
nobase_dist_js_DATA = \
|
||||||
@@ -21,17 +7,16 @@ nobase_dist_js_DATA = \
|
|||||||
gdm/fingerprint.js \
|
gdm/fingerprint.js \
|
||||||
gdm/loginDialog.js \
|
gdm/loginDialog.js \
|
||||||
gdm/powerMenu.js \
|
gdm/powerMenu.js \
|
||||||
gdm/systemd.js \
|
|
||||||
gdm/util.js \
|
|
||||||
extensionPrefs/main.js \
|
|
||||||
misc/config.js \
|
misc/config.js \
|
||||||
misc/extensionUtils.js \
|
misc/docInfo.js \
|
||||||
misc/fileUtils.js \
|
misc/fileUtils.js \
|
||||||
|
misc/format.js \
|
||||||
misc/gnomeSession.js \
|
misc/gnomeSession.js \
|
||||||
misc/history.js \
|
misc/history.js \
|
||||||
misc/jsParse.js \
|
misc/jsParse.js \
|
||||||
misc/modemManager.js \
|
misc/modemManager.js \
|
||||||
misc/params.js \
|
misc/params.js \
|
||||||
|
misc/screenSaver.js \
|
||||||
misc/util.js \
|
misc/util.js \
|
||||||
perf/core.js \
|
perf/core.js \
|
||||||
ui/altTab.js \
|
ui/altTab.js \
|
||||||
@@ -41,22 +26,20 @@ nobase_dist_js_DATA = \
|
|||||||
ui/autorunManager.js \
|
ui/autorunManager.js \
|
||||||
ui/boxpointer.js \
|
ui/boxpointer.js \
|
||||||
ui/calendar.js \
|
ui/calendar.js \
|
||||||
ui/checkBox.js \
|
ui/contactDisplay.js \
|
||||||
ui/ctrlAltTab.js \
|
ui/ctrlAltTab.js \
|
||||||
ui/dash.js \
|
ui/dash.js \
|
||||||
ui/dateMenu.js \
|
ui/dateMenu.js \
|
||||||
ui/dnd.js \
|
ui/dnd.js \
|
||||||
|
ui/docDisplay.js \
|
||||||
ui/endSessionDialog.js \
|
ui/endSessionDialog.js \
|
||||||
ui/environment.js \
|
ui/environment.js \
|
||||||
ui/extensionSystem.js \
|
ui/extensionSystem.js \
|
||||||
ui/extensionDownloader.js \
|
|
||||||
ui/flashspot.js \
|
|
||||||
ui/ibusCandidatePopup.js\
|
|
||||||
ui/iconGrid.js \
|
ui/iconGrid.js \
|
||||||
ui/keyboard.js \
|
ui/keyboard.js \
|
||||||
ui/keyringPrompt.js \
|
|
||||||
ui/layout.js \
|
ui/layout.js \
|
||||||
ui/lightbox.js \
|
ui/lightbox.js \
|
||||||
|
ui/link.js \
|
||||||
ui/lookingGlass.js \
|
ui/lookingGlass.js \
|
||||||
ui/magnifier.js \
|
ui/magnifier.js \
|
||||||
ui/magnifierDBus.js \
|
ui/magnifierDBus.js \
|
||||||
@@ -64,7 +47,6 @@ nobase_dist_js_DATA = \
|
|||||||
ui/messageTray.js \
|
ui/messageTray.js \
|
||||||
ui/modalDialog.js \
|
ui/modalDialog.js \
|
||||||
ui/networkAgent.js \
|
ui/networkAgent.js \
|
||||||
ui/sessionMode.js \
|
|
||||||
ui/shellEntry.js \
|
ui/shellEntry.js \
|
||||||
ui/shellMountOperation.js \
|
ui/shellMountOperation.js \
|
||||||
ui/notificationDaemon.js \
|
ui/notificationDaemon.js \
|
||||||
@@ -74,13 +56,12 @@ nobase_dist_js_DATA = \
|
|||||||
ui/placeDisplay.js \
|
ui/placeDisplay.js \
|
||||||
ui/polkitAuthenticationAgent.js \
|
ui/polkitAuthenticationAgent.js \
|
||||||
ui/popupMenu.js \
|
ui/popupMenu.js \
|
||||||
ui/remoteSearch.js \
|
|
||||||
ui/runDialog.js \
|
ui/runDialog.js \
|
||||||
ui/screenShield.js \
|
|
||||||
ui/scripting.js \
|
ui/scripting.js \
|
||||||
ui/search.js \
|
ui/search.js \
|
||||||
ui/searchDisplay.js \
|
ui/searchDisplay.js \
|
||||||
ui/shellDBus.js \
|
ui/shellDBus.js \
|
||||||
|
ui/statusIconDispatcher.js \
|
||||||
ui/status/accessibility.js \
|
ui/status/accessibility.js \
|
||||||
ui/status/keyboard.js \
|
ui/status/keyboard.js \
|
||||||
ui/status/network.js \
|
ui/status/network.js \
|
||||||
@@ -89,10 +70,8 @@ nobase_dist_js_DATA = \
|
|||||||
ui/status/bluetooth.js \
|
ui/status/bluetooth.js \
|
||||||
ui/telepathyClient.js \
|
ui/telepathyClient.js \
|
||||||
ui/tweener.js \
|
ui/tweener.js \
|
||||||
ui/unlockDialog.js \
|
|
||||||
ui/userMenu.js \
|
ui/userMenu.js \
|
||||||
ui/viewSelector.js \
|
ui/viewSelector.js \
|
||||||
ui/wanda.js \
|
|
||||||
ui/windowAttentionHandler.js \
|
ui/windowAttentionHandler.js \
|
||||||
ui/windowManager.js \
|
ui/windowManager.js \
|
||||||
ui/workspace.js \
|
ui/workspace.js \
|
||||||
|
|||||||
@@ -1,270 +0,0 @@
|
|||||||
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const Gettext = imports.gettext;
|
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const GObject = imports.gi.GObject;
|
|
||||||
const Gio = imports.gi.Gio;
|
|
||||||
const Gtk = imports.gi.Gtk;
|
|
||||||
const Pango = imports.gi.Pango;
|
|
||||||
const Format = imports.format;
|
|
||||||
|
|
||||||
const _ = Gettext.gettext;
|
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
|
||||||
|
|
||||||
const GnomeShellIface = <interface name="org.gnome.Shell.Extensions">
|
|
||||||
<signal name="ExtensionStatusChanged">
|
|
||||||
<arg type="s" name="uuid"/>
|
|
||||||
<arg type="i" name="state"/>
|
|
||||||
<arg type="s" name="error"/>
|
|
||||||
</signal>
|
|
||||||
</interface>;
|
|
||||||
|
|
||||||
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
|
|
||||||
|
|
||||||
function stripPrefix(string, prefix) {
|
|
||||||
if (string.slice(0, prefix.length) == prefix)
|
|
||||||
return string.slice(prefix.length);
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Application = new Lang.Class({
|
|
||||||
Name: 'Application',
|
|
||||||
_init: function() {
|
|
||||||
GLib.set_prgname('gnome-shell-extension-prefs');
|
|
||||||
this.application = new Gtk.Application({
|
|
||||||
application_id: 'org.gnome.shell.ExtensionPrefs',
|
|
||||||
flags: Gio.ApplicationFlags.HANDLES_COMMAND_LINE
|
|
||||||
});
|
|
||||||
|
|
||||||
this.application.connect('activate', Lang.bind(this, this._onActivate));
|
|
||||||
this.application.connect('command-line', Lang.bind(this, this._onCommandLine));
|
|
||||||
this.application.connect('startup', Lang.bind(this, this._onStartup));
|
|
||||||
|
|
||||||
this._extensionPrefsModules = {};
|
|
||||||
|
|
||||||
this._extensionIters = {};
|
|
||||||
},
|
|
||||||
|
|
||||||
_buildModel: function() {
|
|
||||||
this._model = new Gtk.ListStore();
|
|
||||||
this._model.set_column_types([GObject.TYPE_STRING, GObject.TYPE_STRING]);
|
|
||||||
},
|
|
||||||
|
|
||||||
_extensionAvailable: function(uuid) {
|
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
|
||||||
|
|
||||||
if (!extension)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (ExtensionUtils.isOutOfDate(extension))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!extension.dir.get_child('prefs.js').query_exists(null))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
_setExtensionInsensitive: function(layout, cell, model, iter, data) {
|
|
||||||
let uuid = model.get_value(iter, 0);
|
|
||||||
cell.set_sensitive(this._extensionAvailable(uuid));
|
|
||||||
},
|
|
||||||
|
|
||||||
_getExtensionPrefsModule: function(extension) {
|
|
||||||
let uuid = extension.metadata.uuid;
|
|
||||||
|
|
||||||
if (this._extensionPrefsModules.hasOwnProperty(uuid))
|
|
||||||
return this._extensionPrefsModules[uuid];
|
|
||||||
|
|
||||||
ExtensionUtils.installImporter(extension);
|
|
||||||
|
|
||||||
let prefsModule = extension.imports.prefs;
|
|
||||||
prefsModule.init(extension.metadata);
|
|
||||||
|
|
||||||
this._extensionPrefsModules[uuid] = prefsModule;
|
|
||||||
return prefsModule;
|
|
||||||
},
|
|
||||||
|
|
||||||
_selectExtension: function(uuid) {
|
|
||||||
if (!this._extensionAvailable(uuid))
|
|
||||||
return;
|
|
||||||
|
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
|
||||||
let widget;
|
|
||||||
|
|
||||||
try {
|
|
||||||
let prefsModule = this._getExtensionPrefsModule(extension);
|
|
||||||
widget = prefsModule.buildPrefsWidget();
|
|
||||||
} catch (e) {
|
|
||||||
widget = this._buildErrorUI(extension, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy the current prefs widget, if it exists
|
|
||||||
if (this._extensionPrefsBin.get_child())
|
|
||||||
this._extensionPrefsBin.get_child().destroy();
|
|
||||||
|
|
||||||
this._extensionPrefsBin.add(widget);
|
|
||||||
this._extensionSelector.set_active_iter(this._extensionIters[uuid]);
|
|
||||||
},
|
|
||||||
|
|
||||||
_extensionSelected: function() {
|
|
||||||
let [success, iter] = this._extensionSelector.get_active_iter();
|
|
||||||
if (!success)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let uuid = this._model.get_value(iter, 0);
|
|
||||||
this._selectExtension(uuid);
|
|
||||||
},
|
|
||||||
|
|
||||||
_buildErrorUI: function(extension, exc) {
|
|
||||||
let box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
|
|
||||||
let label = new Gtk.Label({
|
|
||||||
label: _("There was an error loading the preferences dialog for %s:").format(extension.metadata.name)
|
|
||||||
});
|
|
||||||
box.add(label);
|
|
||||||
|
|
||||||
let errortext = '';
|
|
||||||
errortext += exc;
|
|
||||||
errortext += '\n\n';
|
|
||||||
errortext += 'Stack trace:\n';
|
|
||||||
|
|
||||||
// Indent stack trace.
|
|
||||||
errortext += exc.stack.split('\n').map(function(line) {
|
|
||||||
return ' ' + line;
|
|
||||||
}).join('\n');
|
|
||||||
|
|
||||||
let scroll = new Gtk.ScrolledWindow({ vexpand: true });
|
|
||||||
let buffer = new Gtk.TextBuffer({ text: errortext });
|
|
||||||
let textview = new Gtk.TextView({ buffer: buffer });
|
|
||||||
textview.override_font(Pango.font_description_from_string('monospace'));
|
|
||||||
scroll.add(textview);
|
|
||||||
box.add(scroll);
|
|
||||||
|
|
||||||
box.show_all();
|
|
||||||
return box;
|
|
||||||
},
|
|
||||||
|
|
||||||
_buildUI: function(app) {
|
|
||||||
this._window = new Gtk.ApplicationWindow({ application: app,
|
|
||||||
window_position: Gtk.WindowPosition.CENTER,
|
|
||||||
title: _("GNOME Shell Extension Preferences") });
|
|
||||||
|
|
||||||
this._window.set_size_request(600, 400);
|
|
||||||
|
|
||||||
let vbox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
|
|
||||||
this._window.add(vbox);
|
|
||||||
|
|
||||||
let toolbar = new Gtk.Toolbar();
|
|
||||||
toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR);
|
|
||||||
vbox.add(toolbar);
|
|
||||||
let toolitem;
|
|
||||||
|
|
||||||
let label = new Gtk.Label({ label: '<b>' + _("Extension") + '</b>',
|
|
||||||
use_markup: true });
|
|
||||||
toolitem = new Gtk.ToolItem({ child: label });
|
|
||||||
toolbar.add(toolitem);
|
|
||||||
|
|
||||||
this._extensionSelector = new Gtk.ComboBox({ model: this._model,
|
|
||||||
margin_left: 8,
|
|
||||||
hexpand: true });
|
|
||||||
this._extensionSelector.get_style_context().add_class(Gtk.STYLE_CLASS_RAISED);
|
|
||||||
|
|
||||||
let renderer = new Gtk.CellRendererText();
|
|
||||||
this._extensionSelector.pack_start(renderer, true);
|
|
||||||
this._extensionSelector.add_attribute(renderer, 'text', 1);
|
|
||||||
this._extensionSelector.set_cell_data_func(renderer, Lang.bind(this, this._setExtensionInsensitive), null);
|
|
||||||
this._extensionSelector.connect('changed', Lang.bind(this, this._extensionSelected));
|
|
||||||
|
|
||||||
toolitem = new Gtk.ToolItem({ child: this._extensionSelector });
|
|
||||||
toolitem.set_expand(true);
|
|
||||||
toolbar.add(toolitem);
|
|
||||||
|
|
||||||
this._extensionPrefsBin = new Gtk.Frame();
|
|
||||||
vbox.add(this._extensionPrefsBin);
|
|
||||||
|
|
||||||
let label = new Gtk.Label({
|
|
||||||
label: _("Select an extension to configure using the combobox above."),
|
|
||||||
vexpand: true
|
|
||||||
});
|
|
||||||
|
|
||||||
this._extensionPrefsBin.add(label);
|
|
||||||
|
|
||||||
this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
|
|
||||||
this._shellProxy.connectSignal('ExtensionStatusChanged', Lang.bind(this, function(proxy, senderName, [uuid, state, error]) {
|
|
||||||
if (ExtensionUtils.extensions[uuid] !== undefined)
|
|
||||||
this._scanExtensions();
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._window.show_all();
|
|
||||||
},
|
|
||||||
|
|
||||||
_scanExtensions: function() {
|
|
||||||
let finder = new ExtensionUtils.ExtensionFinder();
|
|
||||||
finder.connect('extension-found', Lang.bind(this, this._extensionFound));
|
|
||||||
finder.scanExtensions();
|
|
||||||
},
|
|
||||||
|
|
||||||
_extensionFound: function(signals, extension) {
|
|
||||||
let iter = this._model.append();
|
|
||||||
this._model.set(iter, [0, 1], [extension.uuid, extension.metadata.name]);
|
|
||||||
this._extensionIters[extension.uuid] = iter;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
_onActivate: function() {
|
|
||||||
this._window.present();
|
|
||||||
},
|
|
||||||
|
|
||||||
_onStartup: function(app) {
|
|
||||||
this._buildModel();
|
|
||||||
this._buildUI(app);
|
|
||||||
this._scanExtensions();
|
|
||||||
},
|
|
||||||
|
|
||||||
_onCommandLine: function(app, commandLine) {
|
|
||||||
app.activate();
|
|
||||||
let args = commandLine.get_arguments();
|
|
||||||
if (args.length) {
|
|
||||||
let uuid = args[0];
|
|
||||||
|
|
||||||
// Strip off "extension:///" prefix which fakes a URI, if it exists
|
|
||||||
uuid = stripPrefix(uuid, "extension:///");
|
|
||||||
|
|
||||||
if (!this._extensionAvailable(uuid))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
this._selectExtension(uuid);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function initEnvironment() {
|
|
||||||
// Monkey-patch in a "global" object that fakes some Shell utilities
|
|
||||||
// that ExtensionUtils depends on.
|
|
||||||
window.global = {
|
|
||||||
log: function() {
|
|
||||||
print([].join.call(arguments, ', '));
|
|
||||||
},
|
|
||||||
|
|
||||||
logError: function(s) {
|
|
||||||
log('ERROR: ' + s);
|
|
||||||
},
|
|
||||||
|
|
||||||
userdatadir: GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell'])
|
|
||||||
};
|
|
||||||
|
|
||||||
String.prototype.format = Format.format;
|
|
||||||
}
|
|
||||||
|
|
||||||
function main(argv) {
|
|
||||||
initEnvironment();
|
|
||||||
|
|
||||||
Gettext.bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
|
|
||||||
Gettext.textdomain(Config.GETTEXT_PACKAGE);
|
|
||||||
|
|
||||||
let app = new Application();
|
|
||||||
app.application.run(argv);
|
|
||||||
}
|
|
||||||
@@ -21,9 +21,11 @@
|
|||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
|
||||||
const Task = new Lang.Class({
|
function Task() {
|
||||||
Name: 'Task',
|
this._init.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Task.prototype = {
|
||||||
_init: function(scope, handler) {
|
_init: function(scope, handler) {
|
||||||
if (scope)
|
if (scope)
|
||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
@@ -39,15 +41,20 @@ const Task = new Lang.Class({
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(Task.prototype);
|
Signals.addSignalMethods(Task.prototype);
|
||||||
|
|
||||||
const Hold = new Lang.Class({
|
function Hold() {
|
||||||
Name: 'Hold',
|
this._init.apply(this, arguments);
|
||||||
Extends: Task,
|
}
|
||||||
|
|
||||||
|
Hold.prototype = {
|
||||||
|
__proto__: Task.prototype,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent(this, function () {
|
Task.prototype._init.call(this,
|
||||||
|
this,
|
||||||
|
function () {
|
||||||
return this;
|
return this;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -81,15 +88,18 @@ const Hold = new Lang.Class({
|
|||||||
isAcquired: function() {
|
isAcquired: function() {
|
||||||
return this._acquisitions > 0;
|
return this._acquisitions > 0;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
Signals.addSignalMethods(Hold.prototype);
|
Signals.addSignalMethods(Hold.prototype);
|
||||||
|
|
||||||
const Batch = new Lang.Class({
|
function Batch() {
|
||||||
Name: 'Batch',
|
this._init.apply(this, arguments);
|
||||||
Extends: Task,
|
}
|
||||||
|
|
||||||
|
Batch.prototype = {
|
||||||
|
__proto__: Task.prototype,
|
||||||
|
|
||||||
_init: function(scope, tasks) {
|
_init: function(scope, tasks) {
|
||||||
this.parent();
|
Task.prototype._init.call(this);
|
||||||
|
|
||||||
this.tasks = [];
|
this.tasks = [];
|
||||||
|
|
||||||
@@ -156,12 +166,20 @@ const Batch = new Lang.Class({
|
|||||||
cancel: function() {
|
cancel: function() {
|
||||||
this.tasks = this.tasks.splice(0, this._currentTaskIndex + 1);
|
this.tasks = this.tasks.splice(0, this._currentTaskIndex + 1);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
};
|
||||||
Signals.addSignalMethods(Batch.prototype);
|
Signals.addSignalMethods(Batch.prototype);
|
||||||
|
|
||||||
const ConcurrentBatch = new Lang.Class({
|
function ConcurrentBatch() {
|
||||||
Name: 'ConcurrentBatch',
|
this._init.apply(this, arguments);
|
||||||
Extends: Batch,
|
}
|
||||||
|
|
||||||
|
ConcurrentBatch.prototype = {
|
||||||
|
__proto__: Batch.prototype,
|
||||||
|
|
||||||
|
_init: function(scope, tasks) {
|
||||||
|
Batch.prototype._init.call(this, scope, tasks);
|
||||||
|
},
|
||||||
|
|
||||||
process: function() {
|
process: function() {
|
||||||
let hold = this.runTask();
|
let hold = this.runTask();
|
||||||
@@ -175,12 +193,19 @@ const ConcurrentBatch = new Lang.Class({
|
|||||||
// concurrently.
|
// concurrently.
|
||||||
this.nextTask();
|
this.nextTask();
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(ConcurrentBatch.prototype);
|
Signals.addSignalMethods(ConcurrentBatch.prototype);
|
||||||
|
|
||||||
const ConsecutiveBatch = new Lang.Class({
|
function ConsecutiveBatch() {
|
||||||
Name: 'ConsecutiveBatch',
|
this._init.apply(this, arguments);
|
||||||
Extends: Batch,
|
}
|
||||||
|
|
||||||
|
ConsecutiveBatch.prototype = {
|
||||||
|
__proto__: Batch.prototype,
|
||||||
|
|
||||||
|
_init: function(scope, tasks) {
|
||||||
|
Batch.prototype._init.call(this, scope, tasks);
|
||||||
|
},
|
||||||
|
|
||||||
process: function() {
|
process: function() {
|
||||||
let hold = this.runTask();
|
let hold = this.runTask();
|
||||||
@@ -199,5 +224,5 @@ const ConsecutiveBatch = new Lang.Class({
|
|||||||
this.nextTask();
|
this.nextTask();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(ConsecutiveBatch.prototype);
|
Signals.addSignalMethods(ConsecutiveBatch.prototype);
|
||||||
|
|||||||
@@ -1,22 +1,32 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Gio = imports.gi.Gio;
|
const DBus = imports.dbus;
|
||||||
|
|
||||||
const ConsoleKitManagerIface = <interface name='org.freedesktop.ConsoleKit.Manager'>
|
const ConsoleKitManagerIface = {
|
||||||
<method name='CanRestart'>
|
name: 'org.freedesktop.ConsoleKit.Manager',
|
||||||
<arg type='b' direction='out'/>
|
methods: [{ name: 'CanRestart',
|
||||||
</method>
|
inSignature: '',
|
||||||
<method name='CanStop'>
|
outSignature: 'b' },
|
||||||
<arg type='b' direction='out'/>
|
{ name: 'CanStop',
|
||||||
</method>
|
inSignature: '',
|
||||||
<method name='Restart' />
|
outSignature: 'b' },
|
||||||
<method name='Stop' />
|
{ name: 'Restart',
|
||||||
</interface>;
|
inSignature: '',
|
||||||
|
outSignature: '' },
|
||||||
const ConsoleKitProxy = Gio.DBusProxy.makeProxyWrapper(ConsoleKitManagerIface);
|
{ name: 'Stop',
|
||||||
|
inSignature: '',
|
||||||
|
outSignature: '' }]
|
||||||
|
};
|
||||||
|
|
||||||
function ConsoleKitManager() {
|
function ConsoleKitManager() {
|
||||||
return new ConsoleKitProxy(Gio.DBus.system,
|
this._init();
|
||||||
|
};
|
||||||
|
|
||||||
|
ConsoleKitManager.prototype = {
|
||||||
|
_init: function() {
|
||||||
|
DBus.system.proxifyObject(this,
|
||||||
'org.freedesktop.ConsoleKit',
|
'org.freedesktop.ConsoleKit',
|
||||||
'/org/freedesktop/ConsoleKit/Manager');
|
'/org/freedesktop/ConsoleKit/Manager');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
DBus.proxifyPrototype(ConsoleKitManager.prototype, ConsoleKitManagerIface);
|
||||||
|
|||||||
@@ -1,27 +1,26 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Gio = imports.gi.Gio;
|
const DBus = imports.dbus;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
|
||||||
const FprintManagerIface = <interface name='net.reactivated.Fprint.Manager'>
|
const FprintManagerIface = {
|
||||||
<method name='GetDefaultDevice'>
|
name: 'net.reactivated.Fprint.Manager',
|
||||||
<arg type='o' direction='out' />
|
methods: [{ name: 'GetDefaultDevice',
|
||||||
</method>
|
inSignature: '',
|
||||||
</interface>;
|
outSignature: 'o' }]
|
||||||
|
};
|
||||||
const FprintManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(FprintManagerIface);
|
|
||||||
|
|
||||||
function FprintManager() {
|
function FprintManager() {
|
||||||
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.system,
|
this._init();
|
||||||
g_interface_name: FprintManagerInfo.name,
|
};
|
||||||
g_interface_info: FprintManagerInfo,
|
|
||||||
g_name: 'net.reactivated.Fprint',
|
|
||||||
g_object_path: '/net/reactivated/Fprint/Manager',
|
|
||||||
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
|
|
||||||
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
|
||||||
|
|
||||||
self.init(null);
|
FprintManager.prototype = {
|
||||||
return self;
|
_init: function() {
|
||||||
}
|
DBus.system.proxifyObject(this,
|
||||||
|
'net.reactivated.Fprint',
|
||||||
|
'/net/reactivated/Fprint/Manager');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
DBus.proxifyPrototype(FprintManager.prototype, FprintManagerIface);
|
||||||
|
|||||||
@@ -30,23 +30,84 @@ const Pango = imports.gi.Pango;
|
|||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Gdm = imports.gi.Gdm;
|
const GdmGreeter = imports.gi.GdmGreeter;
|
||||||
|
|
||||||
const Batch = imports.gdm.batch;
|
const Batch = imports.gdm.batch;
|
||||||
|
const DBus = imports.dbus;
|
||||||
const Fprint = imports.gdm.fingerprint;
|
const Fprint = imports.gdm.fingerprint;
|
||||||
const GdmUtil = imports.gdm.util;
|
|
||||||
const Lightbox = imports.ui.lightbox;
|
const Lightbox = imports.ui.lightbox;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
|
const _PASSWORD_SERVICE_NAME = 'gdm-password';
|
||||||
|
const _FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
||||||
|
const _FADE_ANIMATION_TIME = 0.16;
|
||||||
const _RESIZE_ANIMATION_TIME = 0.25;
|
const _RESIZE_ANIMATION_TIME = 0.25;
|
||||||
const _SCROLL_ANIMATION_TIME = 0.5;
|
const _SCROLL_ANIMATION_TIME = 2.0;
|
||||||
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
|
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
|
||||||
const _LOGO_ICON_NAME_SIZE = 48;
|
const _LOGO_ICON_NAME_SIZE = 48;
|
||||||
|
|
||||||
|
const _LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
||||||
|
const _FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
||||||
|
|
||||||
|
const _LOGO_KEY = 'logo';
|
||||||
|
|
||||||
let _loginDialog = null;
|
let _loginDialog = null;
|
||||||
|
|
||||||
|
function _fadeInActor(actor) {
|
||||||
|
let hold = new Batch.Hold();
|
||||||
|
|
||||||
|
if (actor.opacity == 255 && actor.visible)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
actor.show();
|
||||||
|
let [minHeight, naturalHeight] = actor.get_preferred_height(-1);
|
||||||
|
|
||||||
|
actor.opacity = 0;
|
||||||
|
actor.set_height(0);
|
||||||
|
Tweener.addTween(actor,
|
||||||
|
{ opacity: 255,
|
||||||
|
height: naturalHeight,
|
||||||
|
time: _FADE_ANIMATION_TIME,
|
||||||
|
transition: 'easeOutQuad',
|
||||||
|
onComplete: function() {
|
||||||
|
actor.set_height(-1);
|
||||||
|
hold.release();
|
||||||
|
},
|
||||||
|
onCompleteScope: this
|
||||||
|
});
|
||||||
|
return hold;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _fadeOutActor(actor) {
|
||||||
|
let hold = new Batch.Hold();
|
||||||
|
|
||||||
|
if (!actor.visible) {
|
||||||
|
actor.opacity = 0;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actor.opacity == 0) {
|
||||||
|
actor.hide();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tweener.addTween(actor,
|
||||||
|
{ opacity: 0,
|
||||||
|
height: 0,
|
||||||
|
time: _FADE_ANIMATION_TIME,
|
||||||
|
transition: 'easeOutQuad',
|
||||||
|
onComplete: function() {
|
||||||
|
actor.hide();
|
||||||
|
actor.set_height(-1);
|
||||||
|
hold.release();
|
||||||
|
},
|
||||||
|
onCompleteScope: this
|
||||||
|
});
|
||||||
|
return hold;
|
||||||
|
}
|
||||||
|
|
||||||
function _smoothlyResizeActor(actor, width, height) {
|
function _smoothlyResizeActor(actor, width, height) {
|
||||||
let finalWidth;
|
let finalWidth;
|
||||||
let finalHeight;
|
let finalHeight;
|
||||||
@@ -80,45 +141,53 @@ function _smoothlyResizeActor(actor, width, height) {
|
|||||||
return hold;
|
return hold;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserListItem = new Lang.Class({
|
function UserListItem(user, reason) {
|
||||||
Name: 'UserListItem',
|
this._init(user, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserListItem.prototype = {
|
||||||
_init: function(user) {
|
_init: function(user) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this._userChangedId = this.user.connect('changed',
|
this._userChangedId = this.user.connect('changed',
|
||||||
Lang.bind(this, this._onUserChanged));
|
Lang.bind(this, this._onUserChanged));
|
||||||
|
|
||||||
let layout = new St.BoxLayout({ vertical: false });
|
this._verticalBox = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-vertical-layout',
|
||||||
|
vertical: true });
|
||||||
|
|
||||||
this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
|
this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
|
||||||
can_focus: true,
|
can_focus: true,
|
||||||
child: layout,
|
child: this._verticalBox,
|
||||||
reactive: true,
|
reactive: true,
|
||||||
x_align: St.Align.START,
|
x_align: St.Align.START,
|
||||||
x_fill: true });
|
x_fill: true });
|
||||||
|
let layout = new St.BoxLayout({ vertical: false });
|
||||||
|
|
||||||
|
this._verticalBox.add(layout,
|
||||||
|
{ y_fill: true,
|
||||||
|
x_fill: true,
|
||||||
|
expand: true });
|
||||||
|
|
||||||
|
this._focusBin = new St.Bin({ style_class: 'login-dialog-user-list-item-focus-bin' });
|
||||||
|
this._verticalBox.add(this._focusBin,
|
||||||
|
{ x_fill: false,
|
||||||
|
x_align: St.Align.MIDDLE,
|
||||||
|
y_fill: false,
|
||||||
|
expand: true });
|
||||||
|
|
||||||
this._iconBin = new St.Bin();
|
this._iconBin = new St.Bin();
|
||||||
layout.add(this._iconBin);
|
layout.add(this._iconBin);
|
||||||
let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
|
let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
layout.add(textLayout, { expand: true });
|
layout.add(textLayout,
|
||||||
|
|
||||||
this._nameLabel = new St.Label({ text: this.user.get_real_name(),
|
|
||||||
style_class: 'login-dialog-user-list-item-name' });
|
|
||||||
textLayout.add(this._nameLabel,
|
|
||||||
{ y_fill: false,
|
{ y_fill: false,
|
||||||
y_align: St.Align.MIDDLE,
|
y_align: St.Align.MIDDLE,
|
||||||
expand: true });
|
expand: true });
|
||||||
|
|
||||||
this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator',
|
this._nameLabel = new St.Label({ text: this.user.get_real_name(),
|
||||||
scale_x: 0 });
|
style_class: 'login-dialog-user-list-item-name' });
|
||||||
textLayout.add(this._timedLoginIndicator,
|
textLayout.add(this._nameLabel);
|
||||||
{ x_fill: true,
|
|
||||||
x_align: St.Align.MIDDLE,
|
|
||||||
y_fill: false,
|
|
||||||
y_align: St.Align.END });
|
|
||||||
|
|
||||||
this._updateIcon();
|
this._updateIcon();
|
||||||
this._updateLoggedIn();
|
|
||||||
|
|
||||||
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||||
},
|
},
|
||||||
@@ -126,7 +195,6 @@ const UserListItem = new Lang.Class({
|
|||||||
_onUserChanged: function() {
|
_onUserChanged: function() {
|
||||||
this._nameLabel.set_text(this.user.get_real_name());
|
this._nameLabel.set_text(this.user.get_real_name());
|
||||||
this._updateIcon();
|
this._updateIcon();
|
||||||
this._updateLoggedIn();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_setIconFromFile: function(iconFile, styleClass) {
|
_setIconFromFile: function(iconFile, styleClass) {
|
||||||
@@ -140,8 +208,7 @@ const UserListItem = new Lang.Class({
|
|||||||
// We use background-image instead of, say, St.TextureCache
|
// We use background-image instead of, say, St.TextureCache
|
||||||
// so the theme writers can add a rounded frame around the image
|
// so the theme writers can add a rounded frame around the image
|
||||||
// and so theme writers can pick the icon size.
|
// and so theme writers can pick the icon size.
|
||||||
this._iconBin.set_style('background-image: url("' + iconFile + '");' +
|
this._iconBin.set_style('background-image: url("' + iconFile + '");');
|
||||||
'background-size: contain;');
|
|
||||||
} else {
|
} else {
|
||||||
this._iconBin.hide();
|
this._iconBin.hide();
|
||||||
}
|
}
|
||||||
@@ -174,40 +241,30 @@ const UserListItem = new Lang.Class({
|
|||||||
this._setIconFromName('avatar-default', 'login-dialog-user-list-item-icon');
|
this._setIconFromName('avatar-default', 'login-dialog-user-list-item-icon');
|
||||||
},
|
},
|
||||||
|
|
||||||
syncStyleClasses: function() {
|
|
||||||
this._updateLoggedIn();
|
|
||||||
|
|
||||||
if (global.stage.get_key_focus() == this.actor)
|
|
||||||
this.actor.add_style_pseudo_class('focus');
|
|
||||||
else
|
|
||||||
this.actor.remove_style_pseudo_class('focus');
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateLoggedIn: function() {
|
|
||||||
if (this.user.is_logged_in())
|
|
||||||
this.actor.add_style_pseudo_class('logged-in');
|
|
||||||
else
|
|
||||||
this.actor.remove_style_pseudo_class('logged-in');
|
|
||||||
},
|
|
||||||
|
|
||||||
_onClicked: function() {
|
_onClicked: function() {
|
||||||
this.emit('activate');
|
this.emit('activate');
|
||||||
},
|
},
|
||||||
|
|
||||||
fadeOutName: function() {
|
fadeOutName: function() {
|
||||||
return GdmUtil.fadeOutActor(this._nameLabel);
|
return _fadeOutActor(this._nameLabel);
|
||||||
},
|
},
|
||||||
|
|
||||||
fadeInName: function() {
|
fadeInName: function() {
|
||||||
return GdmUtil.fadeInActor(this._nameLabel);
|
return _fadeInActor(this._nameLabel);
|
||||||
},
|
},
|
||||||
|
|
||||||
showTimedLoginIndicator: function(time) {
|
showFocusAnimation: function(time) {
|
||||||
let hold = new Batch.Hold();
|
let hold = new Batch.Hold();
|
||||||
|
|
||||||
this.hideTimedLoginIndicator();
|
let node = this.actor.get_theme_node();
|
||||||
Tweener.addTween(this._timedLoginIndicator,
|
let padding = node.get_horizontal_padding();
|
||||||
{ scale_x: 1.,
|
|
||||||
|
let box = this._verticalBox.get_allocation_box();
|
||||||
|
|
||||||
|
Tweener.removeTweens(this._focusBin);
|
||||||
|
this._focusBin.width = 0;
|
||||||
|
Tweener.addTween(this._focusBin,
|
||||||
|
{ width: (box.x2 - box.x1 - padding),
|
||||||
time: time,
|
time: time,
|
||||||
transition: 'linear',
|
transition: 'linear',
|
||||||
onComplete: function() {
|
onComplete: function() {
|
||||||
@@ -216,28 +273,29 @@ const UserListItem = new Lang.Class({
|
|||||||
onCompleteScope: this
|
onCompleteScope: this
|
||||||
});
|
});
|
||||||
return hold;
|
return hold;
|
||||||
},
|
|
||||||
|
|
||||||
hideTimedLoginIndicator: function() {
|
|
||||||
Tweener.removeTweens(this._timedLoginIndicator);
|
|
||||||
this._timedLoginIndicator.scale_x = 0.;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
};
|
||||||
Signals.addSignalMethods(UserListItem.prototype);
|
Signals.addSignalMethods(UserListItem.prototype);
|
||||||
|
|
||||||
const UserList = new Lang.Class({
|
function UserList() {
|
||||||
Name: 'UserList',
|
this._init.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserList.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.actor = new St.ScrollView({ style_class: 'login-dialog-user-list-view'});
|
this.actor = new St.ScrollView({ style_class: 'login-dialog-user-list-view'});
|
||||||
this.actor.set_policy(Gtk.PolicyType.NEVER,
|
this.actor.set_policy(Gtk.PolicyType.NEVER,
|
||||||
Gtk.PolicyType.AUTOMATIC);
|
Gtk.PolicyType.AUTOMATIC);
|
||||||
|
|
||||||
this._box = new St.BoxLayout({ vertical: true,
|
this._box = new St.BoxLayout({ vertical: true,
|
||||||
style_class: 'login-dialog-user-list',
|
style_class: 'login-dialog-user-list' });
|
||||||
pseudo_class: 'expanded' });
|
|
||||||
|
|
||||||
this.actor.add_actor(this._box);
|
this.actor.add_actor(this._box,
|
||||||
|
{ x_fill: true,
|
||||||
|
y_fill: true,
|
||||||
|
x_align: St.Align.START,
|
||||||
|
y_align: St.Align.MIDDLE });
|
||||||
this._items = {};
|
this._items = {};
|
||||||
|
|
||||||
this.actor.connect('key-focus-in', Lang.bind(this, this._moveFocusToItems));
|
this.actor.connect('key-focus-in', Lang.bind(this, this._moveFocusToItems));
|
||||||
@@ -257,7 +315,7 @@ const UserList = new Lang.Class({
|
|||||||
|
|
||||||
_showItem: function(item) {
|
_showItem: function(item) {
|
||||||
let tasks = [function() {
|
let tasks = [function() {
|
||||||
return GdmUtil.fadeInActor(item.actor);
|
return _fadeInActor(item.actor);
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
@@ -314,21 +372,17 @@ const UserList = new Lang.Class({
|
|||||||
for (let userName in this._items) {
|
for (let userName in this._items) {
|
||||||
let item = this._items[userName];
|
let item = this._items[userName];
|
||||||
|
|
||||||
item.actor.set_hover(false);
|
|
||||||
item.actor.reactive = false;
|
|
||||||
item.actor.can_focus = false;
|
item.actor.can_focus = false;
|
||||||
item.syncStyleClasses();
|
item._focusBin.width = 0;
|
||||||
item._timedLoginIndicator.scale_x = 0.;
|
|
||||||
if (item != exception)
|
if (item != exception)
|
||||||
tasks.push(function() {
|
tasks.push(function() {
|
||||||
return GdmUtil.fadeOutActor(item.actor);
|
return _fadeOutActor(item.actor);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this._box.remove_style_pseudo_class('expanded');
|
|
||||||
let batch = new Batch.ConsecutiveBatch(this,
|
let batch = new Batch.ConsecutiveBatch(this,
|
||||||
[function() {
|
[function() {
|
||||||
return GdmUtil.fadeOutActor(this.actor.vscroll);
|
return _fadeOutActor(this.actor.vscroll);
|
||||||
},
|
},
|
||||||
|
|
||||||
new Batch.ConcurrentBatch(this, tasks)
|
new Batch.ConcurrentBatch(this, tasks)
|
||||||
@@ -372,16 +426,12 @@ const UserList = new Lang.Class({
|
|||||||
|
|
||||||
for (let userName in this._items) {
|
for (let userName in this._items) {
|
||||||
let item = this._items[userName];
|
let item = this._items[userName];
|
||||||
item.actor.sync_hover();
|
|
||||||
item.actor.reactive = true;
|
|
||||||
item.actor.can_focus = true;
|
item.actor.can_focus = true;
|
||||||
item.syncStyleClasses();
|
|
||||||
tasks.push(function() {
|
tasks.push(function() {
|
||||||
return this._showItem(item);
|
return this._showItem(item);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this._box.add_style_pseudo_class('expanded');
|
|
||||||
let batch = new Batch.ConsecutiveBatch(this,
|
let batch = new Batch.ConsecutiveBatch(this,
|
||||||
[function() {
|
[function() {
|
||||||
this.takeOverWhitespace();
|
this.takeOverWhitespace();
|
||||||
@@ -399,7 +449,7 @@ const UserList = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
return GdmUtil.fadeInActor(this.actor.vscroll);
|
return _fadeInActor(this.actor.vscroll);
|
||||||
}]);
|
}]);
|
||||||
return batch.run();
|
return batch.run();
|
||||||
},
|
},
|
||||||
@@ -414,7 +464,7 @@ const UserList = new Lang.Class({
|
|||||||
Tweener.addTween (adjustment,
|
Tweener.addTween (adjustment,
|
||||||
{ value: value,
|
{ value: value,
|
||||||
time: _SCROLL_ANIMATION_TIME,
|
time: _SCROLL_ANIMATION_TIME,
|
||||||
transition: 'easeOutQuad' });
|
transition: 'linear' });
|
||||||
},
|
},
|
||||||
|
|
||||||
jumpToItem: function(item) {
|
jumpToItem: function(item) {
|
||||||
@@ -443,9 +493,6 @@ const UserList = new Lang.Class({
|
|||||||
if (user.is_system_account())
|
if (user.is_system_account())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (user.locked)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let userName = user.get_user_name();
|
let userName = user.get_user_name();
|
||||||
|
|
||||||
if (!userName)
|
if (!userName)
|
||||||
@@ -466,6 +513,7 @@ const UserList = new Lang.Class({
|
|||||||
Lang.bind(this,
|
Lang.bind(this,
|
||||||
function() {
|
function() {
|
||||||
this.scrollToItem(item);
|
this.scrollToItem(item);
|
||||||
|
item.showFocusAnimation(0);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._moveFocusToItems();
|
this._moveFocusToItems();
|
||||||
@@ -490,12 +538,14 @@ const UserList = new Lang.Class({
|
|||||||
item.actor.destroy();
|
item.actor.destroy();
|
||||||
delete this._items[userName];
|
delete this._items[userName];
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(UserList.prototype);
|
Signals.addSignalMethods(UserList.prototype);
|
||||||
|
|
||||||
const SessionListItem = new Lang.Class({
|
function SessionListItem(id, name) {
|
||||||
Name: 'SessionListItem',
|
this._init(id, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionListItem.prototype = {
|
||||||
_init: function(id, name) {
|
_init: function(id, name) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
|
||||||
@@ -507,7 +557,10 @@ const SessionListItem = new Lang.Class({
|
|||||||
|
|
||||||
this._box = new St.BoxLayout({ style_class: 'login-dialog-session-list-item-box' });
|
this._box = new St.BoxLayout({ style_class: 'login-dialog-session-list-item-box' });
|
||||||
|
|
||||||
this.actor.add_actor(this._box);
|
this.actor.add_actor(this._box,
|
||||||
|
{ expand: true,
|
||||||
|
x_fill: true,
|
||||||
|
y_fill: true });
|
||||||
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||||
|
|
||||||
this._dot = new St.DrawingArea({ style_class: 'login-dialog-session-list-item-dot' });
|
this._dot = new St.DrawingArea({ style_class: 'login-dialog-session-list-item-dot' });
|
||||||
@@ -518,7 +571,10 @@ const SessionListItem = new Lang.Class({
|
|||||||
let label = new St.Label({ style_class: 'login-dialog-session-list-item-label',
|
let label = new St.Label({ style_class: 'login-dialog-session-list-item-label',
|
||||||
text: name });
|
text: name });
|
||||||
|
|
||||||
this._box.add_actor(label);
|
this._box.add_actor(label,
|
||||||
|
{ expand: true,
|
||||||
|
x_fill: true,
|
||||||
|
y_fill: true });
|
||||||
},
|
},
|
||||||
|
|
||||||
setShowDot: function(show) {
|
setShowDot: function(show) {
|
||||||
@@ -544,12 +600,14 @@ const SessionListItem = new Lang.Class({
|
|||||||
_onClicked: function() {
|
_onClicked: function() {
|
||||||
this.emit('activate');
|
this.emit('activate');
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(SessionListItem.prototype);
|
Signals.addSignalMethods(SessionListItem.prototype);
|
||||||
|
|
||||||
const SessionList = new Lang.Class({
|
function SessionList() {
|
||||||
Name: 'SessionList',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionList.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.actor = new St.Bin();
|
this.actor = new St.Bin();
|
||||||
|
|
||||||
@@ -562,7 +620,10 @@ const SessionList = new Lang.Class({
|
|||||||
x_fill: true,
|
x_fill: true,
|
||||||
y_fill: true });
|
y_fill: true });
|
||||||
let box = new St.BoxLayout();
|
let box = new St.BoxLayout();
|
||||||
this._button.add_actor(box);
|
this._button.add_actor(box,
|
||||||
|
{ x_fill: true,
|
||||||
|
y_fill: true,
|
||||||
|
expand: true });
|
||||||
|
|
||||||
this._triangle = new St.Label({ style_class: 'login-dialog-session-list-triangle',
|
this._triangle = new St.Label({ style_class: 'login-dialog-session-list-triangle',
|
||||||
text: '\u25B8' });
|
text: '\u25B8' });
|
||||||
@@ -570,18 +631,30 @@ const SessionList = new Lang.Class({
|
|||||||
|
|
||||||
let label = new St.Label({ style_class: 'login-dialog-session-list-label',
|
let label = new St.Label({ style_class: 'login-dialog-session-list-label',
|
||||||
text: _("Session...") });
|
text: _("Session...") });
|
||||||
box.add_actor(label);
|
box.add_actor(label,
|
||||||
|
{ x_fill: true,
|
||||||
|
y_fill: true,
|
||||||
|
expand: true });
|
||||||
|
|
||||||
this._button.connect('clicked',
|
this._button.connect('clicked',
|
||||||
Lang.bind(this, this._onClicked));
|
Lang.bind(this, this._onClicked));
|
||||||
this._box.add_actor(this._button);
|
this._box.add_actor(this._button,
|
||||||
|
{ x_fill: true,
|
||||||
|
y_fill: true,
|
||||||
|
expand: true });
|
||||||
this._scrollView = new St.ScrollView({ style_class: 'login-dialog-session-list-scroll-view'});
|
this._scrollView = new St.ScrollView({ style_class: 'login-dialog-session-list-scroll-view'});
|
||||||
this._scrollView.set_policy(Gtk.PolicyType.NEVER,
|
this._scrollView.set_policy(Gtk.PolicyType.NEVER,
|
||||||
Gtk.PolicyType.AUTOMATIC);
|
Gtk.PolicyType.AUTOMATIC);
|
||||||
this._box.add_actor(this._scrollView);
|
this._box.add_actor(this._scrollView,
|
||||||
|
{ x_fill: true,
|
||||||
|
y_fill: true,
|
||||||
|
expand: true });
|
||||||
this._itemList = new St.BoxLayout({ style_class: 'login-dialog-session-item-list',
|
this._itemList = new St.BoxLayout({ style_class: 'login-dialog-session-item-list',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
this._scrollView.add_actor(this._itemList);
|
this._scrollView.add_actor(this._itemList,
|
||||||
|
{ x_fill: true,
|
||||||
|
y_fill: true,
|
||||||
|
expand: true });
|
||||||
this._scrollView.hide();
|
this._scrollView.hide();
|
||||||
this.isOpen = false;
|
this.isOpen = false;
|
||||||
this._populate();
|
this._populate();
|
||||||
@@ -630,11 +703,11 @@ const SessionList = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_populate: function() {
|
_populate: function() {
|
||||||
this._itemList.destroy_all_children();
|
this._itemList.destroy_children();
|
||||||
this._activeSessionId = null;
|
this._activeSessionId = null;
|
||||||
this._items = {};
|
this._items = {};
|
||||||
|
|
||||||
let ids = Gdm.get_session_ids();
|
let ids = GdmGreeter.get_session_ids();
|
||||||
ids.sort();
|
ids.sort();
|
||||||
|
|
||||||
if (ids.length <= 1) {
|
if (ids.length <= 1) {
|
||||||
@@ -646,10 +719,14 @@ const SessionList = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < ids.length; i++) {
|
for (let i = 0; i < ids.length; i++) {
|
||||||
let [sessionName, sessionDescription] = Gdm.get_session_name_and_description(ids[i]);
|
let [sessionName, sessionDescription] = GdmGreeter.get_session_name_and_description(ids[i]);
|
||||||
|
|
||||||
let item = new SessionListItem(ids[i], sessionName);
|
let item = new SessionListItem(ids[i], sessionName);
|
||||||
this._itemList.add_actor(item.actor);
|
this._itemList.add_actor(item.actor,
|
||||||
|
{ x_align: St.Align.START,
|
||||||
|
y_align: St.Align.START,
|
||||||
|
x_fill: true,
|
||||||
|
y_fill: true });
|
||||||
this._items[ids[i]] = item;
|
this._items[ids[i]] = item;
|
||||||
|
|
||||||
if (!this._activeSessionId)
|
if (!this._activeSessionId)
|
||||||
@@ -661,62 +738,68 @@ const SessionList = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(SessionList.prototype);
|
Signals.addSignalMethods(SessionList.prototype);
|
||||||
|
|
||||||
const LoginDialog = new Lang.Class({
|
function LoginDialog() {
|
||||||
Name: 'LoginDialog',
|
if (_loginDialog == null) {
|
||||||
Extends: ModalDialog.ModalDialog,
|
this._init();
|
||||||
|
_loginDialog = this;
|
||||||
|
}
|
||||||
|
|
||||||
_init: function(parentActor) {
|
return _loginDialog;
|
||||||
this.parent({ shellReactive: true,
|
}
|
||||||
styleClass: 'login-dialog',
|
|
||||||
parentActor: parentActor
|
LoginDialog.prototype = {
|
||||||
});
|
__proto__: ModalDialog.ModalDialog.prototype,
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
ModalDialog.ModalDialog.prototype._init.call(this, { shellReactive: true,
|
||||||
|
styleClass: 'login-dialog' });
|
||||||
this.connect('destroy',
|
this.connect('destroy',
|
||||||
Lang.bind(this, this._onDestroy));
|
Lang.bind(this, this._onDestroy));
|
||||||
this.connect('opened',
|
this.connect('opened',
|
||||||
Lang.bind(this, this._onOpened));
|
Lang.bind(this, this._onOpened));
|
||||||
|
|
||||||
this._userManager = AccountsService.UserManager.get_default()
|
this._userManager = AccountsService.UserManager.get_default()
|
||||||
this._greeterClient = new Gdm.Client();
|
this._greeterClient = new GdmGreeter.Client();
|
||||||
|
|
||||||
this._greeter = this._greeterClient.get_greeter_sync(null);
|
this._greeterClient.open_connection();
|
||||||
|
|
||||||
this._greeter.connect('default-session-name-changed',
|
this._greeterClient.call_start_conversation(_PASSWORD_SERVICE_NAME);
|
||||||
|
|
||||||
|
this._greeterClient.connect('reset',
|
||||||
|
Lang.bind(this, this._onReset));
|
||||||
|
this._greeterClient.connect('default-session-changed',
|
||||||
Lang.bind(this, this._onDefaultSessionChanged));
|
Lang.bind(this, this._onDefaultSessionChanged));
|
||||||
|
this._greeterClient.connect('info',
|
||||||
this._greeter.connect('session-opened',
|
Lang.bind(this, this._onInfo));
|
||||||
|
this._greeterClient.connect('problem',
|
||||||
|
Lang.bind(this, this._onProblem));
|
||||||
|
this._greeterClient.connect('info-query',
|
||||||
|
Lang.bind(this, this._onInfoQuery));
|
||||||
|
this._greeterClient.connect('secret-info-query',
|
||||||
|
Lang.bind(this, this._onSecretInfoQuery));
|
||||||
|
this._greeterClient.connect('session-opened',
|
||||||
Lang.bind(this, this._onSessionOpened));
|
Lang.bind(this, this._onSessionOpened));
|
||||||
this._greeter.connect('timed-login-requested',
|
this._greeterClient.connect('timed-login-requested',
|
||||||
Lang.bind(this, this._onTimedLoginRequested));
|
Lang.bind(this, this._onTimedLoginRequested));
|
||||||
|
this._greeterClient.connect('authentication-failed',
|
||||||
|
Lang.bind(this, this._onAuthenticationFailed));
|
||||||
|
this._greeterClient.connect('conversation-stopped',
|
||||||
|
Lang.bind(this, this._onConversationStopped));
|
||||||
|
|
||||||
this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient);
|
this._settings = new Gio.Settings({ schema: _LOGIN_SCREEN_SCHEMA });
|
||||||
this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion));
|
|
||||||
this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
|
|
||||||
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
|
||||||
|
|
||||||
this._userVerifier.connect('show-fingerprint-prompt', Lang.bind(this, this._showFingerprintPrompt));
|
this._fprintManager = new Fprint.FprintManager();
|
||||||
this._userVerifier.connect('hide-fingerprint-prompt', Lang.bind(this, this._hideFingerprintPrompt));
|
this._startFingerprintConversationIfNeeded();
|
||||||
|
this._settings.connect('changed::' + _LOGO_KEY,
|
||||||
this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
|
|
||||||
|
|
||||||
this._settings.connect('changed::' + GdmUtil.LOGO_KEY,
|
|
||||||
Lang.bind(this, this._updateLogo));
|
Lang.bind(this, this._updateLogo));
|
||||||
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
|
|
||||||
Lang.bind(this, this._updateBanner));
|
|
||||||
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_TEXT_KEY,
|
|
||||||
Lang.bind(this, this._updateBanner));
|
|
||||||
|
|
||||||
this._logoBox = new St.Bin({ style_class: 'login-dialog-logo-box' });
|
this._logoBox = new St.Bin({ style_class: 'login-dialog-logo-box' });
|
||||||
this.contentLayout.add(this._logoBox);
|
this.contentLayout.add(this._logoBox);
|
||||||
this._updateLogo();
|
this._updateLogo();
|
||||||
|
|
||||||
this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner',
|
|
||||||
text: '' });
|
|
||||||
this.contentLayout.add(this._bannerLabel);
|
|
||||||
this._updateBanner();
|
|
||||||
|
|
||||||
this._titleLabel = new St.Label({ style_class: 'login-dialog-title',
|
this._titleLabel = new St.Label({ style_class: 'login-dialog-title',
|
||||||
text: C_("title", "Sign In") });
|
text: C_("title", "Sign In") });
|
||||||
|
|
||||||
@@ -771,7 +854,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._sessionList = new SessionList();
|
this._sessionList = new SessionList();
|
||||||
this._sessionList.connect('session-activated',
|
this._sessionList.connect('session-activated',
|
||||||
Lang.bind(this, function(list, sessionId) {
|
Lang.bind(this, function(list, sessionId) {
|
||||||
this._greeter.call_select_session_sync (sessionId, null);
|
this._greeterClient.call_select_session (sessionId);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._promptBox.add(this._sessionList.actor,
|
this._promptBox.add(this._sessionList.actor,
|
||||||
@@ -819,9 +902,25 @@ const LoginDialog = new Lang.Class({
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_startFingerprintConversationIfNeeded: function() {
|
||||||
|
this._haveFingerprintReader = false;
|
||||||
|
|
||||||
|
if (!this._settings.get_boolean(_FINGERPRINT_AUTHENTICATION_KEY))
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._fprintManager.GetDefaultDeviceRemote(DBus.CALL_FLAG_START, Lang.bind(this,
|
||||||
|
function(device, error) {
|
||||||
|
if (!error && device)
|
||||||
|
this._haveFingerprintReader = true;
|
||||||
|
|
||||||
|
if (this._haveFingerprintReader)
|
||||||
|
this._greeterClient.call_start_conversation(_FINGERPRINT_SERVICE_NAME);
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
_updateLogo: function() {
|
_updateLogo: function() {
|
||||||
this._logoBox.child = null;
|
this._logoBox.child = null;
|
||||||
let path = this._settings.get_string(GdmUtil.LOGO_KEY);
|
let path = this._settings.get_string(_LOGO_KEY);
|
||||||
|
|
||||||
if (path) {
|
if (path) {
|
||||||
let file = Gio.file_new_for_path(path);
|
let file = Gio.file_new_for_path(path);
|
||||||
@@ -833,19 +932,10 @@ const LoginDialog = new Lang.Class({
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateBanner: function() {
|
|
||||||
let enabled = this._settings.get_boolean(GdmUtil.BANNER_MESSAGE_KEY);
|
|
||||||
let text = this._settings.get_string(GdmUtil.BANNER_MESSAGE_TEXT_KEY);
|
|
||||||
|
|
||||||
if (enabled && text) {
|
|
||||||
this._bannerLabel.set_text(text);
|
|
||||||
this._fadeInBanner();
|
|
||||||
} else {
|
|
||||||
this._fadeOutBanner();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_onReset: function(client, serviceName) {
|
_onReset: function(client, serviceName) {
|
||||||
|
this._greeterClient.call_start_conversation(_PASSWORD_SERVICE_NAME);
|
||||||
|
this._startFingerprintConversationIfNeeded();
|
||||||
|
|
||||||
let tasks = [this._hidePrompt,
|
let tasks = [this._hidePrompt,
|
||||||
|
|
||||||
new Batch.ConcurrentBatch(this, [this._fadeInTitleLabel,
|
new Batch.ConcurrentBatch(this, [this._fadeInTitleLabel,
|
||||||
@@ -875,25 +965,43 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._sessionList.setActiveSession(sessionId);
|
this._sessionList.setActiveSession(sessionId);
|
||||||
},
|
},
|
||||||
|
|
||||||
_showFingerprintPrompt: function() {
|
_onInfo: function(client, serviceName, info) {
|
||||||
GdmUtil.fadeInActor(this._promptFingerprintMessage);
|
// We don't display fingerprint messages, because they
|
||||||
|
// have words like UPEK in them. Instead we use the messages
|
||||||
|
// as a cue to display our own message.
|
||||||
|
if (serviceName == _FINGERPRINT_SERVICE_NAME &&
|
||||||
|
this._haveFingerprintReader &&
|
||||||
|
(!this._promptFingerprintMessage.visible ||
|
||||||
|
this._promptFingerprintMessage.opacity != 255)) {
|
||||||
|
|
||||||
|
_fadeInActor(this._promptFingerprintMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serviceName != _PASSWORD_SERVICE_NAME)
|
||||||
|
return;
|
||||||
|
Main.notifyError(info);
|
||||||
},
|
},
|
||||||
|
|
||||||
_hideFingerprintPrompt: function() {
|
_onProblem: function(client, serviceName, problem) {
|
||||||
GdmUtil.fadeOutActor(this._promptFingerprintMessage);
|
// we don't want to show auth failed messages to
|
||||||
|
// users who haven't enrolled their fingerprint.
|
||||||
|
if (serviceName != _PASSWORD_SERVICE_NAME)
|
||||||
|
return;
|
||||||
|
Main.notifyError(problem);
|
||||||
},
|
},
|
||||||
|
|
||||||
cancel: function() {
|
_onCancel: function(client) {
|
||||||
this._userVerifier.cancel();
|
this._greeterClient.call_cancel();
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeInPrompt: function() {
|
_fadeInPrompt: function() {
|
||||||
let tasks = [function() {
|
let tasks = [function() {
|
||||||
return GdmUtil.fadeInActor(this._promptLabel);
|
return _fadeInActor(this._promptLabel);
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
return GdmUtil.fadeInActor(this._promptEntry);
|
return _fadeInActor(this._promptEntry);
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
@@ -904,14 +1012,14 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
return GdmUtil.fadeInActor(this._promptBox);
|
return _fadeInActor(this._promptBox);
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
if (this._user && this._user.is_logged_in())
|
if (this._user && this._user.is_logged_in())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return GdmUtil.fadeInActor(this._sessionList.actor);
|
return _fadeInActor(this._sessionList.actor);
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
@@ -926,14 +1034,13 @@ const LoginDialog = new Lang.Class({
|
|||||||
_showPrompt: function() {
|
_showPrompt: function() {
|
||||||
let hold = new Batch.Hold();
|
let hold = new Batch.Hold();
|
||||||
|
|
||||||
let buttons = [{ action: Lang.bind(this, this.cancel),
|
let buttons = [{ action: Lang.bind(this, this._onCancel),
|
||||||
label: _("Cancel"),
|
label: _("Cancel"),
|
||||||
key: Clutter.Escape },
|
key: Clutter.Escape },
|
||||||
{ action: Lang.bind(this, function() {
|
{ action: Lang.bind(this, function() {
|
||||||
hold.release();
|
hold.release();
|
||||||
}),
|
}),
|
||||||
label: C_("button", "Sign In"),
|
label: C_("button", "Sign In") }];
|
||||||
default: true }];
|
|
||||||
|
|
||||||
this._promptEntryActivateCallbackId = this._promptEntry.clutter_text.connect('activate',
|
this._promptEntryActivateCallbackId = this._promptEntry.clutter_text.connect('activate',
|
||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
@@ -968,7 +1075,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
this.setButtons([]);
|
this.setButtons([]);
|
||||||
|
|
||||||
let tasks = [function() {
|
let tasks = [function() {
|
||||||
return GdmUtil.fadeOutActor(this._promptBox);
|
return _fadeOutActor(this._promptBox);
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
@@ -983,27 +1090,43 @@ const LoginDialog = new Lang.Class({
|
|||||||
return batch.run();
|
return batch.run();
|
||||||
},
|
},
|
||||||
|
|
||||||
_askQuestion: function(verifier, serviceName, question, passwordChar) {
|
_askQuestion: function(serviceName, question) {
|
||||||
this._promptLabel.set_text(question);
|
this._promptLabel.set_text(question);
|
||||||
|
|
||||||
this._promptEntry.set_text('');
|
|
||||||
this._promptEntry.clutter_text.set_password_char(passwordChar);
|
|
||||||
|
|
||||||
let tasks = [this._showPrompt,
|
let tasks = [this._showPrompt,
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
let _text = this._promptEntry.get_text();
|
let _text = this._promptEntry.get_text();
|
||||||
this._promptEntry.reactive = false;
|
this._promptEntry.reactive = false;
|
||||||
this._promptEntry.add_style_pseudo_class('insensitive');
|
this._promptEntry.add_style_pseudo_class('insensitive');
|
||||||
this._userVerifier.answerQuery(serviceName, _text);
|
this._greeterClient.call_answer_query(serviceName, _text);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||||
return batch.run();
|
return batch.run();
|
||||||
},
|
},
|
||||||
|
_onInfoQuery: function(client, serviceName, question) {
|
||||||
|
// We only expect questions to come from the main auth service
|
||||||
|
if (serviceName != _PASSWORD_SERVICE_NAME)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._promptEntry.set_text('');
|
||||||
|
this._promptEntry.clutter_text.set_password_char('');
|
||||||
|
this._askQuestion(serviceName, question);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onSecretInfoQuery: function(client, serviceName, secretQuestion) {
|
||||||
|
// We only expect secret requests to come from the main auth service
|
||||||
|
if (serviceName != _PASSWORD_SERVICE_NAME)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._promptEntry.set_text('');
|
||||||
|
this._promptEntry.clutter_text.set_password_char('\u25cf');
|
||||||
|
this._askQuestion(serviceName, secretQuestion);
|
||||||
|
},
|
||||||
|
|
||||||
_onSessionOpened: function(client, serviceName) {
|
_onSessionOpened: function(client, serviceName) {
|
||||||
this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
|
this._greeterClient.call_start_session_when_ready(serviceName, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
_waitForItemForUser: function(userName) {
|
_waitForItemForUser: function(userName) {
|
||||||
@@ -1030,7 +1153,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
|
|
||||||
_showTimedLoginAnimation: function() {
|
_showTimedLoginAnimation: function() {
|
||||||
this._timedLoginItem.actor.grab_key_focus();
|
this._timedLoginItem.actor.grab_key_focus();
|
||||||
return this._timedLoginItem.showTimedLoginIndicator(this._timedLoginAnimationTime);
|
return this._timedLoginItem.showFocusAnimation(this._timedLoginAnimationTime);
|
||||||
},
|
},
|
||||||
|
|
||||||
_blockTimedLoginUntilIdle: function() {
|
_blockTimedLoginUntilIdle: function() {
|
||||||
@@ -1071,6 +1194,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
// item.
|
// item.
|
||||||
if (!this.is_loaded) {
|
if (!this.is_loaded) {
|
||||||
this._userList.jumpToItem(this._timedLoginItem);
|
this._userList.jumpToItem(this._timedLoginItem);
|
||||||
|
this._timedLoginItem.showFocusAnimation(0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1084,7 +1208,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
|
|
||||||
function() {
|
function() {
|
||||||
this._timedLoginBatch = null;
|
this._timedLoginBatch = null;
|
||||||
this._greeter.call_begin_auto_login_sync(userName, null);
|
this._greeterClient.call_begin_auto_login(userName);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
this._timedLoginBatch = new Batch.ConsecutiveBatch(this, tasks);
|
this._timedLoginBatch = new Batch.ConsecutiveBatch(this, tasks);
|
||||||
@@ -1098,9 +1222,6 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._timedLoginBatch = null;
|
this._timedLoginBatch = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._timedLoginItem)
|
|
||||||
this._timedLoginItem.hideTimedLoginIndicator();
|
|
||||||
|
|
||||||
let userName = this._timedLoginItem.user.get_user_name();
|
let userName = this._timedLoginItem.user.get_user_name();
|
||||||
|
|
||||||
if (userName)
|
if (userName)
|
||||||
@@ -1130,8 +1251,19 @@ const LoginDialog = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_onVerificationFailed: function() {
|
_onAuthenticationFailed: function(client) {
|
||||||
this._userVerifier.cancel();
|
this._greeterClient.call_cancel();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onConversationStopped: function(client, serviceName) {
|
||||||
|
// if the password service fails, then cancel everything.
|
||||||
|
// But if, e.g., fingerprint fails, still give
|
||||||
|
// password authentication a chance to succeed
|
||||||
|
if (serviceName == _PASSWORD_SERVICE_NAME) {
|
||||||
|
this._greeterClient.call_cancel();
|
||||||
|
} else if (serviceName == _FINGERPRINT_SERVICE_NAME) {
|
||||||
|
_fadeOutActor(this._promptFingerprintMessage);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onNotListedClicked: function(user) {
|
_onNotListedClicked: function(user) {
|
||||||
@@ -1152,10 +1284,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._fadeOutLogo]),
|
this._fadeOutLogo]),
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
let hold = new Batch.Hold();
|
this._greeterClient.call_begin_verification(_PASSWORD_SERVICE_NAME);
|
||||||
|
|
||||||
this._userVerifier.begin(null, hold);
|
|
||||||
return hold;
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||||
@@ -1163,47 +1292,30 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_fadeInLogo: function() {
|
_fadeInLogo: function() {
|
||||||
return GdmUtil.fadeInActor(this._logoBox);
|
return _fadeInActor(this._logoBox);
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeOutLogo: function() {
|
_fadeOutLogo: function() {
|
||||||
return GdmUtil.fadeOutActor(this._logoBox);
|
return _fadeOutActor(this._logoBox);
|
||||||
},
|
|
||||||
|
|
||||||
_fadeInBanner: function() {
|
|
||||||
return GdmUtil.fadeInActor(this._bannerLabel);
|
|
||||||
},
|
|
||||||
|
|
||||||
_fadeOutBanner: function() {
|
|
||||||
return GdmUtil.fadeOutActor(this._bannerLabel);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeInTitleLabel: function() {
|
_fadeInTitleLabel: function() {
|
||||||
return GdmUtil.fadeInActor(this._titleLabel);
|
return _fadeInActor(this._titleLabel);
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeOutTitleLabel: function() {
|
_fadeOutTitleLabel: function() {
|
||||||
return GdmUtil.fadeOutActor(this._titleLabel);
|
return _fadeOutActor(this._titleLabel);
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeInNotListedButton: function() {
|
_fadeInNotListedButton: function() {
|
||||||
return GdmUtil.fadeInActor(this._notListedButton);
|
return _fadeInActor(this._notListedButton);
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeOutNotListedButton: function() {
|
_fadeOutNotListedButton: function() {
|
||||||
return GdmUtil.fadeOutActor(this._notListedButton);
|
return _fadeOutActor(this._notListedButton);
|
||||||
},
|
|
||||||
|
|
||||||
_beginVerificationForUser: function(userName) {
|
|
||||||
let hold = new Batch.Hold();
|
|
||||||
|
|
||||||
this._userVerifier.begin(userName, hold);
|
|
||||||
return hold;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onUserListActivated: function(activatedItem) {
|
_onUserListActivated: function(activatedItem) {
|
||||||
let userName;
|
|
||||||
|
|
||||||
let tasks = [function() {
|
let tasks = [function() {
|
||||||
this._userList.actor.reactive = false;
|
this._userList.actor.reactive = false;
|
||||||
return this._userList.pinInPlace();
|
return this._userList.pinInPlace();
|
||||||
@@ -1230,9 +1342,12 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
userName = activatedItem.user.get_user_name();
|
let userName = activatedItem.user.get_user_name();
|
||||||
|
this._greeterClient.call_begin_verification_for_user(_PASSWORD_SERVICE_NAME,
|
||||||
|
userName);
|
||||||
|
|
||||||
return this._beginVerificationForUser(userName);
|
if (this._haveFingerprintReader)
|
||||||
|
this._greeterClient.call_begin_verification_for_user(_FINGERPRINT_SERVICE_NAME, userName);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
this._user = activatedItem.user;
|
this._user = activatedItem.user;
|
||||||
@@ -1284,8 +1399,8 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
close: function() {
|
close: function() {
|
||||||
this.parent();
|
ModalDialog.ModalDialog.prototype.close.call(this);
|
||||||
|
|
||||||
Main.ctrlAltTabManager.removeGroup(this._group);
|
Main.ctrlAltTabManager.removeGroup(this._group);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|||||||
@@ -22,23 +22,20 @@ const Lang = imports.lang;
|
|||||||
const UPowerGlib = imports.gi.UPowerGlib;
|
const UPowerGlib = imports.gi.UPowerGlib;
|
||||||
|
|
||||||
const ConsoleKit = imports.gdm.consoleKit;
|
const ConsoleKit = imports.gdm.consoleKit;
|
||||||
const Systemd = imports.gdm.systemd;
|
|
||||||
|
|
||||||
const PanelMenu = imports.ui.panelMenu;
|
const PanelMenu = imports.ui.panelMenu;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
|
|
||||||
const PowerMenuButton = new Lang.Class({
|
function PowerMenuButton() {
|
||||||
Name: 'PowerMenuButton',
|
this._init();
|
||||||
Extends: PanelMenu.SystemStatusButton,
|
}
|
||||||
|
|
||||||
|
PowerMenuButton.prototype = {
|
||||||
|
__proto__: PanelMenu.SystemStatusButton.prototype,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('system-shutdown', null);
|
PanelMenu.SystemStatusButton.prototype._init.call(this, 'system-shutdown', null);
|
||||||
this._upClient = new UPowerGlib.Client();
|
|
||||||
|
|
||||||
if (Systemd.haveSystemd())
|
|
||||||
this._systemdLoginManager = new Systemd.SystemdLoginManager();
|
|
||||||
else
|
|
||||||
this._consoleKitManager = new ConsoleKit.ConsoleKitManager();
|
this._consoleKitManager = new ConsoleKit.ConsoleKitManager();
|
||||||
|
this._upClient = new UPowerGlib.Client();
|
||||||
|
|
||||||
this._createSubMenu();
|
this._createSubMenu();
|
||||||
|
|
||||||
@@ -60,67 +57,56 @@ const PowerMenuButton = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_updateVisibility: function() {
|
_updateVisibility: function() {
|
||||||
let shouldBeVisible = (this._haveSuspend || this._haveShutdown || this._haveRestart);
|
if (!this._haveSuspend && !this._haveShutdown && !this._haveRestart)
|
||||||
this.actor.visible = shouldBeVisible;
|
this.actor.hide();
|
||||||
|
else
|
||||||
|
this.actor.show();
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateHaveShutdown: function() {
|
_updateHaveShutdown: function() {
|
||||||
|
|
||||||
if (Systemd.haveSystemd()) {
|
|
||||||
this._systemdLoginManager.CanPowerOffRemote(Lang.bind(this,
|
|
||||||
function(result, error) {
|
|
||||||
if (!error)
|
|
||||||
this._haveShutdown = result[0] != 'no';
|
|
||||||
else
|
|
||||||
this._haveShutdown = false;
|
|
||||||
|
|
||||||
this._powerOffItem.actor.visible = this._haveShutdown;
|
|
||||||
this._updateVisibility();
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
this._consoleKitManager.CanStopRemote(Lang.bind(this,
|
this._consoleKitManager.CanStopRemote(Lang.bind(this,
|
||||||
function(result, error) {
|
function(result, error) {
|
||||||
if (!error)
|
if (!error)
|
||||||
this._haveShutdown = result[0];
|
this._haveShutdown = result;
|
||||||
else
|
else
|
||||||
this._haveShutdown = false;
|
this._haveShutdown = false;
|
||||||
|
|
||||||
this._powerOffItem.actor.visible = this._haveShutdown;
|
if (this._haveShutdown) {
|
||||||
|
this._powerOffItem.actor.show();
|
||||||
|
} else {
|
||||||
|
this._powerOffItem.actor.hide();
|
||||||
|
}
|
||||||
|
|
||||||
this._updateVisibility();
|
this._updateVisibility();
|
||||||
}));
|
}));
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateHaveRestart: function() {
|
_updateHaveRestart: function() {
|
||||||
|
|
||||||
if (Systemd.haveSystemd()) {
|
|
||||||
this._systemdLoginManager.CanRebootRemote(Lang.bind(this,
|
|
||||||
function(result, error) {
|
|
||||||
if (!error)
|
|
||||||
this._haveRestart = result[0] != 'no';
|
|
||||||
else
|
|
||||||
this._haveRestart = false;
|
|
||||||
|
|
||||||
this._restartItem.actor.visible = this._haveRestart;
|
|
||||||
this._updateVisibility();
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
this._consoleKitManager.CanRestartRemote(Lang.bind(this,
|
this._consoleKitManager.CanRestartRemote(Lang.bind(this,
|
||||||
function(result, error) {
|
function(result, error) {
|
||||||
if (!error)
|
if (!error)
|
||||||
this._haveRestart = result[0];
|
this._haveRestart = result;
|
||||||
else
|
else
|
||||||
this._haveRestart = false;
|
this._haveRestart = false;
|
||||||
|
|
||||||
this._restartItem.actor.visible = this._haveRestart;
|
if (this._haveRestart) {
|
||||||
|
this._restartItem.actor.show();
|
||||||
|
} else {
|
||||||
|
this._restartItem.actor.hide();
|
||||||
|
}
|
||||||
|
|
||||||
this._updateVisibility();
|
this._updateVisibility();
|
||||||
}));
|
}));
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateHaveSuspend: function() {
|
_updateHaveSuspend: function() {
|
||||||
this._haveSuspend = this._upClient.get_can_suspend();
|
this._haveSuspend = this._upClient.get_can_suspend();
|
||||||
this._suspendItem.actor.visible = this._haveSuspend;
|
|
||||||
|
if (this._haveSuspend)
|
||||||
|
this._suspendItem.actor.show();
|
||||||
|
else
|
||||||
|
this._suspendItem.actor.hide();
|
||||||
|
|
||||||
this._updateVisibility();
|
this._updateVisibility();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -149,22 +135,12 @@ const PowerMenuButton = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onActivateRestart: function() {
|
_onActivateRestart: function() {
|
||||||
if (!this._haveRestart)
|
if (this._haveRestart)
|
||||||
return;
|
|
||||||
|
|
||||||
if (Systemd.haveSystemd())
|
|
||||||
this._systemdLoginManager.RebootRemote(true);
|
|
||||||
else
|
|
||||||
this._consoleKitManager.RestartRemote();
|
this._consoleKitManager.RestartRemote();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onActivatePowerOff: function() {
|
_onActivatePowerOff: function() {
|
||||||
if (!this._haveShutdown)
|
if (this._haveShutdown)
|
||||||
return;
|
|
||||||
|
|
||||||
if (Systemd.haveSystemd())
|
|
||||||
this._systemdLoginManager.PowerOffRemote(true);
|
|
||||||
else
|
|
||||||
this._consoleKitManager.StopRemote();
|
this._consoleKitManager.StopRemote();
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const Gio = imports.gi.Gio;
|
|
||||||
|
|
||||||
const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager'>
|
|
||||||
<method name='PowerOff'>
|
|
||||||
<arg type='b' direction='in'/>
|
|
||||||
</method>
|
|
||||||
<method name='Reboot'>
|
|
||||||
<arg type='b' direction='in'/>
|
|
||||||
</method>
|
|
||||||
<method name='CanPowerOff'>
|
|
||||||
<arg type='s' direction='out'/>
|
|
||||||
</method>
|
|
||||||
<method name='CanReboot'>
|
|
||||||
<arg type='s' direction='out'/>
|
|
||||||
</method>
|
|
||||||
</interface>;
|
|
||||||
|
|
||||||
const SystemdLoginManagerProxy = Gio.DBusProxy.makeProxyWrapper(SystemdLoginManagerIface);
|
|
||||||
|
|
||||||
function SystemdLoginManager() {
|
|
||||||
return new SystemdLoginManagerProxy(Gio.DBus.system,
|
|
||||||
'org.freedesktop.login1',
|
|
||||||
'/org/freedesktop/login1');
|
|
||||||
};
|
|
||||||
|
|
||||||
function haveSystemd() {
|
|
||||||
return GLib.access("/sys/fs/cgroup/systemd", 0) >= 0;
|
|
||||||
}
|
|
||||||
268
js/gdm/util.js
@@ -1,268 +0,0 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
const Gio = imports.gi.Gio;
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const Signals = imports.signals;
|
|
||||||
|
|
||||||
const Batch = imports.gdm.batch;
|
|
||||||
const Fprint = imports.gdm.fingerprint;
|
|
||||||
const Main = imports.ui.main;
|
|
||||||
const Params = imports.misc.params;
|
|
||||||
const Tweener = imports.ui.tweener;
|
|
||||||
|
|
||||||
const PASSWORD_SERVICE_NAME = 'gdm-password';
|
|
||||||
const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
|
||||||
const FADE_ANIMATION_TIME = 0.16;
|
|
||||||
|
|
||||||
const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
|
||||||
const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
|
||||||
const BANNER_MESSAGE_KEY = 'banner-message-enable';
|
|
||||||
const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
|
|
||||||
|
|
||||||
const LOGO_KEY = 'logo';
|
|
||||||
|
|
||||||
function fadeInActor(actor) {
|
|
||||||
if (actor.opacity == 255 && actor.visible)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
let hold = new Batch.Hold();
|
|
||||||
actor.show();
|
|
||||||
let [minHeight, naturalHeight] = actor.get_preferred_height(-1);
|
|
||||||
|
|
||||||
actor.opacity = 0;
|
|
||||||
actor.set_height(0);
|
|
||||||
Tweener.addTween(actor,
|
|
||||||
{ opacity: 255,
|
|
||||||
height: naturalHeight,
|
|
||||||
time: FADE_ANIMATION_TIME,
|
|
||||||
transition: 'easeOutQuad',
|
|
||||||
onComplete: function() {
|
|
||||||
this.set_height(-1);
|
|
||||||
hold.release();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return hold;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fadeOutActor(actor) {
|
|
||||||
if (!actor.visible || actor.opacity == 0) {
|
|
||||||
actor.opacity = 0;
|
|
||||||
actor.hide();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let hold = new Batch.Hold();
|
|
||||||
Tweener.addTween(actor,
|
|
||||||
{ opacity: 0,
|
|
||||||
height: 0,
|
|
||||||
time: FADE_ANIMATION_TIME,
|
|
||||||
transition: 'easeOutQuad',
|
|
||||||
onComplete: function() {
|
|
||||||
this.hide();
|
|
||||||
this.set_height(-1);
|
|
||||||
hold.release();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return hold;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ShellUserVerifier = new Lang.Class({
|
|
||||||
Name: 'ShellUserVerifier',
|
|
||||||
|
|
||||||
_init: function(client, params) {
|
|
||||||
params = Params.parse(params, { reauthenticationOnly: false });
|
|
||||||
this._reauthOnly = params.reauthenticationOnly;
|
|
||||||
|
|
||||||
this._client = client;
|
|
||||||
|
|
||||||
this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
|
|
||||||
|
|
||||||
this._cancellable = new Gio.Cancellable();
|
|
||||||
|
|
||||||
this._fprintManager = new Fprint.FprintManager();
|
|
||||||
this._checkForFingerprintReader();
|
|
||||||
},
|
|
||||||
|
|
||||||
begin: function(userName, hold) {
|
|
||||||
this._hold = hold;
|
|
||||||
this._userName = userName;
|
|
||||||
|
|
||||||
if (userName) {
|
|
||||||
// If possible, reauthenticate an already running session,
|
|
||||||
// so any session specific credentials get updated appropriately
|
|
||||||
this._client.open_reauthentication_channel(userName, this._cancellable,
|
|
||||||
Lang.bind(this, this._reauthenticationChannelOpened));
|
|
||||||
} else {
|
|
||||||
this._client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
cancel: function() {
|
|
||||||
this._cancellable.cancel();
|
|
||||||
|
|
||||||
if (this._userVerifier)
|
|
||||||
this._userVerifier.call_cancel_sync(null);
|
|
||||||
},
|
|
||||||
|
|
||||||
clear: function() {
|
|
||||||
this._cancellable.cancel();
|
|
||||||
|
|
||||||
if (this._userVerifier) {
|
|
||||||
this._userVerifier.run_dispose();
|
|
||||||
this._userVerifier = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
answerQuery: function(serviceName, answer) {
|
|
||||||
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
|
|
||||||
},
|
|
||||||
|
|
||||||
_checkForFingerprintReader: function() {
|
|
||||||
this._haveFingerprintReader = false;
|
|
||||||
|
|
||||||
if (!this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY))
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._fprintManager.GetDefaultDeviceRemote(Gio.DBusCallFlags.NONE, this._cancellable, Lang.bind(this,
|
|
||||||
function(device, error) {
|
|
||||||
if (!error && device)
|
|
||||||
this._haveFingerprintReader = true;
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
_reauthenticationChannelOpened: function(client, result) {
|
|
||||||
try {
|
|
||||||
this._userVerifier = client.open_reauthentication_channel_finish(result);
|
|
||||||
this._connectSignals();
|
|
||||||
this._beginVerification();
|
|
||||||
|
|
||||||
this._hold.release();
|
|
||||||
} catch (e) {
|
|
||||||
if (this._reauthOnly) {
|
|
||||||
logError(e, 'Failed to open reauthentication channel');
|
|
||||||
|
|
||||||
this._hold.release();
|
|
||||||
this.emit('verification-failed');
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's no session running, or it otherwise fails, then fall back
|
|
||||||
// to performing verification from this login session
|
|
||||||
client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_userVerifierGot: function(client, result) {
|
|
||||||
this._userVerifier = client.get_user_verifier_finish(result);
|
|
||||||
this._connectSignals();
|
|
||||||
this._beginVerification();
|
|
||||||
|
|
||||||
this._hold.release();
|
|
||||||
},
|
|
||||||
|
|
||||||
_connectSignals: function() {
|
|
||||||
this._userVerifier.connect('info', Lang.bind(this, this._onInfo));
|
|
||||||
this._userVerifier.connect('problem', Lang.bind(this, this._onProblem));
|
|
||||||
this._userVerifier.connect('info-query', Lang.bind(this, this._onInfoQuery));
|
|
||||||
this._userVerifier.connect('secret-info-query', Lang.bind(this, this._onSecretInfoQuery));
|
|
||||||
this._userVerifier.connect('conversation-stopped', Lang.bind(this, this._onConversationStopped));
|
|
||||||
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
|
||||||
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
|
|
||||||
},
|
|
||||||
|
|
||||||
_beginVerification: function() {
|
|
||||||
this._hold.acquire();
|
|
||||||
|
|
||||||
if (this._userName) {
|
|
||||||
this._userVerifier.call_begin_verification_for_user(PASSWORD_SERVICE_NAME,
|
|
||||||
this._userName,
|
|
||||||
this._cancellable,
|
|
||||||
Lang.bind(this, function(obj, result) {
|
|
||||||
obj.call_begin_verification_for_user_finish(result);
|
|
||||||
this._hold.release();
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (this._haveFingerprintReader) {
|
|
||||||
this._hold.acquire();
|
|
||||||
|
|
||||||
this._userVerifier.call_begin_verification_for_user(FINGERPRINT_SERVICE_NAME,
|
|
||||||
this._userName,
|
|
||||||
this._cancellable,
|
|
||||||
Lang.bind(this, function(obj, result) {
|
|
||||||
obj.call_begin_verification_for_user_finish(result);
|
|
||||||
this._hold.release();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this._userVerifier.call_begin_verification(PASSWORD_SERVICE_NAME,
|
|
||||||
this._cancellable,
|
|
||||||
Lang.bind(this, function(obj, result) {
|
|
||||||
obj.call_begin_verification_finish(result);
|
|
||||||
this._hold.release();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_onInfo: function(client, serviceName, info) {
|
|
||||||
// We don't display fingerprint messages, because they
|
|
||||||
// have words like UPEK in them. Instead we use the messages
|
|
||||||
// as a cue to display our own message.
|
|
||||||
if (serviceName == FINGERPRINT_SERVICE_NAME &&
|
|
||||||
this._haveFingerprintReader) {
|
|
||||||
this.emit('show-fingerprint-prompt');
|
|
||||||
} else if (serviceName == PASSWORD_SERVICE_NAME) {
|
|
||||||
Main.notifyError(info);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_onProblem: function(client, serviceName, problem) {
|
|
||||||
// we don't want to show auth failed messages to
|
|
||||||
// users who haven't enrolled their fingerprint.
|
|
||||||
if (serviceName != PASSWORD_SERVICE_NAME)
|
|
||||||
return;
|
|
||||||
Main.notifyError(problem);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onInfoQuery: function(client, serviceName, question) {
|
|
||||||
// We only expect questions to come from the main auth service
|
|
||||||
if (serviceName != PASSWORD_SERVICE_NAME)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.emit('ask-question', serviceName, question, '');
|
|
||||||
},
|
|
||||||
|
|
||||||
_onSecretInfoQuery: function(client, serviceName, secretQuestion) {
|
|
||||||
// We only expect secret requests to come from the main auth service
|
|
||||||
if (serviceName != PASSWORD_SERVICE_NAME)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.emit('ask-question', serviceName, secretQuestion, '\u25cf');
|
|
||||||
},
|
|
||||||
|
|
||||||
_onReset: function() {
|
|
||||||
this._userVerifier.run_dispose();
|
|
||||||
this._userVerifier = null;
|
|
||||||
|
|
||||||
this._checkForFingerprintReader();
|
|
||||||
|
|
||||||
this.emit('reset');
|
|
||||||
},
|
|
||||||
|
|
||||||
_onVerificationComplete: function() {
|
|
||||||
this.emit('verification-complete');
|
|
||||||
},
|
|
||||||
|
|
||||||
_onConversationStopped: function(client, serviceName) {
|
|
||||||
// if the password service fails, then cancel everything.
|
|
||||||
// But if, e.g., fingerprint fails, still give
|
|
||||||
// password authentication a chance to succeed
|
|
||||||
if (serviceName == PASSWORD_SERVICE_NAME) {
|
|
||||||
this.emit('verification-failed');
|
|
||||||
} else if (serviceName == FINGERPRINT_SERVICE_NAME) {
|
|
||||||
this.emit('hide-fingerprint-prompt');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
Signals.addSignalMethods(ShellUserVerifier.prototype);
|
|
||||||
@@ -4,12 +4,9 @@
|
|||||||
const PACKAGE_NAME = '@PACKAGE_NAME@';
|
const PACKAGE_NAME = '@PACKAGE_NAME@';
|
||||||
/* The version of this package */
|
/* The version of this package */
|
||||||
const PACKAGE_VERSION = '@PACKAGE_VERSION@';
|
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 */
|
/* 1 if gnome-bluetooth is available, 0 otherwise */
|
||||||
const HAVE_BLUETOOTH = @HAVE_BLUETOOTH@;
|
const HAVE_BLUETOOTH = @HAVE_BLUETOOTH@;
|
||||||
/* gettext package */
|
/* The system TLS CA list */
|
||||||
const GETTEXT_PACKAGE = '@GETTEXT_PACKAGE@';
|
const SHELL_SYSTEM_CA_FILE = '@SHELL_SYSTEM_CA_FILE@';
|
||||||
/* locale dir */
|
|
||||||
const LOCALEDIR = '@datadir@/locale';
|
|
||||||
/* other standard directories */
|
|
||||||
const LIBEXECDIR = '@libexecdir@';
|
|
||||||
const SYSCONFDIR = '@sysconfdir@';
|
|
||||||
|
|||||||
140
js/misc/docInfo.js
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const St = imports.gi.St;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Signals = imports.signals;
|
||||||
|
const Search = imports.ui.search;
|
||||||
|
|
||||||
|
const THUMBNAIL_ICON_MARGIN = 2;
|
||||||
|
|
||||||
|
function DocInfo(recentInfo) {
|
||||||
|
this._init(recentInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
DocInfo.prototype = {
|
||||||
|
_init : function(recentInfo) {
|
||||||
|
this.recentInfo = recentInfo;
|
||||||
|
// We actually used get_modified() instead of get_visited()
|
||||||
|
// here, as GtkRecentInfo doesn't updated get_visited()
|
||||||
|
// correctly. See http://bugzilla.gnome.org/show_bug.cgi?id=567094
|
||||||
|
this.timestamp = recentInfo.get_modified();
|
||||||
|
this.name = recentInfo.get_display_name();
|
||||||
|
this._lowerName = this.name.toLowerCase();
|
||||||
|
this.uri = recentInfo.get_uri();
|
||||||
|
this.mimeType = recentInfo.get_mime_type();
|
||||||
|
},
|
||||||
|
|
||||||
|
createIcon : function(size) {
|
||||||
|
return St.TextureCache.get_default().load_recent_thumbnail(size, this.recentInfo);
|
||||||
|
},
|
||||||
|
|
||||||
|
launch : function(workspaceIndex) {
|
||||||
|
Shell.DocSystem.get_default().open(this.recentInfo, workspaceIndex);
|
||||||
|
},
|
||||||
|
|
||||||
|
matchTerms: function(terms) {
|
||||||
|
let mtype = Search.MatchType.NONE;
|
||||||
|
for (let i = 0; i < terms.length; i++) {
|
||||||
|
let term = terms[i];
|
||||||
|
let idx = this._lowerName.indexOf(term);
|
||||||
|
if (idx == 0) {
|
||||||
|
mtype = Search.MatchType.PREFIX;
|
||||||
|
} else if (idx > 0) {
|
||||||
|
if (mtype == Search.MatchType.NONE)
|
||||||
|
mtype = Search.MatchType.SUBSTRING;
|
||||||
|
} else {
|
||||||
|
return Search.MatchType.NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mtype;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var docManagerInstance = null;
|
||||||
|
|
||||||
|
function getDocManager() {
|
||||||
|
if (docManagerInstance == null)
|
||||||
|
docManagerInstance = new DocManager();
|
||||||
|
return docManagerInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DocManager wraps the DocSystem, primarily to expose DocInfo objects.
|
||||||
|
*/
|
||||||
|
function DocManager() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
DocManager.prototype = {
|
||||||
|
_init: function() {
|
||||||
|
this._docSystem = Shell.DocSystem.get_default();
|
||||||
|
this._infosByTimestamp = [];
|
||||||
|
this._infosByUri = {};
|
||||||
|
this._docSystem.connect('changed', Lang.bind(this, this._reload));
|
||||||
|
this._reload();
|
||||||
|
},
|
||||||
|
|
||||||
|
_reload: function() {
|
||||||
|
let docs = this._docSystem.get_all();
|
||||||
|
this._infosByTimestamp = [];
|
||||||
|
this._infosByUri = {};
|
||||||
|
for (let i = 0; i < docs.length; i++) {
|
||||||
|
let recentInfo = docs[i];
|
||||||
|
|
||||||
|
let docInfo = new DocInfo(recentInfo);
|
||||||
|
this._infosByTimestamp.push(docInfo);
|
||||||
|
this._infosByUri[docInfo.uri] = docInfo;
|
||||||
|
}
|
||||||
|
this.emit('changed');
|
||||||
|
},
|
||||||
|
|
||||||
|
getTimestampOrderedInfos: function() {
|
||||||
|
return this._infosByTimestamp;
|
||||||
|
},
|
||||||
|
|
||||||
|
getInfosByUri: function() {
|
||||||
|
return this._infosByUri;
|
||||||
|
},
|
||||||
|
|
||||||
|
lookupByUri: function(uri) {
|
||||||
|
return this._infosByUri[uri];
|
||||||
|
},
|
||||||
|
|
||||||
|
queueExistenceCheck: function(count) {
|
||||||
|
return this._docSystem.queue_existence_check(count);
|
||||||
|
},
|
||||||
|
|
||||||
|
_searchDocs: function(items, terms) {
|
||||||
|
let multiplePrefixMatches = [];
|
||||||
|
let prefixMatches = [];
|
||||||
|
let multipleSubtringMatches = [];
|
||||||
|
let substringMatches = [];
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
let item = items[i];
|
||||||
|
let mtype = item.matchTerms(terms);
|
||||||
|
if (mtype == Search.MatchType.MULTIPLE_PREFIX)
|
||||||
|
multiplePrefixMatches.push(item.uri);
|
||||||
|
else if (mtype == Search.MatchType.PREFIX)
|
||||||
|
prefixMatches.push(item.uri);
|
||||||
|
else if (mtype == Search.MatchType.MULTIPLE_SUBSTRING)
|
||||||
|
multipleSubtringMatches.push(item.uri);
|
||||||
|
else if (mtype == Search.MatchType.SUBSTRING)
|
||||||
|
substringMatches.push(item.uri);
|
||||||
|
}
|
||||||
|
return multiplePrefixMatches.concat(prefixMatches.concat(multipleSubtringMatches.concat(substringMatches)));
|
||||||
|
},
|
||||||
|
|
||||||
|
initialSearch: function(terms) {
|
||||||
|
return this._searchDocs(this._infosByTimestamp, terms);
|
||||||
|
},
|
||||||
|
|
||||||
|
subsearch: function(previousResults, terms) {
|
||||||
|
return this._searchDocs(previousResults.map(Lang.bind(this,
|
||||||
|
function(url) {
|
||||||
|
return this._infosByUri[url];
|
||||||
|
})), terms);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Signals.addSignalMethods(DocManager.prototype);
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
// Common utils for the extension system and the extension
|
|
||||||
// preferences tool
|
|
||||||
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const Signals = imports.signals;
|
|
||||||
|
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const Gio = imports.gi.Gio;
|
|
||||||
const ShellJS = imports.gi.ShellJS;
|
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
|
||||||
|
|
||||||
const ExtensionType = {
|
|
||||||
SYSTEM: 1,
|
|
||||||
PER_USER: 2
|
|
||||||
};
|
|
||||||
|
|
||||||
// Maps uuid -> metadata object
|
|
||||||
const extensions = {};
|
|
||||||
|
|
||||||
function getCurrentExtension() {
|
|
||||||
let stack = (new Error()).stack;
|
|
||||||
|
|
||||||
// Assuming we're importing this directly from an extension (and we shouldn't
|
|
||||||
// ever not be), its UUID should be directly in the path here.
|
|
||||||
let extensionStackLine = stack.split('\n')[1];
|
|
||||||
if (!extensionStackLine)
|
|
||||||
throw new Error('Could not find current extension');
|
|
||||||
|
|
||||||
// The stack line is like:
|
|
||||||
// init([object Object])@/home/user/data/gnome-shell/extensions/u@u.id/prefs.js:8
|
|
||||||
//
|
|
||||||
// In the case that we're importing from
|
|
||||||
// module scope, the first field is blank:
|
|
||||||
// @/home/user/data/gnome-shell/extensions/u@u.id/prefs.js:8
|
|
||||||
let match = new RegExp('@(.+):\\d+').exec(extensionStackLine);
|
|
||||||
if (!match)
|
|
||||||
throw new Error('Could not find current extension');
|
|
||||||
|
|
||||||
let path = match[1];
|
|
||||||
let file = Gio.File.new_for_path(path);
|
|
||||||
|
|
||||||
// Walk up the directory tree, looking for an extesion with
|
|
||||||
// the same UUID as a directory name.
|
|
||||||
while (file != null) {
|
|
||||||
let extension = extensions[file.get_basename()];
|
|
||||||
if (extension !== undefined)
|
|
||||||
return extension;
|
|
||||||
file = file.get_parent();
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error('Could not find current extension');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* versionCheck:
|
|
||||||
* @required: an array of versions we're compatible with
|
|
||||||
* @current: the version we have
|
|
||||||
*
|
|
||||||
* Check if a component is compatible for an extension.
|
|
||||||
* @required is an array, and at least one version must match.
|
|
||||||
* @current must be in the format <major>.<minor>.<point>.<micro>
|
|
||||||
* <micro> is always ignored
|
|
||||||
* <point> is ignored if <minor> is even (so you can target the
|
|
||||||
* whole stable release)
|
|
||||||
* <minor> and <major> must match
|
|
||||||
* Each target version must be at least <major> and <minor>
|
|
||||||
*/
|
|
||||||
function versionCheck(required, current) {
|
|
||||||
let currentArray = current.split('.');
|
|
||||||
let major = currentArray[0];
|
|
||||||
let minor = currentArray[1];
|
|
||||||
let point = currentArray[2];
|
|
||||||
for (let i = 0; i < required.length; i++) {
|
|
||||||
let requiredArray = required[i].split('.');
|
|
||||||
if (requiredArray[0] == major &&
|
|
||||||
requiredArray[1] == minor &&
|
|
||||||
(requiredArray[2] == point ||
|
|
||||||
(requiredArray[2] == undefined && parseInt(minor) % 2 == 0)))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isOutOfDate(extension) {
|
|
||||||
if (!versionCheck(extension.metadata['shell-version'], Config.PACKAGE_VERSION))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createExtensionObject(uuid, dir, type) {
|
|
||||||
let info;
|
|
||||||
|
|
||||||
let metadataFile = dir.get_child('metadata.json');
|
|
||||||
if (!metadataFile.query_exists(null)) {
|
|
||||||
throw new Error('Missing metadata.json');
|
|
||||||
}
|
|
||||||
|
|
||||||
let metadataContents, success, tag;
|
|
||||||
try {
|
|
||||||
[success, metadataContents, tag] = metadataFile.load_contents(null);
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error('Failed to load metadata.json: ' + e);
|
|
||||||
}
|
|
||||||
let meta;
|
|
||||||
try {
|
|
||||||
meta = JSON.parse(metadataContents);
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error('Failed to parse metadata.json: ' + e);
|
|
||||||
}
|
|
||||||
|
|
||||||
let requiredProperties = ['uuid', 'name', 'description', 'shell-version'];
|
|
||||||
for (let i = 0; i < requiredProperties.length; i++) {
|
|
||||||
let prop = requiredProperties[i];
|
|
||||||
if (!meta[prop]) {
|
|
||||||
throw new Error('missing "' + prop + '" property in metadata.json');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encourage people to add this
|
|
||||||
if (!meta.url) {
|
|
||||||
log('Warning: Missing "url" property in %s/metadata.json'.format(uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uuid != meta.uuid) {
|
|
||||||
throw new Error('uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"');
|
|
||||||
}
|
|
||||||
|
|
||||||
let extension = {};
|
|
||||||
|
|
||||||
extension.metadata = meta;
|
|
||||||
extension.uuid = meta.uuid;
|
|
||||||
extension.type = type;
|
|
||||||
extension.dir = dir;
|
|
||||||
extension.path = dir.get_path();
|
|
||||||
extension.error = '';
|
|
||||||
extension.hasPrefs = dir.get_child('prefs.js').query_exists(null);
|
|
||||||
|
|
||||||
extensions[uuid] = extension;
|
|
||||||
|
|
||||||
return extension;
|
|
||||||
}
|
|
||||||
|
|
||||||
var _extension = null;
|
|
||||||
|
|
||||||
function installImporter(extension) {
|
|
||||||
_extension = extension;
|
|
||||||
ShellJS.add_extension_importer('imports.misc.extensionUtils._extension', 'imports', extension.path);
|
|
||||||
_extension = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ExtensionFinder = new Lang.Class({
|
|
||||||
Name: 'ExtensionFinder',
|
|
||||||
|
|
||||||
_scanExtensionsInDirectory: function(dir, type) {
|
|
||||||
let fileEnum;
|
|
||||||
let file, info;
|
|
||||||
try {
|
|
||||||
fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
|
|
||||||
} catch(e) {
|
|
||||||
logError(e, 'Could not enumerate extensions directory');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((info = fileEnum.next_file(null)) != null) {
|
|
||||||
let fileType = info.get_file_type();
|
|
||||||
if (fileType != Gio.FileType.DIRECTORY)
|
|
||||||
continue;
|
|
||||||
let uuid = info.get_name();
|
|
||||||
let extensionDir = dir.get_child(uuid);
|
|
||||||
|
|
||||||
let existing = extensions[uuid];
|
|
||||||
if (existing) {
|
|
||||||
log('Extension %s already installed in %s. %s will not be loaded'.format(uuid, existing.path, extensionDir.get_path()));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let extension;
|
|
||||||
try {
|
|
||||||
extension = createExtensionObject(uuid, extensionDir, type);
|
|
||||||
} catch(e) {
|
|
||||||
logError(e, 'Could not load extension %s'.format(uuid));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
this.emit('extension-found', extension);
|
|
||||||
}
|
|
||||||
fileEnum.close(null);
|
|
||||||
},
|
|
||||||
|
|
||||||
scanExtensions: function() {
|
|
||||||
let userExtensionsDir = Gio.File.new_for_path(GLib.build_filenamev([global.userdatadir, 'extensions']));
|
|
||||||
this._scanExtensionsInDirectory(userExtensionsDir, ExtensionType.PER_USER);
|
|
||||||
|
|
||||||
let systemDataDirs = GLib.get_system_data_dirs();
|
|
||||||
for (let i = 0; i < systemDataDirs.length; i++) {
|
|
||||||
let dirPath = GLib.build_filenamev([systemDataDirs[i], 'gnome-shell', 'extensions']);
|
|
||||||
let dir = Gio.file_new_for_path(dirPath);
|
|
||||||
if (dir.query_exists(null))
|
|
||||||
this._scanExtensionsInDirectory(dir, ExtensionType.SYSTEM);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Signals.addSignalMethods(ExtensionFinder.prototype);
|
|
||||||
@@ -28,7 +28,7 @@ function deleteGFile(file) {
|
|||||||
return file['delete'](null);
|
return file['delete'](null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function recursivelyDeleteDir(dir, deleteParent) {
|
function recursivelyDeleteDir(dir) {
|
||||||
let children = dir.enumerate_children('standard::name,standard::type',
|
let children = dir.enumerate_children('standard::name,standard::type',
|
||||||
Gio.FileQueryInfoFlags.NONE, null);
|
Gio.FileQueryInfoFlags.NONE, null);
|
||||||
|
|
||||||
@@ -38,30 +38,9 @@ function recursivelyDeleteDir(dir, deleteParent) {
|
|||||||
let child = dir.get_child(info.get_name());
|
let child = dir.get_child(info.get_name());
|
||||||
if (type == Gio.FileType.REGULAR)
|
if (type == Gio.FileType.REGULAR)
|
||||||
deleteGFile(child);
|
deleteGFile(child);
|
||||||
else if (type == Gio.FileType.DIRECTORY)
|
else if (type == Gio.TypeType.DIRECTORY)
|
||||||
recursivelyDeleteDir(child, true);
|
recursivelyDeleteDir(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deleteParent)
|
|
||||||
deleteGFile(dir);
|
deleteGFile(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
function recursivelyMoveDir(srcDir, destDir) {
|
|
||||||
let children = srcDir.enumerate_children('standard::name,standard::type',
|
|
||||||
Gio.FileQueryInfoFlags.NONE, null);
|
|
||||||
|
|
||||||
if (!destDir.query_exists(null))
|
|
||||||
destDir.make_directory_with_parents(null);
|
|
||||||
|
|
||||||
let info, child;
|
|
||||||
while ((info = children.next_file(null)) != null) {
|
|
||||||
let type = info.get_file_type();
|
|
||||||
let srcChild = srcDir.get_child(info.get_name());
|
|
||||||
let destChild = destDir.get_child(info.get_name());
|
|
||||||
log([srcChild.get_path(), destChild.get_path()]);
|
|
||||||
if (type == Gio.FileType.REGULAR)
|
|
||||||
srcChild.move(destChild, Gio.FileCopyFlags.NONE, null, null);
|
|
||||||
else if (type == Gio.FileType.DIRECTORY)
|
|
||||||
recursivelyMoveDir(srcChild, destChild);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
60
js/misc/format.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is intended to extend the String object and provide
|
||||||
|
* an String.format API for string formatting.
|
||||||
|
* It has to be set up using String.prototype.format = Format.format;
|
||||||
|
* Usage:
|
||||||
|
* "somestring %s %d".format('hello', 5);
|
||||||
|
* It supports %s, %d, %x and %f, for %f it also support precisions like
|
||||||
|
* "%.2f".format(1.526). All specifiers can be prefixed with a minimum
|
||||||
|
* field width, e.g. "%5s".format("foo"). Unless the width is prefixed
|
||||||
|
* with '0', the formatted string will be padded with spaces.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function format() {
|
||||||
|
let str = this;
|
||||||
|
let i = 0;
|
||||||
|
let args = arguments;
|
||||||
|
|
||||||
|
return str.replace(/%([0-9]+)?(?:\.([0-9]+))?(.)/g, function (str, widthGroup, precisionGroup, genericGroup) {
|
||||||
|
|
||||||
|
if (precisionGroup != '' && genericGroup != 'f')
|
||||||
|
throw new Error("Precision can only be specified for 'f'");
|
||||||
|
|
||||||
|
let fillChar = (widthGroup[0] == '0') ? '0' : ' ';
|
||||||
|
let width = parseInt(widthGroup, 10) || 0;
|
||||||
|
|
||||||
|
function fillWidth(s, c, w) {
|
||||||
|
let fill = '';
|
||||||
|
for (let i = 0; i < w; i++)
|
||||||
|
fill += c;
|
||||||
|
return fill.substr(s.length) + s;
|
||||||
|
}
|
||||||
|
|
||||||
|
let s = '';
|
||||||
|
switch (genericGroup) {
|
||||||
|
case '%':
|
||||||
|
return '%';
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
s = args[i++].toString();
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
s = parseInt(args[i++]).toString();
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
s = parseInt(args[i++]).toString(16);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
if (precisionGroup == '')
|
||||||
|
s = parseFloat(args[i++]).toString();
|
||||||
|
else
|
||||||
|
s = parseFloat(args[i++]).toFixed(parseInt(precisionGroup));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('Unsupported conversion character %' + genericGroup);
|
||||||
|
}
|
||||||
|
return fillWidth(s, fillChar, width);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -31,12 +31,12 @@ function Presence(initCallback, cancellable) {
|
|||||||
// change at runtime (changes always come in the form
|
// change at runtime (changes always come in the form
|
||||||
// of new inhibitors)
|
// of new inhibitors)
|
||||||
const InhibitorIface = <interface name="org.gnome.SessionManager.Inhibitor">
|
const InhibitorIface = <interface name="org.gnome.SessionManager.Inhibitor">
|
||||||
<method name="GetAppId">
|
<property name="app_id" type="s" access="read" />
|
||||||
<arg type="s" direction="out" />
|
<property name="client_id" type="s" access="read" />
|
||||||
</method>
|
<property name="reason" type="s" access="read" />
|
||||||
<method name="GetReason">
|
<property name="flags" type="u" access="read" />
|
||||||
<arg type="s" direction="out" />
|
<property name="toplevel_xid" type="u" access="read" />
|
||||||
</method>
|
<property name="cookie" type="u" access="read" />
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
var InhibitorProxy = Gio.DBusProxy.makeProxyWrapper(InhibitorIface);
|
var InhibitorProxy = Gio.DBusProxy.makeProxyWrapper(InhibitorIface);
|
||||||
@@ -50,20 +50,9 @@ const SessionManagerIface = <interface name="org.gnome.SessionManager">
|
|||||||
<arg type="u" direction="in" />
|
<arg type="u" direction="in" />
|
||||||
</method>
|
</method>
|
||||||
<method name="Shutdown" />
|
<method name="Shutdown" />
|
||||||
<method name="Reboot" />
|
|
||||||
<method name="CanShutdown">
|
<method name="CanShutdown">
|
||||||
<arg type="b" direction="out" />
|
<arg type="b" direction="out" />
|
||||||
</method>
|
</method>
|
||||||
<method name="IsInhibited">
|
|
||||||
<arg type="u" direction="in" />
|
|
||||||
<arg type="b" direction="out" />
|
|
||||||
</method>
|
|
||||||
<signal name="InhibitorAdded">
|
|
||||||
<arg type="o" direction="out"/>
|
|
||||||
</signal>
|
|
||||||
<signal name="InhibitorRemoved">
|
|
||||||
<arg type="o" direction="out"/>
|
|
||||||
</signal>
|
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
var SessionManagerProxy = Gio.DBusProxy.makeProxyWrapper(SessionManagerIface);
|
var SessionManagerProxy = Gio.DBusProxy.makeProxyWrapper(SessionManagerIface);
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ const Params = imports.misc.params;
|
|||||||
|
|
||||||
const DEFAULT_LIMIT = 512;
|
const DEFAULT_LIMIT = 512;
|
||||||
|
|
||||||
const HistoryManager = new Lang.Class({
|
function HistoryManager(params) {
|
||||||
Name: 'HistoryManager',
|
this._init(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryManager.prototype = {
|
||||||
_init: function(params) {
|
_init: function(params) {
|
||||||
params = Params.parse(params, { gsettingsKey: null,
|
params = Params.parse(params, { gsettingsKey: null,
|
||||||
limit: DEFAULT_LIMIT,
|
limit: DEFAULT_LIMIT,
|
||||||
@@ -109,5 +111,5 @@ const HistoryManager = new Lang.Class({
|
|||||||
if (this._key)
|
if (this._key)
|
||||||
global.settings.set_strv(this._key, this._history);
|
global.settings.set_strv(this._key, this._history);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(HistoryManager.prototype);
|
Signals.addSignalMethods(HistoryManager.prototype);
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ const Signals = imports.signals;
|
|||||||
|
|
||||||
const ModemGsmNetworkInterface = <interface name="org.freedesktop.ModemManager.Modem.Gsm.Network">
|
const ModemGsmNetworkInterface = <interface name="org.freedesktop.ModemManager.Modem.Gsm.Network">
|
||||||
<method name="GetRegistrationInfo">
|
<method name="GetRegistrationInfo">
|
||||||
<arg type="(uss)" direction="out" />
|
<arg type="u" direction="out" />
|
||||||
|
<arg type="s" direction="out" />
|
||||||
|
<arg type="s" direction="out" />
|
||||||
</method>
|
</method>
|
||||||
<method name="GetSignalQuality">
|
<method name="GetSignalQuality">
|
||||||
<arg type="u" direction="out" />
|
<arg type="u" direction="out" />
|
||||||
@@ -33,7 +35,9 @@ const ModemCdmaInterface = <interface name="org.freedesktop.ModemManager.Modem.C
|
|||||||
<arg type="u" direction="out" />
|
<arg type="u" direction="out" />
|
||||||
</method>
|
</method>
|
||||||
<method name="GetServingSystem">
|
<method name="GetServingSystem">
|
||||||
<arg type="(usu)" direction="out" />
|
<arg type="u" direction="out" />
|
||||||
|
<arg type="s" direction="out" />
|
||||||
|
<arg type="u" direction="out" />
|
||||||
</method>
|
</method>
|
||||||
<signal name="SignalQuality">
|
<signal name="SignalQuality">
|
||||||
<arg type="u" direction="out" />
|
<arg type="u" direction="out" />
|
||||||
@@ -50,9 +54,11 @@ function _getProvidersTable() {
|
|||||||
return _providersTable = providers;
|
return _providersTable = providers;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ModemGsm = new Lang.Class({
|
function ModemGsm() {
|
||||||
Name: 'ModemGsm',
|
this._init.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModemGsm.prototype = {
|
||||||
_init: function(path) {
|
_init: function(path) {
|
||||||
this._proxy = new ModemGsmNetworkProxy(Gio.DBus.system, 'org.freedesktop.ModemManager', path);
|
this._proxy = new ModemGsmNetworkProxy(Gio.DBus.system, 'org.freedesktop.ModemManager', path);
|
||||||
|
|
||||||
@@ -68,7 +74,7 @@ const ModemGsm = new Lang.Class({
|
|||||||
this.operator_name = this._findOperatorName(name, code);
|
this.operator_name = this._findOperatorName(name, code);
|
||||||
this.emit('notify::operator-name');
|
this.emit('notify::operator-name');
|
||||||
}));
|
}));
|
||||||
this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function([result], err) {
|
this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function(result, err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
log(err);
|
log(err);
|
||||||
return;
|
return;
|
||||||
@@ -150,18 +156,20 @@ const ModemGsm = new Lang.Class({
|
|||||||
|
|
||||||
return name3 || name2 || null;
|
return name3 || name2 || null;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
Signals.addSignalMethods(ModemGsm.prototype);
|
Signals.addSignalMethods(ModemGsm.prototype);
|
||||||
|
|
||||||
const ModemCdma = new Lang.Class({
|
function ModemCdma() {
|
||||||
Name: 'ModemCdma',
|
this._init.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModemCdma.prototype = {
|
||||||
_init: function(path) {
|
_init: function(path) {
|
||||||
this._proxy = new ModemCdmaProxy(Gio.DBus.system, 'org.freedesktop.ModemManager', path);
|
this._proxy = new ModemCdmaProxy(Gio.DBus.system, 'org.freedesktop.ModemManager', path);
|
||||||
|
|
||||||
this.signal_quality = 0;
|
this.signal_quality = 0;
|
||||||
this.operator_name = null;
|
this.operator_name = null;
|
||||||
this._proxy.connectSignal('SignalQuality', Lang.bind(this, function(proxy, sender, params) {
|
this._proxy.connect('SignalQuality', Lang.bind(this, function(proxy, sender, params) {
|
||||||
this.signal_quality = params[0];
|
this.signal_quality = params[0];
|
||||||
this.emit('notify::signal-quality');
|
this.emit('notify::signal-quality');
|
||||||
|
|
||||||
@@ -183,7 +191,7 @@ const ModemCdma = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_refreshServingSystem: function() {
|
_refreshServingSystem: function() {
|
||||||
this._proxy.GetServingSystemRemote(Lang.bind(this, function([result], err) {
|
this._proxy.GetServingSystemRemote(Lang.bind(this, function(result, err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
// it will return an error if the device is not connected
|
// it will return an error if the device is not connected
|
||||||
this.operator_name = null;
|
this.operator_name = null;
|
||||||
@@ -223,5 +231,5 @@ const ModemCdma = new Lang.Class({
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(ModemCdma.prototype);
|
Signals.addSignalMethods(ModemCdma.prototype);
|
||||||
|
|||||||
48
js/misc/screenSaver.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
|
||||||
|
const ScreenSaverIface = <interface name="org.gnome.ScreenSaver">
|
||||||
|
<method name="GetActive">
|
||||||
|
<arg type="b" direction="out" />
|
||||||
|
</method>
|
||||||
|
<method name="Lock" />
|
||||||
|
<method name="SetActive">
|
||||||
|
<arg type="b" direction="in" />
|
||||||
|
</method>
|
||||||
|
<signal name="ActiveChanged">
|
||||||
|
<arg type="b" direction="out" />
|
||||||
|
</signal>
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
const ScreenSaverInfo = Gio.DBusInterfaceInfo.new_for_xml(ScreenSaverIface);
|
||||||
|
|
||||||
|
function ScreenSaverProxy() {
|
||||||
|
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.session,
|
||||||
|
g_interface_name: ScreenSaverInfo.name,
|
||||||
|
g_interface_info: ScreenSaverInfo,
|
||||||
|
g_name: 'org.gnome.ScreenSaver',
|
||||||
|
g_object_path: '/org/gnome/ScreenSaver',
|
||||||
|
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
|
||||||
|
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
||||||
|
self.init(null);
|
||||||
|
self.screenSaverActive = false;
|
||||||
|
|
||||||
|
self.connectSignal('ActiveChanged', function(proxy, senderName, [isActive]) {
|
||||||
|
self.screenSaverActive = isActive;
|
||||||
|
});
|
||||||
|
self.connect('notify::g-name-owner', function() {
|
||||||
|
if (self.g_name_owner) {
|
||||||
|
self.GetActiveRemote(function(result, excp) {
|
||||||
|
if (result) {
|
||||||
|
let [isActive] = result;
|
||||||
|
self.screenSaverActive = isActive;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else
|
||||||
|
self.screenSaverActive = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Gdk = imports.gi.Gdk;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
@@ -80,33 +83,24 @@ function spawnCommandLine(command_line) {
|
|||||||
// this will throw an error.
|
// this will throw an error.
|
||||||
function trySpawn(argv)
|
function trySpawn(argv)
|
||||||
{
|
{
|
||||||
var success, pid;
|
|
||||||
try {
|
try {
|
||||||
[success, pid] = GLib.spawn_async(null, argv, null,
|
GLib.spawn_async(null, argv, null,
|
||||||
GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
|
GLib.SpawnFlags.SEARCH_PATH,
|
||||||
null, null);
|
null, null);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
/* Rewrite the error in case of ENOENT */
|
if (err.code == GLib.SpawnError.G_SPAWN_ERROR_NOENT) {
|
||||||
if (err.matches(GLib.SpawnError, GLib.SpawnError.NOENT)) {
|
err.message = _("Command not found");
|
||||||
throw new GLib.SpawnError({ code: GLib.SpawnError.NOENT,
|
} else {
|
||||||
message: _("Command not found") });
|
|
||||||
} else if (err instanceof GLib.Error) {
|
|
||||||
// The exception from gjs contains an error string like:
|
// The exception from gjs contains an error string like:
|
||||||
// Error invoking GLib.spawn_command_line_async: Failed to
|
// Error invoking GLib.spawn_command_line_async: Failed to
|
||||||
// execute child process "foo" (No such file or directory)
|
// execute child process "foo" (No such file or directory)
|
||||||
// We are only interested in the part in the parentheses. (And
|
// We are only interested in the part in the parentheses. (And
|
||||||
// we can't pattern match the text, since it gets localized.)
|
// we can't pattern match the text, since it gets localized.)
|
||||||
let message = err.message.replace(/.*\((.+)\)/, '$1');
|
err.message = err.message.replace(/.*\((.+)\)/, '$1');
|
||||||
throw new (err.constructor)({ code: err.code,
|
}
|
||||||
message: message });
|
|
||||||
} else {
|
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Dummy child watch; we don't want to double-fork internally
|
|
||||||
// because then we lose the parent-child relationship, which
|
|
||||||
// can break polkit. See https://bugzilla.redhat.com//show_bug.cgi?id=819275
|
|
||||||
GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function () {}, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// trySpawnCommandLine:
|
// trySpawnCommandLine:
|
||||||
@@ -150,7 +144,7 @@ function killall(processName) {
|
|||||||
// whatever...
|
// whatever...
|
||||||
|
|
||||||
let argv = ['pkill', '-f', '^([^ ]*/)?' + processName + '($| )'];
|
let argv = ['pkill', '-f', '^([^ ]*/)?' + processName + '($| )'];
|
||||||
GLib.spawn_sync(null, argv, null, GLib.SpawnFlags.SEARCH_PATH, null);
|
GLib.spawn_sync(null, argv, null, GLib.SpawnFlags.SEARCH_PATH, null, null);
|
||||||
// It might be useful to return success/failure, but we'd need
|
// It might be useful to return success/failure, but we'd need
|
||||||
// a wrapper around WIFEXITED and WEXITSTATUS. Since none of
|
// a wrapper around WIFEXITED and WEXITSTATUS. Since none of
|
||||||
// the current callers care, we don't bother.
|
// the current callers care, we don't bother.
|
||||||
@@ -238,53 +232,3 @@ function fixupPCIDescription(desc) {
|
|||||||
|
|
||||||
return out.join(' ');
|
return out.join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
// lowerBound:
|
|
||||||
// @array: an array or array-like object, already sorted
|
|
||||||
// according to @cmp
|
|
||||||
// @val: the value to add
|
|
||||||
// @cmp: a comparator (or undefined to compare as numbers)
|
|
||||||
//
|
|
||||||
// Returns the position of the first element that is not
|
|
||||||
// lower than @val, according to @cmp.
|
|
||||||
// That is, returns the first position at which it
|
|
||||||
// is possible to insert @val without violating the
|
|
||||||
// order.
|
|
||||||
// This is quite like an ordinary binary search, except
|
|
||||||
// that it doesn't stop at first element comparing equal.
|
|
||||||
|
|
||||||
function lowerBound(array, val, cmp) {
|
|
||||||
let min, max, mid, v;
|
|
||||||
cmp = cmp || function(a, b) { return a - b; };
|
|
||||||
|
|
||||||
if (array.length == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
min = 0; max = array.length;
|
|
||||||
while (min < (max - 1)) {
|
|
||||||
mid = Math.floor((min + max) / 2);
|
|
||||||
v = cmp(array[mid], val);
|
|
||||||
|
|
||||||
if (v < 0)
|
|
||||||
min = mid + 1;
|
|
||||||
else
|
|
||||||
max = mid;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (min == max || cmp(array[min], val) < 0) ? max : min;
|
|
||||||
}
|
|
||||||
|
|
||||||
// insertSorted:
|
|
||||||
// @array: an array sorted according to @cmp
|
|
||||||
// @val: a value to insert
|
|
||||||
// @cmp: the sorting function
|
|
||||||
//
|
|
||||||
// Inserts @val into @array, preserving the
|
|
||||||
// sorting invariants.
|
|
||||||
// Returns the position at which it was inserted
|
|
||||||
function insertSorted(array, val, cmp) {
|
|
||||||
let pos = lowerBound(array, val, cmp);
|
|
||||||
array.splice(pos, 0, val);
|
|
||||||
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const System = imports.system;
|
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Scripting = imports.ui.scripting;
|
const Scripting = imports.ui.scripting;
|
||||||
|
|
||||||
@@ -101,7 +99,7 @@ function run() {
|
|||||||
Main.overview.hide();
|
Main.overview.hide();
|
||||||
yield Scripting.waitLeisure();
|
yield Scripting.waitLeisure();
|
||||||
|
|
||||||
System.gc();
|
global.gc();
|
||||||
yield Scripting.sleep(1000);
|
yield Scripting.sleep(1000);
|
||||||
Scripting.collectStatistics();
|
Scripting.collectStatistics();
|
||||||
Scripting.scriptEvent('afterShowHide');
|
Scripting.scriptEvent('afterShowHide');
|
||||||
|
|||||||
158
js/ui/altTab.js
@@ -2,14 +2,12 @@
|
|||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gdk = imports.gi.Gdk;
|
const Gdk = imports.gi.Gdk;
|
||||||
const Gtk = imports.gi.Gtk;
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Atk = imports.gi.Atk;
|
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
@@ -45,9 +43,11 @@ function primaryModifier(mask) {
|
|||||||
return primary;
|
return primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AltTabPopup = new Lang.Class({
|
function AltTabPopup() {
|
||||||
Name: 'AltTabPopup',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
AltTabPopup.prototype = {
|
||||||
_init : function() {
|
_init : function() {
|
||||||
this.actor = new Shell.GenericContainer({ name: 'altTabPopup',
|
this.actor = new Shell.GenericContainer({ name: 'altTabPopup',
|
||||||
reactive: true,
|
reactive: true,
|
||||||
@@ -127,7 +127,7 @@ const AltTabPopup = new Lang.Class({
|
|||||||
if (childBox.x2 > primary.x + primary.width - rightPadding)
|
if (childBox.x2 > primary.x + primary.width - rightPadding)
|
||||||
childBox.x2 = primary.x + primary.width - rightPadding;
|
childBox.x2 = primary.x + primary.width - rightPadding;
|
||||||
childBox.y1 = this._appSwitcher.actor.allocation.y2 + spacing;
|
childBox.y1 = this._appSwitcher.actor.allocation.y2 + spacing;
|
||||||
this._thumbnails.addClones(primary.y + primary.height - bottomPadding - childBox.y1);
|
this._thumbnails.addClones(primary.height - bottomPadding - childBox.y1);
|
||||||
let [childMinHeight, childNaturalHeight] = this._thumbnails.actor.get_preferred_height(-1);
|
let [childMinHeight, childNaturalHeight] = this._thumbnails.actor.get_preferred_height(-1);
|
||||||
childBox.y2 = childBox.y1 + childNaturalHeight;
|
childBox.y2 = childBox.y1 + childNaturalHeight;
|
||||||
this._thumbnails.actor.allocate(childBox, flags);
|
this._thumbnails.actor.allocate(childBox, flags);
|
||||||
@@ -141,7 +141,7 @@ const AltTabPopup = new Lang.Class({
|
|||||||
|
|
||||||
let screen = global.screen;
|
let screen = global.screen;
|
||||||
let display = screen.get_display();
|
let display = screen.get_display();
|
||||||
let windows = display.get_tab_list(Meta.TabList.NORMAL_ALL, screen,
|
let windows = display.get_tab_list(Meta.TabList.NORMAL, screen,
|
||||||
screen.get_active_workspace());
|
screen.get_active_workspace());
|
||||||
|
|
||||||
// windows is only the windows on the current workspace. For
|
// windows is only the windows on the current workspace. For
|
||||||
@@ -266,7 +266,7 @@ const AltTabPopup = new Lang.Class({
|
|||||||
|
|
||||||
_keyPressEvent : function(actor, event) {
|
_keyPressEvent : function(actor, event) {
|
||||||
let keysym = event.get_key_symbol();
|
let keysym = event.get_key_symbol();
|
||||||
let event_state = event.get_state();
|
let event_state = Shell.get_event_state(event);
|
||||||
let backwards = event_state & Clutter.ModifierType.SHIFT_MASK;
|
let backwards = event_state & Clutter.ModifierType.SHIFT_MASK;
|
||||||
let action = global.display.get_keybinding_action(event.get_key_code(), event_state);
|
let action = global.display.get_keybinding_action(event.get_key_code(), event_state);
|
||||||
|
|
||||||
@@ -519,7 +519,6 @@ const AltTabPopup = new Lang.Class({
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
this._thumbnails = null;
|
this._thumbnails = null;
|
||||||
this._appSwitcher._items[this._currentApp].remove_accessible_state (Atk.StateType.EXPANDED);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_createThumbnails : function() {
|
_createThumbnails : function() {
|
||||||
@@ -540,14 +539,14 @@ const AltTabPopup = new Lang.Class({
|
|||||||
transition: 'easeOutQuad',
|
transition: 'easeOutQuad',
|
||||||
onComplete: Lang.bind(this, function () { this.thumbnailsVisible = true; })
|
onComplete: Lang.bind(this, function () { this.thumbnailsVisible = true; })
|
||||||
});
|
});
|
||||||
|
|
||||||
this._appSwitcher._items[this._currentApp].add_accessible_state (Atk.StateType.EXPANDED);
|
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const SwitcherList = new Lang.Class({
|
function SwitcherList(squareItems) {
|
||||||
Name: 'SwitcherList',
|
this._init(squareItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitcherList.prototype = {
|
||||||
_init : function(squareItems) {
|
_init : function(squareItems) {
|
||||||
this.actor = new Shell.GenericContainer({ style_class: 'switcher-list' });
|
this.actor = new Shell.GenericContainer({ style_class: 'switcher-list' });
|
||||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||||
@@ -566,14 +565,14 @@ const SwitcherList = new Lang.Class({
|
|||||||
this._list.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
this._list.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||||
this._list.connect('allocate', Lang.bind(this, this._allocate));
|
this._list.connect('allocate', Lang.bind(this, this._allocate));
|
||||||
|
|
||||||
this._scrollView = new St.ScrollView({ style_class: 'hfade',
|
this._clipBin = new St.Bin({style_class: 'cbin'});
|
||||||
enable_mouse_scrolling: false });
|
this._clipBin.child = this._list;
|
||||||
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER);
|
this.actor.add_actor(this._clipBin);
|
||||||
|
|
||||||
let scrollBox = new St.BoxLayout();
|
this._leftGradient = new St.BoxLayout({style_class: 'thumbnail-scroll-gradient-left', vertical: true});
|
||||||
scrollBox.add_actor(this._list);
|
this._rightGradient = new St.BoxLayout({style_class: 'thumbnail-scroll-gradient-right', vertical: true});
|
||||||
this._scrollView.add_actor(scrollBox);
|
this.actor.add_actor(this._leftGradient);
|
||||||
this.actor.add_actor(this._scrollView);
|
this.actor.add_actor(this._rightGradient);
|
||||||
|
|
||||||
// Those arrows indicate whether scrolling in one direction is possible
|
// Those arrows indicate whether scrolling in one direction is possible
|
||||||
this._leftArrow = new St.DrawingArea({ style_class: 'switcher-arrow',
|
this._leftArrow = new St.DrawingArea({ style_class: 'switcher-arrow',
|
||||||
@@ -604,9 +603,21 @@ const SwitcherList = new Lang.Class({
|
|||||||
let childBox = new Clutter.ActorBox();
|
let childBox = new Clutter.ActorBox();
|
||||||
let scrollable = this._minSize > box.x2 - box.x1;
|
let scrollable = this._minSize > box.x2 - box.x1;
|
||||||
|
|
||||||
box.y1 -= this.actor.get_theme_node().get_padding(St.Side.TOP);
|
this._clipBin.allocate(box, flags);
|
||||||
box.y2 += this.actor.get_theme_node().get_padding(St.Side.BOTTOM);
|
|
||||||
this._scrollView.allocate(box, flags);
|
childBox.x1 = 0;
|
||||||
|
childBox.y1 = 0;
|
||||||
|
childBox.x2 = this._leftGradient.width;
|
||||||
|
childBox.y2 = this.actor.height;
|
||||||
|
this._leftGradient.allocate(childBox, flags);
|
||||||
|
this._leftGradient.opacity = (this._scrollableLeft && scrollable) ? 255 : 0;
|
||||||
|
|
||||||
|
childBox.x1 = (this.actor.allocation.x2 - this.actor.allocation.x1) - this._rightGradient.width;
|
||||||
|
childBox.y1 = 0;
|
||||||
|
childBox.x2 = childBox.x1 + this._rightGradient.width;
|
||||||
|
childBox.y2 = this.actor.height;
|
||||||
|
this._rightGradient.allocate(childBox, flags);
|
||||||
|
this._rightGradient.opacity = (this._scrollableRight && scrollable) ? 255 : 0;
|
||||||
|
|
||||||
let arrowWidth = Math.floor(leftPadding / 3);
|
let arrowWidth = Math.floor(leftPadding / 3);
|
||||||
let arrowHeight = arrowWidth * 2;
|
let arrowHeight = arrowWidth * 2;
|
||||||
@@ -615,7 +626,7 @@ const SwitcherList = new Lang.Class({
|
|||||||
childBox.x2 = childBox.x1 + arrowWidth;
|
childBox.x2 = childBox.x1 + arrowWidth;
|
||||||
childBox.y2 = childBox.y1 + arrowHeight;
|
childBox.y2 = childBox.y1 + arrowHeight;
|
||||||
this._leftArrow.allocate(childBox, flags);
|
this._leftArrow.allocate(childBox, flags);
|
||||||
this._leftArrow.opacity = (this._scrollableLeft && scrollable) ? 255 : 0;
|
this._leftArrow.opacity = this._leftGradient.opacity;
|
||||||
|
|
||||||
arrowWidth = Math.floor(rightPadding / 3);
|
arrowWidth = Math.floor(rightPadding / 3);
|
||||||
arrowHeight = arrowWidth * 2;
|
arrowHeight = arrowWidth * 2;
|
||||||
@@ -624,7 +635,7 @@ const SwitcherList = new Lang.Class({
|
|||||||
childBox.x2 = childBox.x1 + arrowWidth;
|
childBox.x2 = childBox.x1 + arrowWidth;
|
||||||
childBox.y2 = childBox.y1 + arrowHeight;
|
childBox.y2 = childBox.y1 + arrowHeight;
|
||||||
this._rightArrow.allocate(childBox, flags);
|
this._rightArrow.allocate(childBox, flags);
|
||||||
this._rightArrow.opacity = (this._scrollableRight && scrollable) ? 255 : 0;
|
this._rightArrow.opacity = this._rightGradient.opacity;
|
||||||
},
|
},
|
||||||
|
|
||||||
addItem : function(item, label) {
|
addItem : function(item, label) {
|
||||||
@@ -641,8 +652,6 @@ const SwitcherList = new Lang.Class({
|
|||||||
bbox.label_actor = label;
|
bbox.label_actor = label;
|
||||||
|
|
||||||
this._items.push(bbox);
|
this._items.push(bbox);
|
||||||
|
|
||||||
return bbox;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onItemClicked: function (index) {
|
_onItemClicked: function (index) {
|
||||||
@@ -674,32 +683,20 @@ const SwitcherList = new Lang.Class({
|
|||||||
this._items[this._highlighted].add_style_pseudo_class('selected');
|
this._items[this._highlighted].add_style_pseudo_class('selected');
|
||||||
}
|
}
|
||||||
|
|
||||||
let adjustment = this._scrollView.hscroll.adjustment;
|
|
||||||
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
|
|
||||||
let [absItemX, absItemY] = this._items[index].get_transformed_position();
|
let [absItemX, absItemY] = this._items[index].get_transformed_position();
|
||||||
let [result, posX, posY] = this.actor.transform_stage_point(absItemX, 0);
|
let [result, posX, posY] = this.actor.transform_stage_point(absItemX, 0);
|
||||||
let [containerWidth, containerHeight] = this.actor.get_transformed_size();
|
let [containerWidth, containerHeight] = this.actor.get_transformed_size();
|
||||||
if (posX + this._items[index].get_width() > containerWidth)
|
if (posX + this._items[index].get_width() > containerWidth)
|
||||||
this._scrollToRight();
|
this._scrollToRight();
|
||||||
else if (this._items[index].allocation.x1 - value < 0)
|
else if (posX < 0)
|
||||||
this._scrollToLeft();
|
this._scrollToLeft();
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_scrollToLeft : function() {
|
_scrollToLeft : function() {
|
||||||
let adjustment = this._scrollView.hscroll.adjustment;
|
let x = this._items[this._highlighted].allocation.x1;
|
||||||
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
|
|
||||||
|
|
||||||
let item = this._items[this._highlighted];
|
|
||||||
|
|
||||||
if (item.allocation.x1 < value)
|
|
||||||
value = Math.min(0, item.allocation.x1);
|
|
||||||
else if (item.allocation.x2 > value + pageSize)
|
|
||||||
value = Math.max(upper, item.allocation.x2 - pageSize);
|
|
||||||
|
|
||||||
this._scrollableRight = true;
|
this._scrollableRight = true;
|
||||||
Tweener.addTween(adjustment,
|
Tweener.addTween(this._list, { anchor_x: x,
|
||||||
{ value: value,
|
|
||||||
time: POPUP_SCROLL_TIME,
|
time: POPUP_SCROLL_TIME,
|
||||||
transition: 'easeOutQuad',
|
transition: 'easeOutQuad',
|
||||||
onComplete: Lang.bind(this, function () {
|
onComplete: Lang.bind(this, function () {
|
||||||
@@ -712,19 +709,12 @@ const SwitcherList = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_scrollToRight : function() {
|
_scrollToRight : function() {
|
||||||
let adjustment = this._scrollView.hscroll.adjustment;
|
|
||||||
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
|
|
||||||
|
|
||||||
let item = this._items[this._highlighted];
|
|
||||||
|
|
||||||
if (item.allocation.x1 < value)
|
|
||||||
value = Math.max(0, item.allocation.x1);
|
|
||||||
else if (item.allocation.x2 > value + pageSize)
|
|
||||||
value = Math.min(upper, item.allocation.x2 - pageSize);
|
|
||||||
|
|
||||||
this._scrollableLeft = true;
|
this._scrollableLeft = true;
|
||||||
Tweener.addTween(adjustment,
|
let monitor = Main.layoutManager.primaryMonitor;
|
||||||
{ value: value,
|
let padding = this.actor.get_theme_node().get_horizontal_padding();
|
||||||
|
let parentPadding = this.actor.get_parent().get_theme_node().get_horizontal_padding();
|
||||||
|
let x = this._items[this._highlighted].allocation.x2 - monitor.width + padding + parentPadding;
|
||||||
|
Tweener.addTween(this._list, { anchor_x: x,
|
||||||
time: POPUP_SCROLL_TIME,
|
time: POPUP_SCROLL_TIME,
|
||||||
transition: 'easeOutQuad',
|
transition: 'easeOutQuad',
|
||||||
onComplete: Lang.bind(this, function () {
|
onComplete: Lang.bind(this, function () {
|
||||||
@@ -819,6 +809,14 @@ const SwitcherList = new Lang.Class({
|
|||||||
|
|
||||||
let primary = Main.layoutManager.primaryMonitor;
|
let primary = Main.layoutManager.primaryMonitor;
|
||||||
let parentRightPadding = this.actor.get_parent().get_theme_node().get_padding(St.Side.RIGHT);
|
let parentRightPadding = this.actor.get_parent().get_theme_node().get_padding(St.Side.RIGHT);
|
||||||
|
if (this.actor.allocation.x2 == primary.x + primary.width - parentRightPadding) {
|
||||||
|
if (this._squareItems)
|
||||||
|
childWidth = childHeight;
|
||||||
|
else {
|
||||||
|
let [childMin, childNat] = children[0].get_preferred_width(childHeight);
|
||||||
|
childWidth = childMin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < children.length; i++) {
|
for (let i = 0; i < children.length; i++) {
|
||||||
if (this._items.indexOf(children[i]) != -1) {
|
if (this._items.indexOf(children[i]) != -1) {
|
||||||
@@ -844,14 +842,24 @@ const SwitcherList = new Lang.Class({
|
|||||||
// we don't allocate it.
|
// we don't allocate it.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
|
||||||
|
let rightPadding = this.actor.get_theme_node().get_padding(St.Side.RIGHT);
|
||||||
|
let topPadding = this.actor.get_theme_node().get_padding(St.Side.TOP);
|
||||||
|
let bottomPadding = this.actor.get_theme_node().get_padding(St.Side.BOTTOM);
|
||||||
|
|
||||||
|
// Clip the area for scrolling
|
||||||
|
this._clipBin.set_clip(0, -topPadding, (this.actor.allocation.x2 - this.actor.allocation.x1) - leftPadding - rightPadding, this.actor.height + bottomPadding);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
Signals.addSignalMethods(SwitcherList.prototype);
|
Signals.addSignalMethods(SwitcherList.prototype);
|
||||||
|
|
||||||
const AppIcon = new Lang.Class({
|
function AppIcon(app) {
|
||||||
Name: 'AppIcon',
|
this._init(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
AppIcon.prototype = {
|
||||||
_init: function(app) {
|
_init: function(app) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.actor = new St.BoxLayout({ style_class: 'alt-tab-app',
|
this.actor = new St.BoxLayout({ style_class: 'alt-tab-app',
|
||||||
@@ -869,14 +877,17 @@ const AppIcon = new Lang.Class({
|
|||||||
this._iconBin.set_size(size, size);
|
this._iconBin.set_size(size, size);
|
||||||
this._iconBin.child = this.icon;
|
this._iconBin.child = this.icon;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const AppSwitcher = new Lang.Class({
|
function AppSwitcher() {
|
||||||
Name: 'AppSwitcher',
|
this._init.apply(this, arguments);
|
||||||
Extends: SwitcherList,
|
}
|
||||||
|
|
||||||
|
AppSwitcher.prototype = {
|
||||||
|
__proto__ : SwitcherList.prototype,
|
||||||
|
|
||||||
_init : function(localApps, otherApps, altTabPopup) {
|
_init : function(localApps, otherApps, altTabPopup) {
|
||||||
this.parent(true);
|
SwitcherList.prototype._init.call(this, true);
|
||||||
|
|
||||||
// Construct the AppIcons, add to the popup
|
// Construct the AppIcons, add to the popup
|
||||||
let activeWorkspace = global.screen.get_active_workspace();
|
let activeWorkspace = global.screen.get_active_workspace();
|
||||||
@@ -955,7 +966,7 @@ const AppSwitcher = new Lang.Class({
|
|||||||
|
|
||||||
_allocate: function (actor, box, flags) {
|
_allocate: function (actor, box, flags) {
|
||||||
// Allocate the main list items
|
// Allocate the main list items
|
||||||
this.parent(actor, box, flags);
|
SwitcherList.prototype._allocate.call(this, actor, box, flags);
|
||||||
|
|
||||||
let arrowHeight = Math.floor(this.actor.get_theme_node().get_padding(St.Side.BOTTOM) / 3);
|
let arrowHeight = Math.floor(this.actor.get_theme_node().get_padding(St.Side.BOTTOM) / 3);
|
||||||
let arrowWidth = arrowHeight * 2;
|
let arrowWidth = arrowHeight * 2;
|
||||||
@@ -1010,7 +1021,7 @@ const AppSwitcher = new Lang.Class({
|
|||||||
this._arrows[this._curApp].remove_style_pseudo_class('highlighted');
|
this._arrows[this._curApp].remove_style_pseudo_class('highlighted');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.parent(n, justOutline);
|
SwitcherList.prototype.highlight.call(this, n, justOutline);
|
||||||
this._curApp = n;
|
this._curApp = n;
|
||||||
|
|
||||||
if (this._curApp != -1) {
|
if (this._curApp != -1) {
|
||||||
@@ -1023,7 +1034,7 @@ const AppSwitcher = new Lang.Class({
|
|||||||
|
|
||||||
_addIcon : function(appIcon) {
|
_addIcon : function(appIcon) {
|
||||||
this.icons.push(appIcon);
|
this.icons.push(appIcon);
|
||||||
let item = this.addItem(appIcon.actor, appIcon.label);
|
this.addItem(appIcon.actor, appIcon.label);
|
||||||
|
|
||||||
let n = this._arrows.length;
|
let n = this._arrows.length;
|
||||||
let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' });
|
let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' });
|
||||||
@@ -1033,17 +1044,18 @@ const AppSwitcher = new Lang.Class({
|
|||||||
|
|
||||||
if (appIcon.cachedWindows.length == 1)
|
if (appIcon.cachedWindows.length == 1)
|
||||||
arrow.hide();
|
arrow.hide();
|
||||||
else
|
|
||||||
item.add_accessible_state (Atk.StateType.EXPANDABLE);
|
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const ThumbnailList = new Lang.Class({
|
function ThumbnailList(windows) {
|
||||||
Name: 'ThumbnailList',
|
this._init(windows);
|
||||||
Extends: SwitcherList,
|
}
|
||||||
|
|
||||||
|
ThumbnailList.prototype = {
|
||||||
|
__proto__ : SwitcherList.prototype,
|
||||||
|
|
||||||
_init : function(windows) {
|
_init : function(windows) {
|
||||||
this.parent(false);
|
SwitcherList.prototype._init.call(this);
|
||||||
|
|
||||||
let activeWorkspace = global.screen.get_active_workspace();
|
let activeWorkspace = global.screen.get_active_workspace();
|
||||||
|
|
||||||
@@ -1121,7 +1133,7 @@ const ThumbnailList = new Lang.Class({
|
|||||||
// Make sure we only do this once
|
// Make sure we only do this once
|
||||||
this._thumbnailBins = new Array();
|
this._thumbnailBins = new Array();
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
function _drawArrow(area, side) {
|
function _drawArrow(area, side) {
|
||||||
let themeNode = area.get_theme_node();
|
let themeNode = area.get_theme_node();
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ const Signals = imports.signals;
|
|||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Atk = imports.gi.Atk;
|
|
||||||
|
|
||||||
const AppFavorites = imports.ui.appFavorites;
|
const AppFavorites = imports.ui.appFavorites;
|
||||||
const DND = imports.ui.dnd;
|
const DND = imports.ui.dnd;
|
||||||
@@ -22,22 +21,22 @@ const Search = imports.ui.search;
|
|||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
const Workspace = imports.ui.workspace;
|
const Workspace = imports.ui.workspace;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const Util = imports.misc.util;
|
|
||||||
|
|
||||||
const MAX_APPLICATION_WORK_MILLIS = 75;
|
const MAX_APPLICATION_WORK_MILLIS = 75;
|
||||||
const MENU_POPUP_TIMEOUT = 600;
|
const MENU_POPUP_TIMEOUT = 600;
|
||||||
const SCROLL_TIME = 0.1;
|
const SCROLL_TIME = 0.1;
|
||||||
|
|
||||||
const AlphabeticalView = new Lang.Class({
|
function AlphabeticalView() {
|
||||||
Name: 'AlphabeticalView',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
AlphabeticalView.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._grid = new IconGrid.IconGrid({ xAlign: St.Align.START });
|
this._grid = new IconGrid.IconGrid({ xAlign: St.Align.START });
|
||||||
this._appSystem = Shell.AppSystem.get_default();
|
this._appSystem = Shell.AppSystem.get_default();
|
||||||
|
|
||||||
this._pendingAppLaterId = 0;
|
this._pendingAppLaterId = 0;
|
||||||
this._appIcons = {}; // desktop file id
|
this._appIcons = {}; // desktop file id
|
||||||
this._allApps = [];
|
|
||||||
|
|
||||||
let box = new St.BoxLayout({ vertical: true });
|
let box = new St.BoxLayout({ vertical: true });
|
||||||
box.add(this._grid.actor, { y_align: St.Align.START, expand: true });
|
box.add(this._grid.actor, { y_align: St.Align.START, expand: true });
|
||||||
@@ -62,22 +61,16 @@ const AlphabeticalView = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
removeAll: function() {
|
_removeAll: function() {
|
||||||
this._grid.removeAll();
|
this._grid.removeAll();
|
||||||
this._appIcons = {};
|
this._appIcons = {};
|
||||||
this._allApps = [];
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addApp: function(app) {
|
_addApp: function(app) {
|
||||||
var id = app.get_id();
|
var id = app.get_id();
|
||||||
if (this._appIcons[id] !== undefined)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let appIcon = new AppWellIcon(app);
|
let appIcon = new AppWellIcon(app);
|
||||||
let pos = Util.insertSorted(this._allApps, app, function(a, b) {
|
|
||||||
return a.compare_by_name(b);
|
this._grid.addItem(appIcon.actor);
|
||||||
});
|
|
||||||
this._grid.addItem(appIcon.actor, pos);
|
|
||||||
appIcon.actor.connect('key-focus-in', Lang.bind(this, this._ensureIconVisible));
|
appIcon.actor.connect('key-focus-in', Lang.bind(this, this._ensureIconVisible));
|
||||||
|
|
||||||
this._appIcons[id] = appIcon;
|
this._appIcons[id] = appIcon;
|
||||||
@@ -128,12 +121,22 @@ const AlphabeticalView = new Lang.Class({
|
|||||||
icon.actor.visible = true;
|
icon.actor.visible = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setAppList: function(apps) {
|
||||||
|
this._removeAll();
|
||||||
|
for (var i = 0; i < apps.length; i++) {
|
||||||
|
var app = apps[i];
|
||||||
|
this._addApp(app);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const ViewByCategories = new Lang.Class({
|
function ViewByCategories() {
|
||||||
Name: 'ViewByCategories',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewByCategories.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._appSystem = Shell.AppSystem.get_default();
|
this._appSystem = Shell.AppSystem.get_default();
|
||||||
this.actor = new St.BoxLayout({ style_class: 'all-app' });
|
this.actor = new St.BoxLayout({ style_class: 'all-app' });
|
||||||
@@ -147,10 +150,9 @@ const ViewByCategories = new Lang.Class({
|
|||||||
// (used only before the actor is mapped the first time)
|
// (used only before the actor is mapped the first time)
|
||||||
this._currentCategory = -2;
|
this._currentCategory = -2;
|
||||||
this._categories = [];
|
this._categories = [];
|
||||||
|
this._apps = null;
|
||||||
|
|
||||||
this._categoryBox = new St.BoxLayout({ vertical: true,
|
this._categoryBox = new St.BoxLayout({ vertical: true, reactive: true });
|
||||||
reactive: true,
|
|
||||||
accessible_role: Atk.Role.LIST });
|
|
||||||
this._categoryScroll = new St.ScrollView({ x_fill: false,
|
this._categoryScroll = new St.ScrollView({ x_fill: false,
|
||||||
y_fill: false,
|
y_fill: false,
|
||||||
style_class: 'vfade' });
|
style_class: 'vfade' });
|
||||||
@@ -203,30 +205,27 @@ const ViewByCategories = new Lang.Class({
|
|||||||
if (nextType == GMenu.TreeItemType.ENTRY) {
|
if (nextType == GMenu.TreeItemType.ENTRY) {
|
||||||
var entry = iter.get_entry();
|
var entry = iter.get_entry();
|
||||||
var app = this._appSystem.lookup_app_by_tree_entry(entry);
|
var app = this._appSystem.lookup_app_by_tree_entry(entry);
|
||||||
if (!entry.get_app_info().get_nodisplay()) {
|
if (!entry.get_app_info().get_nodisplay())
|
||||||
this._view.addApp(app);
|
|
||||||
appList.push(app);
|
appList.push(app);
|
||||||
}
|
|
||||||
} else if (nextType == GMenu.TreeItemType.DIRECTORY) {
|
} else if (nextType == GMenu.TreeItemType.DIRECTORY) {
|
||||||
var itemDir = iter.get_directory();
|
if (!dir.get_is_nodisplay())
|
||||||
if (!itemDir.get_is_nodisplay())
|
this._loadCategory(iter.get_directory(), appList);
|
||||||
this._loadCategory(itemDir, appList);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_addCategory: function(name, index, dir) {
|
_addCategory: function(name, index, dir, allApps) {
|
||||||
let button = new St.Button({ label: GLib.markup_escape_text (name, -1),
|
let button = new St.Button({ label: GLib.markup_escape_text (name, -1),
|
||||||
style_class: 'app-filter',
|
style_class: 'app-filter',
|
||||||
x_align: St.Align.START,
|
x_align: St.Align.START,
|
||||||
can_focus: true ,
|
can_focus: true });
|
||||||
accessible_role: Atk.Role.LIST_ITEM });
|
|
||||||
button.connect('clicked', Lang.bind(this, function() {
|
button.connect('clicked', Lang.bind(this, function() {
|
||||||
this._selectCategory(index);
|
this._selectCategory(index);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
var apps;
|
var apps;
|
||||||
if (dir == null) {
|
if (dir == null) {
|
||||||
|
apps = allApps;
|
||||||
this._allCategoryButton = button;
|
this._allCategoryButton = button;
|
||||||
} else {
|
} else {
|
||||||
apps = [];
|
apps = [];
|
||||||
@@ -240,16 +239,20 @@ const ViewByCategories = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_removeAll: function() {
|
_removeAll: function() {
|
||||||
this._view.removeAll();
|
|
||||||
this._categories = [];
|
this._categories = [];
|
||||||
this._categoryBox.destroy_all_children();
|
this._categoryBox.destroy_children();
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function() {
|
refresh: function() {
|
||||||
this._removeAll();
|
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 */
|
/* Translators: Filter to display all applications */
|
||||||
this._addCategory(_("All"), -1, null);
|
this._addCategory(_("All"), -1, null, allApps);
|
||||||
|
|
||||||
var tree = this._appSystem.get_tree();
|
var tree = this._appSystem.get_tree();
|
||||||
var root = tree.get_root_directory();
|
var root = tree.get_root_directory();
|
||||||
@@ -267,6 +270,7 @@ const ViewByCategories = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._view.setAppList(allApps);
|
||||||
this._selectCategory(-1);
|
this._selectCategory(-1);
|
||||||
|
|
||||||
if (this._focusDummy) {
|
if (this._focusDummy) {
|
||||||
@@ -277,14 +281,16 @@ const ViewByCategories = new Lang.Class({
|
|||||||
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
/* This class represents a display containing a collection of application items.
|
/* This class represents a display containing a collection of application items.
|
||||||
* The applications are sorted based on their name.
|
* The applications are sorted based on their name.
|
||||||
*/
|
*/
|
||||||
const AllAppDisplay = new Lang.Class({
|
function AllAppDisplay() {
|
||||||
Name: 'AllAppDisplay',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
AllAppDisplay.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._appSystem = Shell.AppSystem.get_default();
|
this._appSystem = Shell.AppSystem.get_default();
|
||||||
this._appSystem.connect('installed-changed', Lang.bind(this, function() {
|
this._appSystem.connect('installed-changed', Lang.bind(this, function() {
|
||||||
@@ -300,37 +306,35 @@ const AllAppDisplay = new Lang.Class({
|
|||||||
_redisplay: function() {
|
_redisplay: function() {
|
||||||
this._appView.refresh();
|
this._appView.refresh();
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const AppSearchProvider = new Lang.Class({
|
function AppSearchProvider() {
|
||||||
Name: 'AppSearchProvider',
|
this._init();
|
||||||
Extends: Search.SearchProvider,
|
}
|
||||||
|
|
||||||
|
AppSearchProvider.prototype = {
|
||||||
|
__proto__: Search.SearchProvider.prototype,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent(_("APPLICATIONS"));
|
Search.SearchProvider.prototype._init.call(this, _("APPLICATIONS"));
|
||||||
this._appSys = Shell.AppSystem.get_default();
|
this._appSys = Shell.AppSystem.get_default();
|
||||||
},
|
},
|
||||||
|
|
||||||
getResultMetas: function(apps, callback) {
|
getResultMeta: function(app) {
|
||||||
let metas = [];
|
return { 'id': app,
|
||||||
for (let i = 0; i < apps.length; i++) {
|
|
||||||
let app = apps[i];
|
|
||||||
metas.push({ 'id': app,
|
|
||||||
'name': app.get_name(),
|
'name': app.get_name(),
|
||||||
'createIcon': function(size) {
|
'createIcon': function(size) {
|
||||||
return app.create_icon_texture(size);
|
return app.create_icon_texture(size);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
}
|
|
||||||
callback(metas);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialResultSet: function(terms) {
|
getInitialResultSet: function(terms) {
|
||||||
this.searchSystem.pushResults(this, this._appSys.initial_search(terms));
|
return this._appSys.initial_search(terms);
|
||||||
},
|
},
|
||||||
|
|
||||||
getSubsearchResultSet: function(previousResults, terms) {
|
getSubsearchResultSet: function(previousResults, terms) {
|
||||||
this.searchSystem.pushResults(this, this._appSys.subsearch(previousResults, terms));
|
return this._appSys.subsearch(previousResults, terms);
|
||||||
},
|
},
|
||||||
|
|
||||||
activateResult: function(app, params) {
|
activateResult: function(app, params) {
|
||||||
@@ -338,7 +342,7 @@ const AppSearchProvider = new Lang.Class({
|
|||||||
timestamp: 0 });
|
timestamp: 0 });
|
||||||
|
|
||||||
let event = Clutter.get_current_event();
|
let event = Clutter.get_current_event();
|
||||||
let modifiers = event ? event.get_state() : 0;
|
let modifiers = event ? Shell.get_event_state(event) : 0;
|
||||||
let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK;
|
let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK;
|
||||||
|
|
||||||
if (openNewWindow)
|
if (openNewWindow)
|
||||||
@@ -360,39 +364,36 @@ const AppSearchProvider = new Lang.Class({
|
|||||||
let icon = new AppWellIcon(app);
|
let icon = new AppWellIcon(app);
|
||||||
return icon.actor;
|
return icon.actor;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const SettingsSearchProvider = new Lang.Class({
|
function SettingsSearchProvider() {
|
||||||
Name: 'SettingsSearchProvider',
|
this._init();
|
||||||
Extends: Search.SearchProvider,
|
}
|
||||||
|
|
||||||
|
SettingsSearchProvider.prototype = {
|
||||||
|
__proto__: Search.SearchProvider.prototype,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent(_("SETTINGS"));
|
Search.SearchProvider.prototype._init.call(this, _("SETTINGS"));
|
||||||
|
|
||||||
this._appSys = Shell.AppSystem.get_default();
|
this._appSys = Shell.AppSystem.get_default();
|
||||||
this._gnomecc = this._appSys.lookup_app('gnome-control-center.desktop');
|
this._gnomecc = this._appSys.lookup_app('gnome-control-center.desktop');
|
||||||
},
|
},
|
||||||
|
|
||||||
getResultMetas: function(prefs, callback) {
|
getResultMeta: function(pref) {
|
||||||
let metas = [];
|
return { 'id': pref,
|
||||||
for (let i = 0; i < prefs.length; i++) {
|
|
||||||
let pref = prefs[i];
|
|
||||||
metas.push({ 'id': pref,
|
|
||||||
'name': pref.get_name(),
|
'name': pref.get_name(),
|
||||||
'createIcon': function(size) {
|
'createIcon': function(size) {
|
||||||
return pref.create_icon_texture(size);
|
return pref.create_icon_texture(size);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
}
|
|
||||||
callback(metas);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialResultSet: function(terms) {
|
getInitialResultSet: function(terms) {
|
||||||
this.searchSystem.pushResults(this, this._appSys.search_settings(terms));
|
return this._appSys.search_settings(terms);
|
||||||
},
|
},
|
||||||
|
|
||||||
getSubsearchResultSet: function(previousResults, terms) {
|
getSubsearchResultSet: function(previousResults, terms) {
|
||||||
this.searchSystem.pushResults(this, this._appSys.search_settings(terms));
|
return this._appSys.search_settings(terms);
|
||||||
},
|
},
|
||||||
|
|
||||||
activateResult: function(pref, params) {
|
activateResult: function(pref, params) {
|
||||||
@@ -411,28 +412,35 @@ const SettingsSearchProvider = new Lang.Class({
|
|||||||
let icon = new AppWellIcon(app);
|
let icon = new AppWellIcon(app);
|
||||||
return icon.actor;
|
return icon.actor;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const AppIcon = new Lang.Class({
|
function AppIcon(app, params) {
|
||||||
Name: 'AppIcon',
|
this._init(app, params);
|
||||||
Extends: IconGrid.BaseIcon,
|
}
|
||||||
|
|
||||||
|
AppIcon.prototype = {
|
||||||
|
__proto__: IconGrid.BaseIcon.prototype,
|
||||||
|
|
||||||
_init : function(app, params) {
|
_init : function(app, params) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
|
|
||||||
let label = this.app.get_name();
|
let label = this.app.get_name();
|
||||||
|
|
||||||
this.parent(label, params);
|
IconGrid.BaseIcon.prototype._init.call(this,
|
||||||
|
label,
|
||||||
|
params);
|
||||||
},
|
},
|
||||||
|
|
||||||
createIcon: function(iconSize) {
|
createIcon: function(iconSize) {
|
||||||
return this.app.create_icon_texture(iconSize);
|
return this.app.create_icon_texture(iconSize);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const AppWellIcon = new Lang.Class({
|
function AppWellIcon(app, iconParams, onActivateOverride) {
|
||||||
Name: 'AppWellIcon',
|
this._init(app, iconParams, onActivateOverride);
|
||||||
|
}
|
||||||
|
|
||||||
|
AppWellIcon.prototype = {
|
||||||
_init : function(app, iconParams, onActivateOverride) {
|
_init : function(app, iconParams, onActivateOverride) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.actor = new St.Button({ style_class: 'app-well-app',
|
this.actor = new St.Button({ style_class: 'app-well-app',
|
||||||
@@ -479,7 +487,6 @@ const AppWellIcon = new Lang.Class({
|
|||||||
Lang.bind(this,
|
Lang.bind(this,
|
||||||
this._onStateChanged));
|
this._onStateChanged));
|
||||||
this._onStateChanged();
|
this._onStateChanged();
|
||||||
this.isMenuUp = false;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDestroy: function() {
|
_onDestroy: function() {
|
||||||
@@ -561,8 +568,8 @@ const AppWellIcon = new Lang.Class({
|
|||||||
this._menuManager.addMenu(this._menu);
|
this._menuManager.addMenu(this._menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isMenuUp = true;
|
|
||||||
this.actor.set_hover(true);
|
this.actor.set_hover(true);
|
||||||
|
this.actor.show_tooltip();
|
||||||
this._menu.popup();
|
this._menu.popup();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -578,12 +585,11 @@ const AppWellIcon = new Lang.Class({
|
|||||||
|
|
||||||
_onMenuPoppedDown: function() {
|
_onMenuPoppedDown: function() {
|
||||||
this.actor.sync_hover();
|
this.actor.sync_hover();
|
||||||
this.isMenuUp = false;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onActivate: function (event) {
|
_onActivate: function (event) {
|
||||||
this.emit('launching');
|
this.emit('launching');
|
||||||
let modifiers = event.get_state();
|
let modifiers = Shell.get_event_state(event);
|
||||||
|
|
||||||
if (this._onActivateOverride) {
|
if (this._onActivateOverride) {
|
||||||
this._onActivateOverride(event);
|
this._onActivateOverride(event);
|
||||||
@@ -614,19 +620,22 @@ const AppWellIcon = new Lang.Class({
|
|||||||
getDragActorSource: function() {
|
getDragActorSource: function() {
|
||||||
return this.icon.icon;
|
return this.icon.icon;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(AppWellIcon.prototype);
|
Signals.addSignalMethods(AppWellIcon.prototype);
|
||||||
|
|
||||||
const AppIconMenu = new Lang.Class({
|
function AppIconMenu(source) {
|
||||||
Name: 'AppIconMenu',
|
this._init(source);
|
||||||
Extends: PopupMenu.PopupMenu,
|
}
|
||||||
|
|
||||||
|
AppIconMenu.prototype = {
|
||||||
|
__proto__: PopupMenu.PopupMenu.prototype,
|
||||||
|
|
||||||
_init: function(source) {
|
_init: function(source) {
|
||||||
let side = St.Side.LEFT;
|
let side = St.Side.LEFT;
|
||||||
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||||
side = St.Side.RIGHT;
|
side = St.Side.RIGHT;
|
||||||
|
|
||||||
this.parent(source.actor, 0.5, side);
|
PopupMenu.PopupMenu.prototype._init.call(this, source.actor, 0.5, side);
|
||||||
|
|
||||||
// We want to keep the item hovered while the menu is up
|
// We want to keep the item hovered while the menu is up
|
||||||
this.blockSourceEvents = true;
|
this.blockSourceEvents = true;
|
||||||
@@ -714,5 +723,5 @@ const AppIconMenu = new Lang.Class({
|
|||||||
}
|
}
|
||||||
this.close();
|
this.close();
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(AppIconMenu.prototype);
|
Signals.addSignalMethods(AppIconMenu.prototype);
|
||||||
|
|||||||
@@ -6,9 +6,11 @@ const Signals = imports.signals;
|
|||||||
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
const AppFavorites = new Lang.Class({
|
function AppFavorites() {
|
||||||
Name: 'AppFavorites',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
AppFavorites.prototype = {
|
||||||
FAVORITE_APPS_KEY: 'favorite-apps',
|
FAVORITE_APPS_KEY: 'favorite-apps',
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
@@ -120,7 +122,7 @@ const AppFavorites = new Lang.Class({
|
|||||||
this._addFavorite(appId, pos);
|
this._addFavorite(appId, pos);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(AppFavorites.prototype);
|
Signals.addSignalMethods(AppFavorites.prototype);
|
||||||
|
|
||||||
var appFavoritesInstance = null;
|
var appFavoritesInstance = null;
|
||||||
|
|||||||
@@ -2,16 +2,12 @@
|
|||||||
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
|
|
||||||
const Shell = imports.gi.Shell;
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
const ShellMountOperation = imports.ui.shellMountOperation;
|
||||||
const GnomeSession = imports.misc.gnomeSession;
|
const ScreenSaver = imports.misc.screenSaver;
|
||||||
|
|
||||||
const GNOME_SESSION_AUTOMOUNT_INHIBIT = 16;
|
|
||||||
|
|
||||||
// GSettings keys
|
// GSettings keys
|
||||||
const SETTINGS_SCHEMA = 'org.gnome.desktop.media-handling';
|
const SETTINGS_SCHEMA = 'org.gnome.desktop.media-handling';
|
||||||
@@ -47,7 +43,7 @@ function ConsoleKitManager() {
|
|||||||
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
|
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
|
||||||
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
||||||
|
|
||||||
self._updateSessionActive = function() {
|
self.connect('notify::g-name-owner', function() {
|
||||||
if (self.g_name_owner) {
|
if (self.g_name_owner) {
|
||||||
self.GetCurrentSessionRemote(function([session]) {
|
self.GetCurrentSessionRemote(function([session]) {
|
||||||
self._ckSession = new ConsoleKitSessionProxy(Gio.DBus.system, 'org.freedesktop.ConsoleKit', session);
|
self._ckSession = new ConsoleKitSessionProxy(Gio.DBus.system, 'org.freedesktop.ConsoleKit', session);
|
||||||
@@ -62,36 +58,26 @@ function ConsoleKitManager() {
|
|||||||
} else {
|
} else {
|
||||||
self.sessionActive = true;
|
self.sessionActive = true;
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
self.connect('notify::g-name-owner',
|
|
||||||
Lang.bind(self, self._updateSessionActive));
|
|
||||||
|
|
||||||
self._updateSessionActive();
|
|
||||||
self.init(null);
|
self.init(null);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
function haveSystemd() {
|
function AutomountManager() {
|
||||||
return GLib.access("/sys/fs/cgroup/systemd", 0) >= 0;
|
this._init();
|
||||||
}
|
}
|
||||||
|
|
||||||
const AutomountManager = new Lang.Class({
|
AutomountManager.prototype = {
|
||||||
Name: 'AutomountManager',
|
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
||||||
this._volumeQueue = [];
|
this._volumeQueue = [];
|
||||||
this._session = new GnomeSession.SessionManager();
|
|
||||||
this._session.connectSignal('InhibitorAdded',
|
|
||||||
Lang.bind(this, this._InhibitorsChanged));
|
|
||||||
this._session.connectSignal('InhibitorRemoved',
|
|
||||||
Lang.bind(this, this._InhibitorsChanged));
|
|
||||||
this._inhibited = false;
|
|
||||||
|
|
||||||
if (!haveSystemd())
|
|
||||||
this.ckListener = new ConsoleKitManager();
|
this.ckListener = new ConsoleKitManager();
|
||||||
|
|
||||||
Main.screenShield.connect('lock-status-changed', Lang.bind(this, this._lockStatusChanged));
|
this._ssProxy = new ScreenSaver.ScreenSaverProxy();
|
||||||
|
this._ssProxy.connectSignal('ActiveChanged',
|
||||||
|
Lang.bind(this, this._screenSaverActiveChanged));
|
||||||
|
|
||||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||||
|
|
||||||
@@ -114,18 +100,8 @@ const AutomountManager = new Lang.Class({
|
|||||||
Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
|
Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
|
||||||
},
|
},
|
||||||
|
|
||||||
_InhibitorsChanged: function(object, senderName, [inhibtor]) {
|
_screenSaverActiveChanged: function(object, senderName, [isActive]) {
|
||||||
this._session.IsInhibitedRemote(GNOME_SESSION_AUTOMOUNT_INHIBIT,
|
if (!isActive) {
|
||||||
Lang.bind(this,
|
|
||||||
function(result, error) {
|
|
||||||
if (!error) {
|
|
||||||
this._inhibited = result[0];
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
_lockStatusChanged: function(shield, locked) {
|
|
||||||
if (!locked) {
|
|
||||||
this._volumeQueue.forEach(Lang.bind(this, function(volume) {
|
this._volumeQueue.forEach(Lang.bind(this, function(volume) {
|
||||||
this._checkAndMountVolume(volume);
|
this._checkAndMountVolume(volume);
|
||||||
}));
|
}));
|
||||||
@@ -139,31 +115,19 @@ const AutomountManager = new Lang.Class({
|
|||||||
let volumes = this._volumeMonitor.get_volumes();
|
let volumes = this._volumeMonitor.get_volumes();
|
||||||
volumes.forEach(Lang.bind(this, function(volume) {
|
volumes.forEach(Lang.bind(this, function(volume) {
|
||||||
this._checkAndMountVolume(volume, { checkSession: false,
|
this._checkAndMountVolume(volume, { checkSession: false,
|
||||||
useMountOp: false,
|
useMountOp: false });
|
||||||
allowAutorun: false });
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
isSessionActive: function() {
|
|
||||||
// Return whether the current session is active, using the
|
|
||||||
// right mechanism: either systemd if available or ConsoleKit
|
|
||||||
// as fallback.
|
|
||||||
|
|
||||||
if (haveSystemd())
|
|
||||||
return Shell.session_is_active_for_systemd();
|
|
||||||
|
|
||||||
return this.ckListener.sessionActive;
|
|
||||||
},
|
|
||||||
|
|
||||||
_onDriveConnected: function() {
|
_onDriveConnected: function() {
|
||||||
// if we're not in the current ConsoleKit session,
|
// if we're not in the current ConsoleKit session,
|
||||||
// or screensaver is active, don't play sounds
|
// or screensaver is active, don't play sounds
|
||||||
if (!this.isSessionActive())
|
if (!this.ckListener.sessionActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Main.screenShield.locked)
|
if (this._ssProxy.screenSaverActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
global.play_theme_sound(0, 'device-added-media');
|
global.play_theme_sound(0, 'device-added-media');
|
||||||
@@ -172,10 +136,10 @@ const AutomountManager = new Lang.Class({
|
|||||||
_onDriveDisconnected: function() {
|
_onDriveDisconnected: function() {
|
||||||
// if we're not in the current ConsoleKit session,
|
// if we're not in the current ConsoleKit session,
|
||||||
// or screensaver is active, don't play sounds
|
// or screensaver is active, don't play sounds
|
||||||
if (!this.isSessionActive())
|
if (!this.ckListener.sessionActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Main.screenShield.locked)
|
if (this._ssProxy.screenSaverActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
global.play_theme_sound(0, 'device-removed-media');
|
global.play_theme_sound(0, 'device-removed-media');
|
||||||
@@ -184,7 +148,7 @@ const AutomountManager = new Lang.Class({
|
|||||||
_onDriveEjectButton: function(monitor, drive) {
|
_onDriveEjectButton: function(monitor, drive) {
|
||||||
// TODO: this code path is not tested, as the GVfs volume monitor
|
// TODO: this code path is not tested, as the GVfs volume monitor
|
||||||
// doesn't emit this signal just yet.
|
// doesn't emit this signal just yet.
|
||||||
if (!this.isSessionActive())
|
if (!this.ckListener.sessionActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// we force stop/eject in this case, so we don't have to pass a
|
// we force stop/eject in this case, so we don't have to pass a
|
||||||
@@ -218,16 +182,15 @@ const AutomountManager = new Lang.Class({
|
|||||||
|
|
||||||
_checkAndMountVolume: function(volume, params) {
|
_checkAndMountVolume: function(volume, params) {
|
||||||
params = Params.parse(params, { checkSession: true,
|
params = Params.parse(params, { checkSession: true,
|
||||||
useMountOp: true,
|
useMountOp: true });
|
||||||
allowAutorun: true });
|
|
||||||
|
|
||||||
if (params.checkSession) {
|
if (params.checkSession) {
|
||||||
// if we're not in the current ConsoleKit session,
|
// if we're not in the current ConsoleKit session,
|
||||||
// don't attempt automount
|
// don't attempt automount
|
||||||
if (!this.isSessionActive())
|
if (!this.ckListener.sessionActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Main.screenShield.locked) {
|
if (this._ssProxy.screenSaverActive) {
|
||||||
if (this._volumeQueue.indexOf(volume) == -1)
|
if (this._volumeQueue.indexOf(volume) == -1)
|
||||||
this._volumeQueue.push(volume);
|
this._volumeQueue.push(volume);
|
||||||
|
|
||||||
@@ -235,9 +198,6 @@ const AutomountManager = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._inhibited)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Volume is already mounted, don't bother.
|
// Volume is already mounted, don't bother.
|
||||||
if (volume.get_mount())
|
if (volume.get_mount())
|
||||||
return;
|
return;
|
||||||
@@ -257,20 +217,15 @@ const AutomountManager = new Lang.Class({
|
|||||||
|
|
||||||
if (params.useMountOp) {
|
if (params.useMountOp) {
|
||||||
let operation = new ShellMountOperation.ShellMountOperation(volume);
|
let operation = new ShellMountOperation.ShellMountOperation(volume);
|
||||||
this._mountVolume(volume, operation, params.allowAutorun);
|
this._mountVolume(volume, operation.mountOp);
|
||||||
} else {
|
} else {
|
||||||
this._mountVolume(volume, null, params.allowAutorun);
|
this._mountVolume(volume, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_mountVolume: function(volume, operation, allowAutorun) {
|
_mountVolume: function(volume, operation) {
|
||||||
if (allowAutorun)
|
|
||||||
this._allowAutorun(volume);
|
this._allowAutorun(volume);
|
||||||
|
volume.mount(0, operation, null,
|
||||||
let mountOp = operation ? operation.mountOp : null;
|
|
||||||
volume._operation = operation;
|
|
||||||
|
|
||||||
volume.mount(0, mountOp, null,
|
|
||||||
Lang.bind(this, this._onVolumeMounted));
|
Lang.bind(this, this._onVolumeMounted));
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -279,19 +234,15 @@ const AutomountManager = new Lang.Class({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
volume.mount_finish(res);
|
volume.mount_finish(res);
|
||||||
this._closeOperation(volume);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// FIXME: we will always get G_IO_ERROR_FAILED from the gvfs udisks
|
let string = e.toString();
|
||||||
// backend in this case, see
|
|
||||||
// https://bugs.freedesktop.org/show_bug.cgi?id=51271
|
|
||||||
if (e.message.indexOf('No key available with this passphrase') != -1) {
|
|
||||||
this._reaskPassword(volume);
|
|
||||||
} else {
|
|
||||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED))
|
|
||||||
log('Unable to mount volume ' + volume.get_name() + ': ' + e.toString());
|
|
||||||
|
|
||||||
this._closeOperation(volume);
|
// 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);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -303,16 +254,8 @@ const AutomountManager = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_reaskPassword: function(volume) {
|
_reaskPassword: function(volume) {
|
||||||
let existingDialog = volume._operation ? volume._operation.borrowDialog() : null;
|
let operation = new ShellMountOperation.ShellMountOperation(volume, { reaskPassword: true });
|
||||||
let operation =
|
this._mountVolume(volume, operation.mountOp);
|
||||||
new ShellMountOperation.ShellMountOperation(volume,
|
|
||||||
{ existingDialog: existingDialog });
|
|
||||||
this._mountVolume(volume, operation);
|
|
||||||
},
|
|
||||||
|
|
||||||
_closeOperation: function(volume) {
|
|
||||||
if (volume._operation)
|
|
||||||
volume._operation.close();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_allowAutorun: function(volume) {
|
_allowAutorun: function(volume) {
|
||||||
@@ -325,4 +268,4 @@ const AutomountManager = new Lang.Class({
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@@ -23,14 +23,12 @@ const AutorunSetting = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// misc utils
|
// misc utils
|
||||||
function shouldAutorunMount(mount, forTransient) {
|
function ignoreAutorunForMount(mount) {
|
||||||
let root = mount.get_root();
|
let root = mount.get_root();
|
||||||
let volume = mount.get_volume();
|
let volume = mount.get_volume();
|
||||||
|
|
||||||
if (!volume || (!volume.allowAutorun && forTransient))
|
if ((root.is_native() && !isMountRootHidden(root)) ||
|
||||||
return false;
|
(volume && volume.allowAutorun && volume.should_automount()))
|
||||||
|
|
||||||
if (!root.is_native() || isMountRootHidden(root))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -77,9 +75,11 @@ function HotplugSniffer() {
|
|||||||
'/org/gnome/Shell/HotplugSniffer');
|
'/org/gnome/Shell/HotplugSniffer');
|
||||||
}
|
}
|
||||||
|
|
||||||
const ContentTypeDiscoverer = new Lang.Class({
|
function ContentTypeDiscoverer(callback) {
|
||||||
Name: 'ContentTypeDiscoverer',
|
this._init(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentTypeDiscoverer.prototype = {
|
||||||
_init: function(callback) {
|
_init: function(callback) {
|
||||||
this._callback = callback;
|
this._callback = callback;
|
||||||
},
|
},
|
||||||
@@ -136,11 +136,13 @@ const ContentTypeDiscoverer = new Lang.Class({
|
|||||||
|
|
||||||
this._callback(mount, apps, contentTypes);
|
this._callback(mount, apps, contentTypes);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
const AutorunManager = new Lang.Class({
|
function AutorunManager() {
|
||||||
Name: 'AutorunManager',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
AutorunManager.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||||
|
|
||||||
@@ -176,7 +178,7 @@ const AutorunManager = new Lang.Class({
|
|||||||
_onMountAdded: function(monitor, mount) {
|
_onMountAdded: function(monitor, mount) {
|
||||||
// don't do anything if our session is not the currently
|
// don't do anything if our session is not the currently
|
||||||
// active one
|
// active one
|
||||||
if (!Main.automountManager.isSessionActive())
|
if (!Main.automountManager.ckListener.sessionActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let discoverer = new ContentTypeDiscoverer(Lang.bind (this,
|
let discoverer = new ContentTypeDiscoverer(Lang.bind (this,
|
||||||
@@ -226,7 +228,9 @@ const AutorunManager = new Lang.Class({
|
|||||||
try {
|
try {
|
||||||
mount.unmount_with_operation_finish(res);
|
mount.unmount_with_operation_finish(res);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED))
|
// 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()
|
log('Unable to eject the mount ' + mount.get_name()
|
||||||
+ ': ' + e.toString());
|
+ ': ' + e.toString());
|
||||||
}
|
}
|
||||||
@@ -236,7 +240,9 @@ const AutorunManager = new Lang.Class({
|
|||||||
try {
|
try {
|
||||||
source.eject_with_operation_finish(res);
|
source.eject_with_operation_finish(res);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED))
|
// 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()
|
log('Unable to eject the drive ' + source.get_name()
|
||||||
+ ': ' + e.toString());
|
+ ': ' + e.toString());
|
||||||
}
|
}
|
||||||
@@ -246,27 +252,33 @@ const AutorunManager = new Lang.Class({
|
|||||||
try {
|
try {
|
||||||
drive.stop_finish(res);
|
drive.stop_finish(res);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED))
|
// 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()
|
log('Unable to stop the drive ' + drive.get_name()
|
||||||
+ ': ' + e.toString());
|
+ ': ' + e.toString());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
}
|
||||||
|
|
||||||
const AutorunResidentSource = new Lang.Class({
|
function AutorunResidentSource() {
|
||||||
Name: 'AutorunResidentSource',
|
this._init();
|
||||||
Extends: MessageTray.Source,
|
}
|
||||||
|
|
||||||
|
AutorunResidentSource.prototype = {
|
||||||
|
__proto__: MessageTray.Source.prototype,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent(_("Removable Devices"), 'media-removable', St.IconType.FULLCOLOR);
|
MessageTray.Source.prototype._init.call(this, _("Removable Devices"));
|
||||||
|
|
||||||
this._mounts = [];
|
this._mounts = [];
|
||||||
|
|
||||||
this._notification = new AutorunResidentNotification(this);
|
this._notification = new AutorunResidentNotification(this);
|
||||||
|
this._setSummaryIcon(this.createNotificationIcon());
|
||||||
},
|
},
|
||||||
|
|
||||||
addMount: function(mount, apps) {
|
addMount: function(mount, apps) {
|
||||||
if (!shouldAutorunMount(mount, false))
|
if (ignoreAutorunForMount(mount))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let filtered = this._mounts.filter(function (element) {
|
let filtered = this._mounts.filter(function (element) {
|
||||||
@@ -305,15 +317,26 @@ const AutorunResidentSource = new Lang.Class({
|
|||||||
Main.messageTray.add(this);
|
Main.messageTray.add(this);
|
||||||
this.pushNotification(this._notification);
|
this.pushNotification(this._notification);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
});
|
|
||||||
|
|
||||||
const AutorunResidentNotification = new Lang.Class({
|
createNotificationIcon: function() {
|
||||||
Name: 'AutorunResidentNotification',
|
return new St.Icon ({ icon_name: 'media-removable',
|
||||||
Extends: MessageTray.Notification,
|
icon_type: St.IconType.FULLCOLOR,
|
||||||
|
icon_size: this.ICON_SIZE });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function AutorunResidentNotification(source) {
|
||||||
|
this._init(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
AutorunResidentNotification.prototype = {
|
||||||
|
__proto__: MessageTray.Notification.prototype,
|
||||||
|
|
||||||
_init: function(source) {
|
_init: function(source) {
|
||||||
this.parent(source, source.title, null, { customContent: true });
|
MessageTray.Notification.prototype._init.call(this, source,
|
||||||
|
source.title, null,
|
||||||
|
{ customContent: true });
|
||||||
|
|
||||||
// set the notification as resident
|
// set the notification as resident
|
||||||
this.setResident(true);
|
this.setResident(true);
|
||||||
@@ -328,7 +351,7 @@ const AutorunResidentNotification = new Lang.Class({
|
|||||||
|
|
||||||
updateForMounts: function(mounts) {
|
updateForMounts: function(mounts) {
|
||||||
// remove all the layout content
|
// remove all the layout content
|
||||||
this._layout.destroy_all_children();
|
this._layout.destroy_children();
|
||||||
|
|
||||||
for (let idx = 0; idx < mounts.length; idx++) {
|
for (let idx = 0; idx < mounts.length; idx++) {
|
||||||
let element = mounts[idx];
|
let element = mounts[idx];
|
||||||
@@ -387,11 +410,13 @@ const AutorunResidentNotification = new Lang.Class({
|
|||||||
|
|
||||||
return item;
|
return item;
|
||||||
},
|
},
|
||||||
});
|
}
|
||||||
|
|
||||||
const AutorunTransientDispatcher = new Lang.Class({
|
function AutorunTransientDispatcher() {
|
||||||
Name: 'AutorunTransientDispatcher',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
AutorunTransientDispatcher.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._sources = [];
|
this._sources = [];
|
||||||
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
||||||
@@ -444,7 +469,7 @@ const AutorunTransientDispatcher = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// if the mount doesn't want to be autorun, return
|
// if the mount doesn't want to be autorun, return
|
||||||
if (!shouldAutorunMount(mount, true))
|
if (ignoreAutorunForMount(mount))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let setting = this._getAutorunSettingForType(contentTypes[0]);
|
let setting = this._getAutorunSettingForType(contentTypes[0]);
|
||||||
@@ -482,37 +507,46 @@ const AutorunTransientDispatcher = new Lang.Class({
|
|||||||
// destroy the notification source
|
// destroy the notification source
|
||||||
source.destroy();
|
source.destroy();
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
const AutorunTransientSource = new Lang.Class({
|
function AutorunTransientSource(mount, apps) {
|
||||||
Name: 'AutorunTransientSource',
|
this._init(mount, apps);
|
||||||
Extends: MessageTray.Source,
|
}
|
||||||
|
|
||||||
|
AutorunTransientSource.prototype = {
|
||||||
|
__proto__: MessageTray.Source.prototype,
|
||||||
|
|
||||||
_init: function(mount, apps) {
|
_init: function(mount, apps) {
|
||||||
|
MessageTray.Source.prototype._init.call(this, mount.get_name());
|
||||||
|
|
||||||
this.mount = mount;
|
this.mount = mount;
|
||||||
this.apps = apps;
|
this.apps = apps;
|
||||||
|
|
||||||
this.parent(mount.get_name());
|
|
||||||
|
|
||||||
this._notification = new AutorunTransientNotification(this);
|
this._notification = new AutorunTransientNotification(this);
|
||||||
|
this._setSummaryIcon(this.createNotificationIcon());
|
||||||
|
|
||||||
// add ourselves as a source, and popup the notification
|
// add ourselves as a source, and popup the notification
|
||||||
Main.messageTray.add(this);
|
Main.messageTray.add(this);
|
||||||
this.notify(this._notification);
|
this.notify(this._notification);
|
||||||
},
|
},
|
||||||
|
|
||||||
createIcon: function(size) {
|
createNotificationIcon: function() {
|
||||||
return new St.Icon({ gicon: this.mount.get_icon(),
|
return new St.Icon({ gicon: this.mount.get_icon(),
|
||||||
icon_size: size });
|
icon_size: this.ICON_SIZE });
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
const AutorunTransientNotification = new Lang.Class({
|
function AutorunTransientNotification(source) {
|
||||||
Name: 'AutorunTransientNotification',
|
this._init(source);
|
||||||
Extends: MessageTray.Notification,
|
}
|
||||||
|
|
||||||
|
AutorunTransientNotification.prototype = {
|
||||||
|
__proto__: MessageTray.Notification.prototype,
|
||||||
|
|
||||||
_init: function(source) {
|
_init: function(source) {
|
||||||
this.parent(source, source.title, null, { customContent: true });
|
MessageTray.Notification.prototype._init.call(this, source,
|
||||||
|
source.title, null,
|
||||||
|
{ customContent: true });
|
||||||
|
|
||||||
this._box = new St.BoxLayout({ style_class: 'hotplug-transient-box',
|
this._box = new St.BoxLayout({ style_class: 'hotplug-transient-box',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
@@ -545,7 +579,7 @@ const AutorunTransientNotification = new Lang.Class({
|
|||||||
|
|
||||||
let label = new St.Bin({ y_align: St.Align.MIDDLE,
|
let label = new St.Bin({ y_align: St.Align.MIDDLE,
|
||||||
child: new St.Label
|
child: new St.Label
|
||||||
({ text: _("Open with %s").format(app.get_name()) })
|
({ text: _("Open with %s").format(app.get_display_name()) })
|
||||||
});
|
});
|
||||||
box.add(label);
|
box.add(label);
|
||||||
|
|
||||||
@@ -587,5 +621,5 @@ const AutorunTransientNotification = new Lang.Class({
|
|||||||
|
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,13 +9,6 @@ const Shell = imports.gi.Shell;
|
|||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
const PopupAnimation = {
|
|
||||||
NONE: 0,
|
|
||||||
SLIDE: 1 << 0,
|
|
||||||
FADE: 1 << 1,
|
|
||||||
FULL: ~0,
|
|
||||||
};
|
|
||||||
|
|
||||||
const POPUP_ANIMATION_TIME = 0.15;
|
const POPUP_ANIMATION_TIME = 0.15;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,18 +18,16 @@ const POPUP_ANIMATION_TIME = 0.15;
|
|||||||
*
|
*
|
||||||
* An actor which displays a triangle "arrow" pointing to a given
|
* An actor which displays a triangle "arrow" pointing to a given
|
||||||
* side. The .bin property is a container in which content can be
|
* side. The .bin property is a container in which content can be
|
||||||
* placed. The arrow position may be controlled via
|
* placed. The arrow position may be controlled via setArrowOrigin().
|
||||||
* setArrowOrigin(). The arrow side might be temporarily flipped
|
|
||||||
* depending on the box size and source position to keep the box
|
|
||||||
* totally inside the monitor if possible.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
const BoxPointer = new Lang.Class({
|
function BoxPointer(side, binProperties) {
|
||||||
Name: 'BoxPointer',
|
this._init(side, binProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
BoxPointer.prototype = {
|
||||||
_init: function(arrowSide, binProperties) {
|
_init: function(arrowSide, binProperties) {
|
||||||
this._arrowSide = arrowSide;
|
this._arrowSide = arrowSide;
|
||||||
this._userArrowSide = arrowSide;
|
|
||||||
this._arrowOrigin = 0;
|
this._arrowOrigin = 0;
|
||||||
this.actor = new St.Bin({ x_fill: true,
|
this.actor = new St.Bin({ x_fill: true,
|
||||||
y_fill: true });
|
y_fill: true });
|
||||||
@@ -56,36 +47,16 @@ const BoxPointer = new Lang.Class({
|
|||||||
this._xPosition = 0;
|
this._xPosition = 0;
|
||||||
this._yPosition = 0;
|
this._yPosition = 0;
|
||||||
this._sourceAlignment = 0.5;
|
this._sourceAlignment = 0.5;
|
||||||
this._capturedEventId = 0;
|
|
||||||
this._muteInput();
|
|
||||||
},
|
|
||||||
|
|
||||||
_muteInput: function() {
|
|
||||||
if (this._capturedEventId == 0)
|
|
||||||
this._capturedEventId = this.actor.connect('captured-event',
|
|
||||||
function() { return true; });
|
|
||||||
},
|
|
||||||
|
|
||||||
_unmuteInput: function() {
|
|
||||||
if (this._capturedEventId != 0) {
|
|
||||||
this.actor.disconnect(this._capturedEventId);
|
|
||||||
this._capturedEventId = 0;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
show: function(animate, onComplete) {
|
show: function(animate, onComplete) {
|
||||||
let themeNode = this.actor.get_theme_node();
|
let themeNode = this.actor.get_theme_node();
|
||||||
let rise = themeNode.get_length('-arrow-rise');
|
let rise = themeNode.get_length('-arrow-rise');
|
||||||
let animationTime = (animate & PopupAnimation.FULL) ? POPUP_ANIMATION_TIME : 0;
|
|
||||||
|
|
||||||
if (animate & PopupAnimation.FADE)
|
|
||||||
this.opacity = 0;
|
this.opacity = 0;
|
||||||
else
|
|
||||||
this.opacity = 255;
|
|
||||||
|
|
||||||
this.actor.show();
|
this.actor.show();
|
||||||
|
|
||||||
if (animate & PopupAnimation.SLIDE) {
|
if (animate) {
|
||||||
switch (this._arrowSide) {
|
switch (this._arrowSide) {
|
||||||
case St.Side.TOP:
|
case St.Side.TOP:
|
||||||
this.yOffset = -rise;
|
this.yOffset = -rise;
|
||||||
@@ -106,12 +77,8 @@ const BoxPointer = new Lang.Class({
|
|||||||
xOffset: 0,
|
xOffset: 0,
|
||||||
yOffset: 0,
|
yOffset: 0,
|
||||||
transition: 'linear',
|
transition: 'linear',
|
||||||
onComplete: Lang.bind(this, function() {
|
onComplete: onComplete,
|
||||||
this._unmuteInput();
|
time: POPUP_ANIMATION_TIME });
|
||||||
if (onComplete)
|
|
||||||
onComplete();
|
|
||||||
}),
|
|
||||||
time: animationTime });
|
|
||||||
},
|
},
|
||||||
|
|
||||||
hide: function(animate, onComplete) {
|
hide: function(animate, onComplete) {
|
||||||
@@ -119,10 +86,8 @@ const BoxPointer = new Lang.Class({
|
|||||||
let yOffset = 0;
|
let yOffset = 0;
|
||||||
let themeNode = this.actor.get_theme_node();
|
let themeNode = this.actor.get_theme_node();
|
||||||
let rise = themeNode.get_length('-arrow-rise');
|
let rise = themeNode.get_length('-arrow-rise');
|
||||||
let fade = (animate & PopupAnimation.FADE);
|
|
||||||
let animationTime = (animate & PopupAnimation.FULL) ? POPUP_ANIMATION_TIME : 0;
|
|
||||||
|
|
||||||
if (animate & PopupAnimation.SLIDE) {
|
if (animate) {
|
||||||
switch (this._arrowSide) {
|
switch (this._arrowSide) {
|
||||||
case St.Side.TOP:
|
case St.Side.TOP:
|
||||||
yOffset = rise;
|
yOffset = rise;
|
||||||
@@ -139,16 +104,13 @@ const BoxPointer = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._muteInput();
|
Tweener.addTween(this, { opacity: 0,
|
||||||
|
|
||||||
Tweener.addTween(this, { opacity: fade ? 0 : 255,
|
|
||||||
xOffset: xOffset,
|
xOffset: xOffset,
|
||||||
yOffset: yOffset,
|
yOffset: yOffset,
|
||||||
transition: 'linear',
|
transition: 'linear',
|
||||||
time: animationTime,
|
time: POPUP_ANIMATION_TIME,
|
||||||
onComplete: Lang.bind(this, function () {
|
onComplete: Lang.bind(this, function () {
|
||||||
this.actor.hide();
|
this.actor.hide();
|
||||||
this.opacity = 0;
|
|
||||||
this.xOffset = 0;
|
this.xOffset = 0;
|
||||||
this.yOffset = 0;
|
this.yOffset = 0;
|
||||||
if (onComplete)
|
if (onComplete)
|
||||||
@@ -218,27 +180,8 @@ const BoxPointer = new Lang.Class({
|
|||||||
}
|
}
|
||||||
this.bin.allocate(childBox, flags);
|
this.bin.allocate(childBox, flags);
|
||||||
|
|
||||||
if (this._sourceActor && this._sourceActor.mapped) {
|
if (this._sourceActor && this._sourceActor.mapped)
|
||||||
this._reposition(this._sourceActor, this._arrowAlignment);
|
this._reposition(this._sourceActor, this._arrowAlignment);
|
||||||
|
|
||||||
if (this._shouldFlip()) {
|
|
||||||
switch (this._arrowSide) {
|
|
||||||
case St.Side.TOP:
|
|
||||||
this._arrowSide = St.Side.BOTTOM;
|
|
||||||
break;
|
|
||||||
case St.Side.BOTTOM:
|
|
||||||
this._arrowSide = St.Side.TOP;
|
|
||||||
break;
|
|
||||||
case St.Side.LEFT:
|
|
||||||
this._arrowSide = St.Side.RIGHT;
|
|
||||||
break;
|
|
||||||
case St.Side.RIGHT:
|
|
||||||
this._arrowSide = St.Side.LEFT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this._reposition(this._sourceActor, this._arrowAlignment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_drawBorder: function(area) {
|
_drawBorder: function(area) {
|
||||||
@@ -252,6 +195,7 @@ const BoxPointer = new Lang.Class({
|
|||||||
let halfBorder = borderWidth / 2;
|
let halfBorder = borderWidth / 2;
|
||||||
let halfBase = Math.floor(base/2);
|
let halfBase = Math.floor(base/2);
|
||||||
|
|
||||||
|
let borderColor = themeNode.get_color('-arrow-border-color');
|
||||||
let backgroundColor = themeNode.get_color('-arrow-background-color');
|
let backgroundColor = themeNode.get_color('-arrow-background-color');
|
||||||
|
|
||||||
let [width, height] = area.get_surface_size();
|
let [width, height] = area.get_surface_size();
|
||||||
@@ -262,6 +206,7 @@ const BoxPointer = new Lang.Class({
|
|||||||
boxWidth -= rise;
|
boxWidth -= rise;
|
||||||
}
|
}
|
||||||
let cr = area.get_context();
|
let cr = area.get_context();
|
||||||
|
Clutter.cairo_set_source_color(cr, borderColor);
|
||||||
|
|
||||||
// Translate so that box goes from 0,0 to boxWidth,boxHeight,
|
// Translate so that box goes from 0,0 to boxWidth,boxHeight,
|
||||||
// with the arrow poking out of that
|
// with the arrow poking out of that
|
||||||
@@ -357,18 +302,12 @@ const BoxPointer = new Lang.Class({
|
|||||||
|
|
||||||
Clutter.cairo_set_source_color(cr, backgroundColor);
|
Clutter.cairo_set_source_color(cr, backgroundColor);
|
||||||
cr.fillPreserve();
|
cr.fillPreserve();
|
||||||
|
|
||||||
if (borderWidth > 0) {
|
|
||||||
let borderColor = themeNode.get_color('-arrow-border-color');
|
|
||||||
Clutter.cairo_set_source_color(cr, borderColor);
|
Clutter.cairo_set_source_color(cr, borderColor);
|
||||||
cr.setLineWidth(borderWidth);
|
cr.setLineWidth(borderWidth);
|
||||||
cr.stroke();
|
cr.stroke();
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setPosition: function(sourceActor, alignment) {
|
setPosition: function(sourceActor, alignment) {
|
||||||
this._arrowSide = this._userArrowSide;
|
|
||||||
|
|
||||||
// We need to show it now to force an allocation,
|
// We need to show it now to force an allocation,
|
||||||
// so that we can query the correct size.
|
// so that we can query the correct size.
|
||||||
this.actor.show();
|
this.actor.show();
|
||||||
@@ -385,7 +324,11 @@ const BoxPointer = new Lang.Class({
|
|||||||
if (!this._sourceActor)
|
if (!this._sourceActor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.setPosition(this._sourceActor, this._arrowAlignment);
|
// We need to show it now to force an allocation,
|
||||||
|
// so that we can query the correct size.
|
||||||
|
this.actor.show();
|
||||||
|
|
||||||
|
this._reposition(this._sourceActor, this._arrowAlignment);
|
||||||
},
|
},
|
||||||
|
|
||||||
_reposition: function(sourceActor, alignment) {
|
_reposition: function(sourceActor, alignment) {
|
||||||
@@ -484,39 +427,6 @@ const BoxPointer = new Lang.Class({
|
|||||||
-(this._yPosition + this._yOffset));
|
-(this._yPosition + this._yOffset));
|
||||||
},
|
},
|
||||||
|
|
||||||
_shouldFlip: function() {
|
|
||||||
let sourceAllocation = Shell.util_get_transformed_allocation(this._sourceActor);
|
|
||||||
let boxAllocation = Shell.util_get_transformed_allocation(this.actor);
|
|
||||||
let boxWidth = boxAllocation.x2 - boxAllocation.x1;
|
|
||||||
let boxHeight = boxAllocation.y2 - boxAllocation.y1;
|
|
||||||
let monitor = Main.layoutManager.findMonitorForActor(this.actor);
|
|
||||||
|
|
||||||
switch (this._arrowSide) {
|
|
||||||
case St.Side.TOP:
|
|
||||||
if (boxAllocation.y2 > monitor.y + monitor.height &&
|
|
||||||
boxHeight < sourceAllocation.y1 - monitor.y)
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
case St.Side.BOTTOM:
|
|
||||||
if (boxAllocation.y1 < monitor.y &&
|
|
||||||
boxHeight < monitor.y + monitor.height - sourceAllocation.y2)
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
case St.Side.LEFT:
|
|
||||||
if (boxAllocation.x2 > monitor.x + monitor.width &&
|
|
||||||
boxWidth < sourceAllocation.x1 - monitor.x)
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
case St.Side.RIGHT:
|
|
||||||
if (boxAllocation.x1 < monitor.x &&
|
|
||||||
boxWidth < monitor.x + monitor.width - sourceAllocation.x2)
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
set xOffset(offset) {
|
set xOffset(offset) {
|
||||||
this._xOffset = offset;
|
this._xOffset = offset;
|
||||||
this._shiftActor();
|
this._shiftActor();
|
||||||
@@ -542,4 +452,4 @@ const BoxPointer = new Lang.Class({
|
|||||||
get opacity() {
|
get opacity() {
|
||||||
return this.actor.opacity;
|
return this.actor.opacity;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|||||||
@@ -155,24 +155,28 @@ function _getEventDayAbbreviation(dayNumber) {
|
|||||||
|
|
||||||
// Abstraction for an appointment/event in a calendar
|
// Abstraction for an appointment/event in a calendar
|
||||||
|
|
||||||
const CalendarEvent = new Lang.Class({
|
function CalendarEvent(date, end, summary, allDay) {
|
||||||
Name: 'CalendarEvent',
|
this._init(date, end, summary, allDay);
|
||||||
|
}
|
||||||
|
|
||||||
|
CalendarEvent.prototype = {
|
||||||
_init: function(date, end, summary, allDay) {
|
_init: function(date, end, summary, allDay) {
|
||||||
this.date = date;
|
this.date = date;
|
||||||
this.end = end;
|
this.end = end;
|
||||||
this.summary = summary;
|
this.summary = summary;
|
||||||
this.allDay = allDay;
|
this.allDay = allDay;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
// Interface for appointments/events - e.g. the contents of a calendar
|
// Interface for appointments/events - e.g. the contents of a calendar
|
||||||
//
|
//
|
||||||
|
|
||||||
// First, an implementation with no events
|
// First, an implementation with no events
|
||||||
const EmptyEventSource = new Lang.Class({
|
function EmptyEventSource() {
|
||||||
Name: 'EmptyEventSource',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
EmptyEventSource.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -187,7 +191,7 @@ const EmptyEventSource = new Lang.Class({
|
|||||||
hasEvents: function(day) {
|
hasEvents: function(day) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(EmptyEventSource.prototype);
|
Signals.addSignalMethods(EmptyEventSource.prototype);
|
||||||
|
|
||||||
const CalendarServerIface = <interface name="org.gnome.Shell.CalendarServer">
|
const CalendarServerIface = <interface name="org.gnome.Shell.CalendarServer">
|
||||||
@@ -215,6 +219,11 @@ function CalendarServer() {
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// an implementation that reads data from a session bus service
|
||||||
|
function DBusEventSource() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
function _datesEqual(a, b) {
|
function _datesEqual(a, b) {
|
||||||
if (a < b)
|
if (a < b)
|
||||||
return false;
|
return false;
|
||||||
@@ -233,10 +242,8 @@ function _dateIntervalsOverlap(a0, a1, b0, b1)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// an implementation that reads data from a session bus service
|
|
||||||
const DBusEventSource = new Lang.Class({
|
|
||||||
Name: 'DBusEventSource',
|
|
||||||
|
|
||||||
|
DBusEventSource.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._resetCache();
|
this._resetCache();
|
||||||
|
|
||||||
@@ -337,15 +344,17 @@ const DBusEventSource = new Lang.Class({
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(DBusEventSource.prototype);
|
Signals.addSignalMethods(DBusEventSource.prototype);
|
||||||
|
|
||||||
// Calendar:
|
// Calendar:
|
||||||
// @eventSource: is an object implementing the EventSource API, e.g. the
|
// @eventSource: is an object implementing the EventSource API, e.g. the
|
||||||
// requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
|
// requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
|
||||||
const Calendar = new Lang.Class({
|
function Calendar(eventSource) {
|
||||||
Name: 'Calendar',
|
this._init(eventSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
Calendar.prototype = {
|
||||||
_init: function(eventSource) {
|
_init: function(eventSource) {
|
||||||
if (eventSource) {
|
if (eventSource) {
|
||||||
this._eventSource = eventSource;
|
this._eventSource = eventSource;
|
||||||
@@ -406,7 +415,7 @@ const Calendar = new Lang.Class({
|
|||||||
|
|
||||||
_buildHeader: function() {
|
_buildHeader: function() {
|
||||||
let offsetCols = this._useWeekdate ? 1 : 0;
|
let offsetCols = this._useWeekdate ? 1 : 0;
|
||||||
this.actor.destroy_all_children();
|
this.actor.destroy_children();
|
||||||
|
|
||||||
// Top line of the calendar '<| September 2009 |>'
|
// Top line of the calendar '<| September 2009 |>'
|
||||||
this._topBox = new St.BoxLayout();
|
this._topBox = new St.BoxLayout();
|
||||||
@@ -448,7 +457,7 @@ const Calendar = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// All the children after this are days, and get removed when we update the calendar
|
// All the children after this are days, and get removed when we update the calendar
|
||||||
this._firstDayIndex = this.actor.get_n_children();
|
this._firstDayIndex = this.actor.get_children().length;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onStyleChange: function(actor, event) {
|
_onStyleChange: function(actor, event) {
|
||||||
@@ -551,7 +560,6 @@ const Calendar = new Lang.Class({
|
|||||||
let row = 2;
|
let row = 2;
|
||||||
while (true) {
|
while (true) {
|
||||||
let button = new St.Button({ label: iter.getDate().toString() });
|
let button = new St.Button({ label: iter.getDate().toString() });
|
||||||
let rtl = button.get_text_direction() == Clutter.TextDirection.RTL;
|
|
||||||
|
|
||||||
if (!this._eventSource)
|
if (!this._eventSource)
|
||||||
button.reactive = false;
|
button.reactive = false;
|
||||||
@@ -572,10 +580,7 @@ const Calendar = new Lang.Class({
|
|||||||
// Hack used in lieu of border-collapse - see gnome-shell.css
|
// Hack used in lieu of border-collapse - see gnome-shell.css
|
||||||
if (row == 2)
|
if (row == 2)
|
||||||
styleClass = 'calendar-day-top ' + styleClass;
|
styleClass = 'calendar-day-top ' + styleClass;
|
||||||
|
if (iter.getDay() == this._weekStart)
|
||||||
let leftMost = rtl ? iter.getDay() == (this._weekStart + 6) % 7
|
|
||||||
: iter.getDay() == this._weekStart;
|
|
||||||
if (leftMost)
|
|
||||||
styleClass = 'calendar-day-left ' + styleClass;
|
styleClass = 'calendar-day-left ' + styleClass;
|
||||||
|
|
||||||
if (_sameDay(now, iter))
|
if (_sameDay(now, iter))
|
||||||
@@ -615,13 +620,15 @@ const Calendar = new Lang.Class({
|
|||||||
if (this._eventSource)
|
if (this._eventSource)
|
||||||
this._eventSource.requestRange(beginDate, iter, forceReload);
|
this._eventSource.requestRange(beginDate, iter, forceReload);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
Signals.addSignalMethods(Calendar.prototype);
|
Signals.addSignalMethods(Calendar.prototype);
|
||||||
|
|
||||||
const EventsList = new Lang.Class({
|
function EventsList(eventSource) {
|
||||||
Name: 'EventsList',
|
this._init(eventSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
EventsList.prototype = {
|
||||||
_init: function(eventSource) {
|
_init: function(eventSource) {
|
||||||
this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'});
|
this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'});
|
||||||
this._date = new Date();
|
this._date = new Date();
|
||||||
@@ -689,7 +696,7 @@ const EventsList = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_showOtherDay: function(day) {
|
_showOtherDay: function(day) {
|
||||||
this.actor.destroy_all_children();
|
this.actor.destroy_children();
|
||||||
|
|
||||||
let dayBegin = _getBeginningOfDay(day);
|
let dayBegin = _getBeginningOfDay(day);
|
||||||
let dayEnd = _getEndOfDay(day);
|
let dayEnd = _getEndOfDay(day);
|
||||||
@@ -706,7 +713,7 @@ const EventsList = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_showToday: function() {
|
_showToday: function() {
|
||||||
this.actor.destroy_all_children();
|
this.actor.destroy_children();
|
||||||
|
|
||||||
let now = new Date();
|
let now = new Date();
|
||||||
let dayBegin = _getBeginningOfDay(now);
|
let dayBegin = _getBeginningOfDay(now);
|
||||||
@@ -752,4 +759,4 @@ const EventsList = new Lang.Class({
|
|||||||
this._showOtherDay(this._date);
|
this._showOtherDay(this._date);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|||||||
@@ -1,115 +0,0 @@
|
|||||||
const Clutter = imports.gi.Clutter;
|
|
||||||
const Pango = imports.gi.Pango;
|
|
||||||
const Shell = imports.gi.Shell;
|
|
||||||
const St = imports.gi.St;
|
|
||||||
|
|
||||||
const Lang = imports.lang;
|
|
||||||
|
|
||||||
const CheckBoxContainer = new Lang.Class({
|
|
||||||
Name: 'CheckBoxContainer',
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this.actor = new Shell.GenericContainer();
|
|
||||||
this.actor.connect('get-preferred-width',
|
|
||||||
Lang.bind(this, this._getPreferredWidth));
|
|
||||||
this.actor.connect('get-preferred-height',
|
|
||||||
Lang.bind(this, this._getPreferredHeight));
|
|
||||||
this.actor.connect('allocate',
|
|
||||||
Lang.bind(this, this._allocate));
|
|
||||||
this.actor.connect('style-changed', Lang.bind(this,
|
|
||||||
function() {
|
|
||||||
let node = this.actor.get_theme_node();
|
|
||||||
this._spacing = node.get_length('spacing');
|
|
||||||
}));
|
|
||||||
this.actor.request_mode = Clutter.RequestMode.HEIGHT_FOR_WIDTH;
|
|
||||||
|
|
||||||
this._box = new St.Bin();
|
|
||||||
this.actor.add_actor(this._box);
|
|
||||||
|
|
||||||
this.label = new St.Label();
|
|
||||||
this.label.clutter_text.set_line_wrap(true);
|
|
||||||
this.label.clutter_text.set_ellipsize(Pango.EllipsizeMode.NONE);
|
|
||||||
this.actor.add_actor(this.label);
|
|
||||||
|
|
||||||
this._spacing = 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
_getPreferredWidth: function(actor, forHeight, alloc) {
|
|
||||||
let [minWidth, natWidth] = this._box.get_preferred_width(forHeight);
|
|
||||||
|
|
||||||
alloc.min_size = minWidth + this._spacing;
|
|
||||||
alloc.natural_size = natWidth + this._spacing;
|
|
||||||
},
|
|
||||||
|
|
||||||
_getPreferredHeight: function(actor, forWidth, alloc) {
|
|
||||||
/* FIXME: StBoxlayout currently does not handle
|
|
||||||
height-for-width children correctly, so hard-code
|
|
||||||
two lines for the label until that problem is fixed.
|
|
||||||
|
|
||||||
https://bugzilla.gnome.org/show_bug.cgi?id=672543 */
|
|
||||||
/*
|
|
||||||
let [minBoxHeight, natBoxHeight] =
|
|
||||||
this._box.get_preferred_height(forWidth);
|
|
||||||
let [minLabelHeight, natLabelHeight] =
|
|
||||||
this.label.get_preferred_height(forWidth);
|
|
||||||
|
|
||||||
alloc.min_size = Math.max(minBoxHeight, minLabelHeight);
|
|
||||||
alloc.natural_size = Math.max(natBoxHeight, natLabelHeight);
|
|
||||||
*/
|
|
||||||
let [minBoxHeight, natBoxHeight] =
|
|
||||||
this._box.get_preferred_height(-1);
|
|
||||||
let [minLabelHeight, natLabelHeight] =
|
|
||||||
this.label.get_preferred_height(-1);
|
|
||||||
|
|
||||||
alloc.min_size = Math.max(minBoxHeight, 2 * minLabelHeight);
|
|
||||||
alloc.natural_size = Math.max(natBoxHeight, 2 * natLabelHeight);
|
|
||||||
},
|
|
||||||
|
|
||||||
_allocate: function(actor, box, flags) {
|
|
||||||
let availWidth = box.x2 - box.x1;
|
|
||||||
let availHeight = box.y2 - box.y1;
|
|
||||||
|
|
||||||
let childBox = new Clutter.ActorBox();
|
|
||||||
let [minBoxWidth, natBoxWidth] =
|
|
||||||
this._box.get_preferred_width(-1);
|
|
||||||
let [minBoxHeight, natBoxHeight] =
|
|
||||||
this._box.get_preferred_height(-1);
|
|
||||||
childBox.x1 = box.x1;
|
|
||||||
childBox.x2 = box.x1 + natBoxWidth;
|
|
||||||
childBox.y1 = box.y1;
|
|
||||||
childBox.y2 = box.y1 + natBoxHeight;
|
|
||||||
this._box.allocate(childBox, flags);
|
|
||||||
|
|
||||||
childBox.x1 = box.x1 + natBoxWidth + this._spacing;
|
|
||||||
childBox.x2 = availWidth - childBox.x1;
|
|
||||||
childBox.y1 = box.y1;
|
|
||||||
childBox.y2 = box.y2;
|
|
||||||
this.label.allocate(childBox, flags);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const CheckBox = new Lang.Class({
|
|
||||||
Name: 'CheckBox',
|
|
||||||
|
|
||||||
_init: function(label) {
|
|
||||||
this.actor = new St.Button({ style_class: 'check-box',
|
|
||||||
button_mask: St.ButtonMask.ONE,
|
|
||||||
toggle_mode: true,
|
|
||||||
can_focus: true,
|
|
||||||
x_fill: true,
|
|
||||||
y_fill: true });
|
|
||||||
this._container = new CheckBoxContainer();
|
|
||||||
this.actor.set_child(this._container.actor);
|
|
||||||
|
|
||||||
if (label)
|
|
||||||
this.setLabel(label);
|
|
||||||
},
|
|
||||||
|
|
||||||
setLabel: function(label) {
|
|
||||||
this._container.label.set_text(label);
|
|
||||||
},
|
|
||||||
|
|
||||||
getLabelActor: function() {
|
|
||||||
return this._container.label;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
185
js/ui/contactDisplay.js
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Folks = imports.gi.Folks
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Meta = imports.gi.Meta;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
const St = imports.gi.St;
|
||||||
|
|
||||||
|
const Util = imports.misc.util;
|
||||||
|
const IconGrid = imports.ui.iconGrid;
|
||||||
|
const Search = imports.ui.search;
|
||||||
|
const SearchDisplay = imports.ui.searchDisplay;
|
||||||
|
|
||||||
|
const MAX_SEARCH_RESULTS_ROWS = 1;
|
||||||
|
const ICON_SIZE = 81;
|
||||||
|
|
||||||
|
function launchContact(id) {
|
||||||
|
Util.spawn(['gnome-contacts', '-i', id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This class represents a shown contact search result in the overview */
|
||||||
|
function Contact(id) {
|
||||||
|
this._init(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Contact.prototype = {
|
||||||
|
_init: function(id) {
|
||||||
|
this._contactSys = Shell.ContactSystem.get_default();
|
||||||
|
this.individual = this._contactSys.get_individual(id);
|
||||||
|
|
||||||
|
this.actor = new St.Bin({ style_class: 'contact',
|
||||||
|
reactive: true,
|
||||||
|
track_hover: true });
|
||||||
|
|
||||||
|
let content = new St.BoxLayout( { style_class: 'contact-content',
|
||||||
|
vertical: false });
|
||||||
|
this.actor.set_child(content);
|
||||||
|
|
||||||
|
let icon = new St.Icon({ icon_type: St.IconType.FULLCOLOR,
|
||||||
|
icon_size: ICON_SIZE,
|
||||||
|
style_class: 'contact-icon' });
|
||||||
|
if (this.individual.avatar != null)
|
||||||
|
icon.gicon = this.individual.avatar;
|
||||||
|
else
|
||||||
|
icon.icon_name = 'avatar-default';
|
||||||
|
|
||||||
|
content.add(icon, { x_fill: true,
|
||||||
|
y_fill: false,
|
||||||
|
x_align: St.Align.START,
|
||||||
|
y_align: St.Align.MIDDLE });
|
||||||
|
|
||||||
|
let details = new St.BoxLayout({ style_class: 'contact-details',
|
||||||
|
vertical: true });
|
||||||
|
content.add(details, { x_fill: true,
|
||||||
|
y_fill: false,
|
||||||
|
x_align: St.Align.START,
|
||||||
|
y_align: St.Align.MIDDLE });
|
||||||
|
|
||||||
|
let email = this._contactSys.get_email_for_display(this.individual);
|
||||||
|
let aliasText = this.individual.alias ||
|
||||||
|
this.individual.full_name ||
|
||||||
|
this.individual.nickname ||
|
||||||
|
email ||
|
||||||
|
_("Unknown");
|
||||||
|
let aliasLabel = new St.Label({ text: aliasText,
|
||||||
|
style_class: 'contact-details-alias' });
|
||||||
|
details.add(aliasLabel, { x_fill: true,
|
||||||
|
y_fill: false,
|
||||||
|
x_align: St.Align.START,
|
||||||
|
y_align: St.Align.START });
|
||||||
|
|
||||||
|
let presence = this._createPresence(this.individual.presence_type);
|
||||||
|
details.add(presence, { x_fill: false,
|
||||||
|
y_fill: true,
|
||||||
|
x_align: St.Align.START,
|
||||||
|
y_align: St.Align.END });
|
||||||
|
},
|
||||||
|
|
||||||
|
_createPresence: function(presence) {
|
||||||
|
let text;
|
||||||
|
let iconName;
|
||||||
|
|
||||||
|
switch(presence) {
|
||||||
|
case Folks.PresenceType.AVAILABLE:
|
||||||
|
text = _("Available");
|
||||||
|
iconName = 'user-available';
|
||||||
|
break;
|
||||||
|
case Folks.PresenceType.AWAY:
|
||||||
|
case Folks.PresenceType.EXTENDED_AWAY:
|
||||||
|
text = _("Away");
|
||||||
|
iconName = 'user-away';
|
||||||
|
break;
|
||||||
|
case Folks.PresenceType.BUSY:
|
||||||
|
text = _("Busy");
|
||||||
|
iconName = 'user-busy';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
text = _("Offline");
|
||||||
|
iconName = 'user-offline';
|
||||||
|
}
|
||||||
|
|
||||||
|
let icon = new St.Icon({ icon_name: iconName,
|
||||||
|
icon_type: St.IconType.FULLCOLOR,
|
||||||
|
icon_size: 16,
|
||||||
|
style_class: 'contact-details-status-icon' });
|
||||||
|
let label = new St.Label({ text: text });
|
||||||
|
|
||||||
|
let box = new St.BoxLayout({ vertical: false,
|
||||||
|
style_class: 'contact-details-status' });
|
||||||
|
box.add(icon, { x_fill: true,
|
||||||
|
y_fill: false,
|
||||||
|
x_align: St.Align.START,
|
||||||
|
y_align: St.Align.START });
|
||||||
|
|
||||||
|
box.add(label, { x_fill: true,
|
||||||
|
y_fill: false,
|
||||||
|
x_align: St.Align.END,
|
||||||
|
y_align: St.Align.START });
|
||||||
|
|
||||||
|
return box;
|
||||||
|
},
|
||||||
|
|
||||||
|
createIcon: function(size) {
|
||||||
|
let tc = St.TextureCache.get_default();
|
||||||
|
let icon = this.individual.avatar;
|
||||||
|
|
||||||
|
if (icon != null) {
|
||||||
|
return tc.load_gicon(null, icon, size);
|
||||||
|
} else {
|
||||||
|
return tc.load_icon_name(null, 'avatar-default', St.IconType.FULLCOLOR, size);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Searches for and returns contacts */
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -22,9 +22,11 @@ const SortGroup = {
|
|||||||
BOTTOM: 2
|
BOTTOM: 2
|
||||||
};
|
};
|
||||||
|
|
||||||
const CtrlAltTabManager = new Lang.Class({
|
function CtrlAltTabManager() {
|
||||||
Name: 'CtrlAltTabManager',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
CtrlAltTabManager.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._items = [];
|
this._items = [];
|
||||||
this._focusManager = St.FocusManager.get_for_stage(global.stage);
|
this._focusManager = St.FocusManager.get_for_stage(global.stage);
|
||||||
@@ -132,15 +134,17 @@ const CtrlAltTabManager = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
function mod(a, b) {
|
function mod(a, b) {
|
||||||
return (a + b) % b;
|
return (a + b) % b;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CtrlAltTabPopup = new Lang.Class({
|
function CtrlAltTabPopup() {
|
||||||
Name: 'CtrlAltTabPopup',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
CtrlAltTabPopup.prototype = {
|
||||||
_init : function() {
|
_init : function() {
|
||||||
this.actor = new Shell.GenericContainer({ name: 'ctrlAltTabPopup',
|
this.actor = new Shell.GenericContainer({ name: 'ctrlAltTabPopup',
|
||||||
reactive: true });
|
reactive: true });
|
||||||
@@ -233,7 +237,7 @@ const CtrlAltTabPopup = new Lang.Class({
|
|||||||
|
|
||||||
_keyPressEvent : function(actor, event) {
|
_keyPressEvent : function(actor, event) {
|
||||||
let keysym = event.get_key_symbol();
|
let keysym = event.get_key_symbol();
|
||||||
let shift = (event.get_state() & Clutter.ModifierType.SHIFT_MASK);
|
let shift = (Shell.get_event_state(event) & Clutter.ModifierType.SHIFT_MASK);
|
||||||
if (shift && keysym == Clutter.KEY_Tab)
|
if (shift && keysym == Clutter.KEY_Tab)
|
||||||
keysym = Clutter.ISO_Left_Tab;
|
keysym = Clutter.ISO_Left_Tab;
|
||||||
|
|
||||||
@@ -299,14 +303,17 @@ const CtrlAltTabPopup = new Lang.Class({
|
|||||||
this._selection = num;
|
this._selection = num;
|
||||||
this._switcher.highlight(num);
|
this._switcher.highlight(num);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const CtrlAltTabSwitcher = new Lang.Class({
|
function CtrlAltTabSwitcher(items) {
|
||||||
Name: 'CtrlAltTabSwitcher',
|
this._init(items);
|
||||||
Extends: AltTab.SwitcherList,
|
}
|
||||||
|
|
||||||
|
CtrlAltTabSwitcher.prototype = {
|
||||||
|
__proto__ : AltTab.SwitcherList.prototype,
|
||||||
|
|
||||||
_init : function(items) {
|
_init : function(items) {
|
||||||
this.parent(true);
|
AltTab.SwitcherList.prototype._init.call(this, true);
|
||||||
|
|
||||||
for (let i = 0; i < items.length; i++)
|
for (let i = 0; i < items.length; i++)
|
||||||
this._addIcon(items[i]);
|
this._addIcon(items[i]);
|
||||||
@@ -329,4 +336,4 @@ const CtrlAltTabSwitcher = new Lang.Class({
|
|||||||
|
|
||||||
this.addItem(box, text);
|
this.addItem(box, text);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|||||||
200
js/ui/dash.js
@@ -6,7 +6,6 @@ const Lang = imports.lang;
|
|||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Mainloop = imports.mainloop;
|
|
||||||
|
|
||||||
const AppDisplay = imports.ui.appDisplay;
|
const AppDisplay = imports.ui.appDisplay;
|
||||||
const AppFavorites = imports.ui.appFavorites;
|
const AppFavorites = imports.ui.appFavorites;
|
||||||
@@ -17,15 +16,14 @@ const Tweener = imports.ui.tweener;
|
|||||||
const Workspace = imports.ui.workspace;
|
const Workspace = imports.ui.workspace;
|
||||||
|
|
||||||
const DASH_ANIMATION_TIME = 0.2;
|
const DASH_ANIMATION_TIME = 0.2;
|
||||||
const DASH_ITEM_LABEL_SHOW_TIME = 0.15;
|
|
||||||
const DASH_ITEM_LABEL_HIDE_TIME = 0.1;
|
|
||||||
const DASH_ITEM_HOVER_TIMEOUT = 300;
|
|
||||||
|
|
||||||
// A container like StBin, but taking the child's scale into account
|
// A container like StBin, but taking the child's scale into account
|
||||||
// when requesting a size
|
// when requesting a size
|
||||||
const DashItemContainer = new Lang.Class({
|
function DashItemContainer() {
|
||||||
Name: 'DashItemContainer',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
DashItemContainer.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.actor = new Shell.GenericContainer({ style_class: 'dash-item-container' });
|
this.actor = new Shell.GenericContainer({ style_class: 'dash-item-container' });
|
||||||
this.actor.connect('get-preferred-width',
|
this.actor.connect('get-preferred-width',
|
||||||
@@ -36,8 +34,6 @@ const DashItemContainer = new Lang.Class({
|
|||||||
Lang.bind(this, this._allocate));
|
Lang.bind(this, this._allocate));
|
||||||
this.actor._delegate = this;
|
this.actor._delegate = this;
|
||||||
|
|
||||||
this.label = null;
|
|
||||||
|
|
||||||
this.child = null;
|
this.child = null;
|
||||||
this._childScale = 1;
|
this._childScale = 1;
|
||||||
this._childOpacity = 255;
|
this._childOpacity = 255;
|
||||||
@@ -90,64 +86,11 @@ const DashItemContainer = new Lang.Class({
|
|||||||
alloc.natural_size = natWidth * this.child.scale_y;
|
alloc.natural_size = natWidth * this.child.scale_y;
|
||||||
},
|
},
|
||||||
|
|
||||||
showLabel: function() {
|
|
||||||
if (this.label == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.label.opacity = 0;
|
|
||||||
this.label.show();
|
|
||||||
|
|
||||||
let [stageX, stageY] = this.actor.get_transformed_position();
|
|
||||||
|
|
||||||
let itemHeight = this.actor.allocation.y2 - this.actor.allocation.y1;
|
|
||||||
|
|
||||||
let labelHeight = this.label.get_height();
|
|
||||||
let yOffset = Math.floor((itemHeight - labelHeight) / 2)
|
|
||||||
|
|
||||||
let y = stageY + yOffset;
|
|
||||||
|
|
||||||
let node = this.label.get_theme_node();
|
|
||||||
let xOffset = node.get_length('-x-offset');
|
|
||||||
|
|
||||||
let x;
|
|
||||||
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
|
||||||
x = stageX - this.label.get_width() - xOffset;
|
|
||||||
else
|
|
||||||
x = stageX + this.actor.get_width() + xOffset;
|
|
||||||
|
|
||||||
this.label.set_position(x, y);
|
|
||||||
Tweener.addTween(this.label,
|
|
||||||
{ opacity: 255,
|
|
||||||
time: DASH_ITEM_LABEL_SHOW_TIME,
|
|
||||||
transition: 'easeOutQuad',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
setLabelText: function(text) {
|
|
||||||
if (this.label == null)
|
|
||||||
this.label = new St.Label({ style_class: 'dash-label'});
|
|
||||||
|
|
||||||
this.label.set_text(text);
|
|
||||||
Main.layoutManager.addChrome(this.label);
|
|
||||||
this.label.hide();
|
|
||||||
},
|
|
||||||
|
|
||||||
hideLabel: function () {
|
|
||||||
Tweener.addTween(this.label,
|
|
||||||
{ opacity: 0,
|
|
||||||
time: DASH_ITEM_LABEL_HIDE_TIME,
|
|
||||||
transition: 'easeOutQuad',
|
|
||||||
onComplete: Lang.bind(this, function() {
|
|
||||||
this.label.hide();
|
|
||||||
})
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
setChild: function(actor) {
|
setChild: function(actor) {
|
||||||
if (this.child == actor)
|
if (this.child == actor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.actor.destroy_all_children();
|
this.actor.destroy_children();
|
||||||
|
|
||||||
this.child = actor;
|
this.child = actor;
|
||||||
this.actor.add_actor(this.child);
|
this.actor.add_actor(this.child);
|
||||||
@@ -167,17 +110,7 @@ const DashItemContainer = new Lang.Class({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function() {
|
|
||||||
if (this.label)
|
|
||||||
this.label.destroy();
|
|
||||||
|
|
||||||
this.actor.destroy();
|
|
||||||
},
|
|
||||||
|
|
||||||
animateOutAndDestroy: function() {
|
animateOutAndDestroy: function() {
|
||||||
if (this.label)
|
|
||||||
this.label.destroy();
|
|
||||||
|
|
||||||
if (this.child == null) {
|
if (this.child == null) {
|
||||||
this.actor.destroy();
|
this.actor.destroy();
|
||||||
return;
|
return;
|
||||||
@@ -224,14 +157,17 @@ const DashItemContainer = new Lang.Class({
|
|||||||
get childOpacity() {
|
get childOpacity() {
|
||||||
return this._childOpacity;
|
return this._childOpacity;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const RemoveFavoriteIcon = new Lang.Class({
|
function RemoveFavoriteIcon() {
|
||||||
Name: 'RemoveFavoriteIcon',
|
this._init();
|
||||||
Extends: DashItemContainer,
|
}
|
||||||
|
|
||||||
|
RemoveFavoriteIcon.prototype = {
|
||||||
|
__proto__: DashItemContainer.prototype,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent();
|
DashItemContainer.prototype._init.call(this);
|
||||||
|
|
||||||
this._iconBin = new St.Bin({ style_class: 'remove-favorite' });
|
this._iconBin = new St.Bin({ style_class: 'remove-favorite' });
|
||||||
this._iconActor = null;
|
this._iconActor = null;
|
||||||
@@ -283,21 +219,28 @@ const RemoveFavoriteIcon = new Lang.Class({
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const DragPlaceholderItem = new Lang.Class({
|
|
||||||
Name: 'DragPlaceholderItem',
|
function DragPlaceholderItem() {
|
||||||
Extends: DashItemContainer,
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
DragPlaceholderItem.prototype = {
|
||||||
|
__proto__: DashItemContainer.prototype,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent();
|
DashItemContainer.prototype._init.call(this);
|
||||||
this.setChild(new St.Bin({ style_class: 'placeholder' }));
|
this.setChild(new St.Bin({ style_class: 'placeholder' }));
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const Dash = new Lang.Class({
|
|
||||||
Name: 'Dash',
|
|
||||||
|
|
||||||
|
function Dash() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
Dash.prototype = {
|
||||||
_init : function() {
|
_init : function() {
|
||||||
this._maxHeight = -1;
|
this._maxHeight = -1;
|
||||||
this.iconSize = 64;
|
this.iconSize = 64;
|
||||||
@@ -307,9 +250,6 @@ const Dash = new Lang.Class({
|
|||||||
this._dragPlaceholderPos = -1;
|
this._dragPlaceholderPos = -1;
|
||||||
this._animatingPlaceholdersCount = 0;
|
this._animatingPlaceholdersCount = 0;
|
||||||
this._favRemoveTarget = null;
|
this._favRemoveTarget = null;
|
||||||
this._showLabelTimeoutId = 0;
|
|
||||||
this._resetHoverTimeoutId = 0;
|
|
||||||
this._labelShowing = false;
|
|
||||||
|
|
||||||
this._box = new St.BoxLayout({ name: 'dash',
|
this._box = new St.BoxLayout({ name: 'dash',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
@@ -396,7 +336,6 @@ const Dash = new Lang.Class({
|
|||||||
let srcIsFavorite = (id in favorites);
|
let srcIsFavorite = (id in favorites);
|
||||||
|
|
||||||
if (srcIsFavorite &&
|
if (srcIsFavorite &&
|
||||||
app.get_state() != Shell.AppState.RUNNING &&
|
|
||||||
dragEvent.source.actor &&
|
dragEvent.source.actor &&
|
||||||
this.actor.contains (dragEvent.source.actor) &&
|
this.actor.contains (dragEvent.source.actor) &&
|
||||||
this._favRemoveTarget == null) {
|
this._favRemoveTarget == null) {
|
||||||
@@ -444,60 +383,16 @@ const Dash = new Lang.Class({
|
|||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
display.actor.opacity = 255;
|
display.actor.opacity = 255;
|
||||||
}));
|
}));
|
||||||
|
display.actor.set_tooltip_text(app.get_name());
|
||||||
|
|
||||||
let item = new DashItemContainer();
|
let item = new DashItemContainer();
|
||||||
item.setChild(display.actor);
|
item.setChild(display.actor);
|
||||||
|
|
||||||
item.setLabelText(app.get_name());
|
|
||||||
// Override default AppWellIcon label_actor
|
|
||||||
display.actor.label_actor = item.label;
|
|
||||||
|
|
||||||
|
|
||||||
display.icon.setIconSize(this.iconSize);
|
display.icon.setIconSize(this.iconSize);
|
||||||
display.actor.connect('notify::hover',
|
|
||||||
Lang.bind(this, function() {
|
|
||||||
this._onHover(item, display)
|
|
||||||
}));
|
|
||||||
|
|
||||||
Main.overview.connect('hiding',
|
|
||||||
Lang.bind(this, function() {
|
|
||||||
this._labelShowing = false;
|
|
||||||
item.hideLabel();
|
|
||||||
}));
|
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onHover: function (item, display) {
|
|
||||||
if (display.actor.get_hover() && !display.isMenuUp) {
|
|
||||||
if (this._showLabelTimeoutId == 0) {
|
|
||||||
let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT;
|
|
||||||
this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
|
|
||||||
Lang.bind(this, function() {
|
|
||||||
this._labelShowing = true;
|
|
||||||
item.showLabel();
|
|
||||||
return false;
|
|
||||||
}));
|
|
||||||
if (this._resetHoverTimeoutId > 0) {
|
|
||||||
Mainloop.source_remove(this._resetHoverTimeoutId);
|
|
||||||
this._resetHoverTimeoutId = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this._showLabelTimeoutId > 0)
|
|
||||||
Mainloop.source_remove(this._showLabelTimeoutId);
|
|
||||||
this._showLabelTimeoutId = 0;
|
|
||||||
item.hideLabel();
|
|
||||||
if (this._labelShowing) {
|
|
||||||
this._resetHoverTimeoutId = Mainloop.timeout_add(DASH_ITEM_HOVER_TIMEOUT,
|
|
||||||
Lang.bind(this, function() {
|
|
||||||
this._labelShowing = false;
|
|
||||||
return false;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_adjustIconSize: function() {
|
_adjustIconSize: function() {
|
||||||
// For the icon size, we only consider children which are "proper"
|
// For the icon size, we only consider children which are "proper"
|
||||||
// icons (i.e. ignoring drag placeholders) and which are not
|
// icons (i.e. ignoring drag placeholders) and which are not
|
||||||
@@ -521,7 +416,7 @@ const Dash = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
let themeNode = this._box.get_theme_node();
|
let themeNode = this.actor.get_theme_node();
|
||||||
let maxAllocation = new Clutter.ActorBox({ x1: 0, y1: 0,
|
let maxAllocation = new Clutter.ActorBox({ x1: 0, y1: 0,
|
||||||
x2: 42 /* whatever */,
|
x2: 42 /* whatever */,
|
||||||
y2: this._maxHeight });
|
y2: this._maxHeight });
|
||||||
@@ -697,7 +592,7 @@ const Dash = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < addedItems.length; i++)
|
for (let i = 0; i < addedItems.length; i++)
|
||||||
this._box.insert_child_at_index(addedItems[i].item.actor,
|
this._box.insert_actor(addedItems[i].item.actor,
|
||||||
addedItems[i].pos);
|
addedItems[i].pos);
|
||||||
|
|
||||||
for (let i = 0; i < removedActors.length; i++) {
|
for (let i = 0; i < removedActors.length; i++) {
|
||||||
@@ -707,7 +602,7 @@ const Dash = new Lang.Class({
|
|||||||
if (Main.overview.visible)
|
if (Main.overview.visible)
|
||||||
item.animateOutAndDestroy();
|
item.animateOutAndDestroy();
|
||||||
else
|
else
|
||||||
item.destroy();
|
item.actor.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
this._adjustIconSize();
|
this._adjustIconSize();
|
||||||
@@ -763,10 +658,20 @@ const Dash = new Lang.Class({
|
|||||||
numChildren--;
|
numChildren--;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pos = Math.floor(y * numChildren / boxHeight);
|
let pos = Math.round(y * numChildren / boxHeight);
|
||||||
|
|
||||||
if (pos != this._dragPlaceholderPos && pos <= numFavorites && this._animatingPlaceholdersCount == 0) {
|
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;
|
this._dragPlaceholderPos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
// Don't allow positioning before or after self
|
// Don't allow positioning before or after self
|
||||||
if (favPos != -1 && (pos == favPos || pos == favPos + 1)) {
|
if (favPos != -1 && (pos == favPos || pos == favPos + 1)) {
|
||||||
@@ -797,20 +702,12 @@ const Dash = new Lang.Class({
|
|||||||
this._dragPlaceholder = new DragPlaceholderItem();
|
this._dragPlaceholder = new DragPlaceholderItem();
|
||||||
this._dragPlaceholder.child.set_width (this.iconSize);
|
this._dragPlaceholder.child.set_width (this.iconSize);
|
||||||
this._dragPlaceholder.child.set_height (this.iconSize / 2);
|
this._dragPlaceholder.child.set_height (this.iconSize / 2);
|
||||||
this._box.insert_child_at_index(this._dragPlaceholder.actor,
|
this._box.insert_actor(this._dragPlaceholder.actor,
|
||||||
this._dragPlaceholderPos);
|
this._dragPlaceholderPos);
|
||||||
if (fadeIn)
|
if (fadeIn)
|
||||||
this._dragPlaceholder.animateIn();
|
this._dragPlaceholder.animateIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the drag placeholder if we are not in the
|
|
||||||
// "favorites zone"
|
|
||||||
if (pos > numFavorites && this._dragPlaceholder) {
|
|
||||||
this._clearDragPlaceholder();
|
|
||||||
}
|
|
||||||
if (!this._dragPlaceholder)
|
|
||||||
return DND.DragMotionResult.NO_DROP;
|
|
||||||
|
|
||||||
let srcIsFavorite = (favPos != -1);
|
let srcIsFavorite = (favPos != -1);
|
||||||
|
|
||||||
if (srcIsFavorite)
|
if (srcIsFavorite)
|
||||||
@@ -853,11 +750,6 @@ const Dash = new Lang.Class({
|
|||||||
favPos++;
|
favPos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No drag placeholder means we don't wan't to favorite the app
|
|
||||||
// and we are dragging it to its original position
|
|
||||||
if (!this._dragPlaceholder)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
|
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
|
||||||
function () {
|
function () {
|
||||||
let appFavorites = AppFavorites.getAppFavorites();
|
let appFavorites = AppFavorites.getAppFavorites();
|
||||||
@@ -870,6 +762,6 @@ const Dash = new Lang.Class({
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
Signals.addSignalMethods(Dash.prototype);
|
Signals.addSignalMethods(Dash.prototype);
|
||||||
|
|||||||
@@ -2,14 +2,12 @@
|
|||||||
|
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GnomeDesktop = imports.gi.GnomeDesktop;
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Cairo = imports.cairo;
|
const Cairo = imports.cairo;
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Atk = imports.gi.Atk;
|
|
||||||
|
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const Util = imports.misc.util;
|
const Util = imports.misc.util;
|
||||||
@@ -17,6 +15,14 @@ const Main = imports.ui.main;
|
|||||||
const PanelMenu = imports.ui.panelMenu;
|
const PanelMenu = imports.ui.panelMenu;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
const Calendar = imports.ui.calendar;
|
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)
|
function _onVertSepRepaint (area)
|
||||||
{
|
{
|
||||||
@@ -34,27 +40,27 @@ function _onVertSepRepaint (area)
|
|||||||
cr.stroke();
|
cr.stroke();
|
||||||
};
|
};
|
||||||
|
|
||||||
const DateMenuButton = new Lang.Class({
|
function DateMenuButton() {
|
||||||
Name: 'DateMenuButton',
|
this._init.apply(this, arguments);
|
||||||
Extends: PanelMenu.Button,
|
}
|
||||||
|
|
||||||
|
DateMenuButton.prototype = {
|
||||||
|
__proto__: PanelMenu.Button.prototype,
|
||||||
|
|
||||||
|
_init: function(params) {
|
||||||
|
params = Params.parse(params, { showEvents: true });
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
let item;
|
let item;
|
||||||
let hbox;
|
let hbox;
|
||||||
let vbox;
|
let vbox;
|
||||||
|
|
||||||
let menuAlignment = 0.25;
|
let menuAlignment = 0.25;
|
||||||
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||||
menuAlignment = 1.0 - menuAlignment;
|
menuAlignment = 1.0 - menuAlignment;
|
||||||
this.parent(menuAlignment);
|
PanelMenu.Button.prototype._init.call(this, menuAlignment);
|
||||||
|
|
||||||
// At this moment calendar menu is not keyboard navigable at
|
this._clock = new St.Label();
|
||||||
// all (so not accessible), so it doesn't make sense to set as
|
this.actor.add_actor(this._clock);
|
||||||
// role ATK_ROLE_MENU like other elements of the panel.
|
|
||||||
this.actor.accessible_role = Atk.Role.LABEL;
|
|
||||||
|
|
||||||
this._clockDisplay = new St.Label();
|
|
||||||
this.actor.add_actor(this._clockDisplay);
|
|
||||||
|
|
||||||
hbox = new St.BoxLayout({name: 'calendarArea' });
|
hbox = new St.BoxLayout({name: 'calendarArea' });
|
||||||
this.menu.addActor(hbox);
|
this.menu.addActor(hbox);
|
||||||
@@ -66,11 +72,10 @@ const DateMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
// Date
|
// Date
|
||||||
this._date = new St.Label();
|
this._date = new St.Label();
|
||||||
this.actor.label_actor = this._clockDisplay;
|
|
||||||
this._date.style_class = 'datemenu-date-label';
|
this._date.style_class = 'datemenu-date-label';
|
||||||
vbox.add(this._date);
|
vbox.add(this._date);
|
||||||
|
|
||||||
if (Main.sessionMode.showCalendarEvents) {
|
if (params.showEvents) {
|
||||||
this._eventSource = new Calendar.DBusEventSource();
|
this._eventSource = new Calendar.DBusEventSource();
|
||||||
this._eventList = new Calendar.EventsList(this._eventSource);
|
this._eventList = new Calendar.EventsList(this._eventSource);
|
||||||
} else {
|
} else {
|
||||||
@@ -101,7 +106,7 @@ const DateMenuButton = new Lang.Class({
|
|||||||
item.actor.reparent(vbox);
|
item.actor.reparent(vbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Main.sessionMode.showCalendarEvents) {
|
if (params.showEvents) {
|
||||||
// Add vertical separator
|
// Add vertical separator
|
||||||
|
|
||||||
item = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
|
item = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
|
||||||
@@ -148,29 +153,77 @@ const DateMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
// Done with hbox for calendar and event list
|
// Done with hbox for calendar and event list
|
||||||
|
|
||||||
this._clock = new GnomeDesktop.WallClock();
|
// Track changes to clock settings
|
||||||
this._clock.connect('notify::clock', Lang.bind(this, this._updateClockAndDate));
|
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();
|
this._updateClockAndDate();
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateClockAndDate: function() {
|
_updateClockAndDate: function() {
|
||||||
this._clockDisplay.set_text(this._clock.clock);
|
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
|
/* 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").
|
* shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
|
||||||
*/
|
*/
|
||||||
let dateFormat = _("%A %B %e, %Y");
|
dateFormat = _("%A %B %e, %Y");
|
||||||
let displayDate = new Date();
|
|
||||||
this._date.set_text(displayDate.toLocaleFormat(dateFormat));
|
this._date.set_text(displayDate.toLocaleFormat(dateFormat));
|
||||||
|
|
||||||
|
Mainloop.timeout_add_seconds(1, Lang.bind(this, this._updateClockAndDate));
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onOpenCalendarActivate: function() {
|
_onOpenCalendarActivate: function() {
|
||||||
this.menu.close();
|
this.menu.close();
|
||||||
let calendarSettings = new Gio.Settings({ schema: 'org.gnome.desktop.default-applications.office.calendar' });
|
let calendarSettings = new Gio.Settings({ schema: 'org.gnome.desktop.default-applications.office.calendar' });
|
||||||
let tool = calendarSettings.get_string('exec');
|
let tool = calendarSettings.get_string('exec');
|
||||||
if (tool.length == 0 || tool.substr(0, 9) == 'evolution') {
|
if (tool.length == 0 || tool == 'evolution') {
|
||||||
// TODO: pass the selected day
|
// TODO: pass the selected day
|
||||||
let app = Shell.AppSystem.get_default().lookup_app('evolution-calendar.desktop');
|
Util.spawn(['evolution', '-c', 'calendar']);
|
||||||
app.activate();
|
|
||||||
} else {
|
} else {
|
||||||
let needTerm = calendarSettings.get_boolean('needs-term');
|
let needTerm = calendarSettings.get_boolean('needs-term');
|
||||||
if (needTerm) {
|
if (needTerm) {
|
||||||
@@ -186,4 +239,4 @@ const DateMenuButton = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|||||||
34
js/ui/dnd.js
@@ -69,9 +69,11 @@ function removeDragMonitor(monitor) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const _Draggable = new Lang.Class({
|
function _Draggable(actor, params) {
|
||||||
Name: 'Draggable',
|
this._init(actor, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
_Draggable.prototype = {
|
||||||
_init : function(actor, params) {
|
_init : function(actor, params) {
|
||||||
params = Params.parse(params, { manualMode: false,
|
params = Params.parse(params, { manualMode: false,
|
||||||
restoreOnSuccess: false,
|
restoreOnSuccess: false,
|
||||||
@@ -103,8 +105,8 @@ const _Draggable = new Lang.Class({
|
|||||||
this._dragInProgress = false; // The drag has been started, and has not been dropped or cancelled yet.
|
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).
|
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.
|
// During the drag, we eat enter/leave events so that actors don't prelight or show
|
||||||
// But we remember the actors that we first left/last entered so we can
|
// tooltips. But we remember the actors that we first left/last entered so we can
|
||||||
// fix up the hover state after the drag ends.
|
// fix up the hover state after the drag ends.
|
||||||
this._firstLeaveActor = null;
|
this._firstLeaveActor = null;
|
||||||
this._lastEnterActor = null;
|
this._lastEnterActor = null;
|
||||||
@@ -120,6 +122,12 @@ const _Draggable = new Lang.Class({
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
this._buttonDown = true;
|
this._buttonDown = true;
|
||||||
|
// special case St.Button: grabbing the pointer would mess up the
|
||||||
|
// internal state, so we start the drag manually on hover change
|
||||||
|
if (this.actor instanceof St.Button)
|
||||||
|
this.actor.connect('notify::hover',
|
||||||
|
Lang.bind(this, this._onButtonHoverChanged));
|
||||||
|
else
|
||||||
this._grabActor();
|
this._grabActor();
|
||||||
|
|
||||||
let [stageX, stageY] = event.get_coords();
|
let [stageX, stageY] = event.get_coords();
|
||||||
@@ -129,6 +137,15 @@ const _Draggable = new Lang.Class({
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onButtonHoverChanged: function(button) {
|
||||||
|
if (button.hover || !button.pressed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
button.fake_release();
|
||||||
|
this.startDrag(this._dragStartX, this._dragStartY,
|
||||||
|
global.get_current_time());
|
||||||
|
},
|
||||||
|
|
||||||
_grabActor: function() {
|
_grabActor: function() {
|
||||||
Clutter.grab_pointer(this.actor);
|
Clutter.grab_pointer(this.actor);
|
||||||
this._onEventId = this.actor.connect('event',
|
this._onEventId = this.actor.connect('event',
|
||||||
@@ -217,13 +234,6 @@ const _Draggable = new Lang.Class({
|
|||||||
currentDraggable = this;
|
currentDraggable = this;
|
||||||
this._dragInProgress = true;
|
this._dragInProgress = true;
|
||||||
|
|
||||||
// Special-case St.Button: the pointer grab messes with the internal
|
|
||||||
// state, so force a reset to a reasonable state here
|
|
||||||
if (this.actor instanceof St.Button) {
|
|
||||||
this.actor.fake_release();
|
|
||||||
this.actor.hover = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emit('drag-begin', time);
|
this.emit('drag-begin', time);
|
||||||
if (this._onEventId)
|
if (this._onEventId)
|
||||||
this._ungrabActor();
|
this._ungrabActor();
|
||||||
@@ -586,7 +596,7 @@ const _Draggable = new Lang.Class({
|
|||||||
this._dragActor = undefined;
|
this._dragActor = undefined;
|
||||||
currentDraggable = null;
|
currentDraggable = null;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
Signals.addSignalMethods(_Draggable.prototype);
|
Signals.addSignalMethods(_Draggable.prototype);
|
||||||
|
|
||||||
|
|||||||
47
js/ui/docDisplay.js
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const DocInfo = imports.misc.docInfo;
|
||||||
|
const Params = imports.misc.params;
|
||||||
|
const Search = imports.ui.search;
|
||||||
|
|
||||||
|
|
||||||
|
function DocSearchProvider() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
DocSearchProvider.prototype = {
|
||||||
|
__proto__: Search.SearchProvider.prototype,
|
||||||
|
|
||||||
|
_init: function(name) {
|
||||||
|
Search.SearchProvider.prototype._init.call(this, _("RECENT ITEMS"));
|
||||||
|
this._docManager = DocInfo.getDocManager();
|
||||||
|
},
|
||||||
|
|
||||||
|
getResultMeta: function(resultId) {
|
||||||
|
let docInfo = this._docManager.lookupByUri(resultId);
|
||||||
|
if (!docInfo)
|
||||||
|
return null;
|
||||||
|
return { 'id': resultId,
|
||||||
|
'name': docInfo.name,
|
||||||
|
'createIcon': function(size) {
|
||||||
|
return docInfo.createIcon(size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
activateResult: function(id, params) {
|
||||||
|
params = Params.parse(params, { workspace: -1,
|
||||||
|
timestamp: 0 });
|
||||||
|
|
||||||
|
let docInfo = this._docManager.lookupByUri(id);
|
||||||
|
docInfo.launch(params.workspace);
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialResultSet: function(terms) {
|
||||||
|
return this._docManager.initialSearch(terms);
|
||||||
|
},
|
||||||
|
|
||||||
|
getSubsearchResultSet: function(previousResults, terms) {
|
||||||
|
return this._docManager.subsearch(previousResults, terms);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -31,6 +31,7 @@ const St = imports.gi.St;
|
|||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
|
|
||||||
const GnomeSession = imports.misc.gnomeSession;
|
const GnomeSession = imports.misc.gnomeSession;
|
||||||
|
const Lightbox = imports.ui.lightbox;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
@@ -115,17 +116,37 @@ const DialogContent = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function findAppFromInhibitor(inhibitor) {
|
function findAppFromInhibitor(inhibitor) {
|
||||||
let [desktopFile] = inhibitor.GetAppIdSync();
|
let desktopFile = inhibitor.app_id;
|
||||||
|
|
||||||
if (!GLib.str_has_suffix(desktopFile, '.desktop'))
|
if (!GLib.str_has_suffix(desktopFile, '.desktop'))
|
||||||
desktopFile += '.desktop';
|
desktopFile += '.desktop';
|
||||||
|
|
||||||
return Shell.AppSystem.get_default().lookup_heuristic_basename(desktopFile);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListItem = new Lang.Class({
|
function ListItem(app, reason) {
|
||||||
Name: 'ListItem',
|
this._init(app, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
ListItem.prototype = {
|
||||||
_init: function(app, reason) {
|
_init: function(app, reason) {
|
||||||
this._app = app;
|
this._app = app;
|
||||||
this._reason = reason;
|
this._reason = reason;
|
||||||
@@ -171,7 +192,7 @@ const ListItem = new Lang.Class({
|
|||||||
this.emit('activate');
|
this.emit('activate');
|
||||||
this._app.activate();
|
this._app.activate();
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(ListItem.prototype);
|
Signals.addSignalMethods(ListItem.prototype);
|
||||||
|
|
||||||
// The logout timer only shows updates every 10 seconds
|
// The logout timer only shows updates every 10 seconds
|
||||||
@@ -209,19 +230,27 @@ function _setLabelText(label, text) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function EndSessionDialog() {
|
||||||
|
if (_endSessionDialog == null) {
|
||||||
|
this._init();
|
||||||
|
_endSessionDialog = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _endSessionDialog;
|
||||||
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
// This always returns the same singleton object
|
// This always returns the same singleton object
|
||||||
// By instantiating it initially, we register the
|
// By instantiating it initially, we register the
|
||||||
// bus object, etc.
|
// bus object, etc.
|
||||||
_endSessionDialog = new EndSessionDialog();
|
let dialog = new EndSessionDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
const EndSessionDialog = new Lang.Class({
|
EndSessionDialog.prototype = {
|
||||||
Name: 'EndSessionDialog',
|
__proto__: ModalDialog.ModalDialog.prototype,
|
||||||
Extends: ModalDialog.ModalDialog,
|
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent({ styleClass: 'end-session-dialog' });
|
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'end-session-dialog' });
|
||||||
|
|
||||||
this._user = AccountsService.UserManager.get_default().get_user(GLib.get_user_name());
|
this._user = AccountsService.UserManager.get_default().get_user(GLib.get_user_name());
|
||||||
|
|
||||||
@@ -279,17 +308,21 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
scrollView.hide();
|
scrollView.hide();
|
||||||
|
|
||||||
this._applicationList = new St.BoxLayout({ vertical: true });
|
this._applicationList = new St.BoxLayout({ vertical: true });
|
||||||
scrollView.add_actor(this._applicationList);
|
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',
|
this._applicationList.connect('actor-added',
|
||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
if (this._applicationList.get_n_children() == 1)
|
if (this._applicationList.get_children().length == 1)
|
||||||
scrollView.show();
|
scrollView.show();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._applicationList.connect('actor-removed',
|
this._applicationList.connect('actor-removed',
|
||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
if (this._applicationList.get_n_children() == 0)
|
if (this._applicationList.get_children().length == 0)
|
||||||
scrollView.hide();
|
scrollView.hide();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -310,8 +343,7 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
this._iconBin.child = null;
|
this._iconBin.child = null;
|
||||||
if (iconFile) {
|
if (iconFile) {
|
||||||
this._iconBin.show();
|
this._iconBin.show();
|
||||||
this._iconBin.set_style('background-image: url("' + iconFile + '");' +
|
this._iconBin.set_style('background-image: url("' + iconFile + '");');
|
||||||
'background-size: contain;');
|
|
||||||
} else {
|
} else {
|
||||||
this._iconBin.hide();
|
this._iconBin.hide();
|
||||||
}
|
}
|
||||||
@@ -337,7 +369,7 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateDescription: function() {
|
_updateContent: function() {
|
||||||
if (this.state != ModalDialog.State.OPENING &&
|
if (this.state != ModalDialog.State.OPENING &&
|
||||||
this.state != ModalDialog.State.OPENED)
|
this.state != ModalDialog.State.OPENED)
|
||||||
return;
|
return;
|
||||||
@@ -347,6 +379,17 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
let subject = dialogContent.subject;
|
let subject = dialogContent.subject;
|
||||||
let description;
|
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) {
|
if (this._inhibitors.length > 0) {
|
||||||
this._stopTimer();
|
this._stopTimer();
|
||||||
description = dialogContent.inhibitedDescription;
|
description = dialogContent.inhibitedDescription;
|
||||||
@@ -379,27 +422,6 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
_setLabelText(this._descriptionLabel, description);
|
_setLabelText(this._descriptionLabel, description);
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateContent: function() {
|
|
||||||
if (this.state != ModalDialog.State.OPENING &&
|
|
||||||
this.state != ModalDialog.State.OPENED)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let dialogContent = DialogContent[this._type];
|
|
||||||
|
|
||||||
if (this._user.is_loaded && !dialogContent.iconName) {
|
|
||||||
let iconFile = this._user.get_icon_file();
|
|
||||||
if (GLib.file_test(iconFile, GLib.FileTest.EXISTS))
|
|
||||||
this._setIconFromFile(iconFile, dialogContent.iconStyleClass);
|
|
||||||
else
|
|
||||||
this._setIconFromName('avatar-default', dialogContent.iconStyleClass);
|
|
||||||
} else if (dialogContent.iconName) {
|
|
||||||
this._setIconFromName(dialogContent.iconName,
|
|
||||||
dialogContent.iconStyleClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._updateDescription();
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateButtons: function() {
|
_updateButtons: function() {
|
||||||
let dialogContent = DialogContent[this._type];
|
let dialogContent = DialogContent[this._type];
|
||||||
let buttons = [{ action: Lang.bind(this, this.cancel),
|
let buttons = [{ action: Lang.bind(this, this.cancel),
|
||||||
@@ -419,7 +441,7 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
close: function() {
|
close: function() {
|
||||||
this.parent();
|
ModalDialog.ModalDialog.prototype.close.call(this);
|
||||||
this._dbusImpl.emit_signal('Closed', null);
|
this._dbusImpl.emit_signal('Closed', null);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -446,7 +468,7 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
{ _secondsLeft: 0,
|
{ _secondsLeft: 0,
|
||||||
time: this._secondsLeft,
|
time: this._secondsLeft,
|
||||||
transition: 'linear',
|
transition: 'linear',
|
||||||
onUpdate: Lang.bind(this, this._updateDescription),
|
onUpdate: Lang.bind(this, this._updateContent),
|
||||||
onComplete: Lang.bind(this, function() {
|
onComplete: Lang.bind(this, function() {
|
||||||
let dialogContent = DialogContent[this._type];
|
let dialogContent = DialogContent[this._type];
|
||||||
let button = dialogContent.confirmButtons[dialogContent.confirmButtons.length - 1];
|
let button = dialogContent.confirmButtons[dialogContent.confirmButtons.length - 1];
|
||||||
@@ -469,8 +491,7 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
let app = findAppFromInhibitor(inhibitor);
|
let app = findAppFromInhibitor(inhibitor);
|
||||||
|
|
||||||
if (app) {
|
if (app) {
|
||||||
let [reason] = inhibitor.GetReasonSync();
|
let item = new ListItem(app, inhibitor.reason);
|
||||||
let item = new ListItem(app, reason);
|
|
||||||
item.connect('activate',
|
item.connect('activate',
|
||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
this.close(global.get_current_time());
|
this.close(global.get_current_time());
|
||||||
@@ -489,11 +510,11 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
let [type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths] = parameters;
|
let [type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths] = parameters;
|
||||||
this._totalSecondsToStayOpen = totalSecondsToStayOpen;
|
this._totalSecondsToStayOpen = totalSecondsToStayOpen;
|
||||||
this._inhibitors = [];
|
this._inhibitors = [];
|
||||||
this._applicationList.destroy_all_children();
|
this._applicationList.destroy_children();
|
||||||
this._type = type;
|
this._type = type;
|
||||||
|
|
||||||
if (!(this._type in DialogContent)) {
|
if (!(this._type in DialogContent)) {
|
||||||
invocation.return_dbus_error('org.gnome.Shell.ModalDialog.TypeError',
|
invocation.report_dbus_error('org.gnome.Shell.ModalDialog.TypeError',
|
||||||
"Unknown dialog type requested");
|
"Unknown dialog type requested");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -509,7 +530,7 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
this._updateButtons();
|
this._updateButtons();
|
||||||
|
|
||||||
if (!this.open(timestamp)) {
|
if (!this.open(timestamp)) {
|
||||||
invocation.return_dbus_error('org.gnome.Shell.ModalDialog.GrabError',
|
invocation.report_dbus_error('org.gnome.Shell.ModalDialog.GrabError',
|
||||||
"Cannot grab pointer and keyboard");
|
"Cannot grab pointer and keyboard");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -522,4 +543,4 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
this.disconnect(signalId);
|
this.disconnect(signalId);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|||||||
@@ -39,23 +39,20 @@ function _patchContainerClass(containerClass) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function _makeLoggingFunc(func) {
|
|
||||||
return function() {
|
|
||||||
return func([].join.call(arguments, ', '));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
// Add some bindings to the global JS namespace; (gjs keeps the web
|
// Add some bindings to the global JS namespace; (gjs keeps the web
|
||||||
// browser convention of having that namespace be called 'window'.)
|
// browser convention of having that namespace be called 'window'.)
|
||||||
window.global = Shell.Global.get();
|
window.global = Shell.Global.get();
|
||||||
|
|
||||||
window.log = _makeLoggingFunc(window.log);
|
|
||||||
|
|
||||||
window._ = Gettext.gettext;
|
window._ = Gettext.gettext;
|
||||||
window.C_ = Gettext.pgettext;
|
window.C_ = Gettext.pgettext;
|
||||||
window.ngettext = Gettext.ngettext;
|
window.ngettext = Gettext.ngettext;
|
||||||
|
|
||||||
|
// Set the default direction for St widgets (this needs to be done before any use of St)
|
||||||
|
if (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL) {
|
||||||
|
St.Widget.set_default_direction(St.TextDirection.RTL);
|
||||||
|
}
|
||||||
|
|
||||||
// Miscellaneous monkeypatching
|
// Miscellaneous monkeypatching
|
||||||
_patchContainerClass(St.BoxLayout);
|
_patchContainerClass(St.BoxLayout);
|
||||||
_patchContainerClass(St.Table);
|
_patchContainerClass(St.Table);
|
||||||
@@ -67,14 +64,10 @@ function init() {
|
|||||||
let origToString = Object.prototype.toString;
|
let origToString = Object.prototype.toString;
|
||||||
Object.prototype.toString = function() {
|
Object.prototype.toString = function() {
|
||||||
let base = origToString.call(this);
|
let base = origToString.call(this);
|
||||||
try {
|
|
||||||
if ('actor' in this && this.actor instanceof Clutter.Actor)
|
if ('actor' in this && this.actor instanceof Clutter.Actor)
|
||||||
return base.replace(/\]$/, ' delegate for ' + this.actor.toString().substring(1));
|
return base.replace(/\]$/, ' delegate for ' + this.actor.toString().substring(1));
|
||||||
else
|
else
|
||||||
return base;
|
return base;
|
||||||
} catch(e) {
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=508783
|
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=508783
|
||||||
@@ -90,7 +83,7 @@ function init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OK, now things are initialized enough that we can import shell JS
|
// OK, now things are initialized enough that we can import shell JS
|
||||||
const Format = imports.format;
|
const Format = imports.misc.format;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
Tweener.init();
|
Tweener.init();
|
||||||
|
|||||||
@@ -1,270 +0,0 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
const Lang = imports.lang;
|
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const Gio = imports.gi.Gio;
|
|
||||||
const Soup = imports.gi.Soup;
|
|
||||||
const St = imports.gi.St;
|
|
||||||
const Shell = imports.gi.Shell;
|
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
|
||||||
const ExtensionSystem = imports.ui.extensionSystem;
|
|
||||||
const FileUtils = imports.misc.fileUtils;
|
|
||||||
const ModalDialog = imports.ui.modalDialog;
|
|
||||||
|
|
||||||
const _signals = ExtensionSystem._signals;
|
|
||||||
|
|
||||||
const REPOSITORY_URL_BASE = 'https://extensions.gnome.org';
|
|
||||||
const REPOSITORY_URL_DOWNLOAD = REPOSITORY_URL_BASE + '/download-extension/%s.shell-extension.zip';
|
|
||||||
const REPOSITORY_URL_INFO = REPOSITORY_URL_BASE + '/extension-info/';
|
|
||||||
const REPOSITORY_URL_UPDATE = REPOSITORY_URL_BASE + '/update-info/';
|
|
||||||
|
|
||||||
let _httpSession;
|
|
||||||
|
|
||||||
function installExtension(uuid, invocation) {
|
|
||||||
let params = { uuid: uuid,
|
|
||||||
shell_version: Config.PACKAGE_VERSION };
|
|
||||||
|
|
||||||
let message = Soup.form_request_new_from_hash('GET', REPOSITORY_URL_INFO, params);
|
|
||||||
|
|
||||||
_httpSession.queue_message(message, function(session, message) {
|
|
||||||
if (message.status_code != Soup.KnownStatusCode.OK) {
|
|
||||||
ExtensionSystem.logExtensionError(uuid, 'downloading info: ' + message.status_code);
|
|
||||||
invocation.return_dbus_error('org.gnome.Shell.DownloadInfoError', message.status_code.toString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let info;
|
|
||||||
try {
|
|
||||||
info = JSON.parse(message.response_body.data);
|
|
||||||
} catch (e) {
|
|
||||||
ExtensionSystem.logExtensionError(uuid, 'parsing info: ' + e);
|
|
||||||
invocation.return_dbus_error('org.gnome.Shell.ParseInfoError', e.toString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let dialog = new InstallExtensionDialog(uuid, info, invocation);
|
|
||||||
dialog.open(global.get_current_time());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function uninstallExtension(uuid) {
|
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
|
||||||
if (!extension)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Don't try to uninstall system extensions
|
|
||||||
if (extension.type != ExtensionUtils.ExtensionType.PER_USER)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!ExtensionSystem.unloadExtension(uuid))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
FileUtils.recursivelyDeleteDir(extension.dir, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gotExtensionZipFile(session, message, uuid, dir, callback, errback) {
|
|
||||||
if (message.status_code != Soup.KnownStatusCode.OK) {
|
|
||||||
errback('DownloadExtensionError', message.status_code);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!dir.query_exists(null))
|
|
||||||
dir.make_directory_with_parents(null);
|
|
||||||
} catch (e) {
|
|
||||||
errback('CreateExtensionDirectoryError', e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let [file, stream] = Gio.File.new_tmp('XXXXXX.shell-extension.zip');
|
|
||||||
let contents = message.response_body.flatten().as_bytes();
|
|
||||||
stream.output_stream.write_bytes(contents, null);
|
|
||||||
stream.close(null);
|
|
||||||
let [success, pid] = GLib.spawn_async(null,
|
|
||||||
['unzip', '-uod', dir.get_path(), '--', file.get_path()],
|
|
||||||
null,
|
|
||||||
GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
|
|
||||||
null);
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
errback('ExtractExtensionError');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function(pid, status) {
|
|
||||||
GLib.spawn_close_pid(pid);
|
|
||||||
|
|
||||||
if (status != 0)
|
|
||||||
errback('ExtractExtensionError');
|
|
||||||
else
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateExtension(uuid) {
|
|
||||||
// This gets a bit tricky. We want the update to be seamless -
|
|
||||||
// if we have any error during downloading or extracting, we
|
|
||||||
// want to not unload the current version.
|
|
||||||
|
|
||||||
let oldExtensionTmpDir = GLib.Dir.make_tmp('XXXXXX-shell-extension');
|
|
||||||
let newExtensionTmpDir = GLib.Dir.make_tmp('XXXXXX-shell-extension');
|
|
||||||
|
|
||||||
let params = { shell_version: Config.PACKAGE_VERSION };
|
|
||||||
|
|
||||||
let url = REPOSITORY_URL_DOWNLOAD.format(uuid);
|
|
||||||
let message = Soup.form_request_new_from_hash('GET', url, params);
|
|
||||||
|
|
||||||
_httpSession.queue_message(message, Lang.bind(this, function(session, message) {
|
|
||||||
gotExtensionZipFile(session, message, uuid, newExtensionTmpDir, function() {
|
|
||||||
let oldExtension = ExtensionUtils.extensions[uuid];
|
|
||||||
let extensionDir = oldExtension.dir;
|
|
||||||
|
|
||||||
if (!ExtensionSystem.unloadExtension(uuid))
|
|
||||||
return;
|
|
||||||
|
|
||||||
FileUtils.recursivelyMoveDir(extensionDir, oldExtensionTmpDir);
|
|
||||||
FileUtils.recursivelyMoveDir(newExtensionTmpDir, extensionDir);
|
|
||||||
|
|
||||||
let extension = ExtensionUtils.createExtensionObject(uuid, extensionDir, ExtensionUtils.ExtensionType.PER_USER);
|
|
||||||
|
|
||||||
try {
|
|
||||||
ExtensionSystem.loadExtension(extension);
|
|
||||||
} catch(e) {
|
|
||||||
ExtensionSystem.unloadExtension(uuid);
|
|
||||||
|
|
||||||
logError(e, 'Error loading extension %s'.format(uuid));
|
|
||||||
|
|
||||||
FileUtils.recursivelyDeleteDir(extensionDir, false);
|
|
||||||
FileUtils.recursivelyMoveDir(oldExtensionTmpDir, extensionDir);
|
|
||||||
|
|
||||||
// Restore what was there before. We can't do much if we
|
|
||||||
// fail here.
|
|
||||||
ExtensionSystem.loadExtension(oldExtension);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FileUtils.recursivelyDeleteDir(oldExtensionTmpDir, true);
|
|
||||||
}, function(code, message) {
|
|
||||||
log('Error while updating extension %s: %s (%s)'.format(uuid, code, message ? message : ''));
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkForUpdates() {
|
|
||||||
let metadatas = {};
|
|
||||||
for (let uuid in ExtensionUtils.extensions) {
|
|
||||||
metadatas[uuid] = ExtensionUtils.extensions[uuid].metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
let params = { shell_version: Config.PACKAGE_VERSION,
|
|
||||||
installed: JSON.stringify(metadatas) };
|
|
||||||
|
|
||||||
let url = REPOSITORY_URL_UPDATE;
|
|
||||||
let message = Soup.form_request_new_from_hash('GET', url, params);
|
|
||||||
_httpSession.queue_message(message, function(session, message) {
|
|
||||||
if (message.status_code != Soup.KnownStatusCode.OK)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let operations = JSON.parse(message.response_body.data);
|
|
||||||
for (let uuid in operations) {
|
|
||||||
let operation = operations[uuid];
|
|
||||||
if (operation == 'blacklist')
|
|
||||||
uninstallExtension(uuid);
|
|
||||||
else if (operation == 'upgrade' || operation == 'downgrade')
|
|
||||||
updateExtension(uuid);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const InstallExtensionDialog = new Lang.Class({
|
|
||||||
Name: 'InstallExtensionDialog',
|
|
||||||
Extends: ModalDialog.ModalDialog,
|
|
||||||
|
|
||||||
_init: function(uuid, info, invocation) {
|
|
||||||
this.parent({ styleClass: 'extension-dialog' });
|
|
||||||
|
|
||||||
this._uuid = uuid;
|
|
||||||
this._info = info;
|
|
||||||
this._invocation = invocation;
|
|
||||||
|
|
||||||
this.setButtons([{ label: _("Cancel"),
|
|
||||||
action: Lang.bind(this, this._onCancelButtonPressed),
|
|
||||||
key: Clutter.Escape
|
|
||||||
},
|
|
||||||
{ label: _("Install"),
|
|
||||||
action: Lang.bind(this, this._onInstallButtonPressed),
|
|
||||||
default: true
|
|
||||||
}]);
|
|
||||||
|
|
||||||
let message = _("Download and install '%s' from extensions.gnome.org?").format(info.name);
|
|
||||||
|
|
||||||
let box = new St.BoxLayout();
|
|
||||||
this.contentLayout.add(box);
|
|
||||||
|
|
||||||
let gicon = new Gio.FileIcon({ file: Gio.File.new_for_uri(REPOSITORY_URL_BASE + info.icon) })
|
|
||||||
let icon = new St.Icon({ gicon: gicon });
|
|
||||||
box.add(icon);
|
|
||||||
|
|
||||||
let label = new St.Label({ text: message });
|
|
||||||
box.add(label);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onCancelButtonPressed: function(button, event) {
|
|
||||||
this.close(global.get_current_time());
|
|
||||||
this._invocation.return_value(GLib.Variant.new('(s)', ['cancelled']));
|
|
||||||
},
|
|
||||||
|
|
||||||
_onInstallButtonPressed: function(button, event) {
|
|
||||||
let params = { shell_version: Config.PACKAGE_VERSION };
|
|
||||||
|
|
||||||
let url = REPOSITORY_URL_DOWNLOAD.format(this._uuid);
|
|
||||||
let message = Soup.form_request_new_from_hash('GET', url, params);
|
|
||||||
|
|
||||||
let uuid = this._uuid;
|
|
||||||
let dir = Gio.File.new_for_path(GLib.build_filenamev([global.userdatadir, 'extensions', uuid]));
|
|
||||||
let invocation = this._invocation;
|
|
||||||
function errback(code, message) {
|
|
||||||
invocation.return_dbus_error('org.gnome.Shell.' + code, message ? message.toString() : '');
|
|
||||||
}
|
|
||||||
|
|
||||||
function callback() {
|
|
||||||
// Add extension to 'enabled-extensions' for the user, always...
|
|
||||||
let enabledExtensions = global.settings.get_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY);
|
|
||||||
if (enabledExtensions.indexOf(uuid) == -1) {
|
|
||||||
enabledExtensions.push(uuid);
|
|
||||||
global.settings.set_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY, enabledExtensions);
|
|
||||||
}
|
|
||||||
|
|
||||||
let extension = ExtensionUtils.createExtensionObject(uuid, dir, ExtensionUtils.ExtensionType.PER_USER);
|
|
||||||
|
|
||||||
try {
|
|
||||||
ExtensionSystem.loadExtension(extension);
|
|
||||||
} catch(e) {
|
|
||||||
uninstallExtension(uuid);
|
|
||||||
errback('LoadExtensionError', e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
invocation.return_value(GLib.Variant.new('(s)', 'successful'));
|
|
||||||
}
|
|
||||||
|
|
||||||
_httpSession.queue_message(message, Lang.bind(this, function(session, message) {
|
|
||||||
gotExtensionZipFile(session, message, uuid, dir, callback, errback);
|
|
||||||
}));
|
|
||||||
|
|
||||||
this.close(global.get_current_time());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function init() {
|
|
||||||
_httpSession = new Soup.SessionAsync({ ssl_use_system_ca_file: true });
|
|
||||||
|
|
||||||
// See: https://bugzilla.gnome.org/show_bug.cgi?id=655189 for context.
|
|
||||||
// _httpSession.add_feature(new Soup.ProxyResolverDefault());
|
|
||||||
Soup.Session.prototype.add_feature.call(_httpSession, new Soup.ProxyResolverDefault());
|
|
||||||
}
|
|
||||||
@@ -3,11 +3,18 @@
|
|||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
|
||||||
|
const Clutter = imports.gi.Clutter;
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
const Soup = imports.gi.Soup;
|
||||||
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
const Config = imports.misc.config;
|
||||||
|
const FileUtils = imports.misc.fileUtils;
|
||||||
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
|
|
||||||
|
const API_VERSION = 1;
|
||||||
|
|
||||||
const ExtensionState = {
|
const ExtensionState = {
|
||||||
ENABLED: 1,
|
ENABLED: 1,
|
||||||
@@ -22,11 +29,48 @@ const ExtensionState = {
|
|||||||
UNINSTALLED: 99
|
UNINSTALLED: 99
|
||||||
};
|
};
|
||||||
|
|
||||||
// Arrays of uuids
|
const ExtensionType = {
|
||||||
var enabledExtensions;
|
SYSTEM: 1,
|
||||||
|
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 = {};
|
||||||
// Contains the order that extensions were enabled in.
|
// Contains the order that extensions were enabled in.
|
||||||
const extensionOrder = [];
|
const extensionOrder = [];
|
||||||
|
|
||||||
|
// Arrays of uuids
|
||||||
|
var enabledExtensions;
|
||||||
|
// GFile for user extensions
|
||||||
|
var userExtensionsDir = null;
|
||||||
|
|
||||||
// We don't really have a class to add signals on. So, create
|
// We don't really have a class to add signals on. So, create
|
||||||
// a simple dummy object, add the signal methods, and export those
|
// a simple dummy object, add the signal methods, and export those
|
||||||
// publically.
|
// publically.
|
||||||
@@ -36,16 +80,142 @@ Signals.addSignalMethods(_signals);
|
|||||||
const connect = Lang.bind(_signals, _signals.connect);
|
const connect = Lang.bind(_signals, _signals.connect);
|
||||||
const disconnect = Lang.bind(_signals, _signals.disconnect);
|
const disconnect = Lang.bind(_signals, _signals.disconnect);
|
||||||
|
|
||||||
|
// UUID => Array of error messages
|
||||||
|
var errors = {};
|
||||||
|
|
||||||
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
|
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) {
|
function disableExtension(uuid) {
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
let meta = extensionMeta[uuid];
|
||||||
if (!extension)
|
if (!meta)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (extension.state != ExtensionState.ENABLED)
|
if (meta.state != ExtensionState.ENABLED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
let extensionState = extensionStateObjs[uuid];
|
||||||
|
|
||||||
// "Rebase" the extension order by disabling and then enabling extensions
|
// "Rebase" the extension order by disabling and then enabling extensions
|
||||||
// in order to help prevent conflicts.
|
// in order to help prevent conflicts.
|
||||||
|
|
||||||
@@ -61,147 +231,206 @@ function disableExtension(uuid) {
|
|||||||
for (let i = 0; i < orderReversed.length; i++) {
|
for (let i = 0; i < orderReversed.length; i++) {
|
||||||
let uuid = orderReversed[i];
|
let uuid = orderReversed[i];
|
||||||
try {
|
try {
|
||||||
ExtensionUtils.extensions[uuid].stateObj.disable();
|
extensionStateObjs[uuid].disable();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
logExtensionError(uuid, e);
|
logExtensionError(uuid, e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extension.stylesheet) {
|
try {
|
||||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
extensionState.disable();
|
||||||
theme.unload_stylesheet(extension.stylesheet.get_path());
|
} catch(e) {
|
||||||
|
logExtensionError(uuid, e.toString());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
extension.stateObj.disable();
|
|
||||||
|
|
||||||
for (let i = 0; i < order.length; i++) {
|
for (let i = 0; i < order.length; i++) {
|
||||||
let uuid = order[i];
|
let uuid = order[i];
|
||||||
try {
|
try {
|
||||||
ExtensionUtils.extensions[uuid].stateObj.enable();
|
extensionStateObjs[uuid].enable();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
logExtensionError(uuid, e);
|
logExtensionError(uuid, e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extensionOrder.splice(orderIdx, 1);
|
extensionOrder.splice(orderIdx, 1);
|
||||||
|
|
||||||
extension.state = ExtensionState.DISABLED;
|
meta.state = ExtensionState.DISABLED;
|
||||||
_signals.emit('extension-state-changed', extension);
|
_signals.emit('extension-state-changed', meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
function enableExtension(uuid) {
|
function enableExtension(uuid) {
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
let meta = extensionMeta[uuid];
|
||||||
if (!extension)
|
if (!meta)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (extension.state == ExtensionState.INITIALIZED)
|
if (meta.state == ExtensionState.INITIALIZED) {
|
||||||
initExtension(uuid);
|
loadExtension(meta.dir, meta.type, true);
|
||||||
|
|
||||||
if (extension.state != ExtensionState.DISABLED)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meta.state != ExtensionState.DISABLED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let extensionState = extensionStateObjs[uuid];
|
||||||
|
|
||||||
extensionOrder.push(uuid);
|
extensionOrder.push(uuid);
|
||||||
|
|
||||||
extension.stateObj.enable();
|
try {
|
||||||
|
extensionState.enable();
|
||||||
let stylesheetFile = extension.dir.get_child('stylesheet.css');
|
} catch(e) {
|
||||||
if (stylesheetFile.query_exists(null)) {
|
logExtensionError(uuid, e.toString());
|
||||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
return;
|
||||||
theme.load_stylesheet(stylesheetFile.get_path());
|
|
||||||
extension.stylesheet = stylesheetFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension.state = ExtensionState.ENABLED;
|
meta.state = ExtensionState.ENABLED;
|
||||||
_signals.emit('extension-state-changed', extension);
|
_signals.emit('extension-state-changed', meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
function logExtensionError(uuid, error) {
|
function logExtensionError(uuid, message, state) {
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
if (!errors[uuid]) errors[uuid] = [];
|
||||||
if (!extension)
|
errors[uuid].push(message);
|
||||||
return;
|
global.logError('Extension "%s" had error: %s'.format(uuid, message));
|
||||||
|
state = state || ExtensionState.ERROR;
|
||||||
let message = '' + error;
|
|
||||||
|
|
||||||
if (error.state)
|
|
||||||
extension.state = error.state;
|
|
||||||
else
|
|
||||||
extension.state = ExtensionState.ERROR;
|
|
||||||
|
|
||||||
if (!extension.errors)
|
|
||||||
extension.errors = [];
|
|
||||||
|
|
||||||
log('Extension "%s" had error: %s'.format(uuid, message));
|
|
||||||
_signals.emit('extension-state-changed', { uuid: uuid,
|
_signals.emit('extension-state-changed', { uuid: uuid,
|
||||||
error: message,
|
error: message,
|
||||||
state: extension.state });
|
state: state });
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadExtension(extension) {
|
function loadExtension(dir, type, enabled) {
|
||||||
|
let info;
|
||||||
|
let uuid = dir.get_basename();
|
||||||
|
|
||||||
|
let metadataFile = dir.get_child('metadata.json');
|
||||||
|
if (!metadataFile.query_exists(null)) {
|
||||||
|
logExtensionError(uuid, 'Missing metadata.json');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let metadataContents;
|
||||||
|
try {
|
||||||
|
metadataContents = Shell.get_file_contents_utf8_sync(metadataFile.get_path());
|
||||||
|
} catch (e) {
|
||||||
|
logExtensionError(uuid, 'Failed to load metadata.json: ' + e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let meta;
|
||||||
|
try {
|
||||||
|
meta = JSON.parse(metadataContents);
|
||||||
|
} catch (e) {
|
||||||
|
logExtensionError(uuid, 'Failed to parse metadata.json: ' + e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let requiredProperties = ['uuid', 'name', 'description', 'shell-version'];
|
||||||
|
for (let i = 0; i < requiredProperties.length; i++) {
|
||||||
|
let prop = requiredProperties[i];
|
||||||
|
if (!meta[prop]) {
|
||||||
|
logExtensionError(uuid, 'missing "' + prop + '" property in metadata.json');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extensions[uuid] != undefined) {
|
||||||
|
logExtensionError(uuid, 'extension already loaded');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encourage people to add this
|
||||||
|
if (!meta['url']) {
|
||||||
|
global.log('Warning: Missing "url" property in metadata.json');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uuid != meta.uuid) {
|
||||||
|
logExtensionError(uuid, 'uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
extensionMeta[uuid] = meta;
|
||||||
|
meta.type = type;
|
||||||
|
meta.dir = dir;
|
||||||
|
meta.path = dir.get_path();
|
||||||
|
meta.error = '';
|
||||||
|
|
||||||
// Default to error, we set success as the last step
|
// Default to error, we set success as the last step
|
||||||
extension.state = ExtensionState.ERROR;
|
meta.state = ExtensionState.ERROR;
|
||||||
|
|
||||||
if (ExtensionUtils.isOutOfDate(extension)) {
|
if (!versionCheck(meta['shell-version'], Config.PACKAGE_VERSION) ||
|
||||||
let error = new Error('extension is not compatible with current GNOME Shell and/or GJS version');
|
(meta['js-version'] && !versionCheck(meta['js-version'], Config.GJS_VERSION))) {
|
||||||
error.state = ExtensionState.OUT_OF_DATE;
|
logExtensionError(uuid, 'extension is not compatible with current GNOME Shell and/or GJS version', ExtensionState.OUT_OF_DATE);
|
||||||
throw error;
|
meta.state = ExtensionState.OUT_OF_DATE;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let enabled = enabledExtensions.indexOf(extension.uuid) != -1;
|
if (!enabled) {
|
||||||
if (enabled) {
|
meta.state = ExtensionState.INITIALIZED;
|
||||||
initExtension(extension.uuid);
|
return;
|
||||||
if (extension.state == ExtensionState.DISABLED)
|
|
||||||
enableExtension(extension.uuid);
|
|
||||||
} else {
|
|
||||||
extension.state = ExtensionState.INITIALIZED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_signals.emit('extension-state-changed', extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
function unloadExtension(uuid) {
|
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
|
||||||
if (!extension)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Try to disable it -- if it's ERROR'd, we can't guarantee that,
|
|
||||||
// but it will be removed on next reboot, and hopefully nothing
|
|
||||||
// broke too much.
|
|
||||||
disableExtension(uuid);
|
|
||||||
|
|
||||||
extension.state = ExtensionState.UNINSTALLED;
|
|
||||||
_signals.emit('extension-state-changed', extension);
|
|
||||||
|
|
||||||
delete ExtensionUtils.extensions[uuid];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function initExtension(uuid) {
|
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
|
||||||
let dir = extension.dir;
|
|
||||||
|
|
||||||
if (!extension)
|
|
||||||
throw new Error("Extension was not properly created. Call loadExtension first");
|
|
||||||
|
|
||||||
let extensionJs = dir.get_child('extension.js');
|
let extensionJs = dir.get_child('extension.js');
|
||||||
if (!extensionJs.query_exists(null))
|
if (!extensionJs.query_exists(null)) {
|
||||||
throw new Error('Missing extension.js');
|
logExtensionError(uuid, 'Missing extension.js');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let stylesheetPath = null;
|
||||||
|
let themeContext = St.ThemeContext.get_for_stage(global.stage);
|
||||||
|
let theme = themeContext.get_theme();
|
||||||
|
let stylesheetFile = dir.get_child('stylesheet.css');
|
||||||
|
if (stylesheetFile.query_exists(null)) {
|
||||||
|
try {
|
||||||
|
theme.load_stylesheet(stylesheetFile.get_path());
|
||||||
|
} catch (e) {
|
||||||
|
logExtensionError(uuid, 'Stylesheet parse error: ' + e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let extensionModule;
|
let extensionModule;
|
||||||
let extensionState = null;
|
let extensionState = null;
|
||||||
|
try {
|
||||||
|
global.add_extension_importer('imports.ui.extensionSystem.extensions', meta.uuid, dir.get_path());
|
||||||
|
extensionModule = extensions[meta.uuid].extension;
|
||||||
|
} catch (e) {
|
||||||
|
if (stylesheetPath != null)
|
||||||
|
theme.unload_stylesheet(stylesheetPath);
|
||||||
|
logExtensionError(uuid, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ExtensionUtils.installImporter(extension);
|
if (!extensionModule.init) {
|
||||||
extensionModule = extension.imports.extension;
|
logExtensionError(uuid, 'missing \'init\' function');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (extensionModule.init) {
|
try {
|
||||||
extensionState = extensionModule.init(extension);
|
extensionState = extensionModule.init(meta);
|
||||||
|
} catch (e) {
|
||||||
|
if (stylesheetPath != null)
|
||||||
|
theme.unload_stylesheet(stylesheetPath);
|
||||||
|
logExtensionError(uuid, 'Failed to evaluate init function:' + e);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!extensionState)
|
if (!extensionState)
|
||||||
extensionState = extensionModule;
|
extensionState = extensionModule;
|
||||||
extension.stateObj = extensionState;
|
extensionStateObjs[uuid] = extensionState;
|
||||||
|
|
||||||
extension.state = ExtensionState.DISABLED;
|
if (!extensionState.enable) {
|
||||||
_signals.emit('extension-loaded', uuid);
|
logExtensionError(uuid, 'missing \'enable\' function');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!extensionState.disable) {
|
||||||
|
logExtensionError(uuid, 'missing \'disable\' function');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
meta.state = ExtensionState.DISABLED;
|
||||||
|
|
||||||
|
enableExtension(uuid);
|
||||||
|
|
||||||
|
_signals.emit('extension-loaded', meta.uuid);
|
||||||
|
_signals.emit('extension-state-changed', meta);
|
||||||
|
global.log('Loaded extension ' + meta.uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEnabledExtensionsChanged() {
|
function onEnabledExtensionsChanged() {
|
||||||
@@ -212,11 +441,7 @@ function onEnabledExtensionsChanged() {
|
|||||||
newEnabledExtensions.filter(function(uuid) {
|
newEnabledExtensions.filter(function(uuid) {
|
||||||
return enabledExtensions.indexOf(uuid) == -1;
|
return enabledExtensions.indexOf(uuid) == -1;
|
||||||
}).forEach(function(uuid) {
|
}).forEach(function(uuid) {
|
||||||
try {
|
|
||||||
enableExtension(uuid);
|
enableExtension(uuid);
|
||||||
} catch(e) {
|
|
||||||
logExtensionError(uuid, e);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Find and disable all the newly disabled extensions: UUIDs found in the
|
// Find and disable all the newly disabled extensions: UUIDs found in the
|
||||||
@@ -224,27 +449,125 @@ function onEnabledExtensionsChanged() {
|
|||||||
enabledExtensions.filter(function(item) {
|
enabledExtensions.filter(function(item) {
|
||||||
return newEnabledExtensions.indexOf(item) == -1;
|
return newEnabledExtensions.indexOf(item) == -1;
|
||||||
}).forEach(function(uuid) {
|
}).forEach(function(uuid) {
|
||||||
try {
|
|
||||||
disableExtension(uuid);
|
disableExtension(uuid);
|
||||||
} catch(e) {
|
|
||||||
logExtensionError(uuid, e);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
enabledExtensions = newEnabledExtensions;
|
enabledExtensions = newEnabledExtensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadExtensions() {
|
function init() {
|
||||||
|
let userExtensionsPath = GLib.build_filenamev([global.userdatadir, 'extensions']);
|
||||||
|
userExtensionsDir = Gio.file_new_for_path(userExtensionsPath);
|
||||||
|
try {
|
||||||
|
if (!userExtensionsDir.query_exists(null))
|
||||||
|
userExtensionsDir.make_directory_with_parents(null);
|
||||||
|
} catch (e) {
|
||||||
|
global.logError('' + e);
|
||||||
|
}
|
||||||
|
|
||||||
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
|
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
|
||||||
enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
||||||
|
|
||||||
let finder = new ExtensionUtils.ExtensionFinder();
|
|
||||||
finder.connect('extension-found', function(signals, extension) {
|
|
||||||
try {
|
|
||||||
loadExtension(extension);
|
|
||||||
} catch(e) {
|
|
||||||
logExtensionError(extension.uuid, e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
finder.scanExtensions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _loadExtensionsIn(dir, type) {
|
||||||
|
let fileEnum;
|
||||||
|
let file, info;
|
||||||
|
try {
|
||||||
|
fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
|
||||||
|
} catch (e) {
|
||||||
|
global.logError('' + e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((info = fileEnum.next_file(null)) != null) {
|
||||||
|
let fileType = info.get_file_type();
|
||||||
|
if (fileType != Gio.FileType.DIRECTORY)
|
||||||
|
continue;
|
||||||
|
let name = info.get_name();
|
||||||
|
let child = dir.get_child(name);
|
||||||
|
let enabled = enabledExtensions.indexOf(name) != -1;
|
||||||
|
loadExtension(child, type, enabled);
|
||||||
|
}
|
||||||
|
fileEnum.close(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadExtensions() {
|
||||||
|
let systemDataDirs = GLib.get_system_data_dirs();
|
||||||
|
for (let i = 0; i < systemDataDirs.length; i++) {
|
||||||
|
let dirPath = systemDataDirs[i] + '/gnome-shell/extensions';
|
||||||
|
let dir = Gio.file_new_for_path(dirPath);
|
||||||
|
if (dir.query_exists(null))
|
||||||
|
_loadExtensionsIn(dir, ExtensionType.SYSTEM);
|
||||||
|
}
|
||||||
|
_loadExtensionsIn(userExtensionsDir, ExtensionType.PER_USER);
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
const Lang = imports.lang;
|
|
||||||
|
|
||||||
const Lightbox = imports.ui.lightbox;
|
|
||||||
const Main = imports.ui.main;
|
|
||||||
const Tweener = imports.ui.tweener;
|
|
||||||
|
|
||||||
const FLASHSPOT_ANIMATION_TIME = 0.25; // seconds
|
|
||||||
|
|
||||||
const Flashspot = new Lang.Class({
|
|
||||||
Name: 'Flashspot',
|
|
||||||
Extends: Lightbox.Lightbox,
|
|
||||||
|
|
||||||
_init: function(area) {
|
|
||||||
this.parent(Main.uiGroup, { inhibitEvents: true,
|
|
||||||
width: area.width,
|
|
||||||
height: area.height });
|
|
||||||
|
|
||||||
this.actor.style_class = 'flashspot';
|
|
||||||
this.actor.set_position(area.x, area.y);
|
|
||||||
},
|
|
||||||
|
|
||||||
fire: function() {
|
|
||||||
this.actor.opacity = 0;
|
|
||||||
Tweener.addTween(this.actor,
|
|
||||||
{ opacity: 255,
|
|
||||||
time: FLASHSPOT_ANIMATION_TIME,
|
|
||||||
transition: 'linear',
|
|
||||||
onComplete: Lang.bind(this, this._onFireShowComplete)
|
|
||||||
});
|
|
||||||
this.actor.show();
|
|
||||||
},
|
|
||||||
|
|
||||||
_onFireShowComplete: function() {
|
|
||||||
Tweener.addTween(this.actor,
|
|
||||||
{ opacity: 0,
|
|
||||||
time: FLASHSPOT_ANIMATION_TIME,
|
|
||||||
transition: 'linear',
|
|
||||||
onComplete: Lang.bind(this, function() {
|
|
||||||
this.destroy();
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -1,228 +0,0 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
|
||||||
const IBus = imports.gi.IBus;
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const St = imports.gi.St;
|
|
||||||
|
|
||||||
const BoxPointer = imports.ui.boxpointer;
|
|
||||||
const Main = imports.ui.main;
|
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
|
||||||
|
|
||||||
const MAX_CANDIDATES_PER_PAGE = 16;
|
|
||||||
|
|
||||||
const CandidateArea = new Lang.Class({
|
|
||||||
Name: 'CandidateArea',
|
|
||||||
Extends: PopupMenu.PopupBaseMenuItem,
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this.parent({ reactive: false });
|
|
||||||
|
|
||||||
// St.Table exhibits some sizing problems so let's go with a
|
|
||||||
// clutter layout manager for now.
|
|
||||||
this._table = new Clutter.Actor();
|
|
||||||
this.addActor(this._table);
|
|
||||||
|
|
||||||
this._tableLayout = new Clutter.TableLayout();
|
|
||||||
this._table.set_layout_manager(this._tableLayout);
|
|
||||||
|
|
||||||
this._indexLabels = [];
|
|
||||||
this._candidateLabels = [];
|
|
||||||
for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
|
|
||||||
this._indexLabels.push(new St.Label({ style_class: 'candidate-index' }));
|
|
||||||
this._candidateLabels.push(new St.Label({ style_class: 'candidate-label' }));
|
|
||||||
}
|
|
||||||
|
|
||||||
this._orientation = -1;
|
|
||||||
this._cursorPosition = 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
_setOrientation: function(orientation) {
|
|
||||||
if (this._orientation == orientation)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._orientation = orientation;
|
|
||||||
|
|
||||||
this._table.remove_all_children();
|
|
||||||
|
|
||||||
if (this._orientation == IBus.Orientation.HORIZONTAL)
|
|
||||||
for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
|
|
||||||
this._tableLayout.pack(this._indexLabels[i], i*2, 0);
|
|
||||||
this._tableLayout.pack(this._candidateLabels[i], i*2 + 1, 0);
|
|
||||||
}
|
|
||||||
else // VERTICAL || SYSTEM
|
|
||||||
for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
|
|
||||||
this._tableLayout.pack(this._indexLabels[i], 0, i);
|
|
||||||
this._tableLayout.pack(this._candidateLabels[i], 1, i);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setCandidates: function(indexes, candidates, orientation, cursorPosition, cursorVisible) {
|
|
||||||
this._setOrientation(orientation);
|
|
||||||
|
|
||||||
for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
|
|
||||||
let visible = i < candidates.length;
|
|
||||||
this._indexLabels[i].visible = visible;
|
|
||||||
this._candidateLabels[i].visible = visible;
|
|
||||||
|
|
||||||
if (!visible)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
this._indexLabels[i].text = ((indexes && indexes[i]) ? indexes[i] : '%x.'.format(i + 1));
|
|
||||||
this._candidateLabels[i].text = candidates[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
this._candidateLabels[this._cursorPosition].remove_style_pseudo_class('selected');
|
|
||||||
this._cursorPosition = cursorPosition;
|
|
||||||
if (cursorVisible)
|
|
||||||
this._candidateLabels[cursorPosition].add_style_pseudo_class('selected');
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const CandidatePopup = new Lang.Class({
|
|
||||||
Name: 'CandidatePopup',
|
|
||||||
Extends: PopupMenu.PopupMenu,
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this._cursor = new St.Bin({ opacity: 0 });
|
|
||||||
Main.uiGroup.add_actor(this._cursor);
|
|
||||||
|
|
||||||
this.parent(this._cursor, 0, St.Side.TOP);
|
|
||||||
this.actor.hide();
|
|
||||||
Main.uiGroup.add_actor(this.actor);
|
|
||||||
|
|
||||||
this._preeditTextItem = new PopupMenu.PopupMenuItem('', { reactive: false });
|
|
||||||
this._preeditTextItem.actor.hide();
|
|
||||||
this.addMenuItem(this._preeditTextItem);
|
|
||||||
|
|
||||||
this._auxTextItem = new PopupMenu.PopupMenuItem('', { reactive: false });
|
|
||||||
this._auxTextItem.actor.hide();
|
|
||||||
this.addMenuItem(this._auxTextItem);
|
|
||||||
|
|
||||||
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
||||||
|
|
||||||
this._lookupTableItem = new CandidateArea();
|
|
||||||
this._lookupTableItem.actor.hide();
|
|
||||||
this.addMenuItem(this._lookupTableItem);
|
|
||||||
|
|
||||||
this._panelService = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
setPanelService: function(panelService) {
|
|
||||||
this._panelService = panelService;
|
|
||||||
if (!panelService)
|
|
||||||
return;
|
|
||||||
|
|
||||||
panelService.connect('set-cursor-location',
|
|
||||||
Lang.bind(this, function(ps, x, y, w, h) {
|
|
||||||
this._cursor.set_position(x, y);
|
|
||||||
this._cursor.set_size(w, h);
|
|
||||||
}));
|
|
||||||
panelService.connect('update-preedit-text',
|
|
||||||
Lang.bind(this, function(ps, text, cursorPosition, visible) {
|
|
||||||
if (visible)
|
|
||||||
this._preeditTextItem.actor.show();
|
|
||||||
else
|
|
||||||
this._preeditTextItem.actor.hide();
|
|
||||||
this._updateVisibility();
|
|
||||||
|
|
||||||
this._preeditTextItem.actor.label_actor.text = text.get_text();
|
|
||||||
|
|
||||||
let attrs = text.get_attributes();
|
|
||||||
if (attrs)
|
|
||||||
this._setTextAttributes(this._preeditTextItem.actor.label_actor.clutter_text,
|
|
||||||
attrs);
|
|
||||||
}));
|
|
||||||
panelService.connect('show-preedit-text',
|
|
||||||
Lang.bind(this, function(ps) {
|
|
||||||
this._preeditTextItem.actor.show();
|
|
||||||
this._updateVisibility();
|
|
||||||
}));
|
|
||||||
panelService.connect('hide-preedit-text',
|
|
||||||
Lang.bind(this, function(ps) {
|
|
||||||
this._preeditTextItem.actor.hide();
|
|
||||||
this._updateVisibility();
|
|
||||||
}));
|
|
||||||
panelService.connect('update-auxiliary-text',
|
|
||||||
Lang.bind(this, function(ps, text, visible) {
|
|
||||||
if (visible)
|
|
||||||
this._auxTextItem.actor.show();
|
|
||||||
else
|
|
||||||
this._auxTextItem.actor.hide();
|
|
||||||
this._updateVisibility();
|
|
||||||
|
|
||||||
this._auxTextItem.actor.label_actor.text = text.get_text();
|
|
||||||
}));
|
|
||||||
panelService.connect('show-auxiliary-text',
|
|
||||||
Lang.bind(this, function(ps) {
|
|
||||||
this._auxTextItem.actor.show();
|
|
||||||
this._updateVisibility();
|
|
||||||
}));
|
|
||||||
panelService.connect('hide-auxiliary-text',
|
|
||||||
Lang.bind(this, function(ps) {
|
|
||||||
this._auxTextItem.actor.hide();
|
|
||||||
this._updateVisibility();
|
|
||||||
}));
|
|
||||||
panelService.connect('update-lookup-table',
|
|
||||||
Lang.bind(this, function(ps, lookupTable, visible) {
|
|
||||||
if (visible)
|
|
||||||
this._lookupTableItem.actor.show();
|
|
||||||
else
|
|
||||||
this._lookupTableItem.actor.hide();
|
|
||||||
this._updateVisibility();
|
|
||||||
|
|
||||||
let cursorPos = lookupTable.get_cursor_pos();
|
|
||||||
let pageSize = lookupTable.get_page_size();
|
|
||||||
let page = ((cursorPos == 0) ? 0 : Math.floor(cursorPos / pageSize));
|
|
||||||
let startIndex = page * pageSize;
|
|
||||||
let endIndex = Math.min((page + 1) * pageSize,
|
|
||||||
lookupTable.get_number_of_candidates());
|
|
||||||
let indexes = [];
|
|
||||||
let indexLabel;
|
|
||||||
for (let i = 0; indexLabel = lookupTable.get_label(i); ++i)
|
|
||||||
indexes.push(indexLabel.get_text());
|
|
||||||
|
|
||||||
let candidates = [];
|
|
||||||
for (let i = startIndex; i < endIndex; ++i)
|
|
||||||
candidates.push(lookupTable.get_candidate(i).get_text());
|
|
||||||
|
|
||||||
this._lookupTableItem.setCandidates(indexes,
|
|
||||||
candidates,
|
|
||||||
lookupTable.get_orientation(),
|
|
||||||
cursorPos % pageSize,
|
|
||||||
lookupTable.is_cursor_visible());
|
|
||||||
}));
|
|
||||||
panelService.connect('show-lookup-table',
|
|
||||||
Lang.bind(this, function(ps) {
|
|
||||||
this._lookupTableItem.actor.show();
|
|
||||||
this._updateVisibility();
|
|
||||||
}));
|
|
||||||
panelService.connect('hide-lookup-table',
|
|
||||||
Lang.bind(this, function(ps) {
|
|
||||||
this._lookupTableItem.actor.hide();
|
|
||||||
this._updateVisibility();
|
|
||||||
}));
|
|
||||||
panelService.connect('focus-out',
|
|
||||||
Lang.bind(this, function(ps) {
|
|
||||||
this.close(BoxPointer.PopupAnimation.NONE);
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateVisibility: function() {
|
|
||||||
let isVisible = (this._preeditTextItem.actor.visible ||
|
|
||||||
this._auxTextItem.actor.visible ||
|
|
||||||
this._lookupTableItem.actor.visible);
|
|
||||||
|
|
||||||
if (isVisible)
|
|
||||||
this.open(BoxPointer.PopupAnimation.NONE);
|
|
||||||
else
|
|
||||||
this.close(BoxPointer.PopupAnimation.NONE);
|
|
||||||
},
|
|
||||||
|
|
||||||
_setTextAttributes: function(clutterText, ibusAttrList) {
|
|
||||||
let attr;
|
|
||||||
for (let i = 0; attr = ibusAttrList.get(i); ++i)
|
|
||||||
if (attr.get_attr_type() == IBus.AttrType.BACKGROUND)
|
|
||||||
clutterText.set_selection(attr.get_start_index(), attr.get_end_index());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -10,9 +10,11 @@ const Params = imports.misc.params;
|
|||||||
const ICON_SIZE = 48;
|
const ICON_SIZE = 48;
|
||||||
|
|
||||||
|
|
||||||
const BaseIcon = new Lang.Class({
|
function BaseIcon(label, createIcon) {
|
||||||
Name: 'BaseIcon',
|
this._init(label, createIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseIcon.prototype = {
|
||||||
_init : function(label, params) {
|
_init : function(label, params) {
|
||||||
params = Params.parse(params, { createIcon: null,
|
params = Params.parse(params, { createIcon: null,
|
||||||
setSizeManually: false,
|
setSizeManually: false,
|
||||||
@@ -35,8 +37,7 @@ const BaseIcon = new Lang.Class({
|
|||||||
this.actor.set_child(box);
|
this.actor.set_child(box);
|
||||||
|
|
||||||
this.iconSize = ICON_SIZE;
|
this.iconSize = ICON_SIZE;
|
||||||
this._iconBin = new St.Bin({ x_align: St.Align.MIDDLE,
|
this._iconBin = new St.Bin();
|
||||||
y_align: St.Align.MIDDLE });
|
|
||||||
|
|
||||||
box.add_actor(this._iconBin);
|
box.add_actor(this._iconBin);
|
||||||
|
|
||||||
@@ -126,12 +127,12 @@ const BaseIcon = new Lang.Class({
|
|||||||
this.iconSize = size;
|
this.iconSize = size;
|
||||||
this.icon = this.createIcon(this.iconSize);
|
this.icon = this.createIcon(this.iconSize);
|
||||||
|
|
||||||
this._iconBin.child = this.icon;
|
|
||||||
|
|
||||||
// The icon returned by createIcon() might actually be smaller than
|
// The icon returned by createIcon() might actually be smaller than
|
||||||
// the requested icon size (for instance StTextureCache does this
|
// the requested icon size (for instance StTextureCache does this
|
||||||
// for fallback icons), so set the size explicitly.
|
// for fallback icons), so set the size explicitly.
|
||||||
this._iconBin.set_size(this.iconSize, this.iconSize);
|
this.icon.set_size(this.iconSize, this.iconSize);
|
||||||
|
|
||||||
|
this._iconBin.child = this.icon;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onStyleChanged: function() {
|
_onStyleChanged: function() {
|
||||||
@@ -148,11 +149,13 @@ const BaseIcon = new Lang.Class({
|
|||||||
|
|
||||||
this._createIconTexture(size);
|
this._createIconTexture(size);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const IconGrid = new Lang.Class({
|
function IconGrid(params) {
|
||||||
Name: 'IconGrid',
|
this._init(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
IconGrid.prototype = {
|
||||||
_init: function(params) {
|
_init: function(params) {
|
||||||
params = Params.parse(params, { rowLimit: null,
|
params = Params.parse(params, { rowLimit: null,
|
||||||
columnLimit: null,
|
columnLimit: null,
|
||||||
@@ -165,7 +168,7 @@ const IconGrid = new Lang.Class({
|
|||||||
vertical: true });
|
vertical: true });
|
||||||
// Pulled from CSS, but hardcode some defaults here
|
// Pulled from CSS, but hardcode some defaults here
|
||||||
this._spacing = 0;
|
this._spacing = 0;
|
||||||
this._hItemSize = this._vItemSize = ICON_SIZE;
|
this._item_size = ICON_SIZE;
|
||||||
this._grid = new Shell.GenericContainer();
|
this._grid = new Shell.GenericContainer();
|
||||||
this.actor.add(this._grid, { expand: true, y_align: St.Align.START });
|
this.actor.add(this._grid, { expand: true, y_align: St.Align.START });
|
||||||
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
|
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
|
||||||
@@ -184,8 +187,8 @@ const IconGrid = new Lang.Class({
|
|||||||
// Kind of a lie, but not really an issue right now. If
|
// Kind of a lie, but not really an issue right now. If
|
||||||
// we wanted to support some sort of hidden/overflow that would
|
// we wanted to support some sort of hidden/overflow that would
|
||||||
// need higher level design
|
// need higher level design
|
||||||
alloc.min_size = this._hItemSize;
|
alloc.min_size = this._item_size;
|
||||||
alloc.natural_size = nColumns * this._hItemSize + totalSpacing;
|
alloc.natural_size = nColumns * this._item_size + totalSpacing;
|
||||||
},
|
},
|
||||||
|
|
||||||
_getVisibleChildren: function() {
|
_getVisibleChildren: function() {
|
||||||
@@ -207,7 +210,7 @@ const IconGrid = new Lang.Class({
|
|||||||
if (this._rowLimit)
|
if (this._rowLimit)
|
||||||
nRows = Math.min(nRows, this._rowLimit);
|
nRows = Math.min(nRows, this._rowLimit);
|
||||||
let totalSpacing = Math.max(0, nRows - 1) * this._spacing;
|
let totalSpacing = Math.max(0, nRows - 1) * this._spacing;
|
||||||
let height = nRows * this._vItemSize + totalSpacing;
|
let height = nRows * this._item_size + totalSpacing;
|
||||||
alloc.min_size = height;
|
alloc.min_size = height;
|
||||||
alloc.natural_size = height;
|
alloc.natural_size = height;
|
||||||
},
|
},
|
||||||
@@ -240,13 +243,13 @@ const IconGrid = new Lang.Class({
|
|||||||
= children[i].get_preferred_size();
|
= children[i].get_preferred_size();
|
||||||
|
|
||||||
/* Center the item in its allocation horizontally */
|
/* Center the item in its allocation horizontally */
|
||||||
let width = Math.min(this._hItemSize, childNaturalWidth);
|
let width = Math.min(this._item_size, childNaturalWidth);
|
||||||
let childXSpacing = Math.max(0, width - childNaturalWidth) / 2;
|
let childXSpacing = Math.max(0, width - childNaturalWidth) / 2;
|
||||||
let height = Math.min(this._vItemSize, childNaturalHeight);
|
let height = Math.min(this._item_size, childNaturalHeight);
|
||||||
let childYSpacing = Math.max(0, height - childNaturalHeight) / 2;
|
let childYSpacing = Math.max(0, height - childNaturalHeight) / 2;
|
||||||
|
|
||||||
let childBox = new Clutter.ActorBox();
|
let childBox = new Clutter.ActorBox();
|
||||||
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
|
if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
|
||||||
let _x = box.x2 - (x + width);
|
let _x = box.x2 - (x + width);
|
||||||
childBox.x1 = Math.floor(_x - childXSpacing);
|
childBox.x1 = Math.floor(_x - childXSpacing);
|
||||||
} else {
|
} else {
|
||||||
@@ -270,10 +273,10 @@ const IconGrid = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (columnIndex == 0) {
|
if (columnIndex == 0) {
|
||||||
y += this._vItemSize + this._spacing;
|
y += this._item_size + this._spacing;
|
||||||
x = box.x1 + leftPadding;
|
x = box.x1 + leftPadding;
|
||||||
} else {
|
} else {
|
||||||
x += this._hItemSize + this._spacing;
|
x += this._item_size + this._spacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -282,16 +285,12 @@ const IconGrid = new Lang.Class({
|
|||||||
return this._computeLayout(rowWidth)[0];
|
return this._computeLayout(rowWidth)[0];
|
||||||
},
|
},
|
||||||
|
|
||||||
getRowLimit: function() {
|
|
||||||
return this._rowLimit;
|
|
||||||
},
|
|
||||||
|
|
||||||
_computeLayout: function (forWidth) {
|
_computeLayout: function (forWidth) {
|
||||||
let nColumns = 0;
|
let nColumns = 0;
|
||||||
let usedWidth = 0;
|
let usedWidth = 0;
|
||||||
while ((this._colLimit == null || nColumns < this._colLimit) &&
|
while ((this._colLimit == null || nColumns < this._colLimit) &&
|
||||||
(usedWidth + this._hItemSize <= forWidth)) {
|
(usedWidth + this._item_size <= forWidth)) {
|
||||||
usedWidth += this._hItemSize + this._spacing;
|
usedWidth += this._item_size + this._spacing;
|
||||||
nColumns += 1;
|
nColumns += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,27 +303,25 @@ const IconGrid = new Lang.Class({
|
|||||||
_onStyleChanged: function() {
|
_onStyleChanged: function() {
|
||||||
let themeNode = this.actor.get_theme_node();
|
let themeNode = this.actor.get_theme_node();
|
||||||
this._spacing = themeNode.get_length('spacing');
|
this._spacing = themeNode.get_length('spacing');
|
||||||
this._hItemSize = themeNode.get_length('-shell-grid-horizontal-item-size') || ICON_SIZE;
|
this._item_size = themeNode.get_length('-shell-grid-item-size');
|
||||||
this._vItemSize = themeNode.get_length('-shell-grid-vertical-item-size') || ICON_SIZE;
|
|
||||||
this._grid.queue_relayout();
|
this._grid.queue_relayout();
|
||||||
},
|
},
|
||||||
|
|
||||||
removeAll: function() {
|
removeAll: function () {
|
||||||
this._grid.destroy_all_children();
|
this._grid.get_children().forEach(Lang.bind(this, function (child) {
|
||||||
|
child.destroy();
|
||||||
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
addItem: function(actor, index) {
|
addItem: function(actor) {
|
||||||
if (index !== undefined)
|
|
||||||
this._grid.insert_child_at_index(actor, index);
|
|
||||||
else
|
|
||||||
this._grid.add_actor(actor);
|
this._grid.add_actor(actor);
|
||||||
},
|
},
|
||||||
|
|
||||||
getItemAtIndex: function(index) {
|
getItemAtIndex: function(index) {
|
||||||
return this._grid.get_child_at_index(index);
|
return this._grid.get_children()[index];
|
||||||
},
|
},
|
||||||
|
|
||||||
visibleItemsCount: function() {
|
visibleItemsCount: function() {
|
||||||
return this._grid.get_n_children() - this._grid.get_n_skip_paint();
|
return this._grid.get_children().length - this._grid.get_n_skip_paint();
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|||||||
@@ -39,31 +39,34 @@ const PRETTY_KEYS = {
|
|||||||
'Alt_L': 'Alt'
|
'Alt_L': 'Alt'
|
||||||
};
|
};
|
||||||
|
|
||||||
const CaribouKeyboardIface = <interface name='org.gnome.Caribou.Keyboard'>
|
const CaribouKeyboardIface = {
|
||||||
<method name='Show'>
|
name: 'org.gnome.Caribou.Keyboard',
|
||||||
<arg type='u' direction='in' />
|
methods: [ { name: 'Show',
|
||||||
</method>
|
inSignature: 'u',
|
||||||
<method name='Hide'>
|
outSignature: ''
|
||||||
<arg type='u' direction='in' />
|
},
|
||||||
</method>
|
{ name: 'Hide',
|
||||||
<method name='SetCursorLocation'>
|
inSignature: 'u',
|
||||||
<arg type='i' direction='in' />
|
outSignature: ''
|
||||||
<arg type='i' direction='in' />
|
},
|
||||||
<arg type='i' direction='in' />
|
{ name: 'SetCursorLocation',
|
||||||
<arg type='i' direction='in' />
|
inSignature: 'iiii',
|
||||||
</method>
|
outSignature: ''
|
||||||
<method name='SetEntryLocation'>
|
},
|
||||||
<arg type='i' direction='in' />
|
{ name: 'SetEntryLocation',
|
||||||
<arg type='i' direction='in' />
|
inSignature: 'iiii',
|
||||||
<arg type='i' direction='in' />
|
outSignature: ''
|
||||||
<arg type='i' direction='in' />
|
} ],
|
||||||
</method>
|
properties: [ { name: 'Name',
|
||||||
<property name='Name' access='read' type='s' />
|
signature: 's',
|
||||||
</interface>;
|
access: 'read' } ]
|
||||||
|
};
|
||||||
|
|
||||||
const Key = new Lang.Class({
|
function Key() {
|
||||||
Name: 'Key',
|
this._init.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Key.prototype = {
|
||||||
_init : function(key) {
|
_init : function(key) {
|
||||||
this._key = key;
|
this._key = key;
|
||||||
|
|
||||||
@@ -93,7 +96,7 @@ const Key = new Lang.Class({
|
|||||||
this._getExtendedKeys();
|
this._getExtendedKeys();
|
||||||
this.actor._extended_keys = this._extended_keyboard;
|
this.actor._extended_keys = this._extended_keyboard;
|
||||||
this._boxPointer.actor.hide();
|
this._boxPointer.actor.hide();
|
||||||
Main.layoutManager.addChrome(this._boxPointer.actor);
|
Main.layoutManager.addChrome(this._boxPointer.actor, { visibleInFullscreen: true });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -175,7 +178,7 @@ const Key = new Lang.Class({
|
|||||||
this.actor.fake_release();
|
this.actor.fake_release();
|
||||||
this._boxPointer.actor.raise_top();
|
this._boxPointer.actor.raise_top();
|
||||||
this._boxPointer.setPosition(this.actor, 0.5);
|
this._boxPointer.setPosition(this.actor, 0.5);
|
||||||
this._boxPointer.show(BoxPointer.PopupAnimation.FULL);
|
this._boxPointer.show(true);
|
||||||
this.actor.set_hover(false);
|
this.actor.set_hover(false);
|
||||||
if (!this._grabbed) {
|
if (!this._grabbed) {
|
||||||
Main.pushModal(this.actor);
|
Main.pushModal(this.actor);
|
||||||
@@ -186,18 +189,18 @@ const Key = new Lang.Class({
|
|||||||
} else {
|
} else {
|
||||||
if (this._grabbed)
|
if (this._grabbed)
|
||||||
this._ungrab();
|
this._ungrab();
|
||||||
this._boxPointer.hide(BoxPointer.PopupAnimation.FULL);
|
this._boxPointer.hide(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const Keyboard = new Lang.Class({
|
function Keyboard() {
|
||||||
// HACK: we can't set Name, because it collides with Name dbus property
|
this._init.apply(this, arguments);
|
||||||
// Name: 'Keyboard',
|
}
|
||||||
|
|
||||||
|
Keyboard.prototype = {
|
||||||
_init: function () {
|
_init: function () {
|
||||||
this._impl = Gio.DBusExportedObject.wrapJSObject(CaribouKeyboardIface, this);
|
DBus.session.exportObject('/org/gnome/Caribou/Keyboard', this);
|
||||||
this._impl.export(Gio.DBus.session, '/org/gnome/Caribou/Keyboard');
|
|
||||||
|
|
||||||
this.actor = null;
|
this.actor = null;
|
||||||
|
|
||||||
@@ -269,11 +272,6 @@ const Keyboard = new Lang.Class({
|
|||||||
|
|
||||||
this._addKeys();
|
this._addKeys();
|
||||||
|
|
||||||
// Keys should be layout according to the group, not the
|
|
||||||
// locale; as Caribou already provides the expected layout,
|
|
||||||
// this means enforcing LTR for all locales.
|
|
||||||
this.actor.text_direction = Clutter.TextDirection.LTR;
|
|
||||||
|
|
||||||
this._keyboardNotifyId = this._keyboard.connect('notify::active-group', Lang.bind(this, this._onGroupChanged));
|
this._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._focusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
|
||||||
|
|
||||||
@@ -534,15 +532,27 @@ const Keyboard = new Lang.Class({
|
|||||||
get Name() {
|
get Name() {
|
||||||
return 'gnome-shell';
|
return 'gnome-shell';
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
DBus.conformExport(Keyboard.prototype, CaribouKeyboardIface);
|
||||||
|
|
||||||
const KeyboardSource = new Lang.Class({
|
function KeyboardSource() {
|
||||||
Name: 'KeyboardSource',
|
this._init.apply(this, arguments);
|
||||||
Extends: MessageTray.Source,
|
}
|
||||||
|
|
||||||
|
KeyboardSource.prototype = {
|
||||||
|
__proto__: MessageTray.Source.prototype,
|
||||||
|
|
||||||
_init: function(keyboard) {
|
_init: function(keyboard) {
|
||||||
this._keyboard = keyboard;
|
this._keyboard = keyboard;
|
||||||
this.parent(_("Keyboard"), 'input-keyboard', St.IconType.SYMBOLIC);
|
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() {
|
handleSummaryClick: function() {
|
||||||
@@ -557,4 +567,4 @@ const KeyboardSource = new Lang.Class({
|
|||||||
open: function() {
|
open: function() {
|
||||||
this._keyboard.show();
|
this._keyboard.show();
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|||||||
@@ -1,208 +0,0 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const Shell = imports.gi.Shell;
|
|
||||||
const Clutter = imports.gi.Clutter;
|
|
||||||
const St = imports.gi.St;
|
|
||||||
const Pango = imports.gi.Pango;
|
|
||||||
const Gio = imports.gi.Gio;
|
|
||||||
const GObject = imports.gi.GObject;
|
|
||||||
const Gcr = imports.gi.Gcr;
|
|
||||||
|
|
||||||
const ModalDialog = imports.ui.modalDialog;
|
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
|
||||||
const CheckBox = imports.ui.checkBox;
|
|
||||||
|
|
||||||
let prompter = null;
|
|
||||||
|
|
||||||
const KeyringDialog = new Lang.Class({
|
|
||||||
Name: 'KeyringDialog',
|
|
||||||
Extends: ModalDialog.ModalDialog,
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this.parent({ styleClass: 'prompt-dialog' });
|
|
||||||
|
|
||||||
this.prompt = new Shell.KeyringPrompt();
|
|
||||||
this.prompt.connect('show-password', Lang.bind(this, this._onShowPassword));
|
|
||||||
this.prompt.connect('show-confirm', Lang.bind(this, this._onShowConfirm));
|
|
||||||
this.prompt.connect('hide-prompt', Lang.bind(this, this._onHidePrompt));
|
|
||||||
|
|
||||||
let mainContentBox = new St.BoxLayout({ style_class: 'prompt-dialog-main-layout',
|
|
||||||
vertical: false });
|
|
||||||
this.contentLayout.add(mainContentBox);
|
|
||||||
|
|
||||||
let icon = new St.Icon({ icon_name: 'dialog-password-symbolic' });
|
|
||||||
mainContentBox.add(icon,
|
|
||||||
{ x_fill: true,
|
|
||||||
y_fill: false,
|
|
||||||
x_align: St.Align.END,
|
|
||||||
y_align: St.Align.START });
|
|
||||||
|
|
||||||
this._messageBox = new St.BoxLayout({ style_class: 'prompt-dialog-message-layout',
|
|
||||||
vertical: true });
|
|
||||||
mainContentBox.add(this._messageBox,
|
|
||||||
{ y_align: St.Align.START, expand: true, x_fill: true, y_fill: true });
|
|
||||||
|
|
||||||
let subject = new St.Label({ style_class: 'prompt-dialog-headline' });
|
|
||||||
this.prompt.bind_property('message', subject, 'text', GObject.BindingFlags.SYNC_CREATE);
|
|
||||||
|
|
||||||
this._messageBox.add(subject,
|
|
||||||
{ y_fill: false,
|
|
||||||
y_align: St.Align.START });
|
|
||||||
|
|
||||||
let description = new St.Label({ style_class: 'prompt-dialog-description' });
|
|
||||||
description.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
|
||||||
description.clutter_text.line_wrap = true;
|
|
||||||
this.prompt.bind_property('description', description, 'text', GObject.BindingFlags.SYNC_CREATE);
|
|
||||||
this._messageBox.add(description,
|
|
||||||
{ y_fill: true,
|
|
||||||
y_align: St.Align.START });
|
|
||||||
|
|
||||||
this._controlTable = null;
|
|
||||||
|
|
||||||
let buttons = [{ label: '',
|
|
||||||
action: Lang.bind(this, this._onCancelButton),
|
|
||||||
key: Clutter.Escape
|
|
||||||
},
|
|
||||||
{ label: '',
|
|
||||||
action: Lang.bind(this, this._onContinueButton),
|
|
||||||
default: true
|
|
||||||
}]
|
|
||||||
|
|
||||||
this.setButtons(buttons);
|
|
||||||
this._cancelButton = buttons[0].button;
|
|
||||||
this._continueButton = buttons[1].button;
|
|
||||||
|
|
||||||
this.prompt.bind_property('cancel-label', this._cancelButton, 'label', GObject.BindingFlags.SYNC_CREATE);
|
|
||||||
this.prompt.bind_property('continue-label', this._continueButton, 'label', GObject.BindingFlags.SYNC_CREATE);
|
|
||||||
},
|
|
||||||
|
|
||||||
_buildControlTable: function() {
|
|
||||||
let table = new St.Table({ style_class: 'keyring-dialog-control-table' });
|
|
||||||
let row = 0;
|
|
||||||
|
|
||||||
if (this.prompt.password_visible) {
|
|
||||||
let label = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
|
|
||||||
label.set_text(_("Password:"));
|
|
||||||
table.add(label, { row: row, col: 0, x_expand: false, x_fill: true, x_align: St.Align.START });
|
|
||||||
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
|
||||||
text: '',
|
|
||||||
can_focus: true});
|
|
||||||
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
|
||||||
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
|
|
||||||
this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onPasswordActivate));
|
|
||||||
table.add(this._passwordEntry, { row: row, col: 1, x_expand: true, x_fill: true, x_align: St.Align.START });
|
|
||||||
row++;
|
|
||||||
} else {
|
|
||||||
this._passwordEntry = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.prompt.confirm_visible) {
|
|
||||||
var label = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
|
|
||||||
label.set_text(_("Type again:"));
|
|
||||||
table.add(label, { row: row, col: 0, x_expand: false, x_fill: true, x_align: St.Align.START });
|
|
||||||
this._confirmEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
|
||||||
text: '',
|
|
||||||
can_focus: true});
|
|
||||||
this._confirmEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
|
||||||
ShellEntry.addContextMenu(this._confirmEntry, { isPassword: true });
|
|
||||||
this._confirmEntry.clutter_text.connect('activate', Lang.bind(this, this._onConfirmActivate));
|
|
||||||
table.add(this._confirmEntry, { row: row, col: 1, x_expand: true, x_fill: true, x_align: St.Align.START });
|
|
||||||
row++;
|
|
||||||
} else {
|
|
||||||
this._confirmEntry = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.prompt.set_password_actor(this._passwordEntry ? this._passwordEntry.clutter_text : null);
|
|
||||||
this.prompt.set_confirm_actor(this._confirmEntry ? this._confirmEntry.clutter_text : null);
|
|
||||||
|
|
||||||
if (this.prompt.choice_visible) {
|
|
||||||
let choice = new CheckBox.CheckBox();
|
|
||||||
this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE);
|
|
||||||
this.prompt.bind_property('choice-chosen', choice.actor, 'checked', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL);
|
|
||||||
table.add(choice.actor, { row: row, col: 1, x_expand: false, x_fill: true, x_align: St.Align.START });
|
|
||||||
row++;
|
|
||||||
}
|
|
||||||
|
|
||||||
let warning = new St.Label({ style_class: 'prompt-dialog-error-label' });
|
|
||||||
warning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
|
||||||
warning.clutter_text.line_wrap = true;
|
|
||||||
table.add(warning, { row: row, col: 1, x_expand: false, x_fill: false, x_align: St.Align.START });
|
|
||||||
this.prompt.bind_property('warning-visible', warning, 'visible', GObject.BindingFlags.SYNC_CREATE);
|
|
||||||
this.prompt.bind_property('warning', warning, 'text', GObject.BindingFlags.SYNC_CREATE);
|
|
||||||
|
|
||||||
if (this._controlTable) {
|
|
||||||
this._controlTable.destroy_all_children();
|
|
||||||
this._controlTable.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
this._controlTable = table;
|
|
||||||
this._messageBox.add(table, { x_fill: true, y_fill: true });
|
|
||||||
},
|
|
||||||
|
|
||||||
_ensureOpen: function() {
|
|
||||||
// NOTE: ModalDialog.open() is safe to call if the dialog is
|
|
||||||
// already open - it just returns true without side-effects
|
|
||||||
if (this.open())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// The above fail if e.g. unable to get input grab
|
|
||||||
//
|
|
||||||
// In an ideal world this wouldn't happen (because the
|
|
||||||
// Shell is in complete control of the session) but that's
|
|
||||||
// just not how things work right now.
|
|
||||||
|
|
||||||
log('keyringPrompt: Failed to show modal dialog.' +
|
|
||||||
' Dismissing prompt request');
|
|
||||||
this.prompt.cancel()
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
_onShowPassword: function(prompt) {
|
|
||||||
this._buildControlTable();
|
|
||||||
this._ensureOpen();
|
|
||||||
this._passwordEntry.grab_key_focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
_onShowConfirm: function(prompt) {
|
|
||||||
this._buildControlTable();
|
|
||||||
this._ensureOpen();
|
|
||||||
this._continueButton.grab_key_focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
_onHidePrompt: function(prompt) {
|
|
||||||
this.close();
|
|
||||||
},
|
|
||||||
|
|
||||||
_onPasswordActivate: function() {
|
|
||||||
if (this.prompt.confirm_visible)
|
|
||||||
this._confirmEntry.grab_key_focus();
|
|
||||||
else
|
|
||||||
this._onContinueButton();
|
|
||||||
},
|
|
||||||
|
|
||||||
_onConfirmActivate: function() {
|
|
||||||
this._onContinueButton();
|
|
||||||
},
|
|
||||||
|
|
||||||
_onContinueButton: function() {
|
|
||||||
this.prompt.complete()
|
|
||||||
},
|
|
||||||
|
|
||||||
_onCancelButton: function() {
|
|
||||||
this.prompt.cancel()
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function init() {
|
|
||||||
prompter = new Gcr.SystemPrompter();
|
|
||||||
prompter.connect('new-prompt', function(prompter) {
|
|
||||||
let dialog = new KeyringDialog();
|
|
||||||
return dialog.prompt;
|
|
||||||
});
|
|
||||||
|
|
||||||
let connection = Gio.DBus.session;
|
|
||||||
prompter.register(connection);
|
|
||||||
Gio.bus_own_name_on_connection (connection, 'org.gnome.keyring.SystemPrompter',
|
|
||||||
Gio.BusNameOwnerFlags.REPLACE, null, null);
|
|
||||||
}
|
|
||||||
144
js/ui/layout.js
@@ -8,20 +8,22 @@ const Shell = imports.gi.Shell;
|
|||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
const DND = imports.ui.dnd;
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
|
const ScreenSaver = imports.misc.screenSaver;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
|
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
|
||||||
const STARTUP_ANIMATION_TIME = 0.2;
|
const STARTUP_ANIMATION_TIME = 0.2;
|
||||||
const KEYBOARD_ANIMATION_TIME = 0.5;
|
const KEYBOARD_ANIMATION_TIME = 0.5;
|
||||||
|
|
||||||
const LayoutManager = new Lang.Class({
|
function LayoutManager() {
|
||||||
Name: 'LayoutManager',
|
this._init.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutManager.prototype = {
|
||||||
_init: function () {
|
_init: function () {
|
||||||
this._rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL);
|
this._rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL);
|
||||||
this.monitors = [];
|
this.monitors = [];
|
||||||
this.primaryMonitor = null;
|
this.primaryMonitor = null;
|
||||||
this.primaryIndex = -1;
|
this.primaryIndex = -1;
|
||||||
@@ -32,37 +34,26 @@ const LayoutManager = new Lang.Class({
|
|||||||
|
|
||||||
this._chrome = new Chrome(this);
|
this._chrome = new Chrome(this);
|
||||||
|
|
||||||
this.screenShieldGroup = new St.Widget({ name: 'screenShieldGroup',
|
|
||||||
visible: false,
|
|
||||||
clip_to_allocation: true,
|
|
||||||
});
|
|
||||||
this.addChrome(this.screenShieldGroup);
|
|
||||||
|
|
||||||
this.panelBox = new St.BoxLayout({ name: 'panelBox',
|
this.panelBox = new St.BoxLayout({ name: 'panelBox',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
this.addChrome(this.panelBox, { affectsStruts: true,
|
this.addChrome(this.panelBox, { affectsStruts: true });
|
||||||
trackFullscreen: true });
|
|
||||||
this.panelBox.connect('allocation-changed',
|
this.panelBox.connect('allocation-changed',
|
||||||
Lang.bind(this, this._updatePanelBarriers));
|
Lang.bind(this, this._updatePanelBarriers));
|
||||||
|
|
||||||
this.trayBox = new St.BoxLayout({ name: 'trayBox' });
|
this.trayBox = new St.BoxLayout({ name: 'trayBox' });
|
||||||
this.addChrome(this.trayBox);
|
this.addChrome(this.trayBox, { visibleInFullscreen: true });
|
||||||
this.trayBox.connect('allocation-changed',
|
this.trayBox.connect('allocation-changed',
|
||||||
Lang.bind(this, this._updateTrayBarrier));
|
Lang.bind(this, this._updateTrayBarrier));
|
||||||
|
|
||||||
this.keyboardBox = new St.BoxLayout({ name: 'keyboardBox',
|
this.keyboardBox = new St.BoxLayout({ name: 'keyboardBox',
|
||||||
reactive: true,
|
reactive: true,
|
||||||
track_hover: true });
|
track_hover: true });
|
||||||
this.addChrome(this.keyboardBox);
|
this.addChrome(this.keyboardBox, { visibleInFullscreen: true });
|
||||||
this._keyboardHeightNotifyId = 0;
|
this._keyboardHeightNotifyId = 0;
|
||||||
|
|
||||||
global.screen.connect('monitors-changed',
|
global.screen.connect('monitors-changed',
|
||||||
Lang.bind(this, this._monitorsChanged));
|
Lang.bind(this, this._monitorsChanged));
|
||||||
this._monitorsChanged();
|
this._monitorsChanged();
|
||||||
|
|
||||||
this._chrome.connect('primary-fullscreen-changed', Lang.bind(this, function(chrome, state) {
|
|
||||||
this.emit('primary-fullscreen-changed', state);
|
|
||||||
}));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// This is called by Main after everything else is constructed;
|
// This is called by Main after everything else is constructed;
|
||||||
@@ -155,9 +146,6 @@ const LayoutManager = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_updateBoxes: function() {
|
_updateBoxes: function() {
|
||||||
this.screenShieldGroup.set_position(0, 0);
|
|
||||||
this.screenShieldGroup.set_size(global.screen_width, global.screen_height);
|
|
||||||
|
|
||||||
this.panelBox.set_position(this.primaryMonitor.x, this.primaryMonitor.y);
|
this.panelBox.set_position(this.primaryMonitor.x, this.primaryMonitor.y);
|
||||||
this.panelBox.set_size(this.primaryMonitor.width, -1);
|
this.panelBox.set_size(this.primaryMonitor.width, -1);
|
||||||
|
|
||||||
@@ -237,9 +225,26 @@ const LayoutManager = new Lang.Class({
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
get currentMonitor() {
|
get focusIndex() {
|
||||||
let index = global.screen.get_current_monitor();
|
let focusWindow = global.display.focus_window;
|
||||||
return Main.layoutManager.monitors[index];
|
|
||||||
|
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() {
|
_startupAnimation: function() {
|
||||||
@@ -327,10 +332,8 @@ const LayoutManager = new Lang.Class({
|
|||||||
// the window manager struts. Changes to @actor's visibility will
|
// the window manager struts. Changes to @actor's visibility will
|
||||||
// NOT affect whether or not the strut is present, however.
|
// NOT affect whether or not the strut is present, however.
|
||||||
//
|
//
|
||||||
// If %trackFullscreen in @params is %true, the actor's visibility
|
// If %visibleInFullscreen in @params is %true, the actor will be
|
||||||
// will be bound to the presence of fullscreen windows on the same
|
// visible even when a fullscreen window should be covering it.
|
||||||
// monitor (it will be hidden whenever a fullscreen window is visible,
|
|
||||||
// and shown otherwise)
|
|
||||||
addChrome: function(actor, params) {
|
addChrome: function(actor, params) {
|
||||||
this._chrome.addActor(actor, params);
|
this._chrome.addActor(actor, params);
|
||||||
},
|
},
|
||||||
@@ -344,8 +347,10 @@ const LayoutManager = new Lang.Class({
|
|||||||
// struts or input region to cover specific children.
|
// struts or input region to cover specific children.
|
||||||
//
|
//
|
||||||
// @params can have any of the same values as in addChrome(),
|
// @params can have any of the same values as in addChrome(),
|
||||||
// though some possibilities don't make sense. By default, @actor has
|
// though some possibilities don't make sense (eg, trying to have
|
||||||
// the same params as its chrome ancestor.
|
// a %visibleInFullscreen child of a non-%visibleInFullscreen
|
||||||
|
// parent). By default, @actor has the same params as its chrome
|
||||||
|
// ancestor.
|
||||||
trackChrome: function(actor, params) {
|
trackChrome: function(actor, params) {
|
||||||
this._chrome.trackActor(actor, params);
|
this._chrome.trackActor(actor, params);
|
||||||
},
|
},
|
||||||
@@ -369,7 +374,7 @@ const LayoutManager = new Lang.Class({
|
|||||||
findMonitorForActor: function(actor) {
|
findMonitorForActor: function(actor) {
|
||||||
return this._chrome.findMonitorForActor(actor);
|
return this._chrome.findMonitorForActor(actor);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(LayoutManager.prototype);
|
Signals.addSignalMethods(LayoutManager.prototype);
|
||||||
|
|
||||||
|
|
||||||
@@ -377,9 +382,11 @@ Signals.addSignalMethods(LayoutManager.prototype);
|
|||||||
//
|
//
|
||||||
// This class manages a "hot corner" that can toggle switching to
|
// This class manages a "hot corner" that can toggle switching to
|
||||||
// overview.
|
// overview.
|
||||||
const HotCorner = new Lang.Class({
|
function HotCorner() {
|
||||||
Name: 'HotCorner',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
HotCorner.prototype = {
|
||||||
_init : function() {
|
_init : function() {
|
||||||
// We use this flag to mark the case where the user has entered the
|
// 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
|
// hot corner and has not left both the hot corner and a surrounding
|
||||||
@@ -401,7 +408,7 @@ const HotCorner = new Lang.Class({
|
|||||||
|
|
||||||
this.actor.add_actor(this._corner);
|
this.actor.add_actor(this._corner);
|
||||||
|
|
||||||
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
|
if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
|
||||||
this._corner.set_position(this.actor.width - this._corner.width, 0);
|
this._corner.set_position(this.actor.width - this._corner.width, 0);
|
||||||
this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
||||||
} else {
|
} else {
|
||||||
@@ -430,9 +437,9 @@ const HotCorner = new Lang.Class({
|
|||||||
Lang.bind(this, this._onCornerLeft));
|
Lang.bind(this, this._onCornerLeft));
|
||||||
|
|
||||||
// Cache the three ripples instead of dynamically creating and destroying them.
|
// Cache the three ripples instead of dynamically creating and destroying them.
|
||||||
this._ripple1 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
|
this._ripple1 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0 });
|
||||||
this._ripple2 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
|
this._ripple2 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0 });
|
||||||
this._ripple3 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
|
this._ripple3 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0 });
|
||||||
|
|
||||||
Main.uiGroup.add_actor(this._ripple1);
|
Main.uiGroup.add_actor(this._ripple1);
|
||||||
Main.uiGroup.add_actor(this._ripple2);
|
Main.uiGroup.add_actor(this._ripple2);
|
||||||
@@ -453,7 +460,7 @@ const HotCorner = new Lang.Class({
|
|||||||
|
|
||||||
ripple._opacity = startOpacity;
|
ripple._opacity = startOpacity;
|
||||||
|
|
||||||
if (ripple.get_text_direction() == Clutter.TextDirection.RTL)
|
if (ripple.get_direction() == St.TextDirection.RTL)
|
||||||
ripple.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
ripple.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
||||||
|
|
||||||
ripple.visible = true;
|
ripple.visible = true;
|
||||||
@@ -487,15 +494,13 @@ const HotCorner = new Lang.Class({
|
|||||||
|
|
||||||
handleDragOver: function(source, actor, x, y, time) {
|
handleDragOver: function(source, actor, x, y, time) {
|
||||||
if (source != Main.xdndHandler)
|
if (source != Main.xdndHandler)
|
||||||
return DND.DragMotionResult.CONTINUE;
|
return;
|
||||||
|
|
||||||
if (!Main.overview.visible && !Main.overview.animationInProgress) {
|
if (!Main.overview.visible && !Main.overview.animationInProgress) {
|
||||||
this.rippleAnimation();
|
this.rippleAnimation();
|
||||||
Main.overview.showTemporarily();
|
Main.overview.showTemporarily();
|
||||||
Main.overview.beginItemDrag(actor);
|
Main.overview.beginItemDrag(actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return DND.DragMotionResult.CONTINUE;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onCornerEntered : function() {
|
_onCornerEntered : function() {
|
||||||
@@ -543,7 +548,7 @@ const HotCorner = new Lang.Class({
|
|||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
|
||||||
// This manages the shell "chrome"; the UI that's visible in the
|
// This manages the shell "chrome"; the UI that's visible in the
|
||||||
@@ -551,20 +556,21 @@ const HotCorner = new Lang.Class({
|
|||||||
// workspace content.
|
// workspace content.
|
||||||
|
|
||||||
const defaultParams = {
|
const defaultParams = {
|
||||||
trackFullscreen: false,
|
visibleInFullscreen: false,
|
||||||
affectsStruts: false,
|
affectsStruts: false,
|
||||||
affectsInputRegion: true
|
affectsInputRegion: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const Chrome = new Lang.Class({
|
function Chrome() {
|
||||||
Name: 'Chrome',
|
this._init.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Chrome.prototype = {
|
||||||
_init: function(layoutManager) {
|
_init: function(layoutManager) {
|
||||||
this._layoutManager = layoutManager;
|
this._layoutManager = layoutManager;
|
||||||
|
|
||||||
this._monitors = [];
|
this._monitors = [];
|
||||||
this._inOverview = false;
|
this._inOverview = false;
|
||||||
this._isLocked = false;
|
|
||||||
this._updateRegionIdle = 0;
|
this._updateRegionIdle = 0;
|
||||||
this._freezeUpdateCount = 0;
|
this._freezeUpdateCount = 0;
|
||||||
|
|
||||||
@@ -579,6 +585,16 @@ const Chrome = new Lang.Class({
|
|||||||
global.screen.connect('notify::n-workspaces',
|
global.screen.connect('notify::n-workspaces',
|
||||||
Lang.bind(this, this._queueUpdateRegions));
|
Lang.bind(this, this._queueUpdateRegions));
|
||||||
|
|
||||||
|
this._screenSaverActive = false;
|
||||||
|
this._screenSaverProxy = new ScreenSaver.ScreenSaverProxy();
|
||||||
|
this._screenSaverProxy.connectSignal('ActiveChanged', Lang.bind(this, function(proxy, senderName, [isActive]) {
|
||||||
|
this._onScreenSaverActiveChanged(isActive);
|
||||||
|
}));
|
||||||
|
this._screenSaverProxy.GetActiveRemote(Lang.bind(this, function(result, err) {
|
||||||
|
if (!err)
|
||||||
|
this._onScreenSaverActiveChanged(result[0]);
|
||||||
|
}));
|
||||||
|
|
||||||
this._relayout();
|
this._relayout();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -587,8 +603,6 @@ const Chrome = new Lang.Class({
|
|||||||
Lang.bind(this, this._overviewShowing));
|
Lang.bind(this, this._overviewShowing));
|
||||||
Main.overview.connect('hidden',
|
Main.overview.connect('hidden',
|
||||||
Lang.bind(this, this._overviewHidden));
|
Lang.bind(this, this._overviewHidden));
|
||||||
Main.screenShield.connect('lock-status-changed',
|
|
||||||
Lang.bind(this, this._lockStatusChanged));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addActor: function(actor, params) {
|
addActor: function(actor, params) {
|
||||||
@@ -683,18 +697,19 @@ const Chrome = new Lang.Class({
|
|||||||
_updateVisibility: function() {
|
_updateVisibility: function() {
|
||||||
for (let i = 0; i < this._trackedActors.length; i++) {
|
for (let i = 0; i < this._trackedActors.length; i++) {
|
||||||
let actorData = this._trackedActors[i], visible;
|
let actorData = this._trackedActors[i], visible;
|
||||||
if (!actorData.trackFullscreen)
|
|
||||||
continue;
|
|
||||||
if (!actorData.isToplevel)
|
if (!actorData.isToplevel)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (this._inOverview || this._isLocked)
|
if (this._screenSaverActive)
|
||||||
|
visible = false;
|
||||||
|
else if (this._inOverview)
|
||||||
visible = true;
|
visible = true;
|
||||||
else if (this.findMonitorForActor(actorData.actor).inFullscreen)
|
else if (!actorData.visibleInFullscreen &&
|
||||||
|
this.findMonitorForActor(actorData.actor).inFullscreen)
|
||||||
visible = false;
|
visible = false;
|
||||||
else
|
else
|
||||||
visible = true;
|
visible = true;
|
||||||
actorData.actor.visible = visible;
|
Main.uiGroup.set_skip_paint(actorData.actor, !visible);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -710,12 +725,6 @@ const Chrome = new Lang.Class({
|
|||||||
this._queueUpdateRegions();
|
this._queueUpdateRegions();
|
||||||
},
|
},
|
||||||
|
|
||||||
_lockStatusChanged: function(shield, locked) {
|
|
||||||
this._isLocked = locked;
|
|
||||||
this._updateVisibility();
|
|
||||||
this._queueUpdateRegions();
|
|
||||||
},
|
|
||||||
|
|
||||||
_relayout: function() {
|
_relayout: function() {
|
||||||
this._monitors = this._layoutManager.monitors;
|
this._monitors = this._layoutManager.monitors;
|
||||||
this._primaryMonitor = this._layoutManager.primaryMonitor;
|
this._primaryMonitor = this._layoutManager.primaryMonitor;
|
||||||
@@ -725,6 +734,12 @@ const Chrome = new Lang.Class({
|
|||||||
this._queueUpdateRegions();
|
this._queueUpdateRegions();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onScreenSaverActiveChanged: function(screenSaverActive) {
|
||||||
|
this._screenSaverActive = screenSaverActive;
|
||||||
|
this._updateVisibility();
|
||||||
|
this._queueUpdateRegions();
|
||||||
|
},
|
||||||
|
|
||||||
_findMonitorForRect: function(x, y, w, h) {
|
_findMonitorForRect: function(x, y, w, h) {
|
||||||
// First look at what monitor the center of the rectangle is at
|
// First look at what monitor the center of the rectangle is at
|
||||||
let cx = x + w/2;
|
let cx = x + w/2;
|
||||||
@@ -840,8 +855,6 @@ const Chrome = new Lang.Class({
|
|||||||
for (let i = 0; i < this._monitors.length; i++)
|
for (let i = 0; i < this._monitors.length; i++)
|
||||||
wasInFullscreen[i] = this._monitors[i].inFullscreen;
|
wasInFullscreen[i] = this._monitors[i].inFullscreen;
|
||||||
|
|
||||||
let primaryWasInFullscreen = this._primaryMonitor.inFullscreen;
|
|
||||||
|
|
||||||
this._updateFullscreen();
|
this._updateFullscreen();
|
||||||
|
|
||||||
let changed = false;
|
let changed = false;
|
||||||
@@ -851,15 +864,10 @@ const Chrome = new Lang.Class({
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
this._updateVisibility();
|
this._updateVisibility();
|
||||||
this._queueUpdateRegions();
|
this._queueUpdateRegions();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (primaryWasInFullscreen != this._primaryMonitor.inFullscreen) {
|
|
||||||
this.emit('primary-fullscreen-changed', this._primaryMonitor.inFullscreen);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
updateRegions: function() {
|
updateRegions: function() {
|
||||||
@@ -973,6 +981,4 @@ const Chrome = new Lang.Class({
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
Signals.addSignalMethods(Chrome.prototype);
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
@@ -8,8 +7,6 @@ const St = imports.gi.St;
|
|||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
const DEFAULT_FADE_FACTOR = 0.4;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lightbox:
|
* Lightbox:
|
||||||
* @container: parent Clutter.Container
|
* @container: parent Clutter.Container
|
||||||
@@ -17,8 +14,7 @@ const DEFAULT_FADE_FACTOR = 0.4;
|
|||||||
* - inhibitEvents: whether to inhibit events for @container
|
* - inhibitEvents: whether to inhibit events for @container
|
||||||
* - width: shade actor width
|
* - width: shade actor width
|
||||||
* - height: shade actor height
|
* - height: shade actor height
|
||||||
* - fadeInTime: seconds used to fade in
|
* - fadeTime: seconds used to fade in/out
|
||||||
* - fadeOutTime: seconds used to fade out
|
|
||||||
*
|
*
|
||||||
* Lightbox creates a dark translucent "shade" actor to hide the
|
* Lightbox creates a dark translucent "shade" actor to hide the
|
||||||
* contents of @container, and allows you to specify particular actors
|
* contents of @container, and allows you to specify particular actors
|
||||||
@@ -34,23 +30,21 @@ const DEFAULT_FADE_FACTOR = 0.4;
|
|||||||
* @container and will track any changes in its size. You can override
|
* @container and will track any changes in its size. You can override
|
||||||
* this by passing an explicit width and height in @params.
|
* this by passing an explicit width and height in @params.
|
||||||
*/
|
*/
|
||||||
const Lightbox = new Lang.Class({
|
function Lightbox(container, params) {
|
||||||
Name: 'Lightbox',
|
this._init(container, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
Lightbox.prototype = {
|
||||||
_init : function(container, params) {
|
_init : function(container, params) {
|
||||||
params = Params.parse(params, { inhibitEvents: false,
|
params = Params.parse(params, { inhibitEvents: false,
|
||||||
width: null,
|
width: null,
|
||||||
height: null,
|
height: null,
|
||||||
fadeInTime: null,
|
fadeTime: null
|
||||||
fadeOutTime: null,
|
|
||||||
fadeFactor: DEFAULT_FADE_FACTOR
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this._container = container;
|
this._container = container;
|
||||||
this._children = container.get_children();
|
this._children = container.get_children();
|
||||||
this._fadeInTime = params.fadeInTime;
|
this._fadeTime = params.fadeTime;
|
||||||
this._fadeOutTime = params.fadeOutTime;
|
|
||||||
this._fadeFactor = params.fadeFactor;
|
|
||||||
this.actor = new St.Bin({ x: 0,
|
this.actor = new St.Bin({ x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
style_class: 'lightbox',
|
style_class: 'lightbox',
|
||||||
@@ -59,17 +53,17 @@ const Lightbox = new Lang.Class({
|
|||||||
container.add_actor(this.actor);
|
container.add_actor(this.actor);
|
||||||
this.actor.raise_top();
|
this.actor.raise_top();
|
||||||
this.actor.hide();
|
this.actor.hide();
|
||||||
this.shown = false;
|
|
||||||
|
|
||||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||||
|
|
||||||
if (params.width && params.height) {
|
if (params.width && params.height) {
|
||||||
this.actor.width = params.width;
|
this.actor.width = params.width;
|
||||||
this.actor.height = params.height;
|
this.actor.height = params.height;
|
||||||
|
this._allocationChangedSignalId = 0;
|
||||||
} else {
|
} else {
|
||||||
let constraint = new Clutter.BindConstraint({ source: container,
|
this.actor.width = container.width;
|
||||||
coordinate: Clutter.BindCoordinate.ALL });
|
this.actor.height = container.height;
|
||||||
this.actor.add_constraint(constraint);
|
this._allocationChangedSignalId = container.connect('allocation-changed', Lang.bind(this, this._allocationChanged));
|
||||||
}
|
}
|
||||||
|
|
||||||
this._actorAddedSignalId = container.connect('actor-added', Lang.bind(this, this._actorAdded));
|
this._actorAddedSignalId = container.connect('actor-added', Lang.bind(this, this._actorAdded));
|
||||||
@@ -78,6 +72,16 @@ const Lightbox = new Lang.Class({
|
|||||||
this._highlighted = null;
|
this._highlighted = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_allocationChanged : function(container, box, flags) {
|
||||||
|
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
||||||
|
this.actor.width = this.width;
|
||||||
|
this.actor.height = this.height;
|
||||||
|
return false;
|
||||||
|
}));
|
||||||
|
this.width = this._container.width;
|
||||||
|
this.height = this._container.height;
|
||||||
|
},
|
||||||
|
|
||||||
_actorAdded : function(container, newChild) {
|
_actorAdded : function(container, newChild) {
|
||||||
let children = this._container.get_children();
|
let children = this._container.get_children();
|
||||||
let myIndex = children.indexOf(this.actor);
|
let myIndex = children.indexOf(this.actor);
|
||||||
@@ -101,30 +105,24 @@ const Lightbox = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
show: function() {
|
show: function() {
|
||||||
if (this._fadeInTime) {
|
if (this._fadeTime) {
|
||||||
this.shown = false;
|
|
||||||
this.actor.opacity = 0;
|
this.actor.opacity = 0;
|
||||||
Tweener.addTween(this.actor,
|
Tweener.addTween(this.actor,
|
||||||
{ opacity: 255 * this._fadeFactor,
|
{ opacity: 255,
|
||||||
time: this._fadeInTime,
|
time: this._fadeTime,
|
||||||
transition: 'easeOutQuad',
|
transition: 'easeOutQuad'
|
||||||
onComplete: Lang.bind(this, function() {
|
|
||||||
this.shown = true;
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.actor.opacity = 255 * this._fadeFactor;
|
this.actor.opacity = 255;
|
||||||
this.shown = true;
|
|
||||||
}
|
}
|
||||||
this.actor.show();
|
this.actor.show();
|
||||||
},
|
},
|
||||||
|
|
||||||
hide: function() {
|
hide: function() {
|
||||||
this.shown = false;
|
if (this._fadeTime) {
|
||||||
if (this._fadeOutTime) {
|
|
||||||
Tweener.addTween(this.actor,
|
Tweener.addTween(this.actor,
|
||||||
{ opacity: 0,
|
{ opacity: 0,
|
||||||
time: this._fadeOutTime,
|
time: this._fadeTime,
|
||||||
transition: 'easeOutQuad',
|
transition: 'easeOutQuad',
|
||||||
onComplete: Lang.bind(this, function() {
|
onComplete: Lang.bind(this, function() {
|
||||||
this.actor.hide();
|
this.actor.hide();
|
||||||
@@ -191,9 +189,11 @@ const Lightbox = new Lang.Class({
|
|||||||
* by destroying its container or by explicitly calling this.destroy().
|
* by destroying its container or by explicitly calling this.destroy().
|
||||||
*/
|
*/
|
||||||
_onDestroy: function() {
|
_onDestroy: function() {
|
||||||
|
if (this._allocationChangedSignalId != 0)
|
||||||
|
this._container.disconnect(this._allocationChangedSignalId);
|
||||||
this._container.disconnect(this._actorAddedSignalId);
|
this._container.disconnect(this._actorAddedSignalId);
|
||||||
this._container.disconnect(this._actorRemovedSignalId);
|
this._container.disconnect(this._actorRemovedSignalId);
|
||||||
|
|
||||||
this.highlight(null);
|
this.highlight(null);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|||||||
24
js/ui/link.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Signals = imports.signals;
|
||||||
|
const St = imports.gi.St;
|
||||||
|
|
||||||
|
function Link(props) {
|
||||||
|
this._init(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
Link.prototype = {
|
||||||
|
_init : function(props) {
|
||||||
|
let realProps = { reactive: true,
|
||||||
|
track_hover: true,
|
||||||
|
style_class: 'shell-link' };
|
||||||
|
// The user can pass in reactive: false to override the above and get
|
||||||
|
// a non-reactive link (a link to the current page, perhaps)
|
||||||
|
Lang.copyProperties(props, realProps);
|
||||||
|
|
||||||
|
this.actor = new St.Button(realProps);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Signals.addSignalMethods(Link.prototype);
|
||||||
@@ -12,18 +12,15 @@ const Shell = imports.gi.Shell;
|
|||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const System = imports.system;
|
|
||||||
|
|
||||||
const History = imports.misc.history;
|
const History = imports.misc.history;
|
||||||
const ExtensionSystem = imports.ui.extensionSystem;
|
const ExtensionSystem = imports.ui.extensionSystem;
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
const Link = imports.ui.link;
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const JsParse = imports.misc.jsParse;
|
const JsParse = imports.misc.jsParse;
|
||||||
|
|
||||||
const CHEVRON = '>>> ';
|
|
||||||
|
|
||||||
/* Imports...feel free to add here as needed */
|
/* Imports...feel free to add here as needed */
|
||||||
var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
|
var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
|
||||||
'const GLib = imports.gi.GLib; ' +
|
'const GLib = imports.gi.GLib; ' +
|
||||||
@@ -58,9 +55,11 @@ function _getAutoCompleteGlobalKeywords() {
|
|||||||
return keywords.concat(windowProperties).concat(headerProperties);
|
return keywords.concat(windowProperties).concat(headerProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
const AutoComplete = new Lang.Class({
|
function AutoComplete(entry) {
|
||||||
Name: 'AutoComplete',
|
this._init(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoComplete.prototype = {
|
||||||
_init: function(entry) {
|
_init: function(entry) {
|
||||||
this._entry = entry;
|
this._entry = entry;
|
||||||
this._entry.connect('key-press-event', Lang.bind(this, this._entryKeyPressEvent));
|
this._entry.connect('key-press-event', Lang.bind(this, this._entryKeyPressEvent));
|
||||||
@@ -119,13 +118,15 @@ const AutoComplete = new Lang.Class({
|
|||||||
|
|
||||||
this._entry.clutter_text.insert_text(additionalCompletionText, cursorPos);
|
this._entry.clutter_text.insert_text(additionalCompletionText, cursorPos);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(AutoComplete.prototype);
|
Signals.addSignalMethods(AutoComplete.prototype);
|
||||||
|
|
||||||
|
|
||||||
const Notebook = new Lang.Class({
|
function Notebook() {
|
||||||
Name: 'Notebook',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
Notebook.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.actor = new St.BoxLayout({ vertical: true });
|
this.actor = new St.BoxLayout({ vertical: true });
|
||||||
|
|
||||||
@@ -249,7 +250,7 @@ const Notebook = new Lang.Class({
|
|||||||
|
|
||||||
this.selectIndex(prevIndex);
|
this.selectIndex(prevIndex);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(Notebook.prototype);
|
Signals.addSignalMethods(Notebook.prototype);
|
||||||
|
|
||||||
function objectToString(o) {
|
function objectToString(o) {
|
||||||
@@ -261,10 +262,14 @@ function objectToString(o) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ObjLink = new Lang.Class({
|
function ObjLink(o, title) {
|
||||||
Name: 'ObjLink',
|
this._init(o, title);
|
||||||
|
}
|
||||||
|
|
||||||
_init: function(lookingGlass, o, title) {
|
ObjLink.prototype = {
|
||||||
|
__proto__: Link.Link,
|
||||||
|
|
||||||
|
_init: function(o, title) {
|
||||||
let text;
|
let text;
|
||||||
if (title)
|
if (title)
|
||||||
text = title;
|
text = title;
|
||||||
@@ -272,31 +277,26 @@ const ObjLink = new Lang.Class({
|
|||||||
text = objectToString(o);
|
text = objectToString(o);
|
||||||
text = GLib.markup_escape_text(text, -1);
|
text = GLib.markup_escape_text(text, -1);
|
||||||
this._obj = o;
|
this._obj = o;
|
||||||
|
Link.Link.prototype._init.call(this, { label: text });
|
||||||
this.actor = new St.Button({ reactive: true,
|
|
||||||
track_hover: true,
|
|
||||||
style_class: 'shell-link',
|
|
||||||
label: text });
|
|
||||||
this.actor.get_child().single_line_mode = true;
|
this.actor.get_child().single_line_mode = true;
|
||||||
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||||
|
|
||||||
this._lookingGlass = lookingGlass;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onClicked: function (link) {
|
_onClicked: function (link) {
|
||||||
this._lookingGlass.inspectObject(this._obj, this.actor);
|
Main.lookingGlass.inspectObject(this._obj, this.actor);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const Result = new Lang.Class({
|
function Result(command, o, index) {
|
||||||
Name: 'Result',
|
this._init(command, o, index);
|
||||||
|
}
|
||||||
|
|
||||||
_init: function(lookingGlass, command, o, index) {
|
Result.prototype = {
|
||||||
|
_init : function(command, o, index) {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.o = o;
|
this.o = o;
|
||||||
|
|
||||||
this.actor = new St.BoxLayout({ vertical: true });
|
this.actor = new St.BoxLayout({ vertical: true });
|
||||||
this._lookingGlass = lookingGlass;
|
|
||||||
|
|
||||||
let cmdTxt = new St.Label({ text: command });
|
let cmdTxt = new St.Label({ text: command });
|
||||||
cmdTxt.clutter_text.ellipsize = Pango.EllipsizeMode.END;
|
cmdTxt.clutter_text.ellipsize = Pango.EllipsizeMode.END;
|
||||||
@@ -306,30 +306,30 @@ const Result = new Lang.Class({
|
|||||||
let resultTxt = new St.Label({ text: 'r(' + index + ') = ' });
|
let resultTxt = new St.Label({ text: 'r(' + index + ') = ' });
|
||||||
resultTxt.clutter_text.ellipsize = Pango.EllipsizeMode.END;
|
resultTxt.clutter_text.ellipsize = Pango.EllipsizeMode.END;
|
||||||
box.add(resultTxt);
|
box.add(resultTxt);
|
||||||
let objLink = new ObjLink(this._lookingGlass, o);
|
let objLink = new ObjLink(o);
|
||||||
box.add(objLink.actor);
|
box.add(objLink.actor);
|
||||||
let line = new Clutter.Rectangle({ name: 'Separator' });
|
let line = new Clutter.Rectangle({ name: 'Separator' });
|
||||||
let padBin = new St.Bin({ name: 'Separator', x_fill: true, y_fill: true });
|
let padBin = new St.Bin({ name: 'Separator', x_fill: true, y_fill: true });
|
||||||
padBin.add_actor(line);
|
padBin.add_actor(line);
|
||||||
this.actor.add(padBin);
|
this.actor.add(padBin);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const WindowList = new Lang.Class({
|
function WindowList() {
|
||||||
Name: 'WindowList',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
_init: function(lookingGlass) {
|
WindowList.prototype = {
|
||||||
|
_init : function () {
|
||||||
this.actor = new St.BoxLayout({ name: 'Windows', vertical: true, style: 'spacing: 8px' });
|
this.actor = new St.BoxLayout({ name: 'Windows', vertical: true, style: 'spacing: 8px' });
|
||||||
let tracker = Shell.WindowTracker.get_default();
|
let tracker = Shell.WindowTracker.get_default();
|
||||||
this._updateId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._updateWindowList));
|
this._updateId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._updateWindowList));
|
||||||
global.display.connect('window-created', Lang.bind(this, this._updateWindowList));
|
global.display.connect('window-created', Lang.bind(this, this._updateWindowList));
|
||||||
tracker.connect('tracked-windows-changed', Lang.bind(this, this._updateWindowList));
|
tracker.connect('tracked-windows-changed', Lang.bind(this, this._updateWindowList));
|
||||||
|
|
||||||
this._lookingGlass = lookingGlass;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateWindowList: function() {
|
_updateWindowList: function() {
|
||||||
this.actor.destroy_all_children();
|
this.actor.get_children().forEach(function (actor) { actor.destroy(); });
|
||||||
let windows = global.get_window_actors();
|
let windows = global.get_window_actors();
|
||||||
let tracker = Shell.WindowTracker.get_default();
|
let tracker = Shell.WindowTracker.get_default();
|
||||||
for (let i = 0; i < windows.length; i++) {
|
for (let i = 0; i < windows.length; i++) {
|
||||||
@@ -341,7 +341,7 @@ const WindowList = new Lang.Class({
|
|||||||
}
|
}
|
||||||
let box = new St.BoxLayout({ vertical: true });
|
let box = new St.BoxLayout({ vertical: true });
|
||||||
this.actor.add(box);
|
this.actor.add(box);
|
||||||
let windowLink = new ObjLink(this._lookingGlass, metaWindow, metaWindow.title);
|
let windowLink = new ObjLink(metaWindow, metaWindow.title);
|
||||||
box.add(windowLink.actor, { x_align: St.Align.START, x_fill: false });
|
box.add(windowLink.actor, { x_align: St.Align.START, x_fill: false });
|
||||||
let propsBox = new St.BoxLayout({ vertical: true, style: 'padding-left: 6px;' });
|
let propsBox = new St.BoxLayout({ vertical: true, style: 'padding-left: 6px;' });
|
||||||
box.add(propsBox);
|
box.add(propsBox);
|
||||||
@@ -352,7 +352,7 @@ const WindowList = new Lang.Class({
|
|||||||
let propBox = new St.BoxLayout({ style: 'spacing: 6px; ' });
|
let propBox = new St.BoxLayout({ style: 'spacing: 6px; ' });
|
||||||
propsBox.add(propBox);
|
propsBox.add(propBox);
|
||||||
propBox.add(new St.Label({ text: 'app: ' }), { y_fill: false });
|
propBox.add(new St.Label({ text: 'app: ' }), { y_fill: false });
|
||||||
let appLink = new ObjLink(this._lookingGlass, app, app.get_id());
|
let appLink = new ObjLink(app, app.get_id());
|
||||||
propBox.add(appLink.actor, { y_fill: false });
|
propBox.add(appLink.actor, { y_fill: false });
|
||||||
propBox.add(icon, { y_fill: false });
|
propBox.add(icon, { y_fill: false });
|
||||||
} else {
|
} else {
|
||||||
@@ -360,13 +360,15 @@ const WindowList = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(WindowList.prototype);
|
Signals.addSignalMethods(WindowList.prototype);
|
||||||
|
|
||||||
const ObjInspector = new Lang.Class({
|
function ObjInspector() {
|
||||||
Name: 'ObjInspector',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
_init: function(lookingGlass) {
|
ObjInspector.prototype = {
|
||||||
|
_init : function () {
|
||||||
this._obj = null;
|
this._obj = null;
|
||||||
this._previousObj = null;
|
this._previousObj = null;
|
||||||
|
|
||||||
@@ -378,8 +380,6 @@ const ObjInspector = new Lang.Class({
|
|||||||
style_class: 'lg-dialog',
|
style_class: 'lg-dialog',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
this.actor.add_actor(this._container);
|
this.actor.add_actor(this._container);
|
||||||
|
|
||||||
this._lookingGlass = lookingGlass;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
selectObject: function(obj, skipPrevious) {
|
selectObject: function(obj, skipPrevious) {
|
||||||
@@ -389,7 +389,7 @@ const ObjInspector = new Lang.Class({
|
|||||||
this._previousObj = null;
|
this._previousObj = null;
|
||||||
this._obj = obj;
|
this._obj = obj;
|
||||||
|
|
||||||
this._container.destroy_all_children();
|
this._container.get_children().forEach(function (child) { child.destroy(); });
|
||||||
|
|
||||||
let hbox = new St.BoxLayout({ style_class: 'lg-obj-inspector-title' });
|
let hbox = new St.BoxLayout({ style_class: 'lg-obj-inspector-title' });
|
||||||
this._container.add_actor(hbox);
|
this._container.add_actor(hbox);
|
||||||
@@ -411,19 +411,12 @@ const ObjInspector = new Lang.Class({
|
|||||||
button.connect('clicked', Lang.bind(this, this.close));
|
button.connect('clicked', Lang.bind(this, this.close));
|
||||||
hbox.add(button);
|
hbox.add(button);
|
||||||
if (typeof(obj) == typeof({})) {
|
if (typeof(obj) == typeof({})) {
|
||||||
let properties = [];
|
|
||||||
for (let propName in obj) {
|
for (let propName in obj) {
|
||||||
properties.push(propName);
|
|
||||||
}
|
|
||||||
properties.sort();
|
|
||||||
|
|
||||||
for (let i = 0; i < properties.length; i++) {
|
|
||||||
let propName = properties[i];
|
|
||||||
let valueStr;
|
let valueStr;
|
||||||
let link;
|
let link;
|
||||||
try {
|
try {
|
||||||
let prop = obj[propName];
|
let prop = obj[propName];
|
||||||
link = new ObjLink(this._lookingGlass, prop).actor;
|
link = new ObjLink(prop).actor;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
link = new St.Label({ text: '<error>' });
|
link = new St.Label({ text: '<error>' });
|
||||||
}
|
}
|
||||||
@@ -468,22 +461,17 @@ const ObjInspector = new Lang.Class({
|
|||||||
_onInsert: function() {
|
_onInsert: function() {
|
||||||
let obj = this._obj;
|
let obj = this._obj;
|
||||||
this.close();
|
this.close();
|
||||||
this._lookingGlass.insertObject(obj);
|
Main.lookingGlass.insertObject(obj);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onBack: function() {
|
_onBack: function() {
|
||||||
this.selectObject(this._previousObj, true);
|
this.selectObject(this._previousObj, true);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const RedBorderEffect = new Lang.Class({
|
|
||||||
Name: 'RedBorderEffect',
|
|
||||||
Extends: Clutter.Effect,
|
|
||||||
|
|
||||||
vfunc_paint: function() {
|
|
||||||
let actor = this.get_actor();
|
|
||||||
actor.continue_paint();
|
|
||||||
|
|
||||||
|
function addBorderPaintHook(actor) {
|
||||||
|
let signalId = actor.connect_after('paint',
|
||||||
|
function () {
|
||||||
let color = new Cogl.Color();
|
let color = new Cogl.Color();
|
||||||
color.init_from_4ub(0xff, 0, 0, 0xc4);
|
color.init_from_4ub(0xff, 0, 0, 0xc4);
|
||||||
Cogl.set_source_color(color);
|
Cogl.set_source_color(color);
|
||||||
@@ -499,13 +487,18 @@ const RedBorderEffect = new Lang.Class({
|
|||||||
geom.width - width, geom.height - width);
|
geom.width - width, geom.height - width);
|
||||||
Cogl.rectangle(0, geom.height - width,
|
Cogl.rectangle(0, geom.height - width,
|
||||||
width, width);
|
width, width);
|
||||||
},
|
});
|
||||||
});
|
|
||||||
|
|
||||||
const Inspector = new Lang.Class({
|
actor.queue_redraw();
|
||||||
Name: 'Inspector',
|
return signalId;
|
||||||
|
}
|
||||||
|
|
||||||
_init: function(lookingGlass) {
|
function Inspector() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
Inspector.prototype = {
|
||||||
|
_init: function() {
|
||||||
let container = new Shell.GenericContainer({ width: 0,
|
let container = new Shell.GenericContainer({ width: 0,
|
||||||
height: 0 });
|
height: 0 });
|
||||||
container.connect('allocate', Lang.bind(this, this._allocate));
|
container.connect('allocate', Lang.bind(this, this._allocate));
|
||||||
@@ -519,6 +512,9 @@ const Inspector = new Lang.Class({
|
|||||||
this._displayText = new St.Label();
|
this._displayText = new St.Label();
|
||||||
eventHandler.add(this._displayText, { expand: true });
|
eventHandler.add(this._displayText, { expand: true });
|
||||||
|
|
||||||
|
this._borderPaintTarget = null;
|
||||||
|
this._borderPaintId = null;
|
||||||
|
eventHandler.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||||
eventHandler.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
|
eventHandler.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
|
||||||
eventHandler.connect('button-press-event', Lang.bind(this, this._onButtonPressEvent));
|
eventHandler.connect('button-press-event', Lang.bind(this, this._onButtonPressEvent));
|
||||||
eventHandler.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
eventHandler.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
||||||
@@ -533,8 +529,6 @@ const Inspector = new Lang.Class({
|
|||||||
// out, or move the pointer outside of _pointerTarget.
|
// out, or move the pointer outside of _pointerTarget.
|
||||||
this._target = null;
|
this._target = null;
|
||||||
this._pointerTarget = null;
|
this._pointerTarget = null;
|
||||||
|
|
||||||
this._lookingGlass = lookingGlass;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_allocate: function(actor, box, flags) {
|
_allocate: function(actor, box, flags) {
|
||||||
@@ -555,13 +549,18 @@ const Inspector = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_close: function() {
|
_close: function() {
|
||||||
Clutter.ungrab_pointer();
|
Clutter.ungrab_pointer(this._eventHandler);
|
||||||
Clutter.ungrab_keyboard();
|
Clutter.ungrab_keyboard(this._eventHandler);
|
||||||
this._eventHandler.destroy();
|
this._eventHandler.destroy();
|
||||||
this._eventHandler = null;
|
this._eventHandler = null;
|
||||||
this.emit('closed');
|
this.emit('closed');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onDestroy: function() {
|
||||||
|
if (this._borderPaintTarget != null)
|
||||||
|
this._borderPaintTarget.disconnect(this._borderPaintId);
|
||||||
|
},
|
||||||
|
|
||||||
_onKeyPressEvent: function (actor, event) {
|
_onKeyPressEvent: function (actor, event) {
|
||||||
if (event.get_key_symbol() == Clutter.Escape)
|
if (event.get_key_symbol() == Clutter.Escape)
|
||||||
this._close();
|
this._close();
|
||||||
@@ -630,15 +629,63 @@ const Inspector = new Lang.Class({
|
|||||||
this._displayText.text = '';
|
this._displayText.text = '';
|
||||||
this._displayText.text = position + ' ' + this._target;
|
this._displayText.text = position + ' ' + this._target;
|
||||||
|
|
||||||
this._lookingGlass.setBorderPaintTarget(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);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Signals.addSignalMethods(Inspector.prototype);
|
Signals.addSignalMethods(Inspector.prototype);
|
||||||
|
|
||||||
const Memory = new Lang.Class({
|
function ErrorLog() {
|
||||||
Name: 'Memory',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorLog.prototype = {
|
||||||
|
_init: function() {
|
||||||
|
this.actor = new St.BoxLayout();
|
||||||
|
this.text = new St.Label();
|
||||||
|
this.actor.add(this.text);
|
||||||
|
// We need to override StLabel's default ellipsization when
|
||||||
|
// using line_wrap; otherwise ClutterText's layout is going
|
||||||
|
// to constrain both the width and height, which prevents
|
||||||
|
// scrolling.
|
||||||
|
this.text.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
|
this.text.clutter_text.line_wrap = true;
|
||||||
|
this.actor.connect('notify::mapped', Lang.bind(this, this._renderText));
|
||||||
|
},
|
||||||
|
|
||||||
|
_formatTime: function(d){
|
||||||
|
function pad(n) { return n < 10 ? '0' + n : n; }
|
||||||
|
return d.getUTCFullYear()+'-'
|
||||||
|
+ pad(d.getUTCMonth()+1)+'-'
|
||||||
|
+ pad(d.getUTCDate())+'T'
|
||||||
|
+ pad(d.getUTCHours())+':'
|
||||||
|
+ pad(d.getUTCMinutes())+':'
|
||||||
|
+ pad(d.getUTCSeconds())+'Z';
|
||||||
|
},
|
||||||
|
|
||||||
|
_renderText: function() {
|
||||||
|
if (!this.actor.mapped)
|
||||||
|
return;
|
||||||
|
let text = this.text.text;
|
||||||
|
let stack = Main._getAndClearErrorStack();
|
||||||
|
for (let i = 0; i < stack.length; i++) {
|
||||||
|
let logItem = stack[i];
|
||||||
|
text += logItem.category + ' t=' + this._formatTime(new Date(logItem.timestamp)) + ' ' + logItem.message + '\n';
|
||||||
|
}
|
||||||
|
this.text.text = text;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function Memory() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
Memory.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.actor = new St.BoxLayout({ vertical: true });
|
this.actor = new St.BoxLayout({ vertical: true });
|
||||||
this._glibc_uordblks = new St.Label();
|
this._glibc_uordblks = new St.Label();
|
||||||
@@ -664,7 +711,7 @@ const Memory = new Lang.Class({
|
|||||||
|
|
||||||
this._gcbutton = new St.Button({ label: 'Full GC',
|
this._gcbutton = new St.Button({ label: 'Full GC',
|
||||||
style_class: 'lg-obj-inspector-button' });
|
style_class: 'lg-obj-inspector-button' });
|
||||||
this._gcbutton.connect('clicked', Lang.bind(this, function () { System.gc(); this._renderText(); }));
|
this._gcbutton.connect('clicked', Lang.bind(this, function () { global.gc(); this._renderText(); }));
|
||||||
this.actor.add(this._gcbutton, { x_align: St.Align.START,
|
this.actor.add(this._gcbutton, { x_align: St.Align.START,
|
||||||
x_fill: false });
|
x_fill: false });
|
||||||
|
|
||||||
@@ -683,11 +730,13 @@ const Memory = new Lang.Class({
|
|||||||
this._gjs_closure.text = 'gjs_closure: ' + memInfo.gjs_closure;
|
this._gjs_closure.text = 'gjs_closure: ' + memInfo.gjs_closure;
|
||||||
this._last_gc_seconds_ago.text = 'last_gc_seconds_ago: ' + memInfo.last_gc_seconds_ago;
|
this._last_gc_seconds_ago.text = 'last_gc_seconds_ago: ' + memInfo.last_gc_seconds_ago;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const Extensions = new Lang.Class({
|
function Extensions() {
|
||||||
Name: 'Extensions',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
Extensions.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.actor = new St.BoxLayout({ vertical: true,
|
this.actor = new St.BoxLayout({ vertical: true,
|
||||||
name: 'lookingGlassExtensions' });
|
name: 'lookingGlassExtensions' });
|
||||||
@@ -699,7 +748,7 @@ const Extensions = new Lang.Class({
|
|||||||
this._extensionsList.add(this._noExtensions);
|
this._extensionsList.add(this._noExtensions);
|
||||||
this.actor.add(this._extensionsList);
|
this.actor.add(this._extensionsList);
|
||||||
|
|
||||||
for (let uuid in ExtensionUtils.extensions)
|
for (let uuid in ExtensionSystem.extensionMeta)
|
||||||
this._loadExtension(null, uuid);
|
this._loadExtension(null, uuid);
|
||||||
|
|
||||||
ExtensionSystem.connect('extension-loaded',
|
ExtensionSystem.connect('extension-loaded',
|
||||||
@@ -707,10 +756,10 @@ const Extensions = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_loadExtension: function(o, uuid) {
|
_loadExtension: function(o, uuid) {
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
let extension = ExtensionSystem.extensionMeta[uuid];
|
||||||
// There can be cases where we create dummy extension metadata
|
// There can be cases where we create dummy extension metadata
|
||||||
// that's not really a proper extension. Don't bother with these.
|
// that's not really a proper extension. Don't bother with these.
|
||||||
if (!extension.metadata.name)
|
if (!extension.name)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let extensionDisplay = this._createExtensionDisplay(extension);
|
let extensionDisplay = this._createExtensionDisplay(extension);
|
||||||
@@ -722,31 +771,32 @@ const Extensions = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onViewSource: function (actor) {
|
_onViewSource: function (actor) {
|
||||||
let extension = actor._extension;
|
let meta = actor._extensionMeta;
|
||||||
let uri = extension.dir.get_uri();
|
let file = Gio.file_new_for_path(meta.path);
|
||||||
|
let uri = file.get_uri();
|
||||||
Gio.app_info_launch_default_for_uri(uri, global.create_app_launch_context());
|
Gio.app_info_launch_default_for_uri(uri, global.create_app_launch_context());
|
||||||
this._lookingGlass.close();
|
Main.lookingGlass.close();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onWebPage: function (actor) {
|
_onWebPage: function (actor) {
|
||||||
let extension = actor._extension;
|
let meta = actor._extensionMeta;
|
||||||
Gio.app_info_launch_default_for_uri(extension.metadata.url, global.create_app_launch_context());
|
Gio.app_info_launch_default_for_uri(meta.url, global.create_app_launch_context());
|
||||||
this._lookingGlass.close();
|
Main.lookingGlass.close();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onViewErrors: function (actor) {
|
_onViewErrors: function (actor) {
|
||||||
let extension = actor._extension;
|
let meta = actor._extensionMeta;
|
||||||
let shouldShow = !actor._isShowing;
|
let shouldShow = !actor._isShowing;
|
||||||
|
|
||||||
if (shouldShow) {
|
if (shouldShow) {
|
||||||
let errors = extension.errors;
|
let errors = ExtensionSystem.errors[meta.uuid];
|
||||||
let errorDisplay = new St.BoxLayout({ vertical: true });
|
let errorDisplay = new St.BoxLayout({ vertical: true });
|
||||||
if (errors && errors.length) {
|
if (errors && errors.length) {
|
||||||
for (let i = 0; i < errors.length; i ++)
|
for (let i = 0; i < errors.length; i ++)
|
||||||
errorDisplay.add(new St.Label({ text: errors[i] }));
|
errorDisplay.add(new St.Label({ text: errors[i] }));
|
||||||
} else {
|
} else {
|
||||||
/* Translators: argument is an extension UUID. */
|
/* Translators: argument is an extension UUID. */
|
||||||
let message = _("%s has not emitted any errors.").format(extension.uuid);
|
let message = _("%s has not emitted any errors.").format(meta.uuid);
|
||||||
errorDisplay.add(new St.Label({ text: message }));
|
errorDisplay.add(new St.Label({ text: message }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,60 +829,54 @@ const Extensions = new Lang.Class({
|
|||||||
return 'Unknown'; // Not translated, shouldn't appear
|
return 'Unknown'; // Not translated, shouldn't appear
|
||||||
},
|
},
|
||||||
|
|
||||||
_createExtensionDisplay: function(extension) {
|
_createExtensionDisplay: function(meta) {
|
||||||
let box = new St.BoxLayout({ style_class: 'lg-extension', vertical: true });
|
let box = new St.BoxLayout({ style_class: 'lg-extension', vertical: true });
|
||||||
let name = new St.Label({ style_class: 'lg-extension-name',
|
let name = new St.Label({ style_class: 'lg-extension-name',
|
||||||
text: extension.metadata.name });
|
text: meta.name });
|
||||||
box.add(name, { expand: true });
|
box.add(name, { expand: true });
|
||||||
let description = new St.Label({ style_class: 'lg-extension-description',
|
let description = new St.Label({ style_class: 'lg-extension-description',
|
||||||
text: extension.metadata.description || 'No description' });
|
text: meta.description || 'No description' });
|
||||||
box.add(description, { expand: true });
|
box.add(description, { expand: true });
|
||||||
|
|
||||||
let metaBox = new St.BoxLayout({ style_class: 'lg-extension-meta' });
|
let metaBox = new St.BoxLayout({ style_class: 'lg-extension-meta' });
|
||||||
box.add(metaBox);
|
box.add(metaBox);
|
||||||
let stateString = this._stateToString(extension.state);
|
let stateString = this._stateToString(meta.state);
|
||||||
let state = new St.Label({ style_class: 'lg-extension-state',
|
let state = new St.Label({ style_class: 'lg-extension-state',
|
||||||
text: this._stateToString(extension.state) });
|
text: this._stateToString(meta.state) });
|
||||||
metaBox.add(state);
|
metaBox.add(state);
|
||||||
|
|
||||||
let viewsource = new St.Button({ reactive: true,
|
let viewsource = new Link.Link({ label: _("View Source") });
|
||||||
track_hover: true,
|
viewsource.actor._extensionMeta = meta;
|
||||||
style_class: 'shell-link',
|
viewsource.actor.connect('clicked', Lang.bind(this, this._onViewSource));
|
||||||
label: _("View Source") });
|
metaBox.add(viewsource.actor);
|
||||||
viewsource._extension = extension;
|
|
||||||
viewsource.connect('clicked', Lang.bind(this, this._onViewSource));
|
|
||||||
metaBox.add(viewsource);
|
|
||||||
|
|
||||||
if (extension.metadata.url) {
|
if (meta.url) {
|
||||||
let webpage = new St.Button({ reactive: true,
|
let webpage = new Link.Link({ label: _("Web Page") });
|
||||||
track_hover: true,
|
webpage.actor._extensionMeta = meta;
|
||||||
style_class: 'shell-link',
|
webpage.actor.connect('clicked', Lang.bind(this, this._onWebPage));
|
||||||
label: _("Web Page") });
|
metaBox.add(webpage.actor);
|
||||||
webpage._extension = extension;
|
|
||||||
webpage.connect('clicked', Lang.bind(this, this._onWebPage));
|
|
||||||
metaBox.add(webpage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let viewerrors = new St.Button({ reactive: true,
|
let viewerrors = new Link.Link({ label: _("Show Errors") });
|
||||||
track_hover: true,
|
viewerrors.actor._extensionMeta = meta;
|
||||||
style_class: 'shell-link',
|
viewerrors.actor._parentBox = box;
|
||||||
label: _("Show Errors") });
|
viewerrors.actor._isShowing = false;
|
||||||
viewerrors._extension = extension;
|
viewerrors.actor.connect('clicked', Lang.bind(this, this._onViewErrors));
|
||||||
viewerrors._parentBox = box;
|
metaBox.add(viewerrors.actor);
|
||||||
viewerrors._isShowing = false;
|
|
||||||
viewerrors.connect('clicked', Lang.bind(this, this._onViewErrors));
|
|
||||||
metaBox.add(viewerrors);
|
|
||||||
|
|
||||||
return box;
|
return box;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const LookingGlass = new Lang.Class({
|
function LookingGlass() {
|
||||||
Name: 'LookingGlass',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
LookingGlass.prototype = {
|
||||||
_init : function() {
|
_init : function() {
|
||||||
this._borderPaintTarget = null;
|
this._borderPaintTarget = null;
|
||||||
this._redBorderEffect = new RedBorderEffect();
|
this._borderPaintId = 0;
|
||||||
|
this._borderDestroyId = 0;
|
||||||
|
|
||||||
this._open = false;
|
this._open = false;
|
||||||
|
|
||||||
@@ -845,8 +889,7 @@ const LookingGlass = new Lang.Class({
|
|||||||
this.actor = new St.BoxLayout({ name: 'LookingGlassDialog',
|
this.actor = new St.BoxLayout({ name: 'LookingGlassDialog',
|
||||||
style_class: 'lg-dialog',
|
style_class: 'lg-dialog',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
visible: false,
|
visible: false });
|
||||||
reactive: true });
|
|
||||||
this.actor.connect('key-press-event', Lang.bind(this, this._globalKeyPressEvent));
|
this.actor.connect('key-press-event', Lang.bind(this, this._globalKeyPressEvent));
|
||||||
|
|
||||||
this._interfaceSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
|
this._interfaceSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
|
||||||
@@ -862,7 +905,7 @@ const LookingGlass = new Lang.Class({
|
|||||||
Main.layoutManager.keyboardBox.connect('allocation-changed',
|
Main.layoutManager.keyboardBox.connect('allocation-changed',
|
||||||
Lang.bind(this, this._queueResize));
|
Lang.bind(this, this._queueResize));
|
||||||
|
|
||||||
this._objInspector = new ObjInspector(this);
|
this._objInspector = new ObjInspector();
|
||||||
Main.uiGroup.add_actor(this._objInspector.actor);
|
Main.uiGroup.add_actor(this._objInspector.actor);
|
||||||
this._objInspector.actor.hide();
|
this._objInspector.actor.hide();
|
||||||
|
|
||||||
@@ -874,7 +917,7 @@ const LookingGlass = new Lang.Class({
|
|||||||
toolbar.add_actor(inspectIcon);
|
toolbar.add_actor(inspectIcon);
|
||||||
inspectIcon.reactive = true;
|
inspectIcon.reactive = true;
|
||||||
inspectIcon.connect('button-press-event', Lang.bind(this, function () {
|
inspectIcon.connect('button-press-event', Lang.bind(this, function () {
|
||||||
let inspector = new Inspector(this);
|
let inspector = new Inspector();
|
||||||
inspector.connect('target', Lang.bind(this, function(i, target, stageX, stageY) {
|
inspector.connect('target', Lang.bind(this, function(i, target, stageX, stageY) {
|
||||||
this._pushResult('<inspect x:' + stageX + ' y:' + stageY + '>',
|
this._pushResult('<inspect x:' + stageX + ' y:' + stageY + '>',
|
||||||
target);
|
target);
|
||||||
@@ -904,16 +947,23 @@ const LookingGlass = new Lang.Class({
|
|||||||
this._entryArea = new St.BoxLayout({ name: 'EntryArea' });
|
this._entryArea = new St.BoxLayout({ name: 'EntryArea' });
|
||||||
this._evalBox.add_actor(this._entryArea);
|
this._evalBox.add_actor(this._entryArea);
|
||||||
|
|
||||||
let label = new St.Label({ text: CHEVRON });
|
let label = new St.Label({ text: 'js>>> ' });
|
||||||
this._entryArea.add(label);
|
this._entryArea.add(label);
|
||||||
|
|
||||||
this._entry = new St.Entry({ can_focus: true });
|
this._entry = new St.Entry({ can_focus: true });
|
||||||
ShellEntry.addContextMenu(this._entry);
|
ShellEntry.addContextMenu(this._entry);
|
||||||
this._entryArea.add(this._entry, { expand: true });
|
this._entryArea.add(this._entry, { expand: true });
|
||||||
|
|
||||||
this._windowList = new WindowList(this);
|
this._windowList = new WindowList();
|
||||||
|
this._windowList.connect('selected', Lang.bind(this, function(list, window) {
|
||||||
|
notebook.selectIndex(0);
|
||||||
|
this._pushResult('<window selection>', window);
|
||||||
|
}));
|
||||||
notebook.appendPage('Windows', this._windowList.actor);
|
notebook.appendPage('Windows', this._windowList.actor);
|
||||||
|
|
||||||
|
this._errorLog = new ErrorLog();
|
||||||
|
notebook.appendPage('Errors', this._errorLog.actor);
|
||||||
|
|
||||||
this._memory = new Memory();
|
this._memory = new Memory();
|
||||||
notebook.appendPage('Memory', this._memory.actor);
|
notebook.appendPage('Memory', this._memory.actor);
|
||||||
|
|
||||||
@@ -965,22 +1015,23 @@ const LookingGlass = new Lang.Class({
|
|||||||
+ 'font-family: "' + fontDesc.get_family() + '";';
|
+ 'font-family: "' + fontDesc.get_family() + '";';
|
||||||
},
|
},
|
||||||
|
|
||||||
setBorderPaintTarget: function(obj) {
|
|
||||||
if (this._borderPaintTarget != null)
|
|
||||||
this._borderPaintTarget.remove_effect(this._redBorderEffect);
|
|
||||||
this._borderPaintTarget = obj;
|
|
||||||
if (this._borderPaintTarget != null)
|
|
||||||
this._borderPaintTarget.add_effect(this._redBorderEffect);
|
|
||||||
},
|
|
||||||
|
|
||||||
_pushResult: function(command, obj) {
|
_pushResult: function(command, obj) {
|
||||||
let index = this._results.length + this._offset;
|
let index = this._results.length + this._offset;
|
||||||
let result = new Result(this, CHEVRON + command, obj, index);
|
let result = new Result('>>> ' + command, obj, index);
|
||||||
this._results.push(result);
|
this._results.push(result);
|
||||||
this._resultsArea.add(result.actor);
|
this._resultsArea.add(result.actor);
|
||||||
if (obj instanceof Clutter.Actor)
|
if (this._borderPaintTarget != null) {
|
||||||
this.setBorderPaintTarget(obj);
|
this._borderPaintTarget.disconnect(this._borderPaintId);
|
||||||
|
this._borderPaintTarget = null;
|
||||||
|
}
|
||||||
|
if (obj instanceof Clutter.Actor) {
|
||||||
|
this._borderPaintTarget = obj;
|
||||||
|
this._borderPaintId = addBorderPaintHook(obj);
|
||||||
|
this._borderDestroyId = obj.connect('destroy', Lang.bind(this, function () {
|
||||||
|
this._borderDestroyId = 0;
|
||||||
|
this._borderPaintTarget = null;
|
||||||
|
}));
|
||||||
|
}
|
||||||
let children = this._resultsArea.get_children();
|
let children = this._resultsArea.get_children();
|
||||||
if (children.length > this._maxItems) {
|
if (children.length > this._maxItems) {
|
||||||
this._results.shift();
|
this._results.shift();
|
||||||
@@ -1008,7 +1059,7 @@ const LookingGlass = new Lang.Class({
|
|||||||
actor.add(padBin);
|
actor.add(padBin);
|
||||||
|
|
||||||
this._completionActor = actor;
|
this._completionActor = actor;
|
||||||
this._evalBox.insert_child_below(this._completionActor, this._entryArea);
|
this._evalBox.insert_before(this._completionActor, this._entryArea);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._completionText.set_text(completions.join(', '));
|
this._completionText.set_text(completions.join(', '));
|
||||||
@@ -1110,7 +1161,7 @@ const LookingGlass = new Lang.Class({
|
|||||||
// Handle key events which are relevant for all tabs of the LookingGlass
|
// Handle key events which are relevant for all tabs of the LookingGlass
|
||||||
_globalKeyPressEvent : function(actor, event) {
|
_globalKeyPressEvent : function(actor, event) {
|
||||||
let symbol = event.get_key_symbol();
|
let symbol = event.get_key_symbol();
|
||||||
let modifierState = event.get_state();
|
let modifierState = Shell.get_event_state(event);
|
||||||
if (symbol == Clutter.Escape) {
|
if (symbol == Clutter.Escape) {
|
||||||
if (this._objInspector.actor.visible) {
|
if (this._objInspector.actor.visible) {
|
||||||
this._objInspector.close();
|
this._objInspector.close();
|
||||||
@@ -1161,7 +1212,11 @@ const LookingGlass = new Lang.Class({
|
|||||||
this._open = false;
|
this._open = false;
|
||||||
Tweener.removeTweens(this.actor);
|
Tweener.removeTweens(this.actor);
|
||||||
|
|
||||||
this.setBorderPaintTarget(null);
|
if (this._borderPaintTarget != null) {
|
||||||
|
this._borderPaintTarget.disconnect(this._borderPaintId);
|
||||||
|
this._borderPaintTarget.disconnect(this._borderDestroyId);
|
||||||
|
this._borderPaintTarget = null;
|
||||||
|
}
|
||||||
|
|
||||||
Main.popModal(this._entry);
|
Main.popModal(this._entry);
|
||||||
|
|
||||||
@@ -1173,5 +1228,5 @@ const LookingGlass = new Lang.Class({
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(LookingGlass.prototype);
|
Signals.addSignalMethods(LookingGlass.prototype);
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ const Params = imports.misc.params;
|
|||||||
|
|
||||||
const MOUSE_POLL_FREQUENCY = 50;
|
const MOUSE_POLL_FREQUENCY = 50;
|
||||||
const CROSSHAIRS_CLIP_SIZE = [100, 100];
|
const CROSSHAIRS_CLIP_SIZE = [100, 100];
|
||||||
const NO_CHANGE = 0.0;
|
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
const APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
|
const APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
|
||||||
@@ -25,14 +24,6 @@ const SHOW_KEY = 'screen-magnifier-enabled';
|
|||||||
const MAGNIFIER_SCHEMA = 'org.gnome.desktop.a11y.magnifier';
|
const MAGNIFIER_SCHEMA = 'org.gnome.desktop.a11y.magnifier';
|
||||||
const SCREEN_POSITION_KEY = 'screen-position';
|
const SCREEN_POSITION_KEY = 'screen-position';
|
||||||
const MAG_FACTOR_KEY = 'mag-factor';
|
const MAG_FACTOR_KEY = 'mag-factor';
|
||||||
const INVERT_LIGHTNESS_KEY = 'invert-lightness';
|
|
||||||
const COLOR_SATURATION_KEY = 'color-saturation';
|
|
||||||
const BRIGHT_RED_KEY = 'brightness-red';
|
|
||||||
const BRIGHT_GREEN_KEY = 'brightness-green';
|
|
||||||
const BRIGHT_BLUE_KEY = 'brightness-blue';
|
|
||||||
const CONTRAST_RED_KEY = 'contrast-red';
|
|
||||||
const CONTRAST_GREEN_KEY = 'contrast-green';
|
|
||||||
const CONTRAST_BLUE_KEY = 'contrast-blue';
|
|
||||||
const LENS_MODE_KEY = 'lens-mode';
|
const LENS_MODE_KEY = 'lens-mode';
|
||||||
const CLAMP_MODE_KEY = 'scroll-at-edges';
|
const CLAMP_MODE_KEY = 'scroll-at-edges';
|
||||||
const MOUSE_TRACKING_KEY = 'mouse-tracking';
|
const MOUSE_TRACKING_KEY = 'mouse-tracking';
|
||||||
@@ -45,15 +36,17 @@ const CROSS_HAIRS_CLIP_KEY = 'cross-hairs-clip';
|
|||||||
|
|
||||||
let magDBusService = null;
|
let magDBusService = null;
|
||||||
|
|
||||||
const Magnifier = new Lang.Class({
|
function Magnifier() {
|
||||||
Name: 'Magnifier',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
Magnifier.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
// Magnifier is a manager of ZoomRegions.
|
// Magnifier is a manager of ZoomRegions.
|
||||||
this._zoomRegions = [];
|
this._zoomRegions = [];
|
||||||
|
|
||||||
// Create small clutter tree for the magnified mouse.
|
// Create small clutter tree for the magnified mouse.
|
||||||
let xfixesCursor = Shell.XFixesCursor.get_for_stage(global.stage);
|
let xfixesCursor = Shell.XFixesCursor.get_default();
|
||||||
this._mouseSprite = new Clutter.Texture();
|
this._mouseSprite = new Clutter.Texture();
|
||||||
xfixesCursor.update_texture_image(this._mouseSprite);
|
xfixesCursor.update_texture_image(this._mouseSprite);
|
||||||
this._cursorRoot = new Clutter.Group();
|
this._cursorRoot = new Clutter.Group();
|
||||||
@@ -452,25 +445,6 @@ const Magnifier = new Lang.Class({
|
|||||||
aPref = this._settings.get_enum(MOUSE_TRACKING_KEY);
|
aPref = this._settings.get_enum(MOUSE_TRACKING_KEY);
|
||||||
if (aPref)
|
if (aPref)
|
||||||
zoomRegion.setMouseTrackingMode(aPref);
|
zoomRegion.setMouseTrackingMode(aPref);
|
||||||
|
|
||||||
aPref = this._settings.get_boolean(INVERT_LIGHTNESS_KEY);
|
|
||||||
if (aPref)
|
|
||||||
zoomRegion.setInvertLightness(aPref);
|
|
||||||
|
|
||||||
aPref = this._settings.get_double(COLOR_SATURATION_KEY);
|
|
||||||
if (aPref)
|
|
||||||
zoomRegion.setColorSaturation(aPref);
|
|
||||||
|
|
||||||
let bc = {};
|
|
||||||
bc.r = this._settings.get_double(BRIGHT_RED_KEY);
|
|
||||||
bc.g = this._settings.get_double(BRIGHT_GREEN_KEY);
|
|
||||||
bc.b = this._settings.get_double(BRIGHT_BLUE_KEY);
|
|
||||||
zoomRegion.setBrightness(bc);
|
|
||||||
|
|
||||||
bc.r = this._settings.get_double(CONTRAST_RED_KEY);
|
|
||||||
bc.g = this._settings.get_double(CONTRAST_GREEN_KEY);
|
|
||||||
bc.b = this._settings.get_double(CONTRAST_BLUE_KEY);
|
|
||||||
zoomRegion.setContrast(bc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let showCrosshairs = this._settings.get_boolean(SHOW_CROSS_HAIRS_KEY);
|
let showCrosshairs = this._settings.get_boolean(SHOW_CROSS_HAIRS_KEY);
|
||||||
@@ -493,25 +467,6 @@ const Magnifier = new Lang.Class({
|
|||||||
this._settings.connect('changed::' + MOUSE_TRACKING_KEY,
|
this._settings.connect('changed::' + MOUSE_TRACKING_KEY,
|
||||||
Lang.bind(this, this._updateMouseTrackingMode));
|
Lang.bind(this, this._updateMouseTrackingMode));
|
||||||
|
|
||||||
this._settings.connect('changed::' + INVERT_LIGHTNESS_KEY,
|
|
||||||
Lang.bind(this, this._updateInvertLightness));
|
|
||||||
this._settings.connect('changed::' + COLOR_SATURATION_KEY,
|
|
||||||
Lang.bind(this, this._updateColorSaturation));
|
|
||||||
|
|
||||||
this._settings.connect('changed::' + BRIGHT_RED_KEY,
|
|
||||||
Lang.bind(this, this._updateBrightness));
|
|
||||||
this._settings.connect('changed::' + BRIGHT_GREEN_KEY,
|
|
||||||
Lang.bind(this, this._updateBrightness));
|
|
||||||
this._settings.connect('changed::' + BRIGHT_BLUE_KEY,
|
|
||||||
Lang.bind(this, this._updateBrightness));
|
|
||||||
|
|
||||||
this._settings.connect('changed::' + CONTRAST_RED_KEY,
|
|
||||||
Lang.bind(this, this._updateContrast));
|
|
||||||
this._settings.connect('changed::' + CONTRAST_GREEN_KEY,
|
|
||||||
Lang.bind(this, this._updateContrast));
|
|
||||||
this._settings.connect('changed::' + CONTRAST_BLUE_KEY,
|
|
||||||
Lang.bind(this, this._updateContrast));
|
|
||||||
|
|
||||||
this._settings.connect('changed::' + SHOW_CROSS_HAIRS_KEY,
|
this._settings.connect('changed::' + SHOW_CROSS_HAIRS_KEY,
|
||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
this.setCrosshairsVisible(this._settings.get_boolean(SHOW_CROSS_HAIRS_KEY));
|
this.setCrosshairsVisible(this._settings.get_boolean(SHOW_CROSS_HAIRS_KEY));
|
||||||
@@ -587,53 +542,15 @@ const Magnifier = new Lang.Class({
|
|||||||
this._settings.get_enum(MOUSE_TRACKING_KEY)
|
this._settings.get_enum(MOUSE_TRACKING_KEY)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
_updateInvertLightness: function() {
|
|
||||||
// Applies only to the first zoom region.
|
|
||||||
if (this._zoomRegions.length) {
|
|
||||||
this._zoomRegions[0].setInvertLightness(
|
|
||||||
this._settings.get_boolean(INVERT_LIGHTNESS_KEY)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
|
|
||||||
_updateColorSaturation: function() {
|
|
||||||
// Applies only to the first zoom region.
|
|
||||||
if (this._zoomRegions.length) {
|
|
||||||
this._zoomRegions[0].setColorSaturation(
|
|
||||||
this._settings.get_double(COLOR_SATURATION_KEY)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateBrightness: function() {
|
|
||||||
// Applies only to the first zoom region.
|
|
||||||
if (this._zoomRegions.length) {
|
|
||||||
let brightness = {};
|
|
||||||
brightness.r = this._settings.get_double(BRIGHT_RED_KEY);
|
|
||||||
brightness.g = this._settings.get_double(BRIGHT_GREEN_KEY);
|
|
||||||
brightness.b = this._settings.get_double(BRIGHT_BLUE_KEY);
|
|
||||||
this._zoomRegions[0].setBrightness(brightness);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateContrast: function() {
|
|
||||||
// Applies only to the first zoom region.
|
|
||||||
if (this._zoomRegions.length) {
|
|
||||||
let contrast = {};
|
|
||||||
contrast.r = this._settings.get_double(CONTRAST_RED_KEY);
|
|
||||||
contrast.g = this._settings.get_double(CONTRAST_GREEN_KEY);
|
|
||||||
contrast.b = this._settings.get_double(CONTRAST_BLUE_KEY);
|
|
||||||
this._zoomRegions[0].setContrast(contrast);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
Signals.addSignalMethods(Magnifier.prototype);
|
Signals.addSignalMethods(Magnifier.prototype);
|
||||||
|
|
||||||
const ZoomRegion = new Lang.Class({
|
function ZoomRegion(magnifier, mouseSourceActor) {
|
||||||
Name: 'ZoomRegion',
|
this._init(magnifier, mouseSourceActor);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZoomRegion.prototype = {
|
||||||
_init: function(magnifier, mouseSourceActor) {
|
_init: function(magnifier, mouseSourceActor) {
|
||||||
this._magnifier = magnifier;
|
this._magnifier = magnifier;
|
||||||
|
|
||||||
@@ -641,13 +558,8 @@ const ZoomRegion = new Lang.Class({
|
|||||||
this._clampScrollingAtEdges = false;
|
this._clampScrollingAtEdges = false;
|
||||||
this._lensMode = false;
|
this._lensMode = false;
|
||||||
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN;
|
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN;
|
||||||
this._invertLightness = false;
|
|
||||||
this._colorSaturation = 1.0;
|
|
||||||
this._brightness = { r: NO_CHANGE, g: NO_CHANGE, b: NO_CHANGE };
|
|
||||||
this._contrast = { r: NO_CHANGE, g: NO_CHANGE, b: NO_CHANGE };
|
|
||||||
|
|
||||||
this._magView = null;
|
this._magView = null;
|
||||||
this._background = null;
|
|
||||||
this._uiGroupClone = null;
|
this._uiGroupClone = null;
|
||||||
this._mouseSourceActor = mouseSourceActor;
|
this._mouseSourceActor = mouseSourceActor;
|
||||||
this._mouseActor = null;
|
this._mouseActor = null;
|
||||||
@@ -657,15 +569,12 @@ const ZoomRegion = new Lang.Class({
|
|||||||
this._viewPortX = 0;
|
this._viewPortX = 0;
|
||||||
this._viewPortY = 0;
|
this._viewPortY = 0;
|
||||||
this._viewPortWidth = global.screen_width;
|
this._viewPortWidth = global.screen_width;
|
||||||
this._viewPortHeight = global.screen_height;
|
this._viewPortWidth = global.screen_height;
|
||||||
this._xCenter = this._viewPortWidth / 2;
|
this._xCenter = this._viewPortWidth / 2;
|
||||||
this._yCenter = this._viewPortHeight / 2;
|
this._yCenter = this._viewPortHeight / 2;
|
||||||
this._xMagFactor = 1;
|
this._xMagFactor = 1;
|
||||||
this._yMagFactor = 1;
|
this._yMagFactor = 1;
|
||||||
this._followingCursor = false;
|
this._followingCursor = false;
|
||||||
|
|
||||||
Main.layoutManager.connect('monitors-changed',
|
|
||||||
Lang.bind(this, this._monitorsChanged));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -970,107 +879,6 @@ const ZoomRegion = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* setInvertLightness:
|
|
||||||
* Set whether to invert the lightness of the magnified view.
|
|
||||||
* @flag Boolean to either invert brightness (true), or not (false).
|
|
||||||
*/
|
|
||||||
setInvertLightness: function(flag) {
|
|
||||||
this._invertLightness = flag;
|
|
||||||
if (this._magShaderEffects)
|
|
||||||
this._magShaderEffects.setInvertLightness(this._invertLightness);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* getInvertLightness:
|
|
||||||
* Retrieve whether the lightness is inverted.
|
|
||||||
* @return Boolean indicating inversion (true), or not (false).
|
|
||||||
*/
|
|
||||||
getInvertLightness: function() {
|
|
||||||
return this._invertLightness;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* setColorSaturation:
|
|
||||||
* Set the color saturation of the magnified view.
|
|
||||||
* @sauration A value from 0.0 to 1.0 that defines the color
|
|
||||||
* saturation, with 0.0 defining no color (grayscale),
|
|
||||||
* and 1.0 defining full color.
|
|
||||||
*/
|
|
||||||
setColorSaturation: function(saturation) {
|
|
||||||
this._colorSaturation = saturation;
|
|
||||||
if (this._magShaderEffects)
|
|
||||||
this._magShaderEffects.setColorSaturation(this._colorSaturation);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* getColorSaturation:
|
|
||||||
* Retrieve the color saturation of the magnified view.
|
|
||||||
*/
|
|
||||||
getColorSaturation: function() {
|
|
||||||
return this._colorSaturation;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* setBrightness:
|
|
||||||
* Alter the brightness of the magnified view.
|
|
||||||
* @brightness Object containing the contrast for the red, green,
|
|
||||||
* and blue channels. Values of 0.0 represent "standard"
|
|
||||||
* brightness (no change), whereas values less or greater than
|
|
||||||
* 0.0 indicate decreased or incresaed brightness, respectively.
|
|
||||||
*/
|
|
||||||
setBrightness: function(brightness) {
|
|
||||||
this._brightness.r = brightness.r;
|
|
||||||
this._brightness.g = brightness.g;
|
|
||||||
this._brightness.b = brightness.b;
|
|
||||||
if (this._magShaderEffects)
|
|
||||||
this._magShaderEffects.setBrightness(this._brightness);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* getBrightness:
|
|
||||||
* Retrive the current brightness of the Zoom Region.
|
|
||||||
* @return Object containing the brightness change for the red, green,
|
|
||||||
* and blue channels.
|
|
||||||
*/
|
|
||||||
getBrightness: function() {
|
|
||||||
let brightness = {};
|
|
||||||
brightness.r = this._brightness.r;
|
|
||||||
brightness.g = this._brightness.g;
|
|
||||||
brightness.b = this._brightness.b;
|
|
||||||
return brightness;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* setContrast:
|
|
||||||
* Alter the contrast of the magnified view.
|
|
||||||
* @contrast Object containing the contrast for the red, green,
|
|
||||||
* and blue channels. Values of 0.0 represent "standard"
|
|
||||||
* contrast (no change), whereas values less or greater than
|
|
||||||
* 0.0 indicate decreased or incresaed contrast, respectively.
|
|
||||||
*/
|
|
||||||
setContrast: function(contrast) {
|
|
||||||
this._contrast.r = contrast.r;
|
|
||||||
this._contrast.g = contrast.g;
|
|
||||||
this._contrast.b = contrast.b;
|
|
||||||
if (this._magShaderEffects)
|
|
||||||
this._magShaderEffects.setContrast(this._contrast);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* getContrast:
|
|
||||||
* Retreive the contrast of the magnified view.
|
|
||||||
* @return Object containing the contrast for the red, green,
|
|
||||||
* and blue channels.
|
|
||||||
*/
|
|
||||||
getContrast: function() {
|
|
||||||
let contrast = {};
|
|
||||||
contrast.r = this._contrast.r;
|
|
||||||
contrast.g = this._contrast.g;
|
|
||||||
contrast.b = this._contrast.b;
|
|
||||||
return contrast;
|
|
||||||
},
|
|
||||||
|
|
||||||
//// Private methods ////
|
//// Private methods ////
|
||||||
|
|
||||||
_createActors: function() {
|
_createActors: function() {
|
||||||
@@ -1087,15 +895,15 @@ const ZoomRegion = new Lang.Class({
|
|||||||
|
|
||||||
// Add a background for when the magnified uiGroup is scrolled
|
// Add a background for when the magnified uiGroup is scrolled
|
||||||
// out of view (don't want to see desktop showing through).
|
// out of view (don't want to see desktop showing through).
|
||||||
this._background = new Clutter.Rectangle({ color: Main.DEFAULT_BACKGROUND_COLOR });
|
let background = new Clutter.Rectangle({ color: Main.DEFAULT_BACKGROUND_COLOR });
|
||||||
mainGroup.add_actor(this._background);
|
mainGroup.add_actor(background);
|
||||||
|
|
||||||
// Clone the group that contains all of UI on the screen. This is the
|
// Clone the group that contains all of UI on the screen. This is the
|
||||||
// chrome, the windows, etc.
|
// chrome, the windows, etc.
|
||||||
this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup });
|
this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup });
|
||||||
mainGroup.add_actor(this._uiGroupClone);
|
mainGroup.add_actor(this._uiGroupClone);
|
||||||
Main.uiGroup.set_size(global.screen_width, global.screen_height);
|
Main.uiGroup.set_size(global.screen_width, global.screen_height);
|
||||||
this._background.set_size(global.screen_width, global.screen_height);
|
background.set_size(global.screen_width, global.screen_height);
|
||||||
|
|
||||||
// Add either the given mouseSourceActor to the ZoomRegion, or a clone of
|
// Add either the given mouseSourceActor to the ZoomRegion, or a clone of
|
||||||
// it.
|
// it.
|
||||||
@@ -1109,13 +917,6 @@ const ZoomRegion = new Lang.Class({
|
|||||||
this._crossHairsActor = this._crossHairs.addToZoomRegion(this, this._mouseActor);
|
this._crossHairsActor = this._crossHairs.addToZoomRegion(this, this._mouseActor);
|
||||||
else
|
else
|
||||||
this._crossHairsActor = null;
|
this._crossHairsActor = null;
|
||||||
|
|
||||||
// Contrast and brightness effects.
|
|
||||||
this._magShaderEffects = new MagShaderEffects(this._uiGroupClone);
|
|
||||||
this._magShaderEffects.setColorSaturation(this._colorSaturation);
|
|
||||||
this._magShaderEffects.setInvertLightness(this._invertLightness);
|
|
||||||
this._magShaderEffects.setBrightness(this._brightness);
|
|
||||||
this._magShaderEffects.setContrast(this._contrast);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_destroyActors: function() {
|
_destroyActors: function() {
|
||||||
@@ -1124,11 +925,8 @@ const ZoomRegion = new Lang.Class({
|
|||||||
if (this._crossHairs)
|
if (this._crossHairs)
|
||||||
this._crossHairs.removeFromParent(this._crossHairsActor);
|
this._crossHairs.removeFromParent(this._crossHairsActor);
|
||||||
|
|
||||||
this._magShaderEffects.destroyEffects();
|
|
||||||
this._magShaderEffects = null;
|
|
||||||
this._magView.destroy();
|
this._magView.destroy();
|
||||||
this._magView = null;
|
this._magView = null;
|
||||||
this._background = null;
|
|
||||||
this._uiGroupClone = null;
|
this._uiGroupClone = null;
|
||||||
this._mouseActor = null;
|
this._mouseActor = null;
|
||||||
this._crossHairsActor = null;
|
this._crossHairsActor = null;
|
||||||
@@ -1351,28 +1149,14 @@ const ZoomRegion = new Lang.Class({
|
|||||||
this._crossHairsActor.set_position(xMagMouse - groupWidth / 2,
|
this._crossHairsActor.set_position(xMagMouse - groupWidth / 2,
|
||||||
yMagMouse - groupHeight / 2);
|
yMagMouse - groupHeight / 2);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
_monitorsChanged: function() {
|
|
||||||
if (!this.isActive())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Main.uiGroup.set_size(global.screen_width, global.screen_height);
|
|
||||||
this._background.set_size(global.screen_width, global.screen_height);
|
|
||||||
|
|
||||||
if (this._screenPosition == GDesktopEnums.MagnifierScreenPosition.NONE)
|
|
||||||
this._setViewPort({ x: this._viewPortX,
|
|
||||||
y: this._viewPortY,
|
|
||||||
width: this._viewPortWidth,
|
|
||||||
height: this._viewPortHeight });
|
|
||||||
else
|
|
||||||
this.setScreenPosition(this._screenPosition);
|
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const Crosshairs = new Lang.Class({
|
function Crosshairs() {
|
||||||
Name: 'Crosshairs',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
Crosshairs.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
|
|
||||||
// Set the group containing the crosshairs to three times the desktop
|
// Set the group containing the crosshairs to three times the desktop
|
||||||
@@ -1397,14 +1181,6 @@ const Crosshairs = new Lang.Class({
|
|||||||
this._clipSize = [0, 0];
|
this._clipSize = [0, 0];
|
||||||
this._clones = [];
|
this._clones = [];
|
||||||
this.reCenter();
|
this.reCenter();
|
||||||
|
|
||||||
Main.layoutManager.connect('monitors-changed',
|
|
||||||
Lang.bind(this, this._monitorsChanged));
|
|
||||||
},
|
|
||||||
|
|
||||||
_monitorsChanged: function() {
|
|
||||||
this._actor.set_size(global.screen_width * 3, global.screen_height * 3);
|
|
||||||
this.reCenter();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1429,7 +1205,10 @@ const Crosshairs = new Lang.Class({
|
|||||||
crosshairsActor = new Clutter.Clone({ source: this._actor });
|
crosshairsActor = new Clutter.Clone({ source: this._actor });
|
||||||
this._clones.push(crosshairsActor);
|
this._clones.push(crosshairsActor);
|
||||||
}
|
}
|
||||||
crosshairsActor.visible = this._actor.visible;
|
if (this._actor.visible)
|
||||||
|
crosshairsActor.show();
|
||||||
|
else
|
||||||
|
crosshairsActor.hide();
|
||||||
|
|
||||||
container.add_actor(crosshairsActor);
|
container.add_actor(crosshairsActor);
|
||||||
container.raise_child(magnifiedMouse, crosshairsActor);
|
container.raise_child(magnifiedMouse, crosshairsActor);
|
||||||
@@ -1633,145 +1412,4 @@ const Crosshairs = new Lang.Class({
|
|||||||
this._vertTopHair.set_position((groupWidth - thickness) / 2, top);
|
this._vertTopHair.set_position((groupWidth - thickness) / 2, top);
|
||||||
this._vertBottomHair.set_position((groupWidth - thickness) / 2, bottom);
|
this._vertBottomHair.set_position((groupWidth - thickness) / 2, bottom);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const MagShaderEffects = new Lang.Class({
|
|
||||||
Name: 'MagShaderEffects',
|
|
||||||
|
|
||||||
_init: function(uiGroupClone) {
|
|
||||||
this._inverse = new Shell.InvertLightnessEffect();
|
|
||||||
this._brightnessContrast = new Clutter.BrightnessContrastEffect();
|
|
||||||
this._colorDesaturation = new Clutter.DesaturateEffect();
|
|
||||||
this._inverse.set_enabled(false);
|
|
||||||
this._brightnessContrast.set_enabled(false);
|
|
||||||
|
|
||||||
this._magView = uiGroupClone;
|
|
||||||
this._magView.add_effect(this._inverse);
|
|
||||||
this._magView.add_effect(this._brightnessContrast);
|
|
||||||
this._magView.add_effect(this._colorDesaturation);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* destroyEffects:
|
|
||||||
* Remove contrast and brightness effects from the magnified view, and
|
|
||||||
* lose the reference to the actor they were applied to. Don't use this
|
|
||||||
* object after calling this.
|
|
||||||
*/
|
|
||||||
destroyEffects: function() {
|
|
||||||
this._magView.clear_effects();
|
|
||||||
this._colorDesaturation = null;
|
|
||||||
this._brightnessContrast = null;
|
|
||||||
this._inverse = null;
|
|
||||||
this._magView = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* setInvertLightness:
|
|
||||||
* Enable/disable invert lightness effect.
|
|
||||||
* @invertFlag: Enabled flag.
|
|
||||||
*/
|
|
||||||
setInvertLightness: function(invertFlag) {
|
|
||||||
this._inverse.set_enabled(invertFlag);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* getInvertLightness:
|
|
||||||
* Report whether the inversion effect is enabled.
|
|
||||||
* @return: Boolean.
|
|
||||||
*/
|
|
||||||
getInvertLightness: function() {
|
|
||||||
return this._inverse.get_enabled();
|
|
||||||
},
|
|
||||||
|
|
||||||
setColorSaturation: function(factor) {
|
|
||||||
this._colorDesaturation.set_factor(1.0 - factor);
|
|
||||||
},
|
|
||||||
|
|
||||||
getColorSaturation: function() {
|
|
||||||
return 1.0 - this._colorDesaturation.get_factor();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* setBrightness:
|
|
||||||
* Set the brightness of the magnified view.
|
|
||||||
* @brightness: Object containing the brightness for the red, green,
|
|
||||||
* and blue channels. Values of 0.0 represent "standard"
|
|
||||||
* brightness (no change), whereas values less or greater than
|
|
||||||
* 0.0 indicate decreased or incresaed brightness,
|
|
||||||
* respectively.
|
|
||||||
*/
|
|
||||||
setBrightness: function(brightness) {
|
|
||||||
let bRed = brightness.r;
|
|
||||||
let bGreen = brightness.g;
|
|
||||||
let bBlue = brightness.b;
|
|
||||||
this._brightnessContrast.set_brightness_full(bRed, bGreen, bBlue);
|
|
||||||
|
|
||||||
// Enable the effect if the brightness OR contrast change are such that
|
|
||||||
// it modifies the brightness and/or contrast.
|
|
||||||
let [cRed, cGreen, cBlue] = this._brightnessContrast.get_contrast();
|
|
||||||
this._brightnessContrast.set_enabled(
|
|
||||||
(bRed != NO_CHANGE || bGreen != NO_CHANGE || bBlue != NO_CHANGE ||
|
|
||||||
cRed != NO_CHANGE || cGreen != NO_CHANGE || cBlue != NO_CHANGE)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* getBrightness:
|
|
||||||
* Retrieve current brightness of the magnified view.
|
|
||||||
* @return: Object containing the brightness for the red, green,
|
|
||||||
* and blue channels. Values of 0.0 represent "standard"
|
|
||||||
* brightness (no change), whereas values less or greater than
|
|
||||||
* 0.0 indicate decreased or incresaed brightness, respectively.
|
|
||||||
*/
|
|
||||||
getBrightness: function() {
|
|
||||||
let result = {};
|
|
||||||
let [bRed, bGreen, bBlue] = this._brightnessContrast.get_brightness();
|
|
||||||
result.r = bRed;
|
|
||||||
result.g = bGreen;
|
|
||||||
result.b = bBlue;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the contrast of the magnified view.
|
|
||||||
* @contrast: Object containing the contrast for the red, green,
|
|
||||||
* and blue channels. Values of 0.0 represent "standard"
|
|
||||||
* contrast (no change), whereas values less or greater than
|
|
||||||
* 0.0 indicate decreased or incresaed contrast, respectively.
|
|
||||||
*/
|
|
||||||
setContrast: function(contrast) {
|
|
||||||
let cRed = contrast.r;
|
|
||||||
let cGreen = contrast.g;
|
|
||||||
let cBlue = contrast.b;
|
|
||||||
|
|
||||||
this._brightnessContrast.set_contrast_full(cRed, cGreen, cBlue);
|
|
||||||
|
|
||||||
// Enable the effect if the contrast OR brightness change are such that
|
|
||||||
// it modifies the brightness and/or contrast.
|
|
||||||
// should be able to use Clutter.color_equal(), but that complains of
|
|
||||||
// a null first argument.
|
|
||||||
let [bRed, bGreen, bBlue] = this._brightnessContrast.get_brightness();
|
|
||||||
this._brightnessContrast.set_enabled(
|
|
||||||
cRed != NO_CHANGE || cGreen != NO_CHANGE || cBlue != NO_CHANGE ||
|
|
||||||
bRed != NO_CHANGE || bGreen != NO_CHANGE || bBlue != NO_CHANGE
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve current contrast of the magnified view.
|
|
||||||
* @return: Object containing the contrast for the red, green,
|
|
||||||
* and blue channels. Values of 0.0 represent "standard"
|
|
||||||
* contrast (no change), whereas values less or greater than
|
|
||||||
* 0.0 indicate decreased or incresaed contrast, respectively.
|
|
||||||
*/
|
|
||||||
getContrast: function() {
|
|
||||||
let resutl = {};
|
|
||||||
let [cRed, cGreen, cBlue] = this._brightnessContrast.get_contrast();
|
|
||||||
result.r = cRed;
|
|
||||||
result.g = cGreen;
|
|
||||||
result.b = cBlue;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const Lang = imports.lang;
|
const GLib = imports.gi.GLib;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
const MAG_SERVICE_NAME = 'org.gnome.Magnifier';
|
const MAG_SERVICE_NAME = 'org.gnome.Magnifier';
|
||||||
@@ -96,9 +96,11 @@ const ZoomRegionIface = <interface name={ZOOM_SERVICE_NAME}>
|
|||||||
// '/org/gnome/Magnifier/ZoomRegion/zoomer1', etc.
|
// '/org/gnome/Magnifier/ZoomRegion/zoomer1', etc.
|
||||||
let _zoomRegionInstanceCount = 0;
|
let _zoomRegionInstanceCount = 0;
|
||||||
|
|
||||||
const ShellMagnifier = new Lang.Class({
|
function ShellMagnifier() {
|
||||||
Name: 'ShellMagnifier',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShellMagnifier.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._zoomers = {};
|
this._zoomers = {};
|
||||||
|
|
||||||
@@ -324,7 +326,7 @@ const ShellMagnifier = new Lang.Class({
|
|||||||
// Drop the leading '#'.
|
// Drop the leading '#'.
|
||||||
return parseInt(colorString.slice(1), 16);
|
return parseInt(colorString.slice(1), 16);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ShellMagnifierZoomRegion:
|
* ShellMagnifierZoomRegion:
|
||||||
@@ -332,9 +334,11 @@ const ShellMagnifier = new Lang.Class({
|
|||||||
* @zoomerObjectPath: String that is the path to a DBus ZoomRegion.
|
* @zoomerObjectPath: String that is the path to a DBus ZoomRegion.
|
||||||
* @zoomRegion: The actual zoom region associated with the object path.
|
* @zoomRegion: The actual zoom region associated with the object path.
|
||||||
*/
|
*/
|
||||||
const ShellMagnifierZoomRegion = new Lang.Class({
|
function ShellMagnifierZoomRegion(zoomerObjectPath, zoomRegion) {
|
||||||
Name: 'ShellMagnifierZoomRegion',
|
this._init(zoomerObjectPath, zoomRegion);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShellMagnifierZoomRegion.prototype = {
|
||||||
_init: function(zoomerObjectPath, zoomRegion) {
|
_init: function(zoomerObjectPath, zoomRegion) {
|
||||||
this._zoomRegion = zoomRegion;
|
this._zoomRegion = zoomRegion;
|
||||||
|
|
||||||
@@ -419,4 +423,4 @@ const ShellMagnifierZoomRegion = new Lang.Class({
|
|||||||
destroy: function() {
|
destroy: function() {
|
||||||
this._dbusImpl.unexport();
|
this._dbusImpl.unexport();
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|||||||
285
js/ui/main.js
@@ -15,10 +15,8 @@ const AutorunManager = imports.ui.autorunManager;
|
|||||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||||
const EndSessionDialog = imports.ui.endSessionDialog;
|
const EndSessionDialog = imports.ui.endSessionDialog;
|
||||||
const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent;
|
const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent;
|
||||||
const KeyringPrompt = imports.ui.keyringPrompt;
|
|
||||||
const Environment = imports.ui.environment;
|
const Environment = imports.ui.environment;
|
||||||
const ExtensionSystem = imports.ui.extensionSystem;
|
const ExtensionSystem = imports.ui.extensionSystem;
|
||||||
const ExtensionDownloader = imports.ui.extensionDownloader;
|
|
||||||
const Keyboard = imports.ui.keyboard;
|
const Keyboard = imports.ui.keyboard;
|
||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
const Overview = imports.ui.overview;
|
const Overview = imports.ui.overview;
|
||||||
@@ -30,19 +28,15 @@ const LookingGlass = imports.ui.lookingGlass;
|
|||||||
const NetworkAgent = imports.ui.networkAgent;
|
const NetworkAgent = imports.ui.networkAgent;
|
||||||
const NotificationDaemon = imports.ui.notificationDaemon;
|
const NotificationDaemon = imports.ui.notificationDaemon;
|
||||||
const WindowAttentionHandler = imports.ui.windowAttentionHandler;
|
const WindowAttentionHandler = imports.ui.windowAttentionHandler;
|
||||||
const ScreenShield = imports.ui.screenShield;
|
|
||||||
const Scripting = imports.ui.scripting;
|
const Scripting = imports.ui.scripting;
|
||||||
const SessionMode = imports.ui.sessionMode;
|
|
||||||
const ShellDBus = imports.ui.shellDBus;
|
const ShellDBus = imports.ui.shellDBus;
|
||||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
|
||||||
const TelepathyClient = imports.ui.telepathyClient;
|
const TelepathyClient = imports.ui.telepathyClient;
|
||||||
const UnlockDialog = imports.ui.unlockDialog;
|
|
||||||
const WindowManager = imports.ui.windowManager;
|
const WindowManager = imports.ui.windowManager;
|
||||||
const Magnifier = imports.ui.magnifier;
|
const Magnifier = imports.ui.magnifier;
|
||||||
const XdndHandler = imports.ui.xdndHandler;
|
const XdndHandler = imports.ui.xdndHandler;
|
||||||
|
const StatusIconDispatcher = imports.ui.statusIconDispatcher;
|
||||||
const Util = imports.misc.util;
|
const Util = imports.misc.util;
|
||||||
|
|
||||||
const OVERRIDES_SCHEMA = 'org.gnome.shell.overrides';
|
|
||||||
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
|
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
|
||||||
DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
|
DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
|
||||||
|
|
||||||
@@ -50,92 +44,73 @@ let automountManager = null;
|
|||||||
let autorunManager = null;
|
let autorunManager = null;
|
||||||
let panel = null;
|
let panel = null;
|
||||||
let hotCorners = [];
|
let hotCorners = [];
|
||||||
|
let placesManager = null;
|
||||||
let overview = null;
|
let overview = null;
|
||||||
let runDialog = null;
|
let runDialog = null;
|
||||||
let lookingGlass = null;
|
let lookingGlass = null;
|
||||||
let wm = null;
|
let wm = null;
|
||||||
let messageTray = null;
|
let messageTray = null;
|
||||||
let screenShield = null;
|
|
||||||
let notificationDaemon = null;
|
let notificationDaemon = null;
|
||||||
let windowAttentionHandler = null;
|
let windowAttentionHandler = null;
|
||||||
let telepathyClient = null;
|
let telepathyClient = null;
|
||||||
let ctrlAltTabManager = null;
|
let ctrlAltTabManager = null;
|
||||||
let recorder = null;
|
let recorder = null;
|
||||||
let sessionMode = null;
|
|
||||||
let shellDBusService = null;
|
let shellDBusService = null;
|
||||||
let shellMountOpDBusService = null;
|
|
||||||
let screenSaverDBus = null;
|
|
||||||
let modalCount = 0;
|
let modalCount = 0;
|
||||||
let modalActorFocusStack = [];
|
let modalActorFocusStack = [];
|
||||||
let uiGroup = null;
|
let uiGroup = null;
|
||||||
let magnifier = null;
|
let magnifier = null;
|
||||||
let xdndHandler = null;
|
let xdndHandler = null;
|
||||||
|
let statusIconDispatcher = null;
|
||||||
let keyboard = null;
|
let keyboard = null;
|
||||||
let layoutManager = null;
|
let layoutManager = null;
|
||||||
let networkAgent = null;
|
let networkAgent = null;
|
||||||
|
let _errorLogStack = [];
|
||||||
let _startDate;
|
let _startDate;
|
||||||
let _defaultCssStylesheet = null;
|
let _defaultCssStylesheet = null;
|
||||||
let _cssStylesheet = null;
|
let _cssStylesheet = null;
|
||||||
let _overridesSettings = null;
|
let _gdmCssStylesheet = null;
|
||||||
|
|
||||||
let background = null;
|
let background = null;
|
||||||
|
|
||||||
function createUserSession() {
|
function _createUserSession() {
|
||||||
// Load the calendar server. Note that we are careful about
|
// Load the calendar server. Note that we are careful about
|
||||||
// not loading any events until the user presses the clock
|
// not loading any events until the user presses the clock
|
||||||
global.launch_calendar_server();
|
global.launch_calendar_server();
|
||||||
|
|
||||||
|
placesManager = new PlaceDisplay.PlacesManager();
|
||||||
telepathyClient = new TelepathyClient.Client();
|
telepathyClient = new TelepathyClient.Client();
|
||||||
automountManager = new AutomountManager.AutomountManager();
|
automountManager = new AutomountManager.AutomountManager();
|
||||||
autorunManager = new AutorunManager.AutorunManager();
|
autorunManager = new AutorunManager.AutorunManager();
|
||||||
networkAgent = new NetworkAgent.NetworkAgent();
|
networkAgent = new NetworkAgent.NetworkAgent();
|
||||||
|
|
||||||
_initRecorder();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createGDMSession() {
|
function _createGDMSession() {
|
||||||
screenShield.showDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
function createGDMLoginDialog(parentActor) {
|
|
||||||
// We do this this here instead of at the top to prevent GDM
|
// We do this this here instead of at the top to prevent GDM
|
||||||
// related code from getting loaded in normal user sessions
|
// related code from getting loaded in normal user sessions
|
||||||
const LoginDialog = imports.gdm.loginDialog;
|
const LoginDialog = imports.gdm.loginDialog;
|
||||||
|
|
||||||
let loginDialog = new LoginDialog.LoginDialog(parentActor);
|
let loginDialog = new LoginDialog.LoginDialog();
|
||||||
return [loginDialog, true];
|
loginDialog.connect('loaded', function() {
|
||||||
}
|
loginDialog.open();
|
||||||
|
});
|
||||||
function createSessionUnlockDialog(parentActor) {
|
|
||||||
let dialog = new UnlockDialog.UnlockDialog(parentActor);
|
|
||||||
return [dialog, false];
|
|
||||||
}
|
|
||||||
|
|
||||||
function createInitialSetupSession() {
|
|
||||||
networkAgent = new NetworkAgent.NetworkAgent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _initRecorder() {
|
function _initRecorder() {
|
||||||
let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
|
let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
|
||||||
let desktopLockdownSettings = new Gio.Settings({ schema: 'org.gnome.desktop.lockdown' });
|
|
||||||
let bindingSettings = new Gio.Settings({ schema: 'org.gnome.shell.keybindings' });
|
|
||||||
|
|
||||||
global.display.add_keybinding('toggle-recording',
|
global.screen.connect('toggle-recording', function() {
|
||||||
bindingSettings,
|
|
||||||
Meta.KeyBindingFlags.NONE, function() {
|
|
||||||
if (recorder == null) {
|
if (recorder == null) {
|
||||||
recorder = new Shell.Recorder({ stage: global.stage });
|
recorder = new Shell.Recorder({ stage: global.stage });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recorder.is_recording()) {
|
if (recorder.is_recording()) {
|
||||||
recorder.close();
|
recorder.pause();
|
||||||
Meta.enable_unredirect_for_screen(global.screen);
|
Meta.enable_unredirect_for_screen(global.screen);
|
||||||
} else if (!desktopLockdownSettings.get_boolean('disable-save-to-disk')) {
|
} else {
|
||||||
// read the parameters from GSettings always in case they have changed
|
// read the parameters from GSettings always in case they have changed
|
||||||
recorder.set_framerate(recorderSettings.get_int('framerate'));
|
recorder.set_framerate(recorderSettings.get_int('framerate'));
|
||||||
/* Translators: this is a filename used for screencast recording */
|
recorder.set_filename('shell-%d%u-%c.' + recorderSettings.get_string('file-extension'));
|
||||||
// xgettext:no-c-format
|
|
||||||
recorder.set_filename(_("Screencast from %d %t") + '.' + recorderSettings.get_string('file-extension'));
|
|
||||||
let pipeline = recorderSettings.get_string('pipeline');
|
let pipeline = recorderSettings.get_string('pipeline');
|
||||||
|
|
||||||
if (!pipeline.match(/^\s*$/))
|
if (!pipeline.match(/^\s*$/))
|
||||||
@@ -149,19 +124,43 @@ function _initRecorder() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _initUserSession() {
|
||||||
|
_initRecorder();
|
||||||
|
|
||||||
|
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() {
|
function start() {
|
||||||
// These are here so we don't break compatibility.
|
// Monkey patch utility functions into the global proxy;
|
||||||
global.logError = window.log;
|
// This is easier and faster than indirecting down into global
|
||||||
global.log = window.log;
|
// if we want to call back up into JS.
|
||||||
|
global.logError = _logError;
|
||||||
|
global.log = _logDebug;
|
||||||
|
|
||||||
// Chain up async errors reported from C
|
// Chain up async errors reported from C
|
||||||
global.connect('notify-error', function (global, msg, detail) { notifyError(msg, detail); });
|
global.connect('notify-error', function (global, msg, detail) { notifyError(msg, detail); });
|
||||||
|
|
||||||
Gio.DesktopAppInfo.set_desktop_env('GNOME');
|
Gio.DesktopAppInfo.set_desktop_env('GNOME');
|
||||||
|
|
||||||
sessionMode = new SessionMode.SessionMode();
|
|
||||||
shellDBusService = new ShellDBus.GnomeShell();
|
shellDBusService = new ShellDBus.GnomeShell();
|
||||||
shellMountOpDBusService = new ShellMountOperation.GnomeShellMountOpHandler();
|
|
||||||
|
|
||||||
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
|
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
|
||||||
// also initialize ShellAppSystem first. ShellAppSystem
|
// also initialize ShellAppSystem first. ShellAppSystem
|
||||||
@@ -171,11 +170,9 @@ function start() {
|
|||||||
// and recalculate application associations, so to avoid
|
// and recalculate application associations, so to avoid
|
||||||
// races for now we initialize it here. It's better to
|
// races for now we initialize it here. It's better to
|
||||||
// be predictable anyways.
|
// be predictable anyways.
|
||||||
let tracker = Shell.WindowTracker.get_default();
|
Shell.WindowTracker.get_default();
|
||||||
Shell.AppUsage.get_default();
|
Shell.AppUsage.get_default();
|
||||||
|
|
||||||
tracker.connect('startup-sequence-changed', _queueCheckWorkspaces);
|
|
||||||
|
|
||||||
// The stage is always covered so Clutter doesn't need to clear it; however
|
// The stage is always covered so Clutter doesn't need to clear it; however
|
||||||
// the color is used as the default contents for the Mutter root background
|
// the color is used as the default contents for the Mutter root background
|
||||||
// actor so set it anyways.
|
// actor so set it anyways.
|
||||||
@@ -183,6 +180,7 @@ function start() {
|
|||||||
global.stage.no_clear_hint = true;
|
global.stage.no_clear_hint = true;
|
||||||
|
|
||||||
_defaultCssStylesheet = global.datadir + '/theme/gnome-shell.css';
|
_defaultCssStylesheet = global.datadir + '/theme/gnome-shell.css';
|
||||||
|
_gdmCssStylesheet = global.datadir + '/theme/gdm.css';
|
||||||
loadTheme();
|
loadTheme();
|
||||||
|
|
||||||
// Set up stage hierarchy to group all UI actors under one container.
|
// Set up stage hierarchy to group all UI actors under one container.
|
||||||
@@ -193,16 +191,7 @@ function start() {
|
|||||||
for (let i = 0; i < children.length; i++)
|
for (let i = 0; i < children.length; i++)
|
||||||
children[i].allocate_preferred_size(flags);
|
children[i].allocate_preferred_size(flags);
|
||||||
});
|
});
|
||||||
uiGroup.connect('get-preferred-width',
|
St.set_ui_root(global.stage, uiGroup);
|
||||||
function(actor, forHeight, alloc) {
|
|
||||||
let width = global.stage.width;
|
|
||||||
[alloc.min_size, alloc.natural_size] = [width, width];
|
|
||||||
});
|
|
||||||
uiGroup.connect('get-preferred-height',
|
|
||||||
function(actor, forWidth, alloc) {
|
|
||||||
let height = global.stage.height;
|
|
||||||
[alloc.min_size, alloc.natural_size] = [height, height];
|
|
||||||
});
|
|
||||||
global.window_group.reparent(uiGroup);
|
global.window_group.reparent(uiGroup);
|
||||||
global.overlay_group.reparent(uiGroup);
|
global.overlay_group.reparent(uiGroup);
|
||||||
global.stage.add_actor(uiGroup);
|
global.stage.add_actor(uiGroup);
|
||||||
@@ -210,10 +199,10 @@ function start() {
|
|||||||
layoutManager = new Layout.LayoutManager();
|
layoutManager = new Layout.LayoutManager();
|
||||||
xdndHandler = new XdndHandler.XdndHandler();
|
xdndHandler = new XdndHandler.XdndHandler();
|
||||||
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
|
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
|
||||||
overview = new Overview.Overview();
|
// This overview object is just a stub for non-user sessions
|
||||||
|
overview = new Overview.Overview({ isDummy: global.session_type != Shell.SessionType.USER });
|
||||||
magnifier = new Magnifier.Magnifier();
|
magnifier = new Magnifier.Magnifier();
|
||||||
screenShield = new ScreenShield.ScreenShield();
|
statusIconDispatcher = new StatusIconDispatcher.StatusIconDispatcher();
|
||||||
screenSaverDBus = new ShellDBus.ScreenSaverDBus();
|
|
||||||
panel = new Panel.Panel();
|
panel = new Panel.Panel();
|
||||||
wm = new WindowManager.WindowManager();
|
wm = new WindowManager.WindowManager();
|
||||||
messageTray = new MessageTray.MessageTray();
|
messageTray = new MessageTray.MessageTray();
|
||||||
@@ -221,7 +210,10 @@ function start() {
|
|||||||
notificationDaemon = new NotificationDaemon.NotificationDaemon();
|
notificationDaemon = new NotificationDaemon.NotificationDaemon();
|
||||||
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
|
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
|
||||||
|
|
||||||
sessionMode.createSession();
|
if (global.session_type == Shell.SessionType.USER)
|
||||||
|
_createUserSession();
|
||||||
|
else if (global.session_type == Shell.SessionType.GDM)
|
||||||
|
_createGDMSession();
|
||||||
|
|
||||||
panel.startStatusArea();
|
panel.startStatusArea();
|
||||||
|
|
||||||
@@ -229,29 +221,9 @@ function start() {
|
|||||||
keyboard.init();
|
keyboard.init();
|
||||||
overview.init();
|
overview.init();
|
||||||
|
|
||||||
if (sessionMode.hasWorkspaces)
|
if (global.session_type == Shell.SessionType.USER)
|
||||||
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
|
_initUserSession();
|
||||||
false, -1, 1);
|
statusIconDispatcher.start(messageTray.actor);
|
||||||
|
|
||||||
if (sessionMode.allowExtensions) {
|
|
||||||
ExtensionDownloader.init();
|
|
||||||
ExtensionSystem.loadExtensions();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sessionMode.hasRunDialog) {
|
|
||||||
Meta.keybindings_set_custom_handler('panel-run-dialog', function() {
|
|
||||||
getRunDialog().open();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sessionMode.hasOverview) {
|
|
||||||
Meta.keybindings_set_custom_handler('panel-main-menu', function () {
|
|
||||||
overview.toggle();
|
|
||||||
});
|
|
||||||
|
|
||||||
global.display.connect('overlay-key',
|
|
||||||
Lang.bind(overview, overview.toggle));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provide the bus object for gnome-session to
|
// Provide the bus object for gnome-session to
|
||||||
// initiate logouts.
|
// initiate logouts.
|
||||||
@@ -260,13 +232,11 @@ function start() {
|
|||||||
// Attempt to become a PolicyKit authentication agent
|
// Attempt to become a PolicyKit authentication agent
|
||||||
PolkitAuthenticationAgent.init()
|
PolkitAuthenticationAgent.init()
|
||||||
|
|
||||||
// Become a prompter for gnome keyring
|
|
||||||
KeyringPrompt.init();
|
|
||||||
|
|
||||||
_startDate = new Date();
|
_startDate = new Date();
|
||||||
|
|
||||||
global.stage.connect('captured-event', _globalKeyPressHandler);
|
global.stage.connect('captured-event', _globalKeyPressHandler);
|
||||||
|
|
||||||
|
_log('info', 'loaded at ' + _startDate);
|
||||||
log('GNOME Shell started at ' + _startDate);
|
log('GNOME Shell started at ' + _startDate);
|
||||||
|
|
||||||
let perfModuleName = GLib.getenv("SHELL_PERF_MODULE");
|
let perfModuleName = GLib.getenv("SHELL_PERF_MODULE");
|
||||||
@@ -276,9 +246,6 @@ function start() {
|
|||||||
Scripting.runPerfScript(module, perfOutput);
|
Scripting.runPerfScript(module, perfOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
_overridesSettings = new Gio.Settings({ schema: OVERRIDES_SCHEMA });
|
|
||||||
_overridesSettings.connect('changed::dynamic-workspaces', _queueCheckWorkspaces);
|
|
||||||
|
|
||||||
global.screen.connect('notify::n-workspaces', _nWorkspacesChanged);
|
global.screen.connect('notify::n-workspaces', _nWorkspacesChanged);
|
||||||
|
|
||||||
global.screen.connect('window-entered-monitor', _windowEnteredMonitor);
|
global.screen.connect('window-entered-monitor', _windowEnteredMonitor);
|
||||||
@@ -303,30 +270,17 @@ function _checkWorkspaces() {
|
|||||||
let i;
|
let i;
|
||||||
let emptyWorkspaces = [];
|
let emptyWorkspaces = [];
|
||||||
|
|
||||||
if (!Meta.prefs_get_dynamic_workspaces()) {
|
|
||||||
_checkWorkspacesId = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < _workspaces.length; i++) {
|
for (i = 0; i < _workspaces.length; i++) {
|
||||||
let lastRemoved = _workspaces[i]._lastRemovedWindow;
|
let lastRemoved = _workspaces[i]._lastRemovedWindow;
|
||||||
if ((lastRemoved &&
|
if (lastRemoved &&
|
||||||
(lastRemoved.get_window_type() == Meta.WindowType.SPLASHSCREEN ||
|
(lastRemoved.get_window_type() == Meta.WindowType.SPLASHSCREEN ||
|
||||||
lastRemoved.get_window_type() == Meta.WindowType.DIALOG ||
|
lastRemoved.get_window_type() == Meta.WindowType.DIALOG ||
|
||||||
lastRemoved.get_window_type() == Meta.WindowType.MODAL_DIALOG)) ||
|
lastRemoved.get_window_type() == Meta.WindowType.MODAL_DIALOG))
|
||||||
_workspaces[i]._keepAliveId)
|
|
||||||
emptyWorkspaces[i] = false;
|
emptyWorkspaces[i] = false;
|
||||||
else
|
else
|
||||||
emptyWorkspaces[i] = true;
|
emptyWorkspaces[i] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let sequences = Shell.WindowTracker.get_default().get_startup_sequences();
|
|
||||||
for (i = 0; i < sequences.length; i++) {
|
|
||||||
let index = sequences[i].get_workspace();
|
|
||||||
if (index >= 0 && index <= global.screen.n_workspaces)
|
|
||||||
emptyWorkspaces[index] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let windows = global.get_window_actors();
|
let windows = global.get_window_actors();
|
||||||
for (i = 0; i < windows.length; i++) {
|
for (i = 0; i < windows.length; i++) {
|
||||||
let win = windows[i];
|
let win = windows[i];
|
||||||
@@ -374,17 +328,6 @@ function _checkWorkspaces() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function keepWorkspaceAlive(workspace, duration) {
|
|
||||||
if (workspace._keepAliveId)
|
|
||||||
Mainloop.source_remove(workspace._keepAliveId);
|
|
||||||
|
|
||||||
workspace._keepAliveId = Mainloop.timeout_add(duration, function() {
|
|
||||||
workspace._keepAliveId = 0;
|
|
||||||
_queueCheckWorkspaces();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function _windowRemoved(workspace, window) {
|
function _windowRemoved(workspace, window) {
|
||||||
workspace._lastRemovedWindow = window;
|
workspace._lastRemovedWindow = window;
|
||||||
_queueCheckWorkspaces();
|
_queueCheckWorkspaces();
|
||||||
@@ -393,7 +336,6 @@ function _windowRemoved(workspace, window) {
|
|||||||
workspace._lastRemovedWindow = null;
|
workspace._lastRemovedWindow = null;
|
||||||
_queueCheckWorkspaces();
|
_queueCheckWorkspaces();
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,8 +451,8 @@ function loadTheme() {
|
|||||||
|
|
||||||
let theme = new St.Theme ({ application_stylesheet: cssStylesheet });
|
let theme = new St.Theme ({ application_stylesheet: cssStylesheet });
|
||||||
|
|
||||||
if (sessionMode.extraStylesheet)
|
if (global.session_type == Shell.SessionType.GDM)
|
||||||
theme.load_stylesheet(sessionMode.extraStylesheet);
|
theme.load_stylesheet(_gdmCssStylesheet);
|
||||||
|
|
||||||
if (previousTheme) {
|
if (previousTheme) {
|
||||||
let customStylesheets = previousTheme.get_custom_stylesheets();
|
let customStylesheets = previousTheme.get_custom_stylesheets();
|
||||||
@@ -532,7 +474,6 @@ function notify(msg, details) {
|
|||||||
messageTray.add(source);
|
messageTray.add(source);
|
||||||
let notification = new MessageTray.Notification(source, msg, details);
|
let notification = new MessageTray.Notification(source, msg, details);
|
||||||
notification.setTransient(true);
|
notification.setTransient(true);
|
||||||
notification.setShowWhenLocked(true);
|
|
||||||
source.notify(notification);
|
source.notify(notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -553,6 +494,59 @@ function notifyError(msg, details) {
|
|||||||
notify(msg, details);
|
notify(msg, details);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _log:
|
||||||
|
* @category: string message type ('info', 'error')
|
||||||
|
* @msg: A message string
|
||||||
|
* ...: Any further arguments are converted into JSON notation,
|
||||||
|
* and appended to the log message, separated by spaces.
|
||||||
|
*
|
||||||
|
* Log a message into the LookingGlass error
|
||||||
|
* stream. This is primarily intended for use by the
|
||||||
|
* extension system as well as debugging.
|
||||||
|
*/
|
||||||
|
function _log(category, msg) {
|
||||||
|
let text = msg;
|
||||||
|
if (arguments.length > 2) {
|
||||||
|
text += ': ';
|
||||||
|
for (let i = 2; i < arguments.length; i++) {
|
||||||
|
text += JSON.stringify(arguments[i]);
|
||||||
|
if (i < arguments.length - 1)
|
||||||
|
text += ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_errorLogStack.push({timestamp: new Date().getTime(),
|
||||||
|
category: category,
|
||||||
|
message: text });
|
||||||
|
}
|
||||||
|
|
||||||
|
function _logError(msg) {
|
||||||
|
return _log('error', msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _logDebug(msg) {
|
||||||
|
return _log('debug', msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by the error display in lookingGlass.js
|
||||||
|
function _getAndClearErrorStack() {
|
||||||
|
let errors = _errorLogStack;
|
||||||
|
_errorLogStack = [];
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
function logStackTrace(msg) {
|
||||||
|
try {
|
||||||
|
throw new Error();
|
||||||
|
} catch (e) {
|
||||||
|
// e.stack must have at least two lines, with the first being
|
||||||
|
// logStackTrace() (which we strip off), and the second being
|
||||||
|
// our caller.
|
||||||
|
let trace = e.stack.substr(e.stack.indexOf('\n') + 1);
|
||||||
|
log(msg ? (msg + '\n' + trace) : trace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function isWindowActorDisplayedOnWorkspace(win, workspaceIndex) {
|
function isWindowActorDisplayedOnWorkspace(win, workspaceIndex) {
|
||||||
return win.get_workspace() == workspaceIndex ||
|
return win.get_workspace() == workspaceIndex ||
|
||||||
(win.get_meta_window() && win.get_meta_window().is_on_all_workspaces());
|
(win.get_meta_window() && win.get_meta_window().is_on_all_workspaces());
|
||||||
@@ -575,19 +569,18 @@ function _globalKeyPressHandler(actor, event) {
|
|||||||
if (event.type() != Clutter.EventType.KEY_PRESS)
|
if (event.type() != Clutter.EventType.KEY_PRESS)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!sessionMode.allowKeybindingsWhenModal) {
|
|
||||||
if (modalCount > (overview.visible ? 1 : 0))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let symbol = event.get_key_symbol();
|
let symbol = event.get_key_symbol();
|
||||||
let keyCode = event.get_key_code();
|
let keyCode = event.get_key_code();
|
||||||
let ignoredModifiers = global.display.get_ignored_modifier_mask();
|
let modifierState = Shell.get_event_state(event);
|
||||||
let modifierState = event.get_state() & ~ignoredModifiers;
|
|
||||||
|
|
||||||
// This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType
|
// This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType
|
||||||
let action = global.display.get_keybinding_action(keyCode, modifierState);
|
let action = global.display.get_keybinding_action(keyCode, modifierState);
|
||||||
|
|
||||||
|
// Other bindings are only available to the user session when the overview is up and
|
||||||
|
// no modal dialog is present.
|
||||||
|
if (global.session_type == Shell.SessionType.USER && (!overview.visible || modalCount > 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
// This isn't a Meta.KeyBindingAction yet
|
// This isn't a Meta.KeyBindingAction yet
|
||||||
if (symbol == Clutter.Super_L || symbol == Clutter.Super_R) {
|
if (symbol == Clutter.Super_L || symbol == Clutter.Super_R) {
|
||||||
overview.hide();
|
overview.hide();
|
||||||
@@ -600,39 +593,28 @@ function _globalKeyPressHandler(actor, event) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// None of the other bindings are relevant outside of the user's session
|
||||||
|
if (global.session_type != Shell.SessionType.USER)
|
||||||
|
return false;
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
// left/right would effectively act as synonyms for up/down if we enabled them;
|
// 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.
|
// but that could be considered confusing; we also disable them in the main view.
|
||||||
//
|
//
|
||||||
// case Meta.KeyBindingAction.WORKSPACE_LEFT:
|
// case Meta.KeyBindingAction.WORKSPACE_LEFT:
|
||||||
// if (!sessionMode.hasWorkspaces)
|
|
||||||
// return false;
|
|
||||||
//
|
|
||||||
// wm.actionMoveWorkspaceLeft();
|
// wm.actionMoveWorkspaceLeft();
|
||||||
// return true;
|
// return true;
|
||||||
// case Meta.KeyBindingAction.WORKSPACE_RIGHT:
|
// case Meta.KeyBindingAction.WORKSPACE_RIGHT:
|
||||||
// if (!sessionMode.hasWorkspaces)
|
|
||||||
// return false;
|
|
||||||
//
|
|
||||||
// wm.actionMoveWorkspaceRight();
|
// wm.actionMoveWorkspaceRight();
|
||||||
// return true;
|
// return true;
|
||||||
case Meta.KeyBindingAction.WORKSPACE_UP:
|
case Meta.KeyBindingAction.WORKSPACE_UP:
|
||||||
if (!sessionMode.hasWorkspaces)
|
wm.actionMoveWorkspaceUp();
|
||||||
return false;
|
|
||||||
|
|
||||||
wm.actionMoveWorkspace(Meta.MotionDirection.UP);
|
|
||||||
return true;
|
return true;
|
||||||
case Meta.KeyBindingAction.WORKSPACE_DOWN:
|
case Meta.KeyBindingAction.WORKSPACE_DOWN:
|
||||||
if (!sessionMode.hasWorkspaces)
|
wm.actionMoveWorkspaceDown();
|
||||||
return false;
|
|
||||||
|
|
||||||
wm.actionMoveWorkspace(Meta.MotionDirection.DOWN);
|
|
||||||
return true;
|
return true;
|
||||||
case Meta.KeyBindingAction.PANEL_RUN_DIALOG:
|
case Meta.KeyBindingAction.PANEL_RUN_DIALOG:
|
||||||
case Meta.KeyBindingAction.COMMAND_2:
|
case Meta.KeyBindingAction.COMMAND_2:
|
||||||
if (!sessionMode.hasRunDialog)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
getRunDialog().open();
|
getRunDialog().open();
|
||||||
return true;
|
return true;
|
||||||
case Meta.KeyBindingAction.PANEL_MAIN_MENU:
|
case Meta.KeyBindingAction.PANEL_MAIN_MENU:
|
||||||
@@ -651,10 +633,6 @@ function _findModal(actor) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isInModalStack(actor) {
|
|
||||||
return _findModal(actor) != -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pushModal:
|
* pushModal:
|
||||||
* @actor: #ClutterActor which will be given keyboard focus
|
* @actor: #ClutterActor which will be given keyboard focus
|
||||||
@@ -687,7 +665,6 @@ function pushModal(actor, timestamp, options) {
|
|||||||
log('pushModal: invocation of begin_modal failed');
|
log('pushModal: invocation of begin_modal failed');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Meta.disable_unredirect_for_screen(global.screen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
|
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
|
||||||
@@ -696,7 +673,7 @@ function pushModal(actor, timestamp, options) {
|
|||||||
let actorDestroyId = actor.connect('destroy', function() {
|
let actorDestroyId = actor.connect('destroy', function() {
|
||||||
let index = _findModal(actor);
|
let index = _findModal(actor);
|
||||||
if (index >= 0)
|
if (index >= 0)
|
||||||
popModal(actor);
|
modalActorFocusStack.splice(index, 1);
|
||||||
});
|
});
|
||||||
let curFocus = global.stage.get_key_focus();
|
let curFocus = global.stage.get_key_focus();
|
||||||
let curFocusDestroyId;
|
let curFocusDestroyId;
|
||||||
@@ -768,7 +745,6 @@ function popModal(actor, timestamp) {
|
|||||||
|
|
||||||
global.end_modal(timestamp);
|
global.end_modal(timestamp);
|
||||||
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
||||||
Meta.enable_unredirect_for_screen(global.screen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createLookingGlass() {
|
function createLookingGlass() {
|
||||||
@@ -911,8 +887,7 @@ function initializeDeferredWork(actor, callback, props) {
|
|||||||
function queueDeferredWork(workId) {
|
function queueDeferredWork(workId) {
|
||||||
let data = _deferredWorkData[workId];
|
let data = _deferredWorkData[workId];
|
||||||
if (!data) {
|
if (!data) {
|
||||||
let message = 'Invalid work id %d'.format(workId);
|
global.logError('invalid work id ', workId);
|
||||||
logError(new Error(message), message);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_deferredWorkQueue.indexOf(workId) < 0)
|
if (_deferredWorkQueue.indexOf(workId) < 0)
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ const Pango = imports.gi.Pango;
|
|||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const Atk = imports.gi.Atk;
|
|
||||||
|
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
|
|
||||||
@@ -30,33 +29,32 @@ const State = {
|
|||||||
FADED_OUT: 4
|
FADED_OUT: 4
|
||||||
};
|
};
|
||||||
|
|
||||||
const ModalDialog = new Lang.Class({
|
function ModalDialog() {
|
||||||
Name: 'ModalDialog',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
ModalDialog.prototype = {
|
||||||
_init: function(params) {
|
_init: function(params) {
|
||||||
params = Params.parse(params, { shellReactive: false,
|
params = Params.parse(params, { shellReactive: false,
|
||||||
styleClass: null,
|
styleClass: null });
|
||||||
parentActor: Main.uiGroup
|
|
||||||
});
|
|
||||||
|
|
||||||
this.state = State.CLOSED;
|
this.state = State.CLOSED;
|
||||||
this._hasModal = false;
|
this._hasModal = false;
|
||||||
this._shellReactive = params.shellReactive;
|
this._shellReactive = params.shellReactive;
|
||||||
|
|
||||||
this._group = new St.Widget({ visible: false,
|
this._group = new St.Group({ visible: false,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0 });
|
||||||
accessible_role: Atk.Role.DIALOG });
|
Main.uiGroup.add_actor(this._group);
|
||||||
params.parentActor.add_actor(this._group);
|
|
||||||
|
|
||||||
let constraint = new Clutter.BindConstraint({ source: global.stage,
|
let constraint = new Clutter.BindConstraint({ source: global.stage,
|
||||||
coordinate: Clutter.BindCoordinate.ALL });
|
coordinate: Clutter.BindCoordinate.POSITION | Clutter.BindCoordinate.SIZE });
|
||||||
this._group.add_constraint(constraint);
|
this._group.add_constraint(constraint);
|
||||||
|
|
||||||
this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy));
|
this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy));
|
||||||
|
|
||||||
this._actionKeys = {};
|
this._actionKeys = {};
|
||||||
this._group.connect('key-release-event', Lang.bind(this, this._onKeyReleaseEvent));
|
this._group.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
|
||||||
|
|
||||||
this._backgroundBin = new St.Bin();
|
this._backgroundBin = new St.Bin();
|
||||||
this._group.add_actor(this._backgroundBin);
|
this._group.add_actor(this._backgroundBin);
|
||||||
@@ -91,7 +89,6 @@ const ModalDialog = new Lang.Class({
|
|||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
|
|
||||||
this._buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box',
|
this._buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box',
|
||||||
visible: false,
|
|
||||||
vertical: false });
|
vertical: false });
|
||||||
this._dialogLayout.add(this._buttonLayout,
|
this._dialogLayout.add(this._buttonLayout,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
@@ -100,7 +97,6 @@ const ModalDialog = new Lang.Class({
|
|||||||
|
|
||||||
global.focus_manager.add_group(this._dialogLayout);
|
global.focus_manager.add_group(this._dialogLayout);
|
||||||
this._initialKeyFocus = this._dialogLayout;
|
this._initialKeyFocus = this._dialogLayout;
|
||||||
this._initialKeyFocusDestroyId = 0;
|
|
||||||
this._savedKeyFocus = null;
|
this._savedKeyFocus = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -108,34 +104,22 @@ const ModalDialog = new Lang.Class({
|
|||||||
this._group.destroy();
|
this._group.destroy();
|
||||||
},
|
},
|
||||||
|
|
||||||
setActionKey: function(key, action) {
|
|
||||||
this._actionKeys[key] = action;
|
|
||||||
},
|
|
||||||
|
|
||||||
setButtons: function(buttons) {
|
setButtons: function(buttons) {
|
||||||
let hadChildren = this._buttonLayout.get_children() > 0;
|
let hadChildren = this._buttonLayout.get_children() > 0;
|
||||||
|
|
||||||
this._buttonLayout.destroy_all_children();
|
this._buttonLayout.destroy_children();
|
||||||
this._actionKeys = {};
|
this._actionKeys = {};
|
||||||
|
|
||||||
this._buttonLayout.visible = (buttons.length > 0);
|
|
||||||
|
|
||||||
for (let i = 0; i < buttons.length; i++) {
|
for (let i = 0; i < buttons.length; i++) {
|
||||||
let buttonInfo = buttons[i];
|
let buttonInfo = buttons[i];
|
||||||
let label = buttonInfo['label'];
|
let label = buttonInfo['label'];
|
||||||
let action = buttonInfo['action'];
|
let action = buttonInfo['action'];
|
||||||
let key = buttonInfo['key'];
|
let key = buttonInfo['key'];
|
||||||
let isDefault = buttonInfo['default'];
|
|
||||||
|
|
||||||
if (isDefault && !key)
|
|
||||||
key = Clutter.KEY_Return;
|
|
||||||
|
|
||||||
buttonInfo.button = new St.Button({ style_class: 'modal-dialog-button',
|
buttonInfo.button = new St.Button({ style_class: 'modal-dialog-button',
|
||||||
reactive: true,
|
reactive: true,
|
||||||
can_focus: true,
|
can_focus: true,
|
||||||
label: label });
|
label: label });
|
||||||
if (isDefault)
|
|
||||||
buttonInfo.button.add_style_pseudo_class('default');
|
|
||||||
|
|
||||||
let x_alignment;
|
let x_alignment;
|
||||||
if (buttons.length == 1)
|
if (buttons.length == 1)
|
||||||
@@ -147,7 +131,8 @@ const ModalDialog = new Lang.Class({
|
|||||||
else
|
else
|
||||||
x_alignment = St.Align.MIDDLE;
|
x_alignment = St.Align.MIDDLE;
|
||||||
|
|
||||||
if (!this._initialKeyFocusDestroyId)
|
if (this._initialKeyFocus == this._dialogLayout ||
|
||||||
|
this._buttonLayout.contains(this._initialKeyFocus))
|
||||||
this._initialKeyFocus = buttonInfo.button;
|
this._initialKeyFocus = buttonInfo.button;
|
||||||
this._buttonLayout.add(buttonInfo.button,
|
this._buttonLayout.add(buttonInfo.button,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
@@ -179,16 +164,12 @@ const ModalDialog = new Lang.Class({
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onKeyReleaseEvent: function(object, event) {
|
_onKeyPressEvent: function(object, keyPressEvent) {
|
||||||
let symbol = event.get_key_symbol();
|
let symbol = keyPressEvent.get_key_symbol();
|
||||||
let action = this._actionKeys[symbol];
|
let action = this._actionKeys[symbol];
|
||||||
|
|
||||||
if (action) {
|
if (action)
|
||||||
action();
|
action();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onGroupDestroy: function() {
|
_onGroupDestroy: function() {
|
||||||
@@ -196,7 +177,7 @@ const ModalDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_fadeOpen: function() {
|
_fadeOpen: function() {
|
||||||
let monitor = Main.layoutManager.currentMonitor;
|
let monitor = Main.layoutManager.focusMonitor;
|
||||||
|
|
||||||
this._backgroundBin.set_position(monitor.x, monitor.y);
|
this._backgroundBin.set_position(monitor.x, monitor.y);
|
||||||
this._backgroundBin.set_size(monitor.width, monitor.height);
|
this._backgroundBin.set_size(monitor.width, monitor.height);
|
||||||
@@ -221,15 +202,7 @@ const ModalDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
setInitialKeyFocus: function(actor) {
|
setInitialKeyFocus: function(actor) {
|
||||||
if (this._initialKeyFocusDestroyId)
|
|
||||||
this._initialKeyFocus.disconnect(this._initialKeyFocusDestroyId);
|
|
||||||
|
|
||||||
this._initialKeyFocus = actor;
|
this._initialKeyFocus = actor;
|
||||||
|
|
||||||
this._initialKeyFocusDestroyId = actor.connect('destroy', Lang.bind(this, function() {
|
|
||||||
this._initialKeyFocus = this._dialogLayout;
|
|
||||||
this._initialKeyFocusDestroyId = 0;
|
|
||||||
}));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
open: function(timestamp) {
|
open: function(timestamp) {
|
||||||
@@ -330,5 +303,5 @@ const ModalDialog = new Lang.Class({
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(ModalDialog.prototype);
|
Signals.addSignalMethods(ModalDialog.prototype);
|
||||||
|
|||||||
@@ -21,8 +21,6 @@
|
|||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const GObject = imports.gi.GObject;
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const NetworkManager = imports.gi.NetworkManager;
|
const NetworkManager = imports.gi.NetworkManager;
|
||||||
const NMClient = imports.gi.NMClient;
|
const NMClient = imports.gi.NMClient;
|
||||||
@@ -30,19 +28,19 @@ const Pango = imports.gi.Pango;
|
|||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
|
||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
|
|
||||||
const VPN_UI_GROUP = 'VPN Plugin UI';
|
function NetworkSecretDialog() {
|
||||||
|
this._init.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
const NetworkSecretDialog = new Lang.Class({
|
NetworkSecretDialog.prototype = {
|
||||||
Name: 'NetworkSecretDialog',
|
__proto__: ModalDialog.ModalDialog.prototype,
|
||||||
Extends: ModalDialog.ModalDialog,
|
|
||||||
|
|
||||||
_init: function(agent, requestId, connection, settingName, hints, contentOverride) {
|
_init: function(agent, requestId, connection, settingName, hints) {
|
||||||
this.parent({ styleClass: 'prompt-dialog' });
|
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'polkit-dialog' });
|
||||||
|
|
||||||
this._agent = agent;
|
this._agent = agent;
|
||||||
this._requestId = requestId;
|
this._requestId = requestId;
|
||||||
@@ -50,12 +48,9 @@ const NetworkSecretDialog = new Lang.Class({
|
|||||||
this._settingName = settingName;
|
this._settingName = settingName;
|
||||||
this._hints = hints;
|
this._hints = hints;
|
||||||
|
|
||||||
if (contentOverride)
|
|
||||||
this._content = contentOverride;
|
|
||||||
else
|
|
||||||
this._content = this._getContent();
|
this._content = this._getContent();
|
||||||
|
|
||||||
let mainContentBox = new St.BoxLayout({ style_class: 'prompt-dialog-main-layout',
|
let mainContentBox = new St.BoxLayout({ style_class: 'polkit-dialog-main-layout',
|
||||||
vertical: false });
|
vertical: false });
|
||||||
this.contentLayout.add(mainContentBox,
|
this.contentLayout.add(mainContentBox,
|
||||||
{ x_fill: true,
|
{ x_fill: true,
|
||||||
@@ -68,19 +63,19 @@ const NetworkSecretDialog = new Lang.Class({
|
|||||||
x_align: St.Align.END,
|
x_align: St.Align.END,
|
||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
|
|
||||||
let messageBox = new St.BoxLayout({ style_class: 'prompt-dialog-message-layout',
|
let messageBox = new St.BoxLayout({ style_class: 'polkit-dialog-message-layout',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
mainContentBox.add(messageBox,
|
mainContentBox.add(messageBox,
|
||||||
{ y_align: St.Align.START });
|
{ y_align: St.Align.START });
|
||||||
|
|
||||||
let subjectLabel = new St.Label({ style_class: 'prompt-dialog-headline',
|
let subjectLabel = new St.Label({ style_class: 'polkit-dialog-headline',
|
||||||
text: this._content.title });
|
text: this._content.title });
|
||||||
messageBox.add(subjectLabel,
|
messageBox.add(subjectLabel,
|
||||||
{ y_fill: false,
|
{ y_fill: false,
|
||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
|
|
||||||
if (this._content.message != null) {
|
if (this._content.message != null) {
|
||||||
let descriptionLabel = new St.Label({ style_class: 'prompt-dialog-description',
|
let descriptionLabel = new St.Label({ style_class: 'polkit-dialog-description',
|
||||||
text: this._content.message,
|
text: this._content.message,
|
||||||
// HACK: for reasons unknown to me, the label
|
// HACK: for reasons unknown to me, the label
|
||||||
// is not asked the correct height for width,
|
// is not asked the correct height for width,
|
||||||
@@ -101,12 +96,12 @@ const NetworkSecretDialog = new Lang.Class({
|
|||||||
let pos = 0;
|
let pos = 0;
|
||||||
for (let i = 0; i < this._content.secrets.length; i++) {
|
for (let i = 0; i < this._content.secrets.length; i++) {
|
||||||
let secret = this._content.secrets[i];
|
let secret = this._content.secrets[i];
|
||||||
let label = new St.Label({ style_class: 'prompt-dialog-password-label',
|
let label = new St.Label({ style_class: 'polkit-dialog-password-label',
|
||||||
text: secret.label });
|
text: secret.label });
|
||||||
|
|
||||||
let reactive = secret.key != null;
|
let reactive = secret.key != null;
|
||||||
|
|
||||||
secret.entry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
secret.entry = new St.Entry({ style_class: 'polkit-dialog-password-entry',
|
||||||
text: secret.value, can_focus: reactive,
|
text: secret.value, can_focus: reactive,
|
||||||
reactive: reactive });
|
reactive: reactive });
|
||||||
ShellEntry.addContextMenu(secret.entry,
|
ShellEntry.addContextMenu(secret.entry,
|
||||||
@@ -147,7 +142,7 @@ const NetworkSecretDialog = new Lang.Class({
|
|||||||
|
|
||||||
this._okButton = { label: _("Connect"),
|
this._okButton = { label: _("Connect"),
|
||||||
action: Lang.bind(this, this._onOk),
|
action: Lang.bind(this, this._onOk),
|
||||||
default: true
|
key: Clutter.KEY_Return,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setButtons([{ label: _("Cancel"),
|
this.setButtons([{ label: _("Cancel"),
|
||||||
@@ -165,6 +160,11 @@ const NetworkSecretDialog = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._okButton.button.reactive = valid;
|
this._okButton.button.reactive = valid;
|
||||||
|
this._okButton.button.can_focus = valid;
|
||||||
|
if (valid)
|
||||||
|
this._okButton.button.remove_style_pseudo_class('disabled');
|
||||||
|
else
|
||||||
|
this._okButton.button.add_style_pseudo_class('disabled');
|
||||||
},
|
},
|
||||||
|
|
||||||
_onOk: function() {
|
_onOk: function() {
|
||||||
@@ -177,14 +177,14 @@ const NetworkSecretDialog = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.CONFIRMED);
|
this._agent.respond(this._requestId, false);
|
||||||
this.close(global.get_current_time());
|
this.close(global.get_current_time());
|
||||||
}
|
}
|
||||||
// do nothing if not valid
|
// do nothing if not valid
|
||||||
},
|
},
|
||||||
|
|
||||||
cancel: function() {
|
cancel: function() {
|
||||||
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.USER_CANCELED);
|
this._agent.respond(this._requestId, true);
|
||||||
this.close(global.get_current_time());
|
this.close(global.get_current_time());
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -358,263 +358,23 @@ const NetworkSecretDialog = new Lang.Class({
|
|||||||
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const VPNRequestHandler = new Lang.Class({
|
function NetworkAgent() {
|
||||||
Name: 'VPNRequestHandler',
|
this._init.apply(this, arguments);
|
||||||
|
}
|
||||||
_init: function(agent, requestId, authHelper, serviceType, connection, hints, flags) {
|
|
||||||
this._agent = agent;
|
|
||||||
this._requestId = requestId;
|
|
||||||
this._connection = connection;
|
|
||||||
this._pluginOutBuffer = [];
|
|
||||||
this._title = null;
|
|
||||||
this._description = null;
|
|
||||||
this._content = [ ];
|
|
||||||
this._shellDialog = null;
|
|
||||||
|
|
||||||
let connectionSetting = connection.get_setting_connection();
|
|
||||||
|
|
||||||
let argv = [ authHelper.fileName,
|
|
||||||
'-u', connectionSetting.uuid,
|
|
||||||
'-n', connectionSetting.id,
|
|
||||||
'-s', serviceType
|
|
||||||
];
|
|
||||||
if (authHelper.externalUIMode)
|
|
||||||
argv.push('--external-ui-mode');
|
|
||||||
if (flags & NMClient.SecretAgentGetSecretsFlags.ALLOW_INTERACTION)
|
|
||||||
argv.push('-i');
|
|
||||||
if (flags & NMClient.SecretAgentGetSecretsFlags.REQUEST_NEW)
|
|
||||||
argv.push('-r');
|
|
||||||
|
|
||||||
this._newStylePlugin = authHelper.externalUIMode;
|
|
||||||
|
|
||||||
try {
|
|
||||||
let [success, pid, stdin, stdout, stderr] =
|
|
||||||
GLib.spawn_async_with_pipes(null, /* pwd */
|
|
||||||
argv,
|
|
||||||
null, /* envp */
|
|
||||||
GLib.SpawnFlags.DO_NOT_REAP_CHILD,
|
|
||||||
null /* child_setup */);
|
|
||||||
|
|
||||||
this._childPid = pid;
|
|
||||||
this._stdin = new Gio.UnixOutputStream({ fd: stdin, close_fd: true });
|
|
||||||
this._stdout = new Gio.UnixInputStream({ fd: stdout, close_fd: true });
|
|
||||||
// We need this one too, even if don't actually care of what the process
|
|
||||||
// has to say on stderr, because otherwise the fd opened by g_spawn_async_with_pipes
|
|
||||||
// is kept open indefinitely
|
|
||||||
let stderrStream = new Gio.UnixInputStream({ fd: stderr, close_fd: true });
|
|
||||||
stderrStream.close(null);
|
|
||||||
this._dataStdout = new Gio.DataInputStream({ base_stream: this._stdout });
|
|
||||||
|
|
||||||
if (this._newStylePlugin)
|
|
||||||
this._readStdoutNewStyle();
|
|
||||||
else
|
|
||||||
this._readStdoutOldStyle();
|
|
||||||
|
|
||||||
this._childWatch = GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid,
|
|
||||||
Lang.bind(this, this._vpnChildFinished));
|
|
||||||
|
|
||||||
this._writeConnection();
|
|
||||||
} catch(e) {
|
|
||||||
logError(e, 'error while spawning VPN auth helper');
|
|
||||||
|
|
||||||
this._agent.respond(requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
cancel: function() {
|
|
||||||
if (this._newStylePlugin && this._shellDialog) {
|
|
||||||
this._shellDialog.close(global.get_current_time());
|
|
||||||
this._shellDialog.destroy();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
this._stdin.write('QUIT\n\n', null);
|
|
||||||
} catch(e) { /* ignore broken pipe errors */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
this.destroy();
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy: function() {
|
|
||||||
if (this._destroyed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
GLib.source_remove(this._childWatch);
|
|
||||||
|
|
||||||
this._stdin.close(null);
|
|
||||||
// Stdout is closed when we finish reading from it
|
|
||||||
|
|
||||||
this._destroyed = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
_vpnChildFinished: function(pid, status, requestObj) {
|
|
||||||
if (this._newStylePlugin) {
|
|
||||||
// For new style plugin, all work is done in the async reading functions
|
|
||||||
// Just reap the process here
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let [exited, exitStatus] = Shell.util_wifexited(status);
|
|
||||||
|
|
||||||
if (exited) {
|
|
||||||
if (exitStatus != 0)
|
|
||||||
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.USER_CANCELED);
|
|
||||||
else
|
|
||||||
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.CONFIRMED);
|
|
||||||
} else
|
|
||||||
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
|
|
||||||
|
|
||||||
this.destroy();
|
|
||||||
},
|
|
||||||
|
|
||||||
_vpnChildProcessLineOldStyle: function(line) {
|
|
||||||
if (this._previousLine != undefined) {
|
|
||||||
// Two consecutive newlines mean that the child should be closed
|
|
||||||
// (the actual newlines are eaten by Gio.DataInputStream)
|
|
||||||
// Send a termination message
|
|
||||||
if (line == '' && this._previousLine == '') {
|
|
||||||
try {
|
|
||||||
this._stdin.write('QUIT\n\n', null);
|
|
||||||
} catch(e) { /* ignore broken pipe errors */ }
|
|
||||||
} else {
|
|
||||||
this._agent.set_password(this._requestId, this._previousLine, line);
|
|
||||||
this._previousLine = undefined;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this._previousLine = line;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_readStdoutOldStyle: function() {
|
|
||||||
this._dataStdout.read_line_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(stream, result) {
|
|
||||||
let [line, len] = this._dataStdout.read_line_finish_utf8(result);
|
|
||||||
|
|
||||||
if (line == null) {
|
|
||||||
// end of file
|
|
||||||
this._stdout.close(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._vpnChildProcessLineOldStyle(line);
|
|
||||||
|
|
||||||
// try to read more!
|
|
||||||
this._readStdoutOldStyle();
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
_readStdoutNewStyle: function() {
|
|
||||||
this._dataStdout.fill_async(-1, GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(stream, result) {
|
|
||||||
let cnt = this._dataStdout.fill_finish(result);
|
|
||||||
|
|
||||||
if (cnt == 0) {
|
|
||||||
// end of file
|
|
||||||
this._showNewStyleDialog();
|
|
||||||
|
|
||||||
this._stdout.close(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to read more
|
|
||||||
this._dataStdout.set_buffer_size(2 * this._dataStdout.get_buffer_size());
|
|
||||||
this._readStdoutNewStyle();
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
_showNewStyleDialog: function() {
|
|
||||||
let keyfile = new GLib.KeyFile();
|
|
||||||
let contentOverride;
|
|
||||||
|
|
||||||
try {
|
|
||||||
let data = this._dataStdout.peek_buffer();
|
|
||||||
keyfile.load_from_data(data.toString(), data.length,
|
|
||||||
GLib.KeyFileFlags.NONE);
|
|
||||||
|
|
||||||
if (keyfile.get_integer(VPN_UI_GROUP, 'Version') != 2)
|
|
||||||
throw new Error('Invalid plugin keyfile version, is %d');
|
|
||||||
|
|
||||||
contentOverride = { title: keyfile.get_string(VPN_UI_GROUP, 'Title'),
|
|
||||||
message: keyfile.get_string(VPN_UI_GROUP, 'Description'),
|
|
||||||
secrets: [] };
|
|
||||||
|
|
||||||
let [groups, len] = keyfile.get_groups();
|
|
||||||
for (let i = 0; i < groups.length; i++) {
|
|
||||||
if (groups[i] == VPN_UI_GROUP)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
let value = keyfile.get_string(groups[i], 'Value');
|
|
||||||
let shouldAsk = keyfile.get_boolean(groups[i], 'ShouldAsk');
|
|
||||||
|
|
||||||
if (shouldAsk) {
|
|
||||||
contentOverride.secrets.push({ label: keyfile.get_string(groups[i], 'Label'),
|
|
||||||
key: groups[i],
|
|
||||||
value: value,
|
|
||||||
password: keyfile.get_boolean(groups[i], 'IsSecret')
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (!value.length) // Ignore empty secrets
|
|
||||||
continue;
|
|
||||||
|
|
||||||
this._agent.set_password(this._requestId, groups[i], value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(e) {
|
|
||||||
logError(e, 'error while reading VPN plugin output keyfile');
|
|
||||||
|
|
||||||
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contentOverride.secrets.length) {
|
|
||||||
// Only show the dialog if we actually have something to ask
|
|
||||||
this._shellDialog = new NetworkSecretDialog(this._agent, this._requestId, this._connection, 'vpn', [], contentOverride);
|
|
||||||
this._shellDialog.open(global.get_current_time());
|
|
||||||
} else {
|
|
||||||
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.CONFIRMED);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_writeConnection: function() {
|
|
||||||
let vpnSetting = this._connection.get_setting_vpn();
|
|
||||||
|
|
||||||
try {
|
|
||||||
vpnSetting.foreach_data_item(Lang.bind(this, function(key, value) {
|
|
||||||
this._stdin.write('DATA_KEY=' + key + '\n', null);
|
|
||||||
this._stdin.write('DATA_VAL=' + (value || '') + '\n\n', null);
|
|
||||||
}));
|
|
||||||
vpnSetting.foreach_secret(Lang.bind(this, function(key, value) {
|
|
||||||
this._stdin.write('SECRET_KEY=' + key + '\n', null);
|
|
||||||
this._stdin.write('SECRET_VAL=' + (value || '') + '\n\n', null);
|
|
||||||
}));
|
|
||||||
this._stdin.write('DONE\n\n', null);
|
|
||||||
} catch(e) {
|
|
||||||
logError(e, 'internal error while writing connection to helper');
|
|
||||||
|
|
||||||
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const NetworkAgent = new Lang.Class({
|
|
||||||
Name: 'NetworkAgent',
|
|
||||||
|
|
||||||
|
NetworkAgent.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._native = new Shell.NetworkAgent({ auto_register: true,
|
this._native = new Shell.NetworkAgent({ auto_register: true,
|
||||||
identifier: 'org.gnome.Shell.NetworkAgent' });
|
identifier: 'org.gnome.Shell.NetworkAgent' });
|
||||||
|
|
||||||
this._dialogs = { };
|
this._dialogs = { };
|
||||||
this._vpnRequests = { };
|
|
||||||
|
|
||||||
this._native.connect('new-request', Lang.bind(this, this._newRequest));
|
this._native.connect('new-request', Lang.bind(this, this._newRequest));
|
||||||
this._native.connect('cancel-request', Lang.bind(this, this._cancelRequest));
|
this._native.connect('cancel-request', Lang.bind(this, this._cancelRequest));
|
||||||
},
|
},
|
||||||
|
|
||||||
_newRequest: function(agent, requestId, connection, settingName, hints, flags) {
|
_newRequest: function(agent, requestId, connection, settingName, hints) {
|
||||||
if (settingName == 'vpn') {
|
|
||||||
this._vpnRequest(requestId, connection, hints, flags);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let dialog = new NetworkSecretDialog(agent, requestId, connection, settingName, hints);
|
let dialog = new NetworkSecretDialog(agent, requestId, connection, settingName, hints);
|
||||||
dialog.connect('destroy', Lang.bind(this, function() {
|
dialog.connect('destroy', Lang.bind(this, function() {
|
||||||
delete this._dialogs[requestId];
|
delete this._dialogs[requestId];
|
||||||
@@ -624,77 +384,7 @@ const NetworkAgent = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_cancelRequest: function(agent, requestId) {
|
_cancelRequest: function(agent, requestId) {
|
||||||
if (this._dialogs[requestId]) {
|
|
||||||
this._dialogs[requestId].close(global.get_current_time());
|
this._dialogs[requestId].close(global.get_current_time());
|
||||||
this._dialogs[requestId].destroy();
|
this._dialogs[requestId].destroy();
|
||||||
delete this._dialogs[requestId];
|
|
||||||
} else if (this._vpnRequests[requestId]) {
|
|
||||||
this._vpnRequests[requestId].cancel();
|
|
||||||
delete this._vpnRequests[requestId];
|
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
|
|
||||||
_vpnRequest: function(requestId, connection, hints, flags) {
|
|
||||||
let vpnSetting = connection.get_setting_vpn();
|
|
||||||
let serviceType = vpnSetting.service_type;
|
|
||||||
|
|
||||||
this._buildVPNServiceCache();
|
|
||||||
|
|
||||||
let binary = this._vpnBinaries[serviceType];
|
|
||||||
if (!binary) {
|
|
||||||
log('Invalid VPN service type (cannot find authentication binary)');
|
|
||||||
|
|
||||||
/* cancel the auth process */
|
|
||||||
this._native.respond(requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._vpnRequests[requestId] = new VPNRequestHandler(this._native, requestId, binary, serviceType, connection, hints, flags);
|
|
||||||
},
|
|
||||||
|
|
||||||
_buildVPNServiceCache: function() {
|
|
||||||
if (this._vpnCacheBuilt)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._vpnCacheBuilt = true;
|
|
||||||
this._vpnBinaries = { };
|
|
||||||
|
|
||||||
let dir = Gio.file_new_for_path(GLib.build_filenamev([Config.SYSCONFDIR, 'NetworkManager/VPN']));
|
|
||||||
try {
|
|
||||||
let fileEnum = dir.enumerate_children('standard::name', Gio.FileQueryInfoFlags.NONE, null);
|
|
||||||
let info;
|
|
||||||
|
|
||||||
while ((info = fileEnum.next_file(null))) {
|
|
||||||
let name = info.get_name();
|
|
||||||
if (name.substr(-5) != '.name')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
try {
|
|
||||||
let keyfile = new GLib.KeyFile();
|
|
||||||
keyfile.load_from_file(dir.get_child(name).get_path(), GLib.KeyFileFlags.NONE);
|
|
||||||
let service = keyfile.get_string('VPN Connection', 'service');
|
|
||||||
let binary = keyfile.get_string('GNOME', 'auth-dialog');
|
|
||||||
let externalUIMode = false;
|
|
||||||
try {
|
|
||||||
externalUIMode = keyfile.get_boolean('GNOME', 'supports-external-ui-mode');
|
|
||||||
} catch(e) { } // ignore errors if key does not exist
|
|
||||||
let path = binary;
|
|
||||||
if (!GLib.path_is_absolute(path)) {
|
|
||||||
path = GLib.build_filenamev([Config.LIBEXECDIR, path]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GLib.file_test(path, GLib.FileTest.IS_EXECUTABLE))
|
|
||||||
this._vpnBinaries[service] = { fileName: path, externalUIMode: externalUIMode };
|
|
||||||
else
|
|
||||||
throw new Error('VPN plugin at %s is not executable'.format(path));
|
|
||||||
} catch(e) {
|
|
||||||
log('Error \'%s\' while processing VPN keyfile \'%s\''.
|
|
||||||
format(e.message, dir.get_child(name).get_path()));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(e) {
|
|
||||||
logError(e, 'error while enumerating VPN auth helpers');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const GdkPixbuf = imports.gi.GdkPixbuf;
|
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
@@ -88,46 +87,32 @@ const rewriteRules = {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
|
function NotificationDaemon() {
|
||||||
'bluetooth-applet': 'bluetooth',
|
this._init();
|
||||||
'gnome-volume-control-applet': 'volume', // renamed to gnome-sound-applet
|
}
|
||||||
// when moved to control center
|
|
||||||
'gnome-sound-applet': 'volume',
|
|
||||||
'nm-applet': 'network',
|
|
||||||
'gnome-power-manager': 'battery',
|
|
||||||
'keyboard': 'keyboard',
|
|
||||||
'a11y-keyboard': 'a11y',
|
|
||||||
'kbd-scrolllock': 'keyboard',
|
|
||||||
'kbd-numlock': 'keyboard',
|
|
||||||
'kbd-capslock': 'keyboard',
|
|
||||||
'ibus-ui-gtk': 'keyboard'
|
|
||||||
};
|
|
||||||
|
|
||||||
const NotificationDaemon = new Lang.Class({
|
|
||||||
Name: 'NotificationDaemon',
|
|
||||||
|
|
||||||
|
NotificationDaemon.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(NotificationDaemonIface, this);
|
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(NotificationDaemonIface, this);
|
||||||
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
|
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
|
||||||
|
|
||||||
this._sources = [];
|
this._sources = {};
|
||||||
this._senderToPid = {};
|
this._senderToPid = {};
|
||||||
this._notifications = {};
|
this._notifications = {};
|
||||||
this._busProxy = new Bus();
|
this._busProxy = new Bus();
|
||||||
|
|
||||||
this._trayManager = new Shell.TrayManager();
|
Main.statusIconDispatcher.connect('message-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
||||||
this._trayManager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
Main.statusIconDispatcher.connect('message-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
|
||||||
this._trayManager.connect('tray-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
|
|
||||||
|
|
||||||
Shell.WindowTracker.get_default().connect('notify::focus-app',
|
Shell.WindowTracker.get_default().connect('notify::focus-app',
|
||||||
Lang.bind(this, this._onFocusAppChanged));
|
Lang.bind(this, this._onFocusAppChanged));
|
||||||
Main.overview.connect('hidden',
|
Main.overview.connect('hidden',
|
||||||
Lang.bind(this, this._onFocusAppChanged));
|
Lang.bind(this, this._onFocusAppChanged));
|
||||||
|
|
||||||
this._trayManager.manage_stage(global.stage, Main.messageTray.actor);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_iconForNotificationData: function(icon, hints) {
|
_iconForNotificationData: function(icon, hints, size) {
|
||||||
|
let textureCache = St.TextureCache.get_default();
|
||||||
|
|
||||||
// If an icon is not specified, we use 'image-data' or 'image-path' hint for an icon
|
// If an icon is not specified, we use 'image-data' or 'image-path' hint for an icon
|
||||||
// and don't show a large image. There are currently many applications that use
|
// and don't show a large image. There are currently many applications that use
|
||||||
// notify_notification_set_icon_from_pixbuf() from libnotify, which in turn sets
|
// notify_notification_set_icon_from_pixbuf() from libnotify, which in turn sets
|
||||||
@@ -138,18 +123,20 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
// a large image.
|
// a large image.
|
||||||
if (icon) {
|
if (icon) {
|
||||||
if (icon.substr(0, 7) == 'file://')
|
if (icon.substr(0, 7) == 'file://')
|
||||||
return new Gio.FileIcon({ file: Gio.File.new_for_uri(icon) });
|
return textureCache.load_uri_async(icon, size, size);
|
||||||
else if (icon[0] == '/') {
|
else if (icon[0] == '/') {
|
||||||
return new Gio.FileIcon({ file: Gio.File.new_for_path(icon) });
|
let uri = GLib.filename_to_uri(icon, null);
|
||||||
|
return textureCache.load_uri_async(uri, size, size);
|
||||||
} else
|
} else
|
||||||
return new Gio.ThemedIcon({ name: icon });
|
return new St.Icon({ icon_name: icon,
|
||||||
|
icon_type: St.IconType.FULLCOLOR,
|
||||||
|
icon_size: size });
|
||||||
} else if (hints['image-data']) {
|
} else if (hints['image-data']) {
|
||||||
let [width, height, rowStride, hasAlpha,
|
let [width, height, rowStride, hasAlpha,
|
||||||
bitsPerSample, nChannels, data] = hints['image-data'];
|
bitsPerSample, nChannels, data] = hints['image-data'];
|
||||||
return Shell.util_create_pixbuf_from_data(data, GdkPixbuf.Colorspace.RGB, hasAlpha,
|
return textureCache.load_from_raw(data, hasAlpha, width, height, rowStride, size);
|
||||||
bitsPerSample, width, height, rowStride);
|
|
||||||
} else if (hints['image-path']) {
|
} else if (hints['image-path']) {
|
||||||
return new Gio.FileIcon({ file: Gio.File.new_for_path(hints['image-path']) });
|
return textureCache.load_uri_async(GLib.filename_to_uri(hints['image-path'], null), size, size);
|
||||||
} else {
|
} else {
|
||||||
let stockIcon;
|
let stockIcon;
|
||||||
switch (hints.urgency) {
|
switch (hints.urgency) {
|
||||||
@@ -161,34 +148,20 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
stockIcon = 'gtk-dialog-error';
|
stockIcon = 'gtk-dialog-error';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return new Gio.ThemedIcon({ name: stockIcon });
|
return new St.Icon({ icon_name: stockIcon,
|
||||||
|
icon_type: St.IconType.FULLCOLOR,
|
||||||
|
icon_size: size });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_lookupSource: function(title, pid, trayIcon) {
|
|
||||||
for (let i = 0; i < this._sources.length; i++) {
|
|
||||||
let source = this._sources[i];
|
|
||||||
if (source.pid == pid &&
|
|
||||||
(source.initialTitle == title || source.trayIcon || trayIcon))
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Returns the source associated with ndata.notification if it is set.
|
// Returns the source associated with ndata.notification if it is set.
|
||||||
// Otherwise, returns the source associated with the title and pid if
|
// Otherwise, returns the source associated with the pid if one is
|
||||||
// such source is stored in this._sources and the notification is not
|
// stored in this._sources and the notification is not transient.
|
||||||
// transient. If the existing or requested source is associated with
|
// Otherwise, creates a new source as long as pid is provided.
|
||||||
// a tray icon and passed in pid matches a pid of an existing source,
|
|
||||||
// the title match is ignored to enable representing a tray icon and
|
|
||||||
// notifications from the same application with a single source.
|
|
||||||
//
|
|
||||||
// If no existing source is found, a new source is created as long as
|
|
||||||
// pid is provided.
|
|
||||||
//
|
//
|
||||||
// Either a pid or ndata.notification is needed to retrieve or
|
// Either a pid or ndata.notification is needed to retrieve or
|
||||||
// create a source.
|
// create a source.
|
||||||
_getSource: function(title, pid, ndata, sender, trayIcon) {
|
_getSource: function(title, pid, ndata, sender) {
|
||||||
if (!pid && !(ndata && ndata.notification))
|
if (!pid && !(ndata && ndata.notification))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -205,24 +178,20 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
// with a transient one from the same sender, so we
|
// with a transient one from the same sender, so we
|
||||||
// always create a new source object for new transient notifications
|
// always create a new source object for new transient notifications
|
||||||
// and never add it to this._sources .
|
// and never add it to this._sources .
|
||||||
if (!isForTransientNotification) {
|
if (!isForTransientNotification && this._sources[pid]) {
|
||||||
let source = this._lookupSource(title, pid, trayIcon);
|
let source = this._sources[pid];
|
||||||
if (source) {
|
|
||||||
source.setTitle(title);
|
source.setTitle(title);
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let source = new Source(title, pid, sender, trayIcon);
|
let source = new Source(title, pid, sender);
|
||||||
source.setTransient(isForTransientNotification);
|
source.setTransient(isForTransientNotification);
|
||||||
|
|
||||||
if (!isForTransientNotification) {
|
if (!isForTransientNotification) {
|
||||||
this._sources.push(source);
|
this._sources[pid] = source;
|
||||||
source.connect('destroy', Lang.bind(this,
|
source.connect('destroy', Lang.bind(this,
|
||||||
function() {
|
function() {
|
||||||
let index = this._sources.indexOf(source);
|
delete this._sources[pid];
|
||||||
if (index >= 0)
|
|
||||||
this._sources.splice(index, 1);
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,19 +203,12 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
let [appName, replacesId, icon, summary, body, actions, hints, timeout] = params;
|
let [appName, replacesId, icon, summary, body, actions, hints, timeout] = params;
|
||||||
let id;
|
let id;
|
||||||
|
|
||||||
for (let hint in hints) {
|
|
||||||
// unpack the variants
|
|
||||||
hints[hint] = hints[hint].deep_unpack();
|
|
||||||
}
|
|
||||||
|
|
||||||
hints = Params.parse(hints, { urgency: Urgency.NORMAL }, true);
|
|
||||||
|
|
||||||
// Filter out chat, presence, calls and invitation notifications from
|
// Filter out chat, presence, calls and invitation notifications from
|
||||||
// Empathy, since we handle that information from telepathyClient.js
|
// Empathy, since we handle that information from telepathyClient.js
|
||||||
if (appName == 'Empathy' && (hints['category'] == 'im.received' ||
|
if (appName == 'Empathy' && (hints['category'] == 'im.received' ||
|
||||||
hints['category'] == 'x-empathy.im.room-invitation' ||
|
hints['category'] == 'x-empathy.im.room-invitation' ||
|
||||||
hints['category'] == 'x-empathy.call.incoming' ||
|
hints['category'] == 'x-empathy.call.incoming' ||
|
||||||
hints['category'] == 'x-empathy.transfer.incoming' ||
|
hints['category'] == 'x-empathy.call.incoming"' ||
|
||||||
hints['category'] == 'x-empathy.im.subscription-request' ||
|
hints['category'] == 'x-empathy.im.subscription-request' ||
|
||||||
hints['category'] == 'presence.online' ||
|
hints['category'] == 'presence.online' ||
|
||||||
hints['category'] == 'presence.offline')) {
|
hints['category'] == 'presence.offline')) {
|
||||||
@@ -269,6 +231,13 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (let hint in hints) {
|
||||||
|
// unpack the variants
|
||||||
|
hints[hint] = hints[hint].deep_unpack();
|
||||||
|
}
|
||||||
|
|
||||||
|
hints = Params.parse(hints, { urgency: Urgency.NORMAL }, true);
|
||||||
|
|
||||||
// Be compatible with the various hints for image data and image path
|
// Be compatible with the various hints for image data and image path
|
||||||
// 'image-data' and 'image-path' are the latest name of these hints, introduced in 1.2
|
// 'image-data' and 'image-path' are the latest name of these hints, introduced in 1.2
|
||||||
|
|
||||||
@@ -301,7 +270,7 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
let sender = invocation.get_sender();
|
let sender = invocation.get_sender();
|
||||||
let pid = this._senderToPid[sender];
|
let pid = this._senderToPid[sender];
|
||||||
|
|
||||||
let source = this._getSource(appName, pid, ndata, sender, null);
|
let source = this._getSource(appName, pid, ndata, sender);
|
||||||
|
|
||||||
if (source) {
|
if (source) {
|
||||||
this._notifyForSource(source, ndata);
|
this._notifyForSource(source, ndata);
|
||||||
@@ -327,7 +296,7 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
let [pid] = result;
|
let [pid] = result;
|
||||||
source = this._getSource(appName, pid, ndata, sender, null);
|
source = this._getSource(appName, pid, ndata, sender);
|
||||||
|
|
||||||
// We only store sender-pid entries for persistent sources.
|
// We only store sender-pid entries for persistent sources.
|
||||||
// Removing the entries once the source is destroyed
|
// Removing the entries once the source is destroyed
|
||||||
@@ -354,10 +323,7 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
[ndata.id, ndata.icon, ndata.summary, ndata.body,
|
[ndata.id, ndata.icon, ndata.summary, ndata.body,
|
||||||
ndata.actions, ndata.hints, ndata.notification];
|
ndata.actions, ndata.hints, ndata.notification];
|
||||||
|
|
||||||
let gicon = this._iconForNotificationData(icon, hints);
|
let iconActor = this._iconForNotificationData(icon, hints, source.ICON_SIZE);
|
||||||
let iconActor = new St.Icon({ gicon: gicon,
|
|
||||||
icon_type: St.IconType.FULLCOLOR,
|
|
||||||
icon_size: source.ICON_SIZE });
|
|
||||||
|
|
||||||
if (notification == null) {
|
if (notification == null) {
|
||||||
notification = new MessageTray.Notification(source, summary, body,
|
notification = new MessageTray.Notification(source, summary, body,
|
||||||
@@ -437,8 +403,8 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
// of the 'transient' hint with hints['transient'] rather than hints.transient
|
// of the 'transient' hint with hints['transient'] rather than hints.transient
|
||||||
notification.setTransient(hints['transient'] == true);
|
notification.setTransient(hints['transient'] == true);
|
||||||
|
|
||||||
let sourceGIcon = source.useNotificationIcon ? this._iconForNotificationData(icon, hints) : null;
|
let sourceIconActor = source.useNotificationIcon ? this._iconForNotificationData(icon, hints, source.ICON_SIZE) : null;
|
||||||
source.processNotification(notification, sourceGIcon);
|
source.processNotification(notification, sourceIconActor);
|
||||||
},
|
},
|
||||||
|
|
||||||
CloseNotification: function(id) {
|
CloseNotification: function(id) {
|
||||||
@@ -479,8 +445,8 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
if (!tracker.focus_app)
|
if (!tracker.focus_app)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (let i = 0; i < this._sources.length; i++) {
|
for (let id in this._sources) {
|
||||||
let source = this._sources[i];
|
let source = this._sources[id];
|
||||||
if (source.app == tracker.focus_app) {
|
if (source.app == tracker.focus_app) {
|
||||||
source.destroyNonResidentNotifications();
|
source.destroyNonResidentNotifications();
|
||||||
return;
|
return;
|
||||||
@@ -499,30 +465,28 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onTrayIconAdded: function(o, icon) {
|
_onTrayIconAdded: function(o, icon) {
|
||||||
let wmClass = icon.wm_class.toLowerCase();
|
let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null, null);
|
||||||
if (STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass] !== undefined)
|
source.setTrayIcon(icon);
|
||||||
return;
|
|
||||||
|
|
||||||
let source = this._getSource(icon.title || icon.wm_class || C_("program", "Unknown"), icon.pid, null, null, icon);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onTrayIconRemoved: function(o, icon) {
|
_onTrayIconRemoved: function(o, icon) {
|
||||||
let source = this._lookupSource(null, icon.pid, true);
|
let source = this._sources[icon.pid];
|
||||||
if (source)
|
if (source)
|
||||||
source.destroy();
|
source.destroy();
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const Source = new Lang.Class({
|
function Source(title, pid, sender) {
|
||||||
Name: 'NotificationDaemonSource',
|
this._init(title, pid, sender);
|
||||||
Extends: MessageTray.Source,
|
}
|
||||||
|
|
||||||
_init: function(title, pid, sender, trayIcon) {
|
Source.prototype = {
|
||||||
this.parent(title);
|
__proto__: MessageTray.Source.prototype,
|
||||||
|
|
||||||
this.initialTitle = title;
|
_init: function(title, pid, sender) {
|
||||||
|
MessageTray.Source.prototype._init.call(this, title);
|
||||||
|
|
||||||
this.pid = pid;
|
this._pid = pid;
|
||||||
if (sender)
|
if (sender)
|
||||||
this._nameWatcherId = Gio.DBus.session.watch_name(sender,
|
this._nameWatcherId = Gio.DBus.session.watch_name(sender,
|
||||||
Gio.BusNameWatcherFlags.NONE,
|
Gio.BusNameWatcherFlags.NONE,
|
||||||
@@ -536,12 +500,7 @@ const Source = new Lang.Class({
|
|||||||
this.title = this.app.get_name();
|
this.title = this.app.get_name();
|
||||||
else
|
else
|
||||||
this.useNotificationIcon = true;
|
this.useNotificationIcon = true;
|
||||||
|
this._trayIcon = null;
|
||||||
this.trayIcon = trayIcon;
|
|
||||||
if (this.trayIcon) {
|
|
||||||
this._setSummaryIcon(this.trayIcon);
|
|
||||||
this.useNotificationIcon = false;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onNameVanished: function() {
|
_onNameVanished: function() {
|
||||||
@@ -554,11 +513,11 @@ const Source = new Lang.Class({
|
|||||||
this.destroy();
|
this.destroy();
|
||||||
},
|
},
|
||||||
|
|
||||||
processNotification: function(notification, gicon) {
|
processNotification: function(notification, icon) {
|
||||||
if (gicon)
|
if (!this.app)
|
||||||
this._gicon = gicon;
|
this._setApp();
|
||||||
if (!this.trayIcon)
|
if (!this.app && icon)
|
||||||
this.iconUpdated();
|
this._setSummaryIcon(icon);
|
||||||
|
|
||||||
let tracker = Shell.WindowTracker.get_default();
|
let tracker = Shell.WindowTracker.get_default();
|
||||||
if (notification.resident && this.app && tracker.focus_app == this.app)
|
if (notification.resident && this.app && tracker.focus_app == this.app)
|
||||||
@@ -568,7 +527,7 @@ const Source = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleSummaryClick: function() {
|
handleSummaryClick: function() {
|
||||||
if (!this.trayIcon)
|
if (!this._trayIcon)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
let event = Clutter.get_current_event();
|
let event = Clutter.get_current_event();
|
||||||
@@ -589,54 +548,44 @@ const Source = new Lang.Class({
|
|||||||
let id = global.connect('notify::stage-input-mode', Lang.bind(this,
|
let id = global.connect('notify::stage-input-mode', Lang.bind(this,
|
||||||
function () {
|
function () {
|
||||||
global.disconnect(id);
|
global.disconnect(id);
|
||||||
this.trayIcon.click(event);
|
this._trayIcon.click(event);
|
||||||
}));
|
}));
|
||||||
Main.overview.hide();
|
Main.overview.hide();
|
||||||
} else {
|
} else {
|
||||||
this.trayIcon.click(event);
|
this._trayIcon.click(event);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
_getApp: function() {
|
|
||||||
let app;
|
|
||||||
|
|
||||||
app = Shell.WindowTracker.get_default().get_app_from_pid(this.pid);
|
|
||||||
if (app != null)
|
|
||||||
return app;
|
|
||||||
|
|
||||||
if (this.trayIcon) {
|
|
||||||
app = Shell.AppSystem.get_default().lookup_wmclass(this.trayIcon.wmclass);
|
|
||||||
if (app != null)
|
|
||||||
return app;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
_setApp: function() {
|
_setApp: function() {
|
||||||
if (this.app)
|
if (this.app)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.app = this._getApp();
|
this.app = Shell.WindowTracker.get_default().get_app_from_pid(this._pid);
|
||||||
if (!this.app)
|
if (!this.app)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Only override the icon if we were previously using
|
// Only override the icon if we were previously using
|
||||||
// notification-based icons (ie, not a trayicon) or if it was unset before
|
// notification-based icons (ie, not a trayicon) or if it was unset before
|
||||||
if (!this.trayIcon) {
|
if (!this._trayIcon) {
|
||||||
this.useNotificationIcon = false;
|
this.useNotificationIcon = false;
|
||||||
this.iconUpdated();
|
this._setSummaryIcon(this.app.create_icon_texture (this.ICON_SIZE));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setTrayIcon: function(icon) {
|
||||||
|
this._setSummaryIcon(icon);
|
||||||
|
this.useNotificationIcon = false;
|
||||||
|
this._trayIcon = icon;
|
||||||
|
},
|
||||||
|
|
||||||
open: function(notification) {
|
open: function(notification) {
|
||||||
this.destroyNonResidentNotifications();
|
this.destroyNonResidentNotifications();
|
||||||
this.openApp();
|
this.openApp();
|
||||||
},
|
},
|
||||||
|
|
||||||
_lastNotificationRemoved: function() {
|
_lastNotificationRemoved: function() {
|
||||||
if (!this.trayIcon)
|
if (!this._trayIcon)
|
||||||
this.destroy();
|
this.destroy();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -657,21 +606,6 @@ const Source = new Lang.Class({
|
|||||||
this._nameWatcherId = 0;
|
this._nameWatcherId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.parent();
|
MessageTray.Source.prototype.destroy.call(this);
|
||||||
},
|
|
||||||
|
|
||||||
createIcon: function(size) {
|
|
||||||
if (this.trayIcon) {
|
|
||||||
return new Clutter.Clone({ width: size,
|
|
||||||
height: size,
|
|
||||||
source: this.trayIcon });
|
|
||||||
} else if (this.app) {
|
|
||||||
return this.app.create_icon_texture(size);
|
|
||||||
} else if (this._gicon) {
|
|
||||||
return new St.Icon({ gicon: this._gicon,
|
|
||||||
icon_size: size });
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
});
|
|
||||||
|
|||||||
@@ -11,17 +11,18 @@ const Shell = imports.gi.Shell;
|
|||||||
const Gdk = imports.gi.Gdk;
|
const Gdk = imports.gi.Gdk;
|
||||||
|
|
||||||
const AppDisplay = imports.ui.appDisplay;
|
const AppDisplay = imports.ui.appDisplay;
|
||||||
|
const ContactDisplay = imports.ui.contactDisplay;
|
||||||
const Dash = imports.ui.dash;
|
const Dash = imports.ui.dash;
|
||||||
const DND = imports.ui.dnd;
|
const DND = imports.ui.dnd;
|
||||||
|
const DocDisplay = imports.ui.docDisplay;
|
||||||
|
const Lightbox = imports.ui.lightbox;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
const Panel = imports.ui.panel;
|
const Panel = imports.ui.panel;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const PlaceDisplay = imports.ui.placeDisplay;
|
const PlaceDisplay = imports.ui.placeDisplay;
|
||||||
const RemoteSearch = imports.ui.remoteSearch;
|
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
const ViewSelector = imports.ui.viewSelector;
|
const ViewSelector = imports.ui.viewSelector;
|
||||||
const Wanda = imports.ui.wanda;
|
|
||||||
const WorkspacesView = imports.ui.workspacesView;
|
const WorkspacesView = imports.ui.workspacesView;
|
||||||
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
|
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
|
||||||
|
|
||||||
@@ -45,9 +46,11 @@ const SwipeScrollResult = {
|
|||||||
CLICK: 2
|
CLICK: 2
|
||||||
};
|
};
|
||||||
|
|
||||||
const ShellInfo = new Lang.Class({
|
function ShellInfo() {
|
||||||
Name: 'ShellInfo',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShellInfo.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._source = null;
|
this._source = null;
|
||||||
this._undoCallback = null;
|
this._undoCallback = null;
|
||||||
@@ -75,7 +78,6 @@ const ShellInfo = new Lang.Class({
|
|||||||
let notification = null;
|
let notification = null;
|
||||||
if (this._source.notifications.length == 0) {
|
if (this._source.notifications.length == 0) {
|
||||||
notification = new MessageTray.Notification(this._source, text, null);
|
notification = new MessageTray.Notification(this._source, text, null);
|
||||||
notification.setShowWhenLocked(true);
|
|
||||||
} else {
|
} else {
|
||||||
notification = this._source.notifications[0];
|
notification = this._source.notifications[0];
|
||||||
notification.update(text, null, { clear: true });
|
notification.update(text, null, { clear: true });
|
||||||
@@ -93,19 +95,24 @@ const ShellInfo = new Lang.Class({
|
|||||||
|
|
||||||
this._source.notify(notification);
|
this._source.notify(notification);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const Overview = new Lang.Class({
|
function Overview() {
|
||||||
Name: 'Overview',
|
this._init.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
_init : function() {
|
Overview.prototype = {
|
||||||
this.isDummy = !Main.sessionMode.hasOverview;
|
_init : function(params) {
|
||||||
|
params = Params.parse(params, { isDummy: false });
|
||||||
|
|
||||||
|
this.isDummy = params.isDummy;
|
||||||
|
|
||||||
// We only have an overview in user sessions, so
|
// We only have an overview in user sessions, so
|
||||||
// create a dummy overview in other cases
|
// create a dummy overview in other cases
|
||||||
if (this.isDummy) {
|
if (this.isDummy) {
|
||||||
this.animationInProgress = false;
|
this.animationInProgress = false;
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
|
this.workspaces = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,10 +130,7 @@ const Overview = new Lang.Class({
|
|||||||
|
|
||||||
this._spacing = 0;
|
this._spacing = 0;
|
||||||
|
|
||||||
/* Translators: This is the main view to select
|
this._group = new St.Group({ name: 'overview',
|
||||||
activities. See also note for "Activities" string. */
|
|
||||||
this._group = new St.Widget({ name: 'overview',
|
|
||||||
accessible_name: _("Overview"),
|
|
||||||
reactive: true });
|
reactive: true });
|
||||||
this._group._delegate = this;
|
this._group._delegate = this;
|
||||||
this._group.connect('style-changed',
|
this._group.connect('style-changed',
|
||||||
@@ -180,6 +184,8 @@ const Overview = new Lang.Class({
|
|||||||
this._lastActiveWorkspaceIndex = -1;
|
this._lastActiveWorkspaceIndex = -1;
|
||||||
this._lastHoveredWindow = null;
|
this._lastHoveredWindow = null;
|
||||||
this._needsFakePointerEvent = false;
|
this._needsFakePointerEvent = false;
|
||||||
|
|
||||||
|
this.workspaces = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
// The members we construct that are implemented in JS might
|
// The members we construct that are implemented in JS might
|
||||||
@@ -202,14 +208,11 @@ const Overview = new Lang.Class({
|
|||||||
this._viewSelector.addViewTab('applications', _("Applications"), appView.actor, 'system-run');
|
this._viewSelector.addViewTab('applications', _("Applications"), appView.actor, 'system-run');
|
||||||
|
|
||||||
// Default search providers
|
// Default search providers
|
||||||
// Wanda comes obviously first
|
|
||||||
this.addSearchProvider(new Wanda.WandaSearchProvider());
|
|
||||||
this.addSearchProvider(new AppDisplay.AppSearchProvider());
|
this.addSearchProvider(new AppDisplay.AppSearchProvider());
|
||||||
this.addSearchProvider(new AppDisplay.SettingsSearchProvider());
|
this.addSearchProvider(new AppDisplay.SettingsSearchProvider());
|
||||||
this.addSearchProvider(new PlaceDisplay.PlaceSearchProvider());
|
this.addSearchProvider(new PlaceDisplay.PlaceSearchProvider());
|
||||||
|
this.addSearchProvider(new DocDisplay.DocSearchProvider());
|
||||||
// Load remote search providers provided by applications
|
this.addSearchProvider(new ContactDisplay.ContactSearchProvider());
|
||||||
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
|
|
||||||
|
|
||||||
// TODO - recalculate everything when desktop size changes
|
// TODO - recalculate everything when desktop size changes
|
||||||
this._dash = new Dash.Dash();
|
this._dash = new Dash.Dash();
|
||||||
@@ -356,7 +359,7 @@ const Overview = new Lang.Class({
|
|||||||
let direction;
|
let direction;
|
||||||
if (this._scrollDirection == SwipeScrollDirection.HORIZONTAL) {
|
if (this._scrollDirection == SwipeScrollDirection.HORIZONTAL) {
|
||||||
direction = stageX > this._dragStartX ? -1 : 1;
|
direction = stageX > this._dragStartX ? -1 : 1;
|
||||||
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||||
direction *= -1;
|
direction *= -1;
|
||||||
} else {
|
} else {
|
||||||
direction = stageY > this._dragStartY ? -1 : 1;
|
direction = stageY > this._dragStartY ? -1 : 1;
|
||||||
@@ -448,7 +451,7 @@ const Overview = new Lang.Class({
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (this._scrollDirection == SwipeScrollDirection.HORIZONTAL) {
|
if (this._scrollDirection == SwipeScrollDirection.HORIZONTAL) {
|
||||||
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||||
this._scrollAdjustment.value -= (dx / primary.width) * this._scrollAdjustment.page_size;
|
this._scrollAdjustment.value -= (dx / primary.width) * this._scrollAdjustment.page_size;
|
||||||
else
|
else
|
||||||
this._scrollAdjustment.value += (dx / primary.width) * this._scrollAdjustment.page_size;
|
this._scrollAdjustment.value += (dx / primary.width) * this._scrollAdjustment.page_size;
|
||||||
@@ -489,7 +492,7 @@ const Overview = new Lang.Class({
|
|||||||
this.hide();
|
this.hide();
|
||||||
|
|
||||||
let primary = Main.layoutManager.primaryMonitor;
|
let primary = Main.layoutManager.primaryMonitor;
|
||||||
let rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL);
|
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
|
||||||
|
|
||||||
let contentY = Main.panel.actor.height;
|
let contentY = Main.panel.actor.height;
|
||||||
let contentHeight = primary.height - contentY - Main.messageTray.actor.height;
|
let contentHeight = primary.height - contentY - Main.messageTray.actor.height;
|
||||||
@@ -588,10 +591,13 @@ const Overview = new Lang.Class({
|
|||||||
|
|
||||||
this._workspacesDisplay.show();
|
this._workspacesDisplay.show();
|
||||||
|
|
||||||
|
this.workspaces = this._workspacesDisplay.workspacesView;
|
||||||
|
global.overlay_group.add_actor(this.workspaces.actor);
|
||||||
|
|
||||||
if (!this._desktopFade.child)
|
if (!this._desktopFade.child)
|
||||||
this._desktopFade.child = this._getDesktopClone();
|
this._desktopFade.child = this._getDesktopClone();
|
||||||
|
|
||||||
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows()) {
|
if (!this.workspaces.getActiveWorkspace().hasMaximizedWindows()) {
|
||||||
this._desktopFade.opacity = 255;
|
this._desktopFade.opacity = 255;
|
||||||
this._desktopFade.show();
|
this._desktopFade.show();
|
||||||
Tweener.addTween(this._desktopFade,
|
Tweener.addTween(this._desktopFade,
|
||||||
@@ -726,7 +732,7 @@ const Overview = new Lang.Class({
|
|||||||
this.animationInProgress = true;
|
this.animationInProgress = true;
|
||||||
this._hideInProgress = true;
|
this._hideInProgress = true;
|
||||||
|
|
||||||
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows()) {
|
if (!this.workspaces.getActiveWorkspace().hasMaximizedWindows()) {
|
||||||
this._desktopFade.opacity = 0;
|
this._desktopFade.opacity = 0;
|
||||||
this._desktopFade.show();
|
this._desktopFade.show();
|
||||||
Tweener.addTween(this._desktopFade,
|
Tweener.addTween(this._desktopFade,
|
||||||
@@ -735,7 +741,7 @@ const Overview = new Lang.Class({
|
|||||||
transition: 'easeOutQuad' });
|
transition: 'easeOutQuad' });
|
||||||
}
|
}
|
||||||
|
|
||||||
this._workspacesDisplay.zoomFromOverview();
|
this.workspaces.hide();
|
||||||
|
|
||||||
// Make other elements fade out.
|
// Make other elements fade out.
|
||||||
Tweener.addTween(this._group,
|
Tweener.addTween(this._group,
|
||||||
@@ -777,6 +783,9 @@ const Overview = new Lang.Class({
|
|||||||
|
|
||||||
global.window_group.show();
|
global.window_group.show();
|
||||||
|
|
||||||
|
this.workspaces.destroy();
|
||||||
|
this.workspaces = null;
|
||||||
|
|
||||||
this._workspacesDisplay.hide();
|
this._workspacesDisplay.hide();
|
||||||
|
|
||||||
this._desktopFade.hide();
|
this._desktopFade.hide();
|
||||||
@@ -802,5 +811,5 @@ const Overview = new Lang.Class({
|
|||||||
this._needsFakePointerEvent = false;
|
this._needsFakePointerEvent = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(Overview.prototype);
|
Signals.addSignalMethods(Overview.prototype);
|
||||||
|
|||||||
443
js/ui/panel.js
@@ -3,19 +3,15 @@
|
|||||||
const Cairo = imports.cairo;
|
const Cairo = imports.cairo;
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const Gtk = imports.gi.Gtk;
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Meta = imports.gi.Meta;
|
|
||||||
const Pango = imports.gi.Pango;
|
const Pango = imports.gi.Pango;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const Atk = imports.gi.Atk;
|
|
||||||
|
|
||||||
|
const Config = imports.misc.config;
|
||||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||||
const DND = imports.ui.dnd;
|
|
||||||
const Layout = imports.ui.layout;
|
const Layout = imports.ui.layout;
|
||||||
const Overview = imports.ui.overview;
|
const Overview = imports.ui.overview;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
@@ -31,6 +27,33 @@ const BUTTON_DND_ACTIVATION_TIMEOUT = 250;
|
|||||||
const ANIMATED_ICON_UPDATE_TIMEOUT = 100;
|
const ANIMATED_ICON_UPDATE_TIMEOUT = 100;
|
||||||
const SPINNER_ANIMATION_TIME = 0.2;
|
const SPINNER_ANIMATION_TIME = 0.2;
|
||||||
|
|
||||||
|
const STANDARD_STATUS_AREA_ORDER = ['a11y', 'keyboard', 'volume', 'bluetooth', 'network', 'battery', 'userMenu'];
|
||||||
|
const STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION = {
|
||||||
|
'a11y': imports.ui.status.accessibility.ATIndicator,
|
||||||
|
'volume': imports.ui.status.volume.Indicator,
|
||||||
|
'battery': imports.ui.status.power.Indicator,
|
||||||
|
'keyboard': imports.ui.status.keyboard.XKBIndicator,
|
||||||
|
'userMenu': imports.ui.userMenu.UserMenuButton
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Config.HAVE_BLUETOOTH)
|
||||||
|
STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION['bluetooth'] = imports.ui.status.bluetooth.Indicator;
|
||||||
|
|
||||||
|
try {
|
||||||
|
STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION['network'] = imports.ui.status.network.NMApplet;
|
||||||
|
} catch(e) {
|
||||||
|
log('NMApplet is not supported. It is possible that your NetworkManager version is too old');
|
||||||
|
}
|
||||||
|
|
||||||
|
const GDM_STATUS_AREA_ORDER = ['a11y', 'display', 'keyboard', 'volume', 'battery', 'powerMenu'];
|
||||||
|
const GDM_STATUS_AREA_SHELL_IMPLEMENTATION = {
|
||||||
|
'a11y': imports.ui.status.accessibility.ATIndicator,
|
||||||
|
'volume': imports.ui.status.volume.Indicator,
|
||||||
|
'battery': imports.ui.status.power.Indicator,
|
||||||
|
'keyboard': imports.ui.status.keyboard.XKBIndicator,
|
||||||
|
'powerMenu': imports.gdm.powerMenu.PowerMenuButton
|
||||||
|
};
|
||||||
|
|
||||||
// To make sure the panel corners blend nicely with the panel,
|
// To make sure the panel corners blend nicely with the panel,
|
||||||
// we draw background and borders the same way, e.g. drawing
|
// we draw background and borders the same way, e.g. drawing
|
||||||
// them as filled shapes from the outside inwards instead of
|
// them as filled shapes from the outside inwards instead of
|
||||||
@@ -75,59 +98,54 @@ function _unpremultiply(color) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const AnimatedIcon = new Lang.Class({
|
function AnimatedIcon(name, size) {
|
||||||
Name: 'AnimatedIcon',
|
this._init(name, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimatedIcon.prototype = {
|
||||||
_init: function(name, size) {
|
_init: function(name, size) {
|
||||||
this.actor = new St.Bin({ visible: false });
|
this.actor = new St.Bin({ visible: false });
|
||||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||||
this.actor.connect('notify::visible', Lang.bind(this, this._onVisibleNotify));
|
this.actor.connect('notify::visible', Lang.bind(this, function() {
|
||||||
|
if (this.actor.visible) {
|
||||||
|
this._timeoutId = Mainloop.timeout_add(ANIMATED_ICON_UPDATE_TIMEOUT, Lang.bind(this, this._update));
|
||||||
|
} else {
|
||||||
|
if (this._timeoutId)
|
||||||
|
Mainloop.source_remove(this._timeoutId);
|
||||||
|
this._timeoutId = 0;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
this._timeoutId = 0;
|
this._timeoutId = 0;
|
||||||
this._frame = 0;
|
this._i = 0;
|
||||||
this._animations = St.TextureCache.get_default().load_sliced_image (global.datadir + '/theme/' + name, size, size);
|
this._animations = St.TextureCache.get_default().load_sliced_image (global.datadir + '/theme/' + name, size, size);
|
||||||
this.actor.set_child(this._animations);
|
this.actor.set_child(this._animations);
|
||||||
},
|
},
|
||||||
|
|
||||||
_disconnectTimeout: function() {
|
|
||||||
if (this._timeoutId > 0) {
|
|
||||||
Mainloop.source_remove(this._timeoutId);
|
|
||||||
this._timeoutId = 0;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_onVisibleNotify: function() {
|
|
||||||
if (this.actor.visible)
|
|
||||||
this._timeoutId = Mainloop.timeout_add(ANIMATED_ICON_UPDATE_TIMEOUT, Lang.bind(this, this._update));
|
|
||||||
else
|
|
||||||
this._disconnectTimeout();
|
|
||||||
},
|
|
||||||
|
|
||||||
_showFrame: function(frame) {
|
|
||||||
let oldFrameActor = this._animations.get_child_at_index(this._frame);
|
|
||||||
if (oldFrameActor)
|
|
||||||
oldFrameActor.hide();
|
|
||||||
|
|
||||||
this._frame = (frame % this._animations.get_n_children());
|
|
||||||
|
|
||||||
let newFrameActor = this._animations.get_child_at_index(this._frame);
|
|
||||||
if (newFrameActor)
|
|
||||||
newFrameActor.show();
|
|
||||||
},
|
|
||||||
|
|
||||||
_update: function() {
|
_update: function() {
|
||||||
this._showFrame(this._frame + 1);
|
this._animations.hide_all();
|
||||||
|
this._animations.show();
|
||||||
|
if (this._i && this._i < this._animations.get_n_children())
|
||||||
|
this._animations.get_nth_child(this._i++).show();
|
||||||
|
else {
|
||||||
|
this._i = 1;
|
||||||
|
if (this._animations.get_n_children())
|
||||||
|
this._animations.get_nth_child(0).show();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDestroy: function() {
|
_onDestroy: function() {
|
||||||
this._disconnectTimeout();
|
if (this._timeoutId)
|
||||||
|
Mainloop.source_remove(this._timeoutId);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const TextShadower = new Lang.Class({
|
function TextShadower() {
|
||||||
Name: 'TextShadower',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
TextShadower.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.actor = new Shell.GenericContainer();
|
this.actor = new Shell.GenericContainer();
|
||||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||||
@@ -207,7 +225,7 @@ const TextShadower = new Lang.Class({
|
|||||||
child.allocate(childBox, flags);
|
child.allocate(childBox, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AppMenuButton:
|
* AppMenuButton:
|
||||||
@@ -217,26 +235,22 @@ const TextShadower = new Lang.Class({
|
|||||||
* this menu also handles startup notification for it. So when we
|
* this menu also handles startup notification for it. So when we
|
||||||
* have an active startup notification, we switch modes to display that.
|
* have an active startup notification, we switch modes to display that.
|
||||||
*/
|
*/
|
||||||
const AppMenuButton = new Lang.Class({
|
function AppMenuButton() {
|
||||||
Name: 'AppMenuButton',
|
this._init();
|
||||||
Extends: PanelMenu.Button,
|
}
|
||||||
|
|
||||||
_init: function(menuManager) {
|
AppMenuButton.prototype = {
|
||||||
this.parent(0.0, null, true);
|
__proto__: PanelMenu.Button.prototype,
|
||||||
|
|
||||||
this.actor.accessible_role = Atk.Role.MENU;
|
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
PanelMenu.Button.prototype._init.call(this, 0.0);
|
||||||
this._startingApps = [];
|
this._startingApps = [];
|
||||||
|
|
||||||
this._menuManager = menuManager;
|
|
||||||
this._targetApp = null;
|
this._targetApp = null;
|
||||||
this._appMenuNotifyId = 0;
|
|
||||||
this._actionGroupNotifyId = 0;
|
|
||||||
|
|
||||||
let bin = new St.Bin({ name: 'appMenu' });
|
let bin = new St.Bin({ name: 'appMenu' });
|
||||||
this.actor.add_actor(bin);
|
this.actor.add_actor(bin);
|
||||||
|
|
||||||
this.actor.bind_property("reactive", this.actor, "can-focus", 0);
|
|
||||||
this.actor.reactive = false;
|
this.actor.reactive = false;
|
||||||
this._targetIsCurrent = false;
|
this._targetIsCurrent = false;
|
||||||
|
|
||||||
@@ -257,6 +271,10 @@ const AppMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
this._iconBottomClip = 0;
|
this._iconBottomClip = 0;
|
||||||
|
|
||||||
|
this._quitMenu = new PopupMenu.PopupMenuItem('');
|
||||||
|
this.menu.addMenuItem(this._quitMenu);
|
||||||
|
this._quitMenu.connect('activate', Lang.bind(this, this._onQuit));
|
||||||
|
|
||||||
this._visible = !Main.overview.visible;
|
this._visible = !Main.overview.visible;
|
||||||
if (!this._visible)
|
if (!this._visible)
|
||||||
this.actor.hide();
|
this.actor.hide();
|
||||||
@@ -276,7 +294,7 @@ const AppMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
let tracker = Shell.WindowTracker.get_default();
|
let tracker = Shell.WindowTracker.get_default();
|
||||||
let appSys = Shell.AppSystem.get_default();
|
let appSys = Shell.AppSystem.get_default();
|
||||||
tracker.connect('notify::focus-app', Lang.bind(this, this._focusAppChanged));
|
tracker.connect('notify::focus-app', Lang.bind(this, this._sync));
|
||||||
appSys.connect('app-state-changed', Lang.bind(this, this._onAppStateChanged));
|
appSys.connect('app-state-changed', Lang.bind(this, this._onAppStateChanged));
|
||||||
|
|
||||||
global.window_manager.connect('switch-workspace', Lang.bind(this, this._sync));
|
global.window_manager.connect('switch-workspace', Lang.bind(this, this._sync));
|
||||||
@@ -290,12 +308,11 @@ const AppMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
this._visible = true;
|
this._visible = true;
|
||||||
this.actor.show();
|
this.actor.show();
|
||||||
|
this.actor.reactive = true;
|
||||||
|
|
||||||
if (!this._targetIsCurrent)
|
if (!this._targetIsCurrent)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.actor.reactive = true;
|
|
||||||
|
|
||||||
Tweener.removeTweens(this.actor);
|
Tweener.removeTweens(this.actor);
|
||||||
Tweener.addTween(this.actor,
|
Tweener.addTween(this.actor,
|
||||||
{ opacity: 255,
|
{ opacity: 255,
|
||||||
@@ -346,7 +363,6 @@ const AppMenuButton = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
this._stop = true;
|
this._stop = true;
|
||||||
this.actor.reactive = true;
|
|
||||||
Tweener.addTween(this._spinner.actor,
|
Tweener.addTween(this._spinner.actor,
|
||||||
{ opacity: 0,
|
{ opacity: 0,
|
||||||
time: SPINNER_ANIMATION_TIME,
|
time: SPINNER_ANIMATION_TIME,
|
||||||
@@ -361,7 +377,6 @@ const AppMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
startAnimation: function() {
|
startAnimation: function() {
|
||||||
this._stop = false;
|
this._stop = false;
|
||||||
this.actor.reactive = false;
|
|
||||||
this._spinner.actor.show();
|
this._spinner.actor.show();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -392,12 +407,12 @@ const AppMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
let [minWidth, minHeight, naturalWidth, naturalHeight] = this._iconBox.get_preferred_size();
|
let [minWidth, minHeight, naturalWidth, naturalHeight] = this._iconBox.get_preferred_size();
|
||||||
|
|
||||||
let direction = this.actor.get_text_direction();
|
let direction = this.actor.get_direction();
|
||||||
|
|
||||||
let yPadding = Math.floor(Math.max(0, allocHeight - naturalHeight) / 2);
|
let yPadding = Math.floor(Math.max(0, allocHeight - naturalHeight) / 2);
|
||||||
childBox.y1 = yPadding;
|
childBox.y1 = yPadding;
|
||||||
childBox.y2 = childBox.y1 + Math.min(naturalHeight, allocHeight);
|
childBox.y2 = childBox.y1 + Math.min(naturalHeight, allocHeight);
|
||||||
if (direction == Clutter.TextDirection.LTR) {
|
if (direction == St.TextDirection.LTR) {
|
||||||
childBox.x1 = 0;
|
childBox.x1 = 0;
|
||||||
childBox.x2 = childBox.x1 + Math.min(naturalWidth, allocWidth);
|
childBox.x2 = childBox.x1 + Math.min(naturalWidth, allocWidth);
|
||||||
} else {
|
} else {
|
||||||
@@ -414,7 +429,7 @@ const AppMenuButton = new Lang.Class({
|
|||||||
childBox.y1 = yPadding;
|
childBox.y1 = yPadding;
|
||||||
childBox.y2 = childBox.y1 + Math.min(naturalHeight, allocHeight);
|
childBox.y2 = childBox.y1 + Math.min(naturalHeight, allocHeight);
|
||||||
|
|
||||||
if (direction == Clutter.TextDirection.LTR) {
|
if (direction == St.TextDirection.LTR) {
|
||||||
childBox.x1 = Math.floor(iconWidth / 2);
|
childBox.x1 = Math.floor(iconWidth / 2);
|
||||||
childBox.x2 = Math.min(childBox.x1 + naturalWidth, allocWidth);
|
childBox.x2 = Math.min(childBox.x1 + naturalWidth, allocWidth);
|
||||||
} else {
|
} else {
|
||||||
@@ -423,7 +438,7 @@ const AppMenuButton = new Lang.Class({
|
|||||||
}
|
}
|
||||||
this._label.actor.allocate(childBox, flags);
|
this._label.actor.allocate(childBox, flags);
|
||||||
|
|
||||||
if (direction == Clutter.TextDirection.LTR) {
|
if (direction == St.TextDirection.LTR) {
|
||||||
childBox.x1 = Math.floor(iconWidth / 2) + this._label.actor.width;
|
childBox.x1 = Math.floor(iconWidth / 2) + this._label.actor.width;
|
||||||
childBox.x2 = childBox.x1 + this._spinner.actor.width;
|
childBox.x2 = childBox.x1 + this._spinner.actor.width;
|
||||||
childBox.y1 = box.y1;
|
childBox.y1 = box.y1;
|
||||||
@@ -438,6 +453,12 @@ const AppMenuButton = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onQuit: function() {
|
||||||
|
if (this._targetApp == null)
|
||||||
|
return;
|
||||||
|
this._targetApp.request_quit();
|
||||||
|
},
|
||||||
|
|
||||||
_onAppStateChanged: function(appSys, app) {
|
_onAppStateChanged: function(appSys, app) {
|
||||||
let state = app.state;
|
let state = app.state;
|
||||||
if (state != Shell.AppState.STARTING) {
|
if (state != Shell.AppState.STARTING) {
|
||||||
@@ -454,9 +475,16 @@ const AppMenuButton = new Lang.Class({
|
|||||||
this._sync();
|
this._sync();
|
||||||
},
|
},
|
||||||
|
|
||||||
_focusAppChanged: function() {
|
_sync: function() {
|
||||||
let tracker = Shell.WindowTracker.get_default();
|
let tracker = Shell.WindowTracker.get_default();
|
||||||
|
let lastStartedApp = null;
|
||||||
|
let workspace = global.screen.get_active_workspace();
|
||||||
|
for (let i = 0; i < this._startingApps.length; i++)
|
||||||
|
if (this._startingApps[i].is_on_workspace(workspace))
|
||||||
|
lastStartedApp = this._startingApps[i];
|
||||||
|
|
||||||
let focusedApp = tracker.focus_app;
|
let focusedApp = tracker.focus_app;
|
||||||
|
|
||||||
if (!focusedApp) {
|
if (!focusedApp) {
|
||||||
// If the app has just lost focus to the panel, pretend
|
// If the app has just lost focus to the panel, pretend
|
||||||
// nothing happened; otherwise you can't keynav to the
|
// nothing happened; otherwise you can't keynav to the
|
||||||
@@ -464,24 +492,6 @@ const AppMenuButton = new Lang.Class({
|
|||||||
if (global.stage_input_mode == Shell.StageInputMode.FOCUSED)
|
if (global.stage_input_mode == Shell.StageInputMode.FOCUSED)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._sync();
|
|
||||||
},
|
|
||||||
|
|
||||||
setLockedState: function(locked) {
|
|
||||||
if (locked)
|
|
||||||
this.hide();
|
|
||||||
else
|
|
||||||
this._sync();
|
|
||||||
},
|
|
||||||
|
|
||||||
_sync: function() {
|
|
||||||
let tracker = Shell.WindowTracker.get_default();
|
|
||||||
let focusedApp = tracker.focus_app;
|
|
||||||
let lastStartedApp = null;
|
|
||||||
let workspace = global.screen.get_active_workspace();
|
|
||||||
for (let i = 0; i < this._startingApps.length; i++)
|
|
||||||
if (this._startingApps[i].is_on_workspace(workspace))
|
|
||||||
lastStartedApp = this._startingApps[i];
|
|
||||||
|
|
||||||
let targetApp = focusedApp != null ? focusedApp : lastStartedApp;
|
let targetApp = focusedApp != null ? focusedApp : lastStartedApp;
|
||||||
|
|
||||||
@@ -499,9 +509,6 @@ const AppMenuButton = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!targetApp.is_on_workspace(workspace))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!this._targetIsCurrent) {
|
if (!this._targetIsCurrent) {
|
||||||
this.actor.reactive = true;
|
this.actor.reactive = true;
|
||||||
this._targetIsCurrent = true;
|
this._targetIsCurrent = true;
|
||||||
@@ -513,10 +520,8 @@ const AppMenuButton = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (targetApp == this._targetApp) {
|
if (targetApp == this._targetApp) {
|
||||||
if (targetApp && targetApp.get_state() != Shell.AppState.STARTING) {
|
if (targetApp && targetApp.get_state() != Shell.AppState.STARTING)
|
||||||
this.stopAnimation();
|
this.stopAnimation();
|
||||||
this._maybeSetMenu();
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,72 +531,37 @@ const AppMenuButton = new Lang.Class({
|
|||||||
this._iconBox.hide();
|
this._iconBox.hide();
|
||||||
this._label.setText('');
|
this._label.setText('');
|
||||||
|
|
||||||
if (this._appMenuNotifyId)
|
|
||||||
this._targetApp.disconnect(this._appMenuNotifyId);
|
|
||||||
if (this._actionGroupNotifyId)
|
|
||||||
this._targetApp.disconnect(this._actionGroupNotifyId);
|
|
||||||
if (targetApp) {
|
|
||||||
this._appMenuNotifyId = targetApp.connect('notify::menu', Lang.bind(this, this._sync));
|
|
||||||
this._actionGroupNotifyId = targetApp.connect('notify::action-group', Lang.bind(this, this._sync));
|
|
||||||
} else {
|
|
||||||
this._appMenuNotifyId = 0;
|
|
||||||
this._actionGroupNotifyId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._targetApp = targetApp;
|
this._targetApp = targetApp;
|
||||||
let icon = targetApp.get_faded_icon(2 * PANEL_ICON_SIZE);
|
let icon = targetApp.get_faded_icon(2 * PANEL_ICON_SIZE);
|
||||||
|
|
||||||
this._label.setText(targetApp.get_name());
|
this._label.setText(targetApp.get_name());
|
||||||
this.setName(targetApp.get_name());
|
// TODO - _quit() doesn't really work on apps in state STARTING yet
|
||||||
|
this._quitMenu.label.set_text(_("Quit %s").format(targetApp.get_name()));
|
||||||
|
|
||||||
this._iconBox.set_child(icon);
|
this._iconBox.set_child(icon);
|
||||||
this._iconBox.show();
|
this._iconBox.show();
|
||||||
|
|
||||||
if (targetApp.get_state() == Shell.AppState.STARTING)
|
if (targetApp.get_state() == Shell.AppState.STARTING)
|
||||||
this.startAnimation();
|
this.startAnimation();
|
||||||
else
|
|
||||||
this._maybeSetMenu();
|
|
||||||
|
|
||||||
this.emit('changed');
|
this.emit('changed');
|
||||||
},
|
|
||||||
|
|
||||||
_maybeSetMenu: function() {
|
|
||||||
let menu;
|
|
||||||
|
|
||||||
if (this._targetApp.action_group && this._targetApp.menu) {
|
|
||||||
if (this.menu instanceof PopupMenu.RemoteMenu &&
|
|
||||||
this.menu.actionGroup == this._targetApp.action_group)
|
|
||||||
return;
|
|
||||||
|
|
||||||
menu = new PopupMenu.RemoteMenu(this.actor, this._targetApp.menu, this._targetApp.action_group);
|
|
||||||
} else {
|
|
||||||
if (this.menu && !(this.menu instanceof PopupMenu.RemoteMenu))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// fallback to older menu
|
|
||||||
menu = new PopupMenu.PopupMenu(this.actor, 0.0, St.Side.TOP, 0);
|
|
||||||
menu.addAction(_("Quit"), Lang.bind(this, function() {
|
|
||||||
this._targetApp.request_quit();
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
this.setMenu(menu);
|
|
||||||
this._menuManager.addMenu(menu);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Signals.addSignalMethods(AppMenuButton.prototype);
|
Signals.addSignalMethods(AppMenuButton.prototype);
|
||||||
|
|
||||||
// Activities button. Because everything else in the top bar is a
|
// Activities button. Because everything else in the top bar is a
|
||||||
// PanelMenu.Button, it simplifies some things to make this be one too.
|
// PanelMenu.Button, it simplifies some things to make this be one too.
|
||||||
// We just hack it up to not actually have a menu attached to it.
|
// We just hack it up to not actually have a menu attached to it.
|
||||||
const ActivitiesButton = new Lang.Class({
|
function ActivitiesButton() {
|
||||||
Name: 'ActivitiesButton',
|
this._init.apply(this, arguments);
|
||||||
Extends: PanelMenu.Button,
|
}
|
||||||
|
|
||||||
|
ActivitiesButton.prototype = {
|
||||||
|
__proto__: PanelMenu.Button.prototype,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent(0.0);
|
PanelMenu.Button.prototype._init.call(this, 0.0);
|
||||||
this.actor.accessible_role = Atk.Role.TOGGLE_BUTTON;
|
|
||||||
|
|
||||||
let container = new Shell.GenericContainer();
|
let container = new Shell.GenericContainer();
|
||||||
container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth));
|
container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth));
|
||||||
@@ -605,8 +575,6 @@ const ActivitiesButton = new Lang.Class({
|
|||||||
this._label = new St.Label({ text: _("Activities") });
|
this._label = new St.Label({ text: _("Activities") });
|
||||||
container.add_actor(this._label);
|
container.add_actor(this._label);
|
||||||
|
|
||||||
this.actor.label_actor = this._label;
|
|
||||||
|
|
||||||
this._hotCorner = new Layout.HotCorner();
|
this._hotCorner = new Layout.HotCorner();
|
||||||
container.add_actor(this._hotCorner.actor);
|
container.add_actor(this._hotCorner.actor);
|
||||||
|
|
||||||
@@ -622,12 +590,10 @@ const ActivitiesButton = new Lang.Class({
|
|||||||
Main.overview.connect('showing', Lang.bind(this, function() {
|
Main.overview.connect('showing', Lang.bind(this, function() {
|
||||||
this.actor.add_style_pseudo_class('overview');
|
this.actor.add_style_pseudo_class('overview');
|
||||||
this._escapeMenuGrab();
|
this._escapeMenuGrab();
|
||||||
this.actor.add_accessible_state (Atk.StateType.CHECKED);
|
|
||||||
}));
|
}));
|
||||||
Main.overview.connect('hiding', Lang.bind(this, function() {
|
Main.overview.connect('hiding', Lang.bind(this, function() {
|
||||||
this.actor.remove_style_pseudo_class('overview');
|
this.actor.remove_style_pseudo_class('overview');
|
||||||
this._escapeMenuGrab();
|
this._escapeMenuGrab();
|
||||||
this.actor.remove_accessible_state (Atk.StateType.CHECKED);
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._xdndTimeOut = 0;
|
this._xdndTimeOut = 0;
|
||||||
@@ -649,7 +615,7 @@ const ActivitiesButton = new Lang.Class({
|
|||||||
let primary = Main.layoutManager.primaryMonitor;
|
let primary = Main.layoutManager.primaryMonitor;
|
||||||
let hotBox = new Clutter.ActorBox();
|
let hotBox = new Clutter.ActorBox();
|
||||||
let ok, x, y;
|
let ok, x, y;
|
||||||
if (actor.get_text_direction() == Clutter.TextDirection.LTR) {
|
if (actor.get_direction() == St.TextDirection.LTR) {
|
||||||
[ok, x, y] = actor.transform_stage_point(primary.x, primary.y)
|
[ok, x, y] = actor.transform_stage_point(primary.x, primary.y)
|
||||||
} else {
|
} else {
|
||||||
[ok, x, y] = actor.transform_stage_point(primary.x + primary.width, primary.y);
|
[ok, x, y] = actor.transform_stage_point(primary.x + primary.width, primary.y);
|
||||||
@@ -666,14 +632,12 @@ const ActivitiesButton = new Lang.Class({
|
|||||||
|
|
||||||
handleDragOver: function(source, actor, x, y, time) {
|
handleDragOver: function(source, actor, x, y, time) {
|
||||||
if (source != Main.xdndHandler)
|
if (source != Main.xdndHandler)
|
||||||
return DND.DragMotionResult.CONTINUE;
|
return;
|
||||||
|
|
||||||
if (this._xdndTimeOut != 0)
|
if (this._xdndTimeOut != 0)
|
||||||
Mainloop.source_remove(this._xdndTimeOut);
|
Mainloop.source_remove(this._xdndTimeOut);
|
||||||
this._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT,
|
this._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT,
|
||||||
Lang.bind(this, this._xdndShowOverview, actor));
|
Lang.bind(this, this._xdndShowOverview, actor));
|
||||||
|
|
||||||
return DND.DragMotionResult.CONTINUE;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_escapeMenuGrab: function() {
|
_escapeMenuGrab: function() {
|
||||||
@@ -734,11 +698,13 @@ const ActivitiesButton = new Lang.Class({
|
|||||||
Mainloop.source_remove(this._xdndTimeOut);
|
Mainloop.source_remove(this._xdndTimeOut);
|
||||||
this._xdndTimeOut = 0;
|
this._xdndTimeOut = 0;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const PanelCorner = new Lang.Class({
|
function PanelCorner(panel, side) {
|
||||||
Name: 'PanelCorner',
|
this._init(panel, side);
|
||||||
|
}
|
||||||
|
|
||||||
|
PanelCorner.prototype = {
|
||||||
_init: function(box, side) {
|
_init: function(box, side) {
|
||||||
this._side = side;
|
this._side = side;
|
||||||
|
|
||||||
@@ -760,11 +726,10 @@ const PanelCorner = new Lang.Class({
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Start at the back and work backward
|
// Start at the back and work backward
|
||||||
let index;
|
let index = children.length - 1;
|
||||||
for (index = children.length - 1; index >= 0; index--) {
|
while (!children[index].visible && index >= 0)
|
||||||
if (children[index].visible)
|
index--;
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -785,11 +750,10 @@ const PanelCorner = new Lang.Class({
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Start at the front and work forward
|
// Start at the front and work forward
|
||||||
let index;
|
let index = 0;
|
||||||
for (index = 0; index < children.length; index++) {
|
while (!children[index].visible && index < children.length)
|
||||||
if (children[index].visible)
|
index++;
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (index == children.length)
|
if (index == children.length)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -805,7 +769,7 @@ const PanelCorner = new Lang.Class({
|
|||||||
|
|
||||||
let rtlAwareContainer = this._box instanceof St.BoxLayout;
|
let rtlAwareContainer = this._box instanceof St.BoxLayout;
|
||||||
if (rtlAwareContainer &&
|
if (rtlAwareContainer &&
|
||||||
this._box.get_text_direction() == Clutter.TextDirection.RTL) {
|
this._box.get_direction() == St.TextDirection.RTL) {
|
||||||
if (this._side == St.Side.LEFT)
|
if (this._side == St.Side.LEFT)
|
||||||
side = St.Side.RIGHT;
|
side = St.Side.RIGHT;
|
||||||
else if (this._side == St.Side.RIGHT)
|
else if (this._side == St.Side.RIGHT)
|
||||||
@@ -851,10 +815,12 @@ const PanelCorner = new Lang.Class({
|
|||||||
let node = this.actor.get_theme_node();
|
let node = this.actor.get_theme_node();
|
||||||
|
|
||||||
let cornerRadius = node.get_length("-panel-corner-radius");
|
let cornerRadius = node.get_length("-panel-corner-radius");
|
||||||
let borderWidth = node.get_length('-panel-corner-border-width');
|
let innerBorderWidth = node.get_length('-panel-corner-inner-border-width');
|
||||||
|
let outerBorderWidth = node.get_length('-panel-corner-outer-border-width');
|
||||||
|
|
||||||
let backgroundColor = node.get_color('-panel-corner-background-color');
|
let backgroundColor = node.get_color('-panel-corner-background-color');
|
||||||
let borderColor = node.get_color('-panel-corner-border-color');
|
let innerBorderColor = node.get_color('-panel-corner-inner-border-color');
|
||||||
|
let outerBorderColor = node.get_color('-panel-corner-outer-border-color');
|
||||||
|
|
||||||
let cr = this.actor.get_context();
|
let cr = this.actor.get_context();
|
||||||
cr.setOperator(Cairo.Operator.SOURCE);
|
cr.setOperator(Cairo.Operator.SOURCE);
|
||||||
@@ -862,23 +828,40 @@ const PanelCorner = new Lang.Class({
|
|||||||
cr.moveTo(0, 0);
|
cr.moveTo(0, 0);
|
||||||
if (this._side == St.Side.LEFT)
|
if (this._side == St.Side.LEFT)
|
||||||
cr.arc(cornerRadius,
|
cr.arc(cornerRadius,
|
||||||
borderWidth + cornerRadius,
|
innerBorderWidth + cornerRadius,
|
||||||
cornerRadius, Math.PI, 3 * Math.PI / 2);
|
cornerRadius, Math.PI, 3 * Math.PI / 2);
|
||||||
else
|
else
|
||||||
cr.arc(0,
|
cr.arc(0,
|
||||||
borderWidth + cornerRadius,
|
innerBorderWidth + cornerRadius,
|
||||||
cornerRadius, 3 * Math.PI / 2, 2 * Math.PI);
|
cornerRadius, 3 * Math.PI / 2, 2 * Math.PI);
|
||||||
cr.lineTo(cornerRadius, 0);
|
cr.lineTo(cornerRadius, 0);
|
||||||
cr.closePath();
|
cr.closePath();
|
||||||
|
|
||||||
let savedPath = cr.copyPath();
|
let savedPath = cr.copyPath();
|
||||||
|
|
||||||
let xOffsetDirection = this._side == St.Side.LEFT ? -1 : 1;
|
let over = _over(innerBorderColor,
|
||||||
let over = _over(borderColor, backgroundColor);
|
_over(outerBorderColor, backgroundColor));
|
||||||
Clutter.cairo_set_source_color(cr, over);
|
Clutter.cairo_set_source_color(cr, over);
|
||||||
cr.fill();
|
cr.fill();
|
||||||
|
|
||||||
let offset = borderWidth;
|
let xOffsetDirection = this._side == St.Side.LEFT ? -1 : 1;
|
||||||
|
let offset = outerBorderWidth;
|
||||||
|
over = _over(innerBorderColor, backgroundColor);
|
||||||
|
Clutter.cairo_set_source_color(cr, over);
|
||||||
|
|
||||||
|
cr.save();
|
||||||
|
cr.translate(xOffsetDirection * offset, - offset);
|
||||||
|
cr.appendPath(savedPath);
|
||||||
|
cr.fill();
|
||||||
|
cr.restore();
|
||||||
|
|
||||||
|
if (this._side == St.Side.LEFT)
|
||||||
|
cr.rectangle(cornerRadius - offset, 0, offset, outerBorderWidth);
|
||||||
|
else
|
||||||
|
cr.rectangle(0, 0, offset, outerBorderWidth);
|
||||||
|
cr.fill();
|
||||||
|
|
||||||
|
offset = innerBorderWidth;
|
||||||
Clutter.cairo_set_source_color(cr, backgroundColor);
|
Clutter.cairo_set_source_color(cr, backgroundColor);
|
||||||
|
|
||||||
cr.save();
|
cr.save();
|
||||||
@@ -892,17 +875,19 @@ const PanelCorner = new Lang.Class({
|
|||||||
let node = this.actor.get_theme_node();
|
let node = this.actor.get_theme_node();
|
||||||
|
|
||||||
let cornerRadius = node.get_length("-panel-corner-radius");
|
let cornerRadius = node.get_length("-panel-corner-radius");
|
||||||
let borderWidth = node.get_length('-panel-corner-border-width');
|
let innerBorderWidth = node.get_length('-panel-corner-inner-border-width');
|
||||||
|
|
||||||
this.actor.set_size(cornerRadius, borderWidth + cornerRadius);
|
this.actor.set_size(cornerRadius, innerBorderWidth + cornerRadius);
|
||||||
this.actor.set_anchor_point(0, borderWidth);
|
this.actor.set_anchor_point(0, innerBorderWidth);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
|
||||||
const Panel = new Lang.Class({
|
function Panel() {
|
||||||
Name: 'Panel',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
Panel.prototype = {
|
||||||
_init : function() {
|
_init : function() {
|
||||||
this.actor = new Shell.GenericContainer({ name: 'panel',
|
this.actor = new Shell.GenericContainer({ name: 'panel',
|
||||||
reactive: true });
|
reactive: true });
|
||||||
@@ -917,8 +902,6 @@ const Panel = new Lang.Class({
|
|||||||
this.actor.remove_style_class_name('in-overview');
|
this.actor.remove_style_class_name('in-overview');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Main.screenShield.connect('lock-status-changed', Lang.bind(this, this._onLockStateChanged));
|
|
||||||
|
|
||||||
this._menus = new PopupMenu.PopupMenuManager(this);
|
this._menus = new PopupMenu.PopupMenuManager(this);
|
||||||
|
|
||||||
this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
|
this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
|
||||||
@@ -928,14 +911,14 @@ const Panel = new Lang.Class({
|
|||||||
this._rightBox = new St.BoxLayout({ name: 'panelRight' });
|
this._rightBox = new St.BoxLayout({ name: 'panelRight' });
|
||||||
this.actor.add_actor(this._rightBox);
|
this.actor.add_actor(this._rightBox);
|
||||||
|
|
||||||
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL)
|
if (this.actor.get_direction() == St.TextDirection.RTL)
|
||||||
this._leftCorner = new PanelCorner(this._rightBox, St.Side.LEFT);
|
this._leftCorner = new PanelCorner(this._rightBox, St.Side.LEFT);
|
||||||
else
|
else
|
||||||
this._leftCorner = new PanelCorner(this._leftBox, St.Side.LEFT);
|
this._leftCorner = new PanelCorner(this._leftBox, St.Side.LEFT);
|
||||||
|
|
||||||
this.actor.add_actor(this._leftCorner.actor);
|
this.actor.add_actor(this._leftCorner.actor);
|
||||||
|
|
||||||
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL)
|
if (this.actor.get_direction() == St.TextDirection.RTL)
|
||||||
this._rightCorner = new PanelCorner(this._leftBox, St.Side.RIGHT);
|
this._rightCorner = new PanelCorner(this._leftBox, St.Side.RIGHT);
|
||||||
else
|
else
|
||||||
this._rightCorner = new PanelCorner(this._rightBox, St.Side.RIGHT);
|
this._rightCorner = new PanelCorner(this._rightBox, St.Side.RIGHT);
|
||||||
@@ -944,10 +927,9 @@ const Panel = new Lang.Class({
|
|||||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
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('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||||
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
|
||||||
|
|
||||||
/* Button on the left side of the panel. */
|
/* Button on the left side of the panel. */
|
||||||
if (Main.sessionMode.hasOverview) {
|
if (global.session_type == Shell.SessionType.USER) {
|
||||||
this._activitiesButton = new ActivitiesButton();
|
this._activitiesButton = new ActivitiesButton();
|
||||||
this._activities = this._activitiesButton.actor;
|
this._activities = this._activitiesButton.actor;
|
||||||
this._leftBox.add(this._activities);
|
this._leftBox.add(this._activities);
|
||||||
@@ -955,18 +937,32 @@ const Panel = new Lang.Class({
|
|||||||
// The activities button has a pretend menu, so as to integrate
|
// The activities button has a pretend menu, so as to integrate
|
||||||
// more cleanly with the rest of the panel
|
// more cleanly with the rest of the panel
|
||||||
this._menus.addMenu(this._activitiesButton.menu);
|
this._menus.addMenu(this._activitiesButton.menu);
|
||||||
}
|
|
||||||
|
|
||||||
if (Main.sessionMode.hasAppMenu) {
|
this._appMenu = new AppMenuButton();
|
||||||
this._appMenu = new AppMenuButton(this._menus);
|
|
||||||
this._leftBox.add(this._appMenu.actor);
|
this._leftBox.add(this._appMenu.actor);
|
||||||
|
this._menus.addMenu(this._appMenu.menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* center */
|
/* center */
|
||||||
this._dateMenu = new DateMenu.DateMenuButton();
|
if (global.session_type == Shell.SessionType.USER)
|
||||||
|
this._dateMenu = new DateMenu.DateMenuButton({ showEvents: true });
|
||||||
|
else
|
||||||
|
this._dateMenu = new DateMenu.DateMenuButton({ showEvents: false });
|
||||||
this._centerBox.add(this._dateMenu.actor, { y_fill: true });
|
this._centerBox.add(this._dateMenu.actor, { y_fill: true });
|
||||||
this._menus.addMenu(this._dateMenu.menu);
|
this._menus.addMenu(this._dateMenu.menu);
|
||||||
|
|
||||||
|
/* right */
|
||||||
|
if (global.session_type == Shell.SessionType.GDM) {
|
||||||
|
this._status_area_order = GDM_STATUS_AREA_ORDER;
|
||||||
|
this._status_area_shell_implementation = GDM_STATUS_AREA_SHELL_IMPLEMENTATION;
|
||||||
|
} else {
|
||||||
|
this._status_area_order = STANDARD_STATUS_AREA_ORDER;
|
||||||
|
this._status_area_shell_implementation = STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
Main.statusIconDispatcher.connect('status-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
||||||
|
Main.statusIconDispatcher.connect('status-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
|
||||||
|
|
||||||
Main.layoutManager.panelBox.add(this.actor);
|
Main.layoutManager.panelBox.add(this.actor);
|
||||||
Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'start-here',
|
Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'start-here',
|
||||||
{ sortGroup: CtrlAltTab.SortGroup.TOP });
|
{ sortGroup: CtrlAltTab.SortGroup.TOP });
|
||||||
@@ -999,7 +995,7 @@ const Panel = new Lang.Class({
|
|||||||
|
|
||||||
childBox.y1 = 0;
|
childBox.y1 = 0;
|
||||||
childBox.y2 = allocHeight;
|
childBox.y2 = allocHeight;
|
||||||
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL) {
|
if (this.actor.get_direction() == St.TextDirection.RTL) {
|
||||||
childBox.x1 = allocWidth - Math.min(Math.floor(sideWidth),
|
childBox.x1 = allocWidth - Math.min(Math.floor(sideWidth),
|
||||||
leftNaturalWidth);
|
leftNaturalWidth);
|
||||||
childBox.x2 = allocWidth;
|
childBox.x2 = allocWidth;
|
||||||
@@ -1018,7 +1014,7 @@ const Panel = new Lang.Class({
|
|||||||
|
|
||||||
childBox.y1 = 0;
|
childBox.y1 = 0;
|
||||||
childBox.y2 = allocHeight;
|
childBox.y2 = allocHeight;
|
||||||
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL) {
|
if (this.actor.get_direction() == St.TextDirection.RTL) {
|
||||||
childBox.x1 = 0;
|
childBox.x1 = 0;
|
||||||
childBox.x2 = Math.min(Math.floor(sideWidth),
|
childBox.x2 = Math.min(Math.floor(sideWidth),
|
||||||
rightNaturalWidth);
|
rightNaturalWidth);
|
||||||
@@ -1046,58 +1042,10 @@ const Panel = new Lang.Class({
|
|||||||
this._rightCorner.actor.allocate(childBox, flags);
|
this._rightCorner.actor.allocate(childBox, flags);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onButtonPress: function(actor, event) {
|
|
||||||
if (event.get_source() != actor)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
let button = event.get_button();
|
|
||||||
if (button != 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
let focusWindow = global.display.focus_window;
|
|
||||||
if (!focusWindow)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
let dragWindow = focusWindow.is_attached_dialog() ? focusWindow.get_transient_for()
|
|
||||||
: focusWindow;
|
|
||||||
if (!dragWindow)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
let rect = dragWindow.get_outer_rect();
|
|
||||||
let [stageX, stageY] = event.get_coords();
|
|
||||||
|
|
||||||
let allowDrag = dragWindow.maximized_vertically &&
|
|
||||||
stageX > rect.x && stageX < rect.x + rect.width;
|
|
||||||
|
|
||||||
if (!allowDrag)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
global.display.begin_grab_op(global.screen,
|
|
||||||
dragWindow,
|
|
||||||
Meta.GrabOp.MOVING,
|
|
||||||
false, /* pointer grab */
|
|
||||||
true, /* frame action */
|
|
||||||
button,
|
|
||||||
event.get_state(),
|
|
||||||
event.get_time(),
|
|
||||||
stageX, stageY);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
openAppMenu: function() {
|
|
||||||
let menu = this._appMenu.menu;
|
|
||||||
if (!this._appMenu.actor.reactive || menu.isOpen)
|
|
||||||
return;
|
|
||||||
|
|
||||||
menu.open();
|
|
||||||
menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
|
||||||
},
|
|
||||||
|
|
||||||
startStatusArea: function() {
|
startStatusArea: function() {
|
||||||
for (let i = 0; i < Main.sessionMode.statusArea.order.length; i++) {
|
for (let i = 0; i < this._status_area_order.length; i++) {
|
||||||
let role = Main.sessionMode.statusArea.order[i];
|
let role = this._status_area_order[i];
|
||||||
let constructor = Main.sessionMode.statusArea.implementation[role];
|
let constructor = this._status_area_shell_implementation[role];
|
||||||
if (!constructor) {
|
if (!constructor) {
|
||||||
// This icon is not implemented (this is a bug)
|
// This icon is not implemented (this is a bug)
|
||||||
continue;
|
continue;
|
||||||
@@ -1114,13 +1062,13 @@ const Panel = new Lang.Class({
|
|||||||
for (i = children.length - 1; i >= 0; i--) {
|
for (i = children.length - 1; i >= 0; i--) {
|
||||||
let rolePosition = children[i]._rolePosition;
|
let rolePosition = children[i]._rolePosition;
|
||||||
if (position > rolePosition) {
|
if (position > rolePosition) {
|
||||||
this._rightBox.insert_child_at_index(actor, i + 1);
|
this._rightBox.insert_actor(actor, i + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
// If we didn't find a position, we must be first
|
// If we didn't find a position, we must be first
|
||||||
this._rightBox.insert_child_at_index(actor, 0);
|
this._rightBox.insert_actor(actor, 0);
|
||||||
}
|
}
|
||||||
actor._rolePosition = position;
|
actor._rolePosition = position;
|
||||||
},
|
},
|
||||||
@@ -1135,27 +1083,36 @@ const Panel = new Lang.Class({
|
|||||||
if (!position)
|
if (!position)
|
||||||
position = 0;
|
position = 0;
|
||||||
this._insertStatusItem(indicator.actor, position);
|
this._insertStatusItem(indicator.actor, position);
|
||||||
if (indicator.menu)
|
|
||||||
this._menus.addMenu(indicator.menu);
|
this._menus.addMenu(indicator.menu);
|
||||||
|
|
||||||
this._statusArea[role] = indicator;
|
this._statusArea[role] = indicator;
|
||||||
let destroyId = indicator.connect('destroy', Lang.bind(this, function(emitter) {
|
let destroyId = indicator.connect('destroy', Lang.bind(this, function(emitter) {
|
||||||
delete this._statusArea[role];
|
this._statusArea[role] = null;
|
||||||
emitter.disconnect(destroyId);
|
emitter.disconnect(destroyId);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return indicator;
|
return indicator;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onLockStateChanged: function(shield, locked) {
|
_onTrayIconAdded: function(o, icon, role) {
|
||||||
if (this._activitiesButton)
|
if (this._status_area_shell_implementation[role]) {
|
||||||
this._activitiesButton.setLockedState(locked);
|
// This icon is legacy, and replaced by a Shell version
|
||||||
if (this._appMenu)
|
// Hide it
|
||||||
this._appMenu.setLockedState(locked);
|
return;
|
||||||
if (this._dateMenu)
|
}
|
||||||
this._dateMenu.setLockedState(locked);
|
|
||||||
|
|
||||||
for (let id in this._statusArea)
|
icon.height = PANEL_ICON_SIZE;
|
||||||
this._statusArea[id].setLockedState(locked);
|
let buttonBox = new PanelMenu.ButtonBox();
|
||||||
|
let box = buttonBox.actor;
|
||||||
|
box.add_actor(icon);
|
||||||
|
|
||||||
|
this._insertStatusItem(box, this._status_area_order.indexOf(role));
|
||||||
},
|
},
|
||||||
});
|
|
||||||
|
_onTrayIconRemoved: function(o, icon) {
|
||||||
|
let box = icon.get_parent();
|
||||||
|
if (box && box._delegate instanceof PanelMenu.ButtonBox)
|
||||||
|
box.destroy();
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
|
|||||||
@@ -6,15 +6,16 @@ const Lang = imports.lang;
|
|||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Atk = imports.gi.Atk;
|
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
|
|
||||||
const ButtonBox = new Lang.Class({
|
function ButtonBox(params) {
|
||||||
Name: 'ButtonBox',
|
this._init.apply(this, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
ButtonBox.prototype = {
|
||||||
_init: function(params) {
|
_init: function(params) {
|
||||||
params = Params.parse(params, { style_class: 'panel-button' }, true);
|
params = Params.parse(params, { style_class: 'panel-button' }, true);
|
||||||
this.actor = new Shell.GenericContainer(params);
|
this.actor = new Shell.GenericContainer(params);
|
||||||
@@ -91,78 +92,44 @@ const ButtonBox = new Lang.Class({
|
|||||||
|
|
||||||
child.allocate(childBox, flags);
|
child.allocate(childBox, flags);
|
||||||
},
|
},
|
||||||
});
|
}
|
||||||
|
|
||||||
const Button = new Lang.Class({
|
function Button(menuAlignment) {
|
||||||
Name: 'PanelMenuButton',
|
this._init(menuAlignment);
|
||||||
Extends: ButtonBox,
|
}
|
||||||
|
|
||||||
_init: function(menuAlignment, nameText, dontCreateMenu) {
|
Button.prototype = {
|
||||||
this.parent({ reactive: true,
|
__proto__: ButtonBox.prototype,
|
||||||
|
|
||||||
|
_init: function(menuAlignment) {
|
||||||
|
ButtonBox.prototype._init.call(this, { reactive: true,
|
||||||
can_focus: true,
|
can_focus: true,
|
||||||
track_hover: true,
|
track_hover: true });
|
||||||
accessible_role: Atk.Role.MENU });
|
|
||||||
|
|
||||||
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
||||||
this.actor.connect('key-press-event', Lang.bind(this, this._onSourceKeyPress));
|
this.actor.connect('key-press-event', Lang.bind(this, this._onSourceKeyPress));
|
||||||
|
this.menu = new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP);
|
||||||
if (dontCreateMenu)
|
|
||||||
this.menu = null;
|
|
||||||
else
|
|
||||||
this.setMenu(new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP, 0));
|
|
||||||
|
|
||||||
this.setName(nameText);
|
|
||||||
},
|
|
||||||
|
|
||||||
setName: function(text) {
|
|
||||||
if (text != null) {
|
|
||||||
// This is the easiest way to provide a accessible name to
|
|
||||||
// this widget. The label could be also used for other
|
|
||||||
// purposes in the future.
|
|
||||||
if (!this.label) {
|
|
||||||
this.label = new St.Label({ text: text });
|
|
||||||
this.actor.label_actor = this.label;
|
|
||||||
} else
|
|
||||||
this.label.text = text;
|
|
||||||
} else {
|
|
||||||
this.label = null;
|
|
||||||
this.actor.label_actor = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setMenu: function(menu) {
|
|
||||||
if (this.menu)
|
|
||||||
this.menu.destroy();
|
|
||||||
|
|
||||||
this.menu = menu;
|
|
||||||
if (this.menu) {
|
|
||||||
this.menu.actor.add_style_class_name('panel-menu');
|
this.menu.actor.add_style_class_name('panel-menu');
|
||||||
this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
|
this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
|
||||||
this.menu.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress));
|
this.menu.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress));
|
||||||
|
|
||||||
Main.uiGroup.add_actor(this.menu.actor);
|
Main.uiGroup.add_actor(this.menu.actor);
|
||||||
this.menu.actor.hide();
|
this.menu.actor.hide();
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setLockedState: function(locked) {
|
|
||||||
// default behaviour is to hide completely
|
|
||||||
if (locked)
|
|
||||||
this.menu.close();
|
|
||||||
this.actor.visible = !locked;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onButtonPress: function(actor, event) {
|
_onButtonPress: function(actor, event) {
|
||||||
if (!this.menu)
|
if (!this.menu.isOpen) {
|
||||||
return;
|
// Setting the max-height won't do any good if the minimum height of the
|
||||||
|
// menu is higher then the screen; it's useful if part of the menu is
|
||||||
|
// scrollable so the minimum height is smaller than the natural height
|
||||||
|
let monitor = Main.layoutManager.primaryMonitor;
|
||||||
|
this.menu.actor.style = ('max-height: ' +
|
||||||
|
Math.round(monitor.height - Main.panel.actor.height) +
|
||||||
|
'px;');
|
||||||
|
}
|
||||||
this.menu.toggle();
|
this.menu.toggle();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onSourceKeyPress: function(actor, event) {
|
_onSourceKeyPress: function(actor, event) {
|
||||||
if (!this.menu)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
let symbol = event.get_key_symbol();
|
let symbol = event.get_key_symbol();
|
||||||
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
|
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
|
||||||
this.menu.toggle();
|
this.menu.toggle();
|
||||||
@@ -198,14 +165,6 @@ const Button = new Lang.Class({
|
|||||||
this.actor.add_style_pseudo_class('active');
|
this.actor.add_style_pseudo_class('active');
|
||||||
else
|
else
|
||||||
this.actor.remove_style_pseudo_class('active');
|
this.actor.remove_style_pseudo_class('active');
|
||||||
|
|
||||||
// Setting the max-height won't do any good if the minimum height of the
|
|
||||||
// menu is higher then the screen; it's useful if part of the menu is
|
|
||||||
// scrollable so the minimum height is smaller than the natural height
|
|
||||||
let monitor = Main.layoutManager.primaryMonitor;
|
|
||||||
this.menu.actor.style = ('max-height: ' +
|
|
||||||
Math.round(monitor.height - Main.panel.actor.height) +
|
|
||||||
'px;');
|
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
@@ -216,27 +175,30 @@ const Button = new Lang.Class({
|
|||||||
|
|
||||||
this.emit('destroy');
|
this.emit('destroy');
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(Button.prototype);
|
Signals.addSignalMethods(Button.prototype);
|
||||||
|
|
||||||
/* SystemStatusButton:
|
/* SystemStatusButton:
|
||||||
*
|
*
|
||||||
* This class manages one System Status indicator (network, keyboard,
|
* This class manages one System Status indicator (network, keyboard,
|
||||||
* volume, bluetooth...), which is just a PanelMenuButton with an
|
* volume, bluetooth...), which is just a PanelMenuButton with an
|
||||||
* icon.
|
* icon and a tooltip
|
||||||
*/
|
*/
|
||||||
const SystemStatusButton = new Lang.Class({
|
function SystemStatusButton() {
|
||||||
Name: 'SystemStatusButton',
|
this._init.apply(this, arguments);
|
||||||
Extends: Button,
|
}
|
||||||
|
|
||||||
_init: function(iconName, nameText) {
|
SystemStatusButton.prototype = {
|
||||||
this.parent(0.0, nameText);
|
__proto__: Button.prototype,
|
||||||
|
|
||||||
|
_init: function(iconName,tooltipText) {
|
||||||
|
Button.prototype._init.call(this, 0.0);
|
||||||
this._iconActor = new St.Icon({ icon_name: iconName,
|
this._iconActor = new St.Icon({ icon_name: iconName,
|
||||||
icon_type: St.IconType.SYMBOLIC,
|
icon_type: St.IconType.SYMBOLIC,
|
||||||
style_class: 'system-status-icon' });
|
style_class: 'system-status-icon' });
|
||||||
this.actor.add_actor(this._iconActor);
|
this.actor.add_actor(this._iconActor);
|
||||||
this.actor.add_style_class_name('panel-status-button');
|
this.actor.add_style_class_name('panel-status-button');
|
||||||
|
this.setTooltip(tooltipText);
|
||||||
},
|
},
|
||||||
|
|
||||||
setIcon: function(iconName) {
|
setIcon: function(iconName) {
|
||||||
@@ -245,5 +207,16 @@ const SystemStatusButton = new Lang.Class({
|
|||||||
|
|
||||||
setGIcon: function(gicon) {
|
setGIcon: function(gicon) {
|
||||||
this._iconActor.gicon = gicon;
|
this._iconActor.gicon = gicon;
|
||||||
|
},
|
||||||
|
|
||||||
|
setTooltip: function(text) {
|
||||||
|
if (text != null) {
|
||||||
|
this.tooltip = text;
|
||||||
|
this.actor.has_tooltip = true;
|
||||||
|
this.actor.tooltip_text = text;
|
||||||
|
} else {
|
||||||
|
this.actor.has_tooltip = false;
|
||||||
|
this.tooltip = null;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -22,9 +22,11 @@ const Util = imports.misc.util;
|
|||||||
* @iconFactory: A JavaScript callback which will create an icon texture given a size parameter
|
* @iconFactory: A JavaScript callback which will create an icon texture given a size parameter
|
||||||
* @launch: A JavaScript callback to launch the entry
|
* @launch: A JavaScript callback to launch the entry
|
||||||
*/
|
*/
|
||||||
const PlaceInfo = new Lang.Class({
|
function PlaceInfo(id, name, iconFactory, launch) {
|
||||||
Name: 'PlaceInfo',
|
this._init(id, name, iconFactory, launch);
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaceInfo.prototype = {
|
||||||
_init: function(id, name, iconFactory, launch) {
|
_init: function(id, name, iconFactory, launch) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@@ -53,7 +55,7 @@ const PlaceInfo = new Lang.Class({
|
|||||||
isRemovable: function() {
|
isRemovable: function() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
// Helper function to translate launch parameters into a GAppLaunchContext
|
// Helper function to translate launch parameters into a GAppLaunchContext
|
||||||
function _makeLaunchContext(params)
|
function _makeLaunchContext(params)
|
||||||
@@ -70,9 +72,12 @@ function _makeLaunchContext(params)
|
|||||||
return launchContext;
|
return launchContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PlaceDeviceInfo = new Lang.Class({
|
function PlaceDeviceInfo(mount) {
|
||||||
Name: 'PlaceDeviceInfo',
|
this._init(mount);
|
||||||
Extends: PlaceInfo,
|
}
|
||||||
|
|
||||||
|
PlaceDeviceInfo.prototype = {
|
||||||
|
__proto__: PlaceInfo.prototype,
|
||||||
|
|
||||||
_init: function(mount) {
|
_init: function(mount) {
|
||||||
this._mount = mount;
|
this._mount = mount;
|
||||||
@@ -118,11 +123,13 @@ const PlaceDeviceInfo = new Lang.Class({
|
|||||||
_("Retry"));
|
_("Retry"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const PlacesManager = new Lang.Class({
|
function PlacesManager() {
|
||||||
Name: 'PlacesManager',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
PlacesManager.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._defaultPlaces = [];
|
this._defaultPlaces = [];
|
||||||
this._mounts = [];
|
this._mounts = [];
|
||||||
@@ -155,12 +162,9 @@ const PlacesManager = new Lang.Class({
|
|||||||
|
|
||||||
this._connect = new PlaceInfo('special:connect', _("Connect to..."),
|
this._connect = new PlaceInfo('special:connect', _("Connect to..."),
|
||||||
function (size) {
|
function (size) {
|
||||||
// do NOT use St.Icon here, it crashes the shell
|
return new St.Icon({ icon_name: 'applications-internet',
|
||||||
// see wanda.js for details
|
icon_type: St.IconType.FULLCOLOR,
|
||||||
return St.TextureCache.get_default().load_icon_name(null,
|
icon_size: size });
|
||||||
'applications-internet',
|
|
||||||
St.IconType.FULLCOLOR,
|
|
||||||
size);
|
|
||||||
},
|
},
|
||||||
function (params) {
|
function (params) {
|
||||||
// BUG: nautilus-connect-server doesn't have a desktop file, so we can't
|
// BUG: nautilus-connect-server doesn't have a desktop file, so we can't
|
||||||
@@ -189,7 +193,7 @@ const PlacesManager = new Lang.Class({
|
|||||||
this._volumeMonitor.connect('drive-changed', Lang.bind(this, this._updateDevices));
|
this._volumeMonitor.connect('drive-changed', Lang.bind(this, this._updateDevices));
|
||||||
this._updateDevices();
|
this._updateDevices();
|
||||||
|
|
||||||
this._bookmarksPath = GLib.build_filenamev([GLib.get_user_config_dir(), 'gtk-3.0', 'bookmarks']);
|
this._bookmarksPath = GLib.build_filenamev([GLib.get_home_dir(), '.gtk-bookmarks']);
|
||||||
this._bookmarksFile = Gio.file_new_for_path(this._bookmarksPath);
|
this._bookmarksFile = Gio.file_new_for_path(this._bookmarksPath);
|
||||||
this._monitor = this._bookmarksFile.monitor_file(Gio.FileMonitorFlags.NONE, null);
|
this._monitor = this._bookmarksFile.monitor_file(Gio.FileMonitorFlags.NONE, null);
|
||||||
this._bookmarkTimeoutId = 0;
|
this._bookmarkTimeoutId = 0;
|
||||||
@@ -356,48 +360,48 @@ const PlacesManager = new Lang.Class({
|
|||||||
_removeById: function(sourceArray, id) {
|
_removeById: function(sourceArray, id) {
|
||||||
sourceArray.splice(this._lookupIndexById(sourceArray, id), 1);
|
sourceArray.splice(this._lookupIndexById(sourceArray, id), 1);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(PlacesManager.prototype);
|
Signals.addSignalMethods(PlacesManager.prototype);
|
||||||
|
|
||||||
const PlaceSearchProvider = new Lang.Class({
|
|
||||||
Name: 'PlaceSearchProvider',
|
function PlaceSearchProvider() {
|
||||||
Extends: Search.SearchProvider,
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaceSearchProvider.prototype = {
|
||||||
|
__proto__: Search.SearchProvider.prototype,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent(_("PLACES & DEVICES"));
|
Search.SearchProvider.prototype._init.call(this, _("PLACES & DEVICES"));
|
||||||
this.placesManager = new PlacesManager();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getResultMetas: function(resultIds, callback) {
|
getResultMeta: function(resultId) {
|
||||||
let metas = [];
|
let placeInfo = Main.placesManager.lookupPlaceById(resultId);
|
||||||
for (let i = 0; i < resultIds.length; i++) {
|
|
||||||
let placeInfo = this.placesManager.lookupPlaceById(resultIds[i]);
|
|
||||||
if (!placeInfo)
|
if (!placeInfo)
|
||||||
metas.push(null);
|
return null;
|
||||||
else
|
return { 'id': resultId,
|
||||||
metas.push({ 'id': resultIds[i],
|
|
||||||
'name': placeInfo.name,
|
'name': placeInfo.name,
|
||||||
'createIcon': function(size) {
|
'createIcon': function(size) {
|
||||||
return placeInfo.iconFactory(size);
|
return placeInfo.iconFactory(size);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
}
|
|
||||||
callback(metas);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
activateResult: function(id, params) {
|
activateResult: function(id, params) {
|
||||||
let placeInfo = this.placesManager.lookupPlaceById(id);
|
let placeInfo = Main.placesManager.lookupPlaceById(id);
|
||||||
placeInfo.launch(params);
|
placeInfo.launch(params);
|
||||||
},
|
},
|
||||||
|
|
||||||
_compareResultMeta: function (idA, idB) {
|
_compareResultMeta: function (idA, idB) {
|
||||||
let infoA = this.placesManager.lookupPlaceById(idA);
|
let infoA = Main.placesManager.lookupPlaceById(idA);
|
||||||
let infoB = this.placesManager.lookupPlaceById(idB);
|
let infoB = Main.placesManager.lookupPlaceById(idB);
|
||||||
return infoA.name.localeCompare(infoB.name);
|
return infoA.name.localeCompare(infoB.name);
|
||||||
},
|
},
|
||||||
|
|
||||||
_searchPlaces: function(places, terms) {
|
_searchPlaces: function(places, terms) {
|
||||||
|
let multiplePrefixResults = [];
|
||||||
let prefixResults = [];
|
let prefixResults = [];
|
||||||
|
let multipleSubstringResults = [];
|
||||||
let substringResults = [];
|
let substringResults = [];
|
||||||
|
|
||||||
terms = terms.map(String.toLowerCase);
|
terms = terms.map(String.toLowerCase);
|
||||||
@@ -405,26 +409,29 @@ const PlaceSearchProvider = new Lang.Class({
|
|||||||
for (let i = 0; i < places.length; i++) {
|
for (let i = 0; i < places.length; i++) {
|
||||||
let place = places[i];
|
let place = places[i];
|
||||||
let mtype = place.matchTerms(terms);
|
let mtype = place.matchTerms(terms);
|
||||||
if (mtype == Search.MatchType.PREFIX)
|
if (mtype == Search.MatchType.MULTIPLE_PREFIX)
|
||||||
|
multiplePrefixResults.push(place.id);
|
||||||
|
else if (mtype == Search.MatchType.PREFIX)
|
||||||
prefixResults.push(place.id);
|
prefixResults.push(place.id);
|
||||||
|
else if (mtype == Search.MatchType.MULTIPLE_SUBSTRING)
|
||||||
|
multipleSubstringResults.push(place.id);
|
||||||
else if (mtype == Search.MatchType.SUBSTRING)
|
else if (mtype == Search.MatchType.SUBSTRING)
|
||||||
substringResults.push(place.id);
|
substringResults.push(place.id);
|
||||||
}
|
}
|
||||||
prefixResults.sort(Lang.bind(this, this._compareResultMeta));
|
multiplePrefixResults.sort(this._compareResultMeta);
|
||||||
substringResults.sort(Lang.bind(this, this._compareResultMeta));
|
prefixResults.sort(this._compareResultMeta);
|
||||||
|
multipleSubstringResults.sort(this._compareResultMeta);
|
||||||
this.searchSystem.pushResults(this, prefixResults.concat(substringResults));
|
substringResults.sort(this._compareResultMeta);
|
||||||
|
return multiplePrefixResults.concat(prefixResults.concat(multipleSubstringResults.concat(substringResults)));
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialResultSet: function(terms) {
|
getInitialResultSet: function(terms) {
|
||||||
let places = this.placesManager.getAllPlaces();
|
let places = Main.placesManager.getAllPlaces();
|
||||||
this._searchPlaces(places, terms);
|
return this._searchPlaces(places, terms);
|
||||||
},
|
},
|
||||||
|
|
||||||
getSubsearchResultSet: function(previousResults, terms) {
|
getSubsearchResultSet: function(previousResults, terms) {
|
||||||
let places = previousResults.map(Lang.bind(this, function(id) {
|
let places = previousResults.map(function (id) { return Main.placesManager.lookupPlaceById(id); });
|
||||||
return this.placesManager.lookupPlaceById(id);
|
return this._searchPlaces(places, terms);
|
||||||
}));
|
|
||||||
this._searchPlaces(places, terms);
|
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ const AccountsService = imports.gi.AccountsService;
|
|||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Pango = imports.gi.Pango;
|
const Pango = imports.gi.Pango;
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Polkit = imports.gi.Polkit;
|
const Polkit = imports.gi.Polkit;
|
||||||
@@ -36,12 +35,15 @@ const PolkitAgent = imports.gi.PolkitAgent;
|
|||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
|
|
||||||
const AuthenticationDialog = new Lang.Class({
|
function AuthenticationDialog(actionId, message, cookie, userNames) {
|
||||||
Name: 'AuthenticationDialog',
|
this._init(actionId, message, cookie, userNames);
|
||||||
Extends: ModalDialog.ModalDialog,
|
}
|
||||||
|
|
||||||
|
AuthenticationDialog.prototype = {
|
||||||
|
__proto__: ModalDialog.ModalDialog.prototype,
|
||||||
|
|
||||||
_init: function(actionId, message, cookie, userNames) {
|
_init: function(actionId, message, cookie, userNames) {
|
||||||
this.parent({ styleClass: 'prompt-dialog' });
|
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'polkit-dialog' });
|
||||||
|
|
||||||
this.actionId = actionId;
|
this.actionId = actionId;
|
||||||
this.message = message;
|
this.message = message;
|
||||||
@@ -49,7 +51,7 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
this._wasDismissed = false;
|
this._wasDismissed = false;
|
||||||
this._completed = false;
|
this._completed = false;
|
||||||
|
|
||||||
let mainContentBox = new St.BoxLayout({ style_class: 'prompt-dialog-main-layout',
|
let mainContentBox = new St.BoxLayout({ style_class: 'polkit-dialog-main-layout',
|
||||||
vertical: false });
|
vertical: false });
|
||||||
this.contentLayout.add(mainContentBox,
|
this.contentLayout.add(mainContentBox,
|
||||||
{ x_fill: true,
|
{ x_fill: true,
|
||||||
@@ -62,19 +64,19 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
x_align: St.Align.END,
|
x_align: St.Align.END,
|
||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
|
|
||||||
let messageBox = new St.BoxLayout({ style_class: 'prompt-dialog-message-layout',
|
let messageBox = new St.BoxLayout({ style_class: 'polkit-dialog-message-layout',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
mainContentBox.add(messageBox,
|
mainContentBox.add(messageBox,
|
||||||
{ y_align: St.Align.START });
|
{ y_align: St.Align.START });
|
||||||
|
|
||||||
this._subjectLabel = new St.Label({ style_class: 'prompt-dialog-headline',
|
this._subjectLabel = new St.Label({ style_class: 'polkit-dialog-headline',
|
||||||
text: _("Authentication Required") });
|
text: _("Authentication Required") });
|
||||||
|
|
||||||
messageBox.add(this._subjectLabel,
|
messageBox.add(this._subjectLabel,
|
||||||
{ y_fill: false,
|
{ y_fill: false,
|
||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
|
|
||||||
this._descriptionLabel = new St.Label({ style_class: 'prompt-dialog-description',
|
this._descriptionLabel = new St.Label({ style_class: 'polkit-dialog-description',
|
||||||
text: message });
|
text: message });
|
||||||
this._descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
this._descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
this._descriptionLabel.clutter_text.line_wrap = true;
|
this._descriptionLabel.clutter_text.line_wrap = true;
|
||||||
@@ -86,14 +88,10 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
if (userNames.length > 1) {
|
if (userNames.length > 1) {
|
||||||
log('polkitAuthenticationAgent: Received ' + userNames.length +
|
log('polkitAuthenticationAgent: Received ' + userNames.length +
|
||||||
' identities that can be used for authentication. Only ' +
|
' identities that can be used for authentication. Only ' +
|
||||||
'considering one.');
|
'considering the first one.');
|
||||||
}
|
}
|
||||||
|
|
||||||
let userName = GLib.get_user_name();
|
let userName = userNames[0];
|
||||||
if (userNames.indexOf(userName) < 0)
|
|
||||||
userName = 'root';
|
|
||||||
if (userNames.indexOf(userName) < 0)
|
|
||||||
userName = userNames[0];
|
|
||||||
|
|
||||||
this._user = AccountsService.UserManager.get_default().get_user(userName);
|
this._user = AccountsService.UserManager.get_default().get_user(userName);
|
||||||
let userRealName = this._user.get_real_name()
|
let userRealName = this._user.get_real_name()
|
||||||
@@ -135,27 +133,27 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
|
|
||||||
this._onUserChanged();
|
this._onUserChanged();
|
||||||
|
|
||||||
this._passwordBox = new St.BoxLayout({ vertical: false, style_class: 'prompt-dialog-password-box' });
|
this._passwordBox = new St.BoxLayout({ vertical: false });
|
||||||
messageBox.add(this._passwordBox);
|
messageBox.add(this._passwordBox);
|
||||||
this._passwordLabel = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
|
this._passwordLabel = new St.Label(({ style_class: 'polkit-dialog-password-label' }));
|
||||||
this._passwordBox.add(this._passwordLabel, { y_fill: false, y_align: St.Align.MIDDLE });
|
this._passwordBox.add(this._passwordLabel);
|
||||||
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
this._passwordEntry = new St.Entry({ style_class: 'polkit-dialog-password-entry',
|
||||||
text: "",
|
text: "",
|
||||||
can_focus: true});
|
can_focus: true});
|
||||||
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
|
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
|
||||||
this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivate));
|
this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivate));
|
||||||
this._passwordBox.add(this._passwordEntry,
|
this._passwordBox.add(this._passwordEntry,
|
||||||
{ expand: true });
|
{expand: true });
|
||||||
this.setInitialKeyFocus(this._passwordEntry);
|
this.setInitialKeyFocus(this._passwordEntry);
|
||||||
this._passwordBox.hide();
|
this._passwordBox.hide();
|
||||||
|
|
||||||
this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label' });
|
this._errorMessageLabel = new St.Label({ style_class: 'polkit-dialog-error-label' });
|
||||||
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
this._errorMessageLabel.clutter_text.line_wrap = true;
|
this._errorMessageLabel.clutter_text.line_wrap = true;
|
||||||
messageBox.add(this._errorMessageLabel);
|
messageBox.add(this._errorMessageLabel);
|
||||||
this._errorMessageLabel.hide();
|
this._errorMessageLabel.hide();
|
||||||
|
|
||||||
this._infoMessageLabel = new St.Label({ style_class: 'prompt-dialog-info-label' });
|
this._infoMessageLabel = new St.Label({ style_class: 'polkit-dialog-info-label' });
|
||||||
this._infoMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
this._infoMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
this._infoMessageLabel.clutter_text.line_wrap = true;
|
this._infoMessageLabel.clutter_text.line_wrap = true;
|
||||||
messageBox.add(this._infoMessageLabel);
|
messageBox.add(this._infoMessageLabel);
|
||||||
@@ -165,9 +163,8 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
* infoMessage and errorMessageLabel - but it is still invisible because
|
* infoMessage and errorMessageLabel - but it is still invisible because
|
||||||
* gnome-shell.css sets the color to be transparent
|
* gnome-shell.css sets the color to be transparent
|
||||||
*/
|
*/
|
||||||
this._nullMessageLabel = new St.Label({ style_class: 'prompt-dialog-null-label',
|
this._nullMessageLabel = new St.Label({ style_class: 'polkit-dialog-null-label',
|
||||||
text: 'abc'});
|
text: 'abc'});
|
||||||
this._nullMessageLabel.add_style_class_name('hidden');
|
|
||||||
this._nullMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
this._nullMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
this._nullMessageLabel.clutter_text.line_wrap = true;
|
this._nullMessageLabel.clutter_text.line_wrap = true;
|
||||||
messageBox.add(this._nullMessageLabel);
|
messageBox.add(this._nullMessageLabel);
|
||||||
@@ -178,8 +175,7 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
key: Clutter.Escape
|
key: Clutter.Escape
|
||||||
},
|
},
|
||||||
{ label: _("Authenticate"),
|
{ label: _("Authenticate"),
|
||||||
action: Lang.bind(this, this._onAuthenticateButtonPressed),
|
action: Lang.bind(this, this._onAuthenticateButtonPressed)
|
||||||
default: true
|
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
this._doneEmitted = false;
|
this._doneEmitted = false;
|
||||||
@@ -270,7 +266,7 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
|
|
||||||
_onSessionRequest: function(session, request, echo_on) {
|
_onSessionRequest: function(session, request, echo_on) {
|
||||||
// Cheap localization trick
|
// Cheap localization trick
|
||||||
if (request == 'Password:' || request == 'Password: ')
|
if (request == 'Password:')
|
||||||
this._passwordLabel.set_text(_("Password:"));
|
this._passwordLabel.set_text(_("Password:"));
|
||||||
else
|
else
|
||||||
this._passwordLabel.set_text(request);
|
this._passwordLabel.set_text(request);
|
||||||
@@ -334,12 +330,15 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
this.close(global.get_current_time());
|
this.close(global.get_current_time());
|
||||||
this._emitDone(false, true);
|
this._emitDone(false, true);
|
||||||
},
|
},
|
||||||
});
|
|
||||||
|
};
|
||||||
Signals.addSignalMethods(AuthenticationDialog.prototype);
|
Signals.addSignalMethods(AuthenticationDialog.prototype);
|
||||||
|
|
||||||
const AuthenticationAgent = new Lang.Class({
|
function AuthenticationAgent() {
|
||||||
Name: 'AuthenticationAgent',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthenticationAgent.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._native = new Shell.PolkitAuthenticationAgent();
|
this._native = new Shell.PolkitAuthenticationAgent();
|
||||||
this._native.connect('initiate', Lang.bind(this, this._onInitiate));
|
this._native.connect('initiate', Lang.bind(this, this._onInitiate));
|
||||||
@@ -395,13 +394,12 @@ const AuthenticationAgent = new Lang.Class({
|
|||||||
Lang.bind(this,
|
Lang.bind(this,
|
||||||
function() {
|
function() {
|
||||||
this._reallyCompleteRequest(wasDismissed);
|
this._reallyCompleteRequest(wasDismissed);
|
||||||
return false;
|
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
this._reallyCompleteRequest(wasDismissed);
|
this._reallyCompleteRequest(wasDismissed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
let agent = new AuthenticationAgent();
|
let agent = new AuthenticationAgent();
|
||||||
|
|||||||
@@ -1,199 +0,0 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
const Gio = imports.gi.Gio;
|
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const St = imports.gi.St;
|
|
||||||
|
|
||||||
const FileUtils = imports.misc.fileUtils;
|
|
||||||
const Search = imports.ui.search;
|
|
||||||
|
|
||||||
const KEY_FILE_GROUP = 'Shell Search Provider';
|
|
||||||
|
|
||||||
const SearchProviderIface = <interface name="org.gnome.Shell.SearchProvider">
|
|
||||||
<method name="GetInitialResultSet">
|
|
||||||
<arg type="as" direction="in" />
|
|
||||||
<arg type="as" direction="out" />
|
|
||||||
</method>
|
|
||||||
<method name="GetSubsearchResultSet">
|
|
||||||
<arg type="as" direction="in" />
|
|
||||||
<arg type="as" direction="in" />
|
|
||||||
<arg type="as" direction="out" />
|
|
||||||
</method>
|
|
||||||
<method name="GetResultMetas">
|
|
||||||
<arg type="as" direction="in" />
|
|
||||||
<arg type="aa{sv}" direction="out" />
|
|
||||||
</method>
|
|
||||||
<method name="ActivateResult">
|
|
||||||
<arg type="s" direction="in" />
|
|
||||||
</method>
|
|
||||||
</interface>;
|
|
||||||
|
|
||||||
var SearchProviderProxy = Gio.DBusProxy.makeProxyWrapper(SearchProviderIface);
|
|
||||||
|
|
||||||
|
|
||||||
function loadRemoteSearchProviders(addProviderCallback) {
|
|
||||||
let dataDirs = GLib.get_system_data_dirs();
|
|
||||||
for (let i = 0; i < dataDirs.length; i++) {
|
|
||||||
let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', 'search-providers']);
|
|
||||||
let dir = Gio.file_new_for_path(path);
|
|
||||||
if (!dir.query_exists(null))
|
|
||||||
continue;
|
|
||||||
loadRemoteSearchProvidersFromDir(dir, addProviderCallback);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function loadRemoteSearchProvidersFromDir(dir, addProviderCallback) {
|
|
||||||
let dirPath = dir.get_path();
|
|
||||||
FileUtils.listDirAsync(dir, Lang.bind(this, function(files) {
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
|
||||||
let keyfile = new GLib.KeyFile();
|
|
||||||
let path = GLib.build_filenamev([dirPath, files[i].get_name()]);
|
|
||||||
|
|
||||||
try {
|
|
||||||
keyfile.load_from_file(path, 0);
|
|
||||||
} catch(e) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!keyfile.has_group(KEY_FILE_GROUP))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
let remoteProvider, title;
|
|
||||||
try {
|
|
||||||
let group = KEY_FILE_GROUP;
|
|
||||||
let busName = keyfile.get_string(group, 'BusName');
|
|
||||||
let objectPath = keyfile.get_string(group, 'ObjectPath');
|
|
||||||
|
|
||||||
let appInfo = null;
|
|
||||||
try {
|
|
||||||
let desktopId = keyfile.get_string(group, 'DesktopId');
|
|
||||||
appInfo = Gio.DesktopAppInfo.new(desktopId);
|
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
let icon;
|
|
||||||
if (appInfo) {
|
|
||||||
icon = appInfo.get_icon();
|
|
||||||
title = appInfo.get_name();
|
|
||||||
} else {
|
|
||||||
let iconName = keyfile.get_string(group, 'Icon');
|
|
||||||
icon = new Gio.ThemedIcon({ name: iconName });
|
|
||||||
title = keyfile.get_locale_string(group, 'Title', null);
|
|
||||||
}
|
|
||||||
|
|
||||||
remoteProvider = new RemoteSearchProvider(title,
|
|
||||||
icon,
|
|
||||||
busName,
|
|
||||||
objectPath);
|
|
||||||
} catch(e) {
|
|
||||||
log('Failed to add search provider "%s": %s'.format(title, e.toString()));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
addProviderCallback(remoteProvider);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
const RemoteSearchProvider = new Lang.Class({
|
|
||||||
Name: 'RemoteSearchProvider',
|
|
||||||
Extends: Search.SearchProvider,
|
|
||||||
|
|
||||||
_init: function(title, icon, dbusName, dbusPath) {
|
|
||||||
this._proxy = new SearchProviderProxy(Gio.DBus.session,
|
|
||||||
dbusName, dbusPath);
|
|
||||||
|
|
||||||
this.parent(title.toUpperCase());
|
|
||||||
this._cancellable = new Gio.Cancellable();
|
|
||||||
},
|
|
||||||
|
|
||||||
createIcon: function(size, meta) {
|
|
||||||
if (meta['gicon']) {
|
|
||||||
return new St.Icon({ gicon: Gio.icon_new_for_string(meta['gicon']),
|
|
||||||
icon_size: size,
|
|
||||||
icon_type: St.IconType.FULLCOLOR });
|
|
||||||
} else if (meta['icon-data']) {
|
|
||||||
let [width, height, rowStride, hasAlpha,
|
|
||||||
bitsPerSample, nChannels, data] = meta['icon-data'];
|
|
||||||
let textureCache = St.TextureCache.get_default();
|
|
||||||
return textureCache.load_from_raw(data, hasAlpha,
|
|
||||||
width, height, rowStride, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ugh, but we want to fall back to something ...
|
|
||||||
return new St.Icon({ icon_name: 'text-x-generic',
|
|
||||||
icon_size: size,
|
|
||||||
icon_type: St.IconType.FULLCOLOR });
|
|
||||||
},
|
|
||||||
|
|
||||||
_getResultsFinished: function(results, error) {
|
|
||||||
if (error)
|
|
||||||
return;
|
|
||||||
this.searchSystem.pushResults(this, results[0]);
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialResultSet: function(terms) {
|
|
||||||
this._cancellable.cancel();
|
|
||||||
this._cancellable.reset();
|
|
||||||
try {
|
|
||||||
this._proxy.GetInitialResultSetRemote(terms,
|
|
||||||
Lang.bind(this, this._getResultsFinished),
|
|
||||||
this._cancellable);
|
|
||||||
} catch(e) {
|
|
||||||
log('Error calling GetInitialResultSet for provider %s: %s'.format( this.title, e.toString()));
|
|
||||||
this.searchSystem.pushResults(this, []);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getSubsearchResultSet: function(previousResults, newTerms) {
|
|
||||||
this._cancellable.cancel();
|
|
||||||
this._cancellable.reset();
|
|
||||||
try {
|
|
||||||
this._proxy.GetSubsearchResultSetRemote(previousResults, newTerms,
|
|
||||||
Lang.bind(this, this._getResultsFinished),
|
|
||||||
this._cancellable);
|
|
||||||
} catch(e) {
|
|
||||||
log('Error calling GetSubsearchResultSet for provider %s: %s'.format(this.title, e.toString()));
|
|
||||||
this.searchSystem.pushResults(this, []);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_getResultMetasFinished: function(results, error, callback) {
|
|
||||||
if (error) {
|
|
||||||
callback([]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let metas = results[0];
|
|
||||||
let resultMetas = [];
|
|
||||||
for (let i = 0; i < metas.length; i++) {
|
|
||||||
for (let prop in metas[i])
|
|
||||||
metas[i][prop] = metas[i][prop].deep_unpack();
|
|
||||||
resultMetas.push({ id: metas[i]['id'],
|
|
||||||
name: metas[i]['name'],
|
|
||||||
createIcon: Lang.bind(this,
|
|
||||||
this.createIcon, metas[i]) });
|
|
||||||
}
|
|
||||||
callback(resultMetas);
|
|
||||||
},
|
|
||||||
|
|
||||||
getResultMetas: function(ids, callback) {
|
|
||||||
this._cancellable.cancel();
|
|
||||||
this._cancellable.reset();
|
|
||||||
try {
|
|
||||||
this._proxy.GetResultMetasRemote(ids,
|
|
||||||
Lang.bind(this, this._getResultMetasFinished, callback),
|
|
||||||
this._cancellable);
|
|
||||||
} catch(e) {
|
|
||||||
log('Error calling GetResultMetas for provider %s: %s'.format(this.title, e.toString()));
|
|
||||||
callback([]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
activateResult: function(id) {
|
|
||||||
this._proxy.ActivateResultRemote(id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
@@ -30,9 +30,11 @@ const EXEC_ARG_KEY = 'exec-arg';
|
|||||||
|
|
||||||
const DIALOG_GROW_TIME = 0.1;
|
const DIALOG_GROW_TIME = 0.1;
|
||||||
|
|
||||||
const CommandCompleter = new Lang.Class({
|
function CommandCompleter() {
|
||||||
Name: 'CommandCompleter',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandCompleter.prototype = {
|
||||||
_init : function() {
|
_init : function() {
|
||||||
this._changedCount = 0;
|
this._changedCount = 0;
|
||||||
this._paths = GLib.getenv('PATH').split(':');
|
this._paths = GLib.getenv('PATH').split(':');
|
||||||
@@ -160,14 +162,16 @@ const CommandCompleter = new Lang.Class({
|
|||||||
return common.substr(text.length);
|
return common.substr(text.length);
|
||||||
return common;
|
return common;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const RunDialog = new Lang.Class({
|
function RunDialog() {
|
||||||
Name: 'RunDialog',
|
this._init();
|
||||||
Extends: ModalDialog.ModalDialog,
|
}
|
||||||
|
|
||||||
|
RunDialog.prototype = {
|
||||||
|
__proto__: ModalDialog.ModalDialog.prototype,
|
||||||
_init : function() {
|
_init : function() {
|
||||||
this.parent({ styleClass: 'run-dialog' });
|
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'run-dialog' });
|
||||||
|
|
||||||
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
|
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
|
||||||
this._terminalSettings = new Gio.Settings({ schema: TERMINAL_SCHEMA });
|
this._terminalSettings = new Gio.Settings({ schema: TERMINAL_SCHEMA });
|
||||||
@@ -209,8 +213,6 @@ const RunDialog = new Lang.Class({
|
|||||||
let entry = new St.Entry({ style_class: 'run-dialog-entry' });
|
let entry = new St.Entry({ style_class: 'run-dialog-entry' });
|
||||||
ShellEntry.addContextMenu(entry);
|
ShellEntry.addContextMenu(entry);
|
||||||
|
|
||||||
entry.label_actor = label;
|
|
||||||
|
|
||||||
this._entryText = entry.clutter_text;
|
this._entryText = entry.clutter_text;
|
||||||
this.contentLayout.add(entry, { y_align: St.Align.START });
|
this.contentLayout.add(entry, { y_align: St.Align.START });
|
||||||
this.setInitialKeyFocus(this._entryText);
|
this.setInitialKeyFocus(this._entryText);
|
||||||
@@ -244,7 +246,7 @@ const RunDialog = new Lang.Class({
|
|||||||
let symbol = e.get_key_symbol();
|
let symbol = e.get_key_symbol();
|
||||||
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
||||||
this.popModal();
|
this.popModal();
|
||||||
if (e.get_state() & Clutter.ModifierType.CONTROL_MASK)
|
if (Shell.get_event_state(e) & Clutter.ModifierType.CONTROL_MASK)
|
||||||
this._run(o.get_text(), true);
|
this._run(o.get_text(), true);
|
||||||
else
|
else
|
||||||
this._run(o.get_text(), false);
|
this._run(o.get_text(), false);
|
||||||
@@ -382,7 +384,8 @@ const RunDialog = new Lang.Class({
|
|||||||
if (this._lockdownSettings.get_boolean(DISABLE_COMMAND_LINE_KEY))
|
if (this._lockdownSettings.get_boolean(DISABLE_COMMAND_LINE_KEY))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.parent();
|
ModalDialog.ModalDialog.prototype.open.call(this);
|
||||||
},
|
},
|
||||||
});
|
|
||||||
|
};
|
||||||
Signals.addSignalMethods(RunDialog.prototype);
|
Signals.addSignalMethods(RunDialog.prototype);
|
||||||
|
|||||||
@@ -1,616 +0,0 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
|
||||||
const Gio = imports.gi.Gio;
|
|
||||||
const GnomeDesktop = imports.gi.GnomeDesktop;
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const Meta = imports.gi.Meta;
|
|
||||||
const Signals = imports.signals;
|
|
||||||
const St = imports.gi.St;
|
|
||||||
|
|
||||||
const GnomeSession = imports.misc.gnomeSession;
|
|
||||||
const Lightbox = imports.ui.lightbox;
|
|
||||||
const Main = imports.ui.main;
|
|
||||||
const MessageTray = imports.ui.messageTray;
|
|
||||||
const Tweener = imports.ui.tweener;
|
|
||||||
|
|
||||||
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
|
|
||||||
const LOCK_ENABLED_KEY = 'lock-enabled';
|
|
||||||
|
|
||||||
const CURTAIN_SLIDE_TIME = 0.8;
|
|
||||||
// fraction of screen height the arrow must reach before completing
|
|
||||||
// the slide up automatically
|
|
||||||
const ARROW_DRAG_TRESHOLD = 0.1;
|
|
||||||
|
|
||||||
// The distance in px that the lock screen will move to when pressing
|
|
||||||
// a key that has no effect in the lock screen (bumping it)
|
|
||||||
const BUMP_SIZE = 25;
|
|
||||||
const BUMP_TIME = 0.3;
|
|
||||||
|
|
||||||
const SUMMARY_ICON_SIZE = 48;
|
|
||||||
|
|
||||||
// Lightbox fading times
|
|
||||||
// STANDARD_FADE_TIME is used when the session goes idle, while
|
|
||||||
// SHORT_FADE_TIME is used when requesting lock explicitly from the user menu
|
|
||||||
const STANDARD_FADE_TIME = 10;
|
|
||||||
const SHORT_FADE_TIME = 0.8;
|
|
||||||
|
|
||||||
const Clock = new Lang.Class({
|
|
||||||
Name: 'ScreenShieldClock',
|
|
||||||
|
|
||||||
CLOCK_FORMAT_KEY: 'clock-format',
|
|
||||||
CLOCK_SHOW_SECONDS_KEY: 'clock-show-seconds',
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this.actor = new St.BoxLayout({ style_class: 'screen-shield-clock',
|
|
||||||
vertical: true });
|
|
||||||
|
|
||||||
this._time = new St.Label({ style_class: 'screen-shield-clock-time' });
|
|
||||||
this._date = new St.Label({ style_class: 'screen-shield-clock-date' });
|
|
||||||
|
|
||||||
this.actor.add(this._time, { x_align: St.Align.MIDDLE });
|
|
||||||
this.actor.add(this._date, { x_align: St.Align.MIDDLE });
|
|
||||||
|
|
||||||
this._wallClock = new GnomeDesktop.WallClock({ time_only: true });
|
|
||||||
this._wallClock.connect('notify::clock', Lang.bind(this, this._updateClock));
|
|
||||||
|
|
||||||
this._updateClock();
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateClock: function() {
|
|
||||||
this._time.text = this._wallClock.clock;
|
|
||||||
|
|
||||||
let date = new Date();
|
|
||||||
/* Translators: This is a time format for a date in
|
|
||||||
long format */
|
|
||||||
this._date.text = date.toLocaleFormat(_("%A, %B %d"));
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy: function() {
|
|
||||||
this.actor.destroy();
|
|
||||||
this._wallClock.run_dispose();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const NotificationsBox = new Lang.Class({
|
|
||||||
Name: 'NotificationsBox',
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this.actor = new St.BoxLayout({ vertical: true,
|
|
||||||
name: 'screenShieldNotifications',
|
|
||||||
style_class: 'screen-shield-notifications-box' });
|
|
||||||
|
|
||||||
this._residentNotificationBox = new St.BoxLayout({ vertical: true,
|
|
||||||
style_class: 'screen-shield-notifications-box' });
|
|
||||||
let scrollView = new St.ScrollView({ x_fill: false, x_align: St.Align.MIDDLE });
|
|
||||||
this._persistentNotificationBox = new St.BoxLayout({ vertical: true,
|
|
||||||
style_class: 'screen-shield-notifications-box' });
|
|
||||||
scrollView.add_actor(this._persistentNotificationBox);
|
|
||||||
|
|
||||||
this.actor.add(this._residentNotificationBox, { x_fill: true });
|
|
||||||
this.actor.add(scrollView, { x_fill: true, x_align: St.Align.MIDDLE });
|
|
||||||
|
|
||||||
this._items = [];
|
|
||||||
Main.messageTray.getSummaryItems().forEach(Lang.bind(this, function(item) {
|
|
||||||
this._summaryItemAdded(Main.messageTray, item);
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._summaryAddedId = Main.messageTray.connect('summary-item-added', Lang.bind(this, this._summaryItemAdded));
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy: function() {
|
|
||||||
if (this._summaryAddedId) {
|
|
||||||
Main.messageTray.disconnect(this._summaryAddedId);
|
|
||||||
this._summaryAddedId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < this._items.length; i++)
|
|
||||||
this._removeItem(this._items[i]);
|
|
||||||
this._items = [];
|
|
||||||
|
|
||||||
this.actor.destroy();
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateVisibility: function() {
|
|
||||||
if (this._residentNotificationBox.get_n_children() > 0) {
|
|
||||||
this.actor.show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let children = this._persistentNotificationBox.get_children()
|
|
||||||
this.actor.visible = children.some(function(a) { return a.visible; });
|
|
||||||
},
|
|
||||||
|
|
||||||
_sourceIsResident: function(source) {
|
|
||||||
return source.hasResidentNotification() && !source.isChat;
|
|
||||||
},
|
|
||||||
|
|
||||||
_makeNotificationCountText: function(source) {
|
|
||||||
if (source.isChat)
|
|
||||||
return ngettext("%d new message", "%d new messages", source.count).format(source.count);
|
|
||||||
else
|
|
||||||
return ngettext("%d new notification", "%d new notifications", source.count).format(source.count);
|
|
||||||
},
|
|
||||||
|
|
||||||
_makeNotificationSource: function(source) {
|
|
||||||
let box = new St.BoxLayout({ style_class: 'screen-shield-notification-source' });
|
|
||||||
|
|
||||||
let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE);
|
|
||||||
box.add(sourceActor.actor, { y_fill: true });
|
|
||||||
|
|
||||||
let textBox = new St.BoxLayout({ vertical: true });
|
|
||||||
box.add(textBox);
|
|
||||||
|
|
||||||
let label = new St.Label({ text: source.title,
|
|
||||||
style_class: 'screen-shield-notification-label' });
|
|
||||||
textBox.add(label);
|
|
||||||
|
|
||||||
let countLabel = new St.Label({ text: this._makeNotificationCountText(source),
|
|
||||||
style_class: 'screen-shield-notification-count-text' });
|
|
||||||
textBox.add(countLabel);
|
|
||||||
|
|
||||||
box.visible = source.count != 0;
|
|
||||||
return [box, countLabel];
|
|
||||||
},
|
|
||||||
|
|
||||||
_summaryItemAdded: function(tray, item) {
|
|
||||||
// Ignore transient sources
|
|
||||||
if (item.source.isTransient)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let obj = {
|
|
||||||
item: item,
|
|
||||||
source: item.source,
|
|
||||||
resident: this._sourceIsResident(item.source),
|
|
||||||
contentUpdatedId: 0,
|
|
||||||
sourceDestroyId: 0,
|
|
||||||
sourceBox: null,
|
|
||||||
countLabel: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (obj.resident) {
|
|
||||||
item.prepareNotificationStackForShowing();
|
|
||||||
this._residentNotificationBox.add(item.notificationStackView);
|
|
||||||
} else {
|
|
||||||
[obj.sourceBox, obj.countLabel] = this._makeNotificationSource(item.source);
|
|
||||||
this._persistentNotificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.MIDDLE });
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.contentUpdatedId = item.connect('content-updated', Lang.bind(this, this._onItemContentUpdated));
|
|
||||||
obj.sourceCountChangedId = item.source.connect('count-changed', Lang.bind(this, this._onSourceChanged));
|
|
||||||
obj.sourceTitleChangedId = item.source.connect('title-changed', Lang.bind(this, this._onSourceChanged));
|
|
||||||
obj.sourceDestroyId = item.source.connect('destroy', Lang.bind(this, this._onSourceDestroy));
|
|
||||||
this._items.push(obj);
|
|
||||||
|
|
||||||
this._updateVisibility();
|
|
||||||
},
|
|
||||||
|
|
||||||
_findSource: function(source) {
|
|
||||||
for (let i = 0; i < this._items.length; i++) {
|
|
||||||
if (this._items[i].source == source)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
},
|
|
||||||
|
|
||||||
_onItemContentUpdated: function(item) {
|
|
||||||
let obj = this._items[this._findSource(item.source)];
|
|
||||||
this._updateItem(obj);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onSourceChanged: function(source) {
|
|
||||||
let obj = this._items[this._findSource(source)];
|
|
||||||
this._updateItem(obj);
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateItem: function(obj) {
|
|
||||||
let itemShouldBeResident = this._sourceIsResident(obj.source);
|
|
||||||
|
|
||||||
if (itemShouldBeResident && obj.resident) {
|
|
||||||
// Nothing to do here, the actor is already updated
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj.resident && !itemShouldBeResident) {
|
|
||||||
// make into a regular item
|
|
||||||
this._residentNotificationBox.remove_actor(obj.item.notificationStackView);
|
|
||||||
|
|
||||||
[obj.sourceBox, obj.countLabel] = this._makeNotificationSource(obj.source);
|
|
||||||
this._persistentNotificationBox.add(obj.sourceBox);
|
|
||||||
} else if (itemShouldBeResident && !obj.resident) {
|
|
||||||
// make into a resident item
|
|
||||||
obj.sourceBox.destroy();
|
|
||||||
obj.sourceBox = obj.countLabel = null;
|
|
||||||
|
|
||||||
obj.item.prepareNotificationStackForShowing();
|
|
||||||
this._residentNotificationBox.add(obj.item.notificationStackView);
|
|
||||||
} else {
|
|
||||||
// just update the counter
|
|
||||||
obj.countLabel.text = this._makeNotificationCountText(obj.item.source);
|
|
||||||
obj.sourceBox.visible = obj.source.count != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._updateVisibility();
|
|
||||||
},
|
|
||||||
|
|
||||||
_onSourceDestroy: function(source) {
|
|
||||||
let idx = this._findSource(source);
|
|
||||||
|
|
||||||
this._removeItem(this._items[idx]);
|
|
||||||
this._items.splice(idx, 1);
|
|
||||||
|
|
||||||
this._updateVisibility();
|
|
||||||
},
|
|
||||||
|
|
||||||
_removeItem: function(obj) {
|
|
||||||
if (obj.resident) {
|
|
||||||
this._residentNotificationBox.remove_actor(obj.item.notificationStackView);
|
|
||||||
obj.item.doneShowingNotificationStack();
|
|
||||||
} else {
|
|
||||||
obj.sourceBox.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.item.disconnect(obj.contentUpdatedId);
|
|
||||||
obj.source.disconnect(obj.sourceDestroyId);
|
|
||||||
obj.source.disconnect(obj.sourceCountChangedId);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To test screen shield, make sure to kill gnome-screensaver.
|
|
||||||
*
|
|
||||||
* If you are setting org.gnome.desktop.session.idle-delay directly in dconf,
|
|
||||||
* rather than through System Settings, you also need to set
|
|
||||||
* org.gnome.settings-daemon.plugins.power.sleep-display-ac and
|
|
||||||
* org.gnome.settings-daemon.plugins.power.sleep-display-battery to the same value.
|
|
||||||
* This will ensure that the screen blanks at the right time when it fades out.
|
|
||||||
* https://bugzilla.gnome.org/show_bug.cgi?id=668703 explains the dependance.
|
|
||||||
*/
|
|
||||||
const ScreenShield = new Lang.Class({
|
|
||||||
Name: 'ScreenShield',
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this.actor = Main.layoutManager.screenShieldGroup;
|
|
||||||
|
|
||||||
this._lockScreenGroup = new St.Widget({ x_expand: true,
|
|
||||||
y_expand: true,
|
|
||||||
reactive: true,
|
|
||||||
can_focus: true,
|
|
||||||
layout_manager: new Clutter.BinLayout()
|
|
||||||
});
|
|
||||||
|
|
||||||
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
|
|
||||||
this._background.add_effect(new Clutter.BlurEffect());
|
|
||||||
this._background.add_effect(new Clutter.DesaturateEffect({ factor: 0.6 }));
|
|
||||||
|
|
||||||
this._lockScreenGroup.add_actor(this._background);
|
|
||||||
|
|
||||||
this._arrow = new St.DrawingArea({ style_class: 'arrow',
|
|
||||||
reactive: true,
|
|
||||||
x_align: Clutter.ActorAlign.CENTER,
|
|
||||||
y_align: Clutter.ActorAlign.END,
|
|
||||||
// HACK: without these, ClutterBinLayout
|
|
||||||
// ignores alignment properties on the actor
|
|
||||||
x_expand: true,
|
|
||||||
y_expand: true
|
|
||||||
});
|
|
||||||
this._arrow.connect('repaint', Lang.bind(this, this._drawArrow));
|
|
||||||
this._lockScreenGroup.add_actor(this._arrow);
|
|
||||||
|
|
||||||
let action = new Clutter.DragAction({ drag_axis: Clutter.DragAxis.Y_AXIS });
|
|
||||||
action.connect('drag-begin', Lang.bind(this, this._onDragBegin));
|
|
||||||
action.connect('drag-end', Lang.bind(this, this._onDragEnd));
|
|
||||||
this._lockScreenGroup.add_action(action);
|
|
||||||
|
|
||||||
this._lockDialogGroup = new St.Widget({ x_expand: true,
|
|
||||||
y_expand: true });
|
|
||||||
|
|
||||||
this.actor.add_actor(this._lockDialogGroup);
|
|
||||||
this.actor.add_actor(this._lockScreenGroup);
|
|
||||||
|
|
||||||
this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) {
|
|
||||||
if (error) {
|
|
||||||
logError(error, 'Error while reading gnome-session presence');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._onStatusChanged(proxy.status);
|
|
||||||
}));
|
|
||||||
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
|
|
||||||
this._onStatusChanged(status);
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._settings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
|
|
||||||
|
|
||||||
this._isModal = false;
|
|
||||||
this._isLocked = false;
|
|
||||||
this._hasLockScreen = false;
|
|
||||||
|
|
||||||
this._lightbox = new Lightbox.Lightbox(Main.uiGroup,
|
|
||||||
{ inhibitEvents: true,
|
|
||||||
fadeInTime: STANDARD_FADE_TIME,
|
|
||||||
fadeFactor: 1 });
|
|
||||||
},
|
|
||||||
|
|
||||||
_onStageKeyRelease: function(actor, event) {
|
|
||||||
if (!this._isLocked)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (event.get_key_symbol() == Clutter.KEY_Escape) {
|
|
||||||
this._showUnlockDialog(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._bumpLockScreen();
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
_drawArrow: function() {
|
|
||||||
let cr = this._arrow.get_context();
|
|
||||||
let [w, h] = this._arrow.get_surface_size();
|
|
||||||
let node = this._arrow.get_theme_node();
|
|
||||||
|
|
||||||
Clutter.cairo_set_source_color(cr, node.get_foreground_color());
|
|
||||||
|
|
||||||
cr.moveTo(0, h);
|
|
||||||
cr.lineTo(w/2, 0);
|
|
||||||
cr.lineTo(w, h);
|
|
||||||
cr.fill();
|
|
||||||
},
|
|
||||||
|
|
||||||
_onDragBegin: function() {
|
|
||||||
Tweener.removeTweens(this._lockScreenGroup);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onDragEnd: function(action, actor, eventX, eventY, modifiers) {
|
|
||||||
if (this._lockScreenGroup.y < -(ARROW_DRAG_TRESHOLD * global.stage.height)) {
|
|
||||||
// Complete motion automatically
|
|
||||||
this._showUnlockDialog(true);
|
|
||||||
} else {
|
|
||||||
// restore the lock screen to its original place
|
|
||||||
// try to use the same speed as the normal animation
|
|
||||||
let h = global.stage.height;
|
|
||||||
let time = CURTAIN_SLIDE_TIME * (-this._lockScreenGroup.y) / h;
|
|
||||||
Tweener.removeTweens(this._lockScreenGroup);
|
|
||||||
Tweener.addTween(this._lockScreenGroup,
|
|
||||||
{ y: 0,
|
|
||||||
time: time,
|
|
||||||
transition: 'linear',
|
|
||||||
onComplete: function() {
|
|
||||||
this.fixed_position_set = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_onStatusChanged: function(status) {
|
|
||||||
if (status == GnomeSession.PresenceStatus.IDLE) {
|
|
||||||
if (this._dialog) {
|
|
||||||
this._dialog.cancel();
|
|
||||||
if (!this._keepDialog) {
|
|
||||||
this._dialog = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._isModal) {
|
|
||||||
Main.pushModal(this.actor);
|
|
||||||
this._isModal = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._isLocked)
|
|
||||||
this._lightbox.show();
|
|
||||||
} else {
|
|
||||||
let lightboxWasShown = this._lightbox.shown;
|
|
||||||
this._lightbox.hide();
|
|
||||||
|
|
||||||
let shouldLock = lightboxWasShown && this._settings.get_boolean(LOCK_ENABLED_KEY);
|
|
||||||
if (shouldLock || this._isLocked) {
|
|
||||||
this.lock(false);
|
|
||||||
} else if (this._isModal) {
|
|
||||||
this.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
showDialog: function() {
|
|
||||||
this.lock(true);
|
|
||||||
this._showUnlockDialog(false);
|
|
||||||
},
|
|
||||||
|
|
||||||
_bumpLockScreen: function() {
|
|
||||||
Tweener.removeTweens(this._lockScreenGroup);
|
|
||||||
Tweener.addTween(this._lockScreenGroup,
|
|
||||||
{ y: -BUMP_SIZE,
|
|
||||||
time: BUMP_TIME / 2,
|
|
||||||
transition: 'easeOutQuad',
|
|
||||||
onComplete: function() {
|
|
||||||
Tweener.addTween(this,
|
|
||||||
{ y: 0,
|
|
||||||
time: BUMP_TIME / 2,
|
|
||||||
transition: 'easeInQuad' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_showUnlockDialog: function(animate) {
|
|
||||||
if (animate) {
|
|
||||||
// Tween the lock screen out of screen
|
|
||||||
// try to use the same speed regardless of original position
|
|
||||||
let h = global.stage.height;
|
|
||||||
let time = CURTAIN_SLIDE_TIME * (h + this._lockScreenGroup.y) / h;
|
|
||||||
Tweener.removeTweens(this._lockScreenGroup);
|
|
||||||
Tweener.addTween(this._lockScreenGroup,
|
|
||||||
{ y: -h,
|
|
||||||
time: time,
|
|
||||||
transition: 'linear',
|
|
||||||
onComplete: Lang.bind(this, this._hideLockScreen),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this._hideLockScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._dialog) {
|
|
||||||
[this._dialog, this._keepDialog] = Main.sessionMode.createUnlockDialog(this._lockDialogGroup);
|
|
||||||
if (!this._dialog) {
|
|
||||||
// This session mode has no locking capabilities
|
|
||||||
this.unlock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._dialog.connect('loaded', Lang.bind(this, function() {
|
|
||||||
if (!this._dialog.open()) {
|
|
||||||
log('Could not open login dialog: failed to acquire grab');
|
|
||||||
this.unlock();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._dialog.connect('failed', Lang.bind(this, this._onUnlockFailed));
|
|
||||||
this._dialog.connect('unlocked', Lang.bind(this, this._onUnlockSucceded));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._keepDialog) {
|
|
||||||
// Notify the other components that even though we are showing the
|
|
||||||
// screenshield, we're not in a locked state
|
|
||||||
// (this happens for the gdm greeter)
|
|
||||||
|
|
||||||
this._isLocked = false;
|
|
||||||
this.emit('lock-status-changed', false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_onUnlockFailed: function() {
|
|
||||||
this._dialog.destroy();
|
|
||||||
this._dialog = null;
|
|
||||||
|
|
||||||
this._resetLockScreen(false);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onUnlockSucceded: function() {
|
|
||||||
this.unlock();
|
|
||||||
},
|
|
||||||
|
|
||||||
_hideLockScreen: function() {
|
|
||||||
this._arrow.hide();
|
|
||||||
this._lockScreenGroup.hide();
|
|
||||||
},
|
|
||||||
|
|
||||||
_resetLockScreen: function(animate) {
|
|
||||||
this._lockScreenGroup.show();
|
|
||||||
this._arrow.show();
|
|
||||||
|
|
||||||
if (animate) {
|
|
||||||
this._lockScreenGroup.y = -global.screen_height;
|
|
||||||
Tweener.removeTweens(this._lockScreenGroup);
|
|
||||||
Tweener.addTween(this._lockScreenGroup,
|
|
||||||
{ y: 0,
|
|
||||||
time: SHORT_FADE_TIME,
|
|
||||||
transition: 'linear',
|
|
||||||
onComplete: function() {
|
|
||||||
this._lockScreenGroup.fixed_position_set = false;
|
|
||||||
this.emit('lock-screen-shown');
|
|
||||||
},
|
|
||||||
onCompleteScope: this
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this._lockScreenGroup.fixed_position_set = false;
|
|
||||||
this.emit('lock-screen-shown');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._stageKeyHandler)
|
|
||||||
this._stageKeyHandler = global.stage.connect('key-release-event',
|
|
||||||
Lang.bind(this, this._onStageKeyRelease));
|
|
||||||
},
|
|
||||||
|
|
||||||
// Some of the actors in the lock screen are heavy in
|
|
||||||
// resources, so we only create them when needed
|
|
||||||
_prepareLockScreen: function() {
|
|
||||||
this._lockScreenContentsBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.CENTER,
|
|
||||||
y_align: Clutter.ActorAlign.CENTER,
|
|
||||||
x_expand: true,
|
|
||||||
y_expand: true,
|
|
||||||
vertical: true });
|
|
||||||
this._clock = new Clock();
|
|
||||||
this._lockScreenContentsBox.add(this._clock.actor, { x_fill: true,
|
|
||||||
y_fill: true });
|
|
||||||
|
|
||||||
this._lockScreenGroup.add_actor(this._lockScreenContentsBox);
|
|
||||||
|
|
||||||
if (this._settings.get_boolean('show-notifications')) {
|
|
||||||
this._notificationsBox = new NotificationsBox();
|
|
||||||
this._lockScreenContentsBox.add(this._notificationsBox.actor, { x_fill: true,
|
|
||||||
y_fill: true,
|
|
||||||
expand: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
this._hasLockScreen = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
_clearLockScreen: function() {
|
|
||||||
this._clock.destroy();
|
|
||||||
this._clock = null;
|
|
||||||
|
|
||||||
if (this._notificationsBox) {
|
|
||||||
this._notificationsBox.destroy();
|
|
||||||
this._notificationsBox = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._lockScreenContentsBox.destroy();
|
|
||||||
|
|
||||||
this._hasLockScreen = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
get locked() {
|
|
||||||
return this._isLocked;
|
|
||||||
},
|
|
||||||
|
|
||||||
unlock: function() {
|
|
||||||
if (this._hasLockScreen)
|
|
||||||
this._clearLockScreen();
|
|
||||||
|
|
||||||
if (this._stageKeyHandler) {
|
|
||||||
global.stage.disconnect(this._stageKeyHandler);
|
|
||||||
this._stageKeyHandler = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._keepDialog) {
|
|
||||||
// The dialog must be kept alive,
|
|
||||||
// so immediately go back to it
|
|
||||||
// This will also reset _isLocked
|
|
||||||
this._showUnlockDialog(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._dialog) {
|
|
||||||
this._dialog.destroy();
|
|
||||||
this._dialog = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._lightbox.hide();
|
|
||||||
|
|
||||||
Main.popModal(this.actor);
|
|
||||||
this.actor.hide();
|
|
||||||
|
|
||||||
this._isModal = false;
|
|
||||||
this._isLocked = false;
|
|
||||||
|
|
||||||
this.emit('lock-status-changed', false);
|
|
||||||
},
|
|
||||||
|
|
||||||
lock: function(animate) {
|
|
||||||
if (!this._hasLockScreen)
|
|
||||||
this._prepareLockScreen();
|
|
||||||
|
|
||||||
if (!this._isModal) {
|
|
||||||
Main.pushModal(this.actor);
|
|
||||||
this._isModal = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._isLocked = true;
|
|
||||||
this.actor.show();
|
|
||||||
this._resetLockScreen(animate);
|
|
||||||
|
|
||||||
this.emit('lock-status-changed', true);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
Signals.addSignalMethods(ScreenShield.prototype);
|
|
||||||
179
js/ui/search.js
@@ -18,15 +18,20 @@ const DISABLED_OPEN_SEARCH_PROVIDERS_KEY = 'disabled-open-search-providers';
|
|||||||
const MatchType = {
|
const MatchType = {
|
||||||
NONE: 0,
|
NONE: 0,
|
||||||
SUBSTRING: 1,
|
SUBSTRING: 1,
|
||||||
PREFIX: 2
|
MULTIPLE_SUBSTRING: 2,
|
||||||
|
PREFIX: 3,
|
||||||
|
MULTIPLE_PREFIX: 4
|
||||||
};
|
};
|
||||||
|
|
||||||
const SearchResultDisplay = new Lang.Class({
|
function SearchResultDisplay(provider) {
|
||||||
Name: 'SearchResultDisplay',
|
this._init(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchResultDisplay.prototype = {
|
||||||
_init: function(provider) {
|
_init: function(provider) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
this.actor = null;
|
this.actor = null;
|
||||||
|
this.selectionIndex = -1;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,10 +53,20 @@ const SearchResultDisplay = new Lang.Class({
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* clear:
|
* clear:
|
||||||
* Remove all results from this display.
|
* Remove all results from this display and reset the selection index.
|
||||||
*/
|
*/
|
||||||
clear: function() {
|
clear: function() {
|
||||||
this.actor.destroy_all_children();
|
this.actor.get_children().forEach(function (actor) { actor.destroy(); });
|
||||||
|
this.selectionIndex = -1;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getSelectionIndex:
|
||||||
|
*
|
||||||
|
* Returns the index of the selected actor, or -1 if none.
|
||||||
|
*/
|
||||||
|
getSelectionIndex: function() {
|
||||||
|
return this.selectionIndex;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -62,7 +77,26 @@ const SearchResultDisplay = new Lang.Class({
|
|||||||
getVisibleResultCount: function() {
|
getVisibleResultCount: function() {
|
||||||
throw new Error('Not implemented');
|
throw new Error('Not implemented');
|
||||||
},
|
},
|
||||||
});
|
|
||||||
|
/**
|
||||||
|
* selectIndex:
|
||||||
|
* @index: Integer index
|
||||||
|
*
|
||||||
|
* Move selection to the given index.
|
||||||
|
* Return true if successful, false if no more results
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
|
selectIndex: function() {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate the currently selected search result.
|
||||||
|
*/
|
||||||
|
activateSelected: function() {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SearchProvider:
|
* SearchProvider:
|
||||||
@@ -70,15 +104,51 @@ const SearchResultDisplay = new Lang.Class({
|
|||||||
* Subclass this object to add a new result type
|
* Subclass this object to add a new result type
|
||||||
* to the search system, then call registerProvider()
|
* to the search system, then call registerProvider()
|
||||||
* in SearchSystem with an instance.
|
* in SearchSystem with an instance.
|
||||||
* Search is asynchronous and uses the
|
|
||||||
* getInitialResultSet()/getSubsearchResultSet() methods.
|
|
||||||
*/
|
*/
|
||||||
const SearchProvider = new Lang.Class({
|
function SearchProvider(title) {
|
||||||
Name: 'SearchProvider',
|
this._init(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchProvider.prototype = {
|
||||||
_init: function(title) {
|
_init: function(title) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.searchSystem = null;
|
this.searchSystem = null;
|
||||||
|
this.searchAsync = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
_asyncCancelled: function() {
|
||||||
|
},
|
||||||
|
|
||||||
|
startAsync: function() {
|
||||||
|
this.searchAsync = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
tryCancelAsync: function() {
|
||||||
|
if (!this.searchAsync)
|
||||||
|
return;
|
||||||
|
this._asyncCancelled();
|
||||||
|
this.searchAsync = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* addItems:
|
||||||
|
* @items: an array of result identifier strings representing
|
||||||
|
* items which match the last given search terms.
|
||||||
|
*
|
||||||
|
* This should be used for something that requires a bit more
|
||||||
|
* logic; it's designed to be an asyncronous way to add a result
|
||||||
|
* to the current search.
|
||||||
|
*/
|
||||||
|
addItems: function(items) {
|
||||||
|
if (!this.searchSystem)
|
||||||
|
throw new Error('Search provider not registered');
|
||||||
|
|
||||||
|
if (!items.length)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.tryCancelAsync();
|
||||||
|
|
||||||
|
this.searchSystem.addProviderItems(this, items);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,7 +159,7 @@ const SearchProvider = new Lang.Class({
|
|||||||
* therefore a single term of length one or two), or when
|
* therefore a single term of length one or two), or when
|
||||||
* a new term is added.
|
* a new term is added.
|
||||||
*
|
*
|
||||||
* Should "return" an array of result identifier strings representing
|
* Should return an array of result identifier strings representing
|
||||||
* items which match the given search terms. This
|
* items which match the given search terms. This
|
||||||
* is expected to be a substring match on the metadata for a given
|
* is expected to be a substring match on the metadata for a given
|
||||||
* item. Ordering of returned results is up to the discretion of the provider,
|
* item. Ordering of returned results is up to the discretion of the provider,
|
||||||
@@ -99,9 +169,6 @@ const SearchProvider = new Lang.Class({
|
|||||||
* description) before single matches
|
* description) before single matches
|
||||||
* * Put items which match on a prefix before non-prefix substring matches
|
* * Put items which match on a prefix before non-prefix substring matches
|
||||||
*
|
*
|
||||||
* We say "return" above, but in order to make the query asynchronous, use
|
|
||||||
* this.searchSystem.pushResults();. The return value should be ignored.
|
|
||||||
*
|
|
||||||
* This function should be fast; do not perform unindexed full-text searches
|
* This function should be fast; do not perform unindexed full-text searches
|
||||||
* or network queries.
|
* or network queries.
|
||||||
*/
|
*/
|
||||||
@@ -121,26 +188,36 @@ const SearchProvider = new Lang.Class({
|
|||||||
*
|
*
|
||||||
* This allows search providers to only search through the previous
|
* This allows search providers to only search through the previous
|
||||||
* result set, rather than possibly performing a full re-query.
|
* result set, rather than possibly performing a full re-query.
|
||||||
*
|
|
||||||
* Similar to getInitialResultSet, the return value for this will
|
|
||||||
* be ignored; use this.searchSystem.pushResults();.
|
|
||||||
*/
|
*/
|
||||||
getSubsearchResultSet: function(previousResults, newTerms) {
|
getSubsearchResultSet: function(previousResults, newTerms) {
|
||||||
throw new Error('Not implemented');
|
throw new Error('Not implemented');
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getResultMetas:
|
* getResultMeta:
|
||||||
* @ids: Result identifier strings
|
* @id: Result identifier string
|
||||||
*
|
*
|
||||||
* Call callback with array of objects with 'id', 'name', (both strings) and
|
* Return an object with 'id', 'name', (both strings) and 'createIcon'
|
||||||
* 'createIcon' (function(size) returning a Clutter.Texture) properties
|
* (function(size) returning a Clutter.Texture) properties which describe
|
||||||
* with the same number of members as @ids
|
* the given search result.
|
||||||
*/
|
*/
|
||||||
getResultMetas: function(ids, callback) {
|
getResultMeta: function(id) {
|
||||||
throw new Error('Not implemented');
|
throw new Error('Not implemented');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* createResultContainer:
|
||||||
|
*
|
||||||
|
* Search providers may optionally override this to render their
|
||||||
|
* results in a custom fashion. The default implementation
|
||||||
|
* will create a vertical list.
|
||||||
|
*
|
||||||
|
* Returns: An instance of SearchResultDisplay.
|
||||||
|
*/
|
||||||
|
createResultContainerActor: function() {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* createResultActor:
|
* createResultActor:
|
||||||
* @resultMeta: Object with result metadata
|
* @resultMeta: Object with result metadata
|
||||||
@@ -166,12 +243,14 @@ const SearchProvider = new Lang.Class({
|
|||||||
activateResult: function(id) {
|
activateResult: function(id) {
|
||||||
throw new Error('Not implemented');
|
throw new Error('Not implemented');
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(SearchProvider.prototype);
|
Signals.addSignalMethods(SearchProvider.prototype);
|
||||||
|
|
||||||
const OpenSearchSystem = new Lang.Class({
|
function OpenSearchSystem() {
|
||||||
Name: 'OpenSearchSystem',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenSearchSystem.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._providers = [];
|
this._providers = [];
|
||||||
global.settings.connect('changed::' + DISABLED_OPEN_SEARCH_PROVIDERS_KEY, Lang.bind(this, this._refresh));
|
global.settings.connect('changed::' + DISABLED_OPEN_SEARCH_PROVIDERS_KEY, Lang.bind(this, this._refresh));
|
||||||
@@ -229,7 +308,7 @@ const OpenSearchSystem = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_addProvider: function(fileName) {
|
_addProvider: function(fileName) {
|
||||||
let path = global.datadir + '/open-search-providers/' + fileName;
|
let path = global.datadir + '/search_providers/' + fileName;
|
||||||
let source = Shell.get_file_contents_utf8_sync(path);
|
let source = Shell.get_file_contents_utf8_sync(path);
|
||||||
let [success, name, url, langs, icon_uri] = Shell.parse_search_provider(source);
|
let [success, name, url, langs, icon_uri] = Shell.parse_search_provider(source);
|
||||||
let provider ={ name: name,
|
let provider ={ name: name,
|
||||||
@@ -246,7 +325,7 @@ const OpenSearchSystem = new Lang.Class({
|
|||||||
_refresh: function() {
|
_refresh: function() {
|
||||||
this._providers = [];
|
this._providers = [];
|
||||||
let names = global.settings.get_strv(DISABLED_OPEN_SEARCH_PROVIDERS_KEY);
|
let names = global.settings.get_strv(DISABLED_OPEN_SEARCH_PROVIDERS_KEY);
|
||||||
let file = Gio.file_new_for_path(global.datadir + '/open-search-providers');
|
let file = Gio.file_new_for_path(global.datadir + '/search_providers');
|
||||||
FileUtils.listDirAsync(file, Lang.bind(this, function(files) {
|
FileUtils.listDirAsync(file, Lang.bind(this, function(files) {
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
let enabled = true;
|
let enabled = true;
|
||||||
@@ -259,12 +338,14 @@ const OpenSearchSystem = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
Signals.addSignalMethods(OpenSearchSystem.prototype);
|
Signals.addSignalMethods(OpenSearchSystem.prototype);
|
||||||
|
|
||||||
const SearchSystem = new Lang.Class({
|
function SearchSystem() {
|
||||||
Name: 'SearchSystem',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchSystem.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._providers = [];
|
this._providers = [];
|
||||||
this.reset();
|
this.reset();
|
||||||
@@ -296,13 +377,8 @@ const SearchSystem = new Lang.Class({
|
|||||||
this._previousResults = [];
|
this._previousResults = [];
|
||||||
},
|
},
|
||||||
|
|
||||||
pushResults: function(provider, results) {
|
addProviderItems: function(provider, items) {
|
||||||
let i = this._providers.indexOf(provider);
|
this.emit('search-updated', provider, items);
|
||||||
if (i == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._previousResults[i] = [provider, results];
|
|
||||||
this.emit('search-updated', this._previousResults[i]);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
updateSearch: function(searchString) {
|
updateSearch: function(searchString) {
|
||||||
@@ -328,33 +404,34 @@ const SearchSystem = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let previousResultsArr = this._previousResults;
|
|
||||||
|
|
||||||
let results = [];
|
let results = [];
|
||||||
this._previousTerms = terms;
|
|
||||||
this._previousResults = results;
|
|
||||||
|
|
||||||
if (isSubSearch) {
|
if (isSubSearch) {
|
||||||
for (let i = 0; i < this._providers.length; i++) {
|
for (let i = 0; i < this._providers.length; i++) {
|
||||||
let [provider, previousResults] = previousResultsArr[i];
|
let [provider, previousResults] = this._previousResults[i];
|
||||||
|
provider.tryCancelAsync();
|
||||||
try {
|
try {
|
||||||
results.push([provider, []]);
|
let providerResults = provider.getSubsearchResultSet(previousResults, terms);
|
||||||
provider.getSubsearchResultSet(previousResults, terms);
|
results.push([provider, providerResults]);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
|
global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < this._providers.length; i++) {
|
for (let i = 0; i < this._providers.length; i++) {
|
||||||
let provider = this._providers[i];
|
let provider = this._providers[i];
|
||||||
|
provider.tryCancelAsync();
|
||||||
try {
|
try {
|
||||||
results.push([provider, []]);
|
let providerResults = provider.getInitialResultSet(terms);
|
||||||
provider.getInitialResultSet(terms);
|
results.push([provider, providerResults]);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
|
global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._previousTerms = terms;
|
||||||
|
this._previousResults = results;
|
||||||
|
this.emit('search-completed', results);
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
Signals.addSignalMethods(SearchSystem.prototype);
|
Signals.addSignalMethods(SearchSystem.prototype);
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ const Lang = imports.lang;
|
|||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Atk = imports.gi.Atk;
|
|
||||||
|
|
||||||
const DND = imports.ui.dnd;
|
const DND = imports.ui.dnd;
|
||||||
const IconGrid = imports.ui.iconGrid;
|
const IconGrid = imports.ui.iconGrid;
|
||||||
@@ -16,9 +15,11 @@ const Search = imports.ui.search;
|
|||||||
const MAX_SEARCH_RESULTS_ROWS = 1;
|
const MAX_SEARCH_RESULTS_ROWS = 1;
|
||||||
|
|
||||||
|
|
||||||
const SearchResult = new Lang.Class({
|
function SearchResult(provider, metaInfo, terms) {
|
||||||
Name: 'SearchResult',
|
this._init(provider, metaInfo, terms);
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchResult.prototype = {
|
||||||
_init: function(provider, metaInfo, terms) {
|
_init: function(provider, metaInfo, terms) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
this.metaInfo = metaInfo;
|
this.metaInfo = metaInfo;
|
||||||
@@ -33,14 +34,12 @@ const SearchResult = new Lang.Class({
|
|||||||
if (content == null) {
|
if (content == null) {
|
||||||
content = new St.Bin({ style_class: 'search-result-content',
|
content = new St.Bin({ style_class: 'search-result-content',
|
||||||
reactive: true,
|
reactive: true,
|
||||||
can_focus: true,
|
track_hover: true });
|
||||||
track_hover: true,
|
|
||||||
accessible_role: Atk.Role.PUSH_BUTTON });
|
|
||||||
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
|
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
|
||||||
{ createIcon: this.metaInfo['createIcon'] });
|
{ createIcon: this.metaInfo['createIcon'] });
|
||||||
content.set_child(icon.actor);
|
content.set_child(icon.actor);
|
||||||
this._dragActorSource = icon.icon;
|
this._dragActorSource = icon.icon;
|
||||||
content.label_actor = icon.label;
|
this.actor.label_actor = icon.label;
|
||||||
} else {
|
} else {
|
||||||
if (content._delegate && content._delegate.getDragActorSource)
|
if (content._delegate && content._delegate.getDragActorSource)
|
||||||
this._dragActorSource = content._delegate.getDragActorSource();
|
this._dragActorSource = content._delegate.getDragActorSource();
|
||||||
@@ -98,84 +97,100 @@ const SearchResult = new Lang.Class({
|
|||||||
else
|
else
|
||||||
this.provider.activateResult(this.metaInfo.id, params);
|
this.provider.activateResult(this.metaInfo.id, params);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
|
||||||
const GridSearchResults = new Lang.Class({
|
function GridSearchResults(provider, grid) {
|
||||||
Name: 'GridSearchResults',
|
this._init(provider, grid);
|
||||||
Extends: Search.SearchResultDisplay,
|
}
|
||||||
|
|
||||||
|
GridSearchResults.prototype = {
|
||||||
|
__proto__: Search.SearchResultDisplay.prototype,
|
||||||
|
|
||||||
_init: function(provider, grid) {
|
_init: function(provider, grid) {
|
||||||
this.parent(provider);
|
Search.SearchResultDisplay.prototype._init.call(this, provider);
|
||||||
|
|
||||||
this._grid = grid || new IconGrid.IconGrid({ rowLimit: MAX_SEARCH_RESULTS_ROWS,
|
this._grid = grid || new IconGrid.IconGrid({ rowLimit: MAX_SEARCH_RESULTS_ROWS,
|
||||||
xAlign: St.Align.START });
|
xAlign: St.Align.START });
|
||||||
this.actor = new St.Bin({ x_align: St.Align.START });
|
this.actor = new St.Bin({ x_align: St.Align.START });
|
||||||
|
|
||||||
this.actor.set_child(this._grid.actor);
|
this.actor.set_child(this._grid.actor);
|
||||||
|
this.selectionIndex = -1;
|
||||||
this._width = 0;
|
this._width = 0;
|
||||||
this.actor.connect('notify::width', Lang.bind(this, function() {
|
this.actor.connect('notify::width', Lang.bind(this, function() {
|
||||||
this._width = this.actor.width;
|
this._width = this.actor.width;
|
||||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
||||||
let results = this.getResultsForDisplay();
|
this._tryAddResults();
|
||||||
if (results.length == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
provider.getResultMetas(results, Lang.bind(this, this.renderResults));
|
|
||||||
}));
|
}));
|
||||||
}));
|
}));
|
||||||
this._notDisplayedResult = [];
|
this._notDisplayedResult = [];
|
||||||
this._terms = [];
|
this._terms = [];
|
||||||
this._pendingClear = false;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getResultsForDisplay: function() {
|
_tryAddResults: function() {
|
||||||
let alreadyVisible = this._pendingClear ? 0 : this._grid.visibleItemsCount();
|
let canDisplay = this._grid.childrenInRow(this._width) * MAX_SEARCH_RESULTS_ROWS
|
||||||
let canDisplay = this._grid.childrenInRow(this._width) * this._grid.getRowLimit()
|
- this._grid.visibleItemsCount();
|
||||||
- alreadyVisible;
|
|
||||||
|
|
||||||
let numResults = Math.min(this._notDisplayedResult.length, canDisplay);
|
for (let i = Math.min(this._notDisplayedResult.length, canDisplay); i > 0; i--) {
|
||||||
|
let result = this._notDisplayedResult.shift();
|
||||||
return this._notDisplayedResult.splice(0, numResults);
|
let meta = this.provider.getResultMeta(result);
|
||||||
|
let display = new SearchResult(this.provider, meta, this._terms);
|
||||||
|
this._grid.addItem(display.actor);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getVisibleResultCount: function() {
|
getVisibleResultCount: function() {
|
||||||
return this._grid.visibleItemsCount();
|
return this._grid.visibleItemsCount();
|
||||||
},
|
},
|
||||||
|
|
||||||
setResults: function(results, terms) {
|
renderResults: function(results, terms) {
|
||||||
// copy the lists
|
// copy the lists
|
||||||
this._notDisplayedResult = results.slice(0);
|
this._notDisplayedResult = results.slice(0);
|
||||||
this._terms = terms.slice(0);
|
this._terms = terms.slice(0);
|
||||||
this._pendingClear = true;
|
this._tryAddResults();
|
||||||
},
|
|
||||||
|
|
||||||
renderResults: function(metas) {
|
|
||||||
for (let i = 0; i < metas.length; i++) {
|
|
||||||
let display = new SearchResult(this.provider, metas[i], this._terms);
|
|
||||||
this._grid.addItem(display.actor);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
clear: function () {
|
clear: function () {
|
||||||
|
this._terms = [];
|
||||||
|
this._notDisplayedResult = [];
|
||||||
this._grid.removeAll();
|
this._grid.removeAll();
|
||||||
this._pendingClear = false;
|
this.selectionIndex = -1;
|
||||||
},
|
},
|
||||||
|
|
||||||
getFirstResult: function() {
|
selectIndex: function (index) {
|
||||||
if (this.getVisibleResultCount() > 0)
|
let nVisible = this.getVisibleResultCount();
|
||||||
return this._grid.getItemAtIndex(0)._delegate;
|
if (this.selectionIndex >= 0) {
|
||||||
else
|
let prevActor = this._grid.getItemAtIndex(this.selectionIndex);
|
||||||
return null;
|
prevActor._delegate.setSelected(false);
|
||||||
}
|
}
|
||||||
});
|
this.selectionIndex = -1;
|
||||||
|
if (index >= nVisible)
|
||||||
|
return false;
|
||||||
|
else if (index < 0)
|
||||||
|
return false;
|
||||||
|
let targetActor = this._grid.getItemAtIndex(index);
|
||||||
|
targetActor._delegate.setSelected(true);
|
||||||
|
this.selectionIndex = index;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
const SearchResults = new Lang.Class({
|
activateSelected: function() {
|
||||||
Name: 'SearchResults',
|
if (this.selectionIndex < 0)
|
||||||
|
return;
|
||||||
|
let targetActor = this._grid.getItemAtIndex(this.selectionIndex);
|
||||||
|
targetActor._delegate.activate();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function SearchResults(searchSystem, openSearchSystem) {
|
||||||
|
this._init(searchSystem, openSearchSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchResults.prototype = {
|
||||||
_init: function(searchSystem, openSearchSystem) {
|
_init: function(searchSystem, openSearchSystem) {
|
||||||
this._searchSystem = searchSystem;
|
this._searchSystem = searchSystem;
|
||||||
this._searchSystem.connect('search-updated', Lang.bind(this, this._updateResults));
|
this._searchSystem.connect('search-updated', Lang.bind(this, this._updateCurrentResults));
|
||||||
|
this._searchSystem.connect('search-completed', Lang.bind(this, this._updateResults));
|
||||||
this._openSearchSystem = openSearchSystem;
|
this._openSearchSystem = openSearchSystem;
|
||||||
|
|
||||||
this.actor = new St.BoxLayout({ name: 'searchResults',
|
this.actor = new St.BoxLayout({ name: 'searchResults',
|
||||||
@@ -207,10 +222,13 @@ const SearchResults = new Lang.Class({
|
|||||||
|
|
||||||
this._statusText = new St.Label({ style_class: 'search-statustext' });
|
this._statusText = new St.Label({ style_class: 'search-statustext' });
|
||||||
this._content.add(this._statusText);
|
this._content.add(this._statusText);
|
||||||
|
this._selectedProvider = -1;
|
||||||
this._providers = this._searchSystem.getProviders();
|
this._providers = this._searchSystem.getProviders();
|
||||||
this._providerMeta = [];
|
this._providerMeta = [];
|
||||||
|
this._providerMetaResults = {};
|
||||||
for (let i = 0; i < this._providers.length; i++) {
|
for (let i = 0; i < this._providers.length; i++) {
|
||||||
this.createProviderMeta(this._providers[i]);
|
this.createProviderMeta(this._providers[i]);
|
||||||
|
this._providerMetaResults[this.providers[i].title] = [];
|
||||||
}
|
}
|
||||||
this._searchProvidersBox = new St.BoxLayout({ style_class: 'search-providers-box' });
|
this._searchProvidersBox = new St.BoxLayout({ style_class: 'search-providers-box' });
|
||||||
this.actor.add(this._searchProvidersBox);
|
this.actor.add(this._searchProvidersBox);
|
||||||
@@ -218,12 +236,10 @@ const SearchResults = new Lang.Class({
|
|||||||
this._openSearchProviders = [];
|
this._openSearchProviders = [];
|
||||||
this._openSearchSystem.connect('changed', Lang.bind(this, this._updateOpenSearchProviderButtons));
|
this._openSearchSystem.connect('changed', Lang.bind(this, this._updateOpenSearchProviderButtons));
|
||||||
this._updateOpenSearchProviderButtons();
|
this._updateOpenSearchProviderButtons();
|
||||||
|
|
||||||
this._highlightDefault = false;
|
|
||||||
this._defaultResult = null;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateOpenSearchProviderButtons: function() {
|
_updateOpenSearchProviderButtons: function() {
|
||||||
|
this._selectedOpenSearchButton = -1;
|
||||||
for (let i = 0; i < this._openSearchProviders.length; i++)
|
for (let i = 0; i < this._openSearchProviders.length; i++)
|
||||||
this._openSearchProviders[i].actor.destroy();
|
this._openSearchProviders[i].actor.destroy();
|
||||||
this._openSearchProviders = this._openSearchSystem.getProviders();
|
this._openSearchProviders = this._openSearchSystem.getProviders();
|
||||||
@@ -231,10 +247,18 @@ const SearchResults = new Lang.Class({
|
|||||||
this._createOpenSearchProviderButton(this._openSearchProviders[i]);
|
this._createOpenSearchProviderButton(this._openSearchProviders[i]);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_updateOpenSearchButtonState: function() {
|
||||||
|
for (let i = 0; i < this._openSearchProviders.length; i++) {
|
||||||
|
if (i == this._selectedOpenSearchButton)
|
||||||
|
this._openSearchProviders[i].actor.add_style_pseudo_class('selected');
|
||||||
|
else
|
||||||
|
this._openSearchProviders[i].actor.remove_style_pseudo_class('selected');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_createOpenSearchProviderButton: function(provider) {
|
_createOpenSearchProviderButton: function(provider) {
|
||||||
let button = new St.Button({ style_class: 'dash-search-button',
|
let button = new St.Button({ style_class: 'dash-search-button',
|
||||||
reactive: true,
|
reactive: true,
|
||||||
can_focus: true,
|
|
||||||
x_fill: true,
|
x_fill: true,
|
||||||
y_align: St.Align.MIDDLE });
|
y_align: St.Align.MIDDLE });
|
||||||
let bin = new St.Bin({ x_fill: false,
|
let bin = new St.Bin({ x_fill: false,
|
||||||
@@ -250,17 +274,6 @@ const SearchResults = new Lang.Class({
|
|||||||
button.set_child(bin);
|
button.set_child(bin);
|
||||||
provider.actor = button;
|
provider.actor = button;
|
||||||
|
|
||||||
button.setSelected = function(selected) {
|
|
||||||
if (selected)
|
|
||||||
button.add_style_pseudo_class('selected');
|
|
||||||
else
|
|
||||||
button.remove_style_pseudo_class('selected');
|
|
||||||
};
|
|
||||||
button.activate = Lang.bind(this, function() {
|
|
||||||
this._openSearchSystem.activateResult(provider.id);
|
|
||||||
});
|
|
||||||
button.actor = button;
|
|
||||||
|
|
||||||
this._searchProvidersBox.add(button);
|
this._searchProvidersBox.add(button);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -275,7 +288,10 @@ const SearchResults = new Lang.Class({
|
|||||||
x_fill: true,
|
x_fill: true,
|
||||||
y_fill: true });
|
y_fill: true });
|
||||||
providerBox.add(resultDisplayBin, { expand: true });
|
providerBox.add(resultDisplayBin, { expand: true });
|
||||||
let resultDisplay = new GridSearchResults(provider);
|
let resultDisplay = provider.createResultContainerActor();
|
||||||
|
if (resultDisplay == null) {
|
||||||
|
resultDisplay = new GridSearchResults(provider);
|
||||||
|
}
|
||||||
resultDisplayBin.set_child(resultDisplay.actor);
|
resultDisplayBin.set_child(resultDisplay.actor);
|
||||||
|
|
||||||
this._providerMeta.push({ provider: provider,
|
this._providerMeta.push({ provider: provider,
|
||||||
@@ -296,6 +312,8 @@ const SearchResults = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_clearDisplay: function() {
|
_clearDisplay: function() {
|
||||||
|
this._selectedProvider = -1;
|
||||||
|
this._visibleResultsCount = 0;
|
||||||
for (let i = 0; i < this._providerMeta.length; i++) {
|
for (let i = 0; i < this._providerMeta.length; i++) {
|
||||||
let meta = this._providerMeta[i];
|
let meta = this._providerMeta[i];
|
||||||
meta.resultDisplay.clear();
|
meta.resultDisplay.clear();
|
||||||
@@ -303,8 +321,8 @@ const SearchResults = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_clearDisplayForProvider: function(provider) {
|
_clearDisplayForProvider: function(index) {
|
||||||
let meta = this._metaForProvider(provider);
|
let meta = this._providerMeta[index];
|
||||||
meta.resultDisplay.clear();
|
meta.resultDisplay.clear();
|
||||||
meta.actor.hide();
|
meta.actor.hide();
|
||||||
},
|
},
|
||||||
@@ -313,6 +331,8 @@ const SearchResults = new Lang.Class({
|
|||||||
this._searchSystem.reset();
|
this._searchSystem.reset();
|
||||||
this._statusText.hide();
|
this._statusText.hide();
|
||||||
this._clearDisplay();
|
this._clearDisplay();
|
||||||
|
this._selectedOpenSearchButton = -1;
|
||||||
|
this._updateOpenSearchButtonState();
|
||||||
},
|
},
|
||||||
|
|
||||||
startingSearch: function() {
|
startingSearch: function() {
|
||||||
@@ -323,123 +343,147 @@ const SearchResults = new Lang.Class({
|
|||||||
|
|
||||||
doSearch: function (searchString) {
|
doSearch: function (searchString) {
|
||||||
this._searchSystem.updateSearch(searchString);
|
this._searchSystem.updateSearch(searchString);
|
||||||
let terms = this._searchSystem.getTerms();
|
|
||||||
this._openSearchSystem.setSearchTerms(terms);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_metaForProvider: function(provider) {
|
_metaForProvider: function(provider) {
|
||||||
return this._providerMeta[this._providers.indexOf(provider)];
|
return this._providerMeta[this._providers.indexOf(provider)];
|
||||||
},
|
},
|
||||||
|
|
||||||
_maybeSetInitialSelection: function() {
|
_updateCurrentResults: function(searchSystem, provider, results) {
|
||||||
let newDefaultResult = null;
|
let terms = searchSystem.getTerms();
|
||||||
|
let meta = this._metaForProvider(provider);
|
||||||
for (let i = 0; i < this._providerMeta.length; i++) {
|
meta.resultDisplay.clear();
|
||||||
let meta = this._providerMeta[i];
|
meta.actor.show();
|
||||||
|
meta.resultDisplay.renderResults(results, terms);
|
||||||
if (!meta.actor.visible)
|
return true;
|
||||||
continue;
|
|
||||||
|
|
||||||
let firstResult = meta.resultDisplay.getFirstResult();
|
|
||||||
if (firstResult) {
|
|
||||||
newDefaultResult = firstResult;
|
|
||||||
break; // select this one!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!newDefaultResult)
|
|
||||||
newDefaultResult = this._searchProvidersBox.get_first_child();
|
|
||||||
|
|
||||||
if (newDefaultResult != this._defaultResult) {
|
|
||||||
if (this._defaultResult)
|
|
||||||
this._defaultResult.setSelected(false);
|
|
||||||
if (newDefaultResult)
|
|
||||||
newDefaultResult.setSelected(this._highlightDefault);
|
|
||||||
|
|
||||||
this._defaultResult = newDefaultResult;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateStatusText: function () {
|
|
||||||
let haveResults = false;
|
|
||||||
|
|
||||||
for (let i = 0; i < this._providerMeta.length; ++i)
|
|
||||||
if (this._providerMeta[i].resultDisplay.getFirstResult()) {
|
|
||||||
haveResults = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!haveResults) {
|
|
||||||
this._statusText.set_text(_("No matching results."));
|
|
||||||
this._statusText.show();
|
|
||||||
} else {
|
|
||||||
this._statusText.hide();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateResults: function(searchSystem, results) {
|
_updateResults: function(searchSystem, results) {
|
||||||
let terms = searchSystem.getTerms();
|
if (results.length == 0) {
|
||||||
let [provider, providerResults] = results;
|
this._statusText.set_text(_("No matching results."));
|
||||||
let meta = this._metaForProvider(provider);
|
this._statusText.show();
|
||||||
|
|
||||||
if (providerResults.length == 0) {
|
|
||||||
this._clearDisplayForProvider(provider);
|
|
||||||
meta.resultDisplay.setResults([], []);
|
|
||||||
this._maybeSetInitialSelection();
|
|
||||||
this._updateStatusText();
|
|
||||||
} else {
|
} else {
|
||||||
meta.resultDisplay.setResults(providerResults, terms);
|
this._selectedOpenSearchButton = -1;
|
||||||
let results = meta.resultDisplay.getResultsForDisplay();
|
this._updateOpenSearchButtonState();
|
||||||
|
this._statusText.hide();
|
||||||
|
}
|
||||||
|
|
||||||
provider.getResultMetas(results, Lang.bind(this, function(metas) {
|
let terms = searchSystem.getTerms();
|
||||||
this._clearDisplayForProvider(provider);
|
this._openSearchSystem.setSearchTerms(terms);
|
||||||
meta.actor.show();
|
|
||||||
|
|
||||||
// Hiding drops the key focus if we have it
|
// To avoid CSS transitions causing flickering
|
||||||
let focus = global.stage.get_key_focus();
|
// of the selection when the first search result
|
||||||
// To avoid CSS transitions causing flickering when
|
// stays the same, we hide the content while
|
||||||
// the first search result stays the same, we hide the
|
// filling in the results and setting the initial
|
||||||
// content while filling in the results.
|
// selection.
|
||||||
this._content.hide();
|
this._content.hide();
|
||||||
|
|
||||||
meta.resultDisplay.renderResults(metas);
|
for (let i = 0; i < results.length; i++) {
|
||||||
this._maybeSetInitialSelection();
|
let [provider, providerResults] = results[i];
|
||||||
this._updateStatusText();
|
if (providerResults.length == 0) {
|
||||||
|
this._clearDisplayForProvider(i);
|
||||||
|
} else {
|
||||||
|
this._providerMetaResults[provider.title] = providerResults;
|
||||||
|
this._clearDisplayForProvider(i);
|
||||||
|
let meta = this._metaForProvider(provider);
|
||||||
|
meta.actor.show();
|
||||||
|
meta.resultDisplay.renderResults(providerResults, terms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._selectedOpenSearchButton == -1)
|
||||||
|
this.selectDown(false);
|
||||||
|
|
||||||
this._content.show();
|
this._content.show();
|
||||||
if (this._content.contains(focus))
|
|
||||||
global.stage.set_key_focus(focus);
|
return true;
|
||||||
}));
|
},
|
||||||
|
|
||||||
|
_modifyActorSelection: function(resultDisplay, up) {
|
||||||
|
let success;
|
||||||
|
let index = resultDisplay.getSelectionIndex();
|
||||||
|
if (up && index == -1)
|
||||||
|
index = resultDisplay.getVisibleResultCount() - 1;
|
||||||
|
else if (up)
|
||||||
|
index = index - 1;
|
||||||
|
else
|
||||||
|
index = index + 1;
|
||||||
|
return resultDisplay.selectIndex(index);
|
||||||
|
},
|
||||||
|
|
||||||
|
selectUp: function(recursing) {
|
||||||
|
if (this._selectedOpenSearchButton == -1) {
|
||||||
|
for (let i = this._selectedProvider; i >= 0; i--) {
|
||||||
|
let meta = this._providerMeta[i];
|
||||||
|
if (!meta.actor.visible)
|
||||||
|
continue;
|
||||||
|
let success = this._modifyActorSelection(meta.resultDisplay, true);
|
||||||
|
if (success) {
|
||||||
|
this._selectedProvider = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._selectedOpenSearchButton == -1)
|
||||||
|
this._selectedOpenSearchButton = this._openSearchProviders.length;
|
||||||
|
this._selectedOpenSearchButton--;
|
||||||
|
this._updateOpenSearchButtonState();
|
||||||
|
if (this._selectedOpenSearchButton >= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this._providerMeta.length > 0 && !recursing) {
|
||||||
|
this._selectedProvider = this._providerMeta.length - 1;
|
||||||
|
this.selectUp(true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
activateDefault: function() {
|
selectDown: function(recursing) {
|
||||||
if (this._defaultResult)
|
let current = this._selectedProvider;
|
||||||
this._defaultResult.activate();
|
if (this._selectedOpenSearchButton == -1) {
|
||||||
},
|
if (current == -1)
|
||||||
|
current = 0;
|
||||||
|
for (let i = current; i < this._providerMeta.length; i++) {
|
||||||
|
let meta = this._providerMeta[i];
|
||||||
|
if (!meta.actor.visible)
|
||||||
|
continue;
|
||||||
|
let success = this._modifyActorSelection(meta.resultDisplay, false);
|
||||||
|
if (success) {
|
||||||
|
this._selectedProvider = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._selectedOpenSearchButton++;
|
||||||
|
|
||||||
highlightDefault: function(highlight) {
|
if (this._selectedOpenSearchButton < this._openSearchProviders.length) {
|
||||||
this._highlightDefault = highlight;
|
this._updateOpenSearchButtonState();
|
||||||
if (this._defaultResult)
|
|
||||||
this._defaultResult.setSelected(highlight);
|
|
||||||
},
|
|
||||||
|
|
||||||
navigateFocus: function(direction) {
|
|
||||||
let rtl = this.actor.get_text_direction() == Clutter.TextDirection.RTL;
|
|
||||||
if (direction == Gtk.DirectionType.TAB_BACKWARD ||
|
|
||||||
direction == (rtl ? Gtk.DirectionType.RIGHT
|
|
||||||
: Gtk.DirectionType.LEFT) ||
|
|
||||||
direction == Gtk.DirectionType.UP) {
|
|
||||||
this.actor.navigate_focus(null, direction, false);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let from = this._defaultResult ? this._defaultResult.actor : null;
|
this._selectedOpenSearchButton = -1;
|
||||||
this.actor.navigate_focus(from, direction, false);
|
this._updateOpenSearchButtonState();
|
||||||
if (this._defaultResult) {
|
|
||||||
// The default result appears focused, so navigate directly to the
|
if (this._providerMeta.length > 0 && !recursing) {
|
||||||
// next result.
|
this._selectedProvider = 0;
|
||||||
this.actor.navigate_focus(global.stage.key_focus, direction, false);
|
this.selectDown(true);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
activateSelected: function() {
|
||||||
|
if (this._selectedOpenSearchButton != -1) {
|
||||||
|
let provider = this._openSearchProviders[this._selectedOpenSearchButton];
|
||||||
|
this._openSearchSystem.activateResult(provider.id);
|
||||||
|
Main.overview.hide();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
let current = this._selectedProvider;
|
||||||
|
if (current < 0)
|
||||||
|
return;
|
||||||
|
let meta = this._providerMeta[current];
|
||||||
|
let resultDisplay = meta.resultDisplay;
|
||||||
|
resultDisplay.activateSelected();
|
||||||
|
Main.overview.hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,135 +0,0 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
const Lang = imports.lang;
|
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
|
||||||
const Main = imports.ui.main;
|
|
||||||
const Params = imports.misc.params;
|
|
||||||
|
|
||||||
|
|
||||||
const STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION = {
|
|
||||||
'a11y': imports.ui.status.accessibility.ATIndicator,
|
|
||||||
'volume': imports.ui.status.volume.Indicator,
|
|
||||||
'battery': imports.ui.status.power.Indicator,
|
|
||||||
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
|
|
||||||
'userMenu': imports.ui.userMenu.UserMenuButton
|
|
||||||
};
|
|
||||||
|
|
||||||
if (Config.HAVE_BLUETOOTH)
|
|
||||||
STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION['bluetooth'] =
|
|
||||||
imports.ui.status.bluetooth.Indicator;
|
|
||||||
|
|
||||||
try {
|
|
||||||
STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION['network'] =
|
|
||||||
imports.ui.status.network.NMApplet;
|
|
||||||
} catch(e) {
|
|
||||||
log('NMApplet is not supported. It is possible that your NetworkManager version is too old');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const DEFAULT_MODE = 'user';
|
|
||||||
|
|
||||||
const _modes = {
|
|
||||||
'gdm': { hasOverview: false,
|
|
||||||
hasAppMenu: false,
|
|
||||||
showCalendarEvents: false,
|
|
||||||
allowSettings: false,
|
|
||||||
allowExtensions: false,
|
|
||||||
allowKeybindingsWhenModal: true,
|
|
||||||
hasRunDialog: false,
|
|
||||||
hasWorkspaces: false,
|
|
||||||
createSession: Main.createGDMSession,
|
|
||||||
createUnlockDialog: Main.createGDMLoginDialog,
|
|
||||||
extraStylesheet: null,
|
|
||||||
statusArea: {
|
|
||||||
order: [
|
|
||||||
'a11y', 'display', 'keyboard',
|
|
||||||
'volume', 'battery', 'powerMenu'
|
|
||||||
],
|
|
||||||
implementation: {
|
|
||||||
'a11y': imports.ui.status.accessibility.ATIndicator,
|
|
||||||
'volume': imports.ui.status.volume.Indicator,
|
|
||||||
'battery': imports.ui.status.power.Indicator,
|
|
||||||
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
|
|
||||||
'powerMenu': imports.gdm.powerMenu.PowerMenuButton
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
'initial-setup': { hasOverview: false,
|
|
||||||
hasAppMenu: false,
|
|
||||||
showCalendarEvents: false,
|
|
||||||
allowSettings: false,
|
|
||||||
allowExtensions: false,
|
|
||||||
allowKeybindingsWhenModal: false,
|
|
||||||
hasRunDialog: false,
|
|
||||||
hasWorkspaces: false,
|
|
||||||
createSession: Main.createInitialSetupSession,
|
|
||||||
extraStylesheet: null,
|
|
||||||
statusArea: {
|
|
||||||
order: [
|
|
||||||
'a11y', 'keyboard', 'volume'
|
|
||||||
],
|
|
||||||
implementation: {
|
|
||||||
'a11y': imports.ui.status.accessibility.ATIndicator,
|
|
||||||
'keyboard': imports.ui.status.keyboard.XKBIndicator,
|
|
||||||
'volume': imports.ui.status.volume.Indicator
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
'user': { hasOverview: true,
|
|
||||||
hasAppMenu: true,
|
|
||||||
showCalendarEvents: true,
|
|
||||||
allowSettings: true,
|
|
||||||
allowExtensions: true,
|
|
||||||
allowKeybindingsWhenModal: false,
|
|
||||||
hasRunDialog: true,
|
|
||||||
hasWorkspaces: true,
|
|
||||||
createSession: Main.createUserSession,
|
|
||||||
createUnlockDialog: Main.createSessionUnlockDialog,
|
|
||||||
extraStylesheet: null,
|
|
||||||
statusArea: {
|
|
||||||
order: [
|
|
||||||
'input-method', 'a11y', 'keyboard', 'volume', 'bluetooth',
|
|
||||||
'network', 'battery', 'userMenu'
|
|
||||||
],
|
|
||||||
implementation: STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function listModes() {
|
|
||||||
let modes = Object.getOwnPropertyNames(_modes);
|
|
||||||
for (let i = 0; i < modes.length; i++)
|
|
||||||
print(modes[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const SessionMode = new Lang.Class({
|
|
||||||
Name: 'SessionMode',
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
let params = _modes[global.session_mode];
|
|
||||||
|
|
||||||
params = Params.parse(params, _modes[DEFAULT_MODE]);
|
|
||||||
|
|
||||||
this._createSession = params.createSession;
|
|
||||||
delete params.createSession;
|
|
||||||
this._createUnlockDialog = params.createUnlockDialog;
|
|
||||||
delete params.createUnlockDialog;
|
|
||||||
|
|
||||||
Lang.copyProperties(params, this);
|
|
||||||
},
|
|
||||||
|
|
||||||
createSession: function() {
|
|
||||||
if (this._createSession)
|
|
||||||
this._createSession();
|
|
||||||
},
|
|
||||||
|
|
||||||
createUnlockDialog: function() {
|
|
||||||
if (this._createUnlockDialog)
|
|
||||||
return this._createUnlockDialog.apply(this, arguments);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -3,13 +3,9 @@
|
|||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
const Shell = imports.gi.Shell;
|
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
const Config = imports.misc.config;
|
||||||
const ExtensionSystem = imports.ui.extensionSystem;
|
const ExtensionSystem = imports.ui.extensionSystem;
|
||||||
const ExtensionDownloader = imports.ui.extensionDownloader;
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
|
||||||
const Flashspot = imports.ui.flashspot;
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
const GnomeShellIface = <interface name="org.gnome.Shell">
|
const GnomeShellIface = <interface name="org.gnome.Shell">
|
||||||
@@ -18,60 +14,68 @@ const GnomeShellIface = <interface name="org.gnome.Shell">
|
|||||||
<arg type="b" direction="out" name="success" />
|
<arg type="b" direction="out" name="success" />
|
||||||
<arg type="s" direction="out" name="result" />
|
<arg type="s" direction="out" name="result" />
|
||||||
</method>
|
</method>
|
||||||
|
<method name="ListExtensions">
|
||||||
|
<arg type="a{sa{sv}}" direction="out" name="extensions" />
|
||||||
|
</method>
|
||||||
|
<method name="GetExtensionInfo">
|
||||||
|
<arg type="s" direction="in" name="extension" />
|
||||||
|
<arg type="a{sv}" direction="out" name="info" />
|
||||||
|
</method>
|
||||||
|
<method name="GetExtensionErrors">
|
||||||
|
<arg type="s" direction="in" name="extension" />
|
||||||
|
<arg type="as" direction="out" name="errors" />
|
||||||
|
</method>
|
||||||
<method name="ScreenshotArea">
|
<method name="ScreenshotArea">
|
||||||
<arg type="i" direction="in" name="x"/>
|
<arg type="i" direction="in" name="x"/>
|
||||||
<arg type="i" direction="in" name="y"/>
|
<arg type="i" direction="in" name="y"/>
|
||||||
<arg type="i" direction="in" name="width"/>
|
<arg type="i" direction="in" name="width"/>
|
||||||
<arg type="i" direction="in" name="height"/>
|
<arg type="i" direction="in" name="height"/>
|
||||||
<arg type="b" direction="in" name="flash"/>
|
|
||||||
<arg type="s" direction="in" name="filename"/>
|
<arg type="s" direction="in" name="filename"/>
|
||||||
<arg type="b" direction="out" name="success"/>
|
<arg type="b" direction="out" name="success"/>
|
||||||
</method>
|
</method>
|
||||||
<method name="ScreenshotWindow">
|
<method name="ScreenshotWindow">
|
||||||
<arg type="b" direction="in" name="include_frame"/>
|
<arg type="b" direction="in" name="include_frame"/>
|
||||||
<arg type="b" direction="in" name="include_cursor"/>
|
|
||||||
<arg type="b" direction="in" name="flash"/>
|
|
||||||
<arg type="s" direction="in" name="filename"/>
|
<arg type="s" direction="in" name="filename"/>
|
||||||
<arg type="b" direction="out" name="success"/>
|
<arg type="b" direction="out" name="success"/>
|
||||||
</method>
|
</method>
|
||||||
<method name="Screenshot">
|
<method name="Screenshot">
|
||||||
<arg type="b" direction="in" name="include_cursor"/>
|
|
||||||
<arg type="b" direction="in" name="flash"/>
|
|
||||||
<arg type="s" direction="in" name="filename"/>
|
<arg type="s" direction="in" name="filename"/>
|
||||||
<arg type="b" direction="out" name="success"/>
|
<arg type="b" direction="out" name="success"/>
|
||||||
</method>
|
</method>
|
||||||
<method name="FlashArea">
|
<method name="EnableExtension">
|
||||||
<arg type="i" direction="in" name="x"/>
|
<arg type="s" direction="in" name="uuid"/>
|
||||||
<arg type="i" direction="in" name="y"/>
|
</method>
|
||||||
<arg type="i" direction="in" name="width"/>
|
<method name="DisableExtension">
|
||||||
<arg type="i" direction="in" name="height"/>
|
<arg type="s" direction="in" name="uuid"/>
|
||||||
|
</method>
|
||||||
|
<method name="InstallRemoteExtension">
|
||||||
|
<arg type="s" direction="in" name="uuid"/>
|
||||||
|
<arg type="s" direction="in" name="version"/>
|
||||||
|
</method>
|
||||||
|
<method name="UninstallExtension">
|
||||||
|
<arg type="s" direction="in" name="uuid"/>
|
||||||
|
<arg type="b" direction="out" name="success"/>
|
||||||
</method>
|
</method>
|
||||||
<property name="OverviewActive" type="b" access="readwrite" />
|
<property name="OverviewActive" type="b" access="readwrite" />
|
||||||
|
<property name="ApiVersion" type="i" access="read" />
|
||||||
<property name="ShellVersion" type="s" access="read" />
|
<property name="ShellVersion" type="s" access="read" />
|
||||||
</interface>;
|
<signal name="ExtensionStatusChanged">
|
||||||
|
<arg type="s" name="uuid"/>
|
||||||
const ScreenSaverIface = <interface name="org.gnome.ScreenSaver">
|
<arg type="i" name="state"/>
|
||||||
<method name="Lock">
|
<arg type="s" name="error"/>
|
||||||
</method>
|
|
||||||
<method name="GetActive">
|
|
||||||
<arg name="active" direction="out" type="b" />
|
|
||||||
</method>
|
|
||||||
<method name="SetActive">
|
|
||||||
<arg name="value" direction="in" type="u" />
|
|
||||||
</method>
|
|
||||||
<signal name="ActiveChanged">
|
|
||||||
<arg name="new_value" type="b" />
|
|
||||||
</signal>
|
</signal>
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
const GnomeShell = new Lang.Class({
|
function GnomeShell() {
|
||||||
Name: 'GnomeShellDBus',
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
GnomeShell.prototype = {
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellIface, this);
|
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellIface, this);
|
||||||
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
|
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
|
||||||
|
ExtensionSystem.connect('extension-state-changed',
|
||||||
this._extensionsSerivce = new GnomeShellExtensions();
|
Lang.bind(this, this._extensionStateChanged));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -107,23 +111,12 @@ const GnomeShell = new Lang.Class({
|
|||||||
return [success, returnValue];
|
return [success, returnValue];
|
||||||
},
|
},
|
||||||
|
|
||||||
_onScreenshotComplete: function(obj, result, area, flash, invocation) {
|
|
||||||
if (flash) {
|
|
||||||
let flashspot = new Flashspot.Flashspot(area);
|
|
||||||
flashspot.fire();
|
|
||||||
}
|
|
||||||
|
|
||||||
let retval = GLib.Variant.new('(b)', [result]);
|
|
||||||
invocation.return_value(retval);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ScreenshotArea:
|
* ScreenshotArea:
|
||||||
* @x: The X coordinate of the area
|
* @x: The X coordinate of the area
|
||||||
* @y: The Y coordinate of the area
|
* @y: The Y coordinate of the area
|
||||||
* @width: The width of the area
|
* @width: The width of the area
|
||||||
* @height: The height of the area
|
* @height: The height of the area
|
||||||
* @flash: Whether to flash the area or not
|
|
||||||
* @filename: The filename for the screenshot
|
* @filename: The filename for the screenshot
|
||||||
*
|
*
|
||||||
* Takes a screenshot of the passed in area and saves it
|
* Takes a screenshot of the passed in area and saves it
|
||||||
@@ -131,19 +124,13 @@ const GnomeShell = new Lang.Class({
|
|||||||
* indicating whether the operation was successful or not.
|
* indicating whether the operation was successful or not.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
ScreenshotAreaAsync : function (params, invocation) {
|
ScreenshotAreaAsync : function (x, y, width, height, filename, callback) {
|
||||||
let [x, y, width, height, flash, filename, callback] = params;
|
global.screenshot_area (x, y, width, height, filename, function (obj, result) { callback(result); });
|
||||||
let screenshot = new Shell.Screenshot();
|
|
||||||
screenshot.screenshot_area (x, y, width, height, filename,
|
|
||||||
Lang.bind(this, this._onScreenshotComplete,
|
|
||||||
flash, invocation));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ScreenshotWindow:
|
* ScreenshotWindow:
|
||||||
* @include_frame: Whether to include the frame or not
|
* @include_frame: Whether to include the frame or not
|
||||||
* @include_cursor: Whether to include the cursor image or not
|
|
||||||
* @flash: Whether to flash the window area or not
|
|
||||||
* @filename: The filename for the screenshot
|
* @filename: The filename for the screenshot
|
||||||
*
|
*
|
||||||
* Takes a screenshot of the focused window (optionally omitting the frame)
|
* Takes a screenshot of the focused window (optionally omitting the frame)
|
||||||
@@ -151,36 +138,77 @@ const GnomeShell = new Lang.Class({
|
|||||||
* indicating whether the operation was successful or not.
|
* indicating whether the operation was successful or not.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
ScreenshotWindowAsync : function (params, invocation) {
|
ScreenshotWindow : function (include_frame, filename) {
|
||||||
let [include_frame, include_cursor, flash, filename] = params;
|
return global.screenshot_window (include_frame, filename);
|
||||||
let screenshot = new Shell.Screenshot();
|
|
||||||
screenshot.screenshot_window (include_frame, include_cursor, filename,
|
|
||||||
Lang.bind(this, this._onScreenshotComplete,
|
|
||||||
flash, invocation));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Screenshot:
|
* Screenshot:
|
||||||
* @filename: The filename for the screenshot
|
* @filename: The filename for the screenshot
|
||||||
* @include_cursor: Whether to include the cursor image or not
|
|
||||||
* @flash: Whether to flash the screen or not
|
|
||||||
*
|
*
|
||||||
* Takes a screenshot of the whole screen and saves it
|
* Takes a screenshot of the whole screen and saves it
|
||||||
* in @filename as png image, it returns a boolean
|
* in @filename as png image, it returns a boolean
|
||||||
* indicating whether the operation was successful or not.
|
* indicating whether the operation was successful or not.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
ScreenshotAsync : function (params, invocation) {
|
ScreenshotAsync : function (filename, callback) {
|
||||||
let [include_cursor, flash, filename] = params;
|
global.screenshot(filename, function (obj, result) { callback(result); });
|
||||||
let screenshot = new Shell.Screenshot();
|
|
||||||
screenshot.screenshot(include_cursor, filename,
|
|
||||||
Lang.bind(this, this._onScreenshotComplete,
|
|
||||||
flash, invocation));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
FlashArea: function(x, y, width, height) {
|
ListExtensions: function() {
|
||||||
let flashspot = new Flashspot.Flashspot({ x : x, y : y, width: width, height: height});
|
let out;
|
||||||
flashspot.fire();
|
for (let uuid in ExtensionSystem.extensionMeta) {
|
||||||
|
let dbusObj = this.GetExtensionInfo(uuid);
|
||||||
|
out[uuid] = dbusObj;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
},
|
||||||
|
|
||||||
|
GetExtensionInfo: function(uuid) {
|
||||||
|
let meta = ExtensionSystem.extensionMeta[uuid] || {};
|
||||||
|
let out;
|
||||||
|
for (let key in meta) {
|
||||||
|
let val = meta[key];
|
||||||
|
let type;
|
||||||
|
switch (typeof val) {
|
||||||
|
case 'object':
|
||||||
|
throw Error('Extension had a nested object in the metadata. This is not supported');
|
||||||
|
case 'string':
|
||||||
|
type = 's';
|
||||||
|
break;
|
||||||
|
case 'number':
|
||||||
|
type = 'd';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out[key] = GLib.Variant.new(type, val);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
},
|
||||||
|
|
||||||
|
GetExtensionErrors: function(uuid) {
|
||||||
|
return ExtensionSystem.errors[uuid] || [];
|
||||||
|
},
|
||||||
|
|
||||||
|
EnableExtension: function(uuid) {
|
||||||
|
let enabledExtensions = global.settings.get_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY);
|
||||||
|
if (enabledExtensions.indexOf(uuid) == -1)
|
||||||
|
enabledExtensions.push(uuid);
|
||||||
|
global.settings.set_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY, enabledExtensions);
|
||||||
|
},
|
||||||
|
|
||||||
|
DisableExtension: function(uuid) {
|
||||||
|
let enabledExtensions = global.settings.get_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY);
|
||||||
|
while (enabledExtensions.indexOf(uuid) != -1)
|
||||||
|
enabledExtensions.splice(enabledExtensions.indexOf(uuid), 1);
|
||||||
|
global.settings.set_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY, enabledExtensions);
|
||||||
|
},
|
||||||
|
|
||||||
|
InstallRemoteExtension: function(uuid, version_tag) {
|
||||||
|
ExtensionSystem.installExtensionFromUUID(uuid, version_tag);
|
||||||
|
},
|
||||||
|
|
||||||
|
UninstallExtension: function(uuid) {
|
||||||
|
return ExtensionSystem.uninstallExtensionFromUUID(uuid);
|
||||||
},
|
},
|
||||||
|
|
||||||
get OverviewActive() {
|
get OverviewActive() {
|
||||||
@@ -194,137 +222,7 @@ const GnomeShell = new Lang.Class({
|
|||||||
Main.overview.hide();
|
Main.overview.hide();
|
||||||
},
|
},
|
||||||
|
|
||||||
ShellVersion: Config.PACKAGE_VERSION
|
ApiVersion: ExtensionSystem.API_VERSION,
|
||||||
});
|
|
||||||
|
|
||||||
const GnomeShellExtensionsIface = <interface name="org.gnome.Shell.Extensions">
|
|
||||||
<method name="ListExtensions">
|
|
||||||
<arg type="a{sa{sv}}" direction="out" name="extensions" />
|
|
||||||
</method>
|
|
||||||
<method name="GetExtensionInfo">
|
|
||||||
<arg type="s" direction="in" name="extension" />
|
|
||||||
<arg type="a{sv}" direction="out" name="info" />
|
|
||||||
</method>
|
|
||||||
<method name="GetExtensionErrors">
|
|
||||||
<arg type="s" direction="in" name="extension" />
|
|
||||||
<arg type="as" direction="out" name="errors" />
|
|
||||||
</method>
|
|
||||||
<signal name="ExtensionStatusChanged">
|
|
||||||
<arg type="s" name="uuid"/>
|
|
||||||
<arg type="i" name="state"/>
|
|
||||||
<arg type="s" name="error"/>
|
|
||||||
</signal>
|
|
||||||
<method name="InstallRemoteExtension">
|
|
||||||
<arg type="s" direction="in" name="uuid"/>
|
|
||||||
<arg type="s" direction="out" name="result"/>
|
|
||||||
</method>
|
|
||||||
<method name="UninstallExtension">
|
|
||||||
<arg type="s" direction="in" name="uuid"/>
|
|
||||||
<arg type="b" direction="out" name="success"/>
|
|
||||||
</method>
|
|
||||||
<method name="LaunchExtensionPrefs">
|
|
||||||
<arg type="s" direction="in" name="uuid"/>
|
|
||||||
</method>
|
|
||||||
<method name="ReloadExtension">
|
|
||||||
<arg type="s" direction="in" name="uuid"/>
|
|
||||||
</method>
|
|
||||||
<method name="CheckForUpdates">
|
|
||||||
</method>
|
|
||||||
<property name="ShellVersion" type="s" access="read" />
|
|
||||||
</interface>;
|
|
||||||
|
|
||||||
const GnomeShellExtensions = new Lang.Class({
|
|
||||||
Name: 'GnomeShellExtensionsDBus',
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellExtensionsIface, this);
|
|
||||||
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
|
|
||||||
ExtensionSystem.connect('extension-state-changed',
|
|
||||||
Lang.bind(this, this._extensionStateChanged));
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
ListExtensions: function() {
|
|
||||||
let out = {};
|
|
||||||
for (let uuid in ExtensionUtils.extensions) {
|
|
||||||
let dbusObj = this.GetExtensionInfo(uuid);
|
|
||||||
out[uuid] = dbusObj;
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
},
|
|
||||||
|
|
||||||
GetExtensionInfo: function(uuid) {
|
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
|
||||||
if (!extension)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
let obj = {};
|
|
||||||
Lang.copyProperties(extension.metadata, obj);
|
|
||||||
|
|
||||||
// Only serialize the properties that we actually need.
|
|
||||||
const serializedProperties = ["type", "state", "path", "error", "hasPrefs"];
|
|
||||||
|
|
||||||
serializedProperties.forEach(function(prop) {
|
|
||||||
obj[prop] = extension[prop];
|
|
||||||
});
|
|
||||||
|
|
||||||
let out = {};
|
|
||||||
for (let key in obj) {
|
|
||||||
let val = obj[key];
|
|
||||||
let type;
|
|
||||||
switch (typeof val) {
|
|
||||||
case 'string':
|
|
||||||
type = 's';
|
|
||||||
break;
|
|
||||||
case 'number':
|
|
||||||
type = 'd';
|
|
||||||
break;
|
|
||||||
case 'boolean':
|
|
||||||
type = 'b';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
out[key] = GLib.Variant.new(type, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
},
|
|
||||||
|
|
||||||
GetExtensionErrors: function(uuid) {
|
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
|
||||||
if (!extension)
|
|
||||||
return [];
|
|
||||||
|
|
||||||
if (!extension.errors)
|
|
||||||
return [];
|
|
||||||
|
|
||||||
return extension.errors;
|
|
||||||
},
|
|
||||||
|
|
||||||
InstallRemoteExtensionAsync: function([uuid], invocation) {
|
|
||||||
return ExtensionDownloader.installExtension(uuid, invocation);
|
|
||||||
},
|
|
||||||
|
|
||||||
UninstallExtension: function(uuid) {
|
|
||||||
return ExtensionDownloader.uninstallExtension(uuid);
|
|
||||||
},
|
|
||||||
|
|
||||||
LaunchExtensionPrefs: function(uuid) {
|
|
||||||
let appSys = Shell.AppSystem.get_default();
|
|
||||||
let app = appSys.lookup_app('gnome-shell-extension-prefs.desktop');
|
|
||||||
app.launch(global.display.get_current_time_roundtrip(),
|
|
||||||
['extension:///' + uuid], -1, null);
|
|
||||||
},
|
|
||||||
|
|
||||||
ReloadExtension: function(uuid) {
|
|
||||||
ExtensionSystem.unloadExtension(uuid);
|
|
||||||
ExtensionSystem.loadExtension(uuid);
|
|
||||||
},
|
|
||||||
|
|
||||||
CheckForUpdates: function() {
|
|
||||||
ExtensionDownloader.checkForUpdates();
|
|
||||||
},
|
|
||||||
|
|
||||||
ShellVersion: Config.PACKAGE_VERSION,
|
ShellVersion: Config.PACKAGE_VERSION,
|
||||||
|
|
||||||
@@ -332,34 +230,4 @@ const GnomeShellExtensions = new Lang.Class({
|
|||||||
this._dbusImpl.emit_signal('ExtensionStatusChanged',
|
this._dbusImpl.emit_signal('ExtensionStatusChanged',
|
||||||
GLib.Variant.new('(sis)', [newState.uuid, newState.state, newState.error]));
|
GLib.Variant.new('(sis)', [newState.uuid, newState.state, newState.error]));
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const ScreenSaverDBus = new Lang.Class({
|
|
||||||
Name: 'ScreenSaverDBus',
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this.parent();
|
|
||||||
|
|
||||||
Main.screenShield.connect('lock-status-changed', Lang.bind(this, function(shield, locked) {
|
|
||||||
this._dbusImpl.emit_signal('ActiveChanged', GLib.Variant.new('(b)', [locked]));
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreenSaverIface, this);
|
|
||||||
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/ScreenSaver');
|
|
||||||
},
|
|
||||||
|
|
||||||
Lock: function() {
|
|
||||||
Main.screenShield.lock(true);
|
|
||||||
},
|
|
||||||
|
|
||||||
SetActive: function(active) {
|
|
||||||
if (active)
|
|
||||||
Main.screenShield.lock(true);
|
|
||||||
else
|
|
||||||
Main.screenShield.unlock();
|
|
||||||
},
|
|
||||||
|
|
||||||
GetActive: function() {
|
|
||||||
return Main.screenShield.locked;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -7,14 +7,18 @@ const Main = imports.ui.main;
|
|||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
|
|
||||||
const EntryMenu = new Lang.Class({
|
|
||||||
Name: 'ShellEntryMenu',
|
function _EntryMenu(entry, params) {
|
||||||
Extends: PopupMenu.PopupMenu,
|
this._init(entry, params);
|
||||||
|
};
|
||||||
|
|
||||||
|
_EntryMenu.prototype = {
|
||||||
|
__proto__: PopupMenu.PopupMenu.prototype,
|
||||||
|
|
||||||
_init: function(entry, params) {
|
_init: function(entry, params) {
|
||||||
params = Params.parse (params, { isPassword: false });
|
params = Params.parse (params, { isPassword: false });
|
||||||
|
|
||||||
this.parent(entry, 0, St.Side.TOP);
|
PopupMenu.PopupMenu.prototype._init.call(this, entry, 0, St.Side.TOP);
|
||||||
|
|
||||||
this.actor.add_style_class_name('entry-context-menu');
|
this.actor.add_style_class_name('entry-context-menu');
|
||||||
|
|
||||||
@@ -34,35 +38,16 @@ const EntryMenu = new Lang.Class({
|
|||||||
this._pasteItem = item;
|
this._pasteItem = item;
|
||||||
|
|
||||||
this._passwordItem = null;
|
this._passwordItem = null;
|
||||||
if (params.isPassword)
|
if (params.isPassword) {
|
||||||
this._makePasswordItem();
|
item = new PopupMenu.PopupMenuItem('');
|
||||||
|
|
||||||
Main.uiGroup.add_actor(this.actor);
|
|
||||||
this.actor.hide();
|
|
||||||
},
|
|
||||||
|
|
||||||
_makePasswordItem: function() {
|
|
||||||
let item = new PopupMenu.PopupMenuItem('');
|
|
||||||
item.connect('activate', Lang.bind(this,
|
item.connect('activate', Lang.bind(this,
|
||||||
this._onPasswordActivated));
|
this._onPasswordActivated));
|
||||||
this.addMenuItem(item);
|
this.addMenuItem(item);
|
||||||
this._passwordItem = item;
|
this._passwordItem = item;
|
||||||
},
|
|
||||||
|
|
||||||
get isPassword() {
|
|
||||||
return this._passwordItem != null;
|
|
||||||
},
|
|
||||||
|
|
||||||
set isPassword(v) {
|
|
||||||
if (v == this.isPassword)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (v)
|
|
||||||
this._makePasswordItem();
|
|
||||||
else {
|
|
||||||
this._passwordItem.destroy();
|
|
||||||
this._passwordItem = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Main.uiGroup.add_actor(this.actor);
|
||||||
|
this.actor.hide();
|
||||||
},
|
},
|
||||||
|
|
||||||
open: function() {
|
open: function() {
|
||||||
@@ -75,7 +60,7 @@ const EntryMenu = new Lang.Class({
|
|||||||
if (!this.actor.navigate_focus(null, direction, false))
|
if (!this.actor.navigate_focus(null, direction, false))
|
||||||
this.actor.grab_key_focus();
|
this.actor.grab_key_focus();
|
||||||
|
|
||||||
this.parent();
|
PopupMenu.PopupMenu.prototype.open.call(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateCopyItem: function() {
|
_updateCopyItem: function() {
|
||||||
@@ -118,55 +103,56 @@ const EntryMenu = new Lang.Class({
|
|||||||
let visible = !!(this._entry.clutter_text.password_char);
|
let visible = !!(this._entry.clutter_text.password_char);
|
||||||
this._entry.clutter_text.set_password_char(visible ? '' : '\u25cf');
|
this._entry.clutter_text.set_password_char(visible ? '' : '\u25cf');
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
|
||||||
function _setMenuAlignment(entry, stageX) {
|
function _setMenuAlignment(entry, stageX) {
|
||||||
let [success, entryX, entryY] = entry.transform_stage_point(stageX, 0);
|
let [success, entryX, entryY] = entry.transform_stage_point(stageX, 0);
|
||||||
if (success)
|
if (success)
|
||||||
entry.menu.setSourceAlignment(entryX / entry.width);
|
entry._menu.setSourceAlignment(entryX / entry.width);
|
||||||
};
|
};
|
||||||
|
|
||||||
function _onClicked(action, actor) {
|
function _onClicked(action, actor) {
|
||||||
let entry = actor.menu ? actor : actor.get_parent();
|
let entry = actor._menu ? actor : actor.get_parent();
|
||||||
|
|
||||||
if (entry.menu.isOpen) {
|
if (entry._menu.isOpen) {
|
||||||
entry.menu.close();
|
entry._menu.close();
|
||||||
} else if (action.get_button() == 3) {
|
} else if (action.get_button() == 3) {
|
||||||
let [stageX, stageY] = action.get_coords();
|
let [stageX, stageY] = action.get_coords();
|
||||||
_setMenuAlignment(entry, stageX);
|
_setMenuAlignment(entry, stageX);
|
||||||
entry.menu.open();
|
entry._menu.open();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function _onLongPress(action, actor, state) {
|
function _onLongPress(action, actor, state) {
|
||||||
let entry = actor.menu ? actor : actor.get_parent();
|
let entry = actor._menu ? actor : actor.get_parent();
|
||||||
|
|
||||||
if (state == Clutter.LongPressState.QUERY)
|
if (state == Clutter.LongPressState.QUERY)
|
||||||
return action.get_button() == 1 && !entry.menu.isOpen;
|
return action.get_button() == 1 && !entry._menu.isOpen;
|
||||||
|
|
||||||
if (state == Clutter.LongPressState.ACTIVATE) {
|
if (state == Clutter.LongPressState.ACTIVATE) {
|
||||||
let [stageX, stageY] = action.get_coords();
|
let [stageX, stageY] = action.get_coords();
|
||||||
_setMenuAlignment(entry, stageX);
|
_setMenuAlignment(entry, stageX);
|
||||||
entry.menu.open();
|
entry._menu.open();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
function _onPopup(actor) {
|
function _onPopup(actor) {
|
||||||
let entry = actor.menu ? actor : actor.get_parent();
|
let entry = actor._menu ? actor : actor.get_parent();
|
||||||
let [success, textX, textY, lineHeight] = entry.clutter_text.position_to_coords(-1);
|
let [success, textX, textY, lineHeight] = entry.clutter_text.position_to_coords(-1);
|
||||||
if (success)
|
if (success)
|
||||||
entry.menu.setSourceAlignment(textX / entry.width);
|
entry._menu.setSourceAlignment(textX / entry.width);
|
||||||
entry.menu.open();
|
entry._menu.open();
|
||||||
};
|
};
|
||||||
|
|
||||||
function addContextMenu(entry, params) {
|
function addContextMenu(entry, params) {
|
||||||
if (entry.menu)
|
if (entry._menu)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
entry.menu = new EntryMenu(entry, params);
|
entry._menu = new _EntryMenu(entry, params);
|
||||||
entry._menuManager = new PopupMenu.PopupMenuManager({ actor: entry });
|
entry._menuManager = new PopupMenu.PopupMenuManager({ actor: entry });
|
||||||
entry._menuManager.addMenu(entry.menu);
|
entry._menuManager.addMenu(entry._menu);
|
||||||
|
|
||||||
let clickAction;
|
let clickAction;
|
||||||
|
|
||||||
|
|||||||