Compare commits

..

51 Commits
3.4.2 ... 3.2.2

Author SHA1 Message Date
f8c980cb22 Bump version to 3.2.2
Update NEWS
2012-01-18 10:22:09 -05:00
74ed3646ad workspaceThumbnail: fix window tracking bugs
- We should only call workspaceRemoved() for workspaces that are
  are actually being removed.
- When we have multiple monitors, a window on a secondary monitor is
  on all workspaces, so it ends up in all workspaces _allWindows
  lists, so we can't use previous presence in that list to determine
  whether we need to go ahead and add the actor; allWindows is simply
  the list of windows where we are listening  to notify::minimized.

https://bugzilla.gnome.org/show_bug.cgi?id=667652
2012-01-18 10:22:09 -05:00
80dfda17cd messageTray: use a "hot corner" to summon the tray
Instead of leaving the tray covering the whole last pixel row when it's
hidden, hide it completely. This avoids mouse events not being delivered to
application windows on the last pixel row.

To summon the tray we use a single reactive pixel on the corner.

https://bugzilla.gnome.org/show_bug.cgi?id=663366
2012-01-17 13:38:40 -05:00
3e98d47687 st: Fix typo
Commit c7846e1 introduced a small typo, fix.
2012-01-17 11:04:19 -05:00
3d3494a15b st-icon: Fix memory leak
We were never freeing the dup'd icon_name string for an StIcon.
2012-01-17 11:04:09 -05:00
3bf11dbd31 st-theme-node: Fix memory leak
We ref the icon_colors in st_theme_node_get_icon_colors, but never
unref it.
2012-01-17 11:03:59 -05:00
626e962e03 Network Menu: fix pulling out the first element from the More... submenu.
PopupMenu.firstMenuItem returns a PopupMenuItem, not an apObj. We
need to retrive the latter using the _apObj property.

Also, somehow the property from the number of elements in a menu
was changed from .length to .numMenuItems, and this broke the
destruction of the menu upon emptying it.

https://bugzilla.gnome.org/show_bug.cgi?id=659277
2012-01-17 11:00:56 -05:00
759de873b5 NetworkMenu: fix regression in access-point-removed
When changing _findNetwork with _findExistingNetwork, I changed
the return value to avoid searching twice for the access point,
and changed some names. I forgot to update all points where those
names were used.

https://bugzilla.gnome.org/show_bug.cgi?id=663278
2012-01-17 11:00:43 -05:00
552ae78557 NetworkMenu: don't query DBus properties of removed objects
Calling nm_access_point_get_ssid() in the handler of the
access-point-removed signal can result in DBus request, which will
then fail because the object was already removed at the server side.
Instead, use a difference function to retrieve the access point
object (the network), that compares directly by object identity.

https://bugzilla.gnome.org/show_bug.cgi?id=651378
2012-01-17 11:00:32 -05:00
d85a16589b messageTray: don't steal focus when popping under the pointer
We must look for the actor under the pointer in the whole message tray and not
just in the notification. This will avoid us to capture focus when a
notification comes up with the pointer on the whole tray area.

https://bugzilla.gnome.org/show_bug.cgi?id=661358
2012-01-17 11:00:04 -05:00
136c76dcbe gnome-shell-extension-tool: Use xdg-open
gnome-open is deprecated
2012-01-17 10:57:12 -05:00
2d95201af2 gnome-shell-extension-tool: Fix error after creating extension
Commit 7a8a00c705 cleaned up the code to move all
files to a dictionary, which accidentally left an undefined "extensionjs_path"
error. Fix that error.

https://bugzilla.gnome.org/show_bug.cgi?id=661623
2012-01-17 10:57:07 -05:00
039c683bac workspaceThumbnail: improve handling of notify::minimized signal
There were various cases where we could lose track of a window and
leave the notify::minimized signal connect after the actor was destroyed
or the workspace removed. This could result in operations on a removed
workspace and assertion failures inside Mutter.

https://bugzilla.redhat.com/show_bug.cgi?id=773059
https://bugzilla.gnome.org/show_bug.cgi?id=667652
2012-01-17 10:56:09 -05:00
d9ab2320d5 workspaceThumbnail: disconnect handlers when workspace is removed
We need to remove the handlers when the workspace is removed, not
when the animation of it being removed finishes, or we can access
a destroyed workspace and triggger an assertion failure in Mutter.

https://bugzilla.redhat.com/show_bug.cgi?id=705664
https://bugzilla.gnome.org/show_bug.cgi?id=667652
2012-01-17 10:55:58 -05:00
fa515328eb hotplug-sniffer: fix double free when setting D-Bus return value
g_dbus_method_invocation_return_value() adopts a floating reference,
so we don't also need to unreference it; fix by replacing the code
using a more compact form using the ^ convenience character in
GVariant type specifications. (Thanks to Ryan Lortie for the
suggestion.)

https://bugzilla.gnome.org/show_bug.cgi?id=667378
2012-01-17 10:55:21 -05:00
0cfedcaad6 theme-node-drawing: don't crash if st_theme_node_paint() is called on an empty area
When st_theme_node_paint() was called with zero width or height and a theme
node with a shadow, we'd crash because we'd fail to allocate a texture with
an empty size, then unreference the NULL pointer.

https://bugzilla.redhat.com/show_bug.cgi?id=748293
https://bugzilla.gnome.org/show_bug.cgi?id=668050
2012-01-16 17:38:02 -05:00
65230bfd7f st-theme-node-drawing: clear border buffer before drawing on it
A new texture has undefined contents - when we're creating a shadow,
we need to clear the contents of the texture before drawing the border
and background into it.

https://bugzilla.gnome.org/show_bug.cgi?id=668048
2012-01-16 17:37:51 -05:00
a5324462c3 iconGrid: avoid recreating icons unnecessarily
Add a short-circuit when the size doesn't change. Taken from part
of 26580f8f2c (Giovanni Campagna). This greatly reduces the reentrancy
of recreating icons that seems to be responsible for many crashers,
though the exact mechanism for the crashes isn't clear. See:

https://bugzilla.gnome.org/show_bug.cgi?id=648450
https://bugzilla.redhat.com/show_bug.cgi?id=707652
https://bugzilla.redhat.com/show_bug.cgi?id=781780
2012-01-16 17:28:40 -05:00
7e654ab3ca notificationDaemon: group sources based on a combination of pid and title
That way different system notifications, such as the ones about battery power
and the ones about software updates, are shown with separate message tray
sources.

https://bugzilla.gnome.org/show_bug.cgi?id=664138
2012-01-05 08:46:05 -05:00
9601908fca browser-plugin: Fix installation on WebKit-like browsers
I missed this use of raw UTF8Characters last time. Hopefully this
should be the last fix required for WebKit support.

https://bugzilla.gnome.org/show_bug.cgi?id=666444
2012-01-04 18:06:51 -05:00
ab4c160f9d browser-plugin: Fix memory leak when passing an invalid UUID
https://bugzilla.gnome.org/show_bug.cgi?id=665261
2012-01-04 18:06:51 -05:00
234882cbc6 browser-plugin: Fix crash if shell is not running 2012-01-04 18:06:51 -05:00
e890674e49 browser-plugin: Make sure to use the UTF8Length parameter
Some plugin hosts may have junk after the UTF8Characters that we need to strip
off. No current browsers that I know of do this, but it still helps to be
correct.
2012-01-04 18:06:51 -05:00
cd01e2fb25 browser-plugin: Move "entry points" comment
https://bugzilla.gnome.org/show_bug.cgi?id=663823
2012-01-04 18:06:51 -05:00
62027beb8e browser-plugin: Use g_strndup to get a string property
WebKit-based browsers like Chromium and Epiphany may insert extra junk at the
end of NPStrings, so we cannot depend on the strlen matching.

https://bugzilla.gnome.org/show_bug.cgi?id=663823
2012-01-04 18:06:51 -05:00
ee4d861a29 browser-plugin: Set that we need XEmbed
This makes the plugin work under WebKit-based browsers such as Chromium and
Epiphany. See http://code.google.com/p/chromium/issues/detail?id=38229 and
WindowedCreatePlugin() in
http://src.chromium.org/viewvc/chrome/trunk/src/webkit/plugins/npapi/webplugin_delegate_impl_gtk.cc?revision=86823&content-type=text%2Fplain
for more information.

https://bugzilla.gnome.org/show_bug.cgi?id=663823
2012-01-04 18:06:51 -05:00
3a3e26c1bd fileUtils: Fix recursivelyDeleteDir 2012-01-04 17:57:08 -05:00
bf2ad9d4e8 app: Fix crash on search
Not all desktop files tracked by the shell have
Exec lines.  This could be because they're actually
run by another process, for instance, and the desktop
file is merely there to provide metadata.  For example,
nautilus-pastebin provides a desktop file without an
Exec line.

The shell currently crashes if one of these partial
desktop files is installed and the user attempts to
search from the overview.

commit 37726a4cb6 fixed
a similar crasher.

This commit fixes the next one lower in the code.

https://bugzilla.gnome.org/show_bug.cgi?id=663815
2012-01-04 17:42:53 -05:00
b053d9c84f Updated Danish translation 2012-01-03 12:21:00 +01:00
4afa8bebdb Updated Norwegian Nynorsk translation 2011-12-26 14:33:01 +01:00
caf3d5add0 Updated Lithuanian translation 2011-12-06 17:10:37 +02:00
7cf038474a Updated Finnish translation 2011-11-15 22:20:36 +02:00
c7bcc8150c Updated British English translation 2011-11-12 07:48:52 +00:00
6d58397508 Updated Japanese translation 2011-11-09 21:23:48 +09:00
49d0fc178d Updated Czech translation 2011-10-30 14:31:52 +01:00
b83b8f64ff Updated French translation 2011-10-29 19:03:56 +02:00
6cc8a42720 Updated Esperanto translation 2011-10-26 19:05:10 +02:00
50a2d285eb Updated Swedish translation 2011-10-26 11:55:01 +02:00
fdf05310e9 Updated Persian translation 2011-10-24 21:13:22 +03:30
7baa393b1b [l10n]Updated Catalan (Valencian) translation 2011-10-23 23:43:01 +02:00
113694c44b [l10n]Updated Catalan translation 2011-10-23 23:42:57 +02:00
0c2f51b27f Updated Swedish translation 2011-10-23 13:07:22 +02:00
04cb84de2a Updated Lithuanian translation 2011-10-22 23:00:54 +03:00
9475c16e80 Updated Slovenian translation 2011-10-22 13:20:39 +02:00
6f41a9e10c Updated Bulgarian translation 2011-10-21 23:31:28 +03:00
be3b939a24 Updated Slovenian translation 2011-10-21 21:32:39 +02:00
04fb3a5a7c Updated Brazilian Portuguese translation 2011-10-20 12:46:59 -02:00
697b6dbfff Updated Brazilian Portuguese translation 2011-10-20 12:39:00 -02:00
bb4639e423 Updated Telugu Translation 2011-10-20 16:41:52 +05:30
69db63b4cd Updated Vietnamese translation 2011-10-19 19:39:27 +11:00
f9d17b214e po/vi: import from Damned Lies 2011-10-19 19:38:35 +11:00
307 changed files with 35139 additions and 56037 deletions

16
.gitignore vendored
View File

@ -18,24 +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
docs/reference/*/*.args
docs/reference/*/*.bak
docs/reference/*/*.hierarchy
docs/reference/*/*.interfaces
docs/reference/*/*.prerequisites
docs/reference/*/*.sgml
docs/reference/*/*.signals
docs/reference/*/*.stamp
docs/reference/*/*.txt
docs/reference/*/*.types
docs/reference/*/html/
docs/reference/*/xml/
gtk-doc.make
js/misc/config.js js/misc/config.js
intltool-extract.in intltool-extract.in
intltool-merge.in intltool-merge.in
@ -64,7 +49,6 @@ 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

View File

@ -1,7 +1,7 @@
# Point to our macro directory and pick up user flags from the environment # Point to our macro directory and pick up user flags from the environment
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
SUBDIRS = data js src browser-plugin tests po man docs SUBDIRS = data js src browser-plugin tests po man
EXTRA_DIST = \ EXTRA_DIST = \
.project \ .project \
@ -19,5 +19,3 @@ DIST_EXCLUDE = \
distcheck-hook: distcheck-hook:
@echo "Checking disted files against files in git" @echo "Checking disted files against files in git"
@$(srcdir)/tools/check-for-missing.py $(srcdir) $(distdir) $(DIST_EXCLUDE) @$(srcdir)/tools/check-for-missing.py $(srcdir) $(distdir) $(DIST_EXCLUDE)
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc

422
NEWS
View File

@ -1,394 +1,46 @@
3.4.2 3.2.2
===== =====
* Mirror Evolution calendar settings into our own schema [Owen; #674424] * Fix crash when searching in the shell caused by .desktop files
* gdm: don't fail if fprintd unavailable [Ray; #675006] without Exec= lines (commonly, nautilus-pastebin) [Ray; #663815]
* Fix broken extension loading [Owen, Alexandre; #670477] * Message Tray:
* Fix filtering of Empathy notifications [Guillaume; #675370] - Fix bug that would cause confusion between notifications from different
* telepathyClient: Ignore invalidated channels [Guillaume; #677457] services running in the gnome-settings-daemon process
* popupMenu: Fix freeze when appMenu is not populated in one go [Alban; #676447] [Marina, Jasper; #664138]
* mount-operation: fix exceptions when showing password entry [Cosimo; #678428] - Don't steal the focus when popping up beneath the pointer [Rui; #661358]
* Misc. fixes [Guillaume, Jasper, Rico; #677441, #676175] - Only pop up the message tray from a hot corner, rather than trapping
clicks on the entire bottom row. [Rui; #663366]
Contributors: * Browser plugin and extension.gnome.org integration
Alban Browaeys, Cosimo Cecchi, Guillaume Desmottes, Alexandre Rostovtsev, - Fix multiple bugs that kept the plugin from working in WebKit-based browsers
Jasper St. Pierre, Ray Strode, Owen Taylor, Rico Tzschichholz [Jasper, #663823, #666444]
- Fix plugin crash when the shell is installed but not running [Jürg]
Translations: - Fix problem that kept plugin uninstallation from working [Jasper]
OKANO Takayoshi [ja], Changwoo Ryu [ko], Jonh Wendell [pt_BR], * gnome-shell-extension-tool
Luca Ferretti [it], Sandeep Sheshrao Shedmake [mr], Takanori MATSUURA [ja], - Fix error that was printed after creating an extension [Jasper; #661623]
Andika Triwidada [id], Mantas Kriaučiūnas [lt], Nilamdyuti Goswami [as] - Use xdg-open rather than the deprecated gnome-open [Jasper]
* Don't recreate dash icons unnecessarily - this hopefully fixes various
3.4.1 crashes. [Owen, Giovanni; #648450]
===== * Fix several bugs that caused errors and slowdowns when updating the
* Fix crash that occurred when an icon theme change caused unexpected network menu. [Giovanni; #651378, #659277, #663278]
reentrancy in the icon loading code [Jasper; #673512] * Fix several crashers related to updating workspace thumbnails
* Don't show system and other disabled users in the GDM user list [Owen; #667652]
[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 * Fix memory management error causing gnome-shell-hotplug-sniffer to crash
[Owen; #667378] [Owen; #667378]
* Build fixes [Emmanuele, Rico; #667864] * Fix crash and misdrawing with shadowed elements [Owen; #668048, #668050]
* Code cleanups [Adel; #668087] * Fix several small memory leaks. [Jasper, Florian]
* Misc bug fixes [Colin, Florian, Giovanni, Owen, Xavier; #633028, #658817,
#664138, #667881, #668048, #668050]
Contributors: Contributors:
Emmanuele Bassi, Giovanni Campagna, Cosimo Cecchi, Xavier Claessens, Jürg Billeter, Rui Matos, Florian Müllner, Jasper St. Pierre, Ray Strode,
Guillaume Desmottes, Stefano Facchini, Adel Gadllah, Alex Hultman, Owen Taylor, Marina Zhurakhinskaya
Ryan Lortie, Seif Lotfy, Florian Müllner, Vit Stanislav, Owen Taylor,
Rico Tzschichholz, Colin Walters
Translations: Translations:
Ihar Hrachyshka [be], Alexander Shopov [bg], Arash Mousavi [fa], Alexander Shopov [bg], Gil Forcada [ca], Carles Ferrando [ca@valencia],
Jiri Grönroos, Timo Jyrinki [fi], Fran Diéguez [gl], Kjartan Maraas [nb], Marek Černocký [cz], Kris Thomsen [dk], Bruce Cowan [en_GB],
Yuri Myasoedov [ru], Matej Urbančič [sl], Nguyễn Thái Ngọc Duy [vi] Kristjan Schmidt [eo], Daniel Mustieles [es], Arash Mousavi [fa],
Ville-Pekka Vainio [fi], Bruno Brouard [fr], Hideki Yamane [ja],
3.3.3 Žygimantas Beručka, Aurimas Černius [lt], Kjartan Maraas [nb],
===== "Andreas N" [nn], Djavan Fagundes, Antonio Fernandes C. Neto [pt_BR],
* https://live.gnome.org/EveryDetailMatters Daniel Nylander [se], Matej Urbančič [sl], Praveen Illa [te],
- Stop flashing the window labels on actions in overview [Zan; #644861] Nguyễn Thái Ngọc Duy [vi]
- 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
===== =====
@ -483,7 +135,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],

View File

@ -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 3 #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));
@ -268,9 +266,7 @@ typedef struct {
NPP instance; NPP instance;
GDBusProxy *proxy; GDBusProxy *proxy;
NPObject *listener; NPObject *listener;
NPObject *restart_listener;
gint signal_id; gint signal_id;
guint watch_name_id;
} PluginObject; } PluginObject;
static void static void
@ -288,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]);
@ -304,25 +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);
}
}
static NPObject * static NPObject *
plugin_object_allocate (NPP instance, plugin_object_allocate (NPP instance,
NPClass *klass) NPClass *klass)
@ -335,14 +312,6 @@ plugin_object_allocate (NPP instance,
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;
@ -359,9 +328,6 @@ 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);
@ -375,9 +341,7 @@ static NPIdentifier enable_extension_id;
static NPIdentifier install_extension_id; static NPIdentifier install_extension_id;
static NPIdentifier uninstall_extension_id; static NPIdentifier uninstall_extension_id;
static NPIdentifier onextension_changed_id; static NPIdentifier onextension_changed_id;
static NPIdentifier onrestart_id;
static NPIdentifier get_errors_id; static NPIdentifier get_errors_id;
static NPIdentifier launch_extension_prefs_id;
static bool static bool
plugin_object_has_method (NPObject *npobj, plugin_object_has_method (NPObject *npobj,
@ -388,8 +352,7 @@ plugin_object_has_method (NPObject *npobj,
name == enable_extension_id || name == enable_extension_id ||
name == install_extension_id || name == install_extension_id ||
name == uninstall_extension_id || name == uninstall_extension_id ||
name == get_errors_id || name == get_errors_id);
name == launch_extension_prefs_id);
} }
static inline gboolean static inline gboolean
@ -494,10 +457,7 @@ plugin_enable_extension (PluginObject *obj,
{ {
gchar *uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length); gchar *uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
if (!uuid_is_valid (uuid_str)) if (!uuid_is_valid (uuid_str))
{
g_free (uuid_str);
return FALSE; return FALSE;
}
g_dbus_proxy_call (obj->proxy, g_dbus_proxy_call (obj->proxy,
(enabled ? "EnableExtension" : "DisableExtension"), (enabled ? "EnableExtension" : "DisableExtension"),
@ -656,33 +616,6 @@ plugin_get_errors (PluginObject *obj,
return jsonify_variant (res, result); return jsonify_variant (res, result);
} }
static gboolean
plugin_launch_extension_prefs (PluginObject *obj,
NPString uuid,
NPVariant *result)
{
gchar *uuid_str;
uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
if (!uuid_is_valid (uuid_str))
{
g_free (uuid_str);
return FALSE;
}
g_dbus_proxy_call (obj->proxy,
"LaunchExtensionPrefs",
g_variant_new ("(s)", uuid_str),
G_DBUS_CALL_FLAGS_NONE,
-1, /* timeout */
NULL, /* cancellable */
NULL, /* callback */
NULL /* user_data */);
g_free (uuid_str);
return TRUE;
}
static int static int
plugin_get_api_version (PluginObject *obj, plugin_get_api_version (PluginObject *obj,
NPVariant *result) NPVariant *result)
@ -793,14 +726,6 @@ plugin_object_invoke (NPObject *npobj,
NPVARIANT_TO_STRING(args[0]), NPVARIANT_TO_STRING(args[0]),
result); result);
} }
else if (name == launch_extension_prefs_id)
{
if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
return plugin_launch_extension_prefs (obj,
NPVARIANT_TO_STRING(args[0]),
result);
}
return TRUE; return TRUE;
} }
@ -810,7 +735,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);
} }
@ -837,33 +761,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;
} }
@ -875,13 +772,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;
} }
@ -915,9 +824,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");
} }

View File

@ -1,5 +1,5 @@
AC_PREREQ(2.63) AC_PREREQ(2.63)
AC_INIT([gnome-shell],[3.4.2],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell]) AC_INIT([gnome-shell],[3.2.2],[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])
@ -36,6 +36,10 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",
PKG_PROG_PKG_CONFIG([0.22]) PKG_PROG_PKG_CONFIG([0.22])
# GConf stuff
AC_PATH_PROG(GCONFTOOL, gconftool-2, no)
AM_GCONF_SOURCE_2
GLIB_GSETTINGS GLIB_GSETTINGS
# Get a value to substitute into gnome-shell.in # Get a value to substitute into gnome-shell.in
@ -53,39 +57,37 @@ 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-0.10 gstreamer-base-0.10 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.29.18 GJS_MIN_VERSION=1.29.18
MUTTER_MIN_VERSION=3.4.1 MUTTER_MIN_VERSION=3.2.1
FOLKS_MIN_VERSION=0.5.2 FOLKS_MIN_VERSION=0.5.2
GTK_MIN_VERSION=3.3.9 GTK_MIN_VERSION=3.0.0
GIO_MIN_VERSION=2.31.6 GIO_MIN_VERSION=2.29.10
LIBECAL_MIN_VERSION=2.32.0 LIBECAL_MIN_VERSION=2.32.0
LIBEDATASERVER_MIN_VERSION=1.2.0 LIBEDATASERVER_MIN_VERSION=1.2.0
LIBEDATASERVERUI_MIN_VERSION=2.91.6 LIBEDATASERVERUI_MIN_VERSION=2.91.6
TELEPATHY_GLIB_MIN_VERSION=0.17.5 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
# 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-2.0 >= $GIO_MIN_VERSION
libxml-2.0 gio-unix-2.0 dbus-glib-1 libxml-2.0
gtk+-3.0 >= $GTK_MIN_VERSION gtk+-3.0 >= $GTK_MIN_VERSION
folks >= $FOLKS_MIN_VERSION 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 $recorder_modules libgnome-menu-3.0 $recorder_modules gconf-2.0
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
@ -94,8 +96,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)
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0) PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
@ -119,8 +120,8 @@ 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 >= 0.1.7) PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 0.1.7)
@ -130,7 +131,6 @@ PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0],
[BLUETOOTH_DIR=`$PKG_CONFIG --variable=applet_libdir gnome-bluetooth-1.0` [BLUETOOTH_DIR=`$PKG_CONFIG --variable=applet_libdir gnome-bluetooth-1.0`
BLUETOOTH_LIBS=`$PKG_CONFIG --variable=applet_libs gnome-bluetooth-1.0` BLUETOOTH_LIBS=`$PKG_CONFIG --variable=applet_libs gnome-bluetooth-1.0`
AC_SUBST([BLUETOOTH_LIBS],["$BLUETOOTH_LIBS"]) AC_SUBST([BLUETOOTH_LIBS],["$BLUETOOTH_LIBS"])
AC_SUBST([BLUETOOTH_DIR],["$BLUETOOTH_DIR"])
AC_DEFINE_UNQUOTED([BLUETOOTH_DIR],["$BLUETOOTH_DIR"],[Path to installed GnomeBluetooth typelib and library]) AC_DEFINE_UNQUOTED([BLUETOOTH_DIR],["$BLUETOOTH_DIR"],[Path to installed GnomeBluetooth typelib and library])
AC_DEFINE([HAVE_BLUETOOTH],[1],[Define if you have libgnome-bluetooth-applet]) AC_DEFINE([HAVE_BLUETOOTH],[1],[Define if you have libgnome-bluetooth-applet])
AC_SUBST([HAVE_BLUETOOTH],[1]) AC_SUBST([HAVE_BLUETOOTH],[1])
@ -143,33 +143,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)
@ -206,8 +179,6 @@ AC_SUBST(GIRDIR)
TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)" TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)"
AC_SUBST(TYPELIBDIR) AC_SUBST(TYPELIBDIR)
GTK_DOC_CHECK([1.15], [--flavour no-tmpl])
# Stay command-line compatible with the gnome-common configure option. Here # Stay command-line compatible with the gnome-common configure option. Here
# minimum/yes/maximum are the same, however. # minimum/yes/maximum are the same, however.
AC_ARG_ENABLE(compile_warnings, AC_ARG_ENABLE(compile_warnings,
@ -228,7 +199,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
@ -236,7 +207,7 @@ 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_MSG_CHECKING([location of system Certificate Authority list])
@ -270,13 +241,8 @@ AC_ARG_VAR([BROWSER_PLUGIN_DIR],[Where to install the plugin to])
AC_CONFIG_FILES([ AC_CONFIG_FILES([
Makefile Makefile
data/Makefile data/Makefile
docs/Makefile
docs/reference/Makefile
docs/reference/shell/Makefile
docs/reference/shell/shell-docs.sgml
docs/reference/st/Makefile
docs/reference/st/st-docs.sgml
js/Makefile js/Makefile
js/misc/config.js
src/Makefile src/Makefile
browser-plugin/Makefile browser-plugin/Makefile
tests/Makefile tests/Makefile

View File

@ -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
@ -12,23 +12,16 @@ desktop_DATA = gnome-shell.desktop gnome-shell-extension-prefs.desktop
%.desktop:%.desktop.in %.desktop:%.desktop.in
$(AM_V_GEN) sed s/^_// < $< > $@ || rm $@ $(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 \
@ -38,6 +31,7 @@ dist_theme_DATA = \
theme/filter-selected-rtl.svg \ theme/filter-selected-rtl.svg \
theme/gdm.css \ theme/gdm.css \
theme/gnome-shell.css \ theme/gnome-shell.css \
theme/panel-border.svg \
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 \
@ -53,7 +47,7 @@ dist_theme_DATA = \
theme/ws-switch-arrow-up.svg \ theme/ws-switch-arrow-up.svg \
theme/ws-switch-arrow-down.svg theme/ws-switch-arrow-down.svg
gsettings_SCHEMAS = org.gnome.shell.gschema.xml org.gnome.shell.evolution.calendar.gschema.xml gsettings_SCHEMAS = org.gnome.shell.gschema.xml
@INTLTOOL_XML_NOMERGE_RULE@ @INTLTOOL_XML_NOMERGE_RULE@
@GSETTINGS_RULES@ @GSETTINGS_RULES@
@ -65,27 +59,29 @@ gschemas.compiled: $(gsettings_SCHEMAS:.xml=.valid)
all-local: gschemas.compiled all-local: gschemas.compiled
convertdir = $(datadir)/GConf/gsettings
convert_DATA = gnome-shell-overrides.convert # GConf schemas: provide defaults for keys from Metacity we are overriding
gconfschemadir = @GCONF_SCHEMA_FILE_DIR@
gconfschema_DATA = gnome-shell.schemas
shadersdir = $(pkgdatadir)/shaders shadersdir = $(pkgdatadir)/shaders
shaders_DATA = \ shaders_DATA = \
shaders/dim-window.glsl shaders/dim-window.glsl
install-data-local:
GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(srcdir)/$(gconfschema_DATA)
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) \
$(gconfschema_DATA) \
$(shaders_DATA) \ $(shaders_DATA) \
$(convert_DATA) \
org.gnome.shell.evolution.calendar.gschema.xml.in \
org.gnome.shell.gschema.xml.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

View File

@ -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

View File

@ -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

View File

@ -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

100
data/gnome-shell.schemas Normal file
View File

@ -0,0 +1,100 @@
<gconfschemafile>
<schemalist>
<!-- Metacity overrides -->
<schema>
<key>/schemas/desktop/gnome/shell/windows/attach_modal_dialogs</key>
<applyto>/desktop/gnome/shell/windows/attach_modal_dialogs</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>true</default>
<locale name="C">
<short>Attach modal dialog to the parent window</short>
<long>
This key overrides /apps/mutter/general/attach_modal_dialogs when
running GNOME Shell.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/windows/button_layout</key>
<applyto>/desktop/gnome/shell/windows/button_layout</applyto>
<owner>gnome-shell</owner>
<type>string</type>
<default>:close</default>
<locale name="C">
<short>Arrangement of buttons on the titlebar</short>
<long>
Arrangement of buttons on the titlebar. The
value should be a string, such as
"menu:minimize,maximize,spacer,close"; the colon separates the
left corner of the window from the right corner, and
the button names are comma-separated. Duplicate buttons
are not allowed. Unknown button names are silently ignored
so that buttons can be added in future gnome-shell versions
without breaking older versions.
A special spacer tag can be used to insert some space between
two adjacent buttons.
This key overrides /apps/metacity/general/button_layout when
running GNOME Shell.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/windows/edge_tiling</key>
<applyto>/desktop/gnome/shell/windows/edge_tiling</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>true</default>
<locale name="C">
<short>enable edge tiling when dropping windows on screen edges</short>
<long>
If enabled, dropping windows on vertical screen edges maximizes them
vertically and resizes them horizontally to cover half of the
available area. Dropping windows on the top screen edge maximizes them
completely.
This key overrides /apps/metacity/general/edge_tiling when
running GNOME Shell.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/windows/theme</key>
<applyto>/desktop/gnome/shell/windows/theme</applyto>
<owner>gnome-shell</owner>
<type>string</type>
<default>Adwaita</default>
<locale name="C">
<short>Current theme</short>
<long>
The theme determines the appearance of window borders,
titlebar, and so forth.
This key overrides /apps/metacity/general/theme when
running GNOME Shell.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/windows/workspaces_only_on_primary</key>
<applyto>/desktop/gnome/shell/windows/workspaces_only_on_primary</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>true</default>
<locale name="C">
<short>Workspaces only on primary monitor</short>
<long>
This key overrides /apps/mutter/general/workspaces_only_on_primary when
running GNOME Shell.
</long>
</locale>
</schema>
</schemalist>
</gconfschemafile>

View File

@ -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>

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- NOTE: This schema is a GNOME 3.4 workaround - it uses the same path
as org.gnome.evolution.calendar, but avoids us requiring Evolution
be installed. In GNOME 3.6 the selected state will become a flag
on the calendar. Because the translations are in Evolution,
this is untranslated and in POTFILES.skip.
-->
<schemalist>
<schema path="/org/gnome/evolution/calendar/" id="org.gnome.shell.evolution.calendar" gettext-domain="evolution">
<key type="as" name="selected-calendars">
<default>[]</default>
<summary>List of selected calendars</summary>
<description>List of calendars to load</description>
</key>
<key type="as" name="selected-tasks">
<default>[]</default>
<summary>List of selected task lists</summary>
<description>List of task lists to load</description>
</key>
</schema>
</schemalist>

View File

@ -16,9 +16,8 @@
<_summary>Uuids of extensions to enable</_summary> <_summary>Uuids of extensions to enable</_summary>
<_description> <_description>
GNOME Shell extensions have a uuid property; this key lists extensions GNOME Shell extensions have a uuid property; this key lists extensions
which should be loaded. Any extension that wants to be loaded needs which should be loaded. disabled-extensions overrides this setting for
to be in this list. You can also manipulate this list with the extensions that appear in both lists.
EnableExtension and DisableExtension DBus methods on org.gnome.Shell.
</_description> </_description>
</key> </key>
<key name="enable-app-monitoring" type="b"> <key name="enable-app-monitoring" type="b">
@ -53,18 +52,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="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>
@ -79,17 +75,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>["&lt;Super&gt;F10"]</default>
<_summary>Keybinding to open the application menu</_summary>
<_description>
Keybinding to open the application menu.
</_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">
@ -122,7 +107,7 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
<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
@ -141,7 +126,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>
@ -156,48 +141,4 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
</_description> </_description>
</key> </key>
</schema> </schema>
<schema id="org.gnome.shell.overrides" path="/org/gnome/shell/overrides/">
<key name="attach-modal-dialogs" type="b">
<default>true</default>
<summary>Attach modal dialog to the parent window</summary>
<description>
This key overrides the key in org.gnome.mutter when running
GNOME Shell.
</description>
</key>
<key name="button-layout" type="s">
<default>":close"</default>
<summary>Arrangement of buttons on the titlebar</summary>
<description>
This key overrides the key in org.gnome.desktop.wm.preferences when
running GNOME Shell.
</description>
</key>
<key name="edge-tiling" type="b">
<default>true</default>
<summary>Enable edge tiling when dropping windows on screen edges</summary>
<description>
This key overrides the key in org.gnome.mutter when running GNOME Shell.
</description>
</key>
<key name="dynamic-workspaces" type="b">
<default>true</default>
<summary>Workspaces are managed dynamically</summary>
<description>
This key overrides the key in org.gnome.mutter when running GNOME Shell.
</description>
</key>
<key name="workspaces-only-on-primary" type="b">
<default>true</default>
<summary>Workspaces only on primary monitor</summary>
<description>
This key overrides the key in org.gnome.mutter when running GNOME Shell.
</description>
</key>
</schema>
</schemalist> </schemalist>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View 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

View File

@ -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

View File

@ -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

View File

@ -1 +0,0 @@
SUBDIRS = reference

View File

@ -1 +0,0 @@
SUBDIRS = shell st

View File

@ -1,113 +0,0 @@
## Process this file with automake to produce Makefile.in
# We require automake 1.6 at least.
AUTOMAKE_OPTIONS = 1.6
# This is a blank Makefile.am for using gtk-doc.
# Copy this to your project's API docs directory and modify the variables to
# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
# of using the various options.
# The name of the module, e.g. 'glib'.
DOC_MODULE=shell
# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
#DOC_MODULE_VERSION=2
# The top-level SGML file. You can change this if you want to.
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
# Directories containing the source code
# gtk-doc will search all .c and .h files beneath these paths
# for inline comments documenting functions and macros.
DOC_SOURCE_DIR=$(top_srcdir)/src
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
SCANGOBJ_OPTIONS=
# Extra options to supply to gtkdoc-scan.
# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
SCAN_OPTIONS=--rebuild-types
# Extra options to supply to gtkdoc-mkdb.
# e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
MKDB_OPTIONS=--xml-mode --output-format=xml
# Extra options to supply to gtkdoc-mktmpl
# e.g. MKTMPL_OPTIONS=--only-section-tmpl
MKTMPL_OPTIONS=
# Extra options to supply to gtkdoc-mkhtml
MKHTML_OPTIONS=
# Extra options to supply to gtkdoc-fixref. Not normally needed.
# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
FIXXREF_OPTIONS=
# Used for dependencies. The docs will be rebuilt if any of these change.
# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
HFILE_GLOB=$(top_srcdir)/src/*.h
CFILE_GLOB=$(top_srcdir)/src/*.c
# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
EXTRA_HFILES=
# Header files or dirs to ignore when scanning. Use base file/dir names
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
IGNORE_HFILES= \
calendar-server \
gvc \
hotplug-sniffer \
st \
tray \
gactionmuxer.h \
gactionobservable.h \
gactionobserver.h \
shell-recorder-src.h
# Images to copy into HTML directory.
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
HTML_IMAGES=
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
content_files=
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
# These files must be listed here *and* in content_files
# e.g. expand_content_files=running.sgml
expand_content_files=
# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
# Only needed if you are using gtkdoc-scangobj to dynamically query widget
# signals and properties.
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
GTKDOC_CFLAGS=$(GNOME_SHELL_CFLAGS)
GTKDOC_LIBS=$(GNOME_SHELL_LIBS) $(BLUETOOTH_LIBS) $(top_builddir)/src/libgnome-shell.la
# This includes the standard gtk-doc make rules, copied by gtkdocize.
include $(top_srcdir)/gtk-doc.make
# Other files to distribute
# e.g. EXTRA_DIST += version.xml.in
EXTRA_DIST +=
# Files not to distribute
# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
DISTCLEANFILES = $(DOC_MODULES).types
# Comment this out if you want 'make check' to test you doc status
# and run some sanity checks
if ENABLE_GTK_DOC
TESTS_ENVIRONMENT = cd $(srcdir) && \
DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \
SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir)
#TESTS = $(GTKDOC_CHECK)
endif
-include $(top_srcdir)/git.mk

View File

@ -1,73 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
[
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
]>
<book id="index">
<bookinfo>
<title>Shell Reference Manual</title>
<releaseinfo>
for Shell @VERSION@.
<!--The latest version of this documentation can be found on-line at
<ulink role="online-location" url="http://[SERVER]/shell/index.html">http://[SERVER]/shell/</ulink>.-->
</releaseinfo>
</bookinfo>
<chapter>
<title>Actors</title>
<xi:include href="xml/shell-generic-container.xml"/>
<xi:include href="xml/shell-slicer.xml"/>
<xi:include href="xml/shell-stack.xml"/>
</chapter>
<chapter>
<title>Application tracking</title>
<xi:include href="xml/shell-app.xml"/>
<xi:include href="xml/shell-app-usage.xml"/>
<xi:include href="xml/shell-window-tracker.xml"/>
</chapter>
<chapter>
<title>Search</title>
<xi:include href="xml/shell-app-system.xml"/>
<xi:include href="xml/shell-contact-system.xml"/>
<xi:include href="xml/shell-doc-system.xml"/>
</chapter>
<chapter>
<title>Tray Icons</title>
<xi:include href="xml/shell-embedded-window.xml"/>
<xi:include href="xml/shell-gtk-embed.xml"/>
<xi:include href="xml/shell-tray-icon.xml"/>
<xi:include href="xml/shell-tray-manager.xml"/>
</chapter>
<chapter>
<title>Recorder</title>
<xi:include href="xml/shell-recorder.xml"/>
<xi:include href="xml/shell-recorder-src.xml"/>
</chapter>
<chapter>
<title>Integration helpers and utilities</title>
<xi:include href="xml/shell-global.xml"/>
<xi:include href="xml/shell-wm.xml"/>
<xi:include href="xml/shell-xfixes-cursor.xml"/>
<xi:include href="xml/shell-util.xml"/>
<xi:include href="xml/shell-mount-operation.xml"/>
<xi:include href="xml/shell-mobile-providers.xml"/>
<xi:include href="xml/shell-network-agent.xml"/>
<xi:include href="xml/shell-polkit-authentication-agent.xml"/>
<xi:include href="xml/shell-tp-client.xml"/>
</chapter>
<chapter id="object-tree">
<title>Object Hierarchy</title>
<xi:include href="xml/tree_index.sgml"/>
</chapter>
<index id="api-index-full">
<title>API Index</title>
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
</index>
<index id="deprecated-api-index" role="deprecated">
<title>Index of deprecated API</title>
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
</index>
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
</book>

View File

@ -1,104 +0,0 @@
## Process this file with automake to produce Makefile.in
# We require automake 1.6 at least.
AUTOMAKE_OPTIONS = 1.6
# This is a blank Makefile.am for using gtk-doc.
# Copy this to your project's API docs directory and modify the variables to
# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
# of using the various options.
# The name of the module, e.g. 'glib'.
DOC_MODULE=st
# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
#DOC_MODULE_VERSION=2
# The top-level SGML file. You can change this if you want to.
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
# Directories containing the source code
# gtk-doc will search all .c and .h files beneath these paths
# for inline comments documenting functions and macros.
DOC_SOURCE_DIR=$(top_srcdir)/src/st
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
SCANGOBJ_OPTIONS=
# Extra options to supply to gtkdoc-scan.
# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
SCAN_OPTIONS=--rebuild-types --rebuild-sections
# Extra options to supply to gtkdoc-mkdb.
# e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
MKDB_OPTIONS=--xml-mode --output-format=xml
# Extra options to supply to gtkdoc-mktmpl
# e.g. MKTMPL_OPTIONS=--only-section-tmpl
MKTMPL_OPTIONS=
# Extra options to supply to gtkdoc-mkhtml
MKHTML_OPTIONS=
# Extra options to supply to gtkdoc-fixref. Not normally needed.
# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
FIXXREF_OPTIONS=
# Used for dependencies. The docs will be rebuilt if any of these change.
# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
HFILE_GLOB=$(top_srcdir)/src/st/*.h
CFILE_GLOB=$(top_srcdir)/src/st/*.c
# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
EXTRA_HFILES=
# Header files or dirs to ignore when scanning. Use base file/dir names
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
IGNORE_HFILES=st-private.h st-theme-node-private.h
# Images to copy into HTML directory.
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
HTML_IMAGES=
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
content_files=
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
# These files must be listed here *and* in content_files
# e.g. expand_content_files=running.sgml
expand_content_files=
# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
# Only needed if you are using gtkdoc-scangobj to dynamically query widget
# signals and properties.
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
GTKDOC_CFLAGS=
GTKDOC_LIBS=$(top_builddir)/src/libst-1.0.la
# This includes the standard gtk-doc make rules, copied by gtkdocize.
include $(top_srcdir)/gtk-doc.make
# Other files to distribute
# e.g. EXTRA_DIST += version.xml.in
EXTRA_DIST +=
# Files not to distribute
# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
DISTCLEANFILES = $(DOC_MODULE).types $(DOC_MODULE)-sections.txt
# Comment this out if you want 'make check' to test you doc status
# and run some sanity checks
if ENABLE_GTK_DOC
TESTS_ENVIRONMENT = cd $(srcdir) && \
DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \
SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir)
#TESTS = $(GTKDOC_CHECK)
endif
-include $(top_srcdir)/git.mk

View File

@ -1,64 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
[
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
]>
<book id="index">
<bookinfo>
<title>St Reference Manual</title>
<releaseinfo>
for St @VERSION@.
<!--The latest version of this documentation can be found on-line at
<ulink role="online-location" url="http://[SERVER]/st/index.html">http://[SERVER]/st/</ulink>.-->
</releaseinfo>
</bookinfo>
<part>
<title>API reference</title>
<chapter id="base">
<title>Abstract classes and Interfaces</title>
<xi:include href="xml/st-widget.xml"/>
<xi:include href="xml/st-widget-accessible.xml"/>
<xi:include href="xml/st-scrollable.xml"/>
</chapter>
<chapter id="widgets">
<title>Widgets</title>
<xi:include href="xml/st-button.xml"/>
<xi:include href="xml/st-drawing-area.xml"/>
<xi:include href="xml/st-entry.xml"/>
<xi:include href="xml/st-icon.xml"/>
<xi:include href="xml/st-label.xml"/>
</chapter>
<chapter id="containers">
<title>Containers</title>
<xi:include href="xml/st-bin.xml"/>
<xi:include href="xml/st-box-layout.xml"/>
<xi:include href="xml/st-scroll-view.xml"/>
<xi:include href="xml/st-table.xml"/>
</chapter>
<chapter id="styling">
<title>Styling</title>
<xi:include href="xml/st-theme.xml"/>
<xi:include href="xml/st-theme-context.xml"/>
<xi:include href="xml/st-theme-node.xml"/>
<xi:include href="xml/st-theme-node-transition.xml"/>
<xi:include href="xml/st-texture-cache.xml"/>
</chapter>
</part>
<chapter id="object-tree">
<title>Object Hierarchy</title>
<xi:include href="xml/tree_index.sgml"/>
</chapter>
<index id="api-index-full">
<title>API Index</title>
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
</index>
<index id="deprecated-api-index" role="deprecated">
<title>Index of deprecated API</title>
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
</index>
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
</book>

View File

@ -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>

View File

@ -1,20 +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|[@]GJS_VERSION@|$(GJS_VERSION)|g" \
-e "s|[@]HAVE_BLUETOOTH@|$(HAVE_BLUETOOTH)|g" \
-e "s|[@]SHELL_SYSTEM_CA_FILE@|$(SHELL_SYSTEM_CA_FILE)|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 = \
@ -23,15 +7,12 @@ 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 \
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/format.js \
misc/gnomeSession.js \ misc/gnomeSession.js \
misc/history.js \ misc/history.js \
misc/jsParse.js \
misc/modemManager.js \ misc/modemManager.js \
misc/params.js \ misc/params.js \
misc/screenSaver.js \ misc/screenSaver.js \
@ -44,19 +25,17 @@ 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/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/flashspot.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/link.js \
@ -76,7 +55,6 @@ 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/scripting.js \ ui/scripting.js \
ui/search.js \ ui/search.js \
@ -93,7 +71,6 @@ nobase_dist_js_DATA = \
ui/tweener.js \ ui/tweener.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 \

View File

@ -1,278 +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 _ = Gettext.gettext;
const Config = imports.misc.config;
const Format = imports.misc.format;
const ExtensionUtils = imports.misc.extensionUtils;
const GnomeShellIface = <interface name="org.gnome.Shell">
<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() {
ExtensionUtils.scanExtensions(Lang.bind(this, function(uuid, dir, type) {
if (ExtensionUtils.extensions[uuid] !== undefined)
return;
let extension;
try {
extension = ExtensionUtils.createExtensionObject(uuid, dir, type);
} catch(e) {
global.logError('' + e);
return;
}
let iter = this._model.append();
this._model.set(iter, [0, 1], [uuid, extension.metadata.name]);
this._extensionIters[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) {
global.log('ERROR: ' + s);
},
userdatadir: GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell'])
};
String.prototype.format = Format.format;
}
function main(argv) {
initEnvironment();
ExtensionUtils.init();
Gettext.bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
Gettext.textdomain(Config.GETTEXT_PACKAGE);
let app = new Application();
app.application.run(argv);
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -33,6 +33,7 @@ const St = imports.gi.St;
const GdmGreeter = imports.gi.GdmGreeter; 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 Lightbox = imports.ui.lightbox; const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main; const Main = imports.ui.main;
@ -140,9 +141,11 @@ 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',
@ -205,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();
} }
@ -272,12 +274,15 @@ const UserListItem = new Lang.Class({
}); });
return hold; return hold;
} }
});
};
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,
@ -488,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)
@ -536,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;
@ -596,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();
@ -697,7 +703,7 @@ 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 = {};
@ -732,15 +738,24 @@ 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;
}
return _loginDialog;
}
LoginDialog.prototype = {
__proto__: ModalDialog.ModalDialog.prototype,
_init: function() { _init: function() {
this.parent({ shellReactive: true, styleClass: 'login-dialog' }); 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',
@ -829,7 +844,7 @@ const LoginDialog = new Lang.Class({
x_fill: true, x_fill: true,
y_fill: false, y_fill: false,
x_align: St.Align.START }); x_align: St.Align.START });
// Translators: this message is shown below the password entry field // translators: this message is shown below the password entry field
// to indicate the user can swipe their finger instead // to indicate the user can swipe their finger instead
this._promptFingerprintMessage = new St.Label({ text: _("(or swipe finger)"), this._promptFingerprintMessage = new St.Label({ text: _("(or swipe finger)"),
style_class: 'login-dialog-prompt-fingerprint-message' }); style_class: 'login-dialog-prompt-fingerprint-message' });
@ -849,9 +864,6 @@ const LoginDialog = new Lang.Class({
x_align: St.Align.START }); x_align: St.Align.START });
this._promptBox.hide(); this._promptBox.hide();
// translators: this message is shown below the user list on the
// login screen. It can be activated to reveal an entry for
// manually entering the username.
let notListedLabel = new St.Label({ text: _("Not listed?"), let notListedLabel = new St.Label({ text: _("Not listed?"),
style_class: 'login-dialog-not-listed-label' }); style_class: 'login-dialog-not-listed-label' });
this._notListedButton = new St.Button({ style_class: 'login-dialog-not-listed-button', this._notListedButton = new St.Button({ style_class: 'login-dialog-not-listed-button',
@ -893,7 +905,7 @@ const LoginDialog = new Lang.Class({
if (!this._settings.get_boolean(_FINGERPRINT_AUTHENTICATION_KEY)) if (!this._settings.get_boolean(_FINGERPRINT_AUTHENTICATION_KEY))
return; return;
this._fprintManager.GetDefaultDeviceRemote(Gio.DBusCallFlags.NONE, Lang.bind(this, this._fprintManager.GetDefaultDeviceRemote(DBus.CALL_FLAG_START, Lang.bind(this,
function(device, error) { function(device, error) {
if (!error && device) if (!error && device)
this._haveFingerprintReader = true; this._haveFingerprintReader = true;
@ -1384,8 +1396,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);
} }
}); };

View File

@ -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();
@ -67,23 +64,6 @@ const PowerMenuButton = new Lang.Class({
}, },
_updateHaveShutdown: function() { _updateHaveShutdown: function() {
if (Systemd.haveSystemd()) {
this._systemdLoginManager.CanPowerOffRemote(Lang.bind(this,
function(result, error) {
if (!error)
this._haveShutdown = result != 'no';
else
this._haveShutdown = false;
if (this._haveShutdown)
this._powerOffItem.actor.show();
else
this._powerOffItem.actor.hide();
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)
@ -99,27 +79,9 @@ const PowerMenuButton = new Lang.Class({
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 != 'no';
else
this._haveRestart = false;
if (this._haveRestart)
this._restartItem.actor.show();
else
this._restartItem.actor.hide();
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)
@ -135,7 +97,6 @@ const PowerMenuButton = new Lang.Class({
this._updateVisibility(); this._updateVisibility();
})); }));
}
}, },
_updateHaveSuspend: function() { _updateHaveSuspend: function() {
@ -174,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();
} }
}); };

View File

@ -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;
}

View File

@ -10,10 +10,3 @@ const GJS_VERSION = '@GJS_VERSION@';
const HAVE_BLUETOOTH = @HAVE_BLUETOOTH@; const HAVE_BLUETOOTH = @HAVE_BLUETOOTH@;
/* The system TLS CA list */ /* The system TLS CA list */
const SHELL_SYSTEM_CA_FILE = '@SHELL_SYSTEM_CA_FILE@'; const SHELL_SYSTEM_CA_FILE = '@SHELL_SYSTEM_CA_FILE@';
/* gettext package */
const GETTEXT_PACKAGE = '@GETTEXT_PACKAGE@';
/* locale dir */
const LOCALEDIR = '@datadir@/locale';
/* other standard directories */
const LIBEXECDIR = '@libexecdir@';
const SYSCONFDIR = '@sysconfdir@';

140
js/misc/docInfo.js Normal file
View 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);

View File

@ -1,194 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
// Common utils for the extension system and the extension
// preferences tool
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
};
// GFile for user extensions
var userExtensionsDir = null;
// 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 uuid = GLib.path_get_basename(GLib.path_get_dirname(path));
let extension = extensions[uuid];
if (extension === undefined)
throw new Error('Could not find current extension');
return 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;
if (extension.metadata['js-version'] && !versionCheck(extension.metadata['js-version'], Config.GJS_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) {
global.log('Warning: Missing "url" property in metadata.json');
}
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;
}
function init() {
let userExtensionsPath = GLib.build_filenamev([global.userdatadir, 'extensions']);
userExtensionsDir = Gio.file_new_for_path(userExtensionsPath);
try {
if (!userExtensionsDir.query_exists(null))
userExtensionsDir.make_directory_with_parents(null);
} catch (e) {
global.logError('' + e);
}
}
function scanExtensionsInDirectory(callback, 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 uuid = info.get_name();
let extensionDir = dir.get_child(uuid);
callback(uuid, extensionDir, type);
}
fileEnum.close(null);
}
function scanExtensions(callback) {
let systemDataDirs = GLib.get_system_data_dirs();
scanExtensionsInDirectory(callback, userExtensionsDir, ExtensionType.PER_USER);
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))
scanExtensionsInDirectory(callback, dir, ExtensionType.SYSTEM);
}
}

View File

@ -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 ShellJS = imports.gi.ShellJS;
/* /*
* This function is intended to extend the String object and provide * This function is intended to extend the String object and provide
* an String.format API for string formatting. * an String.format API for string formatting.
@ -19,16 +17,11 @@ function format() {
let i = 0; let i = 0;
let args = arguments; let args = arguments;
return str.replace(/%(I+)?([0-9]+)?(?:\.([0-9]+))?(.)/g, function (str, flagsGroup, widthGroup, precisionGroup, genericGroup) { return str.replace(/%([0-9]+)?(?:\.([0-9]+))?(.)/g, function (str, widthGroup, precisionGroup, genericGroup) {
if (precisionGroup != '' && genericGroup != 'f') if (precisionGroup != '' && genericGroup != 'f')
throw new Error("Precision can only be specified for 'f'"); throw new Error("Precision can only be specified for 'f'");
let hasAlternativeIntFlag = (flagsGroup.indexOf('I') != -1);
if (hasAlternativeIntFlag && genericGroup != 'd')
throw new Error("Alternative output digits can only be specfied for 'd'");
let fillChar = (widthGroup[0] == '0') ? '0' : ' '; let fillChar = (widthGroup[0] == '0') ? '0' : ' ';
let width = parseInt(widthGroup, 10) || 0; let width = parseInt(widthGroup, 10) || 0;
@ -48,11 +41,7 @@ function format() {
s = args[i++].toString(); s = args[i++].toString();
break; break;
case 'd': case 'd':
let intV = parseInt(args[i++]); s = parseInt(args[i++]).toString();
if (hasAlternativeIntFlag)
s = ShellJS.format_int_alternative_output(intV);
else
s = intV.toString();
break; break;
case 'x': case 'x':
s = parseInt(args[i++]).toString(16); s = parseInt(args[i++]).toString(16);

View File

@ -1,18 +1,20 @@
// -*- 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 Signals = imports.signals; const Signals = imports.signals;
const PresenceIface = <interface name="org.gnome.SessionManager.Presence"> const PresenceIface = {
<method name="SetStatus"> name: 'org.gnome.SessionManager.Presence',
<arg type="u" direction="in"/> methods: [{ name: 'SetStatus',
</method> inSignature: 'u',
<property name="status" type="u" access="readwrite"/> outSignature: '' }],
<signal name="StatusChanged"> properties: [{ name: 'status',
<arg type="u" direction="out"/> signature: 'u',
</signal> access: 'readwrite' }],
</interface>; signals: [{ name: 'StatusChanged',
inSignature: 'u' }]
};
const PresenceStatus = { const PresenceStatus = {
AVAILABLE: 0, AVAILABLE: 0,
@ -21,41 +23,104 @@ const PresenceStatus = {
IDLE: 3 IDLE: 3
}; };
var PresenceProxy = Gio.DBusProxy.makeProxyWrapper(PresenceIface); function Presence() {
function Presence(initCallback, cancellable) { this._init();
return new PresenceProxy(Gio.DBus.session, 'org.gnome.SessionManager',
'/org/gnome/SessionManager/Presence', initCallback, cancellable);
} }
Presence.prototype = {
_init: function() {
DBus.session.proxifyObject(this, 'org.gnome.SessionManager', '/org/gnome/SessionManager/Presence', this);
},
getStatus: function(callback) {
this.GetRemote('status', Lang.bind(this,
function(status, ex) {
if (!ex)
callback(this, status);
}));
},
setStatus: function(status) {
this.SetStatusRemote(status);
}
};
DBus.proxifyPrototype(Presence.prototype, PresenceIface);
// Note inhibitors are immutable objects, so they don't // Note inhibitors are immutable objects, so they don't
// 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 = {
<method name="GetAppId"> name: 'org.gnome.SessionManager.Inhibitor',
<arg type="s" direction="out" /> properties: [{ name: 'app_id',
</method> signature: 's',
<method name="GetReason"> access: 'readonly' },
<arg type="s" direction="out" /> { name: 'client_id',
</method> signature: 's',
</interface>; access: 'readonly' },
{ name: 'reason',
signature: 's',
access: 'readonly' },
{ name: 'flags',
signature: 'u',
access: 'readonly' },
{ name: 'toplevel_xid',
signature: 'u',
access: 'readonly' },
{ name: 'cookie',
signature: 'u',
access: 'readonly' }],
};
var InhibitorProxy = Gio.DBusProxy.makeProxyWrapper(InhibitorIface); function Inhibitor(objectPath) {
function Inhibitor(objectPath, initCallback, cancellable) { this._init(objectPath);
return new InhibitorProxy(Gio.DBus.session, 'org.gnome.SessionManager', objectPath, initCallback, cancellable);
} }
Inhibitor.prototype = {
_init: function(objectPath) {
DBus.session.proxifyObject(this,
'org.gnome.SessionManager',
objectPath);
this.isLoaded = false;
this._loadingPropertiesCount = InhibitorIface.properties.length;
for (let i = 0; i < InhibitorIface.properties.length; i++) {
let propertyName = InhibitorIface.properties[i].name;
this.GetRemote(propertyName, Lang.bind(this,
function(value, exception) {
if (exception)
return;
this[propertyName] = value;
this._loadingPropertiesCount--;
if (this._loadingPropertiesCount == 0) {
this.isLoaded = true;
this.emit('is-loaded');
}
}));
}
},
};
DBus.proxifyPrototype(Inhibitor.prototype, InhibitorIface);
Signals.addSignalMethods(Inhibitor.prototype);
// Not the full interface, only the methods we use // Not the full interface, only the methods we use
const SessionManagerIface = <interface name="org.gnome.SessionManager"> const SessionManagerIface = {
<method name="Logout"> name: 'org.gnome.SessionManager',
<arg type="u" direction="in" /> methods: [
</method> { name: 'Logout', inSignature: 'u', outSignature: '' },
<method name="Shutdown" /> { name: 'Shutdown', inSignature: '', outSignature: '' },
<method name="CanShutdown"> { name: 'CanShutdown', inSignature: '', outSignature: 'b' }
<arg type="b" direction="out" /> ]
</method> };
</interface>;
var SessionManagerProxy = Gio.DBusProxy.makeProxyWrapper(SessionManagerIface); function SessionManager() {
function SessionManager(initCallback, cancellable) { this._init();
return new SessionManagerProxy(Gio.DBus.session, 'org.gnome.SessionManager', '/org/gnome/SessionManager', initCallback, cancellable);
} }
SessionManager.prototype = {
_init: function() {
DBus.session.proxifyObject(this, 'org.gnome.SessionManager', '/org/gnome/SessionManager');
}
};
DBus.proxifyPrototype(SessionManager.prototype, SessionManagerIface);

View File

@ -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);

View File

@ -1,246 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
// Returns a list of potential completions for text. Completions either
// follow a dot (e.g. foo.ba -> bar) or they are picked from globalCompletionList (e.g. fo -> foo)
// commandHeader is prefixed on any expression before it is eval'ed. It will most likely
// consist of global constants that might not carry over from the calling environment.
//
// This function is likely the one you want to call from external modules
function getCompletions(text, commandHeader, globalCompletionList) {
let methods = [];
let expr, base;
let attrHead = '';
if (globalCompletionList == null) {
globalCompletionList = [];
}
let offset = getExpressionOffset(text, text.length - 1);
if (offset >= 0) {
text = text.slice(offset);
// Look for expressions like "Main.panel.foo" and match Main.panel and foo
let matches = text.match(/(.*)\.(.*)/);
if (matches) {
[expr, base, attrHead] = matches;
methods = getPropertyNamesFromExpression(base, commandHeader).filter(function(attr) {
return attr.slice(0, attrHead.length) == attrHead;
});
}
// Look for the empty expression or partially entered words
// not proceeded by a dot and match them against global constants
matches = text.match(/^(\w*)$/);
if (text == '' || matches) {
[expr, attrHead] = matches;
methods = globalCompletionList.filter(function(attr) {
return attr.slice(0, attrHead.length) == attrHead;
});
}
}
return [methods, attrHead];
}
//
// A few functions for parsing strings of javascript code.
//
// Identify characters that delimit an expression. That is,
// if we encounter anything that isn't a letter, '.', ')', or ']',
// we should stop parsing.
function isStopChar(c) {
return !c.match(/[\w\.\)\]]/);
}
// Given the ending position of a quoted string, find where it starts
function findMatchingQuote(expr, offset) {
let quoteChar = expr.charAt(offset);
for (let i = offset - 1; i >= 0; --i) {
if (expr.charAt(i) == quoteChar && expr.charAt(i-1) != '\\'){
return i;
}
}
return -1;
}
// Given the ending position of a regex, find where it starts
function findMatchingSlash(expr, offset) {
for (let i = offset - 1; i >= 0; --i) {
if (expr.charAt(i) == '/' && expr.charAt(i-1) != '\\'){
return i;
}
}
return -1;
}
// If expr.charAt(offset) is ')' or ']',
// return the position of the corresponding '(' or '[' bracket.
// This function does not check for syntactic correctness. e.g.,
// findMatchingBrace("[(])", 3) returns 1.
function findMatchingBrace(expr, offset) {
let closeBrace = expr.charAt(offset);
let openBrace = ({')': '(', ']': '['})[closeBrace];
function findTheBrace(expr, offset) {
if (offset < 0) {
return -1;
}
if (expr.charAt(offset) == openBrace) {
return offset;
}
if (expr.charAt(offset).match(/['"]/)) {
return findTheBrace(expr, findMatchingQuote(expr, offset) - 1);
}
if (expr.charAt(offset) == '/') {
return findTheBrace(expr, findMatchingSlash(expr, offset) - 1);
}
if (expr.charAt(offset) == closeBrace) {
return findTheBrace(expr, findTheBrace(expr, offset - 1) - 1);
}
return findTheBrace(expr, offset - 1);
}
return findTheBrace(expr, offset - 1);
}
// Walk expr backwards from offset looking for the beginning of an
// expression suitable for passing to eval.
// There is no guarantee of correct javascript syntax between the return
// value and offset. This function is meant to take a string like
// "foo(Obj.We.Are.Completing" and allow you to extract "Obj.We.Are.Completing"
function getExpressionOffset(expr, offset) {
while (offset >= 0) {
let currChar = expr.charAt(offset);
if (isStopChar(currChar)){
return offset + 1;
}
if (currChar.match(/[\)\]]/)) {
offset = findMatchingBrace(expr, offset);
}
--offset;
}
return offset + 1;
}
// Things with non-word characters or that start with a number
// are not accessible via .foo notation and so aren't returned
function isValidPropertyName(w) {
return !(w.match(/\W/) || w.match(/^\d/));
}
// To get all properties (enumerable and not), we need to walk
// the prototype chain ourselves
function getAllProps(obj) {
if (obj === null || obj === undefined) {
return [];
}
return Object.getOwnPropertyNames(obj).concat( getAllProps(Object.getPrototypeOf(obj)) );
}
// Given a string _expr_, returns all methods
// that can be accessed via '.' notation.
// e.g., expr="({ foo: null, bar: null, 4: null })" will
// return ["foo", "bar", ...] but the list will not include "4",
// since methods accessed with '.' notation must star with a letter or _.
function getPropertyNamesFromExpression(expr, commandHeader) {
if (commandHeader == null) {
commandHeader = '';
}
let obj = {};
if (!isUnsafeExpression(expr)) {
try {
obj = eval(commandHeader + expr);
} catch (e) {
return [];
}
} else {
return [];
}
let propsUnique = {};
if (typeof obj === 'object'){
let allProps = getAllProps(obj);
// Get only things we are allowed to complete following a '.'
allProps = allProps.filter( isValidPropertyName );
// Make sure propsUnique contains one key for every
// property so we end up with a unique list of properties
allProps.map(function(p){ propsUnique[p] = null; });
}
return Object.keys(propsUnique).sort();
}
// Given a list of words, returns the longest prefix they all have in common
function getCommonPrefix(words) {
let word = words[0];
for (let i = 0; i < word.length; i++) {
for (let w = 1; w < words.length; w++) {
if (words[w].charAt(i) != word.charAt(i))
return word.slice(0, i);
}
}
return word;
}
// Returns true if there is reason to think that eval(str)
// will modify the global scope
function isUnsafeExpression(str) {
// Remove any blocks that are quoted or are in a regex
function removeLiterals(str) {
if (str.length == 0) {
return '';
}
let currChar = str.charAt(str.length - 1);
if (currChar == '"' || currChar == '\'') {
return removeLiterals(str.slice(0, findMatchingQuote(str, str.length - 1)));
} else if (currChar == '/') {
return removeLiterals(str.slice(0, findMatchingSlash(str, str.length - 1)));
}
return removeLiterals(str.slice(0, str.length - 1)) + currChar;
}
// Check for any sort of assignment
// The strategy used is dumb: remove any quotes
// or regexs and comparison operators and see if there is an '=' character.
// If there is, it might be an unsafe assignment.
let prunedStr = removeLiterals(str);
prunedStr = prunedStr.replace(/[=!]==/g, ''); //replace === and !== with nothing
prunedStr = prunedStr.replace(/[=<>!]=/g, ''); //replace ==, <=, >=, != with nothing
if (prunedStr.match(/=/)) {
return true;
} else if (prunedStr.match(/;/)) {
// If we contain a semicolon not inside of a quote/regex, assume we're unsafe as well
return true;
}
return false;
}
// Returns a list of global keywords derived from str
function getDeclaredConstants(str) {
let ret = [];
str.split(';').forEach(function(s) {
let base, keyword;
let match = s.match(/const\s+(\w+)\s*=/);
if (match) {
[base, keyword] = match;
ret.push(keyword);
}
});
return ret;
}

View File

@ -1,6 +1,6 @@
// -*- 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;
@ -8,39 +8,33 @@ const Signals = imports.signals;
// The following are not the complete interfaces, just the methods we need // The following are not the complete interfaces, just the methods we need
// (or may need in the future) // (or may need in the future)
const ModemGsmNetworkInterface = <interface name="org.freedesktop.ModemManager.Modem.Gsm.Network"> const ModemGsmNetworkInterface = {
<method name="GetRegistrationInfo"> name: 'org.freedesktop.ModemManager.Modem.Gsm.Network',
<arg type="(uss)" direction="out" /> methods: [
</method> { name: 'GetRegistrationInfo', inSignature: '', outSignature: 'uss' },
<method name="GetSignalQuality"> { name: 'GetSignalQuality', inSignature: '', outSignature: 'u' }
<arg type="u" direction="out" /> ],
</method> properties: [
<property name="AccessTechnology" type="u" access="read" /> { name: 'AccessTechnology', signature: 'u', access: 'read' }
<signal name="SignalQuality"> ],
<arg type="u" direction="out" /> signals: [
</signal> { name: 'SignalQuality', inSignature: 'u' },
<signal name="RegistrationInfo"> { name: 'RegistrationInfo', inSignature: 'uss' }
<arg type="u" direction="out" /> ]
<arg type="s" direction="out" /> };
<arg type="s" direction="out" /> const ModemGsmNetworkProxy = DBus.makeProxyClass(ModemGsmNetworkInterface);
</signal>
</interface>;
const ModemGsmNetworkProxy = Gio.DBusProxy.makeProxyWrapper(ModemGsmNetworkInterface); const ModemCdmaInterface = {
name: 'org.freedesktop.ModemManager.Modem.Cdma',
const ModemCdmaInterface = <interface name="org.freedesktop.ModemManager.Modem.Cdma"> methods: [
<method name="GetSignalQuality"> { name: 'GetSignalQuality', inSignature: '', outSignature: 'u' },
<arg type="u" direction="out" /> { name: 'GetServingSystem', inSignature: '', outSignature: 'usu' }
</method> ],
<method name="GetServingSystem"> signals: [
<arg type="(usu)" direction="out" /> { name: 'SignalQuality', inSignature: 'u' }
</method> ]
<signal name="SignalQuality"> };
<arg type="u" direction="out" /> const ModemCdmaProxy = DBus.makeProxyClass(ModemCdmaInterface);
</signal>
</interface>;
const ModemCdmaProxy = Gio.DBusProxy.makeProxyWrapper(ModemCdmaInterface);
let _providersTable; let _providersTable;
function _getProvidersTable() { function _getProvidersTable() {
@ -50,25 +44,27 @@ 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(DBus.system, 'org.freedesktop.ModemManager', path);
this.signal_quality = 0; this.signal_quality = 0;
this.operator_name = null; this.operator_name = null;
// Code is duplicated because the function have different signatures // Code is duplicated because the function have different signatures
this._proxy.connectSignal('SignalQuality', Lang.bind(this, function(proxy, sender, [quality]) { this._proxy.connect('SignalQuality', Lang.bind(this, function(proxy, quality) {
this.signal_quality = quality; this.signal_quality = quality;
this.emit('notify::signal-quality'); this.emit('notify::signal-quality');
})); }));
this._proxy.connectSignal('RegistrationInfo', Lang.bind(this, function(proxy, sender, [status, code, name]) { this._proxy.connect('RegistrationInfo', Lang.bind(this, function(proxy, status, code, name) {
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,19 +146,21 @@ 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(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, quality) {
this.signal_quality = params[0]; this.signal_quality = quality;
this.emit('notify::signal-quality'); this.emit('notify::signal-quality');
// receiving this signal means the device got activated // receiving this signal means the device got activated
@ -183,7 +181,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 +221,5 @@ const ModemCdma = new Lang.Class({
return null; return null;
} }
}); };
Signals.addSignalMethods(ModemCdma.prototype); Signals.addSignalMethods(ModemCdma.prototype);

View File

@ -1,48 +1,53 @@
// -*- 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 ScreenSaverIface = <interface name="org.gnome.ScreenSaver"> const ScreenSaverIface = {
<method name="GetActive"> name: 'org.gnome.ScreenSaver',
<arg type="b" direction="out" /> methods: [{ name: 'GetActive',
</method> inSignature: '',
<method name="Lock" /> outSignature: 'b' },
<method name="SetActive"> { name: 'Lock',
<arg type="b" direction="in" /> inSignature: '' },
</method> { name: 'SetActive',
<signal name="ActiveChanged"> inSignature: 'b' }],
<arg type="b" direction="out" /> signals: [{ name: 'ActiveChanged',
</signal> inSignature: 'b' }]
</interface>; };
const ScreenSaverInfo = Gio.DBusInterfaceInfo.new_for_xml(ScreenSaverIface);
function ScreenSaverProxy() { function ScreenSaverProxy() {
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.session, this._init();
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;
} }
ScreenSaverProxy.prototype = {
_init: function() {
DBus.session.proxifyObject(this,
'org.gnome.ScreenSaver',
'/org/gnome/ScreenSaver');
DBus.session.watch_name('org.gnome.ScreenSaver',
false, // do not launch a name-owner if none exists
Lang.bind(this, this._onSSAppeared),
Lang.bind(this, this._onSSVanished));
this.screenSaverActive = false;
this.connect('ActiveChanged',
Lang.bind(this, this._onActiveChanged));
},
_onSSAppeared: function(owner) {
this.GetActiveRemote(Lang.bind(this, function(isActive) {
this.screenSaverActive = isActive;
}))
},
_onSSVanished: function(oldOwner) {
this.screenSaverActive = false;
},
_onActiveChanged: function(object, isActive) {
this.screenSaverActive = isActive;
}
};
DBus.proxifyPrototype(ScreenSaverProxy.prototype, ScreenSaverIface);

View File

@ -232,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;
}

View File

@ -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
@ -170,12 +170,8 @@ const AltTabPopup = new Lang.Class({
if (localApps.length == 0 && otherApps.length == 0) if (localApps.length == 0 && otherApps.length == 0)
return false; return false;
if (!Main.pushModal(this.actor)) { if (!Main.pushModal(this.actor))
// Probably someone else has a pointer grab, try again with keyboard only
if (!Main.pushModal(this.actor, global.get_current_time(), Meta.ModalOptions.POINTER_ALREADY_GRABBED)) {
return false; return false;
}
}
this._haveModal = true; this._haveModal = true;
this._modifierMask = primaryModifier(mask); this._modifierMask = primaryModifier(mask);
@ -199,7 +195,7 @@ const AltTabPopup = new Lang.Class({
this.actor.get_allocation_box(); this.actor.get_allocation_box();
// Make the initial selection // Make the initial selection
if (binding == 'switch-group') { if (binding == 'switch_group') {
if (backward) { if (backward) {
this._select(0, this._appIcons[0].cachedWindows.length - 1); this._select(0, this._appIcons[0].cachedWindows.length - 1);
} else { } else {
@ -208,9 +204,9 @@ const AltTabPopup = new Lang.Class({
else else
this._select(0, 0); this._select(0, 0);
} }
} else if (binding == 'switch-group-backward') { } else if (binding == 'switch_group_backward') {
this._select(0, this._appIcons[0].cachedWindows.length - 1); this._select(0, this._appIcons[0].cachedWindows.length - 1);
} else if (binding == 'switch-windows-backward') { } else if (binding == 'switch_windows_backward') {
this._select(this._appIcons.length - 1); this._select(this._appIcons.length - 1);
} else if (this._appIcons.length == 1) { } else if (this._appIcons.length == 1) {
this._select(0); this._select(0);
@ -266,7 +262,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 +515,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 +535,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 +561,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 +599,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 +622,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 +631,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 +648,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 +679,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 +705,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 +805,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 +838,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 +873,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 +962,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 +1017,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 +1030,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 +1040,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 +1129,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();

View File

@ -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;
@ -27,9 +26,11 @@ 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();
@ -129,11 +130,13 @@ const AlphabeticalView = new Lang.Class({
this._addApp(app); 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' });
@ -149,9 +152,7 @@ const ViewByCategories = new Lang.Class({
this._categories = []; this._categories = [];
this._apps = null; 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' });
@ -217,8 +218,7 @@ const ViewByCategories = new Lang.Class({
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);
})); }));
@ -240,7 +240,7 @@ const ViewByCategories = new Lang.Class({
_removeAll: function() { _removeAll: function() {
this._categories = []; this._categories = [];
this._categoryBox.destroy_all_children(); this._categoryBox.destroy_children();
}, },
refresh: function() { refresh: function() {
@ -281,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() {
@ -304,30 +306,27 @@ 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) { 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);
} }
}); };
}
return metas;
}, },
getInitialResultSet: function(terms) { getInitialResultSet: function(terms) {
@ -343,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)
@ -365,31 +364,28 @@ 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) { 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);
} }
}); };
}
return metas;
}, },
getInitialResultSet: function(terms) { getInitialResultSet: function(terms) {
@ -416,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',
@ -484,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() {
@ -566,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;
@ -583,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);
@ -619,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;
@ -719,5 +723,5 @@ const AppIconMenu = new Lang.Class({
} }
this.close(); this.close();
} }
}); };
Signals.addSignalMethods(AppIconMenu.prototype); Signals.addSignalMethods(AppIconMenu.prototype);

View File

@ -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;

View File

@ -1,12 +1,11 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Lang = imports.lang; const Lang = imports.lang;
const DBus = imports.dbus;
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 ScreenSaver = imports.misc.screenSaver; const ScreenSaver = imports.misc.screenSaver;
@ -17,75 +16,79 @@ const SETTING_ENABLE_AUTOMOUNT = 'automount';
const AUTORUN_EXPIRE_TIMEOUT_SECS = 10; const AUTORUN_EXPIRE_TIMEOUT_SECS = 10;
const ConsoleKitSessionIface = <interface name="org.freedesktop.ConsoleKit.Session"> const ConsoleKitSessionIface = {
<method name="IsActive"> name: 'org.freedesktop.ConsoleKit.Session',
<arg type="b" direction="out" /> methods: [{ name: 'IsActive',
</method> inSignature: '',
<signal name="ActiveChanged"> outSignature: 'b' }],
<arg type="b" direction="out" /> signals: [{ name: 'ActiveChanged',
</signal> inSignature: 'b' }]
</interface>; };
const ConsoleKitSessionProxy = Gio.DBusProxy.makeProxyWrapper(ConsoleKitSessionIface); const ConsoleKitSessionProxy = DBus.makeProxyClass(ConsoleKitSessionIface);
const ConsoleKitManagerIface = <interface name="org.freedesktop.ConsoleKit.Manager"> const ConsoleKitManagerIface = {
<method name="GetCurrentSession"> name: 'org.freedesktop.ConsoleKit.Manager',
<arg type="o" direction="out" /> methods: [{ name: 'GetCurrentSession',
</method> inSignature: '',
</interface>; outSignature: 'o' }]
};
const ConsoleKitManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(ConsoleKitManagerIface);
function ConsoleKitManager() { function ConsoleKitManager() {
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.system, this._init();
g_interface_name: ConsoleKitManagerInfo.name, };
g_interface_info: ConsoleKitManagerInfo,
g_name: 'org.freedesktop.ConsoleKit',
g_object_path: '/org/freedesktop/ConsoleKit/Manager',
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
self._updateSessionActive = function() { ConsoleKitManager.prototype = {
if (self.g_name_owner) { _init: function() {
self.GetCurrentSessionRemote(function([session]) { this.sessionActive = true;
self._ckSession = new ConsoleKitSessionProxy(Gio.DBus.system, 'org.freedesktop.ConsoleKit', session);
self._ckSession.connectSignal('ActiveChanged', function(object, senderName, [isActive]) { DBus.system.proxifyObject(this,
self.sessionActive = isActive; 'org.freedesktop.ConsoleKit',
}); '/org/freedesktop/ConsoleKit/Manager');
self._ckSession.IsActiveRemote(function([isActive]) {
self.sessionActive = isActive; DBus.system.watch_name('org.freedesktop.ConsoleKit',
}); false, // do not launch a name-owner if none exists
}); Lang.bind(this, this._onManagerAppeared),
} else { Lang.bind(this, this._onManagerVanished));
self.sessionActive = true; },
_onManagerAppeared: function(owner) {
this.GetCurrentSessionRemote(Lang.bind(this, this._onCurrentSession));
},
_onManagerVanished: function(oldOwner) {
this.sessionActive = true;
},
_onCurrentSession: function(session) {
this._ckSession = new ConsoleKitSessionProxy(DBus.system, 'org.freedesktop.ConsoleKit', session);
this._ckSession.connect
('ActiveChanged', Lang.bind(this, function(object, isActive) {
this.sessionActive = isActive;
}));
this._ckSession.IsActiveRemote(Lang.bind(this, function(isActive) {
this.sessionActive = isActive;
}));
} }
}; };
self.connect('notify::g-name-owner', DBus.proxifyPrototype(ConsoleKitManager.prototype, ConsoleKitManagerIface);
Lang.bind(self, self._updateSessionActive));
self._updateSessionActive(); function AutomountManager() {
self.init(null); this._init();
return self;
} }
function haveSystemd() { AutomountManager.prototype = {
return GLib.access("/sys/fs/cgroup/systemd", 0) >= 0;
}
const AutomountManager = new Lang.Class({
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 = [];
if (!haveSystemd())
this.ckListener = new ConsoleKitManager(); this.ckListener = new ConsoleKitManager();
this._ssProxy = new ScreenSaver.ScreenSaverProxy(); this._ssProxy = new ScreenSaver.ScreenSaverProxy();
this._ssProxy.connectSignal('ActiveChanged', this._ssProxy.connect('ActiveChanged',
Lang.bind(this, this._screenSaverActiveChanged)); Lang.bind(this,
this._screenSaverActiveChanged));
this._volumeMonitor = Gio.VolumeMonitor.get(); this._volumeMonitor = Gio.VolumeMonitor.get();
@ -108,7 +111,7 @@ const AutomountManager = new Lang.Class({
Mainloop.idle_add(Lang.bind(this, this._startupMountAll)); Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
}, },
_screenSaverActiveChanged: function(object, senderName, [isActive]) { _screenSaverActiveChanged: function(object, isActive) {
if (!isActive) { if (!isActive) {
this._volumeQueue.forEach(Lang.bind(this, function(volume) { this._volumeQueue.forEach(Lang.bind(this, function(volume) {
this._checkAndMountVolume(volume); this._checkAndMountVolume(volume);
@ -129,21 +132,10 @@ const AutomountManager = new Lang.Class({
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 (this._ssProxy.screenSaverActive) if (this._ssProxy.screenSaverActive)
@ -155,7 +147,7 @@ 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 (this._ssProxy.screenSaverActive) if (this._ssProxy.screenSaverActive)
@ -167,7 +159,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
@ -206,7 +198,7 @@ const AutomountManager = new Lang.Class({
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 (this._ssProxy.screenSaverActive) { if (this._ssProxy.screenSaverActive) {
@ -287,4 +279,4 @@ const AutomountManager = new Lang.Class({
return false; return false;
}); });
} }
}); }

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Lang = imports.lang; const Lang = imports.lang;
const DBus = imports.dbus;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const St = imports.gi.St; const St = imports.gi.St;
@ -61,23 +62,31 @@ function startAppForMount(app, mount) {
/******************************************/ /******************************************/
const HotplugSnifferIface = <interface name="org.gnome.Shell.HotplugSniffer"> const HotplugSnifferIface = {
<method name="SniffURI"> name: 'org.gnome.Shell.HotplugSniffer',
<arg type="s" direction="in" /> methods: [{ name: 'SniffURI',
<arg type="as" direction="out" /> inSignature: 's',
</method> outSignature: 'as' }]
</interface>; };
const HotplugSnifferProxy = Gio.DBusProxy.makeProxyWrapper(HotplugSnifferIface); const HotplugSniffer = function() {
function HotplugSniffer() { this._init();
return new HotplugSnifferProxy(Gio.DBus.session, };
HotplugSniffer.prototype = {
_init: function() {
DBus.session.proxifyObject(this,
'org.gnome.Shell.HotplugSniffer', 'org.gnome.Shell.HotplugSniffer',
'/org/gnome/Shell/HotplugSniffer'); '/org/gnome/Shell/HotplugSniffer');
},
};
DBus.proxifyPrototype(HotplugSniffer.prototype, HotplugSnifferIface);
function ContentTypeDiscoverer(callback) {
this._init(callback);
} }
const ContentTypeDiscoverer = new Lang.Class({ ContentTypeDiscoverer.prototype = {
Name: 'ContentTypeDiscoverer',
_init: function(callback) { _init: function(callback) {
this._callback = callback; this._callback = callback;
}, },
@ -105,8 +114,9 @@ const ContentTypeDiscoverer = new Lang.Class({
let root = mount.get_root(); let root = mount.get_root();
let hotplugSniffer = new HotplugSniffer(); let hotplugSniffer = new HotplugSniffer();
hotplugSniffer.SniffURIRemote(root.get_uri(), hotplugSniffer.SniffURIRemote
Lang.bind(this, function([contentTypes]) { (root.get_uri(), DBus.CALL_FLAG_START,
Lang.bind(this, function(contentTypes) {
this._emitCallback(mount, contentTypes); this._emitCallback(mount, contentTypes);
})); }));
} }
@ -134,11 +144,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();
@ -174,7 +186,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,
@ -255,14 +267,17 @@ const AutorunManager = new Lang.Class({
+ ': ' + 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")); MessageTray.Source.prototype._init.call(this, _("Removable Devices"));
this._mounts = []; this._mounts = [];
@ -317,14 +332,19 @@ const AutorunResidentSource = new Lang.Class({
icon_type: St.IconType.FULLCOLOR, icon_type: St.IconType.FULLCOLOR,
icon_size: this.ICON_SIZE }); icon_size: this.ICON_SIZE });
} }
}); }
const AutorunResidentNotification = new Lang.Class({ function AutorunResidentNotification(source) {
Name: 'AutorunResidentNotification', this._init(source);
Extends: MessageTray.Notification, }
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);
@ -339,7 +359,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];
@ -398,11 +418,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 });
@ -493,14 +515,17 @@ 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) {
this.parent(mount.get_name()); MessageTray.Source.prototype._init.call(this, mount.get_name());
this.mount = mount; this.mount = mount;
this.apps = apps; this.apps = apps;
@ -517,14 +542,19 @@ const AutorunTransientSource = new Lang.Class({
return new St.Icon({ gicon: this.mount.get_icon(), return new St.Icon({ gicon: this.mount.get_icon(),
icon_size: this.ICON_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 });
@ -557,7 +587,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);
@ -599,5 +629,5 @@ const AutorunTransientNotification = new Lang.Class({
return button; return button;
} }
}); }

View File

@ -21,9 +21,11 @@ const POPUP_ANIMATION_TIME = 0.15;
* placed. The arrow position may be controlled via setArrowOrigin(). * placed. The arrow position may be controlled via setArrowOrigin().
* *
*/ */
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._arrowOrigin = 0; this._arrowOrigin = 0;
@ -45,21 +47,6 @@ 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) {
@ -90,11 +77,7 @@ 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();
if (onComplete)
onComplete();
}),
time: POPUP_ANIMATION_TIME }); time: POPUP_ANIMATION_TIME });
}, },
@ -121,8 +104,6 @@ const BoxPointer = new Lang.Class({
} }
} }
this._muteInput();
Tweener.addTween(this, { opacity: 0, Tweener.addTween(this, { opacity: 0,
xOffset: xOffset, xOffset: xOffset,
yOffset: yOffset, yOffset: yOffset,
@ -471,4 +452,4 @@ const BoxPointer = new Lang.Class({
get opacity() { get opacity() {
return this.actor.opacity; return this.actor.opacity;
} }
}); };

View File

@ -1,5 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const DBus = imports.dbus;
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const Lang = imports.lang; const Lang = imports.lang;
@ -155,24 +156,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,32 +192,33 @@ 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 = {
<method name="GetEvents"> name: 'org.gnome.Shell.CalendarServer',
<arg type="x" direction="in" /> methods: [{ name: 'GetEvents',
<arg type="x" direction="in" /> inSignature: 'xxb',
<arg type="b" direction="in" /> outSignature: 'a(sssbxxa{sv})' }],
<arg type="a(sssbxxa{sv})" direction="out" /> signals: [{ name: 'Changed',
</method> inSignature: '' }]
<signal name="Changed" /> };
</interface>;
const CalendarServerInfo = Gio.DBusInterfaceInfo.new_for_xml(CalendarServerIface); const CalendarServer = function () {
this._init();
};
function CalendarServer() { CalendarServer.prototype = {
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.session, _init: function() {
g_interface_name: CalendarServerInfo.name, DBus.session.proxifyObject(this, 'org.gnome.Shell.CalendarServer', '/org/gnome/Shell/CalendarServer');
g_interface_info: CalendarServerInfo, }
g_name: 'org.gnome.Shell.CalendarServer', };
g_object_path: '/org/gnome/Shell/CalendarServer',
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
self.init(null); DBus.proxifyPrototype(CalendarServer.prototype, CalendarServerIface);
return self;
// an implementation that reads data from a session bus service
function DBusEventSource(owner) {
this._init(owner);
} }
function _datesEqual(a, b) { function _datesEqual(a, b) {
@ -233,22 +239,18 @@ 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',
_init: function() { DBusEventSource.prototype = {
_init: function(owner) {
this._resetCache(); this._resetCache();
this._dbusProxy = new CalendarServer(); this._dbusProxy = new CalendarServer(owner);
this._dbusProxy.connectSignal('Changed', Lang.bind(this, this._onChanged)); this._dbusProxy.connect('Changed', Lang.bind(this, this._onChanged));
this._dbusProxy.connect('notify::g-name-owner', Lang.bind(this, function() { DBus.session.watch_name('org.gnome.Shell.CalendarServer',
if (this._dbusProxy.g_name_owner) false, // do not launch a name-owner if none exists
this._onNameAppeared(); Lang.bind(this, this._onNameAppeared),
else Lang.bind(this, this._onNameVanished));
this._onNameVanished();
}));
}, },
_resetCache: function() { _resetCache: function() {
@ -271,7 +273,7 @@ const DBusEventSource = new Lang.Class({
this._loadEvents(false); this._loadEvents(false);
}, },
_onEventsReceived: function([appointments]) { _onEventsReceived: function(appointments) {
let newEvents = []; let newEvents = [];
if (appointments != null) { if (appointments != null) {
for (let n = 0; n < appointments.length; n++) { for (let n = 0; n < appointments.length; n++) {
@ -294,9 +296,9 @@ const DBusEventSource = new Lang.Class({
_loadEvents: function(forceReload) { _loadEvents: function(forceReload) {
if (this._curRequestBegin && this._curRequestEnd){ if (this._curRequestBegin && this._curRequestEnd){
let callFlags = Gio.DBusCallFlags.NO_AUTO_START; let callFlags = 0;
if (forceReload) if (forceReload)
callFlags = Gio.DBusCallFlags.NONE; callFlags |= DBus.CALL_FLAG_START;
this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000, this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
this._curRequestEnd.getTime() / 1000, this._curRequestEnd.getTime() / 1000,
forceReload, forceReload,
@ -337,15 +339,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 +410,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();
@ -611,13 +615,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();
@ -685,7 +691,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);
@ -702,7 +708,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);
@ -748,4 +754,4 @@ const EventsList = new Lang.Class({
this._showOtherDay(this._date); this._showOtherDay(this._date);
} }
} }
}); };

View File

@ -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;
}
});

View File

@ -5,7 +5,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 Atk = imports.gi.Atk;
const Util = imports.misc.util; const Util = imports.misc.util;
const IconGrid = imports.ui.iconGrid; const IconGrid = imports.ui.iconGrid;
@ -21,18 +20,18 @@ function launchContact(id) {
/* This class represents a shown contact search result in the overview */ /* This class represents a shown contact search result in the overview */
const Contact = new Lang.Class({ function Contact(id) {
Name: 'Contact', this._init(id);
}
Contact.prototype = {
_init: function(id) { _init: function(id) {
this._contactSys = Shell.ContactSystem.get_default(); this._contactSys = Shell.ContactSystem.get_default();
this.individual = this._contactSys.get_individual(id); this.individual = this._contactSys.get_individual(id);
this.actor = new St.Bin({ style_class: 'contact', this.actor = new St.Bin({ style_class: 'contact',
reactive: true, reactive: true,
can_focus: true, track_hover: true });
track_hover: true,
accessible_role: Atk.Role.PUSH_BUTTON });
let content = new St.BoxLayout( { style_class: 'contact-content', let content = new St.BoxLayout( { style_class: 'contact-content',
vertical: false }); vertical: false });
@ -71,8 +70,6 @@ const Contact = new Lang.Class({
x_align: St.Align.START, x_align: St.Align.START,
y_align: St.Align.START }); y_align: St.Align.START });
this.actor.label_actor = aliasLabel;
let presence = this._createPresence(this.individual.presence_type); let presence = this._createPresence(this.individual.presence_type);
details.add(presence, { x_fill: false, details.add(presence, { x_fill: false,
y_fill: true, y_fill: true,
@ -98,30 +95,23 @@ const Contact = new Lang.Class({
text = _("Busy"); text = _("Busy");
iconName = 'user-busy'; iconName = 'user-busy';
break; break;
case Folks.PresenceType.OFFLINE: default:
text = _("Offline"); text = _("Offline");
iconName = 'user-offline'; iconName = 'user-offline';
break;
default:
text = '';
iconName = null;
} }
let box = new St.BoxLayout({ vertical: false,
style_class: 'contact-details-status' });
if (iconName) {
let icon = new St.Icon({ icon_name: iconName, let icon = new St.Icon({ icon_name: iconName,
icon_type: St.IconType.FULLCOLOR, icon_type: St.IconType.FULLCOLOR,
icon_size: 16, icon_size: 16,
style_class: 'contact-details-status-icon' }); 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, box.add(icon, { x_fill: true,
y_fill: false, y_fill: false,
x_align: St.Align.START, x_align: St.Align.START,
y_align: St.Align.START }); y_align: St.Align.START });
}
let label = new St.Label({ text: text });
box.add(label, { x_fill: true, box.add(label, { x_fill: true,
y_fill: false, y_fill: false,
@ -141,31 +131,30 @@ const Contact = new Lang.Class({
return tc.load_icon_name(null, 'avatar-default', St.IconType.FULLCOLOR, size); return tc.load_icon_name(null, 'avatar-default', St.IconType.FULLCOLOR, size);
} }
}, },
}); };
/* Searches for and returns contacts */ /* Searches for and returns contacts */
const ContactSearchProvider = new Lang.Class({ function ContactSearchProvider() {
Name: 'ContactSearchProvider', this._init();
Extends: Search.SearchProvider, }
ContactSearchProvider.prototype = {
__proto__: Search.SearchProvider.prototype,
_init: function() { _init: function() {
this.parent(_("CONTACTS")); Search.SearchProvider.prototype._init.call(this, _("CONTACTS"));
this._contactSys = Shell.ContactSystem.get_default(); this._contactSys = Shell.ContactSystem.get_default();
}, },
getResultMetas: function(ids) { getResultMeta: function(id) {
let metas = []; let contact = new Contact(id);
for (let i = 0; i < ids.length; i++) { return { 'id': id,
let contact = new Contact(ids[i]);
metas.push({ 'id': ids[i],
'name': contact.alias, 'name': contact.alias,
'createIcon': function(size) { 'createIcon': function(size) {
return contact.createIcon(size); return contact.createIcon(size);
} }
}); };
}
return metas;
}, },
getInitialResultSet: function(terms) { getInitialResultSet: function(terms) {
@ -193,4 +182,4 @@ const ContactSearchProvider = new Lang.Class({
activateResult: function(id, params) { activateResult: function(id, params) {
launchContact(id); launchContact(id);
} }
}); };

View File

@ -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 });
@ -183,7 +187,7 @@ const CtrlAltTabPopup = new Lang.Class({
let [childMinHeight, childNaturalHeight] = this._switcher.actor.get_preferred_height(primary.width - hPadding); let [childMinHeight, childNaturalHeight] = this._switcher.actor.get_preferred_height(primary.width - hPadding);
let [childMinWidth, childNaturalWidth] = this._switcher.actor.get_preferred_width(childNaturalHeight); let [childMinWidth, childNaturalWidth] = this._switcher.actor.get_preferred_width(childNaturalHeight);
childBox.x1 = Math.max(primary.x + leftPadding, primary.x + Math.floor((primary.width - childNaturalWidth) / 2)); childBox.x1 = Math.max(primary.x + leftPadding, primary.x + Math.floor((primary.width - childNaturalWidth) / 2));
childBox.x2 = Math.min(primary.x + primary.width - hPadding, childBox.x1 + childNaturalWidth); childBox.x2 = Math.min(primary.width - hPadding, childBox.x1 + childNaturalWidth);
childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2); childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
childBox.y2 = childBox.y1 + childNaturalHeight; childBox.y2 = childBox.y1 + childNaturalHeight;
this._switcher.actor.allocate(childBox, flags); this._switcher.actor.allocate(childBox, flags);
@ -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);
} }
}); };

View File

@ -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,65 +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 () {
this.label.opacity = 255;
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);
@ -215,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;
@ -274,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: 'dash-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;
@ -298,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,
@ -387,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) {
@ -435,51 +383,14 @@ 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)
}));
return item;
},
_onHover: function (item, display) { return item;
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() {
@ -505,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 });
@ -681,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++) {
@ -747,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)) {
@ -781,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)
@ -837,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();
@ -854,6 +762,6 @@ const Dash = new Lang.Class({
return true; return true;
} }
}); };
Signals.addSignalMethods(Dash.prototype); Signals.addSignalMethods(Dash.prototype);

View File

@ -8,7 +8,6 @@ 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;
@ -41,9 +40,12 @@ 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) { _init: function(params) {
params = Params.parse(params, { showEvents: true }); params = Params.parse(params, { showEvents: true });
@ -53,14 +55,9 @@ const DateMenuButton = new Lang.Class({
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
// all (so not accessible), so it doesn't make sense to set as
// role ATK_ROLE_MENU like other elements of the panel.
this.actor.accessible_role = Atk.Role.LABEL;
this._clock = new St.Label(); this._clock = new St.Label();
this.actor.add_actor(this._clock); this.actor.add_actor(this._clock);
@ -75,7 +72,6 @@ const DateMenuButton = new Lang.Class({
// Date // Date
this._date = new St.Label(); this._date = new St.Label();
this.actor.label_actor = this._date;
this._date.style_class = 'datemenu-date-label'; this._date.style_class = 'datemenu-date-label';
vbox.add(this._date); vbox.add(this._date);
@ -243,4 +239,4 @@ const DateMenuButton = new Lang.Class({
} }
} }
} }
}); };

View File

@ -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
View 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);
}
};

View File

@ -18,19 +18,19 @@
* 02111-1307, USA. * 02111-1307, USA.
*/ */
const DBus = imports.dbus;
const Lang = imports.lang; const Lang = imports.lang;
const Signals = imports.signals; const Signals = imports.signals;
const AccountsService = imports.gi.AccountsService; const AccountsService = imports.gi.AccountsService;
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib; const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk; const Gtk = imports.gi.Gtk;
const Pango = imports.gi.Pango; 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 GnomeSession = imports.misc.gnomeSession; const GnomeSession = imports.misc.gnomeSession
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;
@ -43,23 +43,22 @@ const _DIALOG_ICON_SIZE = 32;
const GSM_SESSION_MANAGER_LOGOUT_FORCE = 2; const GSM_SESSION_MANAGER_LOGOUT_FORCE = 2;
const EndSessionDialogIface = <interface name="org.gnome.SessionManager.EndSessionDialog"> const EndSessionDialogIface = {
<method name="Open"> name: 'org.gnome.SessionManager.EndSessionDialog',
<arg type="u" direction="in" /> methods: [{ name: 'Open',
<arg type="u" direction="in" /> inSignature: 'uuuao',
<arg type="u" direction="in" /> outSignature: ''
<arg type="ao" direction="in" /> }
</method> ],
<signal name="ConfirmedLogout" /> signals: [{ name: 'Canceled',
<signal name="ConfirmedReboot" /> inSignature: '',
<signal name="ConfirmedShutdown" /> }],
<signal name="Canceled" /> properties: []
<signal name="Closed" /> };
</interface>;
const logoutDialogContent = { const logoutDialogContent = {
subjectWithUser: C_("title", "Log Out %s"), subjectWithUser: _("Log Out %s"),
subject: C_("title", "Log Out"), subject: _("Log Out"),
inhibitedDescription: _("Click Log Out to quit these applications and log out of the system."), inhibitedDescription: _("Click Log Out to quit these applications and log out of the system."),
uninhibitedDescriptionWithUser: function(user, seconds) { uninhibitedDescriptionWithUser: function(user, seconds) {
return ngettext("%s will be logged out automatically in %d second.", return ngettext("%s will be logged out automatically in %d second.",
@ -73,12 +72,12 @@ const logoutDialogContent = {
}, },
endDescription: _("Logging out of the system."), endDescription: _("Logging out of the system."),
confirmButtons: [{ signal: 'ConfirmedLogout', confirmButtons: [{ signal: 'ConfirmedLogout',
label: C_("button", "Log Out") }], label: _("Log Out") }],
iconStyleClass: 'end-session-dialog-logout-icon' iconStyleClass: 'end-session-dialog-logout-icon'
}; };
const shutdownDialogContent = { const shutdownDialogContent = {
subject: C_("title", "Power Off"), subject: _("Power Off"),
inhibitedDescription: _("Click Power Off to quit these applications and power off the system."), inhibitedDescription: _("Click Power Off to quit these applications and power off the system."),
uninhibitedDescription: function(seconds) { uninhibitedDescription: function(seconds) {
return ngettext("The system will power off automatically in %d second.", return ngettext("The system will power off automatically in %d second.",
@ -87,15 +86,15 @@ const shutdownDialogContent = {
}, },
endDescription: _("Powering off the system."), endDescription: _("Powering off the system."),
confirmButtons: [{ signal: 'ConfirmedReboot', confirmButtons: [{ signal: 'ConfirmedReboot',
label: C_("button", "Restart") }, label: _("Restart") },
{ signal: 'ConfirmedShutdown', { signal: 'ConfirmedShutdown',
label: C_("button", "Power Off") }], label: _("Power Off") }],
iconName: 'system-shutdown', iconName: 'system-shutdown',
iconStyleClass: 'end-session-dialog-shutdown-icon' iconStyleClass: 'end-session-dialog-shutdown-icon'
}; };
const restartDialogContent = { const restartDialogContent = {
subject: C_("title", "Restart"), subject: _("Restart"),
inhibitedDescription: _("Click Restart to quit these applications and restart the system."), inhibitedDescription: _("Click Restart to quit these applications and restart the system."),
uninhibitedDescription: function(seconds) { uninhibitedDescription: function(seconds) {
return ngettext("The system will restart automatically in %d second.", return ngettext("The system will restart automatically in %d second.",
@ -104,7 +103,7 @@ const restartDialogContent = {
}, },
endDescription: _("Restarting the system."), endDescription: _("Restarting the system."),
confirmButtons: [{ signal: 'ConfirmedReboot', confirmButtons: [{ signal: 'ConfirmedReboot',
label: C_("button", "Restart") }], label: _("Restart") }],
iconName: 'system-shutdown', iconName: 'system-shutdown',
iconStyleClass: 'end-session-dialog-shutdown-icon' iconStyleClass: 'end-session-dialog-shutdown-icon'
}; };
@ -116,17 +115,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;
@ -172,7 +191,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
@ -210,19 +229,29 @@ function _setLabelText(label, text) {
} }
} }
function EndSessionDialog() {
if (_endSessionDialog == null) {
this._init();
DBus.session.exportObject('/org/gnome/SessionManager/EndSessionDialog',
this);
_endSessionDialog = this;
}
return _endSessionDialog;
}
function init() { 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());
@ -297,9 +326,6 @@ const EndSessionDialog = new Lang.Class({
if (this._applicationList.get_children().length == 0) if (this._applicationList.get_children().length == 0)
scrollView.hide(); scrollView.hide();
})); }));
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(EndSessionDialogIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog');
}, },
_onDestroy: function() { _onDestroy: function() {
@ -315,8 +341,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();
} }
@ -414,20 +439,26 @@ const EndSessionDialog = new Lang.Class({
}, },
close: function() { close: function() {
this.parent(); ModalDialog.ModalDialog.prototype.close.call(this);
this._dbusImpl.emit_signal('Closed', null); DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
'org.gnome.SessionManager.EndSessionDialog',
'Closed', '', []);
}, },
cancel: function() { cancel: function() {
this._stopTimer(); this._stopTimer();
this._dbusImpl.emit_signal('Canceled', null); DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
'org.gnome.SessionManager.EndSessionDialog',
'Canceled', '', []);
this.close(global.get_current_time()); this.close(global.get_current_time());
}, },
_confirm: function(signal) { _confirm: function(signal) {
this._fadeOutDialog(); this._fadeOutDialog();
this._stopTimer(); this._stopTimer();
this._dbusImpl.emit_signal(signal, null); DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
'org.gnome.SessionManager.EndSessionDialog',
signal, '', []);
}, },
_onOpened: function() { _onOpened: function() {
@ -464,8 +495,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());
@ -480,41 +510,39 @@ const EndSessionDialog = new Lang.Class({
this._updateContent(); this._updateContent();
}, },
OpenAsync: function(parameters, invocation) { OpenAsync: function(type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths, callback) {
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', throw new DBus.DBusError('org.gnome.Shell.ModalDialog.TypeError',
"Unknown dialog type requested"); "Unknown dialog type requested");
return;
}
for (let i = 0; i < inhibitorObjectPaths.length; i++) { for (let i = 0; i < inhibitorObjectPaths.length; i++) {
let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i], Lang.bind(this, function(proxy, error) { let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i]);
this._onInhibitorLoaded(proxy);
}));
inhibitor.connect('is-loaded',
Lang.bind(this, function() {
this._onInhibitorLoaded(inhibitor);
}));
this._inhibitors.push(inhibitor); this._inhibitors.push(inhibitor);
} }
this._updateButtons(); this._updateButtons();
if (!this.open(timestamp)) { if (!this.open(timestamp))
invocation.return_dbus_error('org.gnome.Shell.ModalDialog.GrabError', throw new DBus.DBusError('org.gnome.Shell.ModalDialog.GrabError',
"Cannot grab pointer and keyboard"); "Cannot grab pointer and keyboard");
return;
}
this._updateContent(); this._updateContent();
let signalId = this.connect('opened', let signalId = this.connect('opened',
Lang.bind(this, function() { Lang.bind(this, function() {
invocation.return_value(null); callback();
this.disconnect(signalId); this.disconnect(signalId);
})); }));
} }
}); };
DBus.conformExport(EndSessionDialog.prototype, EndSessionDialogIface);

View File

@ -48,6 +48,11 @@ function init() {
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);
@ -59,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

View File

@ -11,7 +11,6 @@ const Shell = imports.gi.Shell;
const Soup = imports.gi.Soup; const Soup = imports.gi.Soup;
const Config = imports.misc.config; const Config = imports.misc.config;
const ExtensionUtils = imports.misc.extensionUtils;
const FileUtils = imports.misc.fileUtils; const FileUtils = imports.misc.fileUtils;
const ModalDialog = imports.ui.modalDialog; const ModalDialog = imports.ui.modalDialog;
@ -23,13 +22,17 @@ const ExtensionState = {
ERROR: 3, ERROR: 3,
OUT_OF_DATE: 4, OUT_OF_DATE: 4,
DOWNLOADING: 5, DOWNLOADING: 5,
INITIALIZED: 6,
// Used as an error state for operations on unknown extensions, // Used as an error state for operations on unknown extensions,
// should never be in a real extensionMeta object. // should never be in a real extensionMeta object.
UNINSTALLED: 99 UNINSTALLED: 99
}; };
const ExtensionType = {
SYSTEM: 1,
PER_USER: 2
};
const REPOSITORY_URL_BASE = 'https://extensions.gnome.org'; const REPOSITORY_URL_BASE = 'https://extensions.gnome.org';
const REPOSITORY_URL_DOWNLOAD = REPOSITORY_URL_BASE + '/download-extension/%s.shell-extension.zip'; 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_INFO = REPOSITORY_URL_BASE + '/extension-info/';
@ -53,10 +56,16 @@ function _getCertFile() {
_httpSession.ssl_ca_file = _getCertFile(); _httpSession.ssl_ca_file = _getCertFile();
// Maps uuid -> metadata object
const extensionMeta = {};
// Maps uuid -> importer object (extension directory tree)
const extensions = {};
// Maps uuid -> extension state object (returned from init())
const extensionStateObjs = {};
// Arrays of uuids // Arrays of uuids
var enabledExtensions; var enabledExtensions;
// Contains the order that extensions were enabled in. // GFile for user extensions
const extensionOrder = []; 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
@ -67,8 +76,41 @@ 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) { function installExtensionFromUUID(uuid, version_tag) {
let params = { uuid: uuid, let params = { uuid: uuid,
version_tag: version_tag, version_tag: version_tag,
@ -86,8 +128,8 @@ function installExtensionFromUUID(uuid, version_tag) {
} }
function uninstallExtensionFromUUID(uuid) { function uninstallExtensionFromUUID(uuid) {
let extension = ExtensionUtils.extensions[uuid]; let meta = extensionMeta[uuid];
if (!extension) if (!meta)
return false; return false;
// Try to disable it -- if it's ERROR'd, we can't guarantee that, // Try to disable it -- if it's ERROR'd, we can't guarantee that,
@ -96,15 +138,22 @@ function uninstallExtensionFromUUID(uuid) {
disableExtension(uuid); disableExtension(uuid);
// Don't try to uninstall system extensions // Don't try to uninstall system extensions
if (extension.type != ExtensionUtils.ExtensionType.PER_USER) if (meta.type != ExtensionType.PER_USER)
return false; return false;
extension.state = ExtensionState.UNINSTALLED; meta.state = ExtensionState.UNINSTALLED;
_signals.emit('extension-state-changed', extension); _signals.emit('extension-state-changed', meta);
delete ExtensionUtils.extensions[uuid]; delete extensionMeta[uuid];
FileUtils.recursivelyDeleteDir(Gio.file_new_for_path(extension.path)); // 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; return true;
} }
@ -125,7 +174,7 @@ function gotExtensionZipFile(session, message, uuid) {
} }
let stream = new Gio.UnixOutputStream({ fd: fd }); let stream = new Gio.UnixOutputStream({ fd: fd });
let dir = ExtensionUtils.userExtensionsDir.get_child(uuid); let dir = userExtensionsDir.get_child(uuid);
Shell.write_soup_message_to_stream(stream, message); Shell.write_soup_message_to_stream(stream, message);
stream.close(null); stream.close(null);
let [success, pid] = GLib.spawn_async(null, let [success, pid] = GLib.spawn_async(null,
@ -149,94 +198,55 @@ function gotExtensionZipFile(session, message, uuid) {
global.settings.set_strv(ENABLED_EXTENSIONS_KEY, enabledExtensions); global.settings.set_strv(ENABLED_EXTENSIONS_KEY, enabledExtensions);
} }
loadExtension(dir, ExtensionUtils.ExtensionType.PER_USER, true); 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;
// "Rebase" the extension order by disabling and then enabling extensions let extensionState = extensionStateObjs[uuid];
// in order to help prevent conflicts.
// Example:
// order = [A, B, C, D, E]
// user disables C
// this should: disable E, disable D, disable C, enable D, enable E
let orderIdx = extensionOrder.indexOf(uuid);
let order = extensionOrder.slice(orderIdx + 1);
let orderReversed = order.slice().reverse();
for (let i = 0; i < orderReversed.length; i++) {
let uuid = orderReversed[i];
try {
ExtensionUtils.extensions[uuid].stateObj.disable();
} catch(e) {
logExtensionError(uuid, e.toString());
}
}
try { try {
extension.stateObj.disable(); extensionState.disable();
} catch(e) { } catch(e) {
logExtensionError(uuid, e.toString()); logExtensionError(uuid, e.toString());
return; return;
} }
for (let i = 0; i < order.length; i++) { meta.state = ExtensionState.DISABLED;
let uuid = order[i]; _signals.emit('extension-state-changed', meta);
try {
ExtensionUtils.extensions[uuid].stateObj.enable();
} catch(e) {
logExtensionError(uuid, e.toString());
}
}
extensionOrder.splice(orderIdx, 1);
extension.state = ExtensionState.DISABLED;
_signals.emit('extension-state-changed', extension);
} }
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.DISABLED)
initExtension(uuid);
if (extension.state != ExtensionState.DISABLED)
return; return;
extensionOrder.push(uuid); let extensionState = extensionStateObjs[uuid];
try { try {
extension.stateObj.enable(); extensionState.enable();
} catch(e) { } catch(e) {
logExtensionError(uuid, e.toString()); logExtensionError(uuid, e.toString());
return; return;
} }
extension.state = ExtensionState.ENABLED; meta.state = ExtensionState.ENABLED;
_signals.emit('extension-state-changed', extension); _signals.emit('extension-state-changed', meta);
} }
function logExtensionError(uuid, message, state) { function logExtensionError(uuid, message, state) {
let extension = ExtensionUtils.extensions[uuid]; if (!errors[uuid]) errors[uuid] = [];
if (!extension) errors[uuid].push(message);
return;
if (!extension.errors)
extension.errors = [];
extension.errors.push(message);
global.logError('Extension "%s" had error: %s'.format(uuid, message)); global.logError('Extension "%s" had error: %s'.format(uuid, message));
state = state || ExtensionState.ERROR; state = state || ExtensionState.ERROR;
_signals.emit('extension-state-changed', { uuid: uuid, _signals.emit('extension-state-changed', { uuid: uuid,
@ -244,50 +254,76 @@ function logExtensionError(uuid, message, state) {
state: state }); state: state });
} }
function loadExtension(dir, type, enabled) { function loadExtension(dir, enabled, type) {
let info;
let uuid = dir.get_basename(); let uuid = dir.get_basename();
let extension;
if (ExtensionUtils.extensions[uuid] != undefined) { let metadataFile = dir.get_child('metadata.json');
global.logError('Extension "%s" is already loaded'.format(uuid)); if (!metadataFile.query_exists(null)) {
logExtensionError(uuid, 'Missing metadata.json');
return; return;
} }
let metadataContents;
try { try {
extension = ExtensionUtils.createExtensionObject(uuid, dir, type); metadataContents = Shell.get_file_contents_utf8_sync(metadataFile.get_path());
} catch(e) { } catch (e) {
logExtensionError(uuid, e.message); logExtensionError(uuid, 'Failed to load metadata.json: ' + e);
return; return;
} }
let meta;
try {
meta = JSON.parse(metadataContents);
} catch (e) {
logExtensionError(uuid, 'Failed to parse metadata.json: ' + e);
return;
}
let requiredProperties = ['uuid', 'name', 'description', 'shell-version'];
for (let i = 0; i < requiredProperties.length; i++) {
let prop = requiredProperties[i];
if (!meta[prop]) {
logExtensionError(uuid, 'missing "' + prop + '" property in metadata.json');
return;
}
}
if (extensions[uuid] != undefined) {
logExtensionError(uuid, 'extension already loaded');
return;
}
// Encourage people to add this
if (!meta['url']) {
global.log('Warning: Missing "url" property in metadata.json');
}
if (uuid != meta.uuid) {
logExtensionError(uuid, 'uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"');
return;
}
if (!versionCheck(meta['shell-version'], Config.PACKAGE_VERSION) ||
(meta['js-version'] && !versionCheck(meta['js-version'], Config.GJS_VERSION))) {
logExtensionError(uuid, 'extension is not compatible with current GNOME Shell and/or GJS version');
return;
}
extensionMeta[uuid] = meta;
meta.type = type;
meta.path = dir.get_path();
meta.error = '';
// 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) ||
(meta['js-version'] && !versionCheck(meta['js-version'], Config.GJS_VERSION))) {
logExtensionError(uuid, 'extension is not compatible with current GNOME Shell and/or GJS version', ExtensionState.OUT_OF_DATE); logExtensionError(uuid, 'extension is not compatible with current GNOME Shell and/or GJS version', ExtensionState.OUT_OF_DATE);
extension.state = ExtensionState.OUT_OF_DATE; meta.state = ExtensionState.OUT_OF_DATE;
return; return;
} }
if (enabled) {
initExtension(uuid);
if (extension.state == ExtensionState.DISABLED)
enableExtension(uuid);
} else {
extension.state = ExtensionState.INITIALIZED;
}
_signals.emit('extension-state-changed', extension);
global.log('Loaded extension ' + uuid);
}
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)) {
logExtensionError(uuid, 'Missing extension.js'); logExtensionError(uuid, 'Missing extension.js');
@ -309,12 +345,12 @@ function initExtension(uuid) {
let extensionModule; let extensionModule;
let extensionState = null; let extensionState = null;
try { try {
ExtensionUtils.installImporter(extension); global.add_extension_importer('imports.ui.extensionSystem.extensions', meta.uuid, dir.get_path());
extensionModule = extension.imports.extension; extensionModule = extensions[meta.uuid].extension;
} catch (e) { } catch (e) {
if (stylesheetPath != null) if (stylesheetPath != null)
theme.unload_stylesheet(stylesheetPath); theme.unload_stylesheet(stylesheetPath);
logExtensionError(uuid, '' + e); logExtensionError(uuid, e);
return; return;
} }
@ -324,7 +360,7 @@ function initExtension(uuid) {
} }
try { try {
extensionState = extensionModule.init(extension); extensionState = extensionModule.init(meta);
} catch (e) { } catch (e) {
if (stylesheetPath != null) if (stylesheetPath != null)
theme.unload_stylesheet(stylesheetPath); theme.unload_stylesheet(stylesheetPath);
@ -334,7 +370,7 @@ function initExtension(uuid) {
if (!extensionState) if (!extensionState)
extensionState = extensionModule; extensionState = extensionModule;
extension.stateObj = extensionState; extensionStateObjs[uuid] = extensionState;
if (!extensionState.enable) { if (!extensionState.enable) {
logExtensionError(uuid, 'missing \'enable\' function'); logExtensionError(uuid, 'missing \'enable\' function');
@ -345,9 +381,14 @@ function initExtension(uuid) {
return; return;
} }
extension.state = ExtensionState.DISABLED; meta.state = ExtensionState.DISABLED;
_signals.emit('extension-loaded', uuid); if (enabled)
enableExtension(uuid);
_signals.emit('extension-loaded', meta.uuid);
_signals.emit('extension-state-changed', meta);
global.log('Loaded extension ' + meta.uuid);
} }
function onEnabledExtensionsChanged() { function onEnabledExtensionsChanged() {
@ -373,25 +414,61 @@ function onEnabledExtensionsChanged() {
} }
function init() { function init() {
ExtensionUtils.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);
} }
function loadExtensions() { function _loadExtensionsIn(dir, type) {
ExtensionUtils.scanExtensions(function(uuid, dir, type) { let fileEnum;
let enabled = enabledExtensions.indexOf(uuid) != -1; let file, info;
loadExtension(dir, type, enabled); try {
}); fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
} catch (e) {
global.logError('' + e);
return;
}
while ((info = fileEnum.next_file(null)) != null) {
let fileType = info.get_file_type();
if (fileType != Gio.FileType.DIRECTORY)
continue;
let name = info.get_name();
let child = dir.get_child(name);
let enabled = enabledExtensions.indexOf(name) != -1;
loadExtension(child, enabled, type);
}
fileEnum.close(null);
} }
const InstallExtensionDialog = new Lang.Class({ function loadExtensions() {
Name: 'InstallExtensionDialog', let systemDataDirs = GLib.get_system_data_dirs();
Extends: ModalDialog.ModalDialog, 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) { _init: function(uuid, version_tag, name) {
this.parent({ styleClass: 'extension-dialog' }); ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'extension-dialog' });
this._uuid = uuid; this._uuid = uuid;
this._version_tag = version_tag; this._version_tag = version_tag;
@ -429,11 +506,13 @@ const InstallExtensionDialog = new Lang.Class({
}, },
_onInstallButtonPressed: function(button, event) { _onInstallButtonPressed: function(button, event) {
let state = { uuid: this._uuid, let meta = { uuid: this._uuid,
state: ExtensionState.DOWNLOADING, state: ExtensionState.DOWNLOADING,
error: '' }; error: '' };
_signals.emit('extension-state-changed', state); extensionMeta[this._uuid] = meta;
_signals.emit('extension-state-changed', meta);
let params = { version_tag: this._version_tag, let params = { version_tag: this._version_tag,
shell_version: Config.PACKAGE_VERSION, shell_version: Config.PACKAGE_VERSION,
@ -449,4 +528,4 @@ const InstallExtensionDialog = new Lang.Class({
this.close(global.get_current_time()); this.close(global.get_current_time());
} }
}); };

View File

@ -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();
})
});
}
});

View File

@ -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() {
@ -146,13 +147,20 @@ const BaseIcon = new Lang.Class({
size = found ? len : ICON_SIZE; size = found ? len : ICON_SIZE;
} }
// don't create icons unnecessarily
if (size == this.iconSize &&
this._iconBin.child)
return;
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 +173,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 +192,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 +215,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 +248,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 +278,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;
} }
} }
}, },
@ -286,8 +294,8 @@ const IconGrid = new Lang.Class({
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;
} }
@ -300,8 +308,7 @@ 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();
}, },
@ -322,4 +329,4 @@ const IconGrid = new Lang.Class({
visibleItemsCount: function() { visibleItemsCount: function() {
return this._grid.get_children().length - this._grid.get_n_skip_paint(); return this._grid.get_children().length - this._grid.get_n_skip_paint();
} }
}); };

View File

@ -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;
@ -189,15 +192,15 @@ const Key = new Lang.Class({
this._boxPointer.hide(true); 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));
@ -291,7 +289,7 @@ const Keyboard = new Lang.Class({
if (focus && (focus._extended_keys || (focus._key && focus._key.extended_key))) if (focus && (focus._extended_keys || (focus._key && focus._key.extended_key)))
return; return;
let time = global.get_current_time(); let time = global.current_event_time();
if (focus instanceof Clutter.Text) if (focus instanceof Clutter.Text)
this.Show(time); this.Show(time);
else else
@ -534,15 +532,19 @@ 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.parent(_("Keyboard"));
this._keyboard = keyboard; this._keyboard = keyboard;
MessageTray.Source.prototype._init.call(this, _("Keyboard"));
this._setSummaryIcon(this.createNotificationIcon()); this._setSummaryIcon(this.createNotificationIcon());
}, },
@ -565,4 +567,4 @@ const KeyboardSource = new Lang.Class({
open: function() { open: function() {
this._keyboard.show(); this._keyboard.show();
} }
}); };

View File

@ -1,207 +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)
}]
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);
}

View File

@ -8,7 +8,6 @@ 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 ScreenSaver = imports.misc.screenSaver;
@ -18,11 +17,13 @@ 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;
@ -373,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);
@ -381,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
@ -405,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 {
@ -434,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);
@ -457,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;
@ -491,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() {
@ -547,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
@ -560,9 +561,11 @@ const defaultParams = {
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;
@ -584,12 +587,11 @@ const Chrome = new Lang.Class({
this._screenSaverActive = false; this._screenSaverActive = false;
this._screenSaverProxy = new ScreenSaver.ScreenSaverProxy(); this._screenSaverProxy = new ScreenSaver.ScreenSaverProxy();
this._screenSaverProxy.connectSignal('ActiveChanged', Lang.bind(this, function(proxy, senderName, [isActive]) { this._screenSaverProxy.connect('ActiveChanged', Lang.bind(this, this._onScreenSaverActiveChanged));
this._onScreenSaverActiveChanged(isActive); this._screenSaverProxy.GetActiveRemote(Lang.bind(this,
})); function(result, err) {
this._screenSaverProxy.GetActiveRemote(Lang.bind(this, function(result, err) {
if (!err) if (!err)
this._onScreenSaverActiveChanged(result[0]); this._onScreenSaverActiveChanged(this._screenSaverProxy, result);
})); }));
this._relayout(); this._relayout();
@ -731,7 +733,7 @@ const Chrome = new Lang.Class({
this._queueUpdateRegions(); this._queueUpdateRegions();
}, },
_onScreenSaverActiveChanged: function(screenSaverActive) { _onScreenSaverActiveChanged: function(proxy, screenSaverActive) {
this._screenSaverActive = screenSaverActive; this._screenSaverActive = screenSaverActive;
this._updateVisibility(); this._updateVisibility();
this._queueUpdateRegions(); this._queueUpdateRegions();
@ -978,4 +980,4 @@ const Chrome = new Lang.Class({
return false; return false;
} }
}); };

View File

@ -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;
@ -31,9 +30,11 @@ const Tweener = imports.ui.tweener;
* @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,
@ -58,10 +59,11 @@ const Lightbox = new Lang.Class({
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));
@ -70,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);
@ -177,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);
} }
}); };

View File

@ -4,9 +4,11 @@ const Lang = imports.lang;
const Signals = imports.signals; const Signals = imports.signals;
const St = imports.gi.St; const St = imports.gi.St;
const Link = new Lang.Class({ function Link(props) {
Name: 'Link', this._init(props);
}
Link.prototype = {
_init : function(props) { _init : function(props) {
let realProps = { reactive: true, let realProps = { reactive: true,
track_hover: true, track_hover: true,
@ -17,5 +19,6 @@ const Link = new Lang.Class({
this.actor = new St.Button(realProps); this.actor = new St.Button(realProps);
} }
}); };
Signals.addSignalMethods(Link.prototype); Signals.addSignalMethods(Link.prototype);

View File

@ -2,6 +2,7 @@
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const Cogl = imports.gi.Cogl; const Cogl = imports.gi.Cogl;
const GConf = imports.gi.GConf;
const GLib = imports.gi.GLib; const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk; const Gtk = imports.gi.Gtk;
@ -15,12 +16,10 @@ const Mainloop = imports.mainloop;
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 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;
/* 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; ' +
@ -42,88 +41,12 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
'const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); '; 'const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); ';
const HISTORY_KEY = 'looking-glass-history'; const HISTORY_KEY = 'looking-glass-history';
// Time between tabs for them to count as a double-tab event
const AUTO_COMPLETE_DOUBLE_TAB_DELAY = 500;
const AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION = 0.2;
const AUTO_COMPLETE_GLOBAL_KEYWORDS = _getAutoCompleteGlobalKeywords();
function _getAutoCompleteGlobalKeywords() { function Notebook() {
const keywords = ['true', 'false', 'null', 'new']; this._init();
// Don't add the private properties of window (i.e., ones starting with '_')
const windowProperties = Object.getOwnPropertyNames(window).filter(function(a){ return a.charAt(0) != '_' });
const headerProperties = JsParse.getDeclaredConstants(commandHeader);
return keywords.concat(windowProperties).concat(headerProperties);
} }
const AutoComplete = new Lang.Class({ Notebook.prototype = {
Name: 'AutoComplete',
_init: function(entry) {
this._entry = entry;
this._entry.connect('key-press-event', Lang.bind(this, this._entryKeyPressEvent));
this._lastTabTime = global.get_current_time();
},
_processCompletionRequest: function(event) {
if (event.completions.length == 0) {
return;
}
// Unique match = go ahead and complete; multiple matches + single tab = complete the common starting string;
// multiple matches + double tab = emit a suggest event with all possible options
if (event.completions.length == 1) {
this.additionalCompletionText(event.completions[0], event.attrHead);
this.emit('completion', { completion: event.completions[0], type: 'whole-word' });
} else if (event.completions.length > 1 && event.tabType === 'single') {
let commonPrefix = JsParse.getCommonPrefix(event.completions);
if (commonPrefix.length > 0) {
this.additionalCompletionText(commonPrefix, event.attrHead);
this.emit('completion', { completion: commonPrefix, type: 'prefix' });
this.emit('suggest', { completions: event.completions});
}
} else if (event.completions.length > 1 && event.tabType === 'double') {
this.emit('suggest', { completions: event.completions});
}
},
_entryKeyPressEvent: function(actor, event) {
let cursorPos = this._entry.clutter_text.get_cursor_position();
let text = this._entry.get_text();
if (cursorPos != -1) {
text = text.slice(0, cursorPos);
}
if (event.get_key_symbol() == Clutter.Tab) {
let [completions, attrHead] = JsParse.getCompletions(text, commandHeader, AUTO_COMPLETE_GLOBAL_KEYWORDS);
let currTime = global.get_current_time();
if ((currTime - this._lastTabTime) < AUTO_COMPLETE_DOUBLE_TAB_DELAY) {
this._processCompletionRequest({ tabType: 'double',
completions: completions,
attrHead: attrHead });
} else {
this._processCompletionRequest({ tabType: 'single',
completions: completions,
attrHead: attrHead });
}
this._lastTabTime = currTime;
}
},
// Insert characters of text not already included in head at cursor position. i.e., if text="abc" and head="a",
// the string "bc" will be appended to this._entry
additionalCompletionText: function(text, head) {
let additionalCompletionText = text.slice(head.length);
let cursorPos = this._entry.clutter_text.get_cursor_position();
this._entry.clutter_text.insert_text(additionalCompletionText, cursorPos);
}
});
Signals.addSignalMethods(AutoComplete.prototype);
const Notebook = new Lang.Class({
Name: 'Notebook',
_init: function() { _init: function() {
this.actor = new St.BoxLayout({ vertical: true }); this.actor = new St.BoxLayout({ vertical: true });
@ -228,26 +151,8 @@ const Notebook = new Lang.Class({
return; return;
let vAdjust = tabData.scrollView.vscroll.adjustment; let vAdjust = tabData.scrollView.vscroll.adjustment;
vAdjust.value = vAdjust.upper - vAdjust.page_size; vAdjust.value = vAdjust.upper - vAdjust.page_size;
},
nextTab: function() {
let nextIndex = this._selectedIndex;
if (nextIndex < this._tabs.length - 1) {
++nextIndex;
} }
};
this.selectIndex(nextIndex);
},
prevTab: function() {
let prevIndex = this._selectedIndex;
if (prevIndex > 0) {
--prevIndex;
}
this.selectIndex(prevIndex);
}
});
Signals.addSignalMethods(Notebook.prototype); Signals.addSignalMethods(Notebook.prototype);
function objectToString(o) { function objectToString(o) {
@ -259,9 +164,12 @@ function objectToString(o) {
} }
} }
const ObjLink = new Lang.Class({ function ObjLink(o, title) {
Name: 'ObjLink', this._init(o, title);
Extends: Link.Link, }
ObjLink.prototype = {
__proto__: Link.Link,
_init: function(o, title) { _init: function(o, title) {
let text; let text;
@ -271,8 +179,7 @@ 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.parent({ 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));
}, },
@ -280,11 +187,13 @@ const ObjLink = new Lang.Class({
_onClicked: function (link) { _onClicked: function (link) {
Main.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);
}
Result.prototype = {
_init : function(command, o, index) { _init : function(command, o, index) {
this.index = index; this.index = index;
this.o = o; this.o = o;
@ -306,11 +215,13 @@ const Result = new Lang.Class({
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();
}
WindowList.prototype = {
_init : function () { _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();
@ -351,12 +262,14 @@ const WindowList = new Lang.Class({
} }
} }
} }
}); };
Signals.addSignalMethods(WindowList.prototype); Signals.addSignalMethods(WindowList.prototype);
const ObjInspector = new Lang.Class({ function ObjInspector() {
Name: 'ObjInspector', this._init();
}
ObjInspector.prototype = {
_init : function () { _init : function () {
this._obj = null; this._obj = null;
this._previousObj = null; this._previousObj = null;
@ -400,14 +313,7 @@ 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 {
@ -463,7 +369,7 @@ const ObjInspector = new Lang.Class({
_onBack: function() { _onBack: function() {
this.selectObject(this._previousObj, true); this.selectObject(this._previousObj, true);
} }
}); };
function addBorderPaintHook(actor) { function addBorderPaintHook(actor) {
let signalId = actor.connect_after('paint', let signalId = actor.connect_after('paint',
@ -489,9 +395,11 @@ function addBorderPaintHook(actor) {
return signalId; return signalId;
} }
const Inspector = new Lang.Class({ function Inspector() {
Name: 'Inspector', this._init();
}
Inspector.prototype = {
_init: function() { _init: function() {
let container = new Shell.GenericContainer({ width: 0, let container = new Shell.GenericContainer({ width: 0,
height: 0 }); height: 0 });
@ -630,13 +538,15 @@ const Inspector = new Lang.Class({
this._borderPaintId = addBorderPaintHook(this._target); this._borderPaintId = addBorderPaintHook(this._target);
} }
} }
}); };
Signals.addSignalMethods(Inspector.prototype); Signals.addSignalMethods(Inspector.prototype);
const ErrorLog = new Lang.Class({ function ErrorLog() {
Name: 'ErrorLog', this._init();
}
ErrorLog.prototype = {
_init: function() { _init: function() {
this.actor = new St.BoxLayout(); this.actor = new St.BoxLayout();
this.text = new St.Label(); this.text = new St.Label();
@ -671,11 +581,13 @@ const ErrorLog = new Lang.Class({
} }
this.text.text = text; this.text.text = text;
} }
}); };
const Memory = new Lang.Class({ function Memory() {
Name: '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();
@ -720,11 +632,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' });
@ -736,7 +650,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',
@ -744,10 +658,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);
@ -759,52 +673,24 @@ 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());
Main.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());
Main.lookingGlass.close(); Main.lookingGlass.close();
}, },
_onViewErrors: function (actor) {
let extension = actor._extension;
let shouldShow = !actor._isShowing;
if (shouldShow) {
let errors = extension.errors;
let errorDisplay = new St.BoxLayout({ vertical: true });
if (errors && errors.length) {
for (let i = 0; i < errors.length; i ++)
errorDisplay.add(new St.Label({ text: errors[i] }));
} else {
/* Translators: argument is an extension UUID. */
let message = _("%s has not emitted any errors.").format(extension.uuid);
errorDisplay.add(new St.Label({ text: message }));
}
actor._errorDisplay = errorDisplay;
actor._parentBox.add(errorDisplay);
actor.label = _("Hide Errors");
} else {
actor._errorDisplay.destroy();
actor._errorDisplay = null;
actor.label = _("Show Errors");
}
actor._isShowing = shouldShow;
},
_stateToString: function(extensionState) { _stateToString: function(extensionState) {
switch (extensionState) { switch (extensionState) {
case ExtensionSystem.ExtensionState.ENABLED: case ExtensionSystem.ExtensionState.ENABLED:
return _("Enabled"); return _("Enabled");
case ExtensionSystem.ExtensionState.DISABLED: case ExtensionSystem.ExtensionState.DISABLED:
case ExtensionSystem.ExtensionState.INITIALIZED:
return _("Disabled"); return _("Disabled");
case ExtensionSystem.ExtensionState.ERROR: case ExtensionSystem.ExtensionState.ERROR:
return _("Error"); return _("Error");
@ -816,48 +702,43 @@ 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 Link.Link({ label: _("View Source") }); let viewsource = new Link.Link({ label: _("View Source") });
viewsource.actor._extension = extension; viewsource.actor._extensionMeta = meta;
viewsource.actor.connect('clicked', Lang.bind(this, this._onViewSource)); viewsource.actor.connect('clicked', Lang.bind(this, this._onViewSource));
metaBox.add(viewsource.actor); metaBox.add(viewsource.actor);
if (extension.metadata.url) { if (meta.url) {
let webpage = new Link.Link({ label: _("Web Page") }); let webpage = new Link.Link({ label: _("Web Page") });
webpage.actor._extension = extension; webpage.actor._extensionMeta = meta;
webpage.actor.connect('clicked', Lang.bind(this, this._onWebPage)); webpage.actor.connect('clicked', Lang.bind(this, this._onWebPage));
metaBox.add(webpage.actor); metaBox.add(webpage.actor);
} }
let viewerrors = new Link.Link({ label: _("Show Errors") });
viewerrors.actor._extension = extension;
viewerrors.actor._parentBox = box;
viewerrors.actor._isShowing = false;
viewerrors.actor.connect('clicked', Lang.bind(this, this._onViewErrors));
metaBox.add(viewerrors.actor);
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._borderPaintId = 0; this._borderPaintId = 0;
@ -874,8 +755,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' });
@ -930,15 +810,15 @@ const LookingGlass = new Lang.Class({
this._resultsArea = new St.BoxLayout({ name: 'ResultsArea', vertical: true }); this._resultsArea = new St.BoxLayout({ name: 'ResultsArea', vertical: true });
this._evalBox.add(this._resultsArea, { expand: true }); this._evalBox.add(this._resultsArea, { expand: true });
this._entryArea = new St.BoxLayout({ name: 'EntryArea' }); let entryArea = new St.BoxLayout({ name: 'EntryArea' });
this._evalBox.add_actor(this._entryArea); this._evalBox.add_actor(entryArea);
let label = new St.Label({ text: 'js>>> ' }); let label = new St.Label({ text: 'js>>> ' });
this._entryArea.add(label); 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 }); entryArea.add(this._entry, { expand: true });
this._windowList = new WindowList(); this._windowList = new WindowList();
this._windowList.connect('selected', Lang.bind(this, function(list, window) { this._windowList.connect('selected', Lang.bind(this, function(list, window) {
@ -957,9 +837,6 @@ const LookingGlass = new Lang.Class({
notebook.appendPage('Extensions', this._extensions.actor); notebook.appendPage('Extensions', this._extensions.actor);
this._entry.clutter_text.connect('activate', Lang.bind(this, function (o, e) { this._entry.clutter_text.connect('activate', Lang.bind(this, function (o, e) {
// Hide any completions we are currently showing
this._hideCompletions();
let text = o.get_text(); let text = o.get_text();
// Ensure we don't get newlines in the command; the history file is // Ensure we don't get newlines in the command; the history file is
// newline-separated. // newline-separated.
@ -975,17 +852,6 @@ const LookingGlass = new Lang.Class({
this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY, this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY,
entry: this._entry.clutter_text }); entry: this._entry.clutter_text });
this._autoComplete = new AutoComplete(this._entry);
this._autoComplete.connect('suggest', Lang.bind(this, function(a,e) {
this._showCompletions(e.completions);
}));
// If a completion is completed unambiguously, the currently-displayed completion
// suggestions become irrelevant.
this._autoComplete.connect('completion', Lang.bind(this, function(a,e) {
if (e.type == 'whole-word')
this._hideCompletions();
}));
this._resize(); this._resize();
}, },
@ -1030,59 +896,6 @@ const LookingGlass = new Lang.Class({
this._notebook.scrollToBottom(0); this._notebook.scrollToBottom(0);
}, },
_showCompletions: function(completions) {
if (!this._completionActor) {
let actor = new St.BoxLayout({ vertical: true });
this._completionText = new St.Label({ name: 'LookingGlassAutoCompletionText', style_class: 'lg-completions-text' });
this._completionText.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._completionText.clutter_text.line_wrap = true;
actor.add(this._completionText);
let line = new Clutter.Rectangle();
let padBin = new St.Bin({ x_fill: true, y_fill: true });
padBin.add_actor(line);
actor.add(padBin);
this._completionActor = actor;
this._evalBox.insert_child_below(this._completionActor, this._entryArea);
}
this._completionText.set_text(completions.join(', '));
// Setting the height to -1 allows us to get its actual preferred height rather than
// whatever was last given in set_height by Tweener.
this._completionActor.set_height(-1);
let [minHeight, naturalHeight] = this._completionText.get_preferred_height(this._resultsArea.get_width());
// Don't reanimate if we are already visible
if (this._completionActor.visible) {
this._completionActor.height = naturalHeight;
} else {
this._completionActor.show();
Tweener.removeTweens(this._completionActor);
Tweener.addTween(this._completionActor, { time: AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION / St.get_slow_down_factor(),
transition: 'easeOutQuad',
height: naturalHeight,
opacity: 255
});
}
},
_hideCompletions: function() {
if (this._completionActor) {
Tweener.removeTweens(this._completionActor);
Tweener.addTween(this._completionActor, { time: AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION / St.get_slow_down_factor(),
transition: 'easeOutQuad',
height: 0,
opacity: 0,
onComplete: Lang.bind(this, function () {
this._completionActor.hide();
})
});
}
},
_evaluate : function(command) { _evaluate : function(command) {
this._history.addItem(command); this._history.addItem(command);
@ -1147,7 +960,6 @@ 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();
if (symbol == Clutter.Escape) { if (symbol == Clutter.Escape) {
if (this._objInspector.actor.visible) { if (this._objInspector.actor.visible) {
this._objInspector.close(); this._objInspector.close();
@ -1156,14 +968,6 @@ const LookingGlass = new Lang.Class({
} }
return true; return true;
} }
// Ctrl+PgUp and Ctrl+PgDown switches tabs in the notebook view
if (modifierState & Clutter.ModifierType.CONTROL_MASK) {
if (symbol == Clutter.KEY_Page_Up) {
this._notebook.prevTab();
} else if (symbol == Clutter.KEY_Page_Down) {
this._notebook.nextTab();
}
}
return false; return false;
}, },
@ -1214,5 +1018,5 @@ const LookingGlass = new Lang.Class({
}) })
}); });
} }
}); };
Signals.addSignalMethods(LookingGlass.prototype); Signals.addSignalMethods(LookingGlass.prototype);

View File

@ -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 GDesktopEnums = imports.gi.GDesktopEnums;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const Shell = imports.gi.Shell; const Shell = imports.gi.Shell;
const St = imports.gi.St; const St = imports.gi.St;
@ -13,6 +12,22 @@ const Main = imports.ui.main;
const MagnifierDBus = imports.ui.magnifierDBus; const MagnifierDBus = imports.ui.magnifierDBus;
const Params = imports.misc.params; const Params = imports.misc.params;
// Keep enums in sync with GSettings schemas
const MouseTrackingMode = {
NONE: 0,
CENTERED: 1,
PROPORTIONAL: 2,
PUSH: 3
};
const ScreenPosition = {
NONE: 0,
FULL_SCREEN: 1,
TOP_HALF: 2,
BOTTOM_HALF: 3,
LEFT_HALF: 4,
RIGHT_HALF: 5
};
const MOUSE_POLL_FREQUENCY = 50; const MOUSE_POLL_FREQUENCY = 50;
const CROSSHAIRS_CLIP_SIZE = [100, 100]; const CROSSHAIRS_CLIP_SIZE = [100, 100];
@ -36,15 +51,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();
@ -503,7 +520,7 @@ const Magnifier = new Lang.Class({
if (this._zoomRegions.length) { if (this._zoomRegions.length) {
let position = this._settings.get_enum(SCREEN_POSITION_KEY); let position = this._settings.get_enum(SCREEN_POSITION_KEY);
this._zoomRegions[0].setScreenPosition(position); this._zoomRegions[0].setScreenPosition(position);
if (position != GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN) if (position != ScreenPosition.FULL_SCREEN)
this._updateLensMode(); this._updateLensMode();
} }
}, },
@ -541,22 +558,23 @@ const Magnifier = new Lang.Class({
); );
} }
} }
}); };
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;
this._mouseTrackingMode = GDesktopEnums.MagnifierMouseTrackingMode.NONE; this._mouseTrackingMode = MouseTrackingMode.NONE;
this._clampScrollingAtEdges = false; this._clampScrollingAtEdges = false;
this._lensMode = false; this._lensMode = false;
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN; this._screenPosition = ScreenPosition.FULL_SCREEN;
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;
@ -566,15 +584,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));
}, },
/** /**
@ -632,8 +647,7 @@ const ZoomRegion = new Lang.Class({
* @mode: One of the enum MouseTrackingMode values. * @mode: One of the enum MouseTrackingMode values.
*/ */
setMouseTrackingMode: function(mode) { setMouseTrackingMode: function(mode) {
if (mode >= GDesktopEnums.MagnifierMouseTrackingMode.NONE && if (mode >= MouseTrackingMode.NONE && mode <= MouseTrackingMode.PUSH)
mode <= GDesktopEnums.MagnifierMouseTrackingMode.PUSH)
this._mouseTrackingMode = mode; this._mouseTrackingMode = mode;
}, },
@ -654,7 +668,7 @@ const ZoomRegion = new Lang.Class({
*/ */
setViewPort: function(viewPort) { setViewPort: function(viewPort) {
this._setViewPort(viewPort); this._setViewPort(viewPort);
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.NONE; this._screenPosition = ScreenPosition.NONE;
}, },
/** /**
@ -736,7 +750,7 @@ const ZoomRegion = new Lang.Class({
viewPort.width = global.screen_width; viewPort.width = global.screen_width;
viewPort.height = global.screen_height/2; viewPort.height = global.screen_height/2;
this._setViewPort(viewPort); this._setViewPort(viewPort);
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.TOP_HALF; this._screenPosition = ScreenPosition.TOP_HALF;
}, },
/** /**
@ -750,7 +764,7 @@ const ZoomRegion = new Lang.Class({
viewPort.width = global.screen_width; viewPort.width = global.screen_width;
viewPort.height = global.screen_height/2; viewPort.height = global.screen_height/2;
this._setViewPort(viewPort); this._setViewPort(viewPort);
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.BOTTOM_HALF; this._screenPosition = ScreenPosition.BOTTOM_HALF;
}, },
/** /**
@ -764,7 +778,7 @@ const ZoomRegion = new Lang.Class({
viewPort.width = global.screen_width/2; viewPort.width = global.screen_width/2;
viewPort.height = global.screen_height; viewPort.height = global.screen_height;
this._setViewPort(viewPort); this._setViewPort(viewPort);
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.LEFT_HALF; this._screenPosition = ScreenPosition.LEFT_HALF;
}, },
/** /**
@ -778,7 +792,7 @@ const ZoomRegion = new Lang.Class({
viewPort.width = global.screen_width/2; viewPort.width = global.screen_width/2;
viewPort.height = global.screen_height; viewPort.height = global.screen_height;
this._setViewPort(viewPort); this._setViewPort(viewPort);
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.RIGHT_HALF; this._screenPosition = ScreenPosition.RIGHT_HALF;
}, },
/** /**
@ -794,7 +808,7 @@ const ZoomRegion = new Lang.Class({
viewPort.height = global.screen_height; viewPort.height = global.screen_height;
this.setViewPort(viewPort); this.setViewPort(viewPort);
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN; this._screenPosition = ScreenPosition.FULL_SCREEN;
}, },
/** /**
@ -807,19 +821,19 @@ const ZoomRegion = new Lang.Class({
*/ */
setScreenPosition: function(inPosition) { setScreenPosition: function(inPosition) {
switch (inPosition) { switch (inPosition) {
case GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN: case ScreenPosition.FULL_SCREEN:
this.setFullScreenMode(); this.setFullScreenMode();
break; break;
case GDesktopEnums.MagnifierScreenPosition.TOP_HALF: case ScreenPosition.TOP_HALF:
this.setTopHalf(); this.setTopHalf();
break; break;
case GDesktopEnums.MagnifierScreenPosition.BOTTOM_HALF: case ScreenPosition.BOTTOM_HALF:
this.setBottomHalf(); this.setBottomHalf();
break; break;
case GDesktopEnums.MagnifierScreenPosition.LEFT_HALF: case ScreenPosition.LEFT_HALF:
this.setLeftHalf(); this.setLeftHalf();
break; break;
case GDesktopEnums.MagnifierScreenPosition.RIGHT_HALF: case ScreenPosition.RIGHT_HALF:
this.setRightHalf(); this.setRightHalf();
break; break;
} }
@ -842,7 +856,7 @@ const ZoomRegion = new Lang.Class({
*/ */
scrollToMousePos: function() { scrollToMousePos: function() {
this._followingCursor = true; this._followingCursor = true;
if (this._mouseTrackingMode != GDesktopEnums.MagnifierMouseTrackingMode.NONE) if (this._mouseTrackingMode != MouseTrackingMode.NONE)
this._changeROI({ redoCursorTracking: true }); this._changeROI({ redoCursorTracking: true });
else else
this._updateMousePosition(); this._updateMousePosition();
@ -895,15 +909,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.
@ -927,7 +941,6 @@ const ZoomRegion = new Lang.Class({
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;
@ -978,7 +991,7 @@ const ZoomRegion = new Lang.Class({
this._yMagFactor = params.yMagFactor; this._yMagFactor = params.yMagFactor;
if (params.redoCursorTracking && if (params.redoCursorTracking &&
this._mouseTrackingMode != GDesktopEnums.MagnifierMouseTrackingMode.NONE) { this._mouseTrackingMode != MouseTrackingMode.NONE) {
// This depends on this.xMagFactor/yMagFactor already being updated // This depends on this.xMagFactor/yMagFactor already being updated
[params.xCenter, params.yCenter] = this._centerFromMousePosition(); [params.xCenter, params.yCenter] = this._centerFromMousePosition();
} }
@ -1028,7 +1041,7 @@ const ZoomRegion = new Lang.Class({
_isFullScreen: function() { _isFullScreen: function() {
// Does the magnified view occupy the whole screen? Note that this // Does the magnified view occupy the whole screen? Note that this
// doesn't necessarily imply // doesn't necessarily imply
// this._screenPosition = GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN; // this._screenPosition = ScreenPosition.FULL_SCREEN;
if (this._viewPortX != 0 || this._viewPortY != 0) if (this._viewPortX != 0 || this._viewPortY != 0)
return false; return false;
@ -1045,13 +1058,13 @@ const ZoomRegion = new Lang.Class({
let xMouse = this._magnifier.xMouse; let xMouse = this._magnifier.xMouse;
let yMouse = this._magnifier.yMouse; let yMouse = this._magnifier.yMouse;
if (this._mouseTrackingMode == GDesktopEnums.MagnifierMouseTrackingMode.PROPORTIONAL) { if (this._mouseTrackingMode == MouseTrackingMode.PROPORTIONAL) {
return this._centerFromMouseProportional(xMouse, yMouse); return this._centerFromMouseProportional(xMouse, yMouse);
} }
else if (this._mouseTrackingMode == GDesktopEnums.MagnifierMouseTrackingMode.PUSH) { else if (this._mouseTrackingMode == MouseTrackingMode.PUSH) {
return this._centerFromMousePush(xMouse, yMouse); return this._centerFromMousePush(xMouse, yMouse);
} }
else if (this._mouseTrackingMode == GDesktopEnums.MagnifierMouseTrackingMode.CENTERED) { else if (this._mouseTrackingMode == MouseTrackingMode.CENTERED) {
return this._centerFromMouseCentered(xMouse, yMouse); return this._centerFromMouseCentered(xMouse, yMouse);
} }
@ -1150,28 +1163,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
@ -1196,14 +1195,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();
}, },
/** /**
@ -1435,4 +1426,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);
} }
}); };

View File

@ -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 Gio = imports.gi.Gio; const DBus = imports.dbus;
const Lang = imports.lang;
const Main = imports.ui.main; const Main = imports.ui.main;
const MAG_SERVICE_NAME = 'org.gnome.Magnifier'; const MAG_SERVICE_NAME = 'org.gnome.Magnifier';
@ -11,99 +10,61 @@ const ZOOM_SERVICE_PATH = '/org/gnome/Magnifier/ZoomRegion';
// Subset of gnome-mag's Magnifier dbus interface -- to be expanded. See: // Subset of gnome-mag's Magnifier dbus interface -- to be expanded. See:
// http://git.gnome.org/browse/gnome-mag/tree/xml/...Magnifier.xml // http://git.gnome.org/browse/gnome-mag/tree/xml/...Magnifier.xml
const MagnifierIface = <interface name={MAG_SERVICE_NAME}> const MagnifierIface = {
<method name="setActive"> name: MAG_SERVICE_NAME,
<arg type="b" direction="in" /> methods: [
</method> { name: 'setActive', inSignature: 'b', outSignature: '' },
<method name="isActive"> { name: 'isActive', inSignature: '', outSignature: 'b' },
<arg type="b" direction="out" /> { name: 'showCursor', inSignature: '', outSignature: '' },
</method> { name: 'hideCursor', inSignature: '', outSignature: '' },
<method name="showCursor" /> { name: 'createZoomRegion', inSignature: 'ddaiai', outSignature: 'o' },
<method name="hideCursor" /> { name: 'addZoomRegion', inSignature: 'o', outSignature: 'b' },
<method name="createZoomRegion"> { name: 'getZoomRegions', inSignature: '', outSignature: 'ao' },
<arg type="d" direction="in" /> { name: 'clearAllZoomRegions', inSignature: '', outSignature: '' },
<arg type="d" direction="in" /> { name: 'fullScreenCapable', inSignature: '', outSignature: 'b' },
<arg type="ai" direction="in" />
<arg type="ai" direction="in" /> { name: 'setCrosswireSize', inSignature: 'i', outSignature: '' },
<arg type="o" direction="out" /> { name: 'getCrosswireSize', inSignature: '', outSignature: 'i' },
</method> { name: 'setCrosswireLength', inSignature: 'i', outSignature: '' },
<method name="addZoomRegion"> { name: 'getCrosswireLength', inSignature: '', outSignature: 'i' },
<arg type="o" direction="in" /> { name: 'setCrosswireClip', inSignature: 'b', outSignature: '' },
<arg type="b" direction="out" /> { name: 'getCrosswireClip', inSignature: '', outSignature: 'b' },
</method> { name: 'setCrosswireColor', inSignature: 'u', outSignature: '' },
<method name="getZoomRegions"> { name: 'getCrosswireColor', inSignature: '', outSignature: 'u' }
<arg type="ao" direction="out" /> ],
</method> signals: [],
<method name="clearAllZoomRegions" /> properties: []
<method name="fullScreenCapable"> };
<arg type="b" direction="out" />
</method>
<method name="setCrosswireSize">
<arg type="i" direction="in" />
</method>
<method name="getCrosswireSize">
<arg type="i" direction="out" />
</method>
<method name="setCrosswireLength">
<arg type="i" direction="in" />
</method>
<method name="getCrosswireLength">
<arg type="i" direction="out" />
</method>
<method name="setCrosswireClip">
<arg type="b" direction="in" />
</method>
<method name="getCrosswireClip">
<arg type="b" direction="out" />
</method>
<method name="setCrosswireColor">
<arg type="u" direction="in" />
</method>
<method name="getCrosswireColor">
<arg type="u" direction="out" />
</method>
</interface>;
// Subset of gnome-mag's ZoomRegion dbus interface -- to be expanded. See: // Subset of gnome-mag's ZoomRegion dbus interface -- to be expanded. See:
// http://git.gnome.org/browse/gnome-mag/tree/xml/...ZoomRegion.xml // http://git.gnome.org/browse/gnome-mag/tree/xml/...ZoomRegion.xml
const ZoomRegionIface = <interface name={ZOOM_SERVICE_NAME}> const ZoomRegionIface = {
<method name="setMagFactor"> name: ZOOM_SERVICE_NAME,
<arg type="d" direction="in" /> methods: [
<arg type="d" direction="in" /> { name: 'setMagFactor', inSignature: 'dd', outSignature: ''},
</method> { name: 'getMagFactor', inSignature: '', outSignature: 'dd' },
<method name="getMagFactor"> { name: 'setRoi', inSignature: 'ai', outSignature: '' },
<arg type="d" direction="out" /> { name: 'getRoi', inSignature: '', outSignature: 'ai' },
<arg type="d" direction="out" /> { name: 'shiftContentsTo', inSignature: 'ii', outSignature: 'b' },
</method> { name: 'moveResize', inSignature: 'ai', outSignature: '' }
<method name="setRoi"> ],
<arg type="ai" direction="in" /> signals: [],
</method> properties: []
<method name="getRoi"> };
<arg type="ai" direction="out" />
</method>
<method name="shiftContentsTo">
<arg type="i" direction="in" />
<arg type="i" direction="in" />
<arg type="b" direction="out" />
</method>
<method name="moveResize">
<arg type="ai" direction="in" />
</method>
</interface>;
// For making unique ZoomRegion DBus proxy object paths of the form: // For making unique ZoomRegion DBus proxy object paths of the form:
// '/org/gnome/Magnifier/ZoomRegion/zoomer0', // '/org/gnome/Magnifier/ZoomRegion/zoomer0',
// '/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 = {};
DBus.session.exportObject(MAG_SERVICE_PATH, this);
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(MagnifierIface, this);
this._dbusImpl.export(Gio.DBus.session, MAG_SERVICE_PATH);
}, },
/** /**
@ -234,10 +195,10 @@ const ShellMagnifier = new Lang.Class({
Main.magnifier.clearAllZoomRegions(); Main.magnifier.clearAllZoomRegions();
for (let objectPath in this._zoomers) { for (let objectPath in this._zoomers) {
let proxyAndZoomer = this._zoomers[objectPath]; let proxyAndZoomer = this._zoomers[objectPath];
proxyAndZoomer.proxy.destroy();
proxyAndZoomer.proxy = null; proxyAndZoomer.proxy = null;
proxyAndZoomer.zoomRegion = null; proxyAndZoomer.zoomRegion = null;
delete this._zoomers[objectPath]; delete this._zoomers[objectPath];
DBus.session.unexportObject(proxyAndZoomer);
} }
this._zoomers = {}; this._zoomers = {};
}, },
@ -324,7 +285,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,14 +293,15 @@ 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;
DBus.session.proxifyObject(this, ZOOM_SERVICE_NAME, zoomerObjectPath);
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ZoomRegionIface, this); DBus.session.exportObject(zoomerObjectPath, this);
this._dbusImpl.export(Gio.DBus.session, zoomerObjectPath);
}, },
/** /**
@ -414,9 +376,8 @@ const ShellMagnifierZoomRegion = new Lang.Class({
moveResize: function(viewPort) { moveResize: function(viewPort) {
let viewRect = { x: viewPort[0], y: viewPort[1], width: viewPort[2] - viewPort[0], height: viewPort[3] - viewPort[1] }; let viewRect = { x: viewPort[0], y: viewPort[1], width: viewPort[2] - viewPort[0], height: viewPort[3] - viewPort[1] };
this._zoomRegion.setViewPort(viewRect); this._zoomRegion.setViewPort(viewRect);
},
destroy: function() {
this._dbusImpl.unexport();
} }
}); };
DBus.conformExport(ShellMagnifier.prototype, MagnifierIface);
DBus.conformExport(ShellMagnifierZoomRegion.prototype, ZoomRegionIface);

View File

@ -1,9 +1,11 @@
// -*- 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 DBus = imports.dbus;
const Gdk = imports.gi.Gdk; const Gdk = imports.gi.Gdk;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib; const GLib = imports.gi.GLib;
const GConf = imports.gi.GConf;
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;
@ -15,7 +17,6 @@ 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 Keyboard = imports.ui.keyboard; const Keyboard = imports.ui.keyboard;
@ -38,7 +39,6 @@ const XdndHandler = imports.ui.xdndHandler;
const StatusIconDispatcher = imports.ui.statusIconDispatcher; 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);
@ -72,7 +72,6 @@ let _startDate;
let _defaultCssStylesheet = null; let _defaultCssStylesheet = null;
let _cssStylesheet = null; let _cssStylesheet = null;
let _gdmCssStylesheet = null; let _gdmCssStylesheet = null;
let _overridesSettings = null;
let background = null; let background = null;
@ -113,9 +112,7 @@ function _initRecorder() {
} else { } 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*$/))
@ -137,11 +134,15 @@ function _initUserSession() {
ExtensionSystem.init(); ExtensionSystem.init();
ExtensionSystem.loadExtensions(); ExtensionSystem.loadExtensions();
Meta.keybindings_set_custom_handler('panel-run-dialog', function() { let shellwm = global.window_manager;
shellwm.takeover_keybinding('panel_run_dialog');
shellwm.connect('keybinding::panel_run_dialog', function () {
getRunDialog().open(); getRunDialog().open();
}); });
Meta.keybindings_set_custom_handler('panel-main-menu', function () { shellwm.takeover_keybinding('panel_main_menu');
shellwm.connect('keybinding::panel_main_menu', function () {
overview.toggle(); overview.toggle();
}); });
@ -162,6 +163,11 @@ function start() {
Gio.DesktopAppInfo.set_desktop_env('GNOME'); Gio.DesktopAppInfo.set_desktop_env('GNOME');
shellDBusService = new ShellDBus.GnomeShell(); shellDBusService = new ShellDBus.GnomeShell();
// Force a connection now; dbus.js will do this internally
// if we use its name acquisition stuff but we aren't right
// now; to do so we'd need to convert from its async calls
// back into sync ones.
DBus.session.flush();
// 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 +177,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.
@ -194,16 +198,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);
@ -244,9 +239,6 @@ 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);
@ -261,9 +253,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);
@ -288,30 +277,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];
@ -359,17 +335,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();
@ -378,7 +343,6 @@ function _windowRemoved(workspace, window) {
workspace._lastRemovedWindow = null; workspace._lastRemovedWindow = null;
_queueCheckWorkspaces(); _queueCheckWorkspaces();
} }
return false;
}); });
} }
@ -614,12 +578,21 @@ function _globalKeyPressHandler(actor, event) {
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);
// The screenshot action should always be available (even if a
// modal dialog is present)
if (action == Meta.KeyBindingAction.COMMAND_SCREENSHOT) {
let gconf = GConf.Client.get_default();
let command = gconf.get_string('/apps/metacity/keybinding_commands/command_screenshot');
if (command != null && command != '')
Util.spawnCommandLine(command);
return true;
}
// Other bindings are only available to the user session when the overview is up and // Other bindings are only available to the user session when the overview is up and
// no modal dialog is present. // no modal dialog is present.
if (global.session_type == Shell.SessionType.USER && (!overview.visible || modalCount > 1)) if (global.session_type == Shell.SessionType.USER && (!overview.visible || modalCount > 1))
@ -695,17 +668,14 @@ function _findModal(actor) {
* initiated event. If not provided then the value of * initiated event. If not provided then the value of
* global.get_current_time() is assumed. * global.get_current_time() is assumed.
* *
* @options: optional Meta.ModalOptions flags to indicate that the
* pointer is alrady grabbed
*
* Returns: true iff we successfully acquired a grab or already had one * Returns: true iff we successfully acquired a grab or already had one
*/ */
function pushModal(actor, timestamp, options) { function pushModal(actor, timestamp) {
if (timestamp == undefined) if (timestamp == undefined)
timestamp = global.get_current_time(); timestamp = global.get_current_time();
if (modalCount == 0) { if (modalCount == 0) {
if (!global.begin_modal(timestamp, options ? options : 0)) { if (!global.begin_modal(timestamp)) {
log('pushModal: invocation of begin_modal failed'); log('pushModal: invocation of begin_modal failed');
return false; return false;
} }

View File

@ -4,7 +4,6 @@ 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 Gtk = imports.gi.Gtk; const Gtk = imports.gi.Gtk;
const Atk = imports.gi.Atk;
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;
@ -84,9 +83,11 @@ function _fixMarkup(text, allowMarkup) {
return GLib.markup_escape_text(text, -1); return GLib.markup_escape_text(text, -1);
} }
const URLHighlighter = new Lang.Class({ function URLHighlighter(text, lineWrap, allowMarkup) {
Name: 'URLHighlighter', this._init(text, lineWrap, allowMarkup);
}
URLHighlighter.prototype = {
_init: function(text, lineWrap, allowMarkup) { _init: function(text, lineWrap, allowMarkup) {
if (!text) if (!text)
text = ''; text = '';
@ -210,11 +211,13 @@ const URLHighlighter = new Lang.Class({
} }
return -1; return -1;
} }
}); };
const FocusGrabber = new Lang.Class({ function FocusGrabber() {
Name: 'FocusGrabber', this._init();
}
FocusGrabber.prototype = {
_init: function() { _init: function() {
this.actor = null; this.actor = null;
@ -262,9 +265,7 @@ const FocusGrabber = new Lang.Class({
this._hasFocus = true; this._hasFocus = true;
if (!this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false)) this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
this.actor.grab_key_focus();
this.emit('focus-grabbed'); this.emit('focus-grabbed');
}, },
@ -350,7 +351,7 @@ const FocusGrabber = new Lang.Class({
this._togglingFocusGrabMode = false; this._togglingFocusGrabMode = false;
} }
} }
}); }
Signals.addSignalMethods(FocusGrabber.prototype); Signals.addSignalMethods(FocusGrabber.prototype);
// Notification: // Notification:
@ -407,9 +408,11 @@ Signals.addSignalMethods(FocusGrabber.prototype);
// the content and the action area of the notification will be cleared. // the content and the action area of the notification will be cleared.
// The content area is also always cleared if 'customContent' is false // The content area is also always cleared if 'customContent' is false
// because it might contain the @banner that didn't fit in the banner mode. // because it might contain the @banner that didn't fit in the banner mode.
const Notification = new Lang.Class({ function Notification(source, title, banner, params) {
Name: 'Notification', this._init(source, title, banner, params);
}
Notification.prototype = {
IMAGE_SIZE: 125, IMAGE_SIZE: 125,
_init: function(source, title, banner, params) { _init: function(source, title, banner, params) {
@ -426,7 +429,7 @@ const Notification = new Lang.Class({
this._bannerBodyText = null; this._bannerBodyText = null;
this._bannerBodyMarkup = false; this._bannerBodyMarkup = false;
this._titleFitsInBannerMode = true; this._titleFitsInBannerMode = true;
this._titleDirection = Clutter.TextDirection.DEFAULT; this._titleDirection = St.TextDirection.NONE;
this._spacing = 0; this._spacing = 0;
this._scrollPolicy = Gtk.PolicyType.AUTOMATIC; this._scrollPolicy = Gtk.PolicyType.AUTOMATIC;
this._imageBin = null; this._imageBin = null;
@ -436,7 +439,7 @@ const Notification = new Lang.Class({
this.destroy(reason); this.destroy(reason);
})); }));
this.actor = new St.Button({ accessible_role: Atk.Role.NOTIFICATION }); this.actor = new St.Button();
this.actor._delegate = this; this.actor._delegate = this;
this.actor.connect('clicked', Lang.bind(this, this._onClicked)); this.actor.connect('clicked', Lang.bind(this, this._onClicked));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
@ -547,9 +550,9 @@ const Notification = new Lang.Class({
this._titleLabel.clutter_text.set_markup('<b>' + title + '</b>'); this._titleLabel.clutter_text.set_markup('<b>' + title + '</b>');
if (Pango.find_base_dir(title, -1) == Pango.Direction.RTL) if (Pango.find_base_dir(title, -1) == Pango.Direction.RTL)
this._titleDirection = Clutter.TextDirection.RTL; this._titleDirection = St.TextDirection.RTL;
else else
this._titleDirection = Clutter.TextDirection.LTR; this._titleDirection = St.TextDirection.LTR;
// Let the title's text direction control the overall direction // Let the title's text direction control the overall direction
// of the notification - in case where different scripts are used // of the notification - in case where different scripts are used
@ -557,7 +560,7 @@ const Notification = new Lang.Class({
// arguably for action buttons as well. Labels other than the title // arguably for action buttons as well. Labels other than the title
// will be allocated at the available width, so that their alignment // will be allocated at the available width, so that their alignment
// is done correctly automatically. // is done correctly automatically.
this._table.set_text_direction(this._titleDirection); this._table.set_direction(this._titleDirection);
// Unless the notification has custom content, we save this._bannerBodyText // Unless the notification has custom content, we save this._bannerBodyText
// to add it to the content of the notification if the notification is // to add it to the content of the notification if the notification is
@ -577,7 +580,7 @@ const Notification = new Lang.Class({
if (params.body) if (params.body)
this.addBody(params.body, params.bodyMarkup); this.addBody(params.body, params.bodyMarkup);
this.updated(); this._updated();
}, },
setIconVisible: function(visible) { setIconVisible: function(visible) {
@ -594,7 +597,8 @@ const Notification = new Lang.Class({
this._table.add_style_class_name('multi-line-notification'); this._table.add_style_class_name('multi-line-notification');
this._scrollArea = new St.ScrollView({ name: 'notification-scrollview', this._scrollArea = new St.ScrollView({ name: 'notification-scrollview',
vscrollbar_policy: this._scrollPolicy, vscrollbar_policy: this._scrollPolicy,
hscrollbar_policy: Gtk.PolicyType.NEVER }); hscrollbar_policy: Gtk.PolicyType.NEVER,
style_class: 'vfade' });
this._table.add(this._scrollArea, { row: 1, this._table.add(this._scrollArea, { row: 1,
col: 2 }); col: 2 });
this._updateLastColumnSettings(); this._updateLastColumnSettings();
@ -616,7 +620,7 @@ const Notification = new Lang.Class({
} }
this._contentArea.add(actor, style ? style : {}); this._contentArea.add(actor, style ? style : {});
this.updated(); this._updated();
}, },
// addBody: // addBody:
@ -679,7 +683,7 @@ const Notification = new Lang.Class({
this._table.add_style_class_name('multi-line-notification'); this._table.add_style_class_name('multi-line-notification');
this._table.add(this._actionArea, props); this._table.add(this._actionArea, props);
this._updateLastColumnSettings(); this._updateLastColumnSettings();
this.updated(); this._updated();
}, },
_updateLastColumnSettings: function() { _updateLastColumnSettings: function() {
@ -760,7 +764,7 @@ const Notification = new Lang.Class({
this._buttonFocusManager.add_group(this._buttonBox); this._buttonFocusManager.add_group(this._buttonBox);
button.connect('clicked', Lang.bind(this, this._onActionInvoked, id)); button.connect('clicked', Lang.bind(this, this._onActionInvoked, id));
this.updated(); this._updated();
}, },
setUrgency: function(urgency) { setUrgency: function(urgency) {
@ -805,7 +809,7 @@ const Notification = new Lang.Class({
let titleBox = new Clutter.ActorBox(); let titleBox = new Clutter.ActorBox();
let titleBoxW = Math.min(titleNatW, availWidth); let titleBoxW = Math.min(titleNatW, availWidth);
if (this._titleDirection == Clutter.TextDirection.RTL) { if (this._titleDirection == St.TextDirection.RTL) {
titleBox.x1 = availWidth - titleBoxW; titleBox.x1 = availWidth - titleBoxW;
titleBox.x2 = availWidth; titleBox.x2 = availWidth;
} else { } else {
@ -824,7 +828,7 @@ const Notification = new Lang.Class({
} else { } else {
let bannerBox = new Clutter.ActorBox(); let bannerBox = new Clutter.ActorBox();
if (this._titleDirection == Clutter.TextDirection.RTL) { if (this._titleDirection == St.TextDirection.RTL) {
bannerBox.x1 = 0; bannerBox.x1 = 0;
bannerBox.x2 = titleBox.x1 - this._spacing; bannerBox.x2 = titleBox.x1 - this._spacing;
@ -856,7 +860,7 @@ const Notification = new Lang.Class({
if (this._canExpandContent()) { if (this._canExpandContent()) {
this._addBannerBody(); this._addBannerBody();
this._table.add_style_class_name('multi-line-notification'); this._table.add_style_class_name('multi-line-notification');
this.updated(); this._updated();
} }
return false; return false;
})); }));
@ -867,7 +871,7 @@ const Notification = new Lang.Class({
(!this._titleFitsInBannerMode && !this._table.has_style_class_name('multi-line-notification')); (!this._titleFitsInBannerMode && !this._table.has_style_class_name('multi-line-notification'));
}, },
updated: function() { _updated: function() {
if (this.expanded) if (this.expanded)
this.expand(false); this.expand(false);
}, },
@ -950,12 +954,14 @@ const Notification = new Lang.Class({
this.actor.destroy(); this.actor.destroy();
this.actor._delegate = null; this.actor._delegate = null;
} }
}); };
Signals.addSignalMethods(Notification.prototype); Signals.addSignalMethods(Notification.prototype);
const Source = new Lang.Class({ function Source(title) {
Name: 'MessageTraySource', this._init(title);
}
Source.prototype = {
ICON_SIZE: 24, ICON_SIZE: 24,
_init: function(title) { _init: function(title) {
@ -986,7 +992,6 @@ const Source = new Lang.Class({
this.isTransient = false; this.isTransient = false;
this.isChat = false; this.isChat = false;
this.isMuted = false;
this.notifications = []; this.notifications = [];
}, },
@ -1008,9 +1013,9 @@ const Source = new Lang.Class({
let childBox = new Clutter.ActorBox(); let childBox = new Clutter.ActorBox();
let [minWidth, minHeight, naturalWidth, naturalHeight] = this._counterBin.get_preferred_size(); let [minWidth, minHeight, naturalWidth, naturalHeight] = this._counterBin.get_preferred_size();
let direction = this.actor.get_text_direction(); let direction = this.actor.get_direction();
if (direction == Clutter.TextDirection.LTR) { if (direction == St.TextDirection.LTR) {
// allocate on the right in LTR // allocate on the right in LTR
childBox.x1 = box.x2 - naturalWidth; childBox.x1 = box.x2 - naturalWidth;
childBox.x2 = box.x2; childBox.x2 = box.x2;
@ -1051,13 +1056,6 @@ const Source = new Lang.Class({
this.emit('title-changed'); this.emit('title-changed');
}, },
setMuted: function(muted) {
if (!this.isChat || this.isMuted == muted)
return;
this.isMuted = muted;
this.emit('muted-changed');
},
// Called to create a new icon actor (of size this.ICON_SIZE). // Called to create a new icon actor (of size this.ICON_SIZE).
// Must be overridden by the subclass if you do not pass icons // Must be overridden by the subclass if you do not pass icons
// explicitly to the Notification() constructor. // explicitly to the Notification() constructor.
@ -1096,7 +1094,6 @@ const Source = new Lang.Class({
notify: function(notification) { notify: function(notification) {
this.pushNotification(notification); this.pushNotification(notification);
if (!this.isMuted)
this.emit('notify', notification); this.emit('notify', notification);
}, },
@ -1137,12 +1134,14 @@ const Source = new Lang.Class({
_lastNotificationRemoved: function() { _lastNotificationRemoved: function() {
this.destroy(); this.destroy();
} }
}); };
Signals.addSignalMethods(Source.prototype); Signals.addSignalMethods(Source.prototype);
const SummaryItem = new Lang.Class({ function SummaryItem(source) {
Name: 'SummaryItem', this._init(source);
}
SummaryItem.prototype = {
_init: function(source) { _init: function(source) {
this.source = source; this.source = source;
this.source.connect('notification-added', Lang.bind(this, this._notificationAddedToSource)); this.source.connect('notification-added', Lang.bind(this, this._notificationAddedToSource));
@ -1211,18 +1210,6 @@ const SummaryItem = new Lang.Class({
})); }));
this.rightClickMenu.add(item.actor); this.rightClickMenu.add(item.actor);
if (source.isChat) {
item = new PopupMenu.PopupMenuItem('');
item.actor.connect('notify::mapped', Lang.bind(this, function() {
item.label.set_text(source.isMuted ? _("Unmute") : _("Mute"));
}));
item.connect('activate', Lang.bind(this, function() {
source.setMuted(!source.isMuted);
this.emit('done-displaying-content');
}));
this.rightClickMenu.add(item.actor);
}
let focusManager = St.FocusManager.get_for_stage(global.stage); let focusManager = St.FocusManager.get_for_stage(global.stage);
focusManager.add_group(this.rightClickMenu); focusManager.add_group(this.rightClickMenu);
}, },
@ -1330,26 +1317,26 @@ const SummaryItem = new Lang.Class({
} }
} }
let firstNotification = this._stackedNotifications[0]; if (this.notificationStack.get_children().length > 0)
if (firstNotification) this.notificationStack.get_children()[0]._delegate.setIconVisible(true);
firstNotification.notification.setIconVisible(true);
} }
}); };
Signals.addSignalMethods(SummaryItem.prototype); Signals.addSignalMethods(SummaryItem.prototype);
const MessageTray = new Lang.Class({ function MessageTray() {
Name: 'MessageTray', this._init();
}
MessageTray.prototype = {
_init: function() { _init: function() {
this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) { this._presence = new GnomeSession.Presence();
this._onStatusChanged(proxy.status); this._userStatus = GnomeSession.PresenceStatus.AVAILABLE;
}));
this._busy = false; this._busy = false;
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) { this._backFromAway = false;
this._onStatusChanged(status); this._presence.connect('StatusChanged', Lang.bind(this, this._onStatusChanged));
})); this._presence.getStatus(Lang.bind(this, this._onStatusChanged));
this.actor = new St.Widget({ name: 'message-tray', this.actor = new St.Group({ name: 'message-tray',
reactive: true, reactive: true,
track_hover: true }); track_hover: true });
this.actor.connect('notify::hover', Lang.bind(this, this._onTrayHoverChanged)); this.actor.connect('notify::hover', Lang.bind(this, this._onTrayHoverChanged));
@ -1390,12 +1377,6 @@ const MessageTray = new Lang.Class({
this._summaryItemTitleWidth = 0; this._summaryItemTitleWidth = 0;
this._pointerBarrier = 0; this._pointerBarrier = 0;
this._unseenNotifications = [];
this._idleMonitorWatchId = 0;
this._backFromAway = false;
this.idleMonitor = new Shell.IdleMonitor();
// To simplify the summary item animation code, we pretend // To simplify the summary item animation code, we pretend
// that there's an invisible SummaryItem to the left of the // that there's an invisible SummaryItem to the left of the
// leftmost real summary item, and that it's expanded when all // leftmost real summary item, and that it's expanded when all
@ -1498,7 +1479,7 @@ const MessageTray = new Lang.Class({
this._summaryBin.x = 0; this._summaryBin.x = 0;
this._summaryBin.width = monitor.width; this._summaryBin.width = monitor.width;
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) if (St.Widget.get_default_direction() == St.TextDirection.RTL)
this._corner.x = 0; this._corner.x = 0;
else else
this._corner.x = Main.layoutManager.trayBox.width - 1; this._corner.x = Main.layoutManager.trayBox.width - 1;
@ -1527,10 +1508,10 @@ const MessageTray = new Lang.Class({
let summaryItem = new SummaryItem(source); let summaryItem = new SummaryItem(source);
if (source.isChat) { if (source.isChat) {
this._summary.insert_child_at_index(summaryItem.actor, 0); this._summary.insert_actor(summaryItem.actor, 0);
this._chatSummaryItemsCount++; this._chatSummaryItemsCount++;
} else { } else {
this._summary.insert_child_at_index(summaryItem.actor, this._chatSummaryItemsCount); this._summary.insert_actor(summaryItem.actor, this._chatSummaryItemsCount);
} }
let titleWidth = summaryItem.getTitleNaturalWidth(); let titleWidth = summaryItem.getTitleNaturalWidth();
@ -1557,14 +1538,6 @@ const MessageTray = new Lang.Class({
source.connect('notify', Lang.bind(this, this._onNotify)); source.connect('notify', Lang.bind(this, this._onNotify));
source.connect('muted-changed', Lang.bind(this,
function () {
if (source.isMuted)
this._notificationQueue = this._notificationQueue.filter(function(notification) {
return source != notification.source;
});
}));
summaryItem.actor.connect('notify::hover', Lang.bind(this, summaryItem.actor.connect('notify::hover', Lang.bind(this,
function () { function () {
this._onSummaryItemHoverChanged(summaryItem); this._onSummaryItemHoverChanged(summaryItem);
@ -1639,10 +1612,6 @@ const MessageTray = new Lang.Class({
}, },
_onNotificationDestroy: function(notification) { _onNotificationDestroy: function(notification) {
let unseenNotificationsIndex = this._unseenNotifications.indexOf(notification);
if (unseenNotificationsIndex != -1)
this._unseenNotifications.splice(unseenNotificationsIndex, 1);
if (this._notification == notification && (this._notificationState == State.SHOWN || this._notificationState == State.SHOWING)) { if (this._notification == notification && (this._notificationState == State.SHOWN || this._notificationState == State.SHOWING)) {
this._updateNotificationTimeout(0); this._updateNotificationTimeout(0);
this._notificationRemoved = true; this._notificationRemoved = true;
@ -1925,11 +1894,17 @@ const MessageTray = new Lang.Class({
this._updateState(); this._updateState();
}, },
_onStatusChanged: function(status) { _onStatusChanged: function(presence, status) {
this._backFromAway = (this._userStatus == GnomeSession.PresenceStatus.IDLE && this._userStatus != status);
this._userStatus = status;
if (status == GnomeSession.PresenceStatus.BUSY) { if (status == GnomeSession.PresenceStatus.BUSY) {
// remove notification and allow the summary to be closed now // remove notification and allow the summary to be closed now
this._updateNotificationTimeout(0); this._updateNotificationTimeout(0);
this._unsetSummaryTimeout(); if (this._summaryTimeoutId) {
Mainloop.source_remove(this._summaryTimeoutId);
this._summaryTimeoutId = 0;
}
this._busy = true; this._busy = true;
} else if (status != GnomeSession.PresenceStatus.IDLE) { } else if (status != GnomeSession.PresenceStatus.IDLE) {
// We preserve the previous value of this._busy if the status turns to IDLE // We preserve the previous value of this._busy if the status turns to IDLE
@ -1959,7 +1934,6 @@ const MessageTray = new Lang.Class({
this._pointerInTray = false; this._pointerInTray = false;
this._pointerInSummary = false; this._pointerInSummary = false;
this._updateNotificationTimeout(0); this._updateNotificationTimeout(0);
this._unsetSummaryTimeout();
this._updateState(); this._updateState();
} }
return false; return false;
@ -1970,7 +1944,6 @@ const MessageTray = new Lang.Class({
this._pointerInTray = false; this._pointerInTray = false;
this._pointerInSummary = false; this._pointerInSummary = false;
this._updateNotificationTimeout(0); this._updateNotificationTimeout(0);
this._unsetSummaryTimeout();
this._updateState(); this._updateState();
}, },
@ -2016,13 +1989,15 @@ const MessageTray = new Lang.Class({
|| notificationsVisible; || notificationsVisible;
if (this._summaryState == State.HIDDEN && !mustHideSummary) { if (this._summaryState == State.HIDDEN && !mustHideSummary) {
if (summarySummoned) { if (this._backFromAway) {
this._showSummary(0); // Immediately set this to false, so that we don't schedule a timeout later
} else if (notificationsDone && !this._busy) { this._backFromAway = false;
if (this._backFromAway && this._unseenNotifications.length > 0) if (!this._busy)
this._showSummary(LONGER_SUMMARY_TIMEOUT); this._showSummary(LONGER_SUMMARY_TIMEOUT);
else if (this._newSummaryItems.length > 0) } else if (notificationsDone && this._newSummaryItems.length > 0 && !this._busy) {
this._showSummary(SUMMARY_TIMEOUT); this._showSummary(SUMMARY_TIMEOUT);
} else if (summarySummoned) {
this._showSummary(0);
} }
} else if (this._summaryState == State.SHOWN) { } else if (this._summaryState == State.SHOWN) {
if (!summaryPinned || mustHideSummary) if (!summaryPinned || mustHideSummary)
@ -2054,11 +2029,8 @@ const MessageTray = new Lang.Class({
if (haveClickedSummaryItem && !summarySourceIsMainNotificationSource && canShowSummaryBoxPointer && !requestedNotificationStackIsEmpty) if (haveClickedSummaryItem && !summarySourceIsMainNotificationSource && canShowSummaryBoxPointer && !requestedNotificationStackIsEmpty)
this._showSummaryBoxPointer(); this._showSummaryBoxPointer();
} else if (this._summaryBoxPointerState == State.SHOWN) { } else if (this._summaryBoxPointerState == State.SHOWN) {
if (!haveClickedSummaryItem || !canShowSummaryBoxPointer || wrongSummaryBoxPointer || mustHideSummary) { if (!haveClickedSummaryItem || !canShowSummaryBoxPointer || wrongSummaryBoxPointer || mustHideSummary)
this._hideSummaryBoxPointer(); this._hideSummaryBoxPointer();
if (wrongSummaryBoxPointer)
this._showSummaryBoxPointer();
}
} }
// Tray itself // Tray itself
@ -2111,32 +2083,8 @@ const MessageTray = new Lang.Class({
}); });
}, },
_onIdleMonitorWatch: function(monitor, id, userBecameIdle) {
this.idleMonitor.remove_watch(this._idleMonitorWatchId);
this._idleMonitorWatchId = 0;
if (userBecameIdle) {
// The user became idle, which means the user was active while the notifications were
// shown and we can unset this._unseenNotifications .
this._unseenNotiications = [];
} else if (this._unseenNotifications.length == 1 && this._unseenNotifications[0] == this._notification) {
// The user became active while the only notification in this._unseenNotifications is being shown
// as this._notification , so we can unset this._unseenNotifications .
this._unseenNotifications = [];
} else {
// The user became active and we have one or more unseen notifications. We should show
// the message tray to the user to inform the user about the missed notifications.
this._backFromAway = true;
this._updateState();
}
},
_showNotification: function() { _showNotification: function() {
this._notification = this._notificationQueue.shift(); this._notification = this._notificationQueue.shift();
this._unseenNotifications.push(this._notification);
if (this._idleMonitorWatchId == 0)
this._idleMonitorWatchId = this.idleMonitor.add_watch(1000,
Lang.bind(this, this._onIdleMonitorWatch));
this._notificationClickedId = this._notification.connect('done-displaying', this._notificationClickedId = this._notification.connect('done-displaying',
Lang.bind(this, this._escapeTray)); Lang.bind(this, this._escapeTray));
this._notificationBin.child = this._notification.actor; this._notificationBin.child = this._notification.actor;
@ -2215,13 +2163,6 @@ const MessageTray = new Lang.Class({
Lang.bind(this, this._notificationTimeout)); Lang.bind(this, this._notificationTimeout));
}, },
_unsetSummaryTimeout: function(timeout) {
if (this._summaryTimeoutId) {
Mainloop.source_remove(this._summaryTimeoutId);
this._summaryTimeoutId = 0;
}
},
_notificationTimeout: function() { _notificationTimeout: function() {
let [x, y, mods] = global.get_pointer(); let [x, y, mods] = global.get_pointer();
if (y > this._lastSeenMouseY + 10 && !this.actor.hover) { if (y > this._lastSeenMouseY + 10 && !this.actor.hover) {
@ -2305,7 +2246,6 @@ const MessageTray = new Lang.Class({
}, },
_showSummary: function(timeout) { _showSummary: function(timeout) {
this._updateSeenSummaryItems();
this._summaryBin.opacity = 0; this._summaryBin.opacity = 0;
this._summaryBin.y = this.actor.height; this._summaryBin.y = this.actor.height;
this._tween(this._summaryBin, '_summaryState', State.SHOWN, this._tween(this._summaryBin, '_summaryState', State.SHOWN,
@ -2320,6 +2260,8 @@ const MessageTray = new Lang.Class({
}, },
_showSummaryCompleted: function(timeout) { _showSummaryCompleted: function(timeout) {
this._newSummaryItems = [];
if (timeout != 0) { if (timeout != 0) {
this._summaryTimeoutId = this._summaryTimeoutId =
Mainloop.timeout_add(timeout * 1000, Mainloop.timeout_add(timeout * 1000,
@ -2334,7 +2276,6 @@ const MessageTray = new Lang.Class({
}, },
_hideSummary: function() { _hideSummary: function() {
this._updateSeenSummaryItems();
this._tween(this._summaryBin, '_summaryState', State.HIDDEN, this._tween(this._summaryBin, '_summaryState', State.HIDDEN,
{ opacity: 0, { opacity: 0,
time: ANIMATION_TIME, time: ANIMATION_TIME,
@ -2342,20 +2283,13 @@ const MessageTray = new Lang.Class({
onComplete: this._hideSummaryCompleted, onComplete: this._hideSummaryCompleted,
onCompleteScope: this, onCompleteScope: this,
}); });
this._newSummaryItems = [];
}, },
_hideSummaryCompleted: function() { _hideSummaryCompleted: function() {
this._setExpandedSummaryItem(null); this._setExpandedSummaryItem(null);
}, },
_updateSeenSummaryItems: function() {
if (this._backFromAway) {
this._backFromAway = false;
this._unseenNotifications = [];
}
this._newSummaryItems = [];
},
_showSummaryBoxPointer: function() { _showSummaryBoxPointer: function() {
this._summaryBoxPointerItem = this._clickedSummaryItem; this._summaryBoxPointerItem = this._clickedSummaryItem;
this._summaryBoxPointerContentUpdatedId = this._summaryBoxPointerItem.connect('content-updated', this._summaryBoxPointerContentUpdatedId = this._summaryBoxPointerItem.connect('content-updated',
@ -2437,8 +2371,9 @@ const MessageTray = new Lang.Class({
} }
this._summaryBoxPointerState = State.HIDING; this._summaryBoxPointerState = State.HIDING;
// Unset this._clickedSummaryItem if we are no longer showing the summary // Unset this._clickedSummaryItem if we are no longer showing the summary or if
if (this._summaryState != State.SHOWN) // this._clickedSummaryItem is still the item associated with the currently showing box pointer
if (this._summaryState != State.SHOWN || this._summaryBoxPointerItem == this._clickedSummaryItem)
this._unsetClickedSummaryItem(); this._unsetClickedSummaryItem();
this._focusGrabber.ungrabFocus(); this._focusGrabber.ungrabFocus();
@ -2480,14 +2415,17 @@ const MessageTray = new Lang.Class({
if (this._clickedSummaryItem) if (this._clickedSummaryItem)
this._updateState(); this._updateState();
} }
}); };
const SystemNotificationSource = new Lang.Class({ function SystemNotificationSource() {
Name: 'SystemNotificationSource', this._init();
Extends: Source, }
SystemNotificationSource.prototype = {
__proto__: Source.prototype,
_init: function() { _init: function() {
this.parent(_("System Information")); Source.prototype._init.call(this, _("System Information"));
this._setSummaryIcon(this.createNotificationIcon()); this._setSummaryIcon(this.createNotificationIcon());
}, },
@ -2501,4 +2439,4 @@ const SystemNotificationSource = new Lang.Class({
open: function() { open: function() {
this.destroy(); this.destroy();
} }
}); };

View File

@ -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,9 +29,11 @@ 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 });
@ -41,14 +42,13 @@ const ModalDialog = new Lang.Class({
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); Main.uiGroup.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));
@ -89,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,
@ -98,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;
}, },
@ -109,12 +107,10 @@ const ModalDialog = new Lang.Class({
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'];
@ -135,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,
@ -205,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) {
@ -314,5 +303,5 @@ const ModalDialog = new Lang.Class({
}) })
}); });
} }
}); };
Signals.addSignalMethods(ModalDialog.prototype); Signals.addSignalMethods(ModalDialog.prototype);

View File

@ -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,
@ -182,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());
}, },
@ -363,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];
@ -629,74 +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 = GLib.build_filenamev([Config.LIBEXECDIR, binary]);
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');
}
}
});

View File

@ -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 Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio; const DBus = imports.dbus;
const GLib = imports.gi.GLib; const GLib = imports.gi.GLib;
const Lang = imports.lang; const Lang = imports.lang;
const Shell = imports.gi.Shell; const Shell = imports.gi.Shell;
@ -16,52 +16,49 @@ const Util = imports.misc.util;
let nextNotificationId = 1; let nextNotificationId = 1;
// Should really be defined in Gio.js // Should really be defined in dbus.js
const BusIface = <interface name="org.freedesktop.DBus"> const BusIface = {
<method name="GetConnectionUnixProcessID"> name: 'org.freedesktop.DBus',
<arg type="s" direction="in" /> methods: [{ name: 'GetConnectionUnixProcessID',
<arg type="u" direction="out" /> inSignature: 's',
</method> outSignature: 'i' }]
</interface>; };
var BusProxy = Gio.DBusProxy.makeProxyWrapper(BusIface); const Bus = function () {
function Bus() { this._init();
return new BusProxy(Gio.DBus.session, 'org.freedesktop.DBus', '/org/freedesktop/DBus'); };
}
const NotificationDaemonIface = <interface name="org.freedesktop.Notifications"> Bus.prototype = {
<method name="Notify"> _init: function() {
<arg type="s" direction="in"/> DBus.session.proxifyObject(this, 'org.freedesktop.DBus', '/org/freedesktop/DBus');
<arg type="u" direction="in"/> }
<arg type="s" direction="in"/> };
<arg type="s" direction="in"/>
<arg type="s" direction="in"/> DBus.proxifyPrototype(Bus.prototype, BusIface);
<arg type="as" direction="in"/>
<arg type="a{sv}" direction="in"/> const NotificationDaemonIface = {
<arg type="i" direction="in"/> name: 'org.freedesktop.Notifications',
<arg type="u" direction="out"/> methods: [{ name: 'Notify',
</method> inSignature: 'susssasa{sv}i',
<method name="CloseNotification"> outSignature: 'u'
<arg type="u" direction="in"/> },
</method> { name: 'CloseNotification',
<method name="GetCapabilities"> inSignature: 'u',
<arg type="as" direction="out"/> outSignature: ''
</method> },
<method name="GetServerInformation"> { name: 'GetCapabilities',
<arg type="s" direction="out"/> inSignature: '',
<arg type="s" direction="out"/> outSignature: 'as'
<arg type="s" direction="out"/> },
<arg type="s" direction="out"/> { name: 'GetServerInformation',
</method> inSignature: '',
<signal name="NotificationClosed"> outSignature: 'ssss'
<arg type="u"/> }],
<arg type="u"/> signals: [{ name: 'NotificationClosed',
</signal> inSignature: 'uu' },
<signal name="ActionInvoked"> { name: 'ActionInvoked',
<arg type="u"/> inSignature: 'us' }]
<arg type="s"/> };
</signal>
</interface>;
const NotificationClosedReason = { const NotificationClosedReason = {
EXPIRED: 1, EXPIRED: 1,
@ -87,12 +84,13 @@ const rewriteRules = {
] ]
}; };
const NotificationDaemon = new Lang.Class({ function NotificationDaemon() {
Name: 'NotificationDaemon', this._init();
}
NotificationDaemon.prototype = {
_init: function() { _init: function() {
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(NotificationDaemonIface, this); DBus.session.exportObject('/org/freedesktop/Notifications', this);
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
this._sources = []; this._sources = [];
this._senderToPid = {}; this._senderToPid = {};
@ -217,23 +215,16 @@ const NotificationDaemon = new Lang.Class({
return source; return source;
}, },
NotifyAsync: function(params, invocation) { Notify: function(appName, replacesId, icon, summary, body,
let [appName, replacesId, icon, summary, body, actions, hints, timeout] = params; actions, hints, timeout) {
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')) {
@ -244,7 +235,7 @@ const NotificationDaemon = new Lang.Class({
function () { function () {
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED); this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
})); }));
return invocation.return_value(GLib.Variant.new('(u)', [id])); return id;
} }
let rewrites = rewriteRules[appName]; let rewrites = rewriteRules[appName];
@ -256,6 +247,8 @@ const NotificationDaemon = new Lang.Class({
} }
} }
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
@ -285,35 +278,30 @@ const NotificationDaemon = new Lang.Class({
} }
this._notifications[id] = ndata; this._notifications[id] = ndata;
let sender = invocation.get_sender(); let sender = DBus.getCurrentMessageContext().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, null);
if (source) { if (source) {
this._notifyForSource(source, ndata); this._notifyForSource(source, ndata);
return invocation.return_value(GLib.Variant.new('(u)', [id])); return id;
} }
if (replacesId) { if (replacesId) {
// There's already a pending call to GetConnectionUnixProcessID, // There's already a pending call to GetConnectionUnixProcessID,
// which will see the new notification data when it finishes, // which will see the new notification data when it finishes,
// so we don't have to do anything. // so we don't have to do anything.
return invocation.return_value(GLib.Variant.new('(u)', [id]));; return id;
} }
this._busProxy.GetConnectionUnixProcessIDRemote(sender, Lang.bind(this, function (result, excp) { this._busProxy.GetConnectionUnixProcessIDRemote(sender, Lang.bind(this,
function (pid, ex) {
// The app may have updated or removed the notification // The app may have updated or removed the notification
ndata = this._notifications[id]; ndata = this._notifications[id];
if (!ndata) if (!ndata)
return; return;
if (excp) {
logError(excp, 'Call to GetConnectionUnixProcessID failed');
return;
}
let [pid] = result;
source = this._getSource(appName, pid, ndata, sender, null); source = this._getSource(appName, pid, ndata, sender, null);
// We only store sender-pid entries for persistent sources. // We only store sender-pid entries for persistent sources.
@ -326,14 +314,15 @@ const NotificationDaemon = new Lang.Class({
// distroyed. // distroyed.
if (!source.isTransient) { if (!source.isTransient) {
this._senderToPid[sender] = pid; this._senderToPid[sender] = pid;
source.connect('destroy', Lang.bind(this, function() { source.connect('destroy', Lang.bind(this,
function() {
delete this._senderToPid[sender]; delete this._senderToPid[sender];
})); }));
} }
this._notifyForSource(source, ndata); this._notifyForSource(source, ndata);
})); }));
return invocation.return_value(GLib.Variant.new('(u)', [id])); return id;
}, },
_notifyForSource: function(source, ndata) { _notifyForSource: function(source, ndata) {
@ -473,13 +462,17 @@ const NotificationDaemon = new Lang.Class({
}, },
_emitNotificationClosed: function(id, reason) { _emitNotificationClosed: function(id, reason) {
this._dbusImpl.emit_signal('NotificationClosed', DBus.session.emit_signal('/org/freedesktop/Notifications',
GLib.Variant.new('(uu)', [id, reason])); 'org.freedesktop.Notifications',
'NotificationClosed', 'uu',
[id, reason]);
}, },
_emitActionInvoked: function(id, action) { _emitActionInvoked: function(id, action) {
this._dbusImpl.emit_signal('ActionInvoked', DBus.session.emit_signal('/org/freedesktop/Notifications',
GLib.Variant.new('(us)', [id, action])); 'org.freedesktop.Notifications',
'ActionInvoked', 'us',
[id, action]);
}, },
_onTrayIconAdded: function(o, icon) { _onTrayIconAdded: function(o, icon) {
@ -487,29 +480,37 @@ const NotificationDaemon = new Lang.Class({
}, },
_onTrayIconRemoved: function(o, icon) { _onTrayIconRemoved: function(o, icon) {
let source = this._lookupSource(null, icon.pid, true); let source = this._lookupSource(icon.pid, null, true);
if (source) if (source)
source.destroy(); source.destroy();
} }
}); };
const Source = new Lang.Class({ DBus.conformExport(NotificationDaemon.prototype, NotificationDaemonIface);
Name: 'NotificationDaemonSource',
Extends: MessageTray.Source, function Source(title, pid, sender) {
this._init(title, pid, sender);
}
Source.prototype = {
__proto__: MessageTray.Source.prototype,
_init: function(title, pid, sender, trayIcon) { _init: function(title, pid, sender, trayIcon) {
this.parent(title); MessageTray.Source.prototype._init.call(this, title);
this.initialTitle = title; this.initialTitle = title;
this.pid = pid; this.pid = pid;
if (sender) if (sender)
this._nameWatcherId = Gio.DBus.session.watch_name(sender, // TODO: dbus-glib implementation of watch_name() doesnt return an id to be used for
Gio.BusNameWatcherFlags.NONE, // unwatch_name() or implement unwatch_name(), however when we move to using GDBus implementation,
// we should save the id here and call unwatch_name() with it in destroy().
// Moving to GDBus is the work in progress: https://bugzilla.gnome.org/show_bug.cgi?id=648651
// and https://bugzilla.gnome.org/show_bug.cgi?id=622921 .
DBus.session.watch_name(sender,
false,
null, null,
Lang.bind(this, this._onNameVanished)); Lang.bind(this, this._onNameVanished));
else
this._nameWatcherId = 0;
this._setApp(); this._setApp();
if (this.app) if (this.app)
@ -616,11 +617,6 @@ const Source = new Lang.Class({
}, },
destroy: function() { destroy: function() {
if (this._nameWatcherId) { MessageTray.Source.prototype.destroy.call(this);
Gio.DBus.session.unwatch_name(this._nameWatcherId);
this._nameWatcherId = 0;
} }
};
this.parent();
}
});

View File

@ -14,16 +14,15 @@ const AppDisplay = imports.ui.appDisplay;
const ContactDisplay = imports.ui.contactDisplay; 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 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;
@ -47,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;
@ -94,11 +95,13 @@ 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);
}
Overview.prototype = {
_init : function(params) { _init : function(params) {
params = Params.parse(params, { isDummy: false }); params = Params.parse(params, { isDummy: false });
@ -109,6 +112,7 @@ const Overview = new Lang.Class({
if (this.isDummy) { if (this.isDummy) {
this.animationInProgress = false; this.animationInProgress = false;
this.visible = false; this.visible = false;
this.workspaces = null;
return; return;
} }
@ -126,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',
@ -183,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
@ -205,16 +208,12 @@ 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());
this.addSearchProvider(new ContactDisplay.ContactSearchProvider()); this.addSearchProvider(new ContactDisplay.ContactSearchProvider());
// Load remote search providers provided by applications
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();
this._group.add_actor(this._dash.actor); this._group.add_actor(this._dash.actor);
@ -360,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;
@ -452,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;
@ -493,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;
@ -592,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,
@ -730,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,
@ -739,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,
@ -781,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();
@ -806,5 +811,5 @@ const Overview = new Lang.Class({
this._needsFakePointerEvent = false; this._needsFakePointerEvent = false;
} }
} }
}); };
Signals.addSignalMethods(Overview.prototype); Signals.addSignalMethods(Overview.prototype);

View File

@ -3,20 +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 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;
@ -103,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));
@ -235,7 +225,7 @@ const TextShadower = new Lang.Class({
child.allocate(childBox, flags); child.allocate(childBox, flags);
} }
} }
}); };
/** /**
* AppMenuButton: * AppMenuButton:
@ -245,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;
@ -285,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();
@ -304,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));
@ -318,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,
@ -418,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 {
@ -440,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 {
@ -449,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;
@ -464,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) {
@ -480,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
@ -490,17 +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();
},
_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;
@ -518,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;
@ -532,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;
} }
@ -545,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));
@ -624,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);
@ -641,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;
@ -668,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);
@ -685,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() {
@ -753,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;
@ -822,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)
@ -868,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);
@ -879,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();
@ -909,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 });
@ -943,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);
@ -959,7 +927,6 @@ 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 (global.session_type == Shell.SessionType.USER) { if (global.session_type == Shell.SessionType.USER) {
@ -971,8 +938,9 @@ const Panel = new Lang.Class({
// 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);
this._appMenu = new AppMenuButton(this._menus); this._appMenu = new AppMenuButton();
this._leftBox.add(this._appMenu.actor); this._leftBox.add(this._appMenu.actor);
this._menus.addMenu(this._appMenu.menu);
} }
/* center */ /* center */
@ -1027,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;
@ -1046,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);
@ -1074,54 +1042,6 @@ 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 (Main.overview.visible || menu.isOpen)
return;
menu.open();
menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
},
startStatusArea: function() { startStatusArea: function() {
for (let i = 0; i < this._status_area_order.length; i++) { for (let i = 0; i < this._status_area_order.length; i++) {
let role = this._status_area_order[i]; let role = this._status_area_order[i];
@ -1142,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;
}, },
@ -1194,4 +1114,5 @@ const Panel = new Lang.Class({
if (box && box._delegate instanceof PanelMenu.ButtonBox) if (box && box._delegate instanceof PanelMenu.ButtonBox)
box.destroy(); box.destroy();
}, },
});
};

View File

@ -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,71 +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();
}
}, },
_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();
@ -191,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() {
@ -209,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) {
@ -238,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;
} }
}); }
};

View File

@ -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
@ -191,9 +195,9 @@ const PlacesManager = new Lang.Class({
this._bookmarksPath = GLib.build_filenamev([GLib.get_home_dir(), '.gtk-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); let monitor = this._bookmarksFile.monitor_file(Gio.FileMonitorFlags.NONE, null);
this._bookmarkTimeoutId = 0; this._bookmarkTimeoutId = 0;
this._monitor.connect('changed', Lang.bind(this, function () { monitor.connect('changed', Lang.bind(this, function () {
if (this._bookmarkTimeoutId > 0) if (this._bookmarkTimeoutId > 0)
return; return;
/* Defensive event compression */ /* Defensive event compression */
@ -356,32 +360,31 @@ 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"));
}, },
getResultMetas: function(resultIds) { getResultMeta: function(resultId) {
let metas = []; let placeInfo = Main.placesManager.lookupPlaceById(resultId);
for (let i = 0; i < resultIds.length; i++) {
let placeInfo = Main.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);
} }
}); };
}
return metas;
}, },
activateResult: function(id, params) { activateResult: function(id, params) {
@ -431,4 +434,4 @@ const PlaceSearchProvider = new Lang.Class({
let places = previousResults.map(function (id) { return Main.placesManager.lookupPlaceById(id); }); let places = previousResults.map(function (id) { return Main.placesManager.lookupPlaceById(id); });
return this._searchPlaces(places, terms); return this._searchPlaces(places, terms);
} }
}); };

View File

@ -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()
@ -137,9 +135,9 @@ const AuthenticationDialog = new Lang.Class({
this._passwordBox = new St.BoxLayout({ vertical: false }); 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); 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 });
@ -149,13 +147,13 @@ const AuthenticationDialog = new Lang.Class({
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,7 +163,7 @@ 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.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;
@ -332,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));
@ -393,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();

View File

@ -2,14 +2,11 @@
const Cairo = imports.cairo; const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk; const Gtk = imports.gi.Gtk;
const Gio = imports.gi.Gio;
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 St = imports.gi.St; const St = imports.gi.St;
const Atk = imports.gi.Atk;
const BoxPointer = imports.ui.boxpointer; const BoxPointer = imports.ui.boxpointer;
const Main = imports.ui.main; const Main = imports.ui.main;
@ -29,9 +26,11 @@ function _ensureStyle(actor) {
actor.ensure_style(); actor.ensure_style();
} }
const PopupBaseMenuItem = new Lang.Class({ function PopupBaseMenuItem(params) {
Name: 'PopupBaseMenuItem', this._init(params);
}
PopupBaseMenuItem.prototype = {
_init: function (params) { _init: function (params) {
params = Params.parse (params, { reactive: true, params = Params.parse (params, { reactive: true,
activate: true, activate: true,
@ -42,8 +41,7 @@ const PopupBaseMenuItem = new Lang.Class({
this.actor = new Shell.GenericContainer({ style_class: 'popup-menu-item', this.actor = new Shell.GenericContainer({ style_class: 'popup-menu-item',
reactive: params.reactive, reactive: params.reactive,
track_hover: params.reactive, track_hover: params.reactive,
can_focus: params.reactive, can_focus: params.reactive });
accessible_role: Atk.Role.MENU_ITEM});
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));
@ -110,15 +108,13 @@ const PopupBaseMenuItem = new Lang.Class({
this.emit('activate', event); this.emit('activate', event);
}, },
setActive: function (active, params) { setActive: function (active) {
let activeChanged = active != this.active; let activeChanged = active != this.active;
params = Params.parse (params, { grabKeyboard: true });
if (activeChanged) { if (activeChanged) {
this.active = active; this.active = active;
if (active) { if (active) {
this.actor.add_style_pseudo_class('active'); this.actor.add_style_pseudo_class('active');
if (params.grabKeyboard)
this.actor.grab_key_focus(); this.actor.grab_key_focus();
} else } else
this.actor.remove_style_pseudo_class('active'); this.actor.remove_style_pseudo_class('active');
@ -275,7 +271,7 @@ const PopupBaseMenuItem = new Lang.Class({
_allocate: function(actor, box, flags) { _allocate: function(actor, box, flags) {
let height = box.y2 - box.y1; let height = box.y2 - box.y1;
let direction = this.actor.get_text_direction(); let direction = this.actor.get_direction();
if (this._dot) { if (this._dot) {
// The dot is placed outside box // The dot is placed outside box
@ -285,7 +281,7 @@ const PopupBaseMenuItem = new Lang.Class({
let dotBox = new Clutter.ActorBox(); let dotBox = new Clutter.ActorBox();
let dotWidth = Math.round(box.x1 / 2); let dotWidth = Math.round(box.x1 / 2);
if (direction == Clutter.TextDirection.LTR) { if (direction == St.TextDirection.LTR) {
dotBox.x1 = Math.round(box.x1 / 4); dotBox.x1 = Math.round(box.x1 / 4);
dotBox.x2 = dotBox.x1 + dotWidth; dotBox.x2 = dotBox.x1 + dotWidth;
} else { } else {
@ -298,7 +294,7 @@ const PopupBaseMenuItem = new Lang.Class({
} }
let x; let x;
if (direction == Clutter.TextDirection.LTR) if (direction == St.TextDirection.LTR)
x = box.x1; x = box.x1;
else else
x = box.x2; x = box.x2;
@ -313,7 +309,7 @@ const PopupBaseMenuItem = new Lang.Class({
let availWidth, extraWidth; let availWidth, extraWidth;
if (this._columnWidths) { if (this._columnWidths) {
if (child.span == -1) { if (child.span == -1) {
if (direction == Clutter.TextDirection.LTR) if (direction == St.TextDirection.LTR)
availWidth = box.x2 - x; availWidth = box.x2 - x;
else else
availWidth = x - box.x1; availWidth = x - box.x1;
@ -325,7 +321,7 @@ const PopupBaseMenuItem = new Lang.Class({
extraWidth = availWidth - naturalWidth; extraWidth = availWidth - naturalWidth;
} else { } else {
if (child.span == -1) { if (child.span == -1) {
if (direction == Clutter.TextDirection.LTR) if (direction == St.TextDirection.LTR)
availWidth = box.x2 - x; availWidth = box.x2 - x;
else else
availWidth = x - box.x1; availWidth = x - box.x1;
@ -335,7 +331,7 @@ const PopupBaseMenuItem = new Lang.Class({
extraWidth = 0; extraWidth = 0;
} }
if (direction == Clutter.TextDirection.LTR) { if (direction == St.TextDirection.LTR) {
if (child.expand) { if (child.expand) {
childBox.x1 = x; childBox.x1 = x;
childBox.x2 = x + availWidth; childBox.x2 = x + availWidth;
@ -373,34 +369,39 @@ const PopupBaseMenuItem = new Lang.Class({
child.actor.allocate(childBox, flags); child.actor.allocate(childBox, flags);
if (direction == Clutter.TextDirection.LTR) if (direction == St.TextDirection.LTR)
x += availWidth + this._spacing; x += availWidth + this._spacing;
else else
x -= availWidth + this._spacing; x -= availWidth + this._spacing;
} }
} }
}); };
Signals.addSignalMethods(PopupBaseMenuItem.prototype); Signals.addSignalMethods(PopupBaseMenuItem.prototype);
const PopupMenuItem = new Lang.Class({ function PopupMenuItem() {
Name: 'PopupMenuItem', this._init.apply(this, arguments);
Extends: PopupBaseMenuItem, }
PopupMenuItem.prototype = {
__proto__: PopupBaseMenuItem.prototype,
_init: function (text, params) { _init: function (text, params) {
this.parent(params); PopupBaseMenuItem.prototype._init.call(this, params);
this.label = new St.Label({ text: text }); this.label = new St.Label({ text: text });
this.addActor(this.label); this.addActor(this.label);
this.actor.label_actor = this.label
} }
}); };
const PopupSeparatorMenuItem = new Lang.Class({ function PopupSeparatorMenuItem() {
Name: 'PopupSeparatorMenuItem', this._init();
Extends: PopupBaseMenuItem, }
PopupSeparatorMenuItem.prototype = {
__proto__: PopupBaseMenuItem.prototype,
_init: function () { _init: function () {
this.parent({ reactive: false }); PopupBaseMenuItem.prototype._init.call(this, { reactive: false });
this._drawingArea = new St.DrawingArea({ style_class: 'popup-separator-menu-item' }); this._drawingArea = new St.DrawingArea({ style_class: 'popup-separator-menu-item' });
this.addActor(this._drawingArea, { span: -1, expand: true }); this.addActor(this._drawingArea, { span: -1, expand: true });
@ -426,19 +427,22 @@ const PopupSeparatorMenuItem = new Lang.Class({
cr.rectangle(margin, gradientOffset, gradientWidth, gradientHeight); cr.rectangle(margin, gradientOffset, gradientWidth, gradientHeight);
cr.fill(); cr.fill();
} }
}); };
const PopupAlternatingMenuItemState = { const PopupAlternatingMenuItemState = {
DEFAULT: 0, DEFAULT: 0,
ALTERNATIVE: 1 ALTERNATIVE: 1
} }
const PopupAlternatingMenuItem = new Lang.Class({ function PopupAlternatingMenuItem() {
Name: 'PopupAlternatingMenuItem', this._init.apply(this, arguments);
Extends: PopupBaseMenuItem, }
PopupAlternatingMenuItem.prototype = {
__proto__: PopupBaseMenuItem.prototype,
_init: function(text, alternateText, params) { _init: function(text, alternateText, params) {
this.parent(params); PopupBaseMenuItem.prototype._init.call(this, params);
this.actor.add_style_class_name('popup-alternating-menu-item'); this.actor.add_style_class_name('popup-alternating-menu-item');
this._text = text; this._text = text;
@ -446,7 +450,6 @@ const PopupAlternatingMenuItem = new Lang.Class({
this.label = new St.Label({ text: text }); this.label = new St.Label({ text: text });
this.state = PopupAlternatingMenuItemState.DEFAULT; this.state = PopupAlternatingMenuItemState.DEFAULT;
this.addActor(this.label); this.addActor(this.label);
this.actor.label_actor = this.label;
this.actor.connect('notify::mapped', Lang.bind(this, this._onMapped)); this.actor.connect('notify::mapped', Lang.bind(this, this._onMapped));
}, },
@ -525,14 +528,17 @@ const PopupAlternatingMenuItem = new Lang.Class({
this._updateLabel(); this._updateLabel();
} }
}); };
const PopupSliderMenuItem = new Lang.Class({ function PopupSliderMenuItem() {
Name: 'PopupSliderMenuItem', this._init.apply(this, arguments);
Extends: PopupBaseMenuItem, }
PopupSliderMenuItem.prototype = {
__proto__: PopupBaseMenuItem.prototype,
_init: function(value) { _init: function(value) {
this.parent({ activate: false }); PopupBaseMenuItem.prototype._init.call(this, { activate: false });
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent)); this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
@ -708,14 +714,15 @@ const PopupSliderMenuItem = new Lang.Class({
} }
return false; return false;
} }
}); };
const Switch = new Lang.Class({ function Switch() {
Name: 'Switch', this._init.apply(this, arguments);
}
Switch.prototype = {
_init: function(state) { _init: function(state) {
this.actor = new St.Bin({ style_class: 'toggle-switch', this.actor = new St.Bin({ style_class: 'toggle-switch' });
accessible_role: Atk.Role.CHECK_BOX});
// Translators: this MUST be either "toggle-switch-us" // Translators: this MUST be either "toggle-switch-us"
// (for toggle switches containing the English words // (for toggle switches containing the English words
// "ON" and "OFF") or "toggle-switch-intl" (for toggle // "ON" and "OFF") or "toggle-switch-intl" (for toggle
@ -736,22 +743,21 @@ const Switch = new Lang.Class({
toggle: function() { toggle: function() {
this.setToggleState(!this.state); this.setToggleState(!this.state);
} }
}); };
const PopupSwitchMenuItem = new Lang.Class({ function PopupSwitchMenuItem() {
Name: 'PopupSwitchMenuItem', this._init.apply(this, arguments);
Extends: PopupBaseMenuItem, }
PopupSwitchMenuItem.prototype = {
__proto__: PopupBaseMenuItem.prototype,
_init: function(text, active, params) { _init: function(text, active, params) {
this.parent(params); PopupBaseMenuItem.prototype._init.call(this, params);
this.label = new St.Label({ text: text }); this.label = new St.Label({ text: text });
this._switch = new Switch(active); this._switch = new Switch(active);
this.actor.accessible_role = Atk.Role.CHECK_MENU_ITEM;
this.checkAccessibleState();
this.actor.label_actor = this.label;
this.addActor(this.label); this.addActor(this.label);
this._statusBin = new St.Bin({ x_align: St.Align.END }); this._statusBin = new St.Bin({ x_align: St.Align.END });
@ -770,14 +776,11 @@ const PopupSwitchMenuItem = new Lang.Class({
this._statusBin.child = this._statusLabel; this._statusBin.child = this._statusLabel;
this.actor.reactive = false; this.actor.reactive = false;
this.actor.can_focus = false; this.actor.can_focus = false;
this.actor.accessible_role = Atk.Role.MENU_ITEM;
} else { } else {
this._statusBin.child = this._switch.actor; this._statusBin.child = this._switch.actor;
this.actor.reactive = true; this.actor.reactive = true;
this.actor.can_focus = true; this.actor.can_focus = true;
this.actor.accessible_role = Atk.Role.CHECK_MENU_ITEM;
} }
this.checkAccessibleState();
}, },
activate: function(event) { activate: function(event) {
@ -785,19 +788,12 @@ const PopupSwitchMenuItem = new Lang.Class({
this.toggle(); this.toggle();
} }
// we allow pressing space to toggle the switch PopupBaseMenuItem.prototype.activate.call(this, event);
// without closing the menu
if (event.type() == Clutter.EventType.KEY_PRESS &&
event.get_key_symbol() == Clutter.KEY_space)
return;
this.parent(event);
}, },
toggle: function() { toggle: function() {
this._switch.toggle(); this._switch.toggle();
this.emit('toggled', this._switch.state); this.emit('toggled', this._switch.state);
this.checkAccessibleState();
}, },
get state() { get state() {
@ -806,29 +802,18 @@ const PopupSwitchMenuItem = new Lang.Class({
setToggleState: function(state) { setToggleState: function(state) {
this._switch.setToggleState(state); this._switch.setToggleState(state);
this.checkAccessibleState();
},
checkAccessibleState: function() {
switch (this.actor.accessible_role) {
case Atk.Role.CHECK_MENU_ITEM:
if (this._switch.state)
this.actor.add_accessible_state (Atk.StateType.CHECKED);
else
this.actor.remove_accessible_state (Atk.StateType.CHECKED);
break;
default:
this.actor.remove_accessible_state (Atk.StateType.CHECKED);
} }
} };
});
const PopupImageMenuItem = new Lang.Class({ function PopupImageMenuItem() {
Name: 'PopupImageMenuItem', this._init.apply(this, arguments);
Extends: PopupBaseMenuItem, }
PopupImageMenuItem.prototype = {
__proto__: PopupBaseMenuItem.prototype,
_init: function (text, iconName, params) { _init: function (text, iconName, params) {
this.parent(params); PopupBaseMenuItem.prototype._init.call(this, params);
this.label = new St.Label({ text: text }); this.label = new St.Label({ text: text });
this.addActor(this.label); this.addActor(this.label);
@ -841,12 +826,13 @@ const PopupImageMenuItem = new Lang.Class({
setIcon: function(name) { setIcon: function(name) {
this._icon.icon_name = name; this._icon.icon_name = name;
} }
}); };
const PopupMenuBase = new Lang.Class({ function PopupMenuBase() {
Name: 'PopupMenuBase', throw new TypeError('Trying to instantiate abstract class PopupMenuBase');
Abstract: true, }
PopupMenuBase.prototype = {
_init: function(sourceActor, styleClass) { _init: function(sourceActor, styleClass) {
this.sourceActor = sourceActor; this.sourceActor = sourceActor;
@ -902,10 +888,6 @@ const PopupMenuBase = new Lang.Class({
return menuItem; return menuItem;
}, },
isEmpty: function() {
return this.box.get_children().length == 0;
},
isChildMenu: function(menu) { isChildMenu: function(menu) {
return this._childMenus.indexOf(menu) != -1; return this._childMenus.indexOf(menu) != -1;
}, },
@ -976,12 +958,7 @@ const PopupMenuBase = new Lang.Class({
this.emit('activate', menuItem); this.emit('activate', menuItem);
this.close(true); this.close(true);
})); }));
// the weird name is to avoid a conflict with some random property menuItem.connect('destroy', Lang.bind(this, function(emitter) {
// the menuItem may have, called destroyId
// (FIXME: in the future it may make sense to have container objects
// like PopupMenuManager does)
menuItem._popupMenuDestroyId = menuItem.connect('destroy', Lang.bind(this, function(menuItem) {
menuItem.disconnect(menuItem._popupMenuDestroyId);
menuItem.disconnect(menuItem._activateId); menuItem.disconnect(menuItem._activateId);
menuItem.disconnect(menuItem._activeChangeId); menuItem.disconnect(menuItem._activeChangeId);
menuItem.disconnect(menuItem._sensitiveChangeId); menuItem.disconnect(menuItem._sensitiveChangeId);
@ -1036,19 +1013,12 @@ const PopupMenuBase = new Lang.Class({
let items = this._getMenuItems(); let items = this._getMenuItems();
if (position < items.length) { if (position < items.length) {
before_item = items[position].actor; before_item = items[position].actor;
this.box.insert_child_below(menuItem.actor, before_item); this.box.insert_before(menuItem.actor, before_item);
} else { } else
this.box.add(menuItem.actor); this.box.add(menuItem.actor);
} }
}
if (menuItem instanceof PopupMenuSection) { if (menuItem instanceof PopupMenuSection) {
this._connectSubMenuSignals(menuItem, menuItem); this._connectSubMenuSignals(menuItem, menuItem);
menuItem._closingId = this.connect('open-state-changed',
function(self, open) {
if (!open)
menuItem.close(false);
});
menuItem.connect('destroy', Lang.bind(this, function() { menuItem.connect('destroy', Lang.bind(this, function() {
menuItem.disconnect(menuItem._subMenuActivateId); menuItem.disconnect(menuItem._subMenuActivateId);
menuItem.disconnect(menuItem._subMenuActiveChangeId); menuItem.disconnect(menuItem._subMenuActiveChangeId);
@ -1059,7 +1029,7 @@ const PopupMenuBase = new Lang.Class({
if (before_item == null) if (before_item == null)
this.box.add(menuItem.menu.actor); this.box.add(menuItem.menu.actor);
else else
this.box.insert_child_below(menuItem.menu.actor, before_item); this.box.insert_before(menuItem.menu.actor, before_item);
this._connectSubMenuSignals(menuItem, menuItem.menu); this._connectSubMenuSignals(menuItem, menuItem.menu);
this._connectItemSignals(menuItem); this._connectItemSignals(menuItem);
menuItem._closingId = this.connect('open-state-changed', function(self, open) { menuItem._closingId = this.connect('open-state-changed', function(self, open) {
@ -1162,15 +1132,18 @@ const PopupMenuBase = new Lang.Class({
this.emit('destroy'); this.emit('destroy');
} }
}); };
Signals.addSignalMethods(PopupMenuBase.prototype); Signals.addSignalMethods(PopupMenuBase.prototype);
const PopupMenu = new Lang.Class({ function PopupMenu() {
Name: 'PopupMenu', this._init.apply(this, arguments);
Extends: PopupMenuBase, }
PopupMenu.prototype = {
__proto__: PopupMenuBase.prototype,
_init: function(sourceActor, arrowAlignment, arrowSide) { _init: function(sourceActor, arrowAlignment, arrowSide) {
this.parent(sourceActor, 'popup-menu-content'); PopupMenuBase.prototype._init.call (this, sourceActor, 'popup-menu-content');
this._arrowAlignment = arrowAlignment; this._arrowAlignment = arrowAlignment;
this._arrowSide = arrowSide; this._arrowSide = arrowSide;
@ -1233,9 +1206,6 @@ const PopupMenu = new Lang.Class({
if (this.isOpen) if (this.isOpen)
return; return;
if (this.isEmpty())
return;
this.isOpen = true; this.isOpen = true;
this._boxPointer.setPosition(this.sourceActor, this._arrowAlignment); this._boxPointer.setPosition(this.sourceActor, this._arrowAlignment);
@ -1258,14 +1228,17 @@ const PopupMenu = new Lang.Class({
this.isOpen = false; this.isOpen = false;
this.emit('open-state-changed', false); this.emit('open-state-changed', false);
} }
}); };
const PopupSubMenu = new Lang.Class({ function PopupSubMenu() {
Name: 'PopupSubMenu', this._init.apply(this, arguments);
Extends: PopupMenuBase, }
PopupSubMenu.prototype = {
__proto__: PopupMenuBase.prototype,
_init: function(sourceActor, sourceArrow) { _init: function(sourceActor, sourceArrow) {
this.parent(sourceActor); PopupMenuBase.prototype._init.call(this, sourceActor);
this._arrow = sourceArrow; this._arrow = sourceArrow;
this._arrow.rotation_center_z_gravity = Clutter.Gravity.CENTER; this._arrow.rotation_center_z_gravity = Clutter.Gravity.CENTER;
@ -1327,9 +1300,6 @@ const PopupSubMenu = new Lang.Class({
if (this.isOpen) if (this.isOpen)
return; return;
if (this.isEmpty())
return;
this.isOpen = true; this.isOpen = true;
this.actor.show(); this.actor.show();
@ -1423,7 +1393,7 @@ const PopupSubMenu = new Lang.Class({
return false; return false;
} }
}); };
/** /**
* PopupMenuSection: * PopupMenuSection:
@ -1433,47 +1403,40 @@ const PopupSubMenu = new Lang.Class({
* can add it to another menu), but is completely transparent * can add it to another menu), but is completely transparent
* to the user * to the user
*/ */
const PopupMenuSection = new Lang.Class({ function PopupMenuSection() {
Name: 'PopupMenuSection', this._init.apply(this, arguments);
Extends: PopupMenuBase, }
PopupMenuSection.prototype = {
__proto__: PopupMenuBase.prototype,
_init: function() { _init: function() {
this.parent(); PopupMenuBase.prototype._init.call(this);
this.actor = this.box; this.actor = this.box;
this.actor._delegate = this; this.actor._delegate = this;
this.isOpen = true; this.isOpen = true;
// an array of externally managed separators
this.separators = [];
}, },
// deliberately ignore any attempt to open() or close(), but emit the // deliberately ignore any attempt to open() or close()
// corresponding signal so children can still pick it up open: function(animate) { },
open: function(animate) { this.emit('open-state-changed', true); }, close: function() { },
close: function() { this.emit('open-state-changed', false); }, }
destroy: function() { function PopupSubMenuMenuItem() {
for (let i = 0; i < this.separators.length; i++) this._init.apply(this, arguments);
this.separators[i].destroy(); }
this.separators = [];
this.parent(); PopupSubMenuMenuItem.prototype = {
} __proto__: PopupBaseMenuItem.prototype,
});
const PopupSubMenuMenuItem = new Lang.Class({
Name: 'PopupSubMenuMenuItem',
Extends: PopupBaseMenuItem,
_init: function(text) { _init: function(text) {
this.parent(); PopupBaseMenuItem.prototype._init.call(this);
this.actor.add_style_class_name('popup-submenu-menu-item'); this.actor.add_style_class_name('popup-submenu-menu-item');
this.label = new St.Label({ text: text }); this.label = new St.Label({ text: text });
this.addActor(this.label); this.addActor(this.label);
this.actor.label_actor = this.label;
this._triangle = new St.Label({ text: '\u25B8' }); this._triangle = new St.Label({ text: '\u25B8' });
this.addActor(this._triangle, { align: St.Align.END }); this.addActor(this._triangle, { align: St.Align.END });
@ -1490,8 +1453,7 @@ const PopupSubMenuMenuItem = new Lang.Class({
destroy: function() { destroy: function() {
this.menu.destroy(); this.menu.destroy();
PopupBaseMenuItem.prototype.destroy.call(this);
this.parent();
}, },
_onKeyPressEvent: function(actor, event) { _onKeyPressEvent: function(actor, event) {
@ -1506,7 +1468,7 @@ const PopupSubMenuMenuItem = new Lang.Class({
return true; return true;
} }
return this.parent(actor, event); return PopupBaseMenuItem.prototype._onKeyPressEvent.call(this, actor, event);
}, },
activate: function(event) { activate: function(event) {
@ -1516,21 +1478,22 @@ const PopupSubMenuMenuItem = new Lang.Class({
_onButtonReleaseEvent: function(actor) { _onButtonReleaseEvent: function(actor) {
this.menu.toggle(); this.menu.toggle();
} }
}); };
const PopupComboMenu = new Lang.Class({ function PopupComboMenu() {
Name: 'PopupComboMenu', this._init.apply(this, arguments);
Extends: PopupMenuBase, }
PopupComboMenu.prototype = {
__proto__: PopupMenuBase.prototype,
_init: function(sourceActor) { _init: function(sourceActor) {
this.parent(sourceActor, 'popup-combo-menu'); PopupMenuBase.prototype._init.call(this,
sourceActor, 'popup-combo-menu');
this.actor = this.box; this.actor = this.box;
this.actor._delegate = this; this.actor._delegate = this;
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent)); this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
this.actor.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn)); this.actor.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
sourceActor.connect('style-changed',
Lang.bind(this, this._onSourceActorStyleChanged));
this._activeItemPos = -1; this._activeItemPos = -1;
global.focus_manager.add_group(this.actor); global.focus_manager.add_group(this.actor);
}, },
@ -1550,33 +1513,10 @@ const PopupComboMenu = new Lang.Class({
activeItem.actor.grab_key_focus(); activeItem.actor.grab_key_focus();
}, },
_onSourceActorStyleChanged: function() {
// PopupComboBoxMenuItem clones the active item's actors
// to work with arbitrary items in the menu; this means
// that we need to propagate some style information and
// enforce style updates even when the menu is closed
let activeItem = this._getMenuItems()[this._activeItemPos];
if (this.sourceActor.has_style_pseudo_class('insensitive'))
activeItem.actor.add_style_pseudo_class('insensitive');
else
activeItem.actor.remove_style_pseudo_class('insensitive');
// To propagate the :active style, we need to make sure that the
// internal state of the PopupComboMenu is updated as well, but
// we must not move the keyboard grab
activeItem.setActive(this.sourceActor.has_style_pseudo_class('active'),
{ grabKeyboard: false });
_ensureStyle(this.actor);
},
open: function() { open: function() {
if (this.isOpen) if (this.isOpen)
return; return;
if (this.isEmpty())
return;
this.isOpen = true; this.isOpen = true;
let [sourceX, sourceY] = this.sourceActor.get_transformed_position(); let [sourceX, sourceY] = this.sourceActor.get_transformed_position();
@ -1620,10 +1560,6 @@ const PopupComboMenu = new Lang.Class({
this._activeItemPos = position; this._activeItemPos = position;
}, },
getActiveItem: function() {
return this._getMenuItems()[this._activeItemPos];
},
setItemVisible: function(position, visible) { setItemVisible: function(position, visible) {
if (!visible && position == this._activeItemPos) { if (!visible && position == this._activeItemPos) {
log('Trying to hide the active menu item.'); log('Trying to hide the active menu item.');
@ -1636,16 +1572,17 @@ const PopupComboMenu = new Lang.Class({
getItemVisible: function(position) { getItemVisible: function(position) {
return this._getMenuItems()[position].actor.visible; return this._getMenuItems()[position].actor.visible;
} }
}); };
const PopupComboBoxMenuItem = new Lang.Class({ function PopupComboBoxMenuItem() {
Name: 'PopupComboBoxMenuItem', this._init.apply(this, arguments);
Extends: PopupBaseMenuItem, }
PopupComboBoxMenuItem.prototype = {
__proto__: PopupBaseMenuItem.prototype,
_init: function (params) { _init: function (params) {
this.parent(params); PopupBaseMenuItem.prototype._init.call(this, params);
this.actor.accessible_role = Atk.Role.COMBO_BOX;
this._itemBox = new Shell.Stack(); this._itemBox = new Shell.Stack();
this.addActor(this._itemBox); this.addActor(this._itemBox);
@ -1743,11 +1680,6 @@ const PopupComboBoxMenuItem = new Lang.Class({
Lang.bind(this, this._itemActivated, position)); Lang.bind(this, this._itemActivated, position));
}, },
checkAccessibleLabel: function() {
let activeItem = this._menu.getActiveItem();
this.actor.label_actor = activeItem.label;
},
setActiveItem: function(position) { setActiveItem: function(position) {
let item = this._items[position]; let item = this._items[position];
if (!item) if (!item)
@ -1758,8 +1690,6 @@ const PopupComboBoxMenuItem = new Lang.Class({
this._activeItemPos = position; this._activeItemPos = position;
for (let i = 0; i < this._items.length; i++) for (let i = 0; i < this._items.length; i++)
this._items[i].visible = (i == this._activeItemPos); this._items[i].visible = (i == this._activeItemPos);
this.checkAccessibleLabel();
}, },
setItemVisible: function(position, visible) { setItemVisible: function(position, visible) {
@ -1770,277 +1700,16 @@ const PopupComboBoxMenuItem = new Lang.Class({
this.setActiveItem(position); this.setActiveItem(position);
this.emit('active-item-changed', position); this.emit('active-item-changed', position);
} }
}); };
/**
* RemoteMenu:
*
* A PopupMenu that tracks a GMenuModel and shows its actions
* (exposed by GApplication/GActionGroup)
*/
const RemoteMenu = new Lang.Class({
Name: 'RemoteMenu',
Extends: PopupMenu,
_init: function(sourceActor, model, actionGroup) {
this.parent(sourceActor, 0.0, St.Side.TOP);
this.model = model;
this.actionGroup = actionGroup;
this._actions = { };
this._modelChanged(this.model, 0, 0, this.model.get_n_items(), this);
this._actionStateChangeId = this.actionGroup.connect('action-state-changed', Lang.bind(this, this._actionStateChanged));
this._actionEnableChangeId = this.actionGroup.connect('action-enabled-changed', Lang.bind(this, this._actionEnabledChanged));
},
destroy: function() {
if (this._actionStateChangeId) {
this.actionGroup.disconnect(this._actionStateChangeId);
this._actionStateChangeId = 0;
}
if (this._actionEnableChangeId) {
this.actionGroup.disconnect(this._actionEnableChangeId);
this._actionEnableChangeId = 0;
}
this.parent();
},
_createMenuItem: function(model, index) {
let labelValue = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_LABEL, null);
let label = labelValue ? labelValue.deep_unpack() : '';
// remove all underscores that are not followed by another underscore
label = label.replace(/_([^_])/, '$1');
let section_link = model.get_item_link(index, Gio.MENU_LINK_SECTION);
if (section_link) {
let item = new PopupMenuSection();
if (label) {
let title = new PopupMenuItem(label, { reactive: false,
style_class: 'popup-subtitle-menu-item' });
item._titleMenuItem = title;
title._ignored = true;
item.addMenuItem(title);
}
this._modelChanged(section_link, 0, 0, section_link.get_n_items(), item);
return [item, true, ''];
}
let submenu_link = model.get_item_link(index, Gio.MENU_LINK_SUBMENU);
if (submenu_link) {
let item = new PopupSubMenuMenuItem(label);
this._modelChanged(submenu_link, 0, 0, submenu_link.get_n_items(), item.menu);
return [item, false, ''];
}
let action_id = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_ACTION, null).deep_unpack();
if (!this.actionGroup.has_action(action_id)) {
// the action may not be there yet, wait for action-added
return [null, false, 'action-added'];
}
if (!this._actions[action_id])
this._actions[action_id] = { enabled: this.actionGroup.get_action_enabled(action_id),
state: this.actionGroup.get_action_state(action_id),
items: [ ],
};
let action = this._actions[action_id];
let item, target, destroyId, specificSignalId;
if (action.state) {
// Docs have get_state_hint(), except that the DBus protocol
// has no provision for it (so ShellApp does not implement it,
// and neither GApplication), and g_action_get_state_hint()
// always returns null
// Funny :)
switch (String.fromCharCode(action.state.classify())) {
case 'b':
item = new PopupSwitchMenuItem(label, action.state.get_boolean());
action.items.push(item);
specificSignalId = item.connect('toggled', Lang.bind(this, function(item) {
this.actionGroup.activate_action(action_id, null);
}));
break;
case 's':
item = new PopupMenuItem(label);
item._remoteTarget = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_TARGET, null).deep_unpack();
action.items.push(item);
item.setShowDot(action.state.deep_unpack() == item._remoteTarget);
specificSignalId = item.connect('activate', Lang.bind(this, function(item) {
this.actionGroup.activate_action(action_id, GLib.Variant.new_string(item._remoteTarget));
}));
break;
default:
log('Action "%s" has state of type %s, which is not supported'.format(action_id, action.state.get_type_string()));
return [null, false, 'action-state-changed'];
}
} else {
target = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_TARGET, null);
item = new PopupMenuItem(label);
action.items.push(item);
specificSignalId = item.connect('activate', Lang.bind(this, function() {
this.actionGroup.activate_action(action_id, target);
}));
}
item.actor.reactive = item.actor.can_focus = action.enabled;
if (action.enabled)
item.actor.remove_style_pseudo_class('insensitive');
else
item.actor.add_style_pseudo_class('insensitive');
destroyId = item.connect('destroy', Lang.bind(this, function() {
item.disconnect(destroyId);
item.disconnect(specificSignalId);
let pos = action.items.indexOf(item);
if (pos != -1)
action.items.splice(pos, 1);
}));
return [item, false, ''];
},
_modelChanged: function(model, position, removed, added, target) {
let j, k;
let j0, k0;
let currentItems = target._getMenuItems();
k0 = 0;
// skip ignored items at the beginning
while (k0 < currentItems.length && currentItems[k0]._ignored)
k0++;
// find the right menu item matching the model item
for (j0 = 0; k0 < currentItems.length && j0 < position; j0++, k0++) {
if (currentItems[k0]._ignored)
k0++;
}
if (removed == -1) {
// special flag to indicate we should destroy everything
for (k = k0; k < currentItems.length; k++)
currentItems[k].destroy();
} else {
for (j = j0, k = k0; k < currentItems.length && j < j0 + removed; j++, k++) {
currentItems[k].destroy();
if (currentItems[k]._ignored)
j--;
}
}
for (j = j0, k = k0; j < j0 + added; j++, k++) {
let [item, addSeparator, changeSignal] = this._createMenuItem(model, j);
if (item) {
// separators must be added in the parent to make autohiding work
if (addSeparator) {
let separator = new PopupSeparatorMenuItem();
item.separators.push(separator);
separator._ignored = true;
target.addMenuItem(separator, k+1);
k++;
}
target.addMenuItem(item, k);
if (addSeparator) {
let separator = new PopupSeparatorMenuItem();
item.separators.push(separator);
separator._ignored = true;
target.addMenuItem(separator, k+1);
k++;
}
} else if (changeSignal) {
let signalId = this.actionGroup.connect(changeSignal, Lang.bind(this, function(actionGroup, actionName) {
actionGroup.disconnect(signalId);
if (this._actions[actionName]) return;
// force a full update
this._modelChanged(model, 0, -1, model.get_n_items(), target);
}));
}
}
if (!model._changedId) {
model._changedId = model.connect('items-changed', Lang.bind(this, this._modelChanged, target));
model._destroyId = target.connect('destroy', function() {
if (model._changedId)
model.disconnect(model._changedId);
if (model._destroyId)
target.disconnect(model._destroyId);
model._changedId = 0;
model._destroyId = 0;
});
}
if (target instanceof PopupMenuSection) {
if (target._titleMenuItem)
target.actor.visible = target.numMenuItems != 1;
else
target.actor.visible = target.numMenuItems != 0;
} else {
let sourceItem = target.sourceActor._delegate;
if (sourceItem instanceof PopupSubMenuMenuItem)
sourceItem.actor.visible = target.numMenuItems != 0;
}
},
_actionStateChanged: function(actionGroup, action_id) {
let action = this._actions[action_id];
if (!action)
return;
action.state = actionGroup.get_action_state(action_id);
if (action.items.length) {
switch (String.fromCharCode(action.state.classify())) {
case 'b':
for (let i = 0; i < action.items.length; i++)
action.items[i].setToggleState(action.state.get_boolean());
break;
case 'd':
for (let i = 0; i < action.items.length; i++)
action.items[i].setValue(action.state.get_double());
break;
case 's':
for (let i = 0; i < action.items.length; i++)
action.items[i].setShowDot(action.items[i]._remoteTarget == action.state.deep_unpack());
}
}
},
_actionEnabledChanged: function(actionGroup, action_id) {
let action = this._actions[action_id];
if (!action)
return;
action.enabled = actionGroup.get_action_enabled(action_id);
if (action.items.length) {
for (let i = 0; i < action.items.length; i++) {
let item = action.items[i];
item.actor.reactive = item.actor.can_focus = action.enabled;
if (action.enabled)
item.actor.remove_style_pseudo_class('insensitive');
else
item.actor.add_style_pseudo_class('insensitive');
}
}
}
});
/* Basic implementation of a menu manager. /* Basic implementation of a menu manager.
* Call addMenu to add menus * Call addMenu to add menus
*/ */
const PopupMenuManager = new Lang.Class({ function PopupMenuManager(owner) {
Name: 'PopupMenuManager', this._init(owner);
}
PopupMenuManager.prototype = {
_init: function(owner) { _init: function(owner) {
this._owner = owner; this._owner = owner;
this.grabbed = false; this.grabbed = false;
@ -2312,4 +1981,4 @@ const PopupMenuManager = new Lang.Class({
if (this._activeMenu != null) if (this._activeMenu != null)
this._activeMenu.close(true); this._activeMenu.close(true);
} }
}); };

View File

@ -1,185 +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 icon = keyfile.get_string(group, 'Icon');
let busName = keyfile.get_string(group, 'BusName');
let objectPath = keyfile.get_string(group, 'ObjectPath');
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.async = true;
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]);
},
getInitialResultSetAsync: 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, []);
}
},
getSubsearchResultSetAsync: 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);
},
getResultMetasAsync: 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);
}
});

View File

@ -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);

View File

@ -1,5 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const DBus = imports.dbus;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta; const Meta = imports.gi.Meta;
@ -69,21 +70,24 @@ function waitLeisure() {
}; };
} }
const PerfHelperIface = <interface name="org.gnome.Shell.PerfHelper"> const PerfHelperIface = {
<method name="CreateWindow"> name: 'org.gnome.Shell.PerfHelper',
<arg type="i" direction="in" /> methods: [{ name: 'CreateWindow', inSignature: 'iibb', outSignature: '' },
<arg type="i" direction="in" /> { name: 'WaitWindows', inSignature: '', outSignature: '' },
<arg type="b" direction="in" /> { name: 'DestroyWindows', inSignature: '', outSignature: ''}]
<arg type="b" direction="in" /> };
</method>
<method name="WaitWindows" />
<method name="DestroyWindows" />
</interface>;
var PerfHelperProxy = Gio.DBusProxy.makeProxyWrapper(PerfHelperIface); const PerfHelper = function () {
function PerfHelper() { this._init();
return new PerfHelperProxy(Gio.DBus.session, 'org.gnome.Shell.PerfHelper', '/org/gnome/Shell/PerfHelper'); };
}
PerfHelper.prototype = {
_init: function() {
DBus.session.proxifyObject(this, 'org.gnome.Shell.PerfHelper', '/org/gnome/Shell/PerfHelper');
}
};
DBus.proxifyPrototype(PerfHelper.prototype, PerfHelperIface);
let _perfHelper = null; let _perfHelper = null;
function _getPerfHelper() { function _getPerfHelper() {

View File

@ -23,12 +23,15 @@ const MatchType = {
MULTIPLE_PREFIX: 4 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;
}, },
/** /**
@ -50,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.get_children().forEach(function (actor) { actor.destroy(); }); 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;
}, },
/** /**
@ -64,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:
@ -72,19 +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.
* By default, search is synchronous and uses the
* getInitialResultSet()/getSubsearchResultSet() methods.
* For asynchronous search, set the async property to true
* and implement getInitialResultSetAsync()/getSubsearchResultSetAsync()
* instead.
*/ */
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.async = false; 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);
}, },
/** /**
@ -112,18 +176,6 @@ const SearchProvider = new Lang.Class({
throw new Error('Not implemented'); throw new Error('Not implemented');
}, },
/**
* getInitialResultSetAsync:
* @terms: Array of search terms, treated as logical AND
*
* Like getInitialResultSet(), but the method should return immediately
* without a return value - use SearchSystem.pushResults() when the
* corresponding results are ready.
*/
getInitialResultSetAsync: function(terms) {
throw new Error('Not implemented');
},
/** /**
* getSubsearchResultSet: * getSubsearchResultSet:
* @previousResults: Array of item identifiers * @previousResults: Array of item identifiers
@ -142,40 +194,14 @@ const SearchProvider = new Lang.Class({
}, },
/** /**
* getSubsearchResultSetAsync: * getResultMeta:
* @previousResults: Array of item identifiers * @id: Result identifier string
* @newTerms: Updated search terms
* *
* Like getSubsearchResultSet(), but the method should return immediately * Return an object with 'id', 'name', (both strings) and 'createIcon'
* without a return value - use SearchSystem.pushResults() when the * (function(size) returning a Clutter.Texture) properties which describe
* corresponding results are ready. * the given search result.
*/ */
getSubsearchResultSetAsync: function(previousResults, newTerms) { getResultMeta: function(id) {
throw new Error('Not implemented');
},
/**
* getResultMetas:
* @ids: Result identifier strings
*
* Return an array of objects with 'id', 'name', (both strings) and
* 'createIcon' (function(size) returning a Clutter.Texture) properties
* with the same number of members as @ids
*/
getResultMetas: function(ids) {
throw new Error('Not implemented');
},
/**
* getResultMetasAsync:
* @ids: Result identifier strings
* @callback: callback to pass the results to when ready
*
* Like getResultMetas(), but the method should return immediately
* without a return value - pass the results to the provided @callback
* when ready.
*/
getResultMetasAsync: function(ids, callback) {
throw new Error('Not implemented'); throw new Error('Not implemented');
}, },
@ -217,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));
@ -280,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,
@ -297,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;
@ -310,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();
@ -347,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) {
@ -383,14 +408,10 @@ const SearchSystem = new Lang.Class({
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] = this._previousResults[i]; let [provider, previousResults] = this._previousResults[i];
provider.tryCancelAsync();
try { try {
if (provider.async) {
provider.getSubsearchResultSetAsync(previousResults, terms);
results.push([provider, []]);
} else {
let providerResults = provider.getSubsearchResultSet(previousResults, terms); let providerResults = provider.getSubsearchResultSet(previousResults, terms);
results.push([provider, providerResults]); results.push([provider, providerResults]);
}
} catch (error) { } catch (error) {
global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message); global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
} }
@ -398,14 +419,10 @@ const SearchSystem = new Lang.Class({
} 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 {
if (provider.async) {
provider.getInitialResultSetAsync(terms);
results.push([provider, []]);
} else {
let providerResults = provider.getInitialResultSet(terms); let providerResults = provider.getInitialResultSet(terms);
results.push([provider, providerResults]); results.push([provider, providerResults]);
}
} catch (error) { } catch (error) {
global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message); global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
} }
@ -416,5 +433,5 @@ const SearchSystem = new Lang.Class({
this._previousResults = results; this._previousResults = results;
this.emit('search-completed', results); this.emit('search-completed', results);
}, },
}); };
Signals.addSignalMethods(SearchSystem.prototype); Signals.addSignalMethods(SearchSystem.prototype);

View File

@ -15,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;
@ -32,7 +34,6 @@ 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 });
let icon = new IconGrid.BaseIcon(this.metaInfo['name'], let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
{ createIcon: this.metaInfo['createIcon'] }); { createIcon: this.metaInfo['createIcon'] });
@ -96,87 +97,96 @@ 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;
if (provider.async) {
provider.getResultMetasAsync(results,
Lang.bind(this, this.renderResults));
} else {
let metas = provider.getResultMetas(results);
this.renderResults(metas);
}
})); }));
})); }));
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) * MAX_SEARCH_RESULTS_ROWS
- alreadyVisible; - this._grid.visibleItemsCount();
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._updateCurrentResults)); this._searchSystem.connect('search-updated', Lang.bind(this, this._updateCurrentResults));
@ -212,6 +222,7 @@ 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 = {}; this._providerMetaResults = {};
@ -225,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();
@ -238,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,
@ -257,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);
}, },
@ -290,8 +296,7 @@ const SearchResults = new Lang.Class({
this._providerMeta.push({ provider: provider, this._providerMeta.push({ provider: provider,
actor: providerBox, actor: providerBox,
resultDisplay: resultDisplay, resultDisplay: resultDisplay });
hasPendingResults: false });
this._content.add(providerBox); this._content.add(providerBox);
}, },
@ -307,6 +312,7 @@ const SearchResults = new Lang.Class({
}, },
_clearDisplay: function() { _clearDisplay: function() {
this._selectedProvider = -1;
this._visibleResultsCount = 0; 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];
@ -315,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();
}, },
@ -325,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() {
@ -341,73 +349,13 @@ const SearchResults = new Lang.Class({
return this._providerMeta[this._providers.indexOf(provider)]; return this._providerMeta[this._providers.indexOf(provider)];
}, },
_maybeSetInitialSelection: function() { _updateCurrentResults: function(searchSystem, provider, results) {
let newDefaultResult = null;
for (let i = 0; i < this._providerMeta.length; i++) {
let meta = this._providerMeta[i];
if (meta.hasPendingResults)
return;
if (!meta.actor.visible)
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;
}
},
_updateCurrentResults: function(searchSystem, results) {
let terms = searchSystem.getTerms(); let terms = searchSystem.getTerms();
let [provider, providerResults] = results;
let meta = this._metaForProvider(provider); let meta = this._metaForProvider(provider);
meta.hasPendingResults = false; meta.resultDisplay.clear();
this._updateProviderResults(provider, providerResults, terms);
},
_updateProviderResults: function(provider, providerResults, terms) {
let meta = this._metaForProvider(provider);
if (providerResults.length == 0) {
this._clearDisplayForProvider(provider);
meta.resultDisplay.setResults([], []);
} else {
this._providerMetaResults[provider.title] = providerResults;
meta.resultDisplay.setResults(providerResults, terms);
let results = meta.resultDisplay.getResultsForDisplay();
if (provider.async) {
provider.getResultMetasAsync(results, Lang.bind(this,
function(metas) {
this._clearDisplayForProvider(provider);
meta.actor.show(); meta.actor.show();
this._content.hide(); meta.resultDisplay.renderResults(results, terms);
meta.resultDisplay.renderResults(metas); return true;
this._maybeSetInitialSelection();
this._content.show();
}));
} else {
let metas = provider.getResultMetas(results);
this._clearDisplayForProvider(provider);
meta.actor.show();
meta.resultDisplay.renderResults(metas);
}
}
this._maybeSetInitialSelection();
}, },
_updateResults: function(searchSystem, results) { _updateResults: function(searchSystem, results) {
@ -415,57 +363,127 @@ const SearchResults = new Lang.Class({
this._statusText.set_text(_("No matching results.")); this._statusText.set_text(_("No matching results."));
this._statusText.show(); this._statusText.show();
} else { } else {
this._selectedOpenSearchButton = -1;
this._updateOpenSearchButtonState();
this._statusText.hide(); this._statusText.hide();
} }
let terms = searchSystem.getTerms(); let terms = searchSystem.getTerms();
this._openSearchSystem.setSearchTerms(terms); this._openSearchSystem.setSearchTerms(terms);
// To avoid CSS transitions causing flickering when the first search // To avoid CSS transitions causing flickering
// result stays the same, we hide the content while filling in the // of the selection when the first search result
// results. // stays the same, we hide the content while
// filling in the results and setting the initial
// selection.
this._content.hide(); this._content.hide();
for (let i = 0; i < results.length; i++) { for (let i = 0; i < results.length; i++) {
let [provider, providerResults] = results[i]; let [provider, providerResults] = results[i];
if (providerResults.length == 0) {
this._clearDisplayForProvider(i);
} else {
this._providerMetaResults[provider.title] = providerResults;
this._clearDisplayForProvider(i);
let meta = this._metaForProvider(provider); let meta = this._metaForProvider(provider);
meta.hasPendingResults = provider.async; meta.actor.show();
if (!meta.hasPendingResults) meta.resultDisplay.renderResults(providerResults, terms);
this._updateProviderResults(provider, providerResults, terms);
} }
}
if (this._selectedOpenSearchButton == -1)
this.selectDown(false);
this._content.show(); this._content.show();
return true; return true;
}, },
activateDefault: function() { _modifyActorSelection: function(resultDisplay, up) {
if (this._defaultResult) let success;
this._defaultResult.activate(); 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);
}, },
highlightDefault: function(highlight) { selectUp: function(recursing) {
this._highlightDefault = highlight; if (this._selectedOpenSearchButton == -1) {
if (this._defaultResult) for (let i = this._selectedProvider; i >= 0; i--) {
this._defaultResult.setSelected(highlight); 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);
}
}, },
navigateFocus: function(direction) { selectDown: function(recursing) {
let rtl = this.actor.get_text_direction() == Clutter.TextDirection.RTL; let current = this._selectedProvider;
if (direction == Gtk.DirectionType.TAB_BACKWARD || if (this._selectedOpenSearchButton == -1) {
direction == (rtl ? Gtk.DirectionType.RIGHT if (current == -1)
: Gtk.DirectionType.LEFT) || current = 0;
direction == Gtk.DirectionType.UP) { for (let i = current; i < this._providerMeta.length; i++) {
this.actor.navigate_focus(null, direction, false); 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++;
if (this._selectedOpenSearchButton < this._openSearchProviders.length) {
this._updateOpenSearchButtonState();
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();
}
};

View File

@ -1,94 +1,79 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const DBus = imports.dbus;
const Lang = imports.lang; const Lang = imports.lang;
const Gio = imports.gi.Gio;
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 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 = {
<method name="Eval"> name: 'org.gnome.Shell',
<arg type="s" direction="in" name="script" /> methods: [{ name: 'Eval',
<arg type="b" direction="out" name="success" /> inSignature: 's',
<arg type="s" direction="out" name="result" /> outSignature: 'bs'
</method> },
<method name="ListExtensions"> { name: 'ListExtensions',
<arg type="a{sa{sv}}" direction="out" name="extensions" /> inSignature: '',
</method> outSignature: 'a{sa{sv}}'
<method name="GetExtensionInfo"> },
<arg type="s" direction="in" name="extension" /> { name: 'GetExtensionInfo',
<arg type="a{sv}" direction="out" name="info" /> inSignature: 's',
</method> outSignature: 'a{sv}'
<method name="GetExtensionErrors"> },
<arg type="s" direction="in" name="extension" /> { name: 'GetExtensionErrors',
<arg type="as" direction="out" name="errors" /> inSignature: 's',
</method> outSignature: 'as'
<method name="ScreenshotArea"> },
<arg type="i" direction="in" name="x"/> { name: 'ScreenshotArea',
<arg type="i" direction="in" name="y"/> inSignature: 'iiiis',
<arg type="i" direction="in" name="width"/> outSignature: 'b'
<arg type="i" direction="in" name="height"/> },
<arg type="b" direction="in" name="flash"/> { name: 'ScreenshotWindow',
<arg type="s" direction="in" name="filename"/> inSignature: 'bs',
<arg type="b" direction="out" name="success"/> outSignature: 'b'
</method> },
<method name="ScreenshotWindow"> { name: 'Screenshot',
<arg type="b" direction="in" name="include_frame"/> inSignature: 's',
<arg type="b" direction="in" name="include_cursor"/> outSignature: 'b'
<arg type="b" direction="in" name="flash"/> },
<arg type="s" direction="in" name="filename"/> { name: 'EnableExtension',
<arg type="b" direction="out" name="success"/> inSignature: 's',
</method> outSignature: ''
<method name="Screenshot"> },
<arg type="b" direction="in" name="include_cursor"/> { name: 'DisableExtension',
<arg type="b" direction="in" name="flash"/> inSignature: 's',
<arg type="s" direction="in" name="filename"/> outSignature: ''
<arg type="b" direction="out" name="success"/> },
</method> { name: 'InstallRemoteExtension',
<method name="FlashArea"> inSignature: 'ss',
<arg type="i" direction="in" name="x"/> outSignature: ''
<arg type="i" direction="in" name="y"/> },
<arg type="i" direction="in" name="width"/> { name: 'UninstallExtension',
<arg type="i" direction="in" name="height"/> inSignature: 's',
</method> outSignature: 'b'
<method name="EnableExtension"> }
<arg type="s" direction="in" name="uuid"/> ],
</method> signals: [{ name: 'ExtensionStatusChanged',
<method name="DisableExtension"> inSignature: 'sis' }],
<arg type="s" direction="in" name="uuid"/> properties: [{ name: 'OverviewActive',
</method> signature: 'b',
<method name="InstallRemoteExtension"> access: 'readwrite' },
<arg type="s" direction="in" name="uuid"/> { name: 'ApiVersion',
<arg type="s" direction="in" name="version"/> signature: 'i',
</method> access: 'read' },
<method name="UninstallExtension"> { name: 'ShellVersion',
<arg type="s" direction="in" name="uuid"/> signature: 's',
<arg type="b" direction="out" name="success"/> access: 'read' }]
</method> };
<method name="LaunchExtensionPrefs">
<arg type="s" direction="in" name="uuid"/>
</method>
<property name="OverviewActive" type="b" access="readwrite" />
<property name="ApiVersion" type="i" access="read" />
<property name="ShellVersion" type="s" access="read" />
<signal name="ExtensionStatusChanged">
<arg type="s" name="uuid"/>
<arg type="i" name="state"/>
<arg type="s" name="error"/>
</signal>
</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); DBus.session.exportObject('/org/gnome/Shell', this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
ExtensionSystem.connect('extension-state-changed', ExtensionSystem.connect('extension-state-changed',
Lang.bind(this, this._extensionStateChanged)); Lang.bind(this, this._extensionStateChanged));
}, },
@ -108,9 +93,6 @@ const GnomeShell = new Lang.Class({
* *
*/ */
Eval: function(code) { Eval: function(code) {
if (!global.settings.get_boolean('development-tools'))
return [false, null];
let returnValue; let returnValue;
let success; let success;
try { try {
@ -126,23 +108,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
@ -150,19 +121,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)
@ -170,94 +135,33 @@ 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) {
let flashspot = new Flashspot.Flashspot({ x : x, y : y, width: width, height: height});
flashspot.fire();
}, },
ListExtensions: function() { ListExtensions: function() {
let out = {}; return ExtensionSystem.extensionMeta;
for (let uuid in ExtensionUtils.extensions) {
let dbusObj = this.GetExtensionInfo(uuid);
out[uuid] = dbusObj;
}
return out;
}, },
GetExtensionInfo: function(uuid) { GetExtensionInfo: function(uuid) {
let extension = ExtensionUtils.extensions[uuid]; return ExtensionSystem.extensionMeta[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) { GetExtensionErrors: function(uuid) {
let extension = ExtensionUtils.extensions[uuid]; return ExtensionSystem.errors[uuid] || [];
if (!extension)
return [];
if (!extension.errors)
return [];
return extension.errors;
}, },
EnableExtension: function(uuid) { EnableExtension: function(uuid) {
@ -282,13 +186,6 @@ const GnomeShell = new Lang.Class({
return ExtensionSystem.uninstallExtensionFromUUID(uuid); return ExtensionSystem.uninstallExtensionFromUUID(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);
},
get OverviewActive() { get OverviewActive() {
return Main.overview.visible; return Main.overview.visible;
}, },
@ -305,7 +202,12 @@ const GnomeShell = new Lang.Class({
ShellVersion: Config.PACKAGE_VERSION, ShellVersion: Config.PACKAGE_VERSION,
_extensionStateChanged: function(_, newState) { _extensionStateChanged: function(_, newState) {
this._dbusImpl.emit_signal('ExtensionStatusChanged', DBus.session.emit_signal('/org/gnome/Shell',
GLib.Variant.new('(sis)', [newState.uuid, newState.state, newState.error])); 'org.gnome.Shell',
'ExtensionStatusChanged', 'sis',
[newState.uuid, newState.state, newState.error]);
} }
}); };
DBus.conformExport(GnomeShell.prototype, GnomeShellIface);

View File

@ -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');
@ -56,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() {
@ -99,7 +103,8 @@ 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);

View File

@ -48,16 +48,13 @@ function _setLabelsForMessage(dialog, message) {
_setLabelText(dialog.descriptionLabel, labels[1]); _setLabelText(dialog.descriptionLabel, labels[1]);
} }
function _createIcon(gicon) {
return new St.Icon({ gicon: gicon,
style_class: 'shell-mount-operation-icon' })
}
/* -------------------------------------------------------- */ /* -------------------------------------------------------- */
const ListItem = new Lang.Class({ function ListItem(app) {
Name: 'ListItem', this._init(app);
}
ListItem.prototype = {
_init: function(app) { _init: function(app) {
this._app = app; this._app = app;
@ -89,12 +86,14 @@ 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);
const ShellMountOperation = new Lang.Class({ function ShellMountOperation(source, params) {
Name: 'ShellMountOperation', this._init(source, params);
}
ShellMountOperation.prototype = {
_init: function(source, params) { _init: function(source, params) {
params = Params.parse(params, { reaskPassword: false }); params = Params.parse(params, { reaskPassword: false });
@ -114,11 +113,12 @@ const ShellMountOperation = new Lang.Class({
this.mountOp.connect('aborted', this.mountOp.connect('aborted',
Lang.bind(this, this._onAborted)); Lang.bind(this, this._onAborted));
this._gicon = source.get_icon(); this._icon = new St.Icon({ gicon: source.get_icon(),
style_class: 'shell-mount-operation-icon' });
}, },
_onAskQuestion: function(op, message, choices) { _onAskQuestion: function(op, message, choices) {
this._dialog = new ShellMountQuestionDialog(this._gicon); this._dialog = new ShellMountQuestionDialog(this._icon);
this._dialog.connect('response', this._dialog.connect('response',
Lang.bind(this, function(object, choice) { Lang.bind(this, function(object, choice) {
@ -135,7 +135,7 @@ const ShellMountOperation = new Lang.Class({
_onAskPassword: function(op, message) { _onAskPassword: function(op, message) {
this._notificationShowing = true; this._notificationShowing = true;
this._source = new ShellMountPasswordSource(message, this._gicon, this._reaskPassword); this._source = new ShellMountPasswordSource(message, this._icon, this._reaskPassword);
this._source.connect('password-ready', this._source.connect('password-ready',
Lang.bind(this, function(source, password) { Lang.bind(this, function(source, password) {
@ -170,7 +170,7 @@ const ShellMountOperation = new Lang.Class({
let message = op.get_show_processes_message(); let message = op.get_show_processes_message();
if (!this._processesDialog) { if (!this._processesDialog) {
this._processesDialog = new ShellProcessesDialog(this._gicon); this._processesDialog = new ShellProcessesDialog(this._icon);
this._dialog = this._processesDialog; this._dialog = this._processesDialog;
this._processesDialog.connect('response', this._processesDialog.connect('response',
@ -190,20 +190,23 @@ const ShellMountOperation = new Lang.Class({
this._processesDialog.update(message, processes, choices); this._processesDialog.update(message, processes, choices);
}, },
}); }
const ShellMountQuestionDialog = new Lang.Class({ function ShellMountQuestionDialog(icon) {
Name: 'ShellMountQuestionDialog', this._init(icon);
Extends: ModalDialog.ModalDialog, }
_init: function(gicon) { ShellMountQuestionDialog.prototype = {
this.parent({ styleClass: 'mount-question-dialog' }); __proto__: ModalDialog.ModalDialog.prototype,
_init: function(icon) {
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'mount-question-dialog' });
let mainContentLayout = new St.BoxLayout(); let mainContentLayout = new St.BoxLayout();
this.contentLayout.add(mainContentLayout, { x_fill: true, this.contentLayout.add(mainContentLayout, { x_fill: true,
y_fill: false }); y_fill: false });
this._iconBin = new St.Bin({ child: _createIcon(gicon) }); this._iconBin = new St.Bin({ child: icon });
mainContentLayout.add(this._iconBin, mainContentLayout.add(this._iconBin,
{ x_fill: true, { x_fill: true,
y_fill: false, y_fill: false,
@ -215,8 +218,6 @@ const ShellMountQuestionDialog = new Lang.Class({
{ y_align: St.Align.START }); { y_align: St.Align.START });
this.subjectLabel = new St.Label({ style_class: 'mount-question-dialog-subject' }); this.subjectLabel = new St.Label({ style_class: 'mount-question-dialog-subject' });
this.subjectLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this.subjectLabel.clutter_text.line_wrap = true;
messageLayout.add(this.subjectLabel, messageLayout.add(this.subjectLabel,
{ y_fill: false, { y_fill: false,
@ -235,37 +236,41 @@ const ShellMountQuestionDialog = new Lang.Class({
_setLabelsForMessage(this, message); _setLabelsForMessage(this, message);
_setButtonsForChoices(this, choices); _setButtonsForChoices(this, choices);
} }
}); }
Signals.addSignalMethods(ShellMountQuestionDialog.prototype); Signals.addSignalMethods(ShellMountQuestionDialog.prototype);
const ShellMountPasswordSource = new Lang.Class({ function ShellMountPasswordSource(message, icon, reaskPassword) {
Name: 'ShellMountPasswordSource', this._init(message, icon, reaskPassword);
Extends: MessageTray.Source, }
_init: function(message, gicon, reaskPassword) { ShellMountPasswordSource.prototype = {
this._gicon = gicon; __proto__: MessageTray.Source.prototype,
_init: function(message, icon, reaskPassword) {
let strings = message.split('\n'); let strings = message.split('\n');
this.parent(strings[0]); MessageTray.Source.prototype._init.call(this, strings[0]);
this._notification = new ShellMountPasswordNotification(this, strings, reaskPassword);
this._notification = new ShellMountPasswordNotification(this, strings, icon, reaskPassword);
// 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);
}, },
}
createNotificationIcon: function() {
return _createIcon(this._gicon);
},
});
Signals.addSignalMethods(ShellMountPasswordSource.prototype); Signals.addSignalMethods(ShellMountPasswordSource.prototype);
const ShellMountPasswordNotification = new Lang.Class({ function ShellMountPasswordNotification(source, strings, icon, reaskPassword) {
Name: 'ShellMountPasswordNotification', this._init(source, strings, icon, reaskPassword);
Extends: MessageTray.Notification, }
_init: function(source, strings, reaskPassword) { ShellMountPasswordNotification.prototype = {
this.parent(source, strings[0], null, { customContent: true }); __proto__: MessageTray.Notification.prototype,
_init: function(source, strings, icon, reaskPassword) {
MessageTray.Notification.prototype._init.call(this, source,
strings[0], null,
{ customContent: true,
icon: icon });
// set the notification to transient and urgent, so that it // set the notification to transient and urgent, so that it
// expands out // expands out
@ -300,20 +305,23 @@ const ShellMountPasswordNotification = new Lang.Class({
this.source.emit('password-ready', text); this.source.emit('password-ready', text);
} }
}); }
const ShellProcessesDialog = new Lang.Class({ function ShellProcessesDialog(icon) {
Name: 'ShellProcessesDialog', this._init(icon);
Extends: ModalDialog.ModalDialog, }
_init: function(gicon) { ShellProcessesDialog.prototype = {
this.parent({ styleClass: 'show-processes-dialog' }); __proto__: ModalDialog.ModalDialog.prototype,
_init: function(icon) {
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'show-processes-dialog' });
let mainContentLayout = new St.BoxLayout(); let mainContentLayout = new St.BoxLayout();
this.contentLayout.add(mainContentLayout, { x_fill: true, this.contentLayout.add(mainContentLayout, { x_fill: true,
y_fill: false }); y_fill: false });
this._iconBin = new St.Bin({ child: _createIcon(gicon) }); this._iconBin = new St.Bin({ child: icon });
mainContentLayout.add(this._iconBin, mainContentLayout.add(this._iconBin,
{ x_fill: true, { x_fill: true,
y_fill: false, y_fill: false,
@ -368,7 +376,7 @@ const ShellProcessesDialog = new Lang.Class({
_setAppsForPids: function(pids) { _setAppsForPids: function(pids) {
// remove all the items // remove all the items
this._applicationList.destroy_all_children(); this._applicationList.destroy_children();
pids.forEach(Lang.bind(this, function(pid) { pids.forEach(Lang.bind(this, function(pid) {
let tracker = Shell.WindowTracker.get_default(); let tracker = Shell.WindowTracker.get_default();
@ -393,5 +401,5 @@ const ShellProcessesDialog = new Lang.Class({
_setLabelsForMessage(this, message); _setLabelsForMessage(this, message);
_setButtonsForChoices(this, choices); _setButtonsForChoices(this, choices);
} }
}); }
Signals.addSignalMethods(ShellProcessesDialog.prototype); Signals.addSignalMethods(ShellProcessesDialog.prototype);

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const GDesktopEnums = imports.gi.GDesktopEnums; const DBus = imports.dbus;
const GConf = imports.gi.GConf;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk; const Gtk = imports.gi.Gtk;
const Lang = imports.lang; const Lang = imports.lang;
@ -29,8 +30,8 @@ const DPI_FACTOR_LARGE = 1.25;
const DPI_FACTOR_LARGER = 1.5; const DPI_FACTOR_LARGER = 1.5;
const DPI_FACTOR_LARGEST = 2.0; const DPI_FACTOR_LARGEST = 2.0;
const WM_SCHEMA = 'org.gnome.desktop.wm.preferences'; const KEY_META_DIR = '/apps/metacity/general';
const KEY_VISUAL_BELL = 'visual-bell'; const KEY_VISUAL_BELL = KEY_META_DIR + '/visual_bell';
const DESKTOP_INTERFACE_SCHEMA = 'org.gnome.desktop.interface'; const DESKTOP_INTERFACE_SCHEMA = 'org.gnome.desktop.interface';
const KEY_GTK_THEME = 'gtk-theme'; const KEY_GTK_THEME = 'gtk-theme';
@ -39,12 +40,19 @@ const KEY_TEXT_SCALING_FACTOR = 'text-scaling-factor';
const HIGH_CONTRAST_THEME = 'HighContrast'; const HIGH_CONTRAST_THEME = 'HighContrast';
const ATIndicator = new Lang.Class({ function ATIndicator() {
Name: 'ATIndicator', this._init.apply(this, arguments);
Extends: PanelMenu.SystemStatusButton, }
ATIndicator.prototype = {
__proto__: PanelMenu.SystemStatusButton.prototype,
_init: function() { _init: function() {
this.parent('preferences-desktop-accessibility', _("Accessibility")); PanelMenu.SystemStatusButton.prototype._init.call(this, 'preferences-desktop-accessibility', null);
let client = GConf.Client.get_default();
client.add_dir(KEY_META_DIR, GConf.ClientPreloadType.PRELOAD_ONELEVEL, null);
client.notify_add(KEY_META_DIR, Lang.bind(this, this._keyChanged), null, null);
let highContrast = this._buildHCItem(); let highContrast = this._buildHCItem();
this.menu.addMenuItem(highContrast); this.menu.addMenuItem(highContrast);
@ -64,7 +72,7 @@ const ATIndicator = new Lang.Class({
'screen-keyboard-enabled'); 'screen-keyboard-enabled');
this.menu.addMenuItem(screenKeyboard); this.menu.addMenuItem(screenKeyboard);
let visualBell = this._buildItem(_("Visual Alerts"), WM_SCHEMA, KEY_VISUAL_BELL); let visualBell = this._buildItemGConf(_("Visual Alerts"), client, KEY_VISUAL_BELL);
this.menu.addMenuItem(visualBell); this.menu.addMenuItem(visualBell);
let stickyKeys = this._buildItem(_("Sticky Keys"), A11Y_SCHEMA, KEY_STICKY_KEYS_ENABLED); let stickyKeys = this._buildItem(_("Sticky Keys"), A11Y_SCHEMA, KEY_STICKY_KEYS_ENABLED);
@ -94,6 +102,22 @@ const ATIndicator = new Lang.Class({
return widget; return widget;
}, },
_buildItemGConf: function(string, client, key) {
function on_get() {
return client.get_bool(key);
}
let widget = this._buildItemExtended(string,
client.get_bool(key),
client.key_is_writable(key),
function(enabled) {
client.set_bool(key, enabled);
});
this.connect('gconf-changed', function() {
widget.setToggleState(client.get_bool(key));
});
return widget;
},
_buildItem: function(string, schema, key) { _buildItem: function(string, schema, key) {
let settings = new Gio.Settings({ schema: schema }); let settings = new Gio.Settings({ schema: schema });
let widget = this._buildItemExtended(string, let widget = this._buildItemExtended(string,
@ -167,5 +191,10 @@ const ATIndicator = new Lang.Class({
widget.setToggleState(active); widget.setToggleState(active);
}); });
return widget; return widget;
},
_keyChanged: function() {
this.emit('gconf-changed');
} }
}); };
Signals.addSignalMethods(ATIndicator.prototype);

View File

@ -23,13 +23,17 @@ const ConnectionState = {
CONNECTING: 3 CONNECTING: 3
} }
const Indicator = new Lang.Class({ function Indicator() {
Name: 'BTIndicator', this._init.apply(this, arguments);
Extends: PanelMenu.SystemStatusButton, }
Indicator.prototype = {
__proto__: PanelMenu.SystemStatusButton.prototype,
_init: function() { _init: function() {
this.parent('bluetooth-disabled', _("Bluetooth")); PanelMenu.SystemStatusButton.prototype._init.call(this, 'bluetooth-disabled', null);
GLib.spawn_command_line_sync ('pkill -f "^bluetooth-applet$"');
this._applet = new GnomeBluetoothApplet.Applet(); this._applet = new GnomeBluetoothApplet.Applet();
this._killswitch = new PopupMenu.PopupSwitchMenuItem(_("Bluetooth"), false); this._killswitch = new PopupMenu.PopupSwitchMenuItem(_("Bluetooth"), false);
@ -181,7 +185,7 @@ const Indicator = new Lang.Class({
// update connected property // update connected property
if (device.can_connect) if (device.can_connect)
item._connectedMenuItem.setToggleState(device.connected); item._connectedMenuitem.setToggleState(device.connected);
}, },
_createDeviceItem: function(device) { _createDeviceItem: function(device) {
@ -200,10 +204,9 @@ const Indicator = new Lang.Class({
_buildDeviceSubMenu: function(item, device) { _buildDeviceSubMenu: function(item, device) {
if (device.can_connect) { if (device.can_connect) {
let menuitem = new PopupMenu.PopupSwitchMenuItem(_("Connection"), device.connected);
item._connected = device.connected; item._connected = device.connected;
item._connectedMenuItem = menuitem; item._connectedMenuitem = new PopupMenu.PopupSwitchMenuItem(_("Connection"), device.connected);
menuitem.connect('toggled', Lang.bind(this, function() { item._connectedMenuitem.connect('toggled', Lang.bind(this, function() {
if (item._connected > ConnectionState.CONNECTED) { if (item._connected > ConnectionState.CONNECTED) {
// operation already in progress, revert // operation already in progress, revert
// (should not happen anyway) // (should not happen anyway)
@ -238,7 +241,7 @@ const Indicator = new Lang.Class({
} }
})); }));
item.menu.addMenuItem(menuitem); item.menu.addMenuItem(item._connectedMenuitem);
} }
if (device.capabilities & GnomeBluetoothApplet.Capabilities.OBEX_PUSH) { if (device.capabilities & GnomeBluetoothApplet.Capabilities.OBEX_PUSH) {
@ -331,14 +334,17 @@ const Indicator = new Lang.Class({
_cancelRequest: function() { _cancelRequest: function() {
this._source.destroy(); this._source.destroy();
} }
}); }
const Source = new Lang.Class({ function Source() {
Name: 'BluetoothSource', this._init.apply(this, arguments);
Extends: MessageTray.Source, }
Source.prototype = {
__proto__: MessageTray.Source.prototype,
_init: function() { _init: function() {
this.parent(_("Bluetooth")); MessageTray.Source.prototype._init.call(this, _("Bluetooth"));
this._setSummaryIcon(this.createNotificationIcon()); this._setSummaryIcon(this.createNotificationIcon());
}, },
@ -352,7 +358,7 @@ const Source = new Lang.Class({
} }
})); }));
this.parent(notification); MessageTray.Source.prototype.notify.call(this, notification);
}, },
createNotificationIcon: function() { createNotificationIcon: function() {
@ -360,14 +366,18 @@ const Source = new Lang.Class({
icon_type: St.IconType.SYMBOLIC, icon_type: St.IconType.SYMBOLIC,
icon_size: this.ICON_SIZE }); icon_size: this.ICON_SIZE });
} }
}); }
const AuthNotification = new Lang.Class({ function AuthNotification() {
Name: 'AuthNotification', this._init.apply(this, arguments);
Extends: MessageTray.Notification, }
AuthNotification.prototype = {
__proto__: MessageTray.Notification.prototype,
_init: function(source, applet, device_path, name, long_name, uuid) { _init: function(source, applet, device_path, name, long_name, uuid) {
this.parent(source, MessageTray.Notification.prototype._init.call(this,
source,
_("Bluetooth"), _("Bluetooth"),
_("Authorization request from %s").format(name), _("Authorization request from %s").format(name),
{ customContent: true }); { customContent: true });
@ -396,14 +406,18 @@ const AuthNotification = new Lang.Class({
this.destroy(); this.destroy();
})); }));
} }
}); }
const ConfirmNotification = new Lang.Class({ function ConfirmNotification() {
Name: 'ConfirmNotification', this._init.apply(this, arguments);
Extends: MessageTray.Notification, }
ConfirmNotification.prototype = {
__proto__: MessageTray.Notification.prototype,
_init: function(source, applet, device_path, name, long_name, pin) { _init: function(source, applet, device_path, name, long_name, pin) {
this.parent(source, MessageTray.Notification.prototype._init.call(this,
source,
_("Bluetooth"), _("Bluetooth"),
_("Pairing confirmation for %s").format(name), _("Pairing confirmation for %s").format(name),
{ customContent: true }); { customContent: true });
@ -425,14 +439,18 @@ const ConfirmNotification = new Lang.Class({
this.destroy(); this.destroy();
})); }));
} }
}); }
const PinNotification = new Lang.Class({ function PinNotification() {
Name: 'PinNotification', this._init.apply(this, arguments);
Extends: MessageTray.Notification, }
PinNotification.prototype = {
__proto__: MessageTray.Notification.prototype,
_init: function(source, applet, device_path, name, long_name, numeric) { _init: function(source, applet, device_path, name, long_name, numeric) {
this.parent(source, MessageTray.Notification.prototype._init.call(this,
source,
_("Bluetooth"), _("Bluetooth"),
_("Pairing request for %s").format(name), _("Pairing request for %s").format(name),
{ customContent: true }); { customContent: true });
@ -484,7 +502,7 @@ const PinNotification = new Lang.Class({
}, },
grabFocus: function(lockTray) { grabFocus: function(lockTray) {
this.parent(lockTray); MessageTray.Notification.prototype.grabFocus.call(this, lockTray);
global.stage.set_key_focus(this._entry); global.stage.set_key_focus(this._entry);
} }
}); }

View File

@ -14,12 +14,15 @@ const PopupMenu = imports.ui.popupMenu;
const PanelMenu = imports.ui.panelMenu; const PanelMenu = imports.ui.panelMenu;
const Util = imports.misc.util; const Util = imports.misc.util;
const LayoutMenuItem = new Lang.Class({ function LayoutMenuItem() {
Name: 'LayoutMenuItem', this._init.apply(this, arguments);
Extends: PopupMenu.PopupBaseMenuItem, }
LayoutMenuItem.prototype = {
__proto__: PopupMenu.PopupBaseMenuItem.prototype,
_init: function(config, id, indicator, long_name) { _init: function(config, id, indicator, long_name) {
this.parent(); PopupMenu.PopupBaseMenuItem.prototype._init.call(this);
this._config = config; this._config = config;
this._id = id; this._id = id;
@ -30,18 +33,20 @@ const LayoutMenuItem = new Lang.Class({
}, },
activate: function(event) { activate: function(event) {
this.parent(event); PopupMenu.PopupBaseMenuItem.prototype.activate.call(this);
this._config.lock_group(this._id); this._config.lock_group(this._id);
} }
}); };
const XKBIndicator = new Lang.Class({ function XKBIndicator() {
Name: 'XKBIndicator', this._init.call(this);
Extends: PanelMenu.Button, }
XKBIndicator.prototype = {
__proto__: PanelMenu.Button.prototype,
_init: function() { _init: function() {
this.parent(0.0, _("Keyboard")); PanelMenu.Button.prototype._init.call(this, St.Align.START);
this._container = new Shell.GenericContainer(); this._container = new Shell.GenericContainer();
this._container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth)); this._container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth));
@ -216,4 +221,4 @@ const XKBIndicator = new Lang.Class({
for (let i = 0; i < this._labelActors.length; i++) for (let i = 0; i < this._labelActors.length; i++)
this._labelActors[i].allocate_align_fill(box, 0.5, 0, false, false, flags); this._labelActors[i].allocate_align_fill(box, 0.5, 0, false, false, flags);
} }
}); };

View File

@ -1,5 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const ByteArray = imports.byteArray; const ByteArray = imports.byteArray;
const DBus = imports.dbus;
const GLib = imports.gi.GLib; const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject; const GObject = imports.gi.GObject;
const Lang = imports.lang; const Lang = imports.lang;
@ -97,12 +98,15 @@ function ssidToLabel(ssid) {
return label; return label;
} }
const NMNetworkMenuItem = new Lang.Class({ function NMNetworkMenuItem() {
Name: 'NMNetworkMenuItem', this._init.apply(this, arguments);
Extends: PopupMenu.PopupBaseMenuItem, }
NMNetworkMenuItem.prototype = {
__proto__: PopupMenu.PopupBaseMenuItem.prototype,
_init: function(accessPoints, title, params) { _init: function(accessPoints, title, params) {
this.parent(params); PopupMenu.PopupBaseMenuItem.prototype._init.call(this, params);
accessPoints = sortAccessPoints(accessPoints); accessPoints = sortAccessPoints(accessPoints);
this.bestAP = accessPoints[0]; this.bestAP = accessPoints[0];
@ -113,7 +117,6 @@ const NMNetworkMenuItem = new Lang.Class({
} }
this._label = new St.Label({ text: title }); this._label = new St.Label({ text: title });
this.actor.label_actor = this._label;
this.addActor(this._label); this.addActor(this._label);
this._icons = new St.BoxLayout({ style_class: 'nm-menu-item-icons' }); this._icons = new St.BoxLayout({ style_class: 'nm-menu-item-icons' });
this.addActor(this._icons, { align: St.Align.END }); this.addActor(this._icons, { align: St.Align.END });
@ -182,18 +185,21 @@ const NMNetworkMenuItem = new Lang.Class({
apObj.updateId = 0; apObj.updateId = 0;
} }
this.parent(); PopupMenu.PopupBaseMenuItem.prototype.destroy.call(this);
} }
}); };
const NMWiredSectionTitleMenuItem = new Lang.Class({ function NMWiredSectionTitleMenuItem() {
Name: 'NMWiredSectionTitleMenuItem', this._init.apply(this, arguments);
Extends: PopupMenu.PopupSwitchMenuItem, }
NMWiredSectionTitleMenuItem.prototype = {
__proto__: PopupMenu.PopupSwitchMenuItem.prototype,
_init: function(label, params) { _init: function(label, params) {
params = params || { }; params = params || { };
params.style_class = 'popup-subtitle-menu-item'; params.style_class = 'popup-subtitle-menu-item';
this.parent(label, false, params); PopupMenu.PopupSwitchMenuItem.prototype._init.call(this, label, false, params);
}, },
updateForDevice: function(device) { updateForDevice: function(device) {
@ -206,7 +212,7 @@ const NMWiredSectionTitleMenuItem = new Lang.Class({
}, },
activate: function(event) { activate: function(event) {
this.parent(event); PopupMenu.PopupSwitchMenuItem.prototype.activate.call(this, event);
if (!this._device) { if (!this._device) {
log('Section title activated when there is more than one device, should be non reactive'); log('Section title activated when there is more than one device, should be non reactive');
@ -225,16 +231,19 @@ const NMWiredSectionTitleMenuItem = new Lang.Class({
else else
this._device.deactivate(); this._device.deactivate();
} }
}); };
const NMWirelessSectionTitleMenuItem = new Lang.Class({ function NMWirelessSectionTitleMenuItem() {
Name: 'NMWirelessSectionTitleMenuItem', this._init.apply(this, arguments);
Extends: PopupMenu.PopupSwitchMenuItem, }
NMWirelessSectionTitleMenuItem.prototype = {
__proto__: PopupMenu.PopupSwitchMenuItem.prototype,
_init: function(client, property, title, params) { _init: function(client, property, title, params) {
params = params || { }; params = params || { };
params.style_class = 'popup-subtitle-menu-item'; params.style_class = 'popup-subtitle-menu-item';
this.parent(title, false, params); PopupMenu.PopupSwitchMenuItem.prototype._init.call(this, title, false, params);
this._client = client; this._client = client;
this._property = property + '_enabled'; this._property = property + '_enabled';
@ -250,11 +259,9 @@ const NMWirelessSectionTitleMenuItem = new Lang.Class({
updateForDevice: function(device) { updateForDevice: function(device) {
// we show the switch // we show the switch
// - if there not just one device // - if there not just one device
// - if the switch is off (but it can be turned on) // - if the switch is off
// - if the device is activated or disconnected // - if the device is activated or disconnected
if (!this._hardwareEnabled) { if (device && this._softwareEnabled && this._hardwareEnabled) {
this.setStatus(_("hardware disabled"));
} else if (device && this._softwareEnabled) {
let text = device.getStatusLabel(); let text = device.getStatusLabel();
this.setStatus(text); this.setStatus(text);
} else } else
@ -262,7 +269,7 @@ const NMWirelessSectionTitleMenuItem = new Lang.Class({
}, },
activate: function(event) { activate: function(event) {
this.parent(event); PopupMenu.PopupSwitchMenuItem.prototype.activate.call(this, event);
this._client[this._setEnabledFunc](this._switch.state); this._client[this._setEnabledFunc](this._switch.state);
}, },
@ -279,12 +286,13 @@ const NMWirelessSectionTitleMenuItem = new Lang.Class({
this.emit('enabled-changed', enabled); this.emit('enabled-changed', enabled);
} }
}); };
const NMDevice = new Lang.Class({ function NMDevice() {
Name: 'NMDevice', throw new TypeError('Instantanting abstract class NMDevice');
Abstract: true, }
NMDevice.prototype = {
_init: function(client, device, connections) { _init: function(client, device, connections) {
this.device = device; this.device = device;
if (device) { if (device) {
@ -330,7 +338,7 @@ const NMDevice = new Lang.Class({
} }
this.section = new PopupMenu.PopupMenuSection(); this.section = new PopupMenu.PopupMenuSection();
this._deferredWorkId = Main.initializeDeferredWork(this.section.actor, Lang.bind(this, this._createSection)); this._createSection();
}, },
destroy: function() { destroy: function() {
@ -397,29 +405,16 @@ const NMDevice = new Lang.Class({
this._activeConnection = activeConnection; this._activeConnection = activeConnection;
this._clearSection(); this._clearSection();
this._queueCreateSection(); this._createSection();
}, },
checkConnection: function(connection) { checkConnection: function(connection) {
let pos = this._findConnection(connection._uuid); let exists = this._findConnection(connection._uuid) != -1;
let exists = pos != -1;
let valid = this.connectionValid(connection); let valid = this.connectionValid(connection);
if (exists && !valid) if (exists && !valid)
this.removeConnection(connection); this.removeConnection(connection);
else if (!exists && valid) else if (!exists && valid)
this.addConnection(connection); this.addConnection(connection);
else if (exists && valid) {
// propagate changes and update the UI
if (this._connections[pos].timestamp != connection._timestamp) {
this._connections[pos].timestamp = connection._timestamp;
this._connections.sort(this._connectionSortFunction);
this._clearSection();
this._queueCreateSection();
}
}
}, },
addConnection: function(connection) { addConnection: function(connection) {
@ -434,7 +429,7 @@ const NMDevice = new Lang.Class({
this._connections.sort(this._connectionSortFunction); this._connections.sort(this._connectionSortFunction);
this._clearSection(); this._clearSection();
this._queueCreateSection(); this._createSection();
}, },
removeConnection: function(connection) { removeConnection: function(connection) {
@ -458,7 +453,7 @@ const NMDevice = new Lang.Class({
// (or in the case of NMDeviceWired, we want to hide // (or in the case of NMDeviceWired, we want to hide
// the only explicit connection) // the only explicit connection)
this._clearSection(); this._clearSection();
this._queueCreateSection(); this._createSection();
} }
}, },
@ -542,11 +537,6 @@ const NMDevice = new Lang.Class({
return -1; return -1;
}, },
_queueCreateSection: function() {
this._clearSection();
Main.queueDeferredWork(this._deferredWorkId);
},
_clearSection: function() { _clearSection: function() {
// Clear everything // Clear everything
this.section.removeAll(); this.section.removeAll();
@ -641,7 +631,7 @@ const NMDevice = new Lang.Class({
this._updateStatusItem(); this._updateStatusItem();
this._clearSection(); this._clearSection();
this._queueCreateSection(); this._createSection();
this.emit('state-changed'); this.emit('state-changed');
}, },
@ -684,23 +674,26 @@ const NMDevice = new Lang.Class({
return out; return out;
} }
}); };
Signals.addSignalMethods(NMDevice.prototype); Signals.addSignalMethods(NMDevice.prototype);
const NMDeviceWired = new Lang.Class({ function NMDeviceWired() {
Name: 'NMDeviceWired', this._init.apply(this, arguments);
Extends: NMDevice, }
NMDeviceWired.prototype = {
__proto__: NMDevice.prototype,
_init: function(client, device, connections) { _init: function(client, device, connections) {
this._autoConnectionName = _("Auto Ethernet"); this._autoConnectionName = _("Auto Ethernet");
this.category = NMConnectionCategory.WIRED; this.category = NMConnectionCategory.WIRED;
this.parent(client, device, connections); NMDevice.prototype._init.call(this, client, device, connections);
}, },
_createSection: function() { _createSection: function() {
this.parent(); NMDevice.prototype._createSection.call(this);
// if we have only one connection (normal or automatic) // if we have only one connection (normal or automatic)
// we hide the connection list, and use the switch to control // we hide the connection list, and use the switch to control
@ -725,11 +718,14 @@ const NMDeviceWired = new Lang.Class({
})); }));
return connection; return connection;
} }
}); };
const NMDeviceModem = new Lang.Class({ function NMDeviceModem() {
Name: 'NMDeviceModem', this._init.apply(this, arguments);
Extends: NMDevice, }
NMDeviceModem.prototype = {
__proto__: NMDevice.prototype,
_init: function(client, device, connections) { _init: function(client, device, connections) {
let is_wwan = false; let is_wwan = false;
@ -778,7 +774,7 @@ const NMDeviceModem = new Lang.Class({
})); }));
} }
this.parent(client, device, connections); NMDevice.prototype._init.call(this, client, device, connections);
}, },
setEnabled: function(enabled) { setEnabled: function(enabled) {
@ -791,7 +787,7 @@ const NMDeviceModem = new Lang.Class({
this.statusItem.setStatus(this.getStatusLabel()); this.statusItem.setStatus(this.getStatusLabel());
} }
this.parent(enabled); NMDevice.prototype.setEnabled.call(this, enabled);
}, },
get connected() { get connected() {
@ -808,7 +804,7 @@ const NMDeviceModem = new Lang.Class({
this._signalQualityId = 0; this._signalQualityId = 0;
} }
this.parent(); NMDevice.prototype.destroy.call(this);
}, },
_getSignalIcon: function() { _getSignalIcon: function() {
@ -829,13 +825,13 @@ const NMDeviceModem = new Lang.Class({
this.section.addMenuItem(this._operatorItem); this.section.addMenuItem(this._operatorItem);
} }
this.parent(); NMDevice.prototype._createSection.call(this);
}, },
_clearSection: function() { _clearSection: function() {
this._operatorItem = null; this._operatorItem = null;
this.parent(); NMDevice.prototype._clearSection.call(this);
}, },
_createAutomaticConnection: function() { _createAutomaticConnection: function() {
@ -845,11 +841,14 @@ const NMDeviceModem = new Lang.Class({
'connect-3g', this.device.get_path()]); 'connect-3g', this.device.get_path()]);
return null; return null;
} }
}); };
const NMDeviceBluetooth = new Lang.Class({ function NMDeviceBluetooth() {
Name: 'NMDeviceBluetooth', this._init.apply(this, arguments);
Extends: NMDevice, }
NMDeviceBluetooth.prototype = {
__proto__: NMDevice.prototype,
_init: function(client, device, connections) { _init: function(client, device, connections) {
this._autoConnectionName = this._makeConnectionName(device); this._autoConnectionName = this._makeConnectionName(device);
@ -857,7 +856,7 @@ const NMDeviceBluetooth = new Lang.Class({
this.category = NMConnectionCategory.WWAN; this.category = NMConnectionCategory.WWAN;
this.parent(client, device, connections); NMDevice.prototype._init.call(this, client, device, connections);
}, },
_createAutomaticConnection: function() { _createAutomaticConnection: function() {
@ -885,27 +884,25 @@ const NMDeviceBluetooth = new Lang.Class({
this._autoConnectionName = this._makeConnectionName(this.device); this._autoConnectionName = this._makeConnectionName(this.device);
this._clearSection(); this._clearSection();
this._queueCreateSection(); this._createSection();
this._updateStatusItem();
},
_getDescription: function() {
return this.device.name || _("Bluetooth");
} }
}); };
// Not a real device, but I save a lot code this way // Not a real device, but I save a lot code this way
const NMDeviceVPN = new Lang.Class({ function NMDeviceVPN() {
Name: 'NMDeviceVPN', this._init.apply(this, arguments);
Extends: NMDevice, }
NMDeviceVPN.prototype = {
__proto__: NMDevice.prototype,
_init: function(client) { _init: function(client) {
// Disable autoconnections // Disable autoconnections
this._autoConnectionName = null; this._autoConnectionName = null;
this.category = NMConnectionCategory.VPN; this.category = NMConnectionCategory.VPN;
this.parent(client, null, [ ]); NMDevice.prototype._init.call(this, client, null, [ ]);
}, },
connectionValid: function(connection) { connectionValid: function(connection) {
@ -921,7 +918,7 @@ const NMDeviceVPN = new Lang.Class({
}, },
setActiveConnection: function(activeConnection) { setActiveConnection: function(activeConnection) {
this.parent(activeConnection); NMDevice.prototype.setActiveConnection.call(this, activeConnection);
this.emit('active-connection-changed'); this.emit('active-connection-changed');
}, },
@ -938,11 +935,14 @@ const NMDeviceVPN = new Lang.Class({
getStatusLabel: function() { getStatusLabel: function() {
return null; return null;
} }
}); };
const NMDeviceWireless = new Lang.Class({ function NMDeviceWireless() {
Name: 'NMDeviceWireless', this._init.apply(this, arguments);
Extends: NMDevice, }
NMDeviceWireless.prototype = {
__proto__: NMDevice.prototype,
_init: function(client, device, connections) { _init: function(client, device, connections) {
this.category = NMConnectionCategory.WIRELESS; this.category = NMConnectionCategory.WIRELESS;
@ -1014,7 +1014,7 @@ const NMDeviceWireless = new Lang.Class({
this._apAddedId = device.connect('access-point-added', Lang.bind(this, this._accessPointAdded)); this._apAddedId = device.connect('access-point-added', Lang.bind(this, this._accessPointAdded));
this._apRemovedId = device.connect('access-point-removed', Lang.bind(this, this._accessPointRemoved)); this._apRemovedId = device.connect('access-point-removed', Lang.bind(this, this._accessPointRemoved));
this.parent(client, device, validConnections); NMDevice.prototype._init.call(this, client, device, validConnections);
}, },
destroy: function() { destroy: function() {
@ -1034,7 +1034,7 @@ const NMDeviceWireless = new Lang.Class({
this._apRemovedId = 0; this._apRemovedId = 0;
} }
this.parent(); NMDevice.prototype.destroy.call(this);
}, },
setEnabled: function(enabled) { setEnabled: function(enabled) {
@ -1235,6 +1235,7 @@ const NMDeviceWireless = new Lang.Class({
accessPoints: [ accessPoint ] accessPoints: [ accessPoint ]
}; };
apObj.ssidText = ssidToLabel(apObj.ssid); apObj.ssidText = ssidToLabel(apObj.ssid);
needsupdate = true;
} }
// check if this enables new connections for this group // check if this enables new connections for this group
@ -1249,13 +1250,37 @@ const NMDeviceWireless = new Lang.Class({
} }
} }
if (pos == -1 || needsupdate) { if (needsupdate) {
if (apObj.item)
apObj.item.destroy();
if (pos != -1) if (pos != -1)
this._networks.splice(pos, 1); this._networks.splice(pos, 1);
pos = Util.insertSorted(this._networks, apObj, this._networkSortFunction);
if (this._networks.length == 0) {
// only network in the list
this._networks.push(apObj);
this._clearSection(); this._clearSection();
this._queueCreateSection(); this._createSection();
return;
}
// skip networks that should appear earlier
let menuPos = 0;
for (pos = 0;
pos < this._networks.length &&
this._networkSortFunction(this._networks[pos], apObj) < 0; ++pos) {
if (this._networks[pos] != this._activeNetwork)
menuPos++;
}
// (re-)add the network
this._networks.splice(pos, 0, apObj);
if (this._shouldShowConnectionList()) {
menuPos += (this._activeConnectionItem ? 1 : 0);
this._createNetworkItem(apObj, menuPos);
}
} }
}, },
@ -1323,7 +1348,7 @@ const NMDeviceWireless = new Lang.Class({
}, },
_clearSection: function() { _clearSection: function() {
this.parent(); NMDevice.prototype._clearSection.call(this);
for (let i = 0; i < this._networks.length; i++) for (let i = 0; i < this._networks.length; i++)
this._networks[i].item = null; this._networks[i].item = null;
@ -1342,7 +1367,7 @@ const NMDeviceWireless = new Lang.Class({
let obj = this._connections[pos]; let obj = this._connections[pos];
this._connections.splice(pos, 1); this._connections.splice(pos, 1);
let forceupdate = false; let anyauto = false, forceupdate = false;
for (let i = 0; i < this._networks.length; i++) { for (let i = 0; i < this._networks.length; i++) {
let apObj = this._networks[i]; let apObj = this._networks[i];
let connections = apObj.connections; let connections = apObj.connections;
@ -1350,14 +1375,16 @@ const NMDeviceWireless = new Lang.Class({
if (connections[k]._uuid == connection._uuid) { if (connections[k]._uuid == connection._uuid) {
// remove the connection from the access point group // remove the connection from the access point group
connections.splice(k); connections.splice(k);
forceupdate = forceupdate || connections.length == 0; anyauto = connections.length == 0;
if (forceupdate) if (anyauto) {
// this potentially changes the sorting order
forceupdate = true;
break; break;
}
if (apObj.item) { if (apObj.item) {
if (apObj.item instanceof PopupMenu.PopupSubMenuMenuItem) { if (apObj.item instanceof PopupMenu.PopupSubMenuMenuItem) {
let items = apObj.item.menu._getMenuItems(); let items = apObj.item.menu.getMenuItems();
if (items.length == 2) { if (items.length == 2) {
// we need to update the connection list to convert this to a normal item // we need to update the connection list to convert this to a normal item
forceupdate = true; forceupdate = true;
@ -1379,10 +1406,10 @@ const NMDeviceWireless = new Lang.Class({
} }
} }
if (forceupdate) { if (forceupdate || anyauto) {
this._networks.sort(this._networkSortFunction); this._networks.sort(this._networkSortFunction);
this._clearSection(); this._clearSection();
this._queueCreateSection(); this._createSection();
} }
}, },
@ -1415,13 +1442,13 @@ const NMDeviceWireless = new Lang.Class({
if (forceupdate) { if (forceupdate) {
this._networks.sort(this._networkSortFunction); this._networks.sort(this._networkSortFunction);
this._clearSection(); this._clearSection();
this._queueCreateSection(); this._createSection();
} }
}, },
_createActiveConnectionItem: function() { _createActiveConnectionItem: function() {
let icon, title; let icon, title;
if (this._activeConnection && this._activeConnection._connection) { if (this._activeConnection._connection) {
let connection = this._activeConnection._connection; let connection = this._activeConnection._connection;
if (this._activeNetwork) if (this._activeNetwork)
this._activeConnectionItem = new NMNetworkMenuItem(this._activeNetwork.accessPoints, undefined, this._activeConnectionItem = new NMNetworkMenuItem(this._activeNetwork.accessPoints, undefined,
@ -1514,7 +1541,7 @@ const NMDeviceWireless = new Lang.Class({
if (!this._shouldShowConnectionList()) if (!this._shouldShowConnectionList())
return; return;
if (this._activeNetwork) { if(this._activeConnection) {
this._createActiveConnectionItem(); this._createActiveConnectionItem();
this.section.addMenuItem(this._activeConnectionItem); this.section.addMenuItem(this._activeConnectionItem);
} }
@ -1523,22 +1550,22 @@ const NMDeviceWireless = new Lang.Class({
for(let j = 0; j < this._networks.length; j++) { for(let j = 0; j < this._networks.length; j++) {
let apObj = this._networks[j]; let apObj = this._networks[j];
if (apObj == this._activeNetwork) { if (apObj == this._activeNetwork)
activeOffset--;
continue; continue;
}
this._createNetworkItem(apObj, j + activeOffset); this._createNetworkItem(apObj, j + activeOffset);
} }
}, },
}); };
const NMApplet = new Lang.Class({ function NMApplet() {
Name: 'NMApplet', this._init.apply(this, arguments);
Extends: PanelMenu.SystemStatusButton, }
NMApplet.prototype = {
__proto__: PanelMenu.SystemStatusButton.prototype,
_init: function() { _init: function() {
this.parent('network-error', _("Network")); PanelMenu.SystemStatusButton.prototype._init.call(this, 'network-error');
this._client = NMClient.Client.new(); this._client = NMClient.Client.new();
@ -1804,7 +1831,6 @@ const NMApplet = new Lang.Class({
let activating = null; let activating = null;
let default_ip4 = null; let default_ip4 = null;
let default_ip6 = null; let default_ip6 = null;
let active_vpn = null;
for (let i = 0; i < this._activeConnections.length; i++) { for (let i = 0; i < this._activeConnections.length; i++) {
let a = this._activeConnections[i]; let a = this._activeConnections[i];
@ -1834,8 +1860,6 @@ const NMApplet = new Lang.Class({
default_ip4 = a; default_ip4 = a;
if (a.default6) if (a.default6)
default_ip6 = a; default_ip6 = a;
if (a._type == 'vpn')
active_vpn = a;
if (a.state == NetworkManager.ActiveConnectionState.ACTIVATING) if (a.state == NetworkManager.ActiveConnectionState.ACTIVATING)
activating = a; activating = a;
@ -1844,7 +1868,7 @@ const NMApplet = new Lang.Class({
if (a._type != NetworkManager.SETTING_VPN_SETTING_NAME) { if (a._type != NetworkManager.SETTING_VPN_SETTING_NAME) {
// find a good device to be considered primary // find a good device to be considered primary
a._primaryDevice = null; a._primaryDevice = null;
let devices = a.get_devices() || []; let devices = a.get_devices();
for (let j = 0; j < devices.length; j++) { for (let j = 0; j < devices.length; j++) {
let d = devices[j]; let d = devices[j];
if (d._delegate) { if (d._delegate) {
@ -1866,7 +1890,7 @@ const NMApplet = new Lang.Class({
} }
} }
this._mainConnection = activating || active_vpn || default_ip4 || default_ip6 || this._activeConnections[0] || null; this._mainConnection = activating || default_ip4 || default_ip6 || this._activeConnections[0] || null;
}, },
_notifyActivated: function(activeConnection) { _notifyActivated: function(activeConnection) {
@ -2041,11 +2065,10 @@ const NMApplet = new Lang.Class({
} }
this.setIcon('network-wireless-connected'); this.setIcon('network-wireless-connected');
} else { } else {
if (this._activeAccessPoint != ap) { if (this._accessPointUpdateId && this._activeAccessPoint != ap) {
if (this._accessPointUpdateId)
this._activeAccessPoint.disconnect(this._accessPointUpdateId); this._activeAccessPoint.disconnect(this._accessPointUpdateId);
this._activeAccessPoint = ap; this._activeAccessPoint = ap;
this._activeAccessPointUpdateId = ap.connect('notify::strength', Lang.bind(this, function() { this._activeAccessPointUpdateId = ap.connect('notify::strength', Lang.bind(function() {
this.setIcon('network-wireless-signal-' + signalToIcon(ap.strength)); this.setIcon('network-wireless-signal-' + signalToIcon(ap.strength));
})); }));
} }
@ -2072,8 +2095,7 @@ const NMApplet = new Lang.Class({
break; break;
} }
if (dev.mobileDevice != this._mobileUpdateDevice) { if (this._mobileUpdateId && this._mobileUpdateDevice != dev) {
if (this._mobileUpdateId)
this._mobileUpdateDevice.disconnect(this._mobileUpdateId); this._mobileUpdateDevice.disconnect(this._mobileUpdateId);
this._mobileUpdateDevice = dev.mobileDevice; this._mobileUpdateDevice = dev.mobileDevice;
this._mobileUpdateId = dev.mobileDevice.connect('notify::signal-quality', Lang.bind(this, function() { this._mobileUpdateId = dev.mobileDevice.connect('notify::signal-quality', Lang.bind(this, function() {
@ -2107,14 +2129,17 @@ const NMApplet = new Lang.Class({
this._mobileUpdateId = 0; this._mobileUpdateId = 0;
} }
} }
}); };
const NMMessageTraySource = new Lang.Class({ function NMMessageTraySource() {
Name: 'NMMessageTraySource', this._init();
Extends: MessageTray.Source, }
NMMessageTraySource.prototype = {
__proto__: MessageTray.Source.prototype,
_init: function() { _init: function() {
this.parent(_("Network Manager")); MessageTray.Source.prototype._init.call(this, _("Network Manager"));
let icon = new St.Icon({ icon_name: 'network-transmit-receive', let icon = new St.Icon({ icon_name: 'network-transmit-receive',
icon_type: St.IconType.SYMBOLIC, icon_type: St.IconType.SYMBOLIC,
@ -2122,4 +2147,4 @@ const NMMessageTraySource = new Lang.Class({
}); });
this._setSummaryIcon(icon); this._setSummaryIcon(icon);
} }
}); };

View File

@ -1,6 +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 DBus = imports.dbus;
const Lang = imports.lang; const Lang = imports.lang;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell; const Shell = imports.gi.Shell;
@ -39,26 +40,31 @@ const UPDeviceState = {
PENDING_DISCHARGE: 6 PENDING_DISCHARGE: 6
}; };
const PowerManagerInterface = <interface name="org.gnome.SettingsDaemon.Power"> const PowerManagerInterface = {
<method name="GetDevices"> name: 'org.gnome.SettingsDaemon.Power',
<arg type="a(susdut)" direction="out" /> methods: [
</method> { name: 'GetDevices', inSignature: '', outSignature: 'a(susdut)' },
<method name="GetPrimaryDevice"> { name: 'GetPrimaryDevice', inSignature: '', outSignature: '(susdut)' },
<arg type="(susdut)" direction="out" /> ],
</method> signals: [
<property name="Icon" type="s" access="read" /> { name: 'Changed', inSignature: '' },
</interface>; ],
properties: [
{ name: 'Icon', signature: 's', access: 'read' },
]
};
let PowerManagerProxy = DBus.makeProxyClass(PowerManagerInterface);
const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(PowerManagerInterface); function Indicator() {
this._init.apply(this, arguments);
}
const Indicator = new Lang.Class({ Indicator.prototype = {
Name: 'PowerIndicator', __proto__: PanelMenu.SystemStatusButton.prototype,
Extends: PanelMenu.SystemStatusButton,
_init: function() { _init: function() {
this.parent('battery-missing', _("Battery")); PanelMenu.SystemStatusButton.prototype._init.call(this, 'battery-missing');
this._proxy = new PowerManagerProxy(DBus.session, BUS_NAME, OBJECT_PATH);
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
this._deviceItems = [ ]; this._deviceItems = [ ];
this._hasPrimary = false; this._hasPrimary = false;
@ -75,20 +81,19 @@ const Indicator = new Lang.Class({
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addSettingsAction(_("Power Settings"), 'gnome-power-panel.desktop'); this.menu.addSettingsAction(_("Power Settings"), 'gnome-power-panel.desktop');
this._proxy.connect('g-properties-changed', this._proxy.connect('Changed', Lang.bind(this, this._devicesChanged));
Lang.bind(this, this._devicesChanged));
this._devicesChanged(); this._devicesChanged();
}, },
_readPrimaryDevice: function() { _readPrimaryDevice: function() {
this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(result, error) { this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(device, error) {
if (error) { if (error) {
this._hasPrimary = false; this._hasPrimary = false;
this._primaryDeviceId = null; this._primaryDeviceId = null;
this._batteryItem.actor.hide(); this._batteryItem.actor.hide();
return; return;
} }
let [[device_id, device_type, icon, percentage, state, seconds]] = result; let [device_id, device_type, icon, percentage, state, seconds] = device;
if (device_type == UPDeviceType.BATTERY) { if (device_type == UPDeviceType.BATTERY) {
this._hasPrimary = true; this._hasPrimary = true;
let time = Math.round(seconds / 60); let time = Math.round(seconds / 60);
@ -125,7 +130,7 @@ const Indicator = new Lang.Class({
}, },
_readOtherDevices: function() { _readOtherDevices: function() {
this._proxy.GetDevicesRemote(Lang.bind(this, function(result, error) { this._proxy.GetDevicesRemote(Lang.bind(this, function(devices, error) {
this._deviceItems.forEach(function(i) { i.destroy(); }); this._deviceItems.forEach(function(i) { i.destroy(); });
this._deviceItems = []; this._deviceItems = [];
@ -134,7 +139,6 @@ const Indicator = new Lang.Class({
} }
let position = 0; let position = 0;
let [devices] = result;
for (let i = 0; i < devices.length; i++) { for (let i = 0; i < devices.length; i++) {
let [device_id, device_type] = devices[i]; let [device_id, device_type] = devices[i];
if (device_type == UPDeviceType.AC_POWER || device_id == this._primaryDeviceId) if (device_type == UPDeviceType.AC_POWER || device_id == this._primaryDeviceId)
@ -149,7 +153,7 @@ const Indicator = new Lang.Class({
}, },
_devicesChanged: function() { _devicesChanged: function() {
let icon = this._proxy.Icon; this._proxy.GetRemote('Icon', Lang.bind(this, function(icon, error) {
if (icon) { if (icon) {
let gicon = Gio.icon_new_for_string(icon); let gicon = Gio.icon_new_for_string(icon);
this.setGIcon(gicon); this.setGIcon(gicon);
@ -158,17 +162,21 @@ const Indicator = new Lang.Class({
this.menu.close(); this.menu.close();
this.actor.hide(); this.actor.hide();
} }
}));
this._readPrimaryDevice(); this._readPrimaryDevice();
this._readOtherDevices(); this._readOtherDevices();
} }
}); };
const DeviceItem = new Lang.Class({ function DeviceItem() {
Name: 'DeviceItem', this._init.apply(this, arguments);
Extends: PopupMenu.PopupBaseMenuItem, }
DeviceItem.prototype = {
__proto__: PopupMenu.PopupBaseMenuItem.prototype,
_init: function(device) { _init: function(device) {
this.parent({ reactive: false }); PopupMenu.PopupBaseMenuItem.prototype._init.call(this, { reactive: false });
let [device_id, device_type, icon, percentage, state, time] = device; let [device_id, device_type, icon, percentage, state, time] = device;
@ -215,4 +223,4 @@ const DeviceItem = new Lang.Class({
return _("Unknown"); return _("Unknown");
} }
} }
}); }

View File

@ -1,6 +1,7 @@
// -*- 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 DBus = imports.dbus;
const Lang = imports.lang; const Lang = imports.lang;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell; const Shell = imports.gi.Shell;
@ -17,12 +18,15 @@ const VOLUME_ADJUSTMENT_STEP = 0.05; /* Volume adjustment step in % */
const VOLUME_NOTIFY_ID = 1; const VOLUME_NOTIFY_ID = 1;
const Indicator = new Lang.Class({ function Indicator() {
Name: 'VolumeIndicator', this._init.apply(this, arguments);
Extends: PanelMenu.SystemStatusButton, }
Indicator.prototype = {
__proto__: PanelMenu.SystemStatusButton.prototype,
_init: function() { _init: function() {
this.parent('audio-volume-muted', _("Volume")); PanelMenu.SystemStatusButton.prototype._init.call(this, 'audio-volume-muted', null);
this._control = new Gvc.MixerControl({ name: 'GNOME Shell Volume Control' }); this._control = new Gvc.MixerControl({ name: 'GNOME Shell Volume Control' });
this._control.connect('state-changed', Lang.bind(this, this._onControlStateChanged)); this._control.connect('state-changed', Lang.bind(this, this._onControlStateChanged));
@ -35,7 +39,6 @@ const Indicator = new Lang.Class({
this._output = null; this._output = null;
this._outputVolumeId = 0; this._outputVolumeId = 0;
this._outputMutedId = 0; this._outputMutedId = 0;
/* Translators: This is the label for audio volume */
this._outputTitle = new PopupMenu.PopupMenuItem(_("Volume"), { reactive: false }); this._outputTitle = new PopupMenu.PopupMenuItem(_("Volume"), { reactive: false });
this._outputSlider = new PopupMenu.PopupSliderMenuItem(0); this._outputSlider = new PopupMenu.PopupSliderMenuItem(0);
this._outputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_output')); this._outputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_output'));
@ -212,4 +215,4 @@ const Indicator = new Lang.Class({
if (property == '_output' && !this._output.is_muted) if (property == '_output' && !this._output.is_muted)
this.setIcon(this._volumeToIcon(this._output.volume)); this.setIcon(this._volumeToIcon(this._output.volume));
} }
}); };

Some files were not shown because too many files have changed in this diff Show More