Compare commits

..

11 Commits

Author SHA1 Message Date
94d01bed12 build: Split out "private" sources variable that can be easily appended
Move the action muxing copy stuff in there.
2011-12-20 13:41:08 -05:00
9daf358122 action muxer: drop direct GDBusActionGroup use
We now have GRemoteActionGroup interface with the needed API,
implemented by GDBusActionGroup.

With the new API we could theoretically turn GActionMuxer itself into a
GRemoteActionGroup and expose the _full API to the shell so that the
timestamps could be passed from there.
2011-12-17 13:23:26 -05:00
b4b3f5a669 GActionMuxer: pass platform data
Pass the current timestamp as platform data when activating
an action. This is implemented slightly hacky, since we use
clutter_get_current_event_time() to get at the timestamp, but
the alternative is to expose g_action_muxer_activate_action_full
to js, which would be quite a bit more involved.
2011-12-16 23:39:14 -05:00
5290a9dd08 Add per-window actions
GTK+ also exports window-specific actions, by putting the object path
for the exported action group in the _DBUS_OBJECT_PATH X property.
We add this action group to the app's muxer with a 'win' prefix,
since that is what the exported menu expects. Whenever the focus
window changes, we update the window-specific actions of its
application, and emit notify::action-group to cause the app
menu to be updated.
2011-12-15 01:25:35 -05:00
ab4a7c5237 Another update for GLib API changes
GDBusActionGroup api has changed again, adapt to that.
Also, use a GActionMuxer to add the 'app.' prefix to actions,
instead of manually stripping it out of the action names.
In the future, the muxer will also contain per-window actions
with a 'win.' prefix.
2011-12-15 00:29:31 -05:00
95e5c5cfb1 Application Menu: watch for menu property changes
By the time the window is first mapped and the app menu button is
synced, we may not have finished reading the menu. In that case,
connect to notify::menu and update accordingly.
2011-12-08 21:55:51 +01:00
757fb5796e Application Menu: update for latest GMenu changes
GMenuProxy has been replaced by GDBusMenuModel, and the object path
has been moved (now needs to be retrieved from the AppMenu GApplication
property).
Update the test to prefix each action with "app." as documented,
and use a GtkApplicationWindow instead of a plain GtkWindow.
2011-12-08 21:53:03 +01:00
75e9fa9cfb test-gapplication: update for latest gapplication changes
g_application_set_action_group is deprecated, we should use
GActionMap. Also, GSimpleActions can now be constructed as normal
GObjects.
2011-12-02 22:15:14 +01:00
8997aa45b1 popupMenu: Remove app. from app actions 2011-12-01 12:33:07 -05:00
f884dbbfb2 Application Menu: add support for showing GApplication actions
Use the new GApplication support in ShellApp to create the application
menu. Supports plain (no state), boolean and double actions.
Includes a test application (as no other application uses GApplication
for actions)

https://bugzilla.gnome.org/show_bug.cgi?id=621203
2011-12-01 10:21:38 -05:00
d0c36bb732 ShellApp: port to new GDBusActionGroup and GMenuProxy API
GDBusActionGroup and GMenuProxy are new objects in GIO 2.32 that
help with accessing menus and actions of remote applications.
This patch makes it possible for the shell to associate an
application with a dbus name and from that a GMenu, that will
be shown as the application menu.

https://bugzilla.gnome.org/show_bug.cgi?id=621203
2011-11-25 18:20:38 -05:00
281 changed files with 32870 additions and 51682 deletions

6
.gitignore vendored
View File

@ -18,13 +18,9 @@ config
configure configure
data/gnome-shell.desktop data/gnome-shell.desktop
data/gnome-shell.desktop.in data/gnome-shell.desktop.in
data/gnome-shell-extension-prefs.desktop
data/gnome-shell-extension-prefs.desktop.in
data/gschemas.compiled data/gschemas.compiled
data/org.gnome.shell.gschema.xml data/org.gnome.shell.gschema.xml
data/org.gnome.shell.gschema.valid data/org.gnome.shell.gschema.valid
data/org.gnome.shell.evolution.calendar.gschema.xml
data/org.gnome.shell.evolution.calendar.gschema.valid
docs/reference/*/*.args docs/reference/*/*.args
docs/reference/*/*.bak docs/reference/*/*.bak
docs/reference/*/*.hierarchy docs/reference/*/*.hierarchy
@ -66,11 +62,9 @@ src/calendar-server/org.gnome.Shell.CalendarServer.service
src/gnome-shell src/gnome-shell
src/gnome-shell-calendar-server src/gnome-shell-calendar-server
src/gnome-shell-extension-tool src/gnome-shell-extension-tool
src/gnome-shell-extension-prefs
src/gnome-shell-hotplug-sniffer src/gnome-shell-hotplug-sniffer
src/gnome-shell-jhbuild src/gnome-shell-jhbuild
src/gnome-shell-perf-helper src/gnome-shell-perf-helper
src/gnome-shell-perf-tool
src/gnome-shell-real src/gnome-shell-real
src/hotplug-sniffer/org.gnome.Shell.HotplugSniffer.service src/hotplug-sniffer/org.gnome.Shell.HotplugSniffer.service
src/run-js-test src/run-js-test

311
NEWS
View File

@ -1,312 +1,3 @@
3.4.1
=====
* Fix crash that occurred when an icon theme change caused unexpected
reentrancy in the icon loading code [Jasper; #673512]
* Don't show system and other disabled users in the GDM user list
[Adel; #673784]
* Make gnome-shell-calendar-server initialize GTK+ so it can display
password prompts if needed [#673608; Owen, Rico]
* Adapt to Mutter API change for keybinding addition [Florian; #673014]
* Fix crash when an extension was installed as both a user extension
and a system extension [#673613; Jasper]
* Fix bug where chat entry could end up partially offscreen [Joost, 661944]
* Fix problem where icons weren't updating when theme was changed
[#672941; Florian]
* Look for Evolution calendar settings in GSettings, not GConf [#673610; Owen]
* Add <super>F10 for the application menu [#672909; Florian]
* Fix %Id format characters to work in translations [#673106; Cosimo]
(were already used in fa translation)
* Fix error when NetworkManager restarts [#673043; Giovanni]
* Improve efficiency of overview redraws by working around Clutter issue
[Stefano; #670636]
* Misc bug fixes [Florian, Giovanni, Jasper, Rui, Stefano;
#672592, #672641, #672719, #673187, #673233, #673656]
Contributors:
Giovanni Campagna, Cosimo Cecchi, Stefano Facchini, Adel Gadllah, Rui Matos,
Florian Müllner, Jasper St. Pierre, Owen Taylor, Rico Tzschichholz,
Joost Verdoorn
Translations:
Khaled Hosny [ar], Ihar Hrachyshka [be], Alexander Shopov [bg], Gil Forcada,
Jordi Serratosa [ca], Petr Kovar [cs], Bruce Cowan [en_GB],
Carles Ferrando [ca@valencia], Wolfgang Stöggl [de], Daniel Mustieles [es],
Arash Mousavi [fa], Bruno Brouard [fr], Fran Diéguez [gl],
Sweta Kothari [gu], Yaron Shahrabani [he], Gabor Kelemen [hu],
Shankar Prasad [kn], Žygimantas Beručka [lt], Rudolfs Mazurs [lv],
Sandeep Sheshrao Shedmake [mr], Kjartan Maraas [nb], Piotr Drąg [pl],
Yuri Myasoedov [ru], Daniel Nylander [se], Matej Urbančič [sl],
Miroslav Nikolić [sr], Sasi Bhushan, Praveen Illa [te], Yinghua Wang [zh_CN]
3.4.0
=====
* Don't crash when taking screenshots [Jasper; #672775]
* Fix dialog-resizing problem [Florian; #672543]
Contributors:
Florian Müllner, Jasper St. Pierre
Translations:
Khaled Hosny, Abderrahim Kitouni [ar], Ihar Hrachyshka [be],
Alexander Shopov [bg], Marek Černocký [cs], Jiri Grönroos, Timo Jyrinki [fi],
Bruno Brouard [fr], Fran Diéguez [gl], Yaron Shahrabani [he],
Gabor Kelemen [hu], Jiro Matsuzawa [ja], Kenneth Nielsen [dk],
Mattias Põldaru [et], Changwoo Ryu [ko], Rudolfs Mazurs [lv],
Jonh Wendell [pt_BR], Yuri Myasoedov[ru], Daniel Korostil [uk],
Nguyễn Thái Ngọc Duy [vi], Chao-Hsiung Liao [zh_HK, zh_TW]
3.3.92
======
* Add shell-dialogs for GNOME Keyring prompts [Stef; #652459, #652460, #671034]
* When the user returns from idle, bring up the message tray if there were
messages while they were away [Marina; #643014]
* https://live.gnome.org/EveryDetailMatters
- Make the workspace thumbnails clickable all the way to the edge of the
screen [Stefano; #643319]
- Don't slide out the workspace thumbnails if the mouse is over them when
entering the overview [Joost, #651092]
- Fix placeholder jumps while dragging a dash item [Joost; #651842]
- Don't favorite apps if they are dropped back at the same position
[Jean-Philippe; #656333]
- To avoid confusion, don't allow removing running apps from favorites
[Florian; #644853]
- Fix creation of new workspaces by dragging application launchers
[Stefano; #664202]
- Make it easier to drag dash items without triggering the menu
[Florian; #637103]
* Accessibility [Alejandro]
- Add StWidget API for easily adding accessible states and setting roles,
names [#668366, #667432, #671378]
- Set accessibility information on UI elements
[#644255, #667432, #668361, #672047, #670308, #670312, #670719, #671404]
* Improve key-navigation in the overview [Rui, Florian; #663901]
* Key navigation bug fixes [Rui, Florian; #662493, #663437, #665215, #671998]
* Honor a 'org.gnome.shell.overrides.dynamic-workspaces' setting that
determines whether the workspace count is dynamic and unsaved in GSettings
or static and saved. [Florian; #671568]
* Avoid saving user presence to GSettings when not necessary
[Florian; #665701, #668214]
* Save screencasts in the users Videos/ directory [Adel; #670749]
Use a "human readable" filename [Florian, Adel, Ray; #670753]
* Allow dragging from the empty part of the top panel to unmaximize a window
[Florian; #666359]
* Fix hangs that could occur when switching away to a VT [Ray; #653833]
* Fix problems with installing from extensions.gnome.org [Giovanni; #671134]
* Fix locking the screen when suspending via menu [David, Gert; #670820]
* Fix browser plugin with Konqueror and Opera [Jasper]
* Fix shell restart not to bring up failure screen [Giovanni; #648384]
* Reorganize and clean up CSS theming [Allan; #668209]
* Improve appearance of modal dialogs [Allan, Florian; #670227, #668209]
* Update the calendar code to use ECalClient [Giovanni; #671177]
* Update jhbuild script to use the main moduleset [Owen, Will; #668440]
* StTextureCache: code cleanup, evict unused icons, merge together
simulataneous requests for the same icon [Jasper; #670771, #671656, #672273]
* Clean up St for recent Clutter changes and fix bugs. StContainer and
StGroup are removed [Jasper, Florian; #670034, #670640, #670904]
* Code cleanup [Adel, Jasper, Rui; #613194, #671086, #671103]
* Misc bug fixes
[Adel, Colin G, Cosimo, Florian, Giovanni, Jasper, Marius, Rui, Stefano;
#651130, #658946, #667552, #670076, #671001, #670979, #671410, #671411,
#671556, #671656, #671657, #672011, #672024, #672240, #672265, #672270,
#672321, #672326, #672413, #672471]
Contributors:
Jean-Philippe Braun, Giovanni Campagna, Cosimo Cecchi, Allan Day,
Stefano Facchini, David Foerster, Adel Gadllah, Marius Gedminas,
Colin Guthrie, Gert Michael Kulyk, William Lachance, Rui Matos,
Florian Müllner, Alejandro Piñeiro, Jan Alexander Steffens,
Jasper St. Pierre, Ray Strode, Owen Taylor, Joost Verdoorn, Stef Walter,
Marina Zhurakhinskaya
Translations:
Nilamdyuti Goswami [as], Ihar Hrachyshka, Kasia Bondarava [be],
Alexander Shopov, Ivaylo Valkov [bg], Gil Forcada [ca], Marek Černocký [cs],
Mario Blättermann [de], Kris Thomsen [dk], Bruce Cowan [en_GB],
Kristjan Schmidt [eo], Daniel Mustieles [es], Mattias Põldaru [et],
Inaki Larranaga Murgoitio [eu], Arash Mousavi [fa], Timo Jyrinki [fi],
Bruno Brouard [fr], Fran Diéguez [gl], Sweta Kothari [gu],
Yaron Shahrabani [he], Gabor Kelemen [hu], Jiro Matsuzawa [ja],
Baurzhan Muftakhidinov [kk], Seong-ho Cho [ko], Žygimantas Beručka [lt],
Anita Reitere [lv], Anish A, Praveen Arimbrathodiyil, Mohammed Sadiq [ml],
fKjartan Maraas [nb], Wouter Bolsterlee [nl], A S Alam [pa], Piotr Drąg [pl],
Duarte Loreto [pt], Jonh Wendell [pt_BR], Yuri Myasoedov [ru],
Matej Urbančič [sl], Miroslav Nikolić [sr], Tirumurti Vasudevan [ta],
Sasi Bhushan, Krishnababu Krothapalli [te], Daniel Korostil [uk],
Nguyễn Thái Ngọc Duy [vi], YunQiang Su, Yinghua Wang [zh_CN],
Chao-Hsiung Liao [zh_HK, zh_TW]
3.3.90
======
* Allow other applications to implement search providers via D-Bus
[Florian; #663125, #670148]
* Remove "Recent Items" search, as replaced by Documents search
[Florian; #663125]
* Allow NetworkManager VPN plugins to use a shell-themed dialog
[Giovanni; #658484]
* Port away from deprecated Clutter API [Jasper, Florian, Adel; #670034]
- StTooltip is removed
- StWidget is now a concrete class and can be instantiated
- st_container_destroy_children(), st_box_layout_insert_actor(),
and other functions removed in favor of new replacements in Clutter.
* Use systemd for console/session handling when available [Lennart]
* Visual improvements to contact search, padding, top panel, checkboxes
[Allan, Florian, Jakub; #669489, #669811, #669993]
* Add a include_cursor parameter to Screenshot and ScreenshotWindow
D-Bus methods [Adel; #670086]
* Add a "FlashArea" D-Bus method to do the screenshot flash without a
screenshot [Adel; #669660]
* Build fixes [Adel, Giovanni, Jasper; #658484, #669637]
* Misc bug fixes [Adel, Florian, Giovanni, Guillaume, Jasper, Jeff,
Marc-Antoine, Stef, Stefano, Will; #642135, #658484, #658908, #667694,
#669098, #669921, #669662, #669694, #669776, #669887, #669921, #670005,
#670006, #670319, #670418, #670489]
Contributors:
Giovanni Campagna, Cosimo Cecchi, Allan Day, Guillaume Desmottes, Jeff Epler,
Stefano Facchini, Adel Gadllah, Florian Müllner, Marc-Antoine Perennou,
Jasper St. Pierre, Lennart Poettering, Jakub Steiner, Jasper St. Pierre,
Will Thompson, Stef Walter
Translations:
Ihar Hrachyshka [be], Marek Černocký, Adam Matoušek [cs],
Kenneth Nielsen [dk], Daniel Mustieles [es], Mattias Põldaru [et],
Fran Diéguez [gl], Yaron Shahrabani [he], Luca Ferretti [it],
Baurzhan Muftakhidinov [kk], Aurimas Černius [lt], Kjartan Maraas [nb],
A S Alam [pa], Matej Urbančič [sl], Miroslav Nikolić [sr],
Praveen Illa [te], Chao-Hsiung Liao [zh_HK, zh_TW]
3.3.5
=====
* Extension system: [Jasper; #668429]
http://blog.mecheye.net/2012/02/more-extension-api-breaks/
- Add a 'gnome-shell-extension-prefs' application for displaying extension
preferences as provided by the extension in a prefs.js file.
- Allow launching gnome-shell-extension-prefs from extensions.gnome.org
throuhg the browser plugin.
- Add ExtensionUtils.getCurrentExtension() for an extension to get a
handle to an extension object, to get local imports or paths.
- Add an onshellrestart callback to the browser plugin [Jasper; #668517]
* Screenshots:
- Move the screenshot "flash" to the shell [Cosimo; #668618]
- Move saving screenshots to a thread [Adel; #652952]
- Correctly screenshot rounded decorations [Jasper; #662486]
* Screen recorder:
- Change the default pipeline to favor speed over quality [Owen; #669066]
- Drop frames to keep from running the user out of memory [Owen; #669066]
* Work around a slow implementation of glReadPixels() in the Intel drivers,
improving performance for screenshots and the screen recorder.
[Owen; #669065]
* Use Keywords: field in desktop files when search for applications
[Florian; #609702]
* Strip debian- when matching desktop file names [Jasper; #665647]
* Fix up various problems from CSS background size-addition
[Florian, Jasper; #668430, #633462]
* UI tweaks and behavior fixes
[Florian, Giovanni, Stefano; #643867, #666197, #664622]
* Some improvements to exported accessibility information [Alejando; #667376]
* Don't show contacts without IM information as offline [Florian; #662685]
* Don't change status from hidden to extended_away when going idle
[Florian; #642408]
* Cleanups [Emmanuele, Jasper; #662152, #669239]
* Misc bug fixes [Cosimo, Dan, Florian, Jasper, Rui, Stefano;
#633462, #643867, #662213, #662386, #662747, #665000, #665017, #665322,
#667371, #667860, #668020, #668517, #668541, #669236]
Contributors:
Emmanuele Bassi, Giovanni Campagna, Cosimo Cecchi, Stefano Facchini,
Adel Gadllah, Rui Matos, Florian Müllner, Alejandro Piñeiro,
Jasper St. Pierre, Owen Taylor, Dan Winship
Translations:
Daniel Mustieles [es], Timo Jyrinki [fi], Seán de Búrca [ga],
Fran Diéguez [gl], Kjartan Maraas [nb], Wouter Bolsterlee [nl],
Danishka Navin [si], Yaron Shahrabani [he], Matej Urbančič [sl],
Chao-Hsiung Liao [zh_HK, zh_TW]
3.3.4
=====
* https://live.gnome.org/EveryDetailMatters
- Add "browse" for labels for dash items - once a tooltip is
showing, switch to other items without a delay [Seif; #666170]
- Always scale down windows in the overview at least to 70% [Vit; #646704]
- Fix the new-workspace drop indicator sometimes getting stuck
[Stefano; #664201]
- Delay rearranging windows in the overview as long as the pointer
is over a window [Vit; #645325]
* Add a GConf => DConf migration file for overriden Mutter settings
[Florian; #667636]
* When a VPN connection is active, show that as the network icon
[Giovanni; #665115]
* Handle the "ExtendedAway" IM status as away, not offline [Guillaume; #667813]
* Improve the appearance of the labels in "Applications" [Alex; #642392]
* Adjust for GTK+ and Mutter API changes for application menu [Ryan; #668118]
* Add section label support to the application menu [Giovanni; #666681]
* Fix screenshot methods to work again [Cosimo; #667662]
* Fix several crashers related to updating workspace thumbnails [Owen; #667652]
* Fix memory management error causing gnome-shell-hotplug-sniffer to crash
[Owen; #667378]
* Build fixes [Emmanuele, Rico; #667864]
* Code cleanups [Adel; #668087]
* Misc bug fixes [Colin, Florian, Giovanni, Owen, Xavier; #633028, #658817,
#664138, #667881, #668048, #668050]
Contributors:
Emmanuele Bassi, Giovanni Campagna, Cosimo Cecchi, Xavier Claessens,
Guillaume Desmottes, Stefano Facchini, Adel Gadllah, Alex Hultman,
Ryan Lortie, Seif Lotfy, Florian Müllner, Vit Stanislav, Owen Taylor,
Rico Tzschichholz, Colin Walters
Translations:
Ihar Hrachyshka [be], Alexander Shopov [bg], Arash Mousavi [fa],
Jiri Grönroos, Timo Jyrinki [fi], Fran Diéguez [gl], Kjartan Maraas [nb],
Yuri Myasoedov [ru], Matej Urbančič [sl], Nguyễn Thái Ngọc Duy [vi]
3.3.3
=====
* https://live.gnome.org/EveryDetailMatters
- Stop flashing the window labels on actions in overview [Zan; #644861]
- Improve the look of window captions in the overview [Marc; #664487]
- Move dash tooltips beside the icon [Seif, Stefano; #666166]
* Support application menus exported from applications via new GLib API
and D-Bus protocol. [Giovanni, Colin, Matthias, Cosimo]
* For removable device prompts, show "Open with Rhythmbox], rather
than "Open with Rhythmbox Music Player' [Florian; #664561]
* Switch to activating the message tray only with a hot corner rather
than a full row of pixels, allowing mouse events to apps [Rui; #663366]
* Fully handle the case where the workspaces-only-on-primary
GSetting is set to false [Florian; #652580]
* Add support for background-size CSS property to St [Quentin; #633462]
* Port to new GJS Lang.Class framework [Giovanni; #664436]
* Finish port to GDBus [Giovanni; #664436]
* Stop using the deprecated Clutter default stage [Florian, Jasper; #664052]
* Fix bugs that kept browser plugin from working in WebKit-based browser
[Jasper; #666444]
* Fix typo that made uninstalling extensions not work [Jasper]
* Fix crash in browser plugin if shell is not run [Jürg]
* Reintroduce piscine paschal ovum [Giovanni; #666606]
* Network menu bug fixes
Giovanni; #664124, #665194, #665680, #666429, #666614]
* Misc bug fixes [Florian, Jasper, Jonny, Marina, Ron; #647587, #659272,
#664138, #665261, #666020, #666243]
* Build fixes [Owen]
Contributors:
Jürg Billeter, Giovanni Campagna, Stefano Candori, Cosimo Cecchi,
Matthias Clasen, Zan Dobersek, Quentin Glidic, Jonny Lamb, Ryan Lortie,
Seif Lotfy, Rui Matos, Florian Müllner, Bastien Nocera, Jasper St. Pierre,
Marc Plano-Lesay, Owen Taylor, Colin Walters, Ron Yorsten,
Marina Zhurakhinskaya
Translations:
Petr Kovar [cs], Kris Thomsen [dk], Daniel Mustieles [es],
Ville-Pekka Vainio [fi], Yaron Shahrabani [he], Luca Ferretti [it],
Hideki Yamane [ja], Žygimantas Beručka [lt], Jovan Naumovski [mk],
Kjartan Maraas [nb], "Andreas N" [nn], Lucian Adrian Grijincu [ro],
Matej Urbančič [sl], Praveen Illa [te], Muhammet Kara [tr],
Daniel Korostil [uk], Aron Xu [zh_CN]
3.3.2 3.3.2
===== =====
* Port D-Bus usage in the shell to GDBus [Giovanni, Marc-Antoine, Florian, * Port D-Bus usage in the shell to GDBus [Giovanni, Marc-Antoine, Florian,
@ -463,7 +154,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));
@ -264,13 +262,11 @@ NPP_Destroy(NPP instance,
/* =================== scripting interface =================== */ /* =================== scripting interface =================== */
typedef struct { typedef struct {
NPObject parent; NPObject parent;
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
@ -492,12 +455,9 @@ plugin_enable_extension (PluginObject *obj,
NPString uuid, NPString uuid,
gboolean enabled) gboolean enabled)
{ {
gchar *uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length); const gchar *uuid_str = uuid.UTF8Characters;
if (!uuid_is_valid (uuid_str)) if (!uuid_is_valid (uuid_str))
{ return FALSE;
g_free (uuid_str);
return FALSE;
}
g_dbus_proxy_call (obj->proxy, g_dbus_proxy_call (obj->proxy,
(enabled ? "EnableExtension" : "DisableExtension"), (enabled ? "EnableExtension" : "DisableExtension"),
@ -508,8 +468,6 @@ plugin_enable_extension (PluginObject *obj,
NULL, /* callback */ NULL, /* callback */
NULL /* user_data */); NULL /* user_data */);
g_free (uuid_str);
return TRUE; return TRUE;
} }
@ -518,32 +476,21 @@ plugin_install_extension (PluginObject *obj,
NPString uuid, NPString uuid,
NPString version_tag) NPString version_tag)
{ {
gchar *uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length); const gchar *uuid_str = uuid.UTF8Characters;
gchar *version_tag_str;
if (!uuid_is_valid (uuid_str)) if (!uuid_is_valid (uuid_str))
{ return FALSE;
g_free (uuid_str);
return FALSE;
}
version_tag_str = g_strndup (version_tag.UTF8Characters,
version_tag.UTF8Length);
g_dbus_proxy_call (obj->proxy, g_dbus_proxy_call (obj->proxy,
"InstallRemoteExtension", "InstallRemoteExtension",
g_variant_new ("(ss)", g_variant_new ("(ss)",
uuid_str, uuid_str,
version_tag_str), version_tag.UTF8Characters),
G_DBUS_CALL_FLAGS_NONE, G_DBUS_CALL_FLAGS_NONE,
-1, /* timeout */ -1, /* timeout */
NULL, /* cancellable */ NULL, /* cancellable */
NULL, /* callback */ NULL, /* callback */
NULL /* user_data */); NULL /* user_data */);
g_free (uuid_str);
g_free (version_tag_str);
return TRUE; return TRUE;
} }
@ -554,14 +501,11 @@ plugin_uninstall_extension (PluginObject *obj,
{ {
GError *error = NULL; GError *error = NULL;
GVariant *res; GVariant *res;
gchar *uuid_str; const gchar *uuid_str;
uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length); uuid_str = uuid.UTF8Characters;
if (!uuid_is_valid (uuid_str)) if (!uuid_is_valid (uuid_str))
{ return FALSE;
g_free (uuid_str);
return FALSE;
}
res = g_dbus_proxy_call_sync (obj->proxy, res = g_dbus_proxy_call_sync (obj->proxy,
"UninstallExtension", "UninstallExtension",
@ -572,8 +516,6 @@ plugin_uninstall_extension (PluginObject *obj,
NULL, /* cancellable */ NULL, /* cancellable */
&error); &error);
g_free (uuid_str);
if (!res) if (!res)
{ {
g_warning ("Failed to uninstall extension: %s", error->message); g_warning ("Failed to uninstall extension: %s", error->message);
@ -591,14 +533,11 @@ plugin_get_info (PluginObject *obj,
{ {
GError *error = NULL; GError *error = NULL;
GVariant *res; GVariant *res;
gchar *uuid_str; const gchar *uuid_str;
uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length); uuid_str = uuid.UTF8Characters;
if (!uuid_is_valid (uuid_str)) if (!uuid_is_valid (uuid_str))
{ return FALSE;
g_free (uuid_str);
return FALSE;
}
res = g_dbus_proxy_call_sync (obj->proxy, res = g_dbus_proxy_call_sync (obj->proxy,
"GetExtensionInfo", "GetExtensionInfo",
@ -608,8 +547,6 @@ plugin_get_info (PluginObject *obj,
NULL, /* cancellable */ NULL, /* cancellable */
&error); &error);
g_free (uuid_str);
if (!res) if (!res)
{ {
g_warning ("Failed to retrieve extension metadata: %s", error->message); g_warning ("Failed to retrieve extension metadata: %s", error->message);
@ -627,14 +564,11 @@ plugin_get_errors (PluginObject *obj,
{ {
GError *error = NULL; GError *error = NULL;
GVariant *res; GVariant *res;
gchar *uuid_str; const gchar *uuid_str;
uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length); uuid_str = uuid.UTF8Characters;
if (!uuid_is_valid (uuid_str)) if (!uuid_is_valid (uuid_str))
{ return FALSE;
g_free (uuid_str);
return FALSE;
}
res = g_dbus_proxy_call_sync (obj->proxy, res = g_dbus_proxy_call_sync (obj->proxy,
"GetExtensionErrors", "GetExtensionErrors",
@ -644,8 +578,6 @@ plugin_get_errors (PluginObject *obj,
NULL, /* cancellable */ NULL, /* cancellable */
&error); &error);
g_free (uuid_str);
if (!res) if (!res)
{ {
g_warning ("Failed to retrieve errors: %s", error->message); g_warning ("Failed to retrieve errors: %s", error->message);
@ -656,33 +588,6 @@ plugin_get_errors (PluginObject *obj,
return jsonify_variant (res, result); return jsonify_variant (res, result);
} }
static gboolean
plugin_launch_extension_prefs (PluginObject *obj,
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)
@ -728,8 +633,7 @@ plugin_get_shell_version (PluginObject *obj,
STRINGN_TO_NPVARIANT (buffer, length, *result); STRINGN_TO_NPVARIANT (buffer, length, *result);
out: out:
if (res) g_variant_unref (res);
g_variant_unref (res);
return ret; return ret;
} }
@ -793,14 +697,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 +706,6 @@ plugin_object_has_property (NPObject *npobj,
NPIdentifier name) NPIdentifier name)
{ {
return (name == onextension_changed_id || return (name == onextension_changed_id ||
name == onrestart_id ||
name == api_version_id || name == api_version_id ||
name == shell_version_id); name == shell_version_id);
} }
@ -837,33 +732,6 @@ plugin_object_get_property (NPObject *npobj,
else else
NULL_TO_NPVARIANT (*result); NULL_TO_NPVARIANT (*result);
} }
else if (name == onrestart_id)
{
if (obj->restart_listener)
OBJECT_TO_NPVARIANT (obj->restart_listener, *result);
else
NULL_TO_NPVARIANT (*result);
}
return TRUE;
}
static bool
plugin_object_set_callback (NPObject **listener,
const NPVariant *value)
{
if (!NPVARIANT_IS_OBJECT (*value) && !NPVARIANT_IS_NULL (*value))
return FALSE;
if (*listener)
funcs.releaseobject (*listener);
*listener = NULL;
if (NPVARIANT_IS_OBJECT (*value))
{
*listener = NPVARIANT_TO_OBJECT (*value);
funcs.retainobject (*listener);
}
return TRUE; return TRUE;
} }
@ -875,13 +743,25 @@ plugin_object_set_property (NPObject *npobj,
{ {
PluginObject *obj; PluginObject *obj;
obj = (PluginObject *)npobj; if (!plugin_object_has_property (npobj, name))
return FALSE;
if (name == onextension_changed_id) if (name == onextension_changed_id)
return plugin_object_set_callback (&obj->listener, value); {
obj = (PluginObject*) npobj;
if (obj->listener)
funcs.releaseobject (obj->listener);
if (name == onrestart_id) obj->listener = NULL;
return plugin_object_set_callback (&obj->restart_listener, value); if (NPVARIANT_IS_OBJECT (*value))
{
obj->listener = NPVARIANT_TO_OBJECT (*value);
funcs.retainobject (obj->listener);
return TRUE;
}
else if (NPVARIANT_IS_NULL (*value))
return TRUE;
}
return FALSE; return FALSE;
} }
@ -915,9 +795,7 @@ init_methods_and_properties (void)
install_extension_id = funcs.getstringidentifier ("installExtension"); install_extension_id = funcs.getstringidentifier ("installExtension");
uninstall_extension_id = funcs.getstringidentifier ("uninstallExtension"); uninstall_extension_id = funcs.getstringidentifier ("uninstallExtension");
get_errors_id = funcs.getstringidentifier ("getExtensionErrors"); get_errors_id = funcs.getstringidentifier ("getExtensionErrors");
launch_extension_prefs_id = funcs.getstringidentifier ("launchExtensionPrefs");
onrestart_id = funcs.getstringidentifier ("onshellrestart");
onextension_changed_id = funcs.getstringidentifier ("onchange"); onextension_changed_id = funcs.getstringidentifier ("onchange");
} }

View File

@ -1,5 +1,5 @@
AC_PREREQ(2.63) AC_PREREQ(2.63)
AC_INIT([gnome-shell],[3.4.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell]) AC_INIT([gnome-shell],[3.3.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])
@ -53,28 +53,27 @@ 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.3.2
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.31.0
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-unix-2.0 >= $GIO_MIN_VERSION
@ -85,7 +84,6 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_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
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 +92,7 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION
polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes
libnm-glib libnm-util gnome-keyring-1 libnm-glib libnm-util gnome-keyring-1)
gcr-3 >= $GCR_MIN_VERSION)
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0) PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
@ -108,6 +105,8 @@ AC_DEFINE_UNQUOTED([GJS_VERSION], ["$GJS_VERSION"], [The version of GJS we're li
AC_SUBST([GJS_VERSION], ["$GJS_VERSION"]) AC_SUBST([GJS_VERSION], ["$GJS_VERSION"])
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION]) GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
JHBUILD_TYPELIBDIR="$INTROSPECTION_TYPELIBDIR"
AC_SUBST(JHBUILD_TYPELIBDIR)
saved_CFLAGS=$CFLAGS saved_CFLAGS=$CFLAGS
saved_LIBS=$LIBS saved_LIBS=$LIBS
@ -117,8 +116,7 @@ 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(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)
@ -141,33 +139,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)
@ -210,7 +181,7 @@ GTK_DOC_CHECK([1.15], [--flavour no-tmpl])
# minimum/yes/maximum are the same, however. # minimum/yes/maximum are the same, however.
AC_ARG_ENABLE(compile_warnings, AC_ARG_ENABLE(compile_warnings,
AS_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@],[Turn on compiler warnings]),, AS_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@],[Turn on compiler warnings]),,
enable_compile_warnings=error) enable_compile_warnings=maximum)
changequote(,)dnl changequote(,)dnl
if test "$enable_compile_warnings" != no ; then if test "$enable_compile_warnings" != no ; then
@ -226,7 +197,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
@ -234,7 +205,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])
@ -275,6 +246,7 @@ AC_CONFIG_FILES([
docs/reference/st/Makefile docs/reference/st/Makefile
docs/reference/st/st-docs.sgml docs/reference/st/st-docs.sgml
js/Makefile js/Makefile
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,8 +59,6 @@ gschemas.compiled: $(gsettings_SCHEMAS:.xml=.valid)
all-local: gschemas.compiled all-local: gschemas.compiled
convertdir = $(datadir)/GConf/gsettings
convert_DATA = gnome-shell-overrides.convert
shadersdir = $(pkgdatadir)/shaders shadersdir = $(pkgdatadir)/shaders
shaders_DATA = \ shaders_DATA = \
@ -75,17 +67,12 @@ shaders_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) \
$(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

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

@ -53,18 +53,15 @@
</key> </key>
<key name="saved-im-presence" type="i"> <key name="saved-im-presence" type="i">
<default>1</default> <default>1</default>
<_summary>Internally used to store the last IM presence explicitly set by the user. The <_summary></_summary>
value here is from the TpConnectionPresenceType enumeration.</_summary>
</key> </key>
<key name="saved-session-presence" type="i"> <key name="saved-session-presence" type="i">
<default>0</default> <default>0</default>
<_summary>Internally used to store the last session presence status for the user. The <_summary></_summary>
value here is from the GsmPresenceStatus enumeration.</_summary>
</key> </key>
<child name="clock" schema="org.gnome.shell.clock"/> <child name="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,24 +76,6 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
</key> </key>
</schema> </schema>
<schema id="org.gnome.shell.keybindings" path="/org/gnome/shell/keybindings/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="open-application-menu" type="as">
<default>["&lt;Super&gt;F10"]</default>
<_summary>Keybinding to open the application menu</_summary>
<_description>
Keybinding to open the application menu.
</_description>
</key>
<key name="toggle-recording" type="as">
<default><![CDATA[['<Control><Shift><Alt>r']]]></default>
<_summary>Keybinding to toggle the screen recorder</_summary>
<_description>
Keybinding to start/stop the builtin screen recorder.
</_description>
</key>
</schema>
<schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/" <schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/"
gettext-domain="@GETTEXT_PACKAGE@"> gettext-domain="@GETTEXT_PACKAGE@">
<key name="keyboard-type" type="s"> <key name="keyboard-type" type="s">
@ -129,7 +108,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
@ -148,7 +127,7 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
take care of its own output - this might be used to send the output take care of its own output - this might be used to send the output
to an icecast server via shout2send or similar. When unset or set to an icecast server via shout2send or similar. When unset or set
to an empty value, the default pipeline will be used. This is currently to an empty value, the default pipeline will be used. This is currently
'vp8enc quality=8 speed=6 threads=%T ! queue ! webmmux' 'videorate ! vp8enc quality=10 speed=2 threads=%T ! queue ! webmmux'
and records to WEBM using the VP8 codec. %T is used as a placeholder and records to WEBM using the VP8 codec. %T is used as a placeholder
for a guess at the optimal thread count on the system. for a guess at the optimal thread count on the system.
</_description> </_description>
@ -191,14 +170,6 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
</description> </description>
</key> </key>
<key name="dynamic-workspaces" type="b">
<default>true</default>
<summary>Workspaces are managed dynamically</summary>
<description>
This key overrides the key in org.gnome.mutter when running GNOME Shell.
</description>
</key>
<key name="workspaces-only-on-primary" type="b"> <key name="workspaces-only-on-primary" type="b">
<default>true</default> <default>true</default>
<summary>Workspaces only on primary monitor</summary> <summary>Workspaces only on primary monitor</summary>

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

View File

@ -17,16 +17,10 @@
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
/* Text Styles */
/* default text style */
stage { stage {
font-family: cantarell, sans-serif; font-family: cantarell, sans-serif;
font-size: 11pt;
color: white;
} }
/* links */
.shell-link { .shell-link {
color: #0000ff; color: #0000ff;
text-decoration: underline; text-decoration: underline;
@ -36,28 +30,10 @@ stage {
color: #0000e0; color: #0000e0;
} }
/* small */ .label-shadow {
.app-well-menu, color: rgba(0,0,0,0.5);
.contact-details-status,
.run-dialog-label,
.run-dialog-error-label {
font-size: 9pt;
} }
/* small bold */
.dash-label,
.window-caption,
.switcher-list,
.source-title,
.app-well-app > .overview-icon,
.remove-favorite > .overview-icon,
.search-result-content > .overview-icon {
font-size: 9pt;
font-weight: bold;
}
/* Scroll Bars */
StScrollBar StScrollBar
{ {
padding: 0px; padding: 0px;
@ -68,11 +44,6 @@ StScrollView.vfade
-st-vfade-offset: 68px; -st-vfade-offset: 68px;
} }
StScrollView.hfade
{
-st-hfade-offset: 68px;
}
StScrollView StScrollBar StScrollView StScrollBar
{ {
min-width: 16px; min-width: 16px;
@ -108,28 +79,15 @@ StScrollBar StButton#vhandle:hover
background-color: #292929; background-color: #292929;
} }
/* Check Boxes */ StTooltip StLabel {
border: 1px solid rgba(255,255,255,0.6);
.check-box ShellGenericContainer { border-radius: 5px;
spacing: .8em; padding: 2px 12px;
} background-color: rgba(0,0,0,0.9);
color: #ffffff;
.check-box StBin { font-size: 0.8em;
width: 24px; font-weight: normal;
height: 22px; text-align: center;
background-image: url("checkbox-off.svg");
}
.check-box:focus StBin {
background-image: url("checkbox-off-focused.svg");
}
.check-box:checked StBin {
background-image: url("checkbox.svg");
}
.check-box:focus:checked StBin {
background-image: url("checkbox-focused.svg");
} }
/* PopupMenu */ /* PopupMenu */
@ -144,6 +102,8 @@ StScrollBar StButton#vhandle:hover
} }
.popup-menu { .popup-menu {
color: #ffffff;
font-size: 10.5pt;
min-width: 200px; min-width: 200px;
} }
@ -182,6 +142,8 @@ StScrollBar StButton#vhandle:hover
.popup-combo-menu { .popup-combo-menu {
background-color: rgba(0,0,0,0.9); background-color: rgba(0,0,0,0.9);
padding: 1em 0em; padding: 1em 0em;
color: #ffffff;
font-size: 10.5pt;
border: 1px solid #5f5f5f; border: 1px solid #5f5f5f;
border-radius: 9px; border-radius: 9px;
} }
@ -251,10 +213,10 @@ StScrollBar StButton#vhandle:hover
} }
.popup-menu-icon { .popup-menu-icon {
icon-size: 1.09em; icon-size: 1.14em;
} }
/* Switches */ /* Switches (to be used in menus) */
.toggle-switch { .toggle-switch {
width: 65px; width: 65px;
height: 22px; height: 22px;
@ -262,68 +224,51 @@ StScrollBar StButton#vhandle:hover
.toggle-switch-us { .toggle-switch-us {
background-image: url("toggle-off-us.svg"); background-image: url("toggle-off-us.svg");
background-size: contain;
} }
.toggle-switch-us:checked { .toggle-switch-us:checked {
background-image: url("toggle-on-us.svg"); background-image: url("toggle-on-us.svg");
background-size: contain;
} }
.toggle-switch-intl { .toggle-switch-intl {
background-image: url("toggle-off-intl.svg"); background-image: url("toggle-off-intl.svg");
background-size: contain;
} }
.toggle-switch-intl:checked { .toggle-switch-intl:checked {
background-image: url("toggle-on-intl.svg"); background-image: url("toggle-on-intl.svg");
background-size: contain;
} }
.nm-menu-item-icons { .nm-menu-item-icons {
spacing: .5em; spacing: .5em;
} }
/* Buttons */ /* Shared button properties */
.dash-search-button, .dash-search-button, .notification-button, .notification-icon-button,
.notification-button, .hotplug-notification-item, .hotplug-resident-eject-button,
.notification-icon-button,
.hotplug-notification-item,
.hotplug-resident-eject-button,
.modal-dialog-button { .modal-dialog-button {
font-weight: bold; color: white;
border: 1px solid #8b8b8b; border: 1px solid #8b8b8b;
background-gradient-direction: vertical; background-gradient-direction: vertical;
background-gradient-start: rgba(255, 255, 255, 0.2); background-gradient-start: rgba(255, 255, 255, 0.2);
background-gradient-end: rgba(255, 255, 255, 0); background-gradient-end: rgba(255, 255, 255, 0);
} }
.dash-search-button:hover, .dash-search-button:hover, .notification-button:hover,
.notification-button:hover, .notification-icon-button:hover, .hotplug-notification-item:hover,
.notification-icon-button:hover, .hotplug-resident-eject-button:hover, .modal-dialog-button:hover {
.hotplug-notification-item:hover,
.hotplug-resident-eject-button:hover,
.modal-dialog-button:hover {
background-gradient-start: rgba(255, 255, 255, 0.3); background-gradient-start: rgba(255, 255, 255, 0.3);
background-gradient-end: rgba(255, 255, 255, 0.1); background-gradient-end: rgba(255, 255, 255, 0.1);
} }
.dash-search-button:selected, .dash-search-button:selected, .notification-button:focus,
.dash-search-button:focus, .notification-icon-button:focus, .hotplug-notification-item:focus,
.notification-button:focus,
.notification-icon-button:focus,
.hotplug-notification-item:focus,
.modal-dialog-button:focus { .modal-dialog-button:focus {
border: 2px solid #8b8b8b; border: 2px solid #8b8b8b;
} }
.dash-search-button:active, .dash-search-button:active, .dash-search-button:pressed,
.dash-search-button:pressed, .notification-button:active, .notification-icon-button:active,
.notification-button:active, .hotplug-notification-item:active, .hotplug-resident-eject-button:active,
.notification-icon-button:active, .modal-dialog-button:active, .modal-dialog-button:pressed {
.hotplug-notification-item:active,
.hotplug-resident-eject-button:active,
.modal-dialog-button:active,
.modal-dialog-button:pressed {
background-gradient-start: rgba(255, 255, 255, 0); background-gradient-start: rgba(255, 255, 255, 0);
background-gradient-end: rgba(255, 255, 255, 0.2); background-gradient-end: rgba(255, 255, 255, 0.2);
} }
@ -331,7 +276,10 @@ StScrollBar StButton#vhandle:hover
/* Panel */ /* Panel */
#panel { #panel {
color: #ffffff;
background-color: black; background-color: black;
border-image: url("panel-border.svg") 1;
font-size: 10.5pt;
font-weight: bold; font-weight: bold;
height: 1.86em; height: 1.86em;
} }
@ -359,25 +307,22 @@ StScrollBar StButton#vhandle:hover
.panel-corner { .panel-corner {
-panel-corner-radius: 10px; -panel-corner-radius: 10px;
-panel-corner-background-color: black; -panel-corner-background-color: black;
-panel-corner-border-width: 2px; -panel-corner-inner-border-width: 2px;
-panel-corner-border-color: transparent; -panel-corner-inner-border-color: transparent;
-panel-corner-outer-border-width: 1px;
-panel-corner-outer-border-color: #536272;
} }
.panel-corner:active, .panel-corner:active,
.panel-corner:overview, .panel-corner:overview,
.panel-corner:focus { .panel-corner:focus {
-panel-corner-border-color: rgba(255,255,255,0.8); -panel-corner-inner-border-color: rgba(255,255,255,0.8);
} }
#appMenu { #appMenu {
spacing: 4px; spacing: 4px;
} }
/* used for the app menu header only */
.label-shadow {
color: rgba(0,0,0,0.5);
}
.panel-button #appMenuIcon { .panel-button #appMenuIcon {
app-icon-bottom-clip: 1px; app-icon-bottom-clip: 1px;
} }
@ -431,8 +376,6 @@ StScrollBar StButton#vhandle:hover
-boxpointer-gap: 4px -boxpointer-gap: 4px
} }
/* User Menu */
#panelUserMenu { #panelUserMenu {
spacing: 4px; spacing: 4px;
} }
@ -472,6 +415,8 @@ StScrollBar StButton#vhandle:hover
padding: .4em 0em; padding: .4em 0em;
border-radius: 4px; border-radius: 4px;
border: 1px solid #5f5f5f; border: 1px solid #5f5f5f;
color: #ffffff;
font-size: 10.5pt;
} }
.status-chooser-status-item, .status-chooser-status-item,
@ -480,7 +425,7 @@ StScrollBar StButton#vhandle:hover
} }
.system-status-icon { .system-status-icon {
icon-size: 1.09em; icon-size: 1.14em;
} }
/* Overview */ /* Overview */
@ -490,6 +435,7 @@ StScrollBar StButton#vhandle:hover
} }
.window-caption { .window-caption {
color: white;
spacing: 25px; spacing: 25px;
} }
@ -521,15 +467,16 @@ StScrollBar StButton#vhandle:hover
} }
.window-caption { .window-caption {
background: rgba(0,0,0,0.5); background: rgba(0,0,0,0.8);
border-radius: 8px; border: 1px solid rgba(128,128,128,0.40);
padding: 4px 12px; border-radius: 10px;
-shell-caption-spacing: 12px; font-size: 9pt;
padding: 2px 8px;
-shell-caption-spacing: 4px;
} }
.window-close { .window-close {
background-image: url("close-window.svg"); background-image: url("close-window.svg");
background-size: 34px;
height: 34px; height: 34px;
width: 34px; width: 34px;
-shell-close-overlap: 20px; -shell-close-overlap: 20px;
@ -564,20 +511,18 @@ StScrollBar StButton#vhandle:hover
.placeholder { .placeholder {
background-image: url("dash-placeholder.svg"); background-image: url("dash-placeholder.svg");
background-size: contain;
height: 24px; height: 24px;
} }
#viewSelector { #viewSelector {
spacing: 1em; spacing: 1em;
font-size: 12pt;
} }
#viewSelectorTabBar { #viewSelectorTabBar {
padding: 1em; padding: 1em;
} }
/* Search Box */
#searchArea { #searchArea {
padding: 0px 24px; padding: 0px 24px;
} }
@ -585,7 +530,6 @@ StScrollBar StButton#vhandle:hover
#searchEntry { #searchEntry {
padding: 4px 12px; padding: 4px 12px;
border-radius: 17px; border-radius: 17px;
font-size: 12pt;
color: rgb(128, 128, 128); color: rgb(128, 128, 128);
border: 2px solid rgba(245,245,245,0.2); border: 2px solid rgba(245,245,245,0.2);
background-gradient-start: rgba(5,5,6,0.1); background-gradient-start: rgba(5,5,6,0.1);
@ -622,11 +566,8 @@ StScrollBar StButton#vhandle:hover
color: #8d8f8a; color: #8d8f8a;
} }
/* View Tabs */
.view-tab-title { .view-tab-title {
color: #888a85; color: #888a85;
font-size: 12pt;
font-weight: bold; font-weight: bold;
padding: 0px 0.75em; padding: 0px 0.75em;
height: 1.5em; height: 1.5em;
@ -642,8 +583,6 @@ StScrollBar StButton#vhandle:hover
border-radius: 0.25em; border-radius: 0.25em;
} }
/* Search Results */
#searchResults { #searchResults {
padding: 20px 10px 10px 10px; padding: 20px 10px 10px 10px;
spacing: 18px; spacing: 18px;
@ -668,6 +607,7 @@ StScrollBar StButton#vhandle:hover
} }
.search-section-results { .search-section-results {
color: #ffffff;
padding: 6px; padding: 6px;
} }
@ -694,27 +634,27 @@ StScrollBar StButton#vhandle:hover
font-weight: bold; font-weight: bold;
} }
.dash-search-button:focus,
.dash-search-button:selected { .dash-search-button:selected {
padding-top: 3px; padding-top: 3px;
padding-bottom: 4px; padding-bottom: 4px;
width: 298px; width: 298px;
} }
.dash-label { .dash-search-button-label {
border-radius: 7px; color: white;
padding: 4px 12px; font-size: 11pt;
background-color: rgba(0,0,0,0.5);
text-align: center;
-x-offset: 8px;
} }
/* Application Launchers and Grid */ /* Apps */
.icon-grid { .icon-grid {
spacing: 36px; spacing: 36px;
-shell-grid-horizontal-item-size: 118px; -shell-grid-item-size: 118px;
-shell-grid-vertical-item-size: 118px; }
.contact-grid {
spacing: 36px;
-shell-grid-item-size: 272px; /* 2 * -shell-grid-item-size + spacing */
} }
.icon-grid .overview-icon { .icon-grid .overview-icon {
@ -732,6 +672,7 @@ StScrollBar StButton#vhandle:hover
} }
.app-filter { .app-filter {
font-size: 10.5pt;
font-weight: bold; font-weight: bold;
height: 2.85em; height: 2.85em;
color: #aaa; color: #aaa;
@ -776,32 +717,12 @@ StScrollBar StButton#vhandle:hover
border-radius: 4px; border-radius: 4px;
padding: 3px; padding: 3px;
border: 1px rgba(0,0,0,0); border: 1px rgba(0,0,0,0);
font-size: 7.5pt;
color: white;
transition-duration: 100; transition-duration: 100;
text-align: center; text-align: center;
} }
.app-well-app.running > .overview-icon {
text-shadow: black 0px 2px 2px;
background-image: url("running-indicator.svg");
background-size: contain;
}
.app-well-app:hover > .overview-icon,
.remove-favorite:hover > .overview-icon,
.search-result-content:hover > .overview-icon {
background-color: rgba(255,255,255,0.1);
text-shadow: black 0px 2px 2px;
transition-duration: 100;
}
/* Contacts */
.contact-grid {
spacing: 36px;
-shell-grid-horizontal-item-size: 272px; /* 2 * -shell-grid-horizontal-item-size + spacing */
-shell-grid-vertical-item-size: 118px;
}
.contact { .contact {
width: 272px; /* Same width as two normal results + spacing */ width: 272px; /* Same width as two normal results + spacing */
height: 118px; /* Aspect ratio = 1.75. Normal US business card ratio */ height: 118px; /* Aspect ratio = 1.75. Normal US business card ratio */
@ -812,12 +733,13 @@ StScrollBar StButton#vhandle:hover
} }
.contact-content { .contact-content {
border-radius: 7px; border-radius: 2px;
padding: 8px; padding: 8px;
width: 232px; width: 232px;
height: 84px; height: 84px;
background-color: rgba(0.0, 0.0, 0.0, 0.5); background-color: white;
color: white; color: black;
text-align: center;
} }
.contact-icon { .contact-icon {
@ -825,16 +747,20 @@ StScrollBar StButton#vhandle:hover
} }
.contact-details { .contact-details {
padding: 0px 6px 22px 10px; padding: 6px 8px 11px 8px;
} }
.contact-details-alias { .contact-details-alias {
font-size: 18px; font-size: 16px;
padding-bottom: 8px; padding-bottom: 11px;
}
.contact-details-status {
font-size: 11pt;
} }
.contact-details-status-icon { .contact-details-status-icon {
padding-right: 4px; padding-right: 2px;
} }
.contact:hover { .contact:hover {
@ -842,15 +768,35 @@ StScrollBar StButton#vhandle:hover
transition-duration: 100; transition-duration: 100;
} }
.contact:focus, .app-well-app.running > .overview-icon {
.app-well-app:focus > .overview-icon, text-shadow: black 0px 2px 2px;
.search-result-content:focus > .overview-icon, background-image: url("running-indicator.svg");
}
.contact:selected, .contact:selected,
.app-well-app:selected > .overview-icon, .app-well-app:selected > .overview-icon,
.search-result-content:selected > .overview-icon { .search-result-content:selected > .overview-icon {
background-color: rgba(255,255,255,0.33); background-color: rgba(255,255,255,0.33);
} }
.app-well-app:hover > .overview-icon,
.remove-favorite:hover > .overview-icon,
.search-result-content:hover > .overview-icon {
background-color: rgba(255,255,255,0.1);
text-shadow: black 0px 2px 2px;
transition-duration: 100;
}
.contact:focus,
.app-well-app:focus > .overview-icon,
.search-result-content:focus > .overview-icon {
border: 1px solid #cccccc;
}
.app-well-menu {
font-size: 9pt;
}
/* LookingGlass */ /* LookingGlass */
#LookingGlassDialog #LookingGlassDialog
@ -860,6 +806,8 @@ StScrollBar StButton#vhandle:hover
padding: 4px; padding: 4px;
border: 2px solid grey; border: 2px solid grey;
border-radius: 4px; border-radius: 4px;
color: #ffffff;
} }
#LookingGlassDialog > #Toolbar #LookingGlassDialog > #Toolbar
@ -899,8 +847,14 @@ StScrollBar StButton#vhandle:hover
padding-bottom: 8px; padding-bottom: 8px;
} }
.lg-dialog StLabel
{
color: #ffffff;
}
.lg-dialog StEntry .lg-dialog StEntry
{ {
color: #ffffff;
selection-background-color: #bbbbbb; selection-background-color: #bbbbbb;
selected-color: #333333; selected-color: #333333;
} }
@ -977,6 +931,7 @@ StScrollBar StButton#vhandle:hover
border: 2px solid grey; border: 2px solid grey;
border-radius: 4px; border-radius: 4px;
padding: 6px; padding: 6px;
color: #ffffff;
} }
/* Calendar popup */ /* Calendar popup */
@ -1055,6 +1010,7 @@ StScrollBar StButton#vhandle:hover
.datemenu-date-label { .datemenu-date-label {
padding: .4em 1.75em; padding: .4em 1.75em;
font-size: 10.5pt;
color: #cccccc; color: #cccccc;
font-weight: bold; font-weight: bold;
} }
@ -1201,9 +1157,10 @@ StScrollBar StButton#vhandle:hover
background-gradient-start: rgba(0,0,0,0.01); background-gradient-start: rgba(0,0,0,0.01);
background-gradient-end: rgba(0,0,0,0.82); background-gradient-end: rgba(0,0,0,0.82);
height: 36px; height: 36px;
color: white;
} }
.notification { #notification {
font-size: 11pt; font-size: 11pt;
border-radius: 10px 10px 0px 0px; border-radius: 10px 10px 0px 0px;
background: rgba(0,0,0,0.8); background: rgba(0,0,0,0.8);
@ -1213,7 +1170,7 @@ StScrollBar StButton#vhandle:hover
width: 34em; width: 34em;
} }
.notification.multi-line-notification { #notification.multi-line-notification {
padding-bottom: 8px; padding-bottom: 8px;
} }
@ -1235,13 +1192,14 @@ StScrollBar StButton#vhandle:hover
color: white; color: white;
} }
.summary-boxpointer .notification { .summary-boxpointer #notification {
border-radius: 9px; border-radius: 9px;
background: rgba(0,0,0,0) !important; background: rgba(0,0,0,0) !important;
padding-bottom: 12px; padding-bottom: 12px;
} }
.summary-boxpointer #summary-right-click-menu { .summary-boxpointer #summary-right-click-menu {
font-size: 10.5pt;
padding-top: 12px; padding-top: 12px;
padding-bottom: 12px; padding-bottom: 12px;
} }
@ -1252,6 +1210,10 @@ StScrollBar StButton#vhandle:hover
padding-bottom: 6px; padding-bottom: 6px;
} }
#summary-notification-stack-scrollview > .top-shadow, #summary-notification-stack-scrollview > .bottom-shadow {
height: 1em;
}
#summary-notification-stack-scrollview:ltr { #summary-notification-stack-scrollview:ltr {
padding-right: 8px; padding-right: 8px;
} }
@ -1260,29 +1222,34 @@ StScrollBar StButton#vhandle:hover
padding-left: 8px; padding-left: 8px;
} }
.notification-scrollview { #notification-scrollview {
max-height: 10em; max-height: 10em;
-st-vfade-offset: 24px; -st-vfade-offset: 24px;
} }
.notification-scrollview:ltr > StScrollBar { #notification-scrollview > .top-shadow, #notification-scrollview > .bottom-shadow {
height: 1em;
}
#notification-scrollview:ltr > StScrollBar {
padding-left: 6px; padding-left: 6px;
} }
.notification-scrollview:rtl > StScrollBar { #notification-scrollview:rtl > StScrollBar {
padding-right: 6px; padding-right: 6px;
} }
.notification-body { #notification-body {
spacing: 5px; spacing: 5px;
} }
.notification-actions { #notification-actions {
spacing: 10px; spacing: 10px;
} }
.notification-button { .notification-button {
border-radius: 18px; border-radius: 18px;
font-size: 11pt;
padding: 4px 42px 5px; padding: 4px 42px 5px;
} }
@ -1312,6 +1279,7 @@ StScrollBar StButton#vhandle:hover
.hotplug-notification-item { .hotplug-notification-item {
padding: 2px 10px; padding: 2px 10px;
border-radius: 18px; border-radius: 18px;
font-size: 10.5pt;
} }
.hotplug-notification-item:focus { .hotplug-notification-item:focus {
@ -1404,7 +1372,7 @@ StScrollBar StButton#vhandle:hover
font-style: italic; font-style: italic;
} }
.notification StEntry { #notification StEntry {
padding: 4px; padding: 4px;
border-radius: 4px; border-radius: 4px;
color: #a8a8a8; color: #a8a8a8;
@ -1420,7 +1388,7 @@ StScrollBar StButton#vhandle:hover
caret-size: 1px; caret-size: 1px;
} }
.notification StEntry:focus { #notification StEntry:focus {
border: 1px solid #8b8b8b; border: 1px solid #8b8b8b;
color: #333333; color: #333333;
background-gradient-direction: vertical; background-gradient-direction: vertical;
@ -1454,6 +1422,7 @@ StScrollBar StButton#vhandle:hover
} }
.summary-source-button { .summary-source-button {
color: #fff;
text-shadow: black 0px 2px 2px; text-shadow: black 0px 2px 2px;
} }
@ -1463,7 +1432,6 @@ StScrollBar StButton#vhandle:hover
.summary-source-button:selected .summary-source { .summary-source-button:selected .summary-source {
background-image: url("panel-button-highlight-narrow.svg"); background-image: url("panel-button-highlight-narrow.svg");
background-size: contain;
border-image: url("source-button-border.svg") 10 10 0 1; border-image: url("source-button-border.svg") 10 10 0 1;
} }
@ -1474,7 +1442,6 @@ StScrollBar StButton#vhandle:hover
.summary-source-button:expanded:selected { .summary-source-button:expanded:selected {
background-image: url("panel-button-highlight-wide.svg"); background-image: url("panel-button-highlight-wide.svg");
background-size: contain;
border-image: url("source-button-border.svg") 10 10 0 1; border-image: url("source-button-border.svg") 10 10 0 1;
} }
@ -1506,6 +1473,8 @@ StScrollBar StButton#vhandle:hover
} }
.source-title { .source-title {
font-size: 9pt;
font-weight: bold;
padding-left: 4px; padding-left: 4px;
} }
@ -1525,6 +1494,9 @@ StScrollBar StButton#vhandle:hover
border: 1px solid rgba(128,128,128,0.40); border: 1px solid rgba(128,128,128,0.40);
border-radius: 24px; border-radius: 24px;
padding: 20px; padding: 20px;
font-size: 9pt;
color: white;
} }
.switcher-list-item-container { .switcher-list-item-container {
@ -1583,7 +1555,6 @@ StScrollBar StButton#vhandle:hover
width: 52px; width: 52px;
height: 52px; height: 52px;
background-image: url("corner-ripple-ltr.png"); background-image: url("corner-ripple-ltr.png");
background-size: contain;
} }
.ripple-box:rtl { .ripple-box:rtl {
@ -1644,20 +1615,12 @@ StScrollBar StButton#vhandle:hover
} }
/* Modal Dialogs */ /* Modal Dialogs */
/* Dialog Subject Text Style */
.show-processes-dialog-subject,
.mount-question-dialog-subject,
.end-session-dialog-subject {
font-size: 14pt;
font-weight: bold;
color: #999999;
}
.modal-dialog { .modal-dialog {
font-size: 12pt;
border-radius: 24px; border-radius: 24px;
background-color: rgba(0.0, 0.0, 0.0, 0.9); background-color: rgba(0.0, 0.0, 0.0, 0.9);
border: 2px solid #868686; border: 2px solid #868686;
color: #babdb6;
padding-right: 42px; padding-right: 42px;
padding-left: 42px; padding-left: 42px;
@ -1667,11 +1630,12 @@ StScrollBar StButton#vhandle:hover
.modal-dialog-button-box { .modal-dialog-button-box {
spacing: 21px; spacing: 21px;
padding-top: 50px;
} }
.modal-dialog-button { .modal-dialog-button {
border-radius: 18px; border-radius: 18px;
font-size: 11pt;
color: white;
margin-left: 10px; margin-left: 10px;
margin-right: 10px; margin-right: 10px;
@ -1687,6 +1651,15 @@ StScrollBar StButton#vhandle:hover
} }
/* Run Dialog */ /* Run Dialog */
.run-dialog-label {
font-size: 9pt;
color: white;
}
.run-dialog-error-label {
font-size: 9pt;
color: white;
}
.run-dialog-error-box { .run-dialog-error-box {
padding-top: 15px; padding-top: 15px;
@ -1694,8 +1667,10 @@ StScrollBar StButton#vhandle:hover
} }
.run-dialog-entry { .run-dialog-entry {
font-size: 10.5pt;
font-weight: bold; font-weight: bold;
width: 23em; width: 23em;
color: white;
selection-background-color: white; selection-background-color: white;
selected-color: black; selected-color: black;
} }
@ -1713,18 +1688,18 @@ StScrollBar StButton#vhandle:hover
background-color: rgba(0, 0, 0, 0.4); background-color: rgba(0, 0, 0, 0.4);
} }
.flashspot {
background-color: white;
}
/* End Session Dialog */ /* End Session Dialog */
.end-session-dialog { .end-session-dialog {
spacing: 42px; spacing: 42px;
} }
.end-session-dialog-subject { .end-session-dialog-subject {
font-size: 12pt;
font-weight: bold;
color: #666666;
padding-top: 10px;
padding-left: 17px; padding-left: 17px;
padding-bottom: 20px; padding-bottom: 30px;
} }
.end-session-dialog-subject:rtl { .end-session-dialog-subject:rtl {
@ -1733,6 +1708,8 @@ StScrollBar StButton#vhandle:hover
} }
.end-session-dialog-description { .end-session-dialog-description {
font-size: 10pt;
color: white;
padding-left: 17px; padding-left: 17px;
width: 28em; width: 28em;
} }
@ -1749,7 +1726,6 @@ StScrollBar StButton#vhandle:hover
} }
.end-session-dialog-shutdown-icon { .end-session-dialog-shutdown-icon {
color: #bebebe;
width: 32px; width: 32px;
height: 32px; height: 32px;
} }
@ -1816,15 +1792,14 @@ StScrollBar StButton#vhandle:hover
.show-processes-dialog-subject, .show-processes-dialog-subject,
.mount-question-dialog-subject { .mount-question-dialog-subject {
font-size: 12pt;
font-weight: bold;
color: #666666;
padding-top: 10px; padding-top: 10px;
padding-left: 17px; padding-left: 17px;
padding-bottom: 6px; padding-bottom: 6px;
} }
.mount-question-dialog-subject {
max-width: 500px;
}
.show-processes-dialog-subject:rtl, .show-processes-dialog-subject:rtl,
.mount-question-dialog-subject:rtl { .mount-question-dialog-subject:rtl {
padding-left: 0px; padding-left: 0px;
@ -1833,6 +1808,8 @@ StScrollBar StButton#vhandle:hover
.show-processes-dialog-description, .show-processes-dialog-description,
.mount-question-dialog-description { .mount-question-dialog-description {
font-size: 10pt;
color: white;
padding-left: 17px; padding-left: 17px;
width: 28em; width: 28em;
} }
@ -1883,75 +1860,32 @@ StScrollBar StButton#vhandle:hover
font-size: 10pt; font-size: 10pt;
} }
/* Password or Authentication Dialog */ /* PolicyKit Authentication Dialog */
.prompt-dialog { .polkit-dialog {
/* this is the width of the entire modal popup */ /* this is the width of the entire modal popup */
width: 500px; width: 500px;
} }
.prompt-dialog-main-layout { .polkit-dialog-main-layout {
spacing: 24px; spacing: 24px;
padding: 10px; padding: 10px;
} }
.prompt-dialog-message-layout { .polkit-dialog-message-layout {
spacing: 16px; spacing: 16px;
} }
.prompt-dialog-headline { .polkit-dialog-headline {
font-size: 12pt; font-size: 12pt;
font-weight: bold; font-weight: bold;
color: #666666; color: #666666;
} }
.prompt-dialog-password-label:ltr { .polkit-dialog-description {
padding-right: 0.5em;
}
.prompt-dialog-password-label:rtl {
padding-left: 0.5em;
}
.prompt-dialog-password-entry {
background-gradient-start: rgb(236,236,236);
background-gradient-end: white;
background-gradient-direction: vertical;
color: black;
selected-color: white;
border-radius: 5px;
border: 2px solid #555753;
}
.prompt-dialog-password-entry:focus {
border: 2px solid #3465a4;
}
.prompt-dialog-password-entry .capslock-warning {
icon-size: 16px;
warning-color: #999;
padding: 0 4px;
}
.prompt-dialog-error-label {
font-size: 10pt; font-size: 10pt;
color: #ffff00; color: white;
padding-bottom: 8px;
} }
.prompt-dialog-info-label {
font-size: 10pt;
padding-bottom: 8px;
}
/* intentionally left transparent to avoid dialog changing size */
.prompt-dialog-null-label {
font-size: 10pt;
color: rgba(0,0,0,0);
padding-bottom: 8px;
}
/* Polkit Dialog */
.polkit-dialog-user-layout { .polkit-dialog-user-layout {
padding-left: 10px; padding-left: 10px;
spacing: 10px; spacing: 10px;
@ -1966,13 +1900,53 @@ StScrollBar StButton#vhandle:hover
color: #ff0000; color: #ff0000;
} }
/* Network Agent Dialog */ .polkit-dialog-password-label:ltr {
padding-right: 0.5em;
.network-dialog-secret-table {
spacing-rows: 15px;
} }
.keyring-dialog-control-table { .polkit-dialog-password-label:rtl {
padding-left: 0.5em;
}
.polkit-dialog-password-entry {
background-gradient-start: rgb(236,236,236);
background-gradient-end: white;
background-gradient-direction: vertical;
color: black;
selected-color: white;
border-radius: 5px;
border: 2px solid #555753;
}
.polkit-dialog-password-entry:focus {
border: 2px solid #3465a4;
}
.polkit-dialog-password-entry .capslock-warning {
icon-size: 16px;
warning-color: #999;
padding: 0 4px;
}
.polkit-dialog-error-label {
font-size: 10pt;
color: #ffff00;
padding-bottom: 8px;
}
.polkit-dialog-info-label {
font-size: 10pt;
padding-bottom: 8px;
}
/* intentionally left transparent to avoid dialog changing size */
.polkit-dialog-null-label {
font-size: 10pt;
color: rgba(0,0,0,0);
padding-bottom: 8px;
}
.network-dialog-secret-table {
spacing-rows: 15px; spacing-rows: 15px;
} }
@ -2040,30 +2014,3 @@ StScrollBar StButton#vhandle:hover
-arrow-rise: 10px; -arrow-rise: 10px;
-boxpointer-gap: 5px; -boxpointer-gap: 5px;
} }
/* Candidate Window */
.candidate-panel {
min-width: 100px;
padding: .5em;
spacing: 0;
}
.candidate-area {
padding-top: 5px;
}
.candidate-label {
cursor: pointer;
}
.candidate-hlabel-content {
padding: 0em .5em 0em 0em;
}
.candidate-htext-content {
padding: 0em;
}
.candidate-vcontent {
padding: 0em .5em 0em 0em;
}

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

@ -18,10 +18,11 @@ DOC_MODULE=shell
# The top-level SGML file. You can change this if you want to. # The top-level SGML file. You can change this if you want to.
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
# Directories containing the source code # Directories containing the source code, relative to $(srcdir).
# gtk-doc will search all .c and .h files beneath these paths # gtk-doc will search all .c and .h files beneath these paths
# for inline comments documenting functions and macros. # for inline comments documenting functions and macros.
DOC_SOURCE_DIR=$(top_srcdir)/src # e.g. DOC_SOURCE_DIR=../../../gtk ../../../gdk
DOC_SOURCE_DIR=../../../src
# Extra options to pass to gtkdoc-scangobj. Not normally needed. # Extra options to pass to gtkdoc-scangobj. Not normally needed.
SCANGOBJ_OPTIONS= SCANGOBJ_OPTIONS=
@ -57,16 +58,7 @@ EXTRA_HFILES=
# Header files or dirs to ignore when scanning. Use base file/dir names # Header files or dirs to ignore when scanning. Use base file/dir names
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
IGNORE_HFILES= \ IGNORE_HFILES=calendar-server gvc hotplug-sniffer st tray
calendar-server \
gvc \
hotplug-sniffer \
st \
tray \
gactionmuxer.h \
gactionobservable.h \
gactionobserver.h \
shell-recorder-src.h
# Images to copy into HTML directory. # Images to copy into HTML directory.
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
@ -87,7 +79,7 @@ expand_content_files=
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) # e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) # e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
GTKDOC_CFLAGS=$(GNOME_SHELL_CFLAGS) GTKDOC_CFLAGS=$(GNOME_SHELL_CFLAGS)
GTKDOC_LIBS=$(GNOME_SHELL_LIBS) $(BLUETOOTH_LIBS) $(top_builddir)/src/libgnome-shell.la GTKDOC_LIBS=$(GNOME_SHELL_LIBS) $(top_builddir)/src/libgnome-shell.la
# This includes the standard gtk-doc make rules, copied by gtkdocize. # This includes the standard gtk-doc make rules, copied by gtkdocize.
include $(top_srcdir)/gtk-doc.make include $(top_srcdir)/gtk-doc.make

View File

@ -18,10 +18,11 @@ DOC_MODULE=st
# The top-level SGML file. You can change this if you want to. # The top-level SGML file. You can change this if you want to.
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
# Directories containing the source code # Directories containing the source code, relative to $(srcdir).
# gtk-doc will search all .c and .h files beneath these paths # gtk-doc will search all .c and .h files beneath these paths
# for inline comments documenting functions and macros. # for inline comments documenting functions and macros.
DOC_SOURCE_DIR=$(top_srcdir)/src/st # e.g. DOC_SOURCE_DIR=../../../gtk ../../../gdk
DOC_SOURCE_DIR=../../../src/st
# Extra options to pass to gtkdoc-scangobj. Not normally needed. # Extra options to pass to gtkdoc-scangobj. Not normally needed.
SCANGOBJ_OPTIONS= SCANGOBJ_OPTIONS=

View File

@ -20,6 +20,7 @@
<title>Abstract classes and Interfaces</title> <title>Abstract classes and Interfaces</title>
<xi:include href="xml/st-widget.xml"/> <xi:include href="xml/st-widget.xml"/>
<xi:include href="xml/st-widget-accessible.xml"/> <xi:include href="xml/st-widget-accessible.xml"/>
<xi:include href="xml/st-container.xml"/>
<xi:include href="xml/st-scrollable.xml"/> <xi:include href="xml/st-scrollable.xml"/>
</chapter> </chapter>
<chapter id="widgets"> <chapter id="widgets">
@ -29,11 +30,14 @@
<xi:include href="xml/st-entry.xml"/> <xi:include href="xml/st-entry.xml"/>
<xi:include href="xml/st-icon.xml"/> <xi:include href="xml/st-icon.xml"/>
<xi:include href="xml/st-label.xml"/> <xi:include href="xml/st-label.xml"/>
<xi:include href="xml/st-tooltip.xml"/>
</chapter> </chapter>
<chapter id="containers"> <chapter id="containers">
<title>Containers</title> <title>Containers</title>
<xi:include href="xml/st-bin.xml"/> <xi:include href="xml/st-bin.xml"/>
<xi:include href="xml/st-box-layout.xml"/> <xi:include href="xml/st-box-layout.xml"/>
<xi:include href="xml/st-group.xml"/>
<xi:include href="xml/st-overflow-box.xml"/>
<xi:include href="xml/st-scroll-view.xml"/> <xi:include href="xml/st-scroll-view.xml"/>
<xi:include href="xml/st-table.xml"/> <xi:include href="xml/st-table.xml"/>
</chapter> </chapter>

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,10 +7,8 @@ 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 \
@ -44,19 +26,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 +56,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 \
@ -84,7 +63,6 @@ nobase_dist_js_DATA = \
ui/shellDBus.js \ ui/shellDBus.js \
ui/statusIconDispatcher.js \ ui/statusIconDispatcher.js \
ui/status/accessibility.js \ ui/status/accessibility.js \
ui/status/candidatePanel.js \
ui/status/keyboard.js \ ui/status/keyboard.js \
ui/status/network.js \ ui/status/network.js \
ui/status/power.js \ ui/status/power.js \
@ -94,7 +72,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

@ -11,17 +11,10 @@ const FprintManagerIface = <interface name='net.reactivated.Fprint.Manager'>
</method> </method>
</interface>; </interface>;
const FprintManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(FprintManagerIface); const FprintManagerProxy = Gio.DBusProxy.makeProxyWrapper(FprintManagerIface);
function FprintManager() { function FprintManager() {
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.system, return new FprintManagerProxy(Gio.DBus.system,
g_interface_name: FprintManagerInfo.name, 'net.reactivated.Fprint',
g_interface_info: FprintManagerInfo, '/net/reactivated/Fprint/Manager');
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);
return self;
}

View File

@ -205,8 +205,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();
} }
@ -488,9 +487,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)
@ -697,7 +693,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 = {};

View File

@ -22,8 +22,6 @@ 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;
@ -33,13 +31,9 @@ const PowerMenuButton = new Lang.Class({
_init: function() { _init: function() {
this.parent('system-shutdown', null); this.parent('system-shutdown', null);
this._consoleKitManager = new ConsoleKit.ConsoleKitManager();
this._upClient = new UPowerGlib.Client(); this._upClient = new UPowerGlib.Client();
if (Systemd.haveSystemd())
this._systemdLoginManager = new Systemd.SystemdLoginManager();
else
this._consoleKitManager = new ConsoleKit.ConsoleKitManager();
this._createSubMenu(); this._createSubMenu();
this._upClient.connect('notify::can-suspend', this._upClient.connect('notify::can-suspend',
@ -60,67 +54,56 @@ const PowerMenuButton = new Lang.Class({
}, },
_updateVisibility: function() { _updateVisibility: function() {
let shouldBeVisible = (this._haveSuspend || this._haveShutdown || this._haveRestart); if (!this._haveSuspend && !this._haveShutdown && !this._haveRestart)
this.actor.visible = shouldBeVisible; this.actor.hide();
else
this.actor.show();
}, },
_updateHaveShutdown: function() { _updateHaveShutdown: function() {
this._consoleKitManager.CanStopRemote(Lang.bind(this,
function(result, error) {
if (!error)
this._haveShutdown = result;
else
this._haveShutdown = false;
if (Systemd.haveSystemd()) { if (this._haveShutdown) {
this._systemdLoginManager.CanPowerOffRemote(Lang.bind(this, this._powerOffItem.actor.show();
function(result, error) { } else {
if (!error) this._powerOffItem.actor.hide();
this._haveShutdown = result != 'no'; }
else
this._haveShutdown = false;
this._powerOffItem.actor.visible = this._haveShutdown; this._updateVisibility();
this._updateVisibility(); }));
}));
} else {
this._consoleKitManager.CanStopRemote(Lang.bind(this,
function(result, error) {
if (!error)
this._haveShutdown = result;
else
this._haveShutdown = false;
this._powerOffItem.actor.visible = this._haveShutdown;
this._updateVisibility();
}));
}
}, },
_updateHaveRestart: function() { _updateHaveRestart: function() {
this._consoleKitManager.CanRestartRemote(Lang.bind(this,
function(result, error) {
if (!error)
this._haveRestart = result;
else
this._haveRestart = false;
if (Systemd.haveSystemd()) { if (this._haveRestart) {
this._systemdLoginManager.CanRebootRemote(Lang.bind(this, this._restartItem.actor.show();
function(result, error) { } else {
if (!error) this._restartItem.actor.hide();
this._haveRestart = result != 'no'; }
else
this._haveRestart = false;
this._restartItem.actor.visible = this._haveRestart; this._updateVisibility();
this._updateVisibility(); }));
}));
} else {
this._consoleKitManager.CanRestartRemote(Lang.bind(this,
function(result, error) {
if (!error)
this._haveRestart = result;
else
this._haveRestart = false;
this._restartItem.actor.visible = this._haveRestart;
this._updateVisibility();
}));
}
}, },
_updateHaveSuspend: function() { _updateHaveSuspend: function() {
this._haveSuspend = this._upClient.get_can_suspend(); this._haveSuspend = this._upClient.get_can_suspend();
this._suspendItem.actor.visible = this._haveSuspend;
if (this._haveSuspend)
this._suspendItem.actor.show();
else
this._suspendItem.actor.hide();
this._updateVisibility(); this._updateVisibility();
}, },
@ -149,22 +132,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@';

136
js/misc/docInfo.js Normal file
View File

@ -0,0 +1,136 @@
// -*- 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;
const DocInfo = new Lang.Class({
Name: 'DocInfo',
_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.
*/
const DocManager = new Lang.Class({
Name: 'DocManager',
_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

@ -38,7 +38,7 @@ function recursivelyDeleteDir(dir) {
let child = dir.get_child(info.get_name()); let child = dir.get_child(info.get_name());
if (type == Gio.FileType.REGULAR) if (type == Gio.FileType.REGULAR)
deleteGFile(child); deleteGFile(child);
else if (type == Gio.FileType.DIRECTORY) else if (type == Gio.TypeType.DIRECTORY)
recursivelyDeleteDir(child); recursivelyDeleteDir(child);
} }

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

@ -31,12 +31,12 @@ function Presence(initCallback, cancellable) {
// change at runtime (changes always come in the form // change at runtime (changes always come in the form
// of new inhibitors) // of new inhibitors)
const InhibitorIface = <interface name="org.gnome.SessionManager.Inhibitor"> const InhibitorIface = <interface name="org.gnome.SessionManager.Inhibitor">
<method name="GetAppId"> <property name="app_id" type="s" access="read" />
<arg type="s" direction="out" /> <property name="client_id" type="s" access="read" />
</method> <property name="reason" type="s" access="read" />
<method name="GetReason"> <property name="flags" type="u" access="read" />
<arg type="s" direction="out" /> <property name="toplevel_xid" type="u" access="read" />
</method> <property name="cookie" type="u" access="read" />
</interface>; </interface>;
var InhibitorProxy = Gio.DBusProxy.makeProxyWrapper(InhibitorIface); var InhibitorProxy = Gio.DBusProxy.makeProxyWrapper(InhibitorIface);

View File

@ -10,7 +10,9 @@ const Signals = imports.signals;
const ModemGsmNetworkInterface = <interface name="org.freedesktop.ModemManager.Modem.Gsm.Network"> const ModemGsmNetworkInterface = <interface name="org.freedesktop.ModemManager.Modem.Gsm.Network">
<method name="GetRegistrationInfo"> <method name="GetRegistrationInfo">
<arg type="(uss)" direction="out" /> <arg type="u" direction="out" />
<arg type="s" direction="out" />
<arg type="s" direction="out" />
</method> </method>
<method name="GetSignalQuality"> <method name="GetSignalQuality">
<arg type="u" direction="out" /> <arg type="u" direction="out" />
@ -33,7 +35,9 @@ const ModemCdmaInterface = <interface name="org.freedesktop.ModemManager.Modem.C
<arg type="u" direction="out" /> <arg type="u" direction="out" />
</method> </method>
<method name="GetServingSystem"> <method name="GetServingSystem">
<arg type="(usu)" direction="out" /> <arg type="u" direction="out" />
<arg type="s" direction="out" />
<arg type="u" direction="out" />
</method> </method>
<signal name="SignalQuality"> <signal name="SignalQuality">
<arg type="u" direction="out" /> <arg type="u" direction="out" />
@ -68,7 +72,7 @@ const ModemGsm = new Lang.Class({
this.operator_name = this._findOperatorName(name, code); this.operator_name = this._findOperatorName(name, code);
this.emit('notify::operator-name'); this.emit('notify::operator-name');
})); }));
this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function([result], err) { this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function(result, err) {
if (err) { if (err) {
log(err); log(err);
return; return;
@ -161,7 +165,7 @@ const ModemCdma = new Lang.Class({
this.signal_quality = 0; this.signal_quality = 0;
this.operator_name = null; this.operator_name = null;
this._proxy.connectSignal('SignalQuality', Lang.bind(this, function(proxy, sender, params) { this._proxy.connect('SignalQuality', Lang.bind(this, function(proxy, sender, params) {
this.signal_quality = params[0]; this.signal_quality = params[0];
this.emit('notify::signal-quality'); this.emit('notify::signal-quality');
@ -183,7 +187,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;

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;
@ -127,7 +125,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 +139,7 @@ const AltTabPopup = new Lang.Class({
let screen = global.screen; let screen = global.screen;
let display = screen.get_display(); let display = screen.get_display();
let windows = display.get_tab_list(Meta.TabList.NORMAL_ALL, screen, let windows = display.get_tab_list(Meta.TabList.NORMAL, screen,
screen.get_active_workspace()); screen.get_active_workspace());
// windows is only the windows on the current workspace. For // windows is only the windows on the current workspace. For
@ -266,7 +264,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 +517,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,8 +537,6 @@ 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);
} }
}); });
@ -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,66 +679,47 @@ 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 () { if (this._highlighted == 0) {
if (this._highlighted == 0) { this._scrollableLeft = false;
this._scrollableLeft = false; this.actor.queue_relayout();
this.actor.queue_relayout(); }
} })
}) });
});
}, },
_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();
time: POPUP_SCROLL_TIME, let parentPadding = this.actor.get_parent().get_theme_node().get_horizontal_padding();
transition: 'easeOutQuad', let x = this._items[this._highlighted].allocation.x2 - monitor.width + padding + parentPadding;
onComplete: Lang.bind(this, function () { Tweener.addTween(this._list, { anchor_x: x,
if (this._highlighted == this._items.length - 1) { time: POPUP_SCROLL_TIME,
this._scrollableRight = false; transition: 'easeOutQuad',
this.actor.queue_relayout(); onComplete: Lang.bind(this, function () {
} if (this._highlighted == this._items.length - 1) {
}) this._scrollableRight = false;
}); this.actor.queue_relayout();
}
})
});
}, },
_itemActivated: function(n) { _itemActivated: function(n) {
@ -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,6 +838,14 @@ 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);
} }
}); });
@ -1023,7 +1025,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,8 +1035,6 @@ 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);
} }
}); });

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;
@ -149,9 +148,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 +214,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 +236,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() {
@ -316,18 +312,13 @@ const AppSearchProvider = new Lang.Class({
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++) { 'name': app.get_name(),
let app = apps[i]; 'createIcon': function(size) {
metas.push({ 'id': app, return app.create_icon_texture(size);
'name': app.get_name(), }
'createIcon': function(size) { };
return app.create_icon_texture(size);
}
});
}
return metas;
}, },
getInitialResultSet: function(terms) { getInitialResultSet: function(terms) {
@ -343,7 +334,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)
@ -378,18 +369,13 @@ const SettingsSearchProvider = new Lang.Class({
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++) { 'name': pref.get_name(),
let pref = prefs[i]; 'createIcon': function(size) {
metas.push({ 'id': pref, return pref.create_icon_texture(size);
'name': pref.get_name(), }
'createIcon': function(size) { };
return pref.create_icon_texture(size);
}
});
}
return metas;
}, },
getInitialResultSet: function(terms) { getInitialResultSet: function(terms) {
@ -484,7 +470,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 +551,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 +568,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);
@ -628,7 +612,7 @@ const AppIconMenu = new Lang.Class({
_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); this.parent(source.actor, 0.5, side);

View File

@ -2,11 +2,9 @@
const Lang = imports.lang; const Lang = imports.lang;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const Params = imports.misc.params; const Params = imports.misc.params;
const Shell = imports.gi.Shell;
const Main = imports.ui.main; const Main = imports.ui.main;
const ShellMountOperation = imports.ui.shellMountOperation; const ShellMountOperation = imports.ui.shellMountOperation;
const ScreenSaver = imports.misc.screenSaver; const ScreenSaver = imports.misc.screenSaver;
@ -45,7 +43,7 @@ function ConsoleKitManager() {
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START | g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) }); Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
self._updateSessionActive = function() { self.connect('notify::g-name-owner', function() {
if (self.g_name_owner) { if (self.g_name_owner) {
self.GetCurrentSessionRemote(function([session]) { self.GetCurrentSessionRemote(function([session]) {
self._ckSession = new ConsoleKitSessionProxy(Gio.DBus.system, 'org.freedesktop.ConsoleKit', session); self._ckSession = new ConsoleKitSessionProxy(Gio.DBus.system, 'org.freedesktop.ConsoleKit', session);
@ -60,19 +58,12 @@ function ConsoleKitManager() {
} else { } else {
self.sessionActive = true; self.sessionActive = true;
} }
}; });
self.connect('notify::g-name-owner',
Lang.bind(self, self._updateSessionActive));
self._updateSessionActive();
self.init(null); self.init(null);
return self; return self;
} }
function haveSystemd() {
return GLib.access("/sys/fs/cgroup/systemd", 0) >= 0;
}
const AutomountManager = new Lang.Class({ const AutomountManager = new Lang.Class({
Name: 'AutomountManager', Name: 'AutomountManager',
@ -80,8 +71,7 @@ const AutomountManager = new Lang.Class({
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.connectSignal('ActiveChanged',
@ -129,22 +119,11 @@ 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)
return; return;
@ -155,8 +134,8 @@ 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)
return; return;
@ -167,7 +146,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 +185,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) {

View File

@ -174,7 +174,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,
@ -339,7 +339,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];
@ -557,7 +557,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);

View File

@ -45,21 +45,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 +75,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 +102,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,

View File

@ -406,7 +406,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();
@ -685,7 +685,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 +702,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);

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;
@ -30,9 +29,7 @@ const Contact = new Lang.Class({
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 +68,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 +93,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 icon = new St.Icon({ icon_name: iconName,
icon_type: St.IconType.FULLCOLOR,
icon_size: 16,
style_class: 'contact-details-status-icon' });
let label = new St.Label({ text: text });
let box = new St.BoxLayout({ vertical: false, let box = new St.BoxLayout({ vertical: false,
style_class: 'contact-details-status' }); style_class: 'contact-details-status' });
box.add(icon, { x_fill: true,
if (iconName) { y_fill: false,
let icon = new St.Icon({ icon_name: iconName, x_align: St.Align.START,
icon_type: St.IconType.FULLCOLOR, y_align: St.Align.START });
icon_size: 16,
style_class: 'contact-details-status-icon' });
box.add(icon, { x_fill: true,
y_fill: false,
x_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,
@ -154,18 +142,14 @@ const ContactSearchProvider = new Lang.Class({
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]); 'name': contact.alias,
metas.push({ 'id': ids[i], 'createIcon': function(size) {
'name': contact.alias, return contact.createIcon(size);
'createIcon': function(size) { }
return contact.createIcon(size); };
}
});
}
return metas;
}, },
getInitialResultSet: function(terms) { getInitialResultSet: function(terms) {

View File

@ -233,7 +233,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;

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,9 +16,6 @@ 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
@ -36,8 +32,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 +84,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);
@ -168,17 +108,7 @@ const DashItemContainer = new Lang.Class({
}); });
}, },
destroy: function() {
if (this.label)
this.label.destroy();
this.actor.destroy();
},
animateOutAndDestroy: function() { animateOutAndDestroy: function() {
if (this.label)
this.label.destroy();
if (this.child == null) { if (this.child == null) {
this.actor.destroy(); this.actor.destroy();
return; return;
@ -308,9 +238,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,
@ -397,7 +324,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) {
@ -445,51 +371,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() {
@ -515,7 +404,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 });
@ -691,8 +580,8 @@ 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++) {
let item = removedActors[i]._delegate; let item = removedActors[i]._delegate;
@ -701,7 +590,7 @@ const Dash = new Lang.Class({
if (Main.overview.visible) if (Main.overview.visible)
item.animateOutAndDestroy(); item.animateOutAndDestroy();
else else
item.destroy(); item.actor.destroy();
} }
this._adjustIconSize(); this._adjustIconSize();
@ -757,10 +646,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) {
this._dragPlaceholderPos = pos; if (this._animatingPlaceholdersCount > 0) {
let appChildren = children.filter(function(actor) {
return actor._delegate &&
actor._delegate.child &&
actor._delegate.child._delegate &&
actor._delegate.child._delegate.app;
});
this._dragPlaceholderPos = children.indexOf(appChildren[pos]);
} else {
this._dragPlaceholderPos = pos;
}
// Don't allow positioning before or after self // Don't allow positioning before or after self
if (favPos != -1 && (pos == favPos || pos == favPos + 1)) { if (favPos != -1 && (pos == favPos || pos == favPos + 1)) {
@ -791,20 +690,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)
@ -847,11 +738,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();

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;
@ -53,15 +52,10 @@ 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); this.parent(menuAlignment);
// At this moment calendar menu is not keyboard navigable at
// all (so not accessible), so it doesn't make sense to set as
// role ATK_ROLE_MENU like other elements of the panel.
this.actor.accessible_role = Atk.Role.LABEL;
this._clock = new St.Label(); this._clock = new St.Label();
this.actor.add_actor(this._clock); this.actor.add_actor(this._clock);
@ -75,7 +69,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);

View File

@ -103,8 +103,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,7 +120,13 @@ const _Draggable = new Lang.Class({
return false; return false;
this._buttonDown = true; this._buttonDown = true;
this._grabActor(); // 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();
let [stageX, stageY] = event.get_coords(); let [stageX, stageY] = event.get_coords();
this._dragStartX = stageX; this._dragStartX = stageX;
@ -129,6 +135,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 +232,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();

44
js/ui/docDisplay.js Normal file
View File

@ -0,0 +1,44 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const DocInfo = imports.misc.docInfo;
const Lang = imports.lang;
const Params = imports.misc.params;
const Search = imports.ui.search;
const DocSearchProvider = new Lang.Class({
Name: 'DocSearchProvider',
Extends: Search.SearchProvider,
_init: function(name) {
this.parent(_("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

@ -116,12 +116,30 @@ 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({ const ListItem = new Lang.Class({
@ -315,8 +333,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();
} }
@ -464,8 +481,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());
@ -484,11 +500,11 @@ const EndSessionDialog = new Lang.Class({
let [type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths] = parameters; let [type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths] = parameters;
this._totalSecondsToStayOpen = totalSecondsToStayOpen; this._totalSecondsToStayOpen = totalSecondsToStayOpen;
this._inhibitors = []; this._inhibitors = [];
this._applicationList.destroy_all_children(); this._applicationList.destroy_children();
this._type = type; this._type = type;
if (!(this._type in DialogContent)) { if (!(this._type in DialogContent)) {
invocation.return_dbus_error('org.gnome.Shell.ModalDialog.TypeError', invocation.report_dbus_error('org.gnome.Shell.ModalDialog.TypeError',
"Unknown dialog type requested"); "Unknown dialog type requested");
return; return;
} }
@ -504,7 +520,7 @@ const EndSessionDialog = new Lang.Class({
this._updateButtons(); this._updateButtons();
if (!this.open(timestamp)) { if (!this.open(timestamp)) {
invocation.return_dbus_error('org.gnome.Shell.ModalDialog.GrabError', invocation.report_dbus_error('org.gnome.Shell.ModalDialog.GrabError',
"Cannot grab pointer and keyboard"); "Cannot grab pointer and keyboard");
return; return;
} }

View File

@ -39,23 +39,20 @@ function _patchContainerClass(containerClass) {
}; };
} }
function _makeLoggingFunc(func) {
return function() {
return func([].join.call(arguments, ', '));
};
}
function init() { function init() {
// Add some bindings to the global JS namespace; (gjs keeps the web // Add some bindings to the global JS namespace; (gjs keeps the web
// browser convention of having that namespace be called 'window'.) // browser convention of having that namespace be called 'window'.)
window.global = Shell.Global.get(); window.global = Shell.Global.get();
window.log = _makeLoggingFunc(window.log);
window._ = Gettext.gettext; window._ = Gettext.gettext;
window.C_ = Gettext.pgettext; window.C_ = Gettext.pgettext;
window.ngettext = Gettext.ngettext; window.ngettext = Gettext.ngettext;
// Set the default direction for St widgets (this needs to be done before any use of St)
if (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL) {
St.Widget.set_default_direction(St.TextDirection.RTL);
}
// Miscellaneous monkeypatching // Miscellaneous monkeypatching
_patchContainerClass(St.BoxLayout); _patchContainerClass(St.BoxLayout);
_patchContainerClass(St.Table); _patchContainerClass(St.Table);
@ -67,14 +64,10 @@ function init() {
let origToString = Object.prototype.toString; let origToString = Object.prototype.toString;
Object.prototype.toString = function() { Object.prototype.toString = function() {
let base = origToString.call(this); let base = origToString.call(this);
try { if ('actor' in this && this.actor instanceof Clutter.Actor)
if ('actor' in this && this.actor instanceof Clutter.Actor) return base.replace(/\]$/, ' delegate for ' + this.actor.toString().substring(1));
return base.replace(/\]$/, ' delegate for ' + this.actor.toString().substring(1)); else
else
return base;
} catch(e) {
return base; 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;
@ -30,6 +29,11 @@ const ExtensionState = {
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,11 +57,20 @@ function _getCertFile() {
_httpSession.ssl_ca_file = _getCertFile(); _httpSession.ssl_ca_file = _getCertFile();
// Arrays of uuids // Maps uuid -> metadata object
var enabledExtensions; const extensionMeta = {};
// Maps uuid -> importer object (extension directory tree)
const extensions = {};
// Maps uuid -> extension state object (returned from init())
const extensionStateObjs = {};
// Contains the order that extensions were enabled in. // Contains the order that extensions were enabled in.
const extensionOrder = []; const extensionOrder = [];
// Arrays of uuids
var enabledExtensions;
// GFile for user extensions
var userExtensionsDir = null;
// We don't really have a class to add signals on. So, create // We don't really have a class to add signals on. So, create
// a simple dummy object, add the signal methods, and export those // a simple dummy object, add the signal methods, and export those
// publically. // publically.
@ -67,8 +80,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 +132,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 +142,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 +178,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,18 +202,20 @@ 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;
let extensionState = extensionStateObjs[uuid];
// "Rebase" the extension order by disabling and then enabling extensions // "Rebase" the extension order by disabling and then enabling extensions
// in order to help prevent conflicts. // in order to help prevent conflicts.
@ -176,14 +231,14 @@ function disableExtension(uuid) {
for (let i = 0; i < orderReversed.length; i++) { for (let i = 0; i < orderReversed.length; i++) {
let uuid = orderReversed[i]; let uuid = orderReversed[i];
try { try {
ExtensionUtils.extensions[uuid].stateObj.disable(); extensionStateObjs[uuid].disable();
} catch(e) { } catch(e) {
logExtensionError(uuid, e.toString()); 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;
@ -192,7 +247,7 @@ function disableExtension(uuid) {
for (let i = 0; i < order.length; i++) { for (let i = 0; i < order.length; i++) {
let uuid = order[i]; let uuid = order[i];
try { try {
ExtensionUtils.extensions[uuid].stateObj.enable(); extensionStateObjs[uuid].enable();
} catch(e) { } catch(e) {
logExtensionError(uuid, e.toString()); logExtensionError(uuid, e.toString());
} }
@ -200,43 +255,41 @@ function disableExtension(uuid) {
extensionOrder.splice(orderIdx, 1); extensionOrder.splice(orderIdx, 1);
extension.state = ExtensionState.DISABLED; meta.state = ExtensionState.DISABLED;
_signals.emit('extension-state-changed', extension); _signals.emit('extension-state-changed', meta);
} }
function enableExtension(uuid) { function enableExtension(uuid) {
let extension = ExtensionUtils.extensions[uuid]; let meta = extensionMeta[uuid];
if (!extension) if (!meta)
return; return;
if (extension.state == ExtensionState.INITIALIZED) if (meta.state == ExtensionState.INITIALIZED) {
initExtension(uuid); loadExtension(meta.dir, meta.type, true);
if (extension.state != ExtensionState.DISABLED)
return; return;
}
if (meta.state != ExtensionState.DISABLED)
return;
let extensionState = extensionStateObjs[uuid];
extensionOrder.push(uuid); extensionOrder.push(uuid);
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,
@ -245,49 +298,75 @@ function logExtensionError(uuid, message, state) {
} }
function loadExtension(dir, type, enabled) { function loadExtension(dir, type, enabled) {
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;
}
extensionMeta[uuid] = meta;
meta.type = type;
meta.dir = dir;
meta.path = dir.get_path();
meta.error = '';
// Default to error, we set success as the last step // Default to error, we set success as the last step
extension.state = ExtensionState.ERROR; meta.state = ExtensionState.ERROR;
if (ExtensionUtils.isOutOfDate(extension)) { if (!versionCheck(meta['shell-version'], Config.PACKAGE_VERSION) ||
(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) { if (!enabled) {
initExtension(uuid); meta.state = ExtensionState.INITIALIZED;
if (extension.state == ExtensionState.DISABLED) return;
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 +388,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 +403,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 +413,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 +424,13 @@ function initExtension(uuid) {
return; return;
} }
extension.state = ExtensionState.DISABLED; meta.state = ExtensionState.DISABLED;
_signals.emit('extension-loaded', uuid); 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,17 +456,50 @@ 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 _loadExtensionsIn(dir, type) {
let fileEnum;
let file, info;
try {
fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
} catch (e) {
global.logError('' + e);
return;
}
while ((info = fileEnum.next_file(null)) != null) {
let fileType = info.get_file_type();
if (fileType != Gio.FileType.DIRECTORY)
continue;
let name = info.get_name();
let child = dir.get_child(name);
let enabled = enabledExtensions.indexOf(name) != -1;
loadExtension(child, type, enabled);
}
fileEnum.close(null);
}
function loadExtensions() { function loadExtensions() {
ExtensionUtils.scanExtensions(function(uuid, dir, type) { let systemDataDirs = GLib.get_system_data_dirs();
let enabled = enabledExtensions.indexOf(uuid) != -1; for (let i = 0; i < systemDataDirs.length; i++) {
loadExtension(dir, type, enabled); 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);
} }
const InstallExtensionDialog = new Lang.Class({ const InstallExtensionDialog = new Lang.Class({
@ -429,11 +545,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,

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

@ -35,8 +35,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 +125,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() {
@ -165,7 +164,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 +183,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 +206,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 +239,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 +269,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 +285,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 +299,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();
}, },

View File

@ -269,11 +269,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));

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;
@ -22,7 +21,7 @@ const LayoutManager = new Lang.Class({
Name: 'LayoutManager', Name: 'LayoutManager',
_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;
@ -405,7 +404,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 +433,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 +456,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 +490,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() {

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;
@ -58,10 +57,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 +70,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,6 +187,8 @@ 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);

View File

@ -15,7 +15,6 @@ 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;
@ -400,14 +399,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 {
@ -634,6 +626,45 @@ const Inspector = new Lang.Class({
Signals.addSignalMethods(Inspector.prototype); Signals.addSignalMethods(Inspector.prototype);
const ErrorLog = new Lang.Class({
Name: 'ErrorLog',
_init: function() {
this.actor = new St.BoxLayout();
this.text = new St.Label();
this.actor.add(this.text);
// We need to override StLabel's default ellipsization when
// using line_wrap; otherwise ClutterText's layout is going
// to constrain both the width and height, which prevents
// scrolling.
this.text.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this.text.clutter_text.line_wrap = true;
this.actor.connect('notify::mapped', Lang.bind(this, this._renderText));
},
_formatTime: function(d){
function pad(n) { return n < 10 ? '0' + n : n; }
return d.getUTCFullYear()+'-'
+ pad(d.getUTCMonth()+1)+'-'
+ pad(d.getUTCDate())+'T'
+ pad(d.getUTCHours())+':'
+ pad(d.getUTCMinutes())+':'
+ pad(d.getUTCSeconds())+'Z';
},
_renderText: function() {
if (!this.actor.mapped)
return;
let text = this.text.text;
let stack = Main._getAndClearErrorStack();
for (let i = 0; i < stack.length; i++) {
let logItem = stack[i];
text += logItem.category + ' t=' + this._formatTime(new Date(logItem.timestamp)) + ' ' + logItem.message + '\n';
}
this.text.text = text;
}
});
const Memory = new Lang.Class({ const Memory = new Lang.Class({
Name: 'Memory', Name: 'Memory',
@ -697,7 +728,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',
@ -705,10 +736,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);
@ -720,31 +751,32 @@ const Extensions = new Lang.Class({
}, },
_onViewSource: function (actor) { _onViewSource: function (actor) {
let extension = actor._extension; let meta = actor._extensionMeta;
let uri = extension.dir.get_uri(); let file = Gio.file_new_for_path(meta.path);
let uri = file.get_uri();
Gio.app_info_launch_default_for_uri(uri, global.create_app_launch_context()); Gio.app_info_launch_default_for_uri(uri, global.create_app_launch_context());
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) { _onViewErrors: function (actor) {
let extension = actor._extension; let meta = actor._extensionMeta;
let shouldShow = !actor._isShowing; let shouldShow = !actor._isShowing;
if (shouldShow) { if (shouldShow) {
let errors = extension.errors; let errors = ExtensionSystem.errors[meta.uuid];
let errorDisplay = new St.BoxLayout({ vertical: true }); let errorDisplay = new St.BoxLayout({ vertical: true });
if (errors && errors.length) { if (errors && errors.length) {
for (let i = 0; i < errors.length; i ++) for (let i = 0; i < errors.length; i ++)
errorDisplay.add(new St.Label({ text: errors[i] })); errorDisplay.add(new St.Label({ text: errors[i] }));
} else { } else {
/* Translators: argument is an extension UUID. */ /* Translators: argument is an extension UUID. */
let message = _("%s has not emitted any errors.").format(extension.uuid); let message = _("%s has not emitted any errors.").format(meta.uuid);
errorDisplay.add(new St.Label({ text: message })); errorDisplay.add(new St.Label({ text: message }));
} }
@ -777,36 +809,36 @@ 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") }); let viewerrors = new Link.Link({ label: _("Show Errors") });
viewerrors.actor._extension = extension; viewerrors.actor._extensionMeta = meta;
viewerrors.actor._parentBox = box; viewerrors.actor._parentBox = box;
viewerrors.actor._isShowing = false; viewerrors.actor._isShowing = false;
viewerrors.actor.connect('clicked', Lang.bind(this, this._onViewErrors)); viewerrors.actor.connect('clicked', Lang.bind(this, this._onViewErrors));
@ -908,6 +940,9 @@ const LookingGlass = new Lang.Class({
})); }));
notebook.appendPage('Windows', this._windowList.actor); notebook.appendPage('Windows', this._windowList.actor);
this._errorLog = new ErrorLog();
notebook.appendPage('Errors', this._errorLog.actor);
this._memory = new Memory(); this._memory = new Memory();
notebook.appendPage('Memory', this._memory.actor); notebook.appendPage('Memory', this._memory.actor);
@ -1003,7 +1038,7 @@ const LookingGlass = new Lang.Class({
actor.add(padBin); actor.add(padBin);
this._completionActor = actor; this._completionActor = actor;
this._evalBox.insert_child_below(this._completionActor, this._entryArea); this._evalBox.insert_before(this._completionActor, this._entryArea);
} }
this._completionText.set_text(completions.join(', ')); this._completionText.set_text(completions.join(', '));
@ -1105,7 +1140,7 @@ const LookingGlass = new Lang.Class({
// Handle key events which are relevant for all tabs of the LookingGlass // Handle key events which are relevant for all tabs of the LookingGlass
_globalKeyPressEvent : function(actor, event) { _globalKeyPressEvent : function(actor, event) {
let symbol = event.get_key_symbol(); let symbol = event.get_key_symbol();
let modifierState = event.get_state(); let modifierState = Shell.get_event_state(event);
if (symbol == Clutter.Escape) { if (symbol == Clutter.Escape) {
if (this._objInspector.actor.visible) { if (this._objInspector.actor.visible) {
this._objInspector.close(); this._objInspector.close();

View File

@ -44,7 +44,7 @@ const Magnifier = new Lang.Class({
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();
@ -556,7 +556,6 @@ const ZoomRegion = new Lang.Class({
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN; this._screenPosition = GDesktopEnums.MagnifierScreenPosition.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 +565,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));
}, },
/** /**
@ -895,15 +891,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 +923,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;
@ -1150,22 +1145,6 @@ 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);
} }
}); });
@ -1196,14 +1175,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();
}, },
/** /**
@ -1228,7 +1199,10 @@ const Crosshairs = new Lang.Class({
crosshairsActor = new Clutter.Clone({ source: this._actor }); crosshairsActor = new Clutter.Clone({ source: this._actor });
this._clones.push(crosshairsActor); this._clones.push(crosshairsActor);
} }
crosshairsActor.visible = this._actor.visible; if (this._actor.visible)
crosshairsActor.show();
else
crosshairsActor.hide();
container.add_actor(crosshairsActor); container.add_actor(crosshairsActor);
container.raise_child(magnifiedMouse, crosshairsActor); container.raise_child(magnifiedMouse, crosshairsActor);

View File

@ -15,7 +15,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 +37,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);
@ -67,11 +65,11 @@ let statusIconDispatcher = null;
let keyboard = null; let keyboard = null;
let layoutManager = null; let layoutManager = null;
let networkAgent = null; let networkAgent = null;
let _errorLogStack = [];
let _startDate; let _startDate;
let _defaultCssStylesheet = null; let _defaultCssStylesheet = null;
let _cssStylesheet = null; let _cssStylesheet = null;
let _gdmCssStylesheet = null; let _gdmCssStylesheet = null;
let _overridesSettings = null;
let background = null; let background = null;
@ -100,24 +98,19 @@ function _createGDMSession() {
function _initRecorder() { function _initRecorder() {
let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' }); let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
let bindingSettings = new Gio.Settings({ schema: 'org.gnome.shell.keybindings' });
global.display.add_keybinding('toggle-recording', global.screen.connect('toggle-recording', function() {
bindingSettings,
Meta.KeyBindingFlags.NONE, function() {
if (recorder == null) { if (recorder == null) {
recorder = new Shell.Recorder({ stage: global.stage }); recorder = new Shell.Recorder({ stage: global.stage });
} }
if (recorder.is_recording()) { if (recorder.is_recording()) {
recorder.close(); recorder.pause();
Meta.enable_unredirect_for_screen(global.screen); Meta.enable_unredirect_for_screen(global.screen);
} else { } 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*$/))
@ -152,9 +145,11 @@ function _initUserSession() {
} }
function start() { function start() {
// These are here so we don't break compatibility. // Monkey patch utility functions into the global proxy;
global.logError = window.log; // This is easier and faster than indirecting down into global
global.log = window.log; // if we want to call back up into JS.
global.logError = _logError;
global.log = _logDebug;
// Chain up async errors reported from C // Chain up async errors reported from C
global.connect('notify-error', function (global, msg, detail) { notifyError(msg, detail); }); global.connect('notify-error', function (global, msg, detail) { notifyError(msg, detail); });
@ -171,11 +166,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 +187,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,13 +228,11 @@ function start() {
// Attempt to become a PolicyKit authentication agent // Attempt to become a PolicyKit authentication agent
PolkitAuthenticationAgent.init() PolkitAuthenticationAgent.init()
// Become a prompter for gnome keyring
KeyringPrompt.init();
_startDate = new Date(); _startDate = new Date();
global.stage.connect('captured-event', _globalKeyPressHandler); global.stage.connect('captured-event', _globalKeyPressHandler);
_log('info', 'loaded at ' + _startDate);
log('GNOME Shell started at ' + _startDate); log('GNOME Shell started at ' + _startDate);
let perfModuleName = GLib.getenv("SHELL_PERF_MODULE"); let perfModuleName = GLib.getenv("SHELL_PERF_MODULE");
@ -260,9 +242,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);
@ -287,30 +266,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];
@ -358,17 +324,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();
@ -377,7 +332,6 @@ function _windowRemoved(workspace, window) {
workspace._lastRemovedWindow = null; workspace._lastRemovedWindow = null;
_queueCheckWorkspaces(); _queueCheckWorkspaces();
} }
return false;
}); });
} }
@ -536,6 +490,59 @@ function notifyError(msg, details) {
notify(msg, details); notify(msg, details);
} }
/**
* _log:
* @category: string message type ('info', 'error')
* @msg: A message string
* ...: Any further arguments are converted into JSON notation,
* and appended to the log message, separated by spaces.
*
* Log a message into the LookingGlass error
* stream. This is primarily intended for use by the
* extension system as well as debugging.
*/
function _log(category, msg) {
let text = msg;
if (arguments.length > 2) {
text += ': ';
for (let i = 2; i < arguments.length; i++) {
text += JSON.stringify(arguments[i]);
if (i < arguments.length - 1)
text += ' ';
}
}
_errorLogStack.push({timestamp: new Date().getTime(),
category: category,
message: text });
}
function _logError(msg) {
return _log('error', msg);
}
function _logDebug(msg) {
return _log('debug', msg);
}
// Used by the error display in lookingGlass.js
function _getAndClearErrorStack() {
let errors = _errorLogStack;
_errorLogStack = [];
return errors;
}
function logStackTrace(msg) {
try {
throw new Error();
} catch (e) {
// e.stack must have at least two lines, with the first being
// logStackTrace() (which we strip off), and the second being
// our caller.
let trace = e.stack.substr(e.stack.indexOf('\n') + 1);
log(msg ? (msg + '\n' + trace) : trace);
}
}
function isWindowActorDisplayedOnWorkspace(win, workspaceIndex) { function isWindowActorDisplayedOnWorkspace(win, workspaceIndex) {
return win.get_workspace() == workspaceIndex || return win.get_workspace() == workspaceIndex ||
(win.get_meta_window() && win.get_meta_window().is_on_all_workspaces()); (win.get_meta_window() && win.get_meta_window().is_on_all_workspaces());
@ -560,8 +567,7 @@ 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);

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;
@ -262,9 +261,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');
}, },
@ -426,7 +423,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,12 +433,12 @@ 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));
this._table = new St.Table({ style_class: 'notification', this._table = new St.Table({ name: 'notification',
reactive: true }); reactive: true });
this._table.connect('style-changed', Lang.bind(this, this._styleChanged)); this._table.connect('style-changed', Lang.bind(this, this._styleChanged));
this.actor.set_child(this._table); this.actor.set_child(this._table);
@ -547,9 +544,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 +554,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 +574,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) {
@ -586,21 +583,19 @@ const Notification = new Lang.Class({
enableScrolling: function(enableScrolling) { enableScrolling: function(enableScrolling) {
this._scrollPolicy = enableScrolling ? Gtk.PolicyType.AUTOMATIC : Gtk.PolicyType.NEVER; this._scrollPolicy = enableScrolling ? Gtk.PolicyType.AUTOMATIC : Gtk.PolicyType.NEVER;
if (this._scrollArea) { if (this._scrollArea)
this._scrollArea.vscrollbar_policy = this._scrollPolicy; this._scrollArea.vscrollbar_policy = this._scrollPolicy;
this._scrollArea.enable_mouse_scrolling = enableScrolling;
}
}, },
_createScrollArea: function() { _createScrollArea: function() {
this._table.add_style_class_name('multi-line-notification'); this._table.add_style_class_name('multi-line-notification');
this._scrollArea = new St.ScrollView({ style_class: '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 });
this._table.add(this._scrollArea, { row: 1, this._table.add(this._scrollArea, { row: 1,
col: 2 }); col: 2 });
this._updateLastColumnSettings(); this._updateLastColumnSettings();
this._contentArea = new St.BoxLayout({ style_class: 'notification-body', this._contentArea = new St.BoxLayout({ name: 'notification-body',
vertical: true }); vertical: true });
this._scrollArea.add_actor(this._contentArea); this._scrollArea.add_actor(this._contentArea);
// If we know the notification will be expandable, we need to add // If we know the notification will be expandable, we need to add
@ -618,7 +613,7 @@ const Notification = new Lang.Class({
} }
this._contentArea.add(actor, style ? style : {}); this._contentArea.add(actor, style ? style : {});
this.updated(); this._updated();
}, },
// addBody: // addBody:
@ -681,7 +676,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() {
@ -736,7 +731,7 @@ const Notification = new Lang.Class({
addButton: function(id, label) { addButton: function(id, label) {
if (!this._buttonBox) { if (!this._buttonBox) {
let box = new St.BoxLayout({ style_class: 'notification-actions' }); let box = new St.BoxLayout({ name: 'notification-actions' });
this.setActionArea(box, { x_expand: false, this.setActionArea(box, { x_expand: false,
y_expand: false, y_expand: false,
x_fill: false, x_fill: false,
@ -762,7 +757,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) {
@ -807,7 +802,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 {
@ -826,7 +821,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;
@ -858,7 +853,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;
})); }));
@ -869,7 +864,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);
}, },
@ -1010,9 +1005,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;
@ -1332,9 +1327,8 @@ 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);
@ -1346,14 +1340,16 @@ const MessageTray = new Lang.Class({
this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) { this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) {
this._onStatusChanged(proxy.status); this._onStatusChanged(proxy.status);
})); }));
this._userStatus = GnomeSession.PresenceStatus.AVAILABLE;
this._busy = false; this._busy = false;
this._backFromAway = false;
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) { this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
this._onStatusChanged(status); this._onStatusChanged(status);
})); }));
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));
this._notificationBin = new St.Bin(); this._notificationBin = new St.Bin();
@ -1392,12 +1388,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
@ -1440,16 +1430,8 @@ const MessageTray = new Lang.Class({
this._notificationRemoved = false; this._notificationRemoved = false;
this._reNotifyAfterHideNotification = null; this._reNotifyAfterHideNotification = null;
this._corner = new Clutter.Rectangle({ width: 1,
height: 1,
opacity: 0,
reactive: true });
this._corner.connect('enter-event', Lang.bind(this, this._onCornerEnter));
Main.layoutManager.trayBox.add_actor(this._corner);
Main.layoutManager.trackChrome(this._corner);
Main.layoutManager.trayBox.add_actor(this.actor); Main.layoutManager.trayBox.add_actor(this.actor);
this.actor.y = this.actor.height; this.actor.y = -1;
Main.layoutManager.trackChrome(this.actor); Main.layoutManager.trackChrome(this.actor);
Main.layoutManager.trackChrome(this._notificationBin); Main.layoutManager.trackChrome(this._notificationBin);
@ -1488,24 +1470,12 @@ const MessageTray = new Lang.Class({
this._chatSummaryItemsCount = 0; this._chatSummaryItemsCount = 0;
}, },
_onCornerEnter: function(actor, event) {
this._pointerInSummary = true;
this._updateState();
},
_setSizePosition: function() { _setSizePosition: function() {
let monitor = Main.layoutManager.bottomMonitor; let monitor = Main.layoutManager.bottomMonitor;
this._notificationBin.x = 0; this._notificationBin.x = 0;
this._notificationBin.width = monitor.width; this._notificationBin.width = monitor.width;
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)
this._corner.x = 0;
else
this._corner.x = Main.layoutManager.trayBox.width - 1;
this._corner.y = Main.layoutManager.trayBox.height - 1;
}, },
contains: function(source) { contains: function(source) {
@ -1529,10 +1499,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();
@ -1641,10 +1611,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;
@ -1928,10 +1894,16 @@ const MessageTray = new Lang.Class({
}, },
_onStatusChanged: function(status) { _onStatusChanged: function(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
@ -1961,7 +1933,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;
@ -1972,7 +1943,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();
}, },
@ -2018,13 +1988,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)
@ -2056,11 +2028,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
@ -2107,38 +2076,14 @@ const MessageTray = new Lang.Class({
_hideTray: function() { _hideTray: function() {
this._tween(this.actor, '_trayState', State.HIDDEN, this._tween(this.actor, '_trayState', State.HIDDEN,
{ y: this.actor.height, { y: -1,
time: ANIMATION_TIME, time: ANIMATION_TIME,
transition: 'easeOutQuad' transition: 'easeOutQuad'
}); });
}, },
_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;
@ -2217,13 +2162,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) {
@ -2307,7 +2245,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,
@ -2322,6 +2259,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,
@ -2336,7 +2275,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,
@ -2344,20 +2282,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',
@ -2439,8 +2370,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();

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;
@ -41,14 +40,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 +87,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 +95,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,11 +105,9 @@ 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'];
@ -135,7 +129,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 +200,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) {

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,16 @@ 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';
const NetworkSecretDialog = new Lang.Class({ const NetworkSecretDialog = new Lang.Class({
Name: 'NetworkSecretDialog', Name: 'NetworkSecretDialog',
Extends: ModalDialog.ModalDialog, Extends: ModalDialog.ModalDialog,
_init: function(agent, requestId, connection, settingName, hints, contentOverride) { _init: function(agent, requestId, connection, settingName, hints) {
this.parent({ styleClass: 'prompt-dialog' }); this.parent({ styleClass: 'polkit-dialog' });
this._agent = agent; this._agent = agent;
this._requestId = requestId; this._requestId = requestId;
@ -50,12 +45,9 @@ const NetworkSecretDialog = new Lang.Class({
this._settingName = settingName; this._settingName = settingName;
this._hints = hints; this._hints = hints;
if (contentOverride) this._content = this._getContent();
this._content = contentOverride;
else
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 +60,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 +93,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 +174,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());
}, },
@ -365,241 +357,6 @@ const NetworkSecretDialog = new Lang.Class({
} }
}); });
const VPNRequestHandler = new Lang.Class({
Name: 'VPNRequestHandler',
_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({ const NetworkAgent = new Lang.Class({
Name: 'NetworkAgent', Name: 'NetworkAgent',
@ -608,18 +365,11 @@ const NetworkAgent = new Lang.Class({
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 +379,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

@ -94,7 +94,7 @@ const NotificationDaemon = new Lang.Class({
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(NotificationDaemonIface, this); this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(NotificationDaemonIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications'); this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
this._sources = []; this._sources = {};
this._senderToPid = {}; this._senderToPid = {};
this._notifications = {}; this._notifications = {};
this._busProxy = new Bus(); this._busProxy = new Bus();
@ -152,30 +152,14 @@ const NotificationDaemon = new Lang.Class({
} }
}, },
_lookupSource: function(title, pid, trayIcon) {
for (let i = 0; i < this._sources.length; i++) {
let source = this._sources[i];
if (source.pid == pid &&
(source.initialTitle == title || source.trayIcon || trayIcon))
return source;
}
return null;
},
// Returns the source associated with ndata.notification if it is set. // Returns the source associated with ndata.notification if it is set.
// Otherwise, returns the source associated with the title and pid if // Otherwise, returns the source associated with the pid if one is
// such source is stored in this._sources and the notification is not // stored in this._sources and the notification is not transient.
// transient. If the existing or requested source is associated with // Otherwise, creates a new source as long as pid is provided.
// a tray icon and passed in pid matches a pid of an existing source,
// the title match is ignored to enable representing a tray icon and
// notifications from the same application with a single source.
//
// If no existing source is found, a new source is created as long as
// pid is provided.
// //
// Either a pid or ndata.notification is needed to retrieve or // Either a pid or ndata.notification is needed to retrieve or
// create a source. // create a source.
_getSource: function(title, pid, ndata, sender, trayIcon) { _getSource: function(title, pid, ndata, sender) {
if (!pid && !(ndata && ndata.notification)) if (!pid && !(ndata && ndata.notification))
return null; return null;
@ -192,24 +176,20 @@ const NotificationDaemon = new Lang.Class({
// with a transient one from the same sender, so we // with a transient one from the same sender, so we
// always create a new source object for new transient notifications // always create a new source object for new transient notifications
// and never add it to this._sources . // and never add it to this._sources .
if (!isForTransientNotification) { if (!isForTransientNotification && this._sources[pid]) {
let source = this._lookupSource(title, pid, trayIcon); let source = this._sources[pid];
if (source) { source.setTitle(title);
source.setTitle(title); return source;
return source;
}
} }
let source = new Source(title, pid, sender, trayIcon); let source = new Source(title, pid, sender);
source.setTransient(isForTransientNotification); source.setTransient(isForTransientNotification);
if (!isForTransientNotification) { if (!isForTransientNotification) {
this._sources.push(source); this._sources[pid] = source;
source.connect('destroy', Lang.bind(this, source.connect('destroy', Lang.bind(this,
function() { function() {
let index = this._sources.indexOf(source); delete this._sources[pid];
if (index >= 0)
this._sources.splice(index, 1);
})); }));
} }
@ -288,7 +268,7 @@ const NotificationDaemon = new Lang.Class({
let sender = invocation.get_sender(); let sender = invocation.get_sender();
let pid = this._senderToPid[sender]; let pid = this._senderToPid[sender];
let source = this._getSource(appName, pid, ndata, sender, null); let source = this._getSource(appName, pid, ndata, sender);
if (source) { if (source) {
this._notifyForSource(source, ndata); this._notifyForSource(source, ndata);
@ -314,7 +294,7 @@ const NotificationDaemon = new Lang.Class({
} }
let [pid] = result; let [pid] = result;
source = this._getSource(appName, pid, ndata, sender, null); source = this._getSource(appName, pid, ndata, sender);
// We only store sender-pid entries for persistent sources. // We only store sender-pid entries for persistent sources.
// Removing the entries once the source is destroyed // Removing the entries once the source is destroyed
@ -463,8 +443,8 @@ const NotificationDaemon = new Lang.Class({
if (!tracker.focus_app) if (!tracker.focus_app)
return; return;
for (let i = 0; i < this._sources.length; i++) { for (let id in this._sources) {
let source = this._sources[i]; let source = this._sources[id];
if (source.app == tracker.focus_app) { if (source.app == tracker.focus_app) {
source.destroyNonResidentNotifications(); source.destroyNonResidentNotifications();
return; return;
@ -483,11 +463,12 @@ const NotificationDaemon = new Lang.Class({
}, },
_onTrayIconAdded: function(o, icon) { _onTrayIconAdded: function(o, icon) {
let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null, null, icon); let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null, null);
source.setTrayIcon(icon);
}, },
_onTrayIconRemoved: function(o, icon) { _onTrayIconRemoved: function(o, icon) {
let source = this._lookupSource(null, icon.pid, true); let source = this._sources[icon.pid];
if (source) if (source)
source.destroy(); source.destroy();
} }
@ -497,12 +478,10 @@ const Source = new Lang.Class({
Name: 'NotificationDaemonSource', Name: 'NotificationDaemonSource',
Extends: MessageTray.Source, Extends: MessageTray.Source,
_init: function(title, pid, sender, trayIcon) { _init: function(title, pid, sender) {
this.parent(title); this.parent(title);
this.initialTitle = title; this._pid = pid;
this.pid = pid;
if (sender) if (sender)
this._nameWatcherId = Gio.DBus.session.watch_name(sender, this._nameWatcherId = Gio.DBus.session.watch_name(sender,
Gio.BusNameWatcherFlags.NONE, Gio.BusNameWatcherFlags.NONE,
@ -516,12 +495,7 @@ const Source = new Lang.Class({
this.title = this.app.get_name(); this.title = this.app.get_name();
else else
this.useNotificationIcon = true; this.useNotificationIcon = true;
this._trayIcon = null;
this.trayIcon = trayIcon;
if (this.trayIcon) {
this._setSummaryIcon(this.trayIcon);
this.useNotificationIcon = false;
}
}, },
_onNameVanished: function() { _onNameVanished: function() {
@ -548,7 +522,7 @@ const Source = new Lang.Class({
}, },
handleSummaryClick: function() { handleSummaryClick: function() {
if (!this.trayIcon) if (!this._trayIcon)
return false; return false;
let event = Clutter.get_current_event(); let event = Clutter.get_current_event();
@ -569,54 +543,44 @@ const Source = new Lang.Class({
let id = global.connect('notify::stage-input-mode', Lang.bind(this, let id = global.connect('notify::stage-input-mode', Lang.bind(this,
function () { function () {
global.disconnect(id); global.disconnect(id);
this.trayIcon.click(event); this._trayIcon.click(event);
})); }));
Main.overview.hide(); Main.overview.hide();
} else { } else {
this.trayIcon.click(event); this._trayIcon.click(event);
} }
return true; return true;
}, },
_getApp: function() {
let app;
app = Shell.WindowTracker.get_default().get_app_from_pid(this.pid);
if (app != null)
return app;
if (this.trayIcon) {
app = Shell.AppSystem.get_default().lookup_wmclass(this.trayIcon.wmclass);
if (app != null)
return app;
}
return null;
},
_setApp: function() { _setApp: function() {
if (this.app) if (this.app)
return; return;
this.app = this._getApp(); this.app = Shell.WindowTracker.get_default().get_app_from_pid(this._pid);
if (!this.app) if (!this.app)
return; return;
// Only override the icon if we were previously using // Only override the icon if we were previously using
// notification-based icons (ie, not a trayicon) or if it was unset before // notification-based icons (ie, not a trayicon) or if it was unset before
if (!this.trayIcon) { if (!this._trayIcon) {
this.useNotificationIcon = false; this.useNotificationIcon = false;
this._setSummaryIcon(this.app.create_icon_texture (this.ICON_SIZE)); this._setSummaryIcon(this.app.create_icon_texture (this.ICON_SIZE));
} }
}, },
setTrayIcon: function(icon) {
this._setSummaryIcon(icon);
this.useNotificationIcon = false;
this._trayIcon = icon;
},
open: function(notification) { open: function(notification) {
this.destroyNonResidentNotifications(); this.destroyNonResidentNotifications();
this.openApp(); this.openApp();
}, },
_lastNotificationRemoved: function() { _lastNotificationRemoved: function() {
if (!this.trayIcon) if (!this._trayIcon)
this.destroy(); this.destroy();
}, },

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;
@ -109,6 +108,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,11 +126,8 @@ 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. */ reactive: true });
this._group = new St.Widget({ name: 'overview',
accessible_name: _("Overview"),
reactive: true });
this._group._delegate = this; this._group._delegate = this;
this._group.connect('style-changed', this._group.connect('style-changed',
Lang.bind(this, function() { Lang.bind(this, function() {
@ -183,6 +180,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 +204,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 +355,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 +447,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 +488,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 +587,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 +728,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 +737,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 +779,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();

View File

@ -4,19 +4,15 @@ 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 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;
@ -37,7 +33,7 @@ const STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION = {
'a11y': imports.ui.status.accessibility.ATIndicator, 'a11y': imports.ui.status.accessibility.ATIndicator,
'volume': imports.ui.status.volume.Indicator, 'volume': imports.ui.status.volume.Indicator,
'battery': imports.ui.status.power.Indicator, 'battery': imports.ui.status.power.Indicator,
'keyboard': imports.ui.status.keyboard.InputSourceIndicator, 'keyboard': imports.ui.status.keyboard.XKBIndicator,
'userMenu': imports.ui.userMenu.UserMenuButton 'userMenu': imports.ui.userMenu.UserMenuButton
}; };
@ -55,7 +51,7 @@ const GDM_STATUS_AREA_SHELL_IMPLEMENTATION = {
'a11y': imports.ui.status.accessibility.ATIndicator, 'a11y': imports.ui.status.accessibility.ATIndicator,
'volume': imports.ui.status.volume.Indicator, 'volume': imports.ui.status.volume.Indicator,
'battery': imports.ui.status.power.Indicator, 'battery': imports.ui.status.power.Indicator,
'keyboard': imports.ui.status.keyboard.InputSourceIndicator, 'keyboard': imports.ui.status.keyboard.XKBIndicator,
'powerMenu': imports.gdm.powerMenu.PowerMenuButton 'powerMenu': imports.gdm.powerMenu.PowerMenuButton
}; };
@ -109,47 +105,38 @@ const AnimatedIcon = new Lang.Class({
_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);
} }
}); });
@ -250,9 +237,7 @@ const AppMenuButton = new Lang.Class({
Extends: PanelMenu.Button, Extends: PanelMenu.Button,
_init: function(menuManager) { _init: function(menuManager) {
this.parent(0.0, null, true); this.parent(0.0, true);
this.actor.accessible_role = Atk.Role.MENU;
this._startingApps = []; this._startingApps = [];
@ -264,7 +249,6 @@ const AppMenuButton = new Lang.Class({
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;
@ -304,7 +288,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 +302,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 +401,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 +423,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 +432,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;
@ -480,9 +463,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 +480,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 +497,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;
@ -552,16 +528,12 @@ const AppMenuButton = new Lang.Class({
if (targetApp) { if (targetApp) {
this._appMenuNotifyId = targetApp.connect('notify::menu', Lang.bind(this, this._sync)); this._appMenuNotifyId = targetApp.connect('notify::menu', Lang.bind(this, this._sync));
this._actionGroupNotifyId = targetApp.connect('notify::action-group', 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());
this._iconBox.set_child(icon); this._iconBox.set_child(icon);
this._iconBox.show(); this._iconBox.show();
@ -577,7 +549,7 @@ const AppMenuButton = new Lang.Class({
_maybeSetMenu: function() { _maybeSetMenu: function() {
let menu; let menu;
if (this._targetApp.action_group && this._targetApp.menu) { if (this._targetApp.action_group) {
if (this.menu instanceof PopupMenu.RemoteMenu && if (this.menu instanceof PopupMenu.RemoteMenu &&
this.menu.actionGroup == this._targetApp.action_group) this.menu.actionGroup == this._targetApp.action_group)
return; return;
@ -610,7 +582,6 @@ const ActivitiesButton = new Lang.Class({
_init: function() { _init: function() {
this.parent(0.0); this.parent(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 +595,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 +610,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 +635,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 +652,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() {
@ -822,7 +787,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 +833,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 +846,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,10 +893,10 @@ 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);
} }
}); });
@ -943,14 +927,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 +943,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) {
@ -1027,7 +1010,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 +1029,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 +1057,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 +1077,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;
}, },

View File

@ -6,7 +6,6 @@ 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;
@ -97,11 +96,10 @@ const Button = new Lang.Class({
Name: 'PanelMenuButton', Name: 'PanelMenuButton',
Extends: ButtonBox, Extends: ButtonBox,
_init: function(menuAlignment, nameText, dontCreateMenu) { _init: function(menuAlignment, dontCreateMenu) {
this.parent({ reactive: true, this.parent({ 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));
@ -110,24 +108,6 @@ const Button = new Lang.Class({
this.menu = null; this.menu = null;
else else
this.setMenu(new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP, 0)); 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) { setMenu: function(menu) {
@ -149,6 +129,15 @@ const Button = new Lang.Class({
if (!this.menu) if (!this.menu)
return; return;
if (!this.menu.isOpen) {
// 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();
}, },
@ -191,14 +180,6 @@ const Button = new Lang.Class({
this.actor.add_style_pseudo_class('active'); this.actor.add_style_pseudo_class('active');
else else
this.actor.remove_style_pseudo_class('active'); this.actor.remove_style_pseudo_class('active');
// Setting the max-height won't do any good if the minimum height of the
// menu is higher then the screen; it's useful if part of the menu is
// scrollable so the minimum height is smaller than the natural height
let monitor = Main.layoutManager.primaryMonitor;
this.menu.actor.style = ('max-height: ' +
Math.round(monitor.height - Main.panel.actor.height) +
'px;');
}, },
destroy: function() { destroy: function() {
@ -216,20 +197,21 @@ Signals.addSignalMethods(Button.prototype);
* *
* 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({ const SystemStatusButton = new Lang.Class({
Name: 'SystemStatusButton', Name: 'SystemStatusButton',
Extends: Button, Extends: Button,
_init: function(iconName, nameText) { _init: function(iconName,tooltipText) {
this.parent(0.0, nameText); this.parent(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 +220,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

@ -155,12 +155,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
@ -367,21 +364,16 @@ const PlaceSearchProvider = new Lang.Class({
this.parent(_("PLACES & DEVICES")); this.parent(_("PLACES & DEVICES"));
}, },
getResultMetas: function(resultIds) { getResultMeta: function(resultId) {
let metas = []; let placeInfo = Main.placesManager.lookupPlaceById(resultId);
for (let i = 0; i < resultIds.length; i++) { if (!placeInfo)
let placeInfo = Main.placesManager.lookupPlaceById(resultIds[i]); return null;
if (!placeInfo) return { 'id': resultId,
metas.push(null); 'name': placeInfo.name,
else 'createIcon': function(size) {
metas.push({ 'id': resultIds[i], return placeInfo.iconFactory(size);
'name': placeInfo.name, }
'createIcon': function(size) { };
return placeInfo.iconFactory(size);
}
});
}
return metas;
}, },
activateResult: function(id, params) { activateResult: function(id, params) {

View File

@ -41,7 +41,7 @@ const AuthenticationDialog = new Lang.Class({
Extends: ModalDialog.ModalDialog, Extends: ModalDialog.ModalDialog,
_init: function(actionId, message, cookie, userNames) { _init: function(actionId, message, cookie, userNames) {
this.parent({ styleClass: 'prompt-dialog' }); this.parent({ styleClass: 'polkit-dialog' });
this.actionId = actionId; this.actionId = actionId;
this.message = message; this.message = message;
@ -49,7 +49,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 +62,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;
@ -137,9 +137,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 +149,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 +165,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;
@ -393,7 +393,6 @@ 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);

View File

@ -9,7 +9,6 @@ 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;
@ -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));
@ -275,7 +273,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 +283,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 +296,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 +311,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 +323,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 +333,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,7 +371,7 @@ 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;
@ -391,7 +389,6 @@ const PopupMenuItem = new Lang.Class({
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
} }
}); });
@ -446,7 +443,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));
}, },
@ -546,10 +542,6 @@ const PopupSliderMenuItem = new Lang.Class({
this._slider.connect('repaint', Lang.bind(this, this._sliderRepaint)); this._slider.connect('repaint', Lang.bind(this, this._sliderRepaint));
this.actor.connect('button-press-event', Lang.bind(this, this._startDragging)); this.actor.connect('button-press-event', Lang.bind(this, this._startDragging));
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent)); this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
this.actor.connect('notify::mapped', Lang.bind(this, function() {
if (!this.actor.mapped)
this._endDragging();
}));
this._releaseId = this._motionId = 0; this._releaseId = this._motionId = 0;
this._dragging = false; this._dragging = false;
@ -718,8 +710,7 @@ const Switch = new Lang.Class({
Name: 'Switch', Name: 'Switch',
_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
@ -752,10 +743,6 @@ const PopupSwitchMenuItem = new Lang.Class({
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 });
@ -774,14 +761,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) {
@ -789,19 +773,12 @@ const PopupSwitchMenuItem = new Lang.Class({
this.toggle(); this.toggle();
} }
// we allow pressing space to toggle the switch
// without closing the menu
if (event.type() == Clutter.EventType.KEY_PRESS &&
event.get_key_symbol() == Clutter.KEY_space)
return;
this.parent(event); 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() {
@ -810,20 +787,6 @@ 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);
}
} }
}); });
@ -906,10 +869,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;
}, },
@ -980,12 +939,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);
@ -1040,12 +994,10 @@ 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', menuItem._closingId = this.connect('open-state-changed',
@ -1063,7 +1015,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) {
@ -1237,9 +1189,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);
@ -1331,9 +1280,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();
@ -1447,23 +1393,12 @@ const PopupMenuSection = new Lang.Class({
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(), but emit the
// corresponding signal so children can still pick it up // corresponding signal so children can still pick it up
open: function(animate) { this.emit('open-state-changed', true); }, open: function(animate) { this.emit('open-state-changed', true); },
close: function() { this.emit('open-state-changed', false); }, close: function() { this.emit('open-state-changed', false); },
destroy: function() {
for (let i = 0; i < this.separators.length; i++)
this.separators[i].destroy();
this.separators = [];
this.parent();
}
}); });
const PopupSubMenuMenuItem = new Lang.Class({ const PopupSubMenuMenuItem = new Lang.Class({
@ -1477,7 +1412,6 @@ const PopupSubMenuMenuItem = new Lang.Class({
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 });
@ -1578,9 +1512,6 @@ const PopupComboMenu = new Lang.Class({
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();
@ -1624,10 +1555,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.');
@ -1649,8 +1576,6 @@ const PopupComboBoxMenuItem = new Lang.Class({
_init: function (params) { _init: function (params) {
this.parent(params); this.parent(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);
@ -1747,11 +1672,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)
@ -1762,8 +1682,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) {
@ -1814,25 +1732,17 @@ const RemoteMenu = new Lang.Class({
}, },
_createMenuItem: function(model, index) { _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); let section_link = model.get_item_link(index, Gio.MENU_LINK_SECTION);
if (section_link) { if (section_link) {
let item = new PopupMenuSection(); 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); this._modelChanged(section_link, 0, 0, section_link.get_n_items(), item);
return [item, true, '']; return [item, true, ''];
} }
// labels are not checked for existance, as they're required for all items
let label = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_LABEL, null).deep_unpack();
// remove all underscores that are not followed by another underscore
label = label.replace(/_([^_])/, '$1');
let submenu_link = model.get_item_link(index, Gio.MENU_LINK_SUBMENU); let submenu_link = model.get_item_link(index, Gio.MENU_LINK_SUBMENU);
if (submenu_link) { if (submenu_link) {
@ -1916,13 +1826,8 @@ const RemoteMenu = new Lang.Class({
let currentItems = target._getMenuItems(); let currentItems = target._getMenuItems();
k0 = 0; for (j0 = 0, k0 = 0; j0 < position; j0++, k0++) {
// skip ignored items at the beginning if (currentItems[k0] instanceof PopupSeparatorMenuItem)
while (k0 < currentItems.length && currentItems[k0]._ignored)
k0++;
// find the right menu item matching the model item
for (j0 = 0; j0 < position; j0++, k0++) {
if (currentItems[k0]._ignored)
k0++; k0++;
} }
@ -1934,7 +1839,7 @@ const RemoteMenu = new Lang.Class({
for (j = j0, k = k0; j < j0 + removed; j++, k++) { for (j = j0, k = k0; j < j0 + removed; j++, k++) {
currentItems[k].destroy(); currentItems[k].destroy();
if (currentItems[k]._ignored) if (currentItems[k] instanceof PopupSeparatorMenuItem)
j--; j--;
} }
} }
@ -1945,20 +1850,14 @@ const RemoteMenu = new Lang.Class({
if (item) { if (item) {
// separators must be added in the parent to make autohiding work // separators must be added in the parent to make autohiding work
if (addSeparator) { if (addSeparator) {
let separator = new PopupSeparatorMenuItem(); target.addMenuItem(new PopupSeparatorMenuItem(), k+1);
item.separators.push(separator);
separator._ignored = true;
target.addMenuItem(separator, k+1);
k++; k++;
} }
target.addMenuItem(item, k); target.addMenuItem(item, k);
if (addSeparator) { if (addSeparator) {
let separator = new PopupSeparatorMenuItem(); target.addMenuItem(new PopupSeparatorMenuItem(), k+1);
item.separators.push(separator);
separator._ignored = true;
target.addMenuItem(separator, k+1);
k++; k++;
} }
} else if (changeSignal) { } else if (changeSignal) {
@ -1984,10 +1883,7 @@ const RemoteMenu = new Lang.Class({
} }
if (target instanceof PopupMenuSection) { if (target instanceof PopupMenuSection) {
if (target._titleMenuItem) target.actor.visible = target.numMenuItems != 0;
target.actor.visible = target.numMenuItems != 1;
else
target.actor.visible = target.numMenuItems != 0;
} else { } else {
let sourceItem = target.sourceActor._delegate; let sourceItem = target.sourceActor._delegate;
if (sourceItem instanceof PopupSubMenuMenuItem) if (sourceItem instanceof PopupSubMenuMenuItem)

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

@ -209,8 +209,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 +242,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);

View File

@ -29,6 +29,7 @@ const SearchResultDisplay = new Lang.Class({
_init: function(provider) { _init: function(provider) {
this.provider = provider; this.provider = provider;
this.actor = null; this.actor = null;
this.selectionIndex = -1;
}, },
/** /**
@ -50,10 +51,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,6 +75,25 @@ 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');
}
}); });
/** /**
@ -72,11 +102,6 @@ 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({ const SearchProvider = new Lang.Class({
Name: 'SearchProvider', Name: 'SearchProvider',
@ -84,7 +109,42 @@ const SearchProvider = new Lang.Class({
_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 +172,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 +190,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');
}, },
@ -280,7 +302,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 +319,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;
@ -347,13 +369,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 +400,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) { let providerResults = provider.getSubsearchResultSet(previousResults, terms);
provider.getSubsearchResultSetAsync(previousResults, terms); results.push([provider, providerResults]);
results.push([provider, []]);
} else {
let providerResults = provider.getSubsearchResultSet(previousResults, terms);
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 +411,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) { let providerResults = provider.getInitialResultSet(terms);
provider.getInitialResultSetAsync(terms); results.push([provider, providerResults]);
results.push([provider, []]);
} else {
let providerResults = provider.getInitialResultSet(terms);
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);
} }

View File

@ -32,7 +32,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'] });
@ -111,66 +110,70 @@ const GridSearchResults = new Lang.Class({
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;
},
activateSelected: function() {
if (this.selectionIndex < 0)
return;
let targetActor = this._grid.getItemAtIndex(this.selectionIndex);
targetActor._delegate.activate();
} }
}); });
@ -212,6 +215,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 +229,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 +240,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 +267,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 +289,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 +305,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 +314,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 +324,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,80 +342,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); meta.actor.show();
}, meta.resultDisplay.renderResults(results, terms);
return true;
_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();
// Hinding drops the key focus if we have it
let focus = global.stage.get_key_focus();
this._content.hide();
meta.resultDisplay.renderResults(metas);
this._maybeSetInitialSelection();
this._content.show();
if (this._content.contains(focus))
global.stage.set_key_focus(focus);
}));
} 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) {
@ -422,57 +356,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];
let meta = this._metaForProvider(provider); if (providerResults.length == 0) {
meta.hasPendingResults = provider.async; this._clearDisplayForProvider(i);
if (!meta.hasPendingResults) } else {
this._updateProviderResults(provider, providerResults, terms); this._providerMetaResults[provider.title] = providerResults;
this._clearDisplayForProvider(i);
let meta = this._metaForProvider(provider);
meta.actor.show();
meta.resultDisplay.renderResults(providerResults, terms);
}
} }
if (this._selectedOpenSearchButton == -1)
this.selectDown(false);
this._content.show(); this._content.show();
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

@ -3,12 +3,9 @@
const Lang = imports.lang; const Lang = imports.lang;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib; const GLib = imports.gi.GLib;
const Shell = imports.gi.Shell;
const Config = imports.misc.config; const Config = imports.misc.config;
const ExtensionSystem = imports.ui.extensionSystem; const ExtensionSystem = imports.ui.extensionSystem;
const ExtensionUtils = imports.misc.extensionUtils;
const Flashspot = imports.ui.flashspot;
const Main = imports.ui.main; const Main = imports.ui.main;
const GnomeShellIface = <interface name="org.gnome.Shell"> const GnomeShellIface = <interface name="org.gnome.Shell">
@ -33,29 +30,18 @@ const GnomeShellIface = <interface name="org.gnome.Shell">
<arg type="i" direction="in" name="y"/> <arg type="i" direction="in" name="y"/>
<arg type="i" direction="in" name="width"/> <arg type="i" direction="in" name="width"/>
<arg type="i" direction="in" name="height"/> <arg type="i" direction="in" name="height"/>
<arg type="b" direction="in" name="flash"/>
<arg type="s" direction="in" name="filename"/> <arg type="s" direction="in" name="filename"/>
<arg type="b" direction="out" name="success"/> <arg type="b" direction="out" name="success"/>
</method> </method>
<method name="ScreenshotWindow"> <method name="ScreenshotWindow">
<arg type="b" direction="in" name="include_frame"/> <arg type="b" direction="in" name="include_frame"/>
<arg type="b" direction="in" name="include_cursor"/>
<arg type="b" direction="in" name="flash"/>
<arg type="s" direction="in" name="filename"/> <arg type="s" direction="in" name="filename"/>
<arg type="b" direction="out" name="success"/> <arg type="b" direction="out" name="success"/>
</method> </method>
<method name="Screenshot"> <method name="Screenshot">
<arg type="b" direction="in" name="include_cursor"/>
<arg type="b" direction="in" name="flash"/>
<arg type="s" direction="in" name="filename"/> <arg type="s" direction="in" name="filename"/>
<arg type="b" direction="out" name="success"/> <arg type="b" direction="out" name="success"/>
</method> </method>
<method name="FlashArea">
<arg type="i" direction="in" name="x"/>
<arg type="i" direction="in" name="y"/>
<arg type="i" direction="in" name="width"/>
<arg type="i" direction="in" name="height"/>
</method>
<method name="EnableExtension"> <method name="EnableExtension">
<arg type="s" direction="in" name="uuid"/> <arg type="s" direction="in" name="uuid"/>
</method> </method>
@ -70,9 +56,6 @@ const GnomeShellIface = <interface name="org.gnome.Shell">
<arg type="s" direction="in" name="uuid"/> <arg type="s" direction="in" name="uuid"/>
<arg type="b" direction="out" name="success"/> <arg type="b" direction="out" name="success"/>
</method> </method>
<method name="LaunchExtensionPrefs">
<arg type="s" direction="in" name="uuid"/>
</method>
<property name="OverviewActive" type="b" access="readwrite" /> <property name="OverviewActive" type="b" access="readwrite" />
<property name="ApiVersion" type="i" access="read" /> <property name="ApiVersion" type="i" access="read" />
<property name="ShellVersion" type="s" access="read" /> <property name="ShellVersion" type="s" access="read" />
@ -126,23 +109,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 +122,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,41 +136,26 @@ 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 = {}; let out = {};
for (let uuid in ExtensionUtils.extensions) { for (let uuid in ExtensionSystem.extensionMeta) {
let dbusObj = this.GetExtensionInfo(uuid); let dbusObj = this.GetExtensionInfo(uuid);
out[uuid] = dbusObj; out[uuid] = dbusObj;
} }
@ -212,23 +163,10 @@ const GnomeShell = new Lang.Class({
}, },
GetExtensionInfo: function(uuid) { GetExtensionInfo: function(uuid) {
let extension = ExtensionUtils.extensions[uuid]; let meta = 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 = {}; let out = {};
for (let key in obj) { for (let key in meta) {
let val = obj[key]; let val = meta[key];
let type; let type;
switch (typeof val) { switch (typeof val) {
case 'string': case 'string':
@ -237,27 +175,16 @@ const GnomeShell = new Lang.Class({
case 'number': case 'number':
type = 'd'; type = 'd';
break; break;
case 'boolean':
type = 'b';
break;
default: default:
continue; continue;
} }
out[key] = GLib.Variant.new(type, val); out[key] = GLib.Variant.new(type, val);
} }
return out; 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 +209,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;
}, },

View File

@ -211,8 +211,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,
@ -359,7 +357,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();

View File

@ -44,7 +44,7 @@ const ATIndicator = new Lang.Class({
Extends: PanelMenu.SystemStatusButton, Extends: PanelMenu.SystemStatusButton,
_init: function() { _init: function() {
this.parent('preferences-desktop-accessibility', _("Accessibility")); this.parent('preferences-desktop-accessibility', null);
let highContrast = this._buildHCItem(); let highContrast = this._buildHCItem();
this.menu.addMenuItem(highContrast); this.menu.addMenuItem(highContrast);

View File

@ -28,8 +28,9 @@ const Indicator = new Lang.Class({
Extends: PanelMenu.SystemStatusButton, Extends: PanelMenu.SystemStatusButton,
_init: function() { _init: function() {
this.parent('bluetooth-disabled', _("Bluetooth")); this.parent('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);
@ -106,7 +107,10 @@ const Indicator = new Lang.Class({
/* TRANSLATORS: this means that bluetooth was disabled by hardware rfkill */ /* TRANSLATORS: this means that bluetooth was disabled by hardware rfkill */
this._killswitch.setStatus(_("hardware disabled")); this._killswitch.setStatus(_("hardware disabled"));
this.actor.visible = has_adapter; if (has_adapter)
this.actor.show();
else
this.actor.hide();
if (on) { if (on) {
this._discoverable.actor.show(); this._discoverable.actor.show();
@ -178,7 +182,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) {

View File

@ -1,584 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/*
* Copyright 2012 Red Hat, Inc.
* Copyright 2012 Peng Huang <shawn.p.huang@gmail.com>
* Copyright 2012 Takao Fujiwara <tfujiwar@redhat.com>
* Copyright 2012 Tiger Soldier <tigersoldi@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const St = imports.gi.St;
const GLib = imports.gi.GLib;
const IBus = imports.gi.IBus;
const Lang = imports.lang;
const Signals = imports.signals;
const Shell = imports.gi.Shell;
const BoxPointer = imports.ui.boxpointer;
const Main = imports.ui.main;
const PopupMenu = imports.ui.popupMenu;
const ORIENTATION_HORIZONTAL = 0;
const ORIENTATION_VERTICAL = 1;
const ORIENTATION_SYSTEM = 2;
const StCandidateArea = new Lang.Class({
Name: 'StCandidateArea',
_init: function(orientation) {
this.actor = new St.BoxLayout({ style_class: 'candidate-area' });
this._orientation = orientation;
this._labels = [];
this._labelBoxes = [];
this._createUI();
},
_removeOldWidgets: function() {
this.actor.destroy_all_children();
this._labels = [];
this._labelBoxes = [];
},
_createUI: function() {
let vbox = null;
let hbox = null;
if (this._orientation == ORIENTATION_VERTICAL) {
vbox = new St.BoxLayout({ vertical: true,
style_class: 'candidate-vertical' });
this.actor.add_child(vbox,
{ expand: true,
x_fill: true,
y_fill: true
});
} else {
hbox = new St.BoxLayout({ vertical: false,
style_class: 'candidate-horizontal' });
this.actor.add_child(hbox,
{ expand: true,
x_fill: true,
y_fill: true
});
}
for (let i = 0; i < 16; i++) {
let label1 = new St.Label({ text: '1234567890abcdef'.charAt(i) + '.',
style_class: 'popup-menu-item',
reactive: true });
let label2 = new St.Label({ text: '' ,
style_class: 'popup-menu-item',
reactive: true });
if (this._orientation == ORIENTATION_VERTICAL) {
let candidateHBox = new St.BoxLayout({vertical: false});
let labelBox = new St.Bin({ style_class: 'candidate-hlabel-content' });
labelBox.set_child(label1);
labelBox.set_fill(true, true);
let textBox = new St.Bin({ style_class: 'candidate-htext-content' });
textBox.set_child(label2);
textBox.set_fill(true, true);
candidateHBox.add_child(labelBox,
{ expand: false,
x_fill: false,
y_fill: true
});
candidateHBox.add_child(textBox,
{ expand: true,
x_fill: true,
y_fill: true
});
vbox.add_child(candidateHBox);
this._labelBoxes.push(candidateHBox);
} else {
let candidateHBox = new St.BoxLayout({ style_class: 'candidate-vcontent',
vertical: false });
candidateHBox.add_child(label1);
candidateHBox.add_child(label2);
hbox.add_child(candidateHBox);
this._labelBoxes.push(candidateHBox);
}
this._labels.push([label1, label2]);
}
for (let i = 0; i < this._labels.length; i++) {
for(let j = 0; j < this._labels[i].length; j++) {
let widget = this._labels[i][j];
widget.candidateIndex = i;
widget.connect('button-press-event',
Lang.bind(this, function (widget, event) {
this._candidateClickedCB(widget, event);
}));
widget.connect('enter-event',
function(widget, event) {
widget.add_style_pseudo_class('hover');
});
widget.connect('leave-event',
function(widget, event) {
widget.remove_style_pseudo_class('hover');
});
}
}
},
_recreateUI: function() {
this._removeOldWidgets();
this._createUI();
},
_candidateClickedCB: function(widget, event) {
this.emit('candidate-clicked',
widget.candidateIndex,
event.get_button(),
event.get_state());
},
setLabels: function(labels) {
if (!labels || labels.length == 0) {
for (let i = 0; i < 16; i++) {
this._labels[i][0].set_text('1234567890abcdef'.charAt(i) + '.');
}
return;
}
for (let i = 0; i < labels.length && i < this._labels.length; i++) {
/* Use a ClutterActor attribute of Shell's theme instead of
* Pango.AttrList for the lookup window GUI and
* can ignore 'attrs' simply from IBus engines?
*/
let [text, attrs] = labels[i];
this._labels[i][0].set_text(text);
}
},
setCandidates: function(candidates, focusCandidate, showCursor) {
if (focusCandidate == undefined) {
focusCandidate = 0;
}
if (showCursor == undefined) {
showCursor = true;
}
if (candidates.length > this._labels.length) {
assert();
}
for (let i = 0; i < candidates.length; i++) {
/* Use a ClutterActor attribute of Shell's theme instead of
* Pango.AttrList for the lookup window GUI and
* can ignore 'attrs' simply from IBus engines?
*/
let [text, attrs] = candidates[i];
if (i == focusCandidate && showCursor) {
this._labels[i][1].add_style_pseudo_class('active');
} else {
this._labels[i][1].remove_style_pseudo_class('active');
}
this._labels[i][1].set_text(text);
this._labelBoxes[i].show();
}
for (let i = this._labelBoxes.length - 1; i >= candidates.length; i--) {
this._labelBoxes[i].hide();
}
},
setOrientation: function(orientation) {
if (orientation == this._orientation)
return;
this._orientation = orientation;
this._recreateUI();
},
showAll: function() {
this.actor.show();
},
hideAll: function() {
this.actor.hide();
},
});
Signals.addSignalMethods(StCandidateArea.prototype);
const CandidatePanel = new Lang.Class({
Name: 'CandidatePanel',
_init: function() {
this._orientation = ORIENTATION_VERTICAL;
this._currentOrientation = this._orientation;
this._preeditVisible = false;
this._auxStringVisible = false;
this._lookupTableVisible = false;
this._lookupTable = null;
this._cursorLocation = [0, 0, 0, 0];
this._movedCursorLocation = null;
this._initSt();
},
_initSt: function() {
this._arrowSide = St.Side.TOP;
this._arrowAlignment = 0.0;
this._boxPointer = new BoxPointer.BoxPointer(this._arrowSide,
{ x_fill: true,
y_fill: true,
x_align: St.Align.START });
this.actor = this._boxPointer.actor;
this.actor._delegate = this;
this.actor.style_class = 'popup-menu-boxpointer';
this.actor.add_style_class_name('popup-menu');
this.actor.add_style_class_name('candidate-panel');
this._cursorActor = new Shell.GenericContainer();
Main.uiGroup.add_actor(this.actor);
Main.uiGroup.add_actor(this._cursorActor);
this._stCandidatePanel = new St.BoxLayout({ style_class: 'candidate-panel',
vertical: true });
this._boxPointer.bin.set_child(this._stCandidatePanel);
this._stPreeditLabel = new St.Label({ style_class: 'popup-menu-item',
text: '' });
if (!this._preeditVisible) {
this._stPreeditLabel.hide();
}
this._stAuxLabel = new St.Label({ style_class: 'popup-menu-item',
text: '' });
if (!this._auxVisible) {
this._stAuxLabel.hide();
}
this._separator = new PopupMenu.PopupSeparatorMenuItem();
if (!this._preeditVisible && !this._auxVisible) {
this._separator.actor.hide();
}
// create candidates area
this._stCandidateArea = new StCandidateArea(this._currentOrientation);
this._stCandidateArea.connect('candidate-clicked',
Lang.bind(this, function(x, i, b, s) {
this.emit('candidate-clicked', i, b, s);}));
this.updateLookupTable(this._lookupTable, this._lookupTableVisible);
// TODO: page up/down GUI
this._packAllStWidgets();
this._isVisible = true;
this.hideAll();
this._checkShowStates();
},
_packAllStWidgets: function() {
this._stCandidatePanel.add_child(this._stPreeditLabel,
{ x_fill: true,
y_fill: false,
x_align: St.Align.MIDDLE,
y_align: St.Align.START });
this._stCandidatePanel.add_child(this._stAuxLabel,
{ x_fill: true,
y_fill: false,
x_align: St.Align.MIDDLE,
y_align: St.Align.MIDDLE });
this._stCandidatePanel.add_child(this._separator.actor,
{ x_fill: true,
y_fill: false,
x_align: St.Align.MIDDLE,
y_align: St.Align.MIDDLE });
this._stCandidatePanel.add_child(this._stCandidateArea.actor,
{ x_fill: true,
y_fill: false,
x_align: St.Align.MIDDLE,
y_align: St.Align.END });
},
showPreeditText: function() {
this._preeditVisible = true;
this._stPreeditLabel.show();
this._checkShowStates();
},
hidePreeditText: function() {
this._preeditVisible = false;
this._checkShowStates();
this._stPreeditLabel.hide();
},
updatePreeditText: function(text, cursorPos, visible) {
if (visible) {
this.showPreeditText();
} else {
this.hidePreeditText();
}
let str = text.get_text();
this._stPreeditLabel.set_text(str);
let attrs = text.get_attributes();
for (let i = 0; attrs != null && attrs.get(i) != null; i++) {
let attr = attrs.get(i);
if (attr.get_attr_type() == IBus.AttrType.BACKGROUND) {
let startIndex = attr.get_start_index();
let endIndex = attr.get_end_index();
let len = GLib.utf8_strlen(str, -1);
let markup = '';
if (startIndex == 0 &&
endIndex == GLib.utf8_strlen(str, -1)) {
markup = markup.concat(str);
} else {
if (startIndex > 0) {
markup = markup.concat(GLib.utf8_substring(str,
0,
startIndex));
}
if (startIndex != endIndex) {
markup = markup.concat('<span background=\"#555555\">');
markup = markup.concat(GLib.utf8_substring(str,
startIndex,
endIndex));
markup = markup.concat('</span>');
}
if (endIndex < len) {
markup = markup.concat(GLib.utf8_substring(str,
endIndex,
len));
}
}
let clutter_text = this._stPreeditLabel.get_clutter_text();
clutter_text.set_markup(markup);
clutter_text.queue_redraw();
}
}
},
showAuxiliaryText: function() {
this._auxStringVisible = true;
this._stAuxLabel.show();
this._checkShowStates();
},
hideAuxiliaryText: function() {
this._auxStringVisible = false;
this._checkShowStates();
this._stAuxLabel.hide();
},
updateAuxiliaryText: function(text, show) {
if (show) {
this.showAuxiliaryText();
} else {
this.hideAuxiliaryText();
}
this._stAuxLabel.set_text(text.get_text());
},
_refreshLabels: function() {
let newLabels = [];
for (let i = 0; this._lookupTable.get_label(i) != null; i++) {
let label = this._lookupTable.get_label(i);
newLabels.push([label.get_text(), label.get_attributes()]);
}
this._stCandidateArea.setLabels(newLabels);
},
_getCandidatesInCurrentPage: function() {
let cursorPos = this._lookupTable.get_cursor_pos();
let pageSize = this._lookupTable.get_page_size();
let page = ((cursorPos == 0) ? 0 : Math.floor(cursorPos / pageSize));
let startIndex = page * pageSize;
let endIndex = Math.min((page + 1) * pageSize,
this._lookupTable.get_number_of_candidates());
let candidates = [];
for (let i = startIndex; i < endIndex; i++) {
candidates.push(this._lookupTable.get_candidate(i));
}
return candidates;
},
_getCursorPosInCurrentPage: function() {
let cursorPos = this._lookupTable.get_cursor_pos();
let pageSize = this._lookupTable.get_page_size();
let posInPage = cursorPos % pageSize;
return posInPage;
},
_refreshCandidates: function() {
let candidates = this._getCandidatesInCurrentPage();
let newCandidates = [];
for (let i = 0; i < candidates.length; i++) {
let candidate = candidates[i];
newCandidates.push([candidate.get_text(),
candidate.get_attributes()]);
}
this._stCandidateArea.setCandidates(newCandidates,
this._getCursorPosInCurrentPage(),
this._lookupTable.is_cursor_visible());
},
updateLookupTable: function(lookupTable, visible) {
// hide lookup table
if (!visible) {
this.hideLookupTable();
}
this._lookupTable = lookupTable || new IBus.LookupTable();
let orientation = this._lookupTable.get_orientation();
if (orientation != ORIENTATION_HORIZONTAL &&
orientation != ORIENTATION_VERTICAL) {
orientation = this._orientation;
}
this.setCurrentOrientation(orientation);
this._refreshCandidates();
this._refreshLabels();
// show lookup table
if (visible) {
this.showLookupTable();
}
},
showLookupTable: function() {
this._lookupTableVisible = true;
this._stCandidateArea.showAll();
this._checkShowStates();
},
hideLookupTable: function() {
this._lookupTableVisible = false;
this._checkShowStates();
this._stCandidateArea.hideAll();
},
pageUpLookupTable: function() {
this._lookupTable.page_up();
this._refreshCandidates();
},
pageDownLookup_table: function() {
this._lookupTable.page_down();
this._refreshCandidates();
},
cursorUpLookupTable: function() {
this._lookupTable.cursor_up();
this._refreshCandidates();
},
cursorDownLookupTable: function() {
this._lookupTable.cursor_down();
this._refreshCandidates();
},
setCursorLocation: function(x, y, w, h) {
// if cursor location is changed, we reset the moved cursor location
if (this._cursorLocation.join() != [x, y, w, h].join()) {
this._cursorLocation = [x, y, w, h];
this._movedCursorLocation = null;
this._checkPosition();
}
},
_checkShowStates: function() {
this._checkSeparatorShowStates();
if (this._preeditVisible ||
this._auxStringVisible ||
this._lookupTableVisible) {
this._checkPosition();
this.showAll();
this.emit('show');
} else {
this.hideAll();
this.emit('hide');
}
},
_checkSeparatorShowStates: function() {
if (this._preeditVisible || this._auxStringVisible) {
this._separator.actor.show();
}
else
this._separator.actor.hide();
},
reset: function() {
let text = IBus.Text.new_from_string('');
this.updatePreeditText(text, 0, false);
text = IBus.Text.new_from_string('');
this.updateAuxiliaryText(text, false);
this.updateLookupTable(null, false);
this.hideAll();
},
setCurrentOrientation: function(orientation) {
if (this._currentOrientation == orientation) {
return;
}
this._currentOrientation = orientation;
this._stCandidateArea.setOrientation(orientation);
},
setOrientation: function(orientation) {
this._orientation = orientation;
this.updateLookupTable(this._lookupTable, this._lookupTableVisible);
},
getCurrentOrientation: function() {
return this._currentOrientation;
},
_checkPosition: function() {
let cursorLocation = this._movedCursorLocation || this._cursorLocation;
let [cursorX, cursorY, cursorWidth, cursorHeight] = cursorLocation;
let windowRight = cursorX + cursorWidth + this.actor.get_width();
let windowBottom = cursorY + cursorHeight + this.actor.get_height();
this._cursorActor.set_position(cursorX, cursorY);
this._cursorActor.set_size(cursorWidth, cursorHeight);
let monitor = Main.layoutManager.findMonitorForActor(this._cursorActor);
let [sx, sy] = [monitor.x + monitor.width, monitor.y + monitor.height];
if (windowBottom > sy) {
this._arrowSide = St.Side.BOTTOM;
} else {
this._arrowSide = St.Side.TOP;
}
this._boxPointer._arrowSide = this._arrowSide;
this._boxPointer.setArrowOrigin(this._arrowSide);
this._boxPointer.setPosition(this._cursorActor, this._arrowAlignment);
},
showAll: function() {
if (!this._isVisible) {
this.actor.opacity = 255;
this.actor.show();
this._isVisible = true;
}
},
hideAll: function() {
if (this._isVisible) {
this.actor.opacity = 0;
this.actor.hide();
this._isVisible = false;
}
},
move: function(x, y) {
this.actor.set_position(x, y);
}
});
Signals.addSignalMethods(CandidatePanel.prototype);

View File

@ -2,56 +2,46 @@
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const GdkPixbuf = imports.gi.GdkPixbuf; const GdkPixbuf = imports.gi.GdkPixbuf;
const Gkbd = imports.gi.Gkbd;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib; const GLib = imports.gi.GLib;
const Lang = imports.lang; const Lang = imports.lang;
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;
try {
var IBus = imports.gi.IBus;
const CandidatePanel = imports.ui.status.candidatePanel;
} catch (e) {
var IBus = null;
}
const Main = imports.ui.main; const Main = imports.ui.main;
const PopupMenu = imports.ui.popupMenu; 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 DESKTOP_INPUT_SOURCES_KEYBINDINGS_SCHEMA = 'org.gnome.desktop.input-sources.keybindings';
const DESKTOP_INPUT_SOURCES_SCHEMA = 'org.gnome.desktop.input-sources';
const KEY_CURRENT_IS = 'current';
const KEY_INPUT_SOURCES = 'sources';
const LayoutMenuItem = new Lang.Class({ const LayoutMenuItem = new Lang.Class({
Name: 'LayoutMenuItem', Name: 'LayoutMenuItem',
Extends: PopupMenu.PopupBaseMenuItem, Extends: PopupMenu.PopupBaseMenuItem,
_init: function(name, shortName, xkbLayout, xkbVariant, ibusEngine) { _init: function(config, id, indicator, long_name) {
this.parent(); this.parent();
this.label = new St.Label({ text: name }); this._config = config;
this.indicator = new St.Label({ text: shortName }); this._id = id;
this.label = new St.Label({ text: long_name });
this.indicator = indicator;
this.addActor(this.label); this.addActor(this.label);
this.addActor(this.indicator); this.addActor(this.indicator);
},
this.sourceName = name; activate: function(event) {
this.shortName = shortName; this.parent(event);
this.xkbLayout = xkbLayout;
this.xkbVariant = xkbVariant; this._config.lock_group(this._id);
this.ibusEngine = ibusEngine;
} }
}); });
const InputSourceIndicator = new Lang.Class({ const XKBIndicator = new Lang.Class({
Name: 'InputSourceIndicator', Name: 'XKBIndicator',
Extends: PanelMenu.Button, Extends: PanelMenu.Button,
_init: function() { _init: function() {
this.parent(0.0, _("Keyboard")); this.parent(0.0);
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));
@ -60,237 +50,61 @@ const InputSourceIndicator = new Lang.Class({
this.actor.add_actor(this._container); this.actor.add_actor(this._container);
this.actor.add_style_class_name('panel-status-button'); this.actor.add_style_class_name('panel-status-button');
this._iconActor = new St.Icon({ icon_name: 'keyboard', icon_type: St.IconType.SYMBOLIC, style_class: 'system-status-icon' });
this._container.add_actor(this._iconActor);
this._labelActors = [ ]; this._labelActors = [ ];
this._layoutItems = [ ]; this._layoutItems = [ ];
this._settings = new Gio.Settings({ schema: DESKTOP_INPUT_SOURCES_SCHEMA }); this._showFlags = false;
this._settings.connect('changed::' + KEY_CURRENT_IS, Lang.bind(this, this._currentISChanged)); this._config = Gkbd.Configuration.get();
this._settings.connect('changed::' + KEY_INPUT_SOURCES, Lang.bind(this, this._inputSourcesChanged)); this._config.connect('changed', Lang.bind(this, this._syncConfig));
this._config.connect('group-changed', Lang.bind(this, this._syncGroup));
this._config.start_listen();
if (IBus) this._syncConfig();
this._ibusInit();
this._inputSourcesChanged();
if (global.session_type == Shell.SessionType.USER) { if (global.session_type == Shell.SessionType.USER) {
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, function() { this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, function() {
Main.overview.hide(); Main.overview.hide();
let description = this._selectedLayout.xkbLayout; Util.spawn(['gkbd-keyboard-display', '-g', String(this._config.get_current_group() + 1)]);
if (this._selectedLayout.xkbVariant.length > 0)
description = description + '\t' + this._selectedLayout.xkbVariant;
Util.spawn(['gkbd-keyboard-display', '-l', description]);
})); }));
} }
this.menu.addSettingsAction(_("Region and Language Settings"), 'gnome-region-panel.desktop'); this.menu.addSettingsAction(_("Region and Language Settings"), 'gnome-region-panel.desktop');
global.display.add_keybinding('switch-next',
new Gio.Settings({ schema: DESKTOP_INPUT_SOURCES_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Lang.bind(this, this._switchNext));
global.display.add_keybinding('switch-previous',
new Gio.Settings({ schema: DESKTOP_INPUT_SOURCES_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Lang.bind(this, this._switchPrevious));
}, },
_ibusInit: function() { _adjustGroupNames: function(names) {
IBus.init(); // Disambiguate duplicate names with a subscript
this._ibus = new IBus.Bus(); // This is O(N^2) to avoid sorting names
if (!this._ibus.is_connected()) { // but N <= 4 so who cares?
log('ibus-daemon is not running');
return;
}
this._ibus.request_name(IBus.SERVICE_PANEL, for (let i = 0; i < names.length; i++) {
IBus.BusNameFlag.ALLOW_REPLACEMENT | let name = names[i];
IBus.BusNameFlag.REPLACE_EXISTING); let cnt = 0;
this._panel = new IBus.PanelService({ connection: this._ibus.get_connection(), for (let j = i + 1; j < names.length; j++) {
object_path: IBus.PATH_PANEL }); if (names[j] == name) {
this._ibusInitPanelService(); cnt++;
// U+2081 SUBSCRIPT ONE
this._candidatePanel = new CandidatePanel.CandidatePanel(); names[j] = name + String.fromCharCode(0x2081 + cnt);
this._ibusInitCandidatePanel(); }
},
_ibusInitCandidatePanel: function() {
this._candidatePanel.connect('cursor-up',
Lang.bind(this, function(widget) {
this.cursorUp();
}));
this._candidatePanel.connect('cursor-down',
Lang.bind(this, function(widget) {
this.cursorDown();
}));
this._candidatePanel.connect('page-up',
Lang.bind(this, function(widget) {
this.pageUp();
}));
this._candidatePanel.connect('page-down',
Lang.bind(this, function(widget) {
this.pageDown();
}));
this._candidatePanel.connect('candidate-clicked',
Lang.bind(this, function(widget, index, button, state) {
this.candidateClicked(index, button, state);
}));
},
_ibusInitPanelService: function() {
this._panel.connect('set-cursor-location',
Lang.bind(this, this.setCursorLocation));
this._panel.connect('update-preedit-text',
Lang.bind(this, this.updatePreeditText));
this._panel.connect('show-preedit-text',
Lang.bind(this, this.showPreeditText));
this._panel.connect('hide-preedit-text',
Lang.bind(this, this.hidePreeditText));
this._panel.connect('update-auxiliary-text',
Lang.bind(this, this.updateAuxiliaryText));
this._panel.connect('show-auxiliary-text',
Lang.bind(this, this.showAuxiliaryText));
this._panel.connect('hide-auxiliary-text',
Lang.bind(this, this.hideAuxiliaryText));
this._panel.connect('update-lookup-table',
Lang.bind(this, this.updateLookupTable));
this._panel.connect('show-lookup-table',
Lang.bind(this, this.showLookupTable));
this._panel.connect('hide-lookup-table',
Lang.bind(this, this.hideLookupTable));
this._panel.connect('page-up-lookup-table',
Lang.bind(this, this.pageUpLookupTable));
this._panel.connect('page-down-lookup-table',
Lang.bind(this, this.pageDownLookupTable));
this._panel.connect('cursor-up-lookup-table',
Lang.bind(this, this.cursorUpLookupTable));
this._panel.connect('cursor-down-lookup-table',
Lang.bind(this, this.cursorDownLookupTable));
this._panel.connect('focus-in', Lang.bind(this, this.focusIn));
this._panel.connect('focus-out', Lang.bind(this, this.focusOut));
},
setCursorLocation: function(panel, x, y, w, h) {
this._candidatePanel.setCursorLocation(x, y, w, h);
},
updatePreeditText: function(panel, text, cursorPos, visible) {
this._candidatePanel.updatePreeditText(text, cursorPos, visible);
},
showPreeditText: function(panel) {
this._candidatePanel.showPreeditText();
},
hidePreeditText: function(panel) {
this._candidatePanel.hidePreeditText();
},
updateAuxiliaryText: function(panel, text, visible) {
this._candidatePanel.updateAuxiliaryText(text, visible);
},
showAuxiliaryText: function(panel) {
this._candidatePanel.showAuxiliaryText();
},
hideAuxiliaryText: function(panel) {
this._candidatePanel.hideAuxiliaryText();
},
updateLookupTable: function(panel, lookupTable, visible) {
this._candidatePanel.updateLookupTable(lookupTable, visible);
},
showLookupTable: function(panel) {
this._candidatePanel.showLookupTable();
},
hideLookupTable: function(panel) {
this._candidatePanel.hideLookupTable();
},
pageUpLookupTable: function(panel) {
this._candidatePanel.pageUpLookupTable();
},
pageDownLookupTable: function(panel) {
this._candidatePanel.pageDownLookupTable();
},
cursorUpLookupTable: function(panel) {
this._candidatePanel.cursorUpLookupTable();
},
cursorDownLookupTable: function(panel) {
this._candidatePanel.cursorDownLookupTable();
},
focusIn: function(panel, path) {
},
focusOut: function(panel, path) {
this._candidatePanel.reset();
},
cursorUp: function() {
this._panel.cursor_up();
},
cursorDown: function() {
this._panel.cursor_down();
},
pageUp: function() {
this._panel.page_up();
},
pageDown: function() {
this._panel.page_down();
},
candidateClicked: function(index, button, state) {
this._panel.candidate_clicked(index, button, state);
},
_currentISChanged: function() {
let source = this._settings.get_value(KEY_CURRENT_IS);
let name = source.get_child_value(0).get_string()[0];
if (this._selectedLayout) {
this._selectedLayout.setShowDot(false);
this._selectedLayout = null;
}
if (this._selectedLabel) {
this._container.set_skip_paint(this._selectedLabel, true);
this._selectedLabel = null;
}
for (let i = 0; i < this._layoutItems.length; ++i) {
let item = this._layoutItems[i];
if (item.sourceName == name) {
item.setShowDot(true);
this._selectedLayout = item;
break;
} }
if (cnt != 0)
names[i] = name + '\u2081';
} }
for (let i = 0; i < this._labelActors.length; ++i) { return names;
let actor = this._labelActors[i];
if (actor.sourceName == name) {
this._selectedLabel = actor;
this._container.set_skip_paint(actor, false);
break;
}
}
if (!this._selectedLayout || !this._selectedLabel)
this._layoutItems[0].activate();
}, },
_inputSourcesChanged: function() { _syncConfig: function() {
let sources = this._settings.get_value(KEY_INPUT_SOURCES); this._showFlags = this._config.if_flags_shown();
if (sources.n_children() > 1) { if (this._showFlags) {
this._container.set_skip_paint(this._iconActor, false);
} else {
this._container.set_skip_paint(this._iconActor, true);
}
let groups = this._config.get_group_names();
if (groups.length > 1) {
this.actor.show(); this.actor.show();
} else { } else {
this.menu.close(); this.menu.close();
@ -303,69 +117,55 @@ const InputSourceIndicator = new Lang.Class({
for (let i = 0; i < this._labelActors.length; i++) for (let i = 0; i < this._labelActors.length; i++)
this._labelActors[i].destroy(); this._labelActors[i].destroy();
let short_names = this._adjustGroupNames(this._config.get_short_group_names());
this._selectedLayout = null; this._selectedLayout = null;
this._layoutItems = [ ]; this._layoutItems = [ ];
this._selectedLabel = null; this._selectedLabel = null;
this._labelActors = [ ]; this._labelActors = [ ];
for (let i = 0; i < groups.length; i++) {
for (let i = 0; i < sources.n_children(); ++i) { let icon_name = this._config.get_group_name(i);
let name = sources.get_child_value(i).get_child_value(0).get_string()[0]; let actor;
let shortName = sources.get_child_value(i).get_child_value(1).get_string()[0]; if (this._showFlags)
let xkbLayout = sources.get_child_value(i).get_child_value(2).get_string()[0]; actor = new St.Icon({ icon_name: icon_name, icon_type: St.IconType.SYMBOLIC, style_class: 'popup-menu-icon' });
let xkbVariant = sources.get_child_value(i).get_child_value(3).get_string()[0]; else
let ibusEngine = sources.get_child_value(i).get_child_value(4).get_string()[0]; actor = new St.Label({ text: short_names[i] });
let item = new LayoutMenuItem(this._config, i, actor, groups[i]);
let item = new LayoutMenuItem(name, shortName, xkbLayout, xkbVariant, ibusEngine); item._short_group_name = short_names[i];
item._icon_name = icon_name;
this._layoutItems.push(item); this._layoutItems.push(item);
this.menu.addMenuItem(item, i); this.menu.addMenuItem(item, i);
item.connect('activate', Lang.bind(this, function() {
if (this._selectedLayout == null || item.sourceName != this._selectedLayout.sourceName) {
let name = GLib.Variant.new_string(item.sourceName);
let shortName = GLib.Variant.new_string(item.shortName);
let xkbLayout = GLib.Variant.new_string(item.xkbLayout);
let xkbVariant = GLib.Variant.new_string(item.xkbVariant);
let ibusEngine = GLib.Variant.new_string(item.ibusEngine);
let tuple = GLib.Variant.new_tuple([name, shortName, xkbLayout, xkbVariant, ibusEngine], 5);
this._settings.set_value(KEY_CURRENT_IS, tuple);
}
}));
let shortLabel = new St.Label({ text: shortName }); let shortLabel = new St.Label({ text: short_names[i] });
shortLabel.sourceName = name;
this._labelActors.push(shortLabel); this._labelActors.push(shortLabel);
this._container.add_actor(shortLabel); this._container.add_actor(shortLabel);
this._container.set_skip_paint(shortLabel, true); this._container.set_skip_paint(shortLabel, true);
} }
this._currentISChanged(); this._syncGroup();
}, },
_switchNext: function() { _syncGroup: function() {
if (!this._selectedLayout || !this._selectedLabel) { let selected = this._config.get_current_group();
this._layoutItems[0].activate();
return;
}
for (let i = 0; i < this._layoutItems.length; ++i) {
let item = this._layoutItems[i];
if (item.sourceName == this._selectedLayout.sourceName) {
this._layoutItems[(++i == this._layoutItems.length) ? 0 : i].activate();
break;
}
}
},
_switchPrevious: function() { if (this._selectedLayout) {
if (!this._selectedLayout || !this._selectedLabel) { this._selectedLayout.setShowDot(false);
this._layoutItems[0].activate(); this._selectedLayout = null;
return;
} }
for (let i = 0; i < this._layoutItems.length; ++i) {
let item = this._layoutItems[i]; if (this._selectedLabel) {
if (item.sourceName == this._selectedLayout.sourceName) { this._container.set_skip_paint(this._selectedLabel, true);
this._layoutItems[(--i == -1) ? (this._layoutItems.length - 1) : i].activate(); this._selectedLabel = null;
break;
}
} }
let item = this._layoutItems[selected];
item.setShowDot(true);
this._iconActor.icon_name = item._icon_name;
this._selectedLabel = this._labelActors[selected];
this._container.set_skip_paint(this._selectedLabel, this._showFlags);
this._selectedLayout = item;
}, },
_containerGetPreferredWidth: function(container, for_height, alloc) { _containerGetPreferredWidth: function(container, for_height, alloc) {
@ -373,11 +173,15 @@ const InputSourceIndicator = new Lang.Class({
// for the height of all children, but we ignore the results // for the height of all children, but we ignore the results
// for those we don't actually display. // for those we don't actually display.
let max_min_width = 0, max_natural_width = 0; let max_min_width = 0, max_natural_width = 0;
if (this._showFlags)
[max_min_width, max_natural_width] = this._iconActor.get_preferred_width(for_height);
for (let i = 0; i < this._labelActors.length; i++) { for (let i = 0; i < this._labelActors.length; i++) {
let [min_width, natural_width] = this._labelActors[i].get_preferred_width(for_height); let [min_width, natural_width] = this._labelActors[i].get_preferred_width(for_height);
max_min_width = Math.max(max_min_width, min_width); if (!this._showFlags) {
max_natural_width = Math.max(max_natural_width, natural_width); max_min_width = Math.max(max_min_width, min_width);
max_natural_width = Math.max(max_natural_width, natural_width);
}
} }
alloc.min_size = max_min_width; alloc.min_size = max_min_width;
@ -386,11 +190,15 @@ const InputSourceIndicator = new Lang.Class({
_containerGetPreferredHeight: function(container, for_width, alloc) { _containerGetPreferredHeight: function(container, for_width, alloc) {
let max_min_height = 0, max_natural_height = 0; let max_min_height = 0, max_natural_height = 0;
if (this._showFlags)
[max_min_height, max_natural_height] = this._iconActor.get_preferred_height(for_width);
for (let i = 0; i < this._labelActors.length; i++) { for (let i = 0; i < this._labelActors.length; i++) {
let [min_height, natural_height] = this._labelActors[i].get_preferred_height(for_width); let [min_height, natural_height] = this._labelActors[i].get_preferred_height(for_width);
max_min_height = Math.max(max_min_height, min_height); if (!this._showFlags) {
max_natural_height = Math.max(max_natural_height, natural_height); max_min_height = Math.max(max_min_height, min_height);
max_natural_height = Math.max(max_natural_height, natural_height);
}
} }
alloc.min_size = max_min_height; alloc.min_size = max_min_height;
@ -404,6 +212,7 @@ const InputSourceIndicator = new Lang.Class({
box.y2 -= box.y1; box.y2 -= box.y1;
box.y1 = 0; box.y1 = 0;
this._iconActor.allocate_align_fill(box, 0.5, 0, false, false, flags);
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

@ -113,7 +113,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 });
@ -250,11 +249,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
@ -330,7 +327,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 +394,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 +418,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 +442,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 +526,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 +620,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');
}, },
@ -707,7 +686,10 @@ const NMDeviceWired = new Lang.Class({
// the device // the device
// we can do it here because addConnection and removeConnection // we can do it here because addConnection and removeConnection
// both call _createSection at some point // both call _createSection at some point
this.section.actor.visible = this._connections.length > 1; if (this._connections.length <= 1)
this.section.actor.hide();
else
this.section.actor.show();
}, },
_createAutomaticConnection: function() { _createAutomaticConnection: function() {
@ -882,12 +864,7 @@ 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");
} }
}); });
@ -1035,8 +1012,13 @@ const NMDeviceWireless = new Lang.Class({
}, },
setEnabled: function(enabled) { setEnabled: function(enabled) {
this.statusItem.actor.visible = enabled; if (enabled) {
this.section.actor.visible = enabled; this.statusItem.actor.show();
this.section.actor.show();
} else {
this.statusItem.actor.hide();
this.section.actor.hide();
}
}, },
activate: function() { activate: function() {
@ -1227,6 +1209,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
@ -1241,13 +1224,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);
this._clearSection(); if (this._networks.length == 0) {
this._queueCreateSection(); // only network in the list
this._networks.push(apObj);
this._clearSection();
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);
}
} }
}, },
@ -1334,7 +1341,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;
@ -1342,14 +1349,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;
@ -1371,10 +1380,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();
} }
}, },
@ -1407,13 +1416,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,
@ -1506,7 +1515,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);
} }
@ -1515,10 +1524,8 @@ 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);
} }
@ -1530,7 +1537,7 @@ const NMApplet = new Lang.Class({
Extends: PanelMenu.SystemStatusButton, Extends: PanelMenu.SystemStatusButton,
_init: function() { _init: function() {
this.parent('network-offline', _("Network")); this.parent('network-error', null);
this._client = NMClient.Client.new(); this._client = NMClient.Client.new();
@ -1796,7 +1803,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];
@ -1826,8 +1832,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;
@ -1836,7 +1840,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) {
@ -1858,7 +1862,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) {

View File

@ -46,6 +46,7 @@ const PowerManagerInterface = <interface name="org.gnome.SettingsDaemon.Power">
<method name="GetPrimaryDevice"> <method name="GetPrimaryDevice">
<arg type="(susdut)" direction="out" /> <arg type="(susdut)" direction="out" />
</method> </method>
<signal name="Changed" />
<property name="Icon" type="s" access="read" /> <property name="Icon" type="s" access="read" />
</interface>; </interface>;
@ -56,7 +57,7 @@ const Indicator = new Lang.Class({
Extends: PanelMenu.SystemStatusButton, Extends: PanelMenu.SystemStatusButton,
_init: function() { _init: function() {
this.parent('battery-missing', _("Battery")); this.parent('battery-missing', null);
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH); this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
@ -75,8 +76,7 @@ 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.connectSignal('Changed', Lang.bind(this, this._devicesChanged));
Lang.bind(this, this._devicesChanged));
this._devicesChanged(); this._devicesChanged();
}, },

View File

@ -22,7 +22,7 @@ const Indicator = new Lang.Class({
Extends: PanelMenu.SystemStatusButton, Extends: PanelMenu.SystemStatusButton,
_init: function() { _init: function() {
this.parent('audio-volume-muted', _("Volume")); this.parent('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 +35,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'));
@ -149,9 +148,13 @@ const Indicator = new Lang.Class({
} }
} }
} }
if (showInput) {
this._inputTitle.actor.visible = showInput; this._inputTitle.actor.show();
this._inputSlider.actor.visible = showInput; this._inputSlider.actor.show();
} else {
this._inputTitle.actor.hide();
this._inputSlider.actor.hide();
}
}, },
_volumeToIcon: function(volume) { _volumeToIcon: function(volume) {

View File

@ -33,6 +33,15 @@ const NotificationDirection = {
RECEIVED: 'chat-received' RECEIVED: 'chat-received'
}; };
let contactFeatures = [Tp.ContactFeature.ALIAS,
Tp.ContactFeature.AVATAR_DATA,
Tp.ContactFeature.PRESENCE];
// This is GNOME Shell's implementation of the Telepathy 'Client'
// interface. Specifically, the shell is a Telepathy 'Observer', which
// lets us see messages even if they belong to another app (eg,
// Empathy).
function makeMessageFromTpMessage(tpMessage, direction) { function makeMessageFromTpMessage(tpMessage, direction) {
let [text, flags] = tpMessage.to_text(); let [text, flags] = tpMessage.to_text();
@ -74,21 +83,11 @@ const Client = new Lang.Class({
// account path -> AccountNotification // account path -> AccountNotification
this._accountNotifications = {}; this._accountNotifications = {};
// Define features we want
this._accountManager = Tp.AccountManager.dup();
let factory = this._accountManager.get_factory();
factory.add_account_features([Tp.Account.get_feature_quark_connection()]);
factory.add_connection_features([Tp.Connection.get_feature_quark_contact_list()]);
factory.add_channel_features([Tp.Channel.get_feature_quark_contacts()]);
factory.add_contact_features([Tp.ContactFeature.ALIAS,
Tp.ContactFeature.AVATAR_DATA,
Tp.ContactFeature.PRESENCE,
Tp.ContactFeature.SUBSCRIPTION_STATES]);
// Set up a SimpleObserver, which will call _observeChannels whenever a // Set up a SimpleObserver, which will call _observeChannels whenever a
// channel matching its filters is detected. // channel matching its filters is detected.
// The second argument, recover, means _observeChannels will be run // The second argument, recover, means _observeChannels will be run
// for any existing channel as well. // for any existing channel as well.
this._accountManager = Tp.AccountManager.dup();
this._tpClient = new Shell.TpClient({ 'account-manager': this._accountManager, this._tpClient = new Shell.TpClient({ 'account-manager': this._accountManager,
'name': 'GnomeShell', 'name': 'GnomeShell',
'uniquify-name': true }) 'uniquify-name': true })
@ -115,9 +114,16 @@ const Client = new Lang.Class({
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e); throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
} }
// Watch subscription requests and connection errors // Watch subscription requests and connection errors
this._subscriptionSource = null; this._subscriptionSource = null;
this._accountSource = null; this._accountSource = null;
let factory = this._accountManager.get_factory();
factory.add_account_features([Tp.Account.get_feature_quark_connection()]);
factory.add_connection_features([Tp.Connection.get_feature_quark_contact_list()]);
factory.add_contact_features([Tp.ContactFeature.SUBSCRIPTION_STATES,
Tp.ContactFeature.ALIAS,
Tp.ContactFeature.AVATAR_DATA]);
this._accountManager.connect('account-validity-changed', this._accountManager.connect('account-validity-changed',
Lang.bind(this, this._accountValidityChanged)); Lang.bind(this, this._accountValidityChanged));
@ -127,6 +133,22 @@ const Client = new Lang.Class({
_observeChannels: function(observer, account, conn, channels, _observeChannels: function(observer, account, conn, channels,
dispatchOp, requests, context) { dispatchOp, requests, context) {
// If the self_contact doesn't have the ALIAS, make sure
// to fetch it before trying to grab the channels.
let self_contact = conn.get_self_contact();
if (self_contact.has_feature(Tp.ContactFeature.ALIAS)) {
this._finishObserveChannels(account, conn, channels, context);
} else {
Shell.get_self_contact_features(conn,
contactFeatures,
Lang.bind(this, function() {
this._finishObserveChannels(account, conn, channels, context);
}));
context.delay();
}
},
_finishObserveChannels: function(account, conn, channels, context) {
let len = channels.length; let len = channels.length;
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
let channel = channels[i]; let channel = channels[i];
@ -137,7 +159,16 @@ const Client = new Lang.Class({
targetHandleType != Tp.HandleType.CONTACT) targetHandleType != Tp.HandleType.CONTACT)
continue; continue;
this._createChatSource(account, conn, channel, channel.get_target_contact()); /* Request a TpContact */
Shell.get_tp_contacts(conn, [targetHandle],
contactFeatures,
Lang.bind(this, function (connection, contacts, failed) {
if (contacts.length < 1)
return;
/* We got the TpContact */
this._createChatSource(account, conn, channel, contacts[0]);
}), null);
} }
context.accept(); context.accept();
@ -166,11 +197,11 @@ const Client = new Lang.Class({
_handleChannels: function(handler, account, conn, channels, _handleChannels: function(handler, account, conn, channels,
requests, user_action_time, context) { requests, user_action_time, context) {
this._handlingChannels(account, conn, channels, true); this._handlingChannels(account, conn, channels);
context.accept(); context.accept();
}, },
_handlingChannels: function(account, conn, channels, notify) { _handlingChannels: function(account, conn, channels) {
let len = channels.length; let len = channels.length;
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
let channel = channels[i]; let channel = channels[i];
@ -181,18 +212,7 @@ const Client = new Lang.Class({
continue; continue;
} }
// 'notify' will be true when coming from an actual HandleChannels if (this._tpClient.is_handling_channel(channel)) {
// call, and not when from a successful Claim call. The point is
// we don't want to notify for a channel we just claimed which
// has no new messages (for example, a new channel which only has
// a delivery notification). We rely on _displayPendingMessages()
// and _messageReceived() to notify for new messages.
// But we should still notify from HandleChannels because the
// Telepathy spec states that handlers must foreground channels
// in HandleChannels calls which are already being handled.
if (notify && this._tpClient.is_handling_channel(channel)) {
// We are already handling the channel, display the source // We are already handling the channel, display the source
let source = this._chatSources[channel.get_object_path()]; let source = this._chatSources[channel.get_object_path()];
if (source) if (source)
@ -203,25 +223,41 @@ const Client = new Lang.Class({
_displayRoomInvitation: function(conn, channel, dispatchOp, context) { _displayRoomInvitation: function(conn, channel, dispatchOp, context) {
// We can only approve the rooms if we have been invited to it // We can only approve the rooms if we have been invited to it
let selfContact = channel.group_get_self_contact(); let selfHandle = channel.group_get_self_handle();
if (selfContact == null) { if (selfHandle == 0) {
Shell.decline_dispatch_op(context, 'Not invited to the room'); Shell.decline_dispatch_op(context, 'Not invited to the room');
return; return;
} }
let [invited, inviter, reason, msg] = channel.group_get_local_pending_contact_info(selfContact); let [invited, inviter, reason, msg] = channel.group_get_local_pending_info(selfHandle);
if (!invited) { if (!invited) {
Shell.decline_dispatch_op(context, 'Not invited to the room'); Shell.decline_dispatch_op(context, 'Not invited to the room');
return; return;
} }
// Request a TpContact for the inviter
Shell.get_tp_contacts(conn, [inviter],
contactFeatures,
Lang.bind(this, this._createRoomInviteSource, channel, context, dispatchOp));
context.delay();
},
_createRoomInviteSource: function(connection, contacts, failed, channel, context, dispatchOp) {
if (contacts.length < 1) {
Shell.decline_dispatch_op(context, 'Failed to get inviter');
return;
}
// We got the TpContact
// FIXME: We don't have a 'chat room' icon (bgo #653737) use // FIXME: We don't have a 'chat room' icon (bgo #653737) use
// system-users for now as Empathy does. // system-users for now as Empathy does.
let source = new ApproverSource(dispatchOp, _("Invitation"), let source = new ApproverSource(dispatchOp, _("Invitation"),
Gio.icon_new_for_string('system-users')); Gio.icon_new_for_string('system-users'));
Main.messageTray.add(source); Main.messageTray.add(source);
let notif = new RoomInviteNotification(source, dispatchOp, channel, inviter); let notif = new RoomInviteNotification(source, dispatchOp, channel, contacts[0]);
source.notify(notif); source.notify(notif);
context.accept(); context.accept();
}, },
@ -233,7 +269,8 @@ const Client = new Lang.Class({
if (chanType == Tp.IFACE_CHANNEL_TYPE_TEXT) if (chanType == Tp.IFACE_CHANNEL_TYPE_TEXT)
this._approveTextChannel(account, conn, channel, dispatchOp, context); this._approveTextChannel(account, conn, channel, dispatchOp, context);
else if (chanType == Tp.IFACE_CHANNEL_TYPE_CALL) else if (chanType == Tp.IFACE_CHANNEL_TYPE_STREAMED_MEDIA ||
chanType == 'org.freedesktop.Telepathy.Channel.Type.Call.DRAFT')
this._approveCall(account, conn, channel, dispatchOp, context); this._approveCall(account, conn, channel, dispatchOp, context);
else if (chanType == Tp.IFACE_CHANNEL_TYPE_FILE_TRANSFER) else if (chanType == Tp.IFACE_CHANNEL_TYPE_FILE_TRANSFER)
this._approveFileTransfer(account, conn, channel, dispatchOp, context); this._approveFileTransfer(account, conn, channel, dispatchOp, context);
@ -248,7 +285,7 @@ const Client = new Lang.Class({
Lang.bind(this, function(dispatchOp, result) { Lang.bind(this, function(dispatchOp, result) {
try { try {
dispatchOp.claim_with_finish(result); dispatchOp.claim_with_finish(result);
this._handlingChannels(account, conn, [channel], false); this._handlingChannels(account, conn, [channel]);
} catch (err) { } catch (err) {
throw new Error('Failed to Claim channel: ' + err); throw new Error('Failed to Claim channel: ' + err);
}})); }}));
@ -260,11 +297,27 @@ const Client = new Lang.Class({
}, },
_approveCall: function(account, conn, channel, dispatchOp, context) { _approveCall: function(account, conn, channel, dispatchOp, context) {
let [targetHandle, targetHandleType] = channel.get_handle();
Shell.get_tp_contacts(conn, [targetHandle],
contactFeatures,
Lang.bind(this, this._createAudioVideoSource, channel, context, dispatchOp));
context.delay();
},
_createAudioVideoSource: function(connection, contacts, failed, channel, context, dispatchOp) {
if (contacts.length < 1) {
Shell.decline_dispatch_op(context, 'Failed to get inviter');
return;
}
let isVideo = false; let isVideo = false;
let props = channel.borrow_immutable_properties(); let props = channel.borrow_immutable_properties();
if (props[Tp.PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO]) if (props['org.freedesktop.Telepathy.Channel.Type.Call.DRAFT.InitialVideo'] ||
props[Tp.PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_VIDEO])
isVideo = true; isVideo = true;
// We got the TpContact // We got the TpContact
@ -273,13 +326,27 @@ const Client = new Lang.Class({
Gio.icon_new_for_string('audio-input-microphone')); Gio.icon_new_for_string('audio-input-microphone'));
Main.messageTray.add(source); Main.messageTray.add(source);
let notif = new AudioVideoNotification(source, dispatchOp, channel, let notif = new AudioVideoNotification(source, dispatchOp, channel, contacts[0], isVideo);
channel.get_target_contact(), isVideo);
source.notify(notif); source.notify(notif);
context.accept(); context.accept();
}, },
_approveFileTransfer: function(account, conn, channel, dispatchOp, context) { _approveFileTransfer: function(account, conn, channel, dispatchOp, context) {
let [targetHandle, targetHandleType] = channel.get_handle();
Shell.get_tp_contacts(conn, [targetHandle],
contactFeatures,
Lang.bind(this, this._createFileTransferSource, channel, context, dispatchOp));
context.delay();
},
_createFileTransferSource: function(connection, contacts, failed, channel, context, dispatchOp) {
if (contacts.length < 1) {
Shell.decline_dispatch_op(context, 'Failed to get file sender');
return;
}
// Use the icon of the file being transferred // Use the icon of the file being transferred
let gicon = Gio.content_type_get_icon(channel.get_mime_type()); let gicon = Gio.content_type_get_icon(channel.get_mime_type());
@ -287,8 +354,7 @@ const Client = new Lang.Class({
let source = new ApproverSource(dispatchOp, _("File Transfer"), gicon); let source = new ApproverSource(dispatchOp, _("File Transfer"), gicon);
Main.messageTray.add(source); Main.messageTray.add(source);
let notif = new FileTransferNotification(source, dispatchOp, channel, let notif = new FileTransferNotification(source, dispatchOp, channel, contacts[0]);
channel.get_target_contact());
source.notify(notif); source.notify(notif);
context.accept(); context.accept();
}, },
@ -436,9 +502,15 @@ const ChatSource = new Lang.Class({
this._notification.setUrgency(MessageTray.Urgency.HIGH); this._notification.setUrgency(MessageTray.Urgency.HIGH);
this._notifyTimeoutId = 0; this._notifyTimeoutId = 0;
// We ack messages when the user expands the new notification or views the summary // We ack messages when the message box is collapsed if user has
// notification, in which case the notification is also expanded. // interacted with it before and so read the messages:
this._notification.connect('expanded', Lang.bind(this, this._ackMessages)); // - user clicked on it the tray
// - user expanded the notification by hovering over the toaster notification
this._shouldAck = false;
this.connect('summary-item-clicked', Lang.bind(this, this._summaryItemClicked));
this._notification.connect('expanded', Lang.bind(this, this._notificationExpanded));
this._notification.connect('collapsed', Lang.bind(this, this._notificationCollapsed));
this._presence = contact.get_presence_type(); this._presence = contact.get_presence_type();
@ -662,12 +734,12 @@ const ChatSource = new Lang.Class({
if (presence == Tp.ConnectionPresenceType.AVAILABLE) { if (presence == Tp.ConnectionPresenceType.AVAILABLE) {
msg = _("%s is online.").format(title); msg = _("%s is online.").format(title);
shouldNotify = (this._presence == Tp.ConnectionPresenceType.OFFLINE); shouldNotify = (this._presence == Tp.ConnectionPresenceType.OFFLINE);
} else if (presence == Tp.ConnectionPresenceType.OFFLINE) { } else if (presence == Tp.ConnectionPresenceType.OFFLINE ||
presence == Tp.ConnectionPresenceType.EXTENDED_AWAY) {
presence = Tp.ConnectionPresenceType.OFFLINE; presence = Tp.ConnectionPresenceType.OFFLINE;
msg = _("%s is offline.").format(title); msg = _("%s is offline.").format(title);
shouldNotify = (this._presence != Tp.ConnectionPresenceType.OFFLINE); shouldNotify = (this._presence != Tp.ConnectionPresenceType.OFFLINE);
} else if (presence == Tp.ConnectionPresenceType.AWAY || } else if (presence == Tp.ConnectionPresenceType.AWAY) {
presence == Tp.ConnectionPresenceType.EXTENDED_AWAY) {
msg = _("%s is away.").format(title); msg = _("%s is away.").format(title);
shouldNotify = false; shouldNotify = false;
} else if (presence == Tp.ConnectionPresenceType.BUSY) { } else if (presence == Tp.ConnectionPresenceType.BUSY) {
@ -702,6 +774,24 @@ const ChatSource = new Lang.Class({
// 'pending-message-removed' for each one. // 'pending-message-removed' for each one.
this._channel.ack_all_pending_messages_async(Lang.bind(this, function(src, result) { this._channel.ack_all_pending_messages_async(Lang.bind(this, function(src, result) {
this._channel.ack_all_pending_messages_finish(result);})); this._channel.ack_all_pending_messages_finish(result);}));
},
_summaryItemClicked: function(source, button) {
if (button != 1)
return;
this._shouldAck = true;
},
_notificationExpanded: function() {
this._shouldAck = true;
},
_notificationCollapsed: function() {
if (this._shouldAck)
this._ackMessages();
this._shouldAck = false;
} }
}); });
@ -853,8 +943,6 @@ const ChatNotification = new Lang.Class({
this._lastGroupActor.add(body, props.childProps); this._lastGroupActor.add(body, props.childProps);
this.updated();
let timestamp = props.timestamp; let timestamp = props.timestamp;
this._history.unshift({ actor: body, time: timestamp, this._history.unshift({ actor: body, time: timestamp,
realMessage: group != 'meta' }); realMessage: group != 'meta' });
@ -1087,7 +1175,7 @@ const AudioVideoNotification = new Lang.Class({
/* translators: argument is a contact name like Alice for example. */ /* translators: argument is a contact name like Alice for example. */
title = _("Call from %s").format(contact.get_alias()); title = _("Call from %s").format(contact.get_alias());
this.parent(source, title, null, { customContent: true }); this.parent(this, source, title, null, { customContent: true });
this.setResident(true); this.setResident(true);
this.addButton('reject', _("Reject")); this.addButton('reject', _("Reject"));
@ -1118,7 +1206,8 @@ const FileTransferNotification = new Lang.Class({
Extends: MessageTray.Notification, Extends: MessageTray.Notification,
_init: function(source, dispatchOp, channel, contact) { _init: function(source, dispatchOp, channel, contact) {
this.parent(source, this.parent(this,
source,
/* To translators: The first parameter is /* To translators: The first parameter is
* the contact's alias and the second one is the * the contact's alias and the second one is the
* file name. The string will be something * file name. The string will be something
@ -1191,7 +1280,7 @@ const SubscriptionRequestNotification = new Lang.Class({
Extends: MessageTray.Notification, Extends: MessageTray.Notification,
_init: function(source, contact) { _init: function(source, contact) {
this.parent(source, this.parent(this, source,
/* To translators: The parameter is the contact's alias */ /* To translators: The parameter is the contact's alias */
_("%s would like permission to see when you are online").format(contact.get_alias()), _("%s would like permission to see when you are online").format(contact.get_alias()),
null, { customContent: true }); null, { customContent: true });
@ -1318,7 +1407,7 @@ _connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_FAILED)]
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_LOST)] _connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_LOST)]
= _("Connection has been lost"); = _("Connection has been lost");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.ALREADY_CONNECTED)] _connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.ALREADY_CONNECTED)]
= _("This account is already connected to the server"); = _("This resource is already connected to the server");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_REPLACED)] _connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_REPLACED)]
= _("Connection has been replaced by a new connection using the same resource"); = _("Connection has been replaced by a new connection using the same resource");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.REGISTRATION_EXISTS)] _connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.REGISTRATION_EXISTS)]
@ -1331,8 +1420,6 @@ _connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_INSECURE)]
= _("Certificate uses an insecure cipher algorithm or is cryptographically weak"); = _("Certificate uses an insecure cipher algorithm or is cryptographically weak");
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_LIMIT_EXCEEDED)] _connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_LIMIT_EXCEEDED)]
= _("The length of the server certificate, or the depth of the server certificate chain, exceed the limits imposed by the cryptography library"); = _("The length of the server certificate, or the depth of the server certificate chain, exceed the limits imposed by the cryptography library");
_connectionErrorMessages['org.freedesktop.DBus.Error.NoReply']
= _("Internal error");
const AccountNotification = new Lang.Class({ const AccountNotification = new Lang.Class({
Name: 'AccountNotification', Name: 'AccountNotification',

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 GLib = imports.gi.GLib;
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;
@ -210,14 +209,9 @@ const ClutterFrameTicker = new Lang.Class({
_init : function() { _init : function() {
// We don't have a finite duration; tweener will tell us to stop // We don't have a finite duration; tweener will tell us to stop
// when we need to stop, so use 1000 seconds as "infinity", and // when we need to stop, so use 1000 seconds as "infinity"
// set the timeline to loop. Doing this means we have to track
// time ourselves, since clutter timeline's time will cycle
// instead of strictly increase.
this._timeline = new Clutter.Timeline({ duration: 1000*1000 }); this._timeline = new Clutter.Timeline({ duration: 1000*1000 });
this._timeline.set_loop(true);
this._startTime = -1; this._startTime = -1;
this._currentTime = -1;
this._timeline.connect('new-frame', Lang.bind(this, this._timeline.connect('new-frame', Lang.bind(this,
function(timeline, frame) { function(timeline, frame) {
@ -240,18 +234,17 @@ const ClutterFrameTicker = new Lang.Class({
// That looks bad, so we always start at the first frame of the // That looks bad, so we always start at the first frame of the
// animation then only do frame dropping from there. // animation then only do frame dropping from there.
if (this._startTime < 0) if (this._startTime < 0)
this._startTime = GLib.get_monotonic_time() / 1000.0; this._startTime = this._timeline.get_elapsed_time();
// currentTime is in milliseconds // currentTime is in milliseconds
let perf_log = Shell.PerfLog.get_default(); let perf_log = Shell.PerfLog.get_default();
this._currentTime = GLib.get_monotonic_time() / 1000.0 - this._startTime;
perf_log.event("tweener.framePrepareStart"); perf_log.event("tweener.framePrepareStart");
this.emit('prepare-frame'); this.emit('prepare-frame');
perf_log.event("tweener.framePrepareDone"); perf_log.event("tweener.framePrepareDone");
}, },
getTime : function() { getTime : function() {
return this._currentTime; return this._timeline.get_elapsed_time();
}, },
start : function() { start : function() {
@ -264,7 +257,6 @@ const ClutterFrameTicker = new Lang.Class({
stop : function() { stop : function() {
this._timeline.stop(); this._timeline.stop();
this._startTime = -1; this._startTime = -1;
this._currentTime = -1;
global.end_work(); global.end_work();
} }
}); });

View File

@ -9,7 +9,6 @@ const Shell = imports.gi.Shell;
const St = imports.gi.St; const St = imports.gi.St;
const Tp = imports.gi.TelepathyGLib; const Tp = imports.gi.TelepathyGLib;
const UPowerGlib = imports.gi.UPowerGlib; const UPowerGlib = imports.gi.UPowerGlib;
const Atk = imports.gi.Atk;
const GnomeSession = imports.misc.gnomeSession; const GnomeSession = imports.misc.gnomeSession;
const Main = imports.ui.main; const Main = imports.ui.main;
@ -57,7 +56,6 @@ const IMStatusItem = new Lang.Class({
this._icon.icon_name = iconName; this._icon.icon_name = iconName;
this.label = new St.Label({ text: label }); this.label = new St.Label({ text: label });
this.actor.label_actor = this.label;
this.addActor(this.label); this.addActor(this.label);
} }
}); });
@ -165,8 +163,6 @@ const IMStatusChooserItem = new Lang.Class({
Lang.bind(this, this._IMAccountsChanged)); Lang.bind(this, this._IMAccountsChanged));
this._accountMgr.connect('account-removed', this._accountMgr.connect('account-removed',
Lang.bind(this, this._IMAccountsChanged)); Lang.bind(this, this._IMAccountsChanged));
this._accountMgr.connect('account-validity-changed',
Lang.bind(this, this._IMAccountsChanged));
this._accountMgr.prepare_async(null, Lang.bind(this, this._accountMgr.prepare_async(null, Lang.bind(this,
function(mgr) { function(mgr) {
let [presence, status, msg] = mgr.get_most_available_presence(); let [presence, status, msg] = mgr.get_most_available_presence();
@ -243,8 +239,7 @@ const IMStatusChooserItem = new Lang.Class({
}, },
_setIconFromFile: function(iconFile) { _setIconFromFile: function(iconFile) {
this._iconBin.set_style('background-image: url("' + iconFile + '");' + this._iconBin.set_style('background-image: url("' + iconFile + '");');
'background-size: contain;');
this._iconBin.child = null; this._iconBin.child = null;
}, },
@ -380,8 +375,7 @@ const IMStatusChooserItem = new Lang.Class({
if (sessionStatus == GnomeSession.PresenceStatus.IDLE) { if (sessionStatus == GnomeSession.PresenceStatus.IDLE) {
// Only change presence if the current one is "more present" than // Only change presence if the current one is "more present" than
// idle // idle
if (this._currentPresence != Tp.ConnectionPresenceType.OFFLINE && if (this._currentPresence != Tp.ConnectionPresenceType.OFFLINE)
this._currentPresence != Tp.ConnectionPresenceType.HIDDEN)
return Tp.ConnectionPresenceType.EXTENDED_AWAY; return Tp.ConnectionPresenceType.EXTENDED_AWAY;
} }
@ -392,15 +386,8 @@ const IMStatusChooserItem = new Lang.Class({
if (!this._imPresenceRestored) if (!this._imPresenceRestored)
return; return;
let savedStatus = global.settings.get_int('saved-session-presence');
if (!this._sessionPresenceRestored) { if (!this._sessionPresenceRestored) {
let savedStatus = global.settings.get_int('saved-session-presence');
// We should never save/restore a status other than AVAILABLE
// or BUSY
if (savedStatus != GnomeSession.PresenceStatus.AVAILABLE &&
savedStatus != GnomeSession.PresenceStatus.BUSY)
savedStatus = GnomeSession.PresenceStatus.AVAILABLE;
if (sessionStatus != savedStatus) { if (sessionStatus != savedStatus) {
this._presence.status = savedStatus; this._presence.status = savedStatus;
return; return;
@ -408,10 +395,7 @@ const IMStatusChooserItem = new Lang.Class({
this._sessionPresenceRestored = true; this._sessionPresenceRestored = true;
} }
if ((sessionStatus == GnomeSession.PresenceStatus.AVAILABLE || global.settings.set_int('saved-session-presence', sessionStatus);
sessionStatus == GnomeSession.PresenceStatus.BUSY) &&
savedStatus != sessionStatus)
global.settings.set_int('saved-session-presence', sessionStatus);
let [presence, s, msg] = this._accountMgr.get_most_available_presence(); let [presence, s, msg] = this._accountMgr.get_most_available_presence();
let newPresence, status; let newPresence, status;
@ -437,8 +421,6 @@ const UserMenuButton = new Lang.Class({
_init: function() { _init: function() {
this.parent(0.0); this.parent(0.0);
this.actor.accessible_role = Atk.Role.MENU;
let box = new St.BoxLayout({ name: 'panelUserMenu' }); let box = new St.BoxLayout({ name: 'panelUserMenu' });
this.actor.add_actor(box); this.actor.add_actor(box);
@ -483,7 +465,6 @@ const UserMenuButton = new Lang.Class({
})); }));
this._name = new St.Label(); this._name = new St.Label();
this.actor.label_actor = this._name;
box.add(this._name, { y_align: St.Align.MIDDLE, y_fill: false }); box.add(this._name, { y_align: St.Align.MIDDLE, y_fill: false });
this._userLoadedId = this._user.connect('notify::is-loaded', Lang.bind(this, this._updateUserName)); this._userLoadedId = this._user.connect('notify::is-loaded', Lang.bind(this, this._updateUserName));
this._userChangedId = this._user.connect('changed', Lang.bind(this, this._updateUserName)); this._userChangedId = this._user.connect('changed', Lang.bind(this, this._updateUserName));
@ -554,12 +535,18 @@ const UserMenuButton = new Lang.Class({
_updateLogout: function() { _updateLogout: function() {
let allowLogout = !this._lockdownSettings.get_boolean(DISABLE_LOG_OUT_KEY); let allowLogout = !this._lockdownSettings.get_boolean(DISABLE_LOG_OUT_KEY);
this._logoutItem.actor.visible = allowLogout; if (allowLogout)
this._logoutItem.actor.show();
else
this._logoutItem.actor.hide();
}, },
_updateLockScreen: function() { _updateLockScreen: function() {
let allowLockScreen = !this._lockdownSettings.get_boolean(DISABLE_LOCK_SCREEN_KEY); let allowLockScreen = !this._lockdownSettings.get_boolean(DISABLE_LOCK_SCREEN_KEY);
this._logoutItem.actor.visible = allowLockScreen; if (allowLockScreen)
this._lockScreenItem.actor.show();
else
this._lockScreenItem.actor.hide();
}, },
_updateHaveShutdown: function() { _updateHaveShutdown: function() {
@ -578,7 +565,10 @@ const UserMenuButton = new Lang.Class({
if (!this._suspendOrPowerOffItem) if (!this._suspendOrPowerOffItem)
return; return;
this._suspendOrPowerOffItem.actor.visible = this._haveShutdown || this._haveSuspend; if (!this._haveShutdown && !this._haveSuspend)
this._suspendOrPowerOffItem.actor.hide();
else
this._suspendOrPowerOffItem.actor.show();
// If we can't suspend show Power Off... instead // If we can't suspend show Power Off... instead
// and disable the alt key // and disable the alt key
@ -620,7 +610,7 @@ const UserMenuButton = new Lang.Class({
this._statusChooser = item; this._statusChooser = item;
item = new PopupMenu.PopupSwitchMenuItem(_("Notifications")); item = new PopupMenu.PopupSwitchMenuItem(_("Notifications"));
item.connect('toggled', Lang.bind(this, this._updatePresenceStatus)); item.connect('activate', Lang.bind(this, this._updatePresenceStatus));
this.menu.addMenuItem(item); this.menu.addMenuItem(item);
this._notificationsSwitch = item; this._notificationsSwitch = item;
@ -725,8 +715,8 @@ const UserMenuButton = new Lang.Class({
if (this._haveSuspend && if (this._haveSuspend &&
this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) { this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
// Ensure we only suspend after locking the screen // Ensure we only suspend after the screensaver has activated
this._screenSaverProxy.LockRemote(Lang.bind(this, function() { this._screenSaverProxy.SetActiveRemote(true, Lang.bind(this, function() {
this._upClient.suspend_sync(null); this._upClient.suspend_sync(null);
})); }));
} else { } else {

View File

@ -133,14 +133,14 @@ const SearchTab = new Lang.Class({
this._text.connect('text-changed', Lang.bind(this, this._onTextChanged)); this._text.connect('text-changed', Lang.bind(this, this._onTextChanged));
this._text.connect('key-press-event', Lang.bind(this, function (o, e) { this._text.connect('key-press-event', Lang.bind(this, function (o, e) {
// We can't connect to 'activate' here because search providers // We can't connect to 'activate' here because search providers
// might want to do something with the modifiers in activateDefault. // might want to do something with the modifiers in activateSelected.
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) {
if (this._searchTimeoutId > 0) { if (this._searchTimeoutId > 0) {
Mainloop.source_remove(this._searchTimeoutId); Mainloop.source_remove(this._searchTimeoutId);
this._doSearch(); this._doSearch();
} }
this._searchResults.activateDefault(); this._searchResults.activateSelected();
return true; return true;
} }
return false; return false;
@ -148,33 +148,9 @@ const SearchTab = new Lang.Class({
this._entry.connect('notify::mapped', Lang.bind(this, this._onMapped)); this._entry.connect('notify::mapped', Lang.bind(this, this._onMapped));
global.stage.connect('notify::key-focus', Lang.bind(this, this._onStageKeyFocusChanged)); global.stage.connect('notify::key-focus', Lang.bind(this, this._updateCursorVisibility));
this._capturedEventId = 0; this._capturedEventId = 0;
this._text.connect('key-focus-in', Lang.bind(this, function() {
this._searchResults.highlightDefault(true);
}));
this._text.connect('key-focus-out', Lang.bind(this, function() {
this._searchResults.highlightDefault(false);
}));
// Since the entry isn't inside the results container we install this
// dummy widget as the last results container child so that we can
// include the entry in the keynav tab path...
this._focusTrap = new St.Bin({ can_focus: true });
this._focusTrap.connect('key-focus-in', Lang.bind(this, function() {
this._entry.grab_key_focus();
}));
// ... but make it unfocusable using arrow keys keynav by making its
// bounding box always contain the possible focus source's bounding
// box since StWidget's keynav logic won't ever select it as a target
// in that case.
this._focusTrap.add_constraint(new Clutter.BindConstraint({ source: this._searchResults.actor,
coordinate: Clutter.BindCoordinate.ALL }));
this._searchResults.actor.add_actor(this._focusTrap);
global.focus_manager.add_group(this._searchResults.actor);
}, },
hide: function() { hide: function() {
@ -187,29 +163,21 @@ const SearchTab = new Lang.Class({
// incorrectly when we remove focus // incorrectly when we remove focus
// (https://bugzilla.gnome.org/show_bug.cgi?id=636341) */ // (https://bugzilla.gnome.org/show_bug.cgi?id=636341) */
if (this._text.text != '') if (this._text.text != '')
this.reset(); this._reset();
}, },
reset: function () { _reset: function () {
global.stage.set_key_focus(null); this._text.text = '';
this._entry.text = ''; global.stage.set_key_focus(null);
this._text.set_cursor_visible(true); this._text.set_cursor_visible(true);
this._text.set_selection(0, 0); this._text.set_selection(0, 0);
}, },
_onStageKeyFocusChanged: function() { _updateCursorVisibility: function() {
let focus = global.stage.get_key_focus(); let focus = global.stage.get_key_focus();
let appearFocused = (this._entry.contains(focus) || this._text.set_cursor_visible(focus == this._text);
this._searchResults.actor.contains(focus));
this._text.set_cursor_visible(appearFocused);
if (appearFocused)
this._entry.add_style_pseudo_class('focus');
else
this._entry.remove_style_pseudo_class('focus');
}, },
_onMapped: function() { _onMapped: function() {
@ -260,7 +228,7 @@ const SearchTab = new Lang.Class({
if (this._iconClickedId == 0) { if (this._iconClickedId == 0) {
this._iconClickedId = this._entry.connect('secondary-icon-clicked', this._iconClickedId = this._entry.connect('secondary-icon-clicked',
Lang.bind(this, function() { Lang.bind(this, function() {
this.reset(); this._reset();
})); }));
} }
this._activate(); this._activate();
@ -286,37 +254,25 @@ const SearchTab = new Lang.Class({
_onKeyPress: function(entry, event) { _onKeyPress: function(entry, event) {
let symbol = event.get_key_symbol(); let symbol = event.get_key_symbol();
if (symbol == Clutter.Escape) { if (symbol == Clutter.Up) {
if (this._isActivated()) { if (!this.active)
this.reset();
return true; return true;
} this._searchResults.selectUp(false);
} else if (this.active) {
let arrowNext, nextDirection;
if (entry.get_text_direction() == Clutter.TextDirection.RTL) {
arrowNext = Clutter.Left;
nextDirection = Gtk.DirectionType.LEFT;
} else {
arrowNext = Clutter.Right;
nextDirection = Gtk.DirectionType.RIGHT;
}
if (symbol == Clutter.Tab) { return true;
this._searchResults.navigateFocus(Gtk.DirectionType.TAB_FORWARD); } else if (symbol == Clutter.Down) {
if (!this.active)
return true; return true;
} else if (symbol == Clutter.ISO_Left_Tab) {
this._focusTrap.can_focus = false; this._searchResults.selectDown(false);
this._searchResults.navigateFocus(Gtk.DirectionType.TAB_BACKWARD); return true;
this._focusTrap.can_focus = true; } else if (symbol == Clutter.Escape) {
return true; if (this._isActivated()) {
} else if (symbol == Clutter.Down) { this._reset();
this._searchResults.navigateFocus(Gtk.DirectionType.DOWN);
return true;
} else if (symbol == arrowNext && this._text.position == -1) {
this._searchResults.navigateFocus(nextDirection);
return true; return true;
} }
} }
return false; return false;
}, },
@ -328,7 +284,7 @@ const SearchTab = new Lang.Class({
// the user clicked outside after activating the entry, but // the user clicked outside after activating the entry, but
// with no search term entered and no keyboard button pressed // with no search term entered and no keyboard button pressed
// - cancel the search // - cancel the search
this.reset(); this._reset();
} }
} }
@ -463,6 +419,29 @@ const ViewSelector = new Lang.Class({
// not when setting the initially selected one. // not when setting the initially selected one.
if (!tab.visible) if (!tab.visible)
tab.show(!firstSwitch); tab.show(!firstSwitch);
// Pull a Meg Ryan:
if (!firstSwitch && Main.overview.workspaces) {
if (tab != this._tabs[0]) {
Tweener.addTween(Main.overview.workspaces.actor,
{ opacity: 0,
time: 0.1,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
Main.overview.workspaces.actor.hide();
Main.overview.workspaces.actor.opacity = 255;
})
});
} else {
Main.overview.workspaces.actor.opacity = 0;
Main.overview.workspaces.actor.show();
Tweener.addTween(Main.overview.workspaces.actor,
{ opacity: 255,
time: 0.1,
transition: 'easeOutQuad' });
}
}
}, },
switchTab: function(id) { switchTab: function(id) {
@ -530,7 +509,7 @@ const ViewSelector = new Lang.Class({
let childBox = new Clutter.ActorBox(); let childBox = new Clutter.ActorBox();
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 - barNatWidth; childBox.x1 = allocWidth - barNatWidth;
childBox.x2 = allocWidth; childBox.x2 = allocWidth;
} else { } else {
@ -539,7 +518,7 @@ const ViewSelector = new Lang.Class({
} }
this._tabBox.allocate(childBox, flags); this._tabBox.allocate(childBox, flags);
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 = searchNatWidth; childBox.x2 = searchNatWidth;
} else { } else {
@ -555,34 +534,24 @@ const ViewSelector = new Lang.Class({
}, },
_onStageKeyPress: function(actor, event) { _onStageKeyPress: function(actor, event) {
let modifiers = event.get_state(); let modifiers = Shell.get_event_state(event);
let symbol = event.get_key_symbol(); let symbol = event.get_key_symbol();
if (symbol == Clutter.Escape) { if (symbol == Clutter.Escape) {
if (this._searchTab.active) Main.overview.hide();
this._searchTab.reset();
else
Main.overview.hide();
return true; return true;
} else if (Clutter.keysym_to_unicode(symbol) || } else if (modifiers & Clutter.ModifierType.CONTROL_MASK) {
(symbol == Clutter.BackSpace && this._searchTab.active)) { if (symbol == Clutter.Page_Up) {
this._searchTab.startSearch(event); if (!this._searchTab.active)
} else if (!this._searchTab.active) {
if (modifiers & Clutter.ModifierType.CONTROL_MASK) {
if (symbol == Clutter.Page_Up) {
this._prevTab(); this._prevTab();
return true;
} else if (symbol == Clutter.Page_Down) {
this._nextTab();
return true;
}
} else if (symbol == Clutter.Tab) {
this._activeTab.page.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
return true; return true;
} else if (symbol == Clutter.ISO_Left_Tab) { } else if (symbol == Clutter.Page_Down) {
this._activeTab.page.navigate_focus(null, Gtk.DirectionType.TAB_BACKWARD, false); if (!this._searchTab.active)
this._nextTab();
return true; return true;
} }
} else if (Clutter.keysym_to_unicode(symbol)) {
this._searchTab.startSearch(event);
} }
return false; return false;
}, },

View File

@ -1,211 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const GdkPixbuf = imports.gi.GdkPixbuf;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Search = imports.ui.search;
// we could make these gsettings
const FISH_NAME = 'wanda';
const FISH_SPEED = 300;
const FISH_COMMAND = 'fortune';
const GNOME_PANEL_PIXMAPDIR = '../gnome-panel/fish';
const FISH_GROUP = 'Fish Animation';
const MAGIC_FISH_KEY = 'free the fish';
const WandaIcon = new Lang.Class({
Name: 'WandaIcon',
Extends: IconGrid.BaseIcon,
_init : function(fish, label, params) {
this._fish = fish;
let file = GLib.build_filenamev([global.datadir, GNOME_PANEL_PIXMAPDIR, fish + '.fish']);
if (GLib.file_test(file, GLib.FileTest.EXISTS)) {
this._keyfile = new GLib.KeyFile();
this._keyfile.load_from_file(file, GLib.KeyFileFlags.NONE);
this._imageFile = GLib.build_filenamev([global.datadir, GNOME_PANEL_PIXMAPDIR,
this._keyfile.get_string(FISH_GROUP, 'image')]);
let tmpPixbuf = GdkPixbuf.Pixbuf.new_from_file(this._imageFile);
this._imgHeight = tmpPixbuf.height;
this._imgWidth = tmpPixbuf.width / this._keyfile.get_integer(FISH_GROUP, 'frames');
} else {
this._imageFile = null;
}
this.parent(label, params);
},
createIcon: function(iconSize) {
if (this._animations)
this._animations.destroy();
if (!this._imageFile) {
return new St.Icon({ icon_name: 'face-smile',
icon_type: St.IconType.FULLCOLOR,
icon_size: iconSize
});
}
this._animations = St.TextureCache.get_default().load_sliced_image(this._imageFile, this._imgWidth, this._imgHeight);
this._animations.connect('destroy', Lang.bind(this, function() {
if (this._timeoutId)
GLib.source_remove(this._timeoutId);
this._timeoutId = 0;
this._animations = null;
}));
this._animations.connect('notify::mapped', Lang.bind(this, function() {
if (this._animations.mapped && !this._timeoutId) {
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, FISH_SPEED, Lang.bind(this, this._update));
this._i = 0;
this._update();
} else if (!this._animations.mapped && this._timeoutId) {
GLib.source_remove(this._timeoutId);
this._timeoutId = 0;
}
}));
this._i = 0;
return this._animations;
},
_update: function() {
let n = this._animations.get_n_children();
if (n == 0) {
return true;
}
this._animations.get_child_at_index(this._i).hide();
this._i = (this._i + 1) % n;
this._animations.get_child_at_index(this._i).show();
return true;
},
});
const WandaIconBin = new Lang.Class({
Name: 'WandaIconBin',
_init: function(fish, label, params) {
this.actor = new St.Bin({ style_class: 'search-result-content',
reactive: true,
track_hover: true });
this.icon = new WandaIcon(fish, label, params);
this.actor.child = this.icon.actor;
this.actor.label_actor = this.icon.label;
},
});
const FortuneDialog = new Lang.Class({
Name: 'FortuneDialog',
_init: function(name, command) {
let text;
try {
let [res, stdout, stderr, status] = GLib.spawn_command_line_sync(command);
text = String.fromCharCode.apply(null, stdout);
} catch(e) {
text = _("Sorry, no wisdom for you today:\n%s").format(e.message);
}
this._title = new St.Label({ style_class: 'prompt-dialog-headline',
text: _("%s the Oracle says").format(name) });
this._label = new St.Label({ style_class: 'prompt-dialog-description',
text: text });
this._label.clutter_text.line_wrap = true;
this._box = new St.BoxLayout({ vertical: true,
style_class: 'prompt-dialog' // this is just to force a reasonable width
});
this._box.add(this._title, { align: St.Align.MIDDLE });
this._box.add(this._label, { expand: true });
this._button = new St.Button({ button_mask: St.ButtonMask.ONE,
style_class: 'modal-dialog',
reactive: true });
this._button.connect('clicked', Lang.bind(this, this.destroy));
this._button.child = this._box;
let monitor = Main.layoutManager.primaryMonitor;
Main.layoutManager.addChrome(this._button);
this._button.set_position(Math.floor(monitor.width / 2 - this._button.width / 2),
Math.floor(monitor.height / 2 - this._button.height / 2));
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 10, Lang.bind(this, this.destroy));
},
destroy: function() {
this._button.destroy();
}
});
function capitalize(str) {
return str[0].toUpperCase() + str.substring(1, str.length);
}
const WandaSearchProvider = new Lang.Class({
Name: 'WandaSearchProvider',
Extends: Search.SearchProvider,
_init: function() {
this.parent(_("Your favorite Easter Egg"));
},
getResultMetas: function(fish) {
return [{ 'id': fish[0], // there may be many fish in the sea, but
// only one which speaks the truth!
'name': capitalize(fish[0]),
'createIcon': function(iconSize) {
// for DND only (maybe could be improved)
// DON'T use St.Icon here, it crashes the shell
// (dnd.js code assumes it can query the actor size
// without parenting it, while StWidget accesses
// StThemeNode in get_preferred_width/height, which
// triggers an assertion failure)
return St.TextureCache.get_default().load_icon_name(null,
'face-smile',
St.IconType.FULLCOLOR,
iconSize);
}
}];
},
getInitialResultSet: function(terms) {
if (terms.join(' ') == MAGIC_FISH_KEY) {
return [ FISH_NAME ];
}
return [];
},
getSubsearchResultSet: function(previousResults, terms) {
return this.getInitialResultSet(terms);
},
activateResult: function(fish, params) {
if (this._dialog)
this._dialog.destroy();
this._dialog = new FortuneDialog(capitalize(fish), FISH_COMMAND);
},
createResultActor: function (resultMeta, terms) {
let icon = new WandaIconBin(resultMeta.id, resultMeta.name);
return icon.actor;
}
});

View File

@ -14,12 +14,6 @@ const WindowAttentionHandler = new Lang.Class({
global.display.connect('window-demands-attention', Lang.bind(this, this._onWindowDemandsAttention)); global.display.connect('window-demands-attention', Lang.bind(this, this._onWindowDemandsAttention));
}, },
_getTitleAndBanner: function(app, window) {
let title = app.get_name();
let banner = _("'%s' is ready").format(window.get_title());
return [title, banner]
},
_onWindowDemandsAttention : function(display, window) { _onWindowDemandsAttention : function(display, window) {
// We don't want to show the notification when the window is already focused, // We don't want to show the notification when the window is already focused,
// because this is rather pointless. // because this is rather pointless.
@ -36,15 +30,16 @@ const WindowAttentionHandler = new Lang.Class({
let source = new Source(app, window); let source = new Source(app, window);
Main.messageTray.add(source); Main.messageTray.add(source);
let [title, banner] = this._getTitleAndBanner(app, window); let banner = _("'%s' is ready").format(window.title);
let title = app.get_name();
let notification = new MessageTray.Notification(source, title, banner); let notification = new MessageTray.Notification(source, title, banner);
source.notify(notification); source.notify(notification);
source.signalIDs.push(window.connect('notify::title', Lang.bind(this, function() { source.signalIDs.push(window.connect('notify::title',
let [title, banner] = this._getTitleAndBanner(app, window); Lang.bind(this, function() {
notification.update(title, banner); notification.update(title, banner);
}))); })));
} }
}); });

View File

@ -13,7 +13,6 @@ const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup;
const Main = imports.ui.main; const Main = imports.ui.main;
const Tweener = imports.ui.tweener; const Tweener = imports.ui.tweener;
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
const WINDOW_ANIMATION_TIME = 0.25; const WINDOW_ANIMATION_TIME = 0.25;
const DIM_TIME = 0.500; const DIM_TIME = 0.500;
const UNDIM_TIME = 0.250; const UNDIM_TIME = 0.250;
@ -135,10 +134,6 @@ const WindowManager = new Lang.Class({
Lang.bind(this, this._startAppSwitcher)); Lang.bind(this, this._startAppSwitcher));
Meta.keybindings_set_custom_handler('switch-panels', Meta.keybindings_set_custom_handler('switch-panels',
Lang.bind(this, this._startA11ySwitcher)); Lang.bind(this, this._startA11ySwitcher));
global.display.add_keybinding('open-application-menu',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Lang.bind(this, this._openAppMenu));
Main.overview.connect('showing', Lang.bind(this, function() { Main.overview.connect('showing', Lang.bind(this, function() {
for (let i = 0; i < this._dimmedWindows.length; i++) for (let i = 0; i < this._dimmedWindows.length; i++)
@ -191,7 +186,7 @@ const WindowManager = new Lang.Class({
let primary = Main.layoutManager.primaryMonitor; let primary = Main.layoutManager.primaryMonitor;
let xDest = primary.x; let xDest = primary.x;
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) if (St.Widget.get_default_direction() == St.TextDirection.RTL)
xDest += primary.width; xDest += primary.width;
Tweener.addTween(actor, Tweener.addTween(actor,
@ -552,10 +547,6 @@ const WindowManager = new Lang.Class({
Main.ctrlAltTabManager.popup(backwards, binding.get_mask()); Main.ctrlAltTabManager.popup(backwards, binding.get_mask());
}, },
_openAppMenu : function(display, screen, window, event, binding) {
Main.panel.openAppMenu();
},
_showWorkspaceSwitcher : function(display, screen, window, binding) { _showWorkspaceSwitcher : function(display, screen, window, binding) {
if (screen.n_workspaces == 1) if (screen.n_workspaces == 1)
return; return;
@ -576,7 +567,7 @@ const WindowManager = new Lang.Class({
}, },
actionMoveWorkspaceLeft: function() { actionMoveWorkspaceLeft: function() {
let rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL); let rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL);
let activeWorkspaceIndex = global.screen.get_active_workspace_index(); let activeWorkspaceIndex = global.screen.get_active_workspace_index();
let indexToActivate = activeWorkspaceIndex; let indexToActivate = activeWorkspaceIndex;
if (rtl && activeWorkspaceIndex < global.screen.n_workspaces - 1) if (rtl && activeWorkspaceIndex < global.screen.n_workspaces - 1)
@ -592,7 +583,7 @@ const WindowManager = new Lang.Class({
}, },
actionMoveWorkspaceRight: function() { actionMoveWorkspaceRight: function() {
let rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL); let rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL);
let activeWorkspaceIndex = global.screen.get_active_workspace_index(); let activeWorkspaceIndex = global.screen.get_active_workspace_index();
let indexToActivate = activeWorkspaceIndex; let indexToActivate = activeWorkspaceIndex;
if (rtl && activeWorkspaceIndex > 0) if (rtl && activeWorkspaceIndex > 0)

View File

@ -23,8 +23,6 @@ const WINDOW_DND_SIZE = 256;
const SCROLL_SCALE_AMOUNT = 100 / 5; const SCROLL_SCALE_AMOUNT = 100 / 5;
const WINDOW_CLONE_MAXIMUM_SCALE = 0.7;
const LIGHTBOX_FADE_TIME = 0.1; const LIGHTBOX_FADE_TIME = 0.1;
const CLOSE_BUTTON_FADE_TIME = 0.1; const CLOSE_BUTTON_FADE_TIME = 0.1;
@ -96,11 +94,10 @@ const ScaledPoint = new Lang.Class({
const WindowClone = new Lang.Class({ const WindowClone = new Lang.Class({
Name: 'WindowClone', Name: 'WindowClone',
_init : function(realWindow, workspace) { _init : function(realWindow) {
this.realWindow = realWindow; this.realWindow = realWindow;
this.metaWindow = realWindow.meta_window; this.metaWindow = realWindow.meta_window;
this.metaWindow._delegate = this; this.metaWindow._delegate = this;
this._workspace = workspace;
let [borderX, borderY] = this._getInvisibleBorderPadding(); let [borderX, borderY] = this._getInvisibleBorderPadding();
this._windowClone = new Clutter.Clone({ source: realWindow.get_texture(), this._windowClone = new Clutter.Clone({ source: realWindow.get_texture(),
@ -370,7 +367,6 @@ const WindowClone = new Lang.Class({
if (this._selected) if (this._selected)
return; return;
let [x, y] = action.get_coords(); let [x, y] = action.get_coords();
action.release();
this._draggable.startDrag(x, y, global.get_current_time()); this._draggable.startDrag(x, y, global.get_current_time());
})); }));
} }
@ -387,12 +383,19 @@ const WindowClone = new Lang.Class({
this.emit('drag-begin'); this.emit('drag-begin');
}, },
_getWorkspaceActor : function() {
let index = this.metaWindow.get_workspace().index();
return Main.overview.workspaces.getWorkspaceByIndex(index);
},
handleDragOver : function(source, actor, x, y, time) { handleDragOver : function(source, actor, x, y, time) {
return this._workspace.handleDragOver(source, actor, x, y, time); let workspace = this._getWorkspaceActor();
return workspace.handleDragOver(source, actor, x, y, time);
}, },
acceptDrop : function(source, actor, x, y, time) { acceptDrop : function(source, actor, x, y, time) {
this._workspace.acceptDrop(source, actor, x, y, time); let workspace = this._getWorkspaceActor();
workspace.acceptDrop(source, actor, x, y, time);
}, },
_onDragCancelled : function (draggable, time) { _onDragCancelled : function (draggable, time) {
@ -491,9 +494,6 @@ const WindowOverlay = new Lang.Class({
}, },
fadeIn: function() { fadeIn: function() {
if (!this._hidden)
return;
this.show(); this.show();
this.title.opacity = 0; this.title.opacity = 0;
this._parentActor.raise_top(); this._parentActor.raise_top();
@ -522,13 +522,13 @@ const WindowOverlay = new Lang.Class({
// get_transformed_position() and get_transformed_size(), // get_transformed_position() and get_transformed_size(),
// as windowClone might be moving. // as windowClone might be moving.
// See Workspace._showWindowOverlay // See Workspace._showWindowOverlay
updatePositions: function(cloneX, cloneY, cloneWidth, cloneHeight, animate) { updatePositions: function(cloneX, cloneY, cloneWidth, cloneHeight) {
let button = this.closeButton; let button = this.closeButton;
let title = this.title; let title = this.title;
let settings = new Gio.Settings({ schema: BUTTON_LAYOUT_SCHEMA }); let settings = new Gio.Settings({ schema: BUTTON_LAYOUT_SCHEMA });
let layout = settings.get_string(BUTTON_LAYOUT_KEY); let layout = settings.get_string(BUTTON_LAYOUT_KEY);
let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL; let rtl = St.Widget.get_default_direction() == St.TextDirection.RTL;
let split = layout.split(":"); let split = layout.split(":");
let side; let side;
@ -544,34 +544,15 @@ const WindowOverlay = new Lang.Class({
else else
buttonX = cloneX + (cloneWidth - button._overlap); buttonX = cloneX + (cloneWidth - button._overlap);
if (animate) button.set_position(Math.floor(buttonX), Math.floor(buttonY));
this._animateOverlayActor(button, Math.floor(buttonX), Math.floor(buttonY), button.width);
else
button.set_position(Math.floor(buttonX), Math.floor(buttonY));
if (!title.fullWidth) if (!title.fullWidth)
title.fullWidth = title.width; title.fullWidth = title.width;
let titleWidth = Math.min(title.fullWidth, cloneWidth); title.width = Math.min(title.fullWidth, cloneWidth);
let titleX = cloneX + (cloneWidth - titleWidth) / 2; let titleX = cloneX + (cloneWidth - title.width) / 2;
let titleY = cloneY + cloneHeight + title._spacing; let titleY = cloneY + cloneHeight + title._spacing;
title.set_position(Math.floor(titleX), Math.floor(titleY));
if (animate)
this._animateOverlayActor(title, Math.floor(titleX), Math.floor(titleY), titleWidth);
else {
title.width = titleWidth;
title.set_position(Math.floor(titleX), Math.floor(titleY));
}
},
_animateOverlayActor: function(actor, x, y, width) {
Tweener.addTween(actor,
{ x: x,
y: y,
width: width,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad'
});
}, },
_closeWindow: function(actor) { _closeWindow: function(actor) {
@ -967,7 +948,7 @@ const Workspace = new Lang.Class({
let scale = Math.min((width - buttonOuterWidth) / rect.width, let scale = Math.min((width - buttonOuterWidth) / rect.width,
(height - buttonOuterHeight - captionHeight) / rect.height, (height - buttonOuterHeight - captionHeight) / rect.height,
WINDOW_CLONE_MAXIMUM_SCALE); 1.0);
x = Math.floor(x + (width - scale * rect.width) / 2); x = Math.floor(x + (width - scale * rect.width) / 2);
@ -1036,7 +1017,7 @@ const Workspace = new Lang.Class({
let [x, y, scale] = this._computeWindowLayout(metaWindow, slot); let [x, y, scale] = this._computeWindowLayout(metaWindow, slot);
if (overlay && initialPositioning) if (overlay)
overlay.hide(); overlay.hide();
if (animate && isOnCurrentWorkspace) { if (animate && isOnCurrentWorkspace) {
if (!metaWindow.showing_on_its_workspace()) { if (!metaWindow.showing_on_its_workspace()) {
@ -1059,11 +1040,20 @@ const Workspace = new Lang.Class({
}); });
} }
this._animateClone(clone, overlay, x, y, scale, initialPositioning); Tweener.addTween(clone.actor,
{ x: x,
y: y,
scale_x: scale,
scale_y: scale,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this._showWindowOverlay(clone, overlay, true);
})
});
} else { } else {
clone.actor.set_position(x, y); clone.actor.set_position(x, y);
clone.actor.set_scale(scale, scale); clone.actor.set_scale(scale, scale);
this._updateWindowOverlayPositions(clone, overlay, x, y, scale, false);
this._showWindowOverlay(clone, overlay, isOnCurrentWorkspace); this._showWindowOverlay(clone, overlay, isOnCurrentWorkspace);
} }
} }
@ -1085,35 +1075,23 @@ const Workspace = new Lang.Class({
} }
}, },
_animateClone: function(clone, overlay, x, y, scale, initialPositioning) {
Tweener.addTween(clone.actor,
{ x: x,
y: y,
scale_x: scale,
scale_y: scale,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this._showWindowOverlay(clone, overlay, true);
})
});
this._updateWindowOverlayPositions(clone, overlay, x, y, scale, true);
},
_updateWindowOverlayPositions: function(clone, overlay, x, y, scale, animate) {
let [cloneWidth, cloneHeight] = clone.actor.get_size();
cloneWidth = scale * cloneWidth;
cloneHeight = scale * cloneHeight;
if (overlay)
overlay.updatePositions(x, y, cloneWidth, cloneHeight, animate);
},
_showWindowOverlay: function(clone, overlay, fade) { _showWindowOverlay: function(clone, overlay, fade) {
if (clone.inDrag) if (clone.inDrag)
return; return;
// This is a little messy and complicated because when we
// start the fade-in we may not have done the final positioning
// of the workspaces. (Tweener doesn't necessarily finish
// all animations before calling onComplete callbacks.)
// So we need to manually compute where the window will
// be after the workspace animation finishes.
let [cloneX, cloneY] = clone.actor.get_position();
let [cloneWidth, cloneHeight] = clone.actor.get_size();
cloneWidth = clone.actor.scale_x * cloneWidth;
cloneHeight = clone.actor.scale_y * cloneHeight;
if (overlay) { if (overlay) {
overlay.updatePositions(cloneX, cloneY, cloneWidth, cloneHeight);
if (fade) if (fade)
overlay.fadeIn(); overlay.fadeIn();
else else
@ -1131,15 +1109,6 @@ const Workspace = new Lang.Class({
} }
}, },
_hideAllOverlays: function() {
for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i];
let overlay = this._windowOverlays[i];
if (overlay)
overlay.hide();
}
},
_delayedWindowRepositioning: function() { _delayedWindowRepositioning: function() {
if (this._windowIsZooming) if (this._windowIsZooming)
return true; return true;
@ -1157,16 +1126,22 @@ const Workspace = new Lang.Class({
return true; return true;
} }
let actorUnderPointer = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
for (let i = 0; i < this._windows.length; i++) {
if (this._windows[i].actor == actorUnderPointer)
return true;
}
this.positionWindows(WindowPositionFlags.ANIMATE); this.positionWindows(WindowPositionFlags.ANIMATE);
return false; return false;
}, },
showWindowsOverlays: function() {
if (this.leavingOverview)
return;
this._windowOverlaysGroup.show();
this._showAllOverlays();
},
hideWindowsOverlays: function() {
this._windowOverlaysGroup.hide();
},
_doRemoveWindow : function(metaWin) { _doRemoveWindow : function(metaWin) {
let win = metaWin.get_compositor_private(); let win = metaWin.get_compositor_private();
@ -1251,7 +1226,7 @@ const Workspace = new Lang.Class({
if (!this._isMyWindow(win) || !this._isOverviewWindow(win)) if (!this._isMyWindow(win) || !this._isOverviewWindow(win))
return; return;
let [clone, overlay] = this._addWindowClone(win); let clone = this._addWindowClone(win);
if (win._overviewHint) { if (win._overviewHint) {
let x = win._overviewHint.x - this.actor.x; let x = win._overviewHint.x - this.actor.x;
@ -1261,7 +1236,6 @@ const Workspace = new Lang.Class({
clone.actor.set_position (x, y); clone.actor.set_position (x, y);
clone.actor.set_scale (scale, scale); clone.actor.set_scale (scale, scale);
this._updateWindowOverlayPositions(clone, overlay, x, y, scale, false);
} else { } else {
// Position new windows at the top corner of the workspace rather // Position new windows at the top corner of the workspace rather
// than where they were placed for real to avoid the window // than where they were placed for real to avoid the window
@ -1321,10 +1295,7 @@ const Workspace = new Lang.Class({
this.leavingOverview = true; this.leavingOverview = true;
for (let i = 0; i < this._windows.length; i++) { this.hideWindowsOverlays();
let clone = this._windows[i];
Tweener.removeTweens(clone.actor);
}
if (this._repositionWindowsId > 0) { if (this._repositionWindowsId > 0) {
Mainloop.source_remove(this._repositionWindowsId); Mainloop.source_remove(this._repositionWindowsId);
@ -1364,7 +1335,6 @@ const Workspace = new Lang.Class({
} }
} }
this._hideAllOverlays();
}, },
destroy : function() { destroy : function() {
@ -1416,7 +1386,7 @@ const Workspace = new Lang.Class({
// Create a clone of a (non-desktop) window and add it to the window list // Create a clone of a (non-desktop) window and add it to the window list
_addWindowClone : function(win) { _addWindowClone : function(win) {
let clone = new WindowClone(win, this); let clone = new WindowClone(win);
let overlay = new WindowOverlay(clone, this._windowOverlaysGroup); let overlay = new WindowOverlay(clone, this._windowOverlaysGroup);
clone.connect('selected', clone.connect('selected',
@ -1455,7 +1425,7 @@ const Workspace = new Lang.Class({
this._windows.push(clone); this._windows.push(clone);
this._windowOverlays.push(overlay); this._windowOverlays.push(overlay);
return [clone, overlay]; return clone;
}, },
_onShowOverlayClose: function (windowOverlay) { _onShowOverlayClose: function (windowOverlay) {

View File

@ -19,12 +19,12 @@ const WorkspaceSwitcherPopup = new Lang.Class({
Name: 'WorkspaceSwitcherPopup', Name: 'WorkspaceSwitcherPopup',
_init : function() { _init : function() {
this.actor = new St.Widget({ reactive: true, this.actor = new St.Group({ reactive: true,
x: 0, x: 0,
y: 0, y: 0,
width: global.screen_width, width: global.screen_width,
height: global.screen_height, height: global.screen_height,
style_class: 'workspace-switcher-group' }); style_class: 'workspace-switcher-group' });
Main.uiGroup.add_actor(this.actor); Main.uiGroup.add_actor(this.actor);
this._container = new St.BoxLayout({ style_class: 'workspace-switcher-container' }); this._container = new St.BoxLayout({ style_class: 'workspace-switcher-container' });
@ -105,7 +105,7 @@ const WorkspaceSwitcherPopup = new Lang.Class({
}, },
_redraw : function(direction, activeWorkspaceIndex) { _redraw : function(direction, activeWorkspaceIndex) {
this._list.destroy_all_children(); this._list.destroy_children();
for (let i = 0; i < global.screen.n_workspaces; i++) { for (let i = 0; i < global.screen.n_workspaces; i++) {
let indicator = null; let indicator = null;

View File

@ -25,8 +25,6 @@ const SLIDE_ANIMATION_TIME = 0.2;
// placeholder exactly. // placeholder exactly.
const WORKSPACE_CUT_SIZE = 10; const WORKSPACE_CUT_SIZE = 10;
const WORKSPACE_KEEP_ALIVE_TIME = 100;
const WindowClone = new Lang.Class({ const WindowClone = new Lang.Class({
Name: 'WindowClone', Name: 'WindowClone',
@ -53,7 +51,6 @@ const WindowClone = new Lang.Class({
dragActorMaxSize: Workspace.WINDOW_DND_SIZE, dragActorMaxSize: Workspace.WINDOW_DND_SIZE,
dragActorOpacity: Workspace.DRAGGING_WINDOW_OPACITY }); dragActorOpacity: Workspace.DRAGGING_WINDOW_OPACITY });
this._draggable.connect('drag-begin', Lang.bind(this, this._onDragBegin)); this._draggable.connect('drag-begin', Lang.bind(this, this._onDragBegin));
this._draggable.connect('drag-cancelled', Lang.bind(this, this._onDragCancelled));
this._draggable.connect('drag-end', Lang.bind(this, this._onDragEnd)); this._draggable.connect('drag-end', Lang.bind(this, this._onDragEnd));
this.inDrag = false; this.inDrag = false;
}, },
@ -111,10 +108,6 @@ const WindowClone = new Lang.Class({
this.emit('drag-begin'); this.emit('drag-begin');
}, },
_onDragCancelled : function (draggable, time) {
this.emit('drag-cancelled');
},
_onDragEnd : function (draggable, time, snapback) { _onDragEnd : function (draggable, time, snapback) {
this.inDrag = false; this.inDrag = false;
@ -156,16 +149,24 @@ const WorkspaceThumbnail = new Lang.Class({
this.metaWorkspace = metaWorkspace; this.metaWorkspace = metaWorkspace;
this.monitorIndex = Main.layoutManager.primaryIndex; this.monitorIndex = Main.layoutManager.primaryIndex;
this._removed = false; this.actor = new St.Group({ reactive: true,
clip_to_allocation: true,
this.actor = new St.Widget({ clip_to_allocation: true, style_class: 'workspace-thumbnail' });
style_class: 'workspace-thumbnail' });
this.actor._delegate = this; this.actor._delegate = this;
this._contents = new Clutter.Group(); this._contents = new Clutter.Group();
this.actor.add_actor(this._contents); this.actor.add_actor(this._contents);
this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this.actor.connect('button-press-event', Lang.bind(this,
function(actor, event) {
return true;
}));
this.actor.connect('button-release-event', Lang.bind(this,
function(actor, event) {
this._activate();
return true;
}));
this._background = Meta.BackgroundActor.new_for_screen(global.screen); this._background = Meta.BackgroundActor.new_for_screen(global.screen);
this._contents.add_actor(this._background); this._contents.add_actor(this._background);
@ -173,21 +174,17 @@ const WorkspaceThumbnail = new Lang.Class({
let monitor = Main.layoutManager.primaryMonitor; let monitor = Main.layoutManager.primaryMonitor;
this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height); this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height);
let windows = global.get_window_actors().filter(this._isWorkspaceWindow, this); let windows = global.get_window_actors().filter(this._isMyWindow, this);
// Create clones for windows that should be visible in the Overview // Create clones for windows that should be visible in the Overview
this._windows = []; this._windows = [];
this._allWindows = [];
this._minimizedChangedIds = [];
for (let i = 0; i < windows.length; i++) { for (let i = 0; i < windows.length; i++) {
let minimizedChangedId = windows[i].meta_window._minimizedChangedId =
windows[i].meta_window.connect('notify::minimized', windows[i].meta_window.connect('notify::minimized',
Lang.bind(this, Lang.bind(this,
this._updateMinimized)); this._updateMinimized));
this._allWindows.push(windows[i].meta_window);
this._minimizedChangedIds.push(minimizedChangedId);
if (this._isMyWindow(windows[i]) && this._isOverviewWindow(windows[i])) { if (this._isOverviewWindow(windows[i])) {
this._addWindowClone(windows[i]); this._addWindowClone(windows[i]);
} }
} }
@ -272,11 +269,17 @@ const WorkspaceThumbnail = new Lang.Class({
let clone = this._windows[index]; let clone = this._windows[index];
this._windows.splice(index, 1); this._windows.splice(index, 1);
if (win && this._isOverviewWindow(win)) {
if (metaWin._minimizedChangedId) {
metaWin.disconnect(metaWin._minimizedChangedId);
delete metaWin._minimizedChangedId;
}
}
clone.destroy(); clone.destroy();
}, },
_doAddWindow : function(metaWin) { _doAddWindow : function(metaWin) {
if (this._removed) if (this.leavingOverview)
return; return;
let win = metaWin.get_compositor_private(); let win = metaWin.get_compositor_private();
@ -286,7 +289,7 @@ const WorkspaceThumbnail = new Lang.Class({
// the compositor finds out about them... // the compositor finds out about them...
Mainloop.idle_add(Lang.bind(this, Mainloop.idle_add(Lang.bind(this,
function () { function () {
if (!this._removed && if (this.actor &&
metaWin.get_compositor_private() && metaWin.get_compositor_private() &&
metaWin.get_workspace() == this.metaWorkspace) metaWin.get_workspace() == this.metaWorkspace)
this._doAddWindow(metaWin); this._doAddWindow(metaWin);
@ -295,19 +298,16 @@ const WorkspaceThumbnail = new Lang.Class({
return; return;
} }
if (this._allWindows.indexOf(metaWin) == -1) {
let minimizedChangedId = metaWin.connect('notify::minimized',
Lang.bind(this,
this._updateMinimized));
this._allWindows.push(metaWin);
this._minimizedChangedIds.push(minimizedChangedId);
}
// We might have the window in our list already if it was on all workspaces and // We might have the window in our list already if it was on all workspaces and
// now was moved to this workspace // now was moved to this workspace
if (this._lookupIndex (metaWin) != -1) if (this._lookupIndex (metaWin) != -1)
return; return;
if (!metaWin._minimizedChangedId)
metaWin._minimizedChangedId = metaWin.connect('notify::minimized',
Lang.bind(this,
this._updateMinimized));
if (!this._isMyWindow(win) || !this._isOverviewWindow(win)) if (!this._isMyWindow(win) || !this._isOverviewWindow(win))
return; return;
@ -319,13 +319,6 @@ const WorkspaceThumbnail = new Lang.Class({
}, },
_windowRemoved : function(metaWorkspace, metaWin) { _windowRemoved : function(metaWorkspace, metaWin) {
let index = this._allWindows.indexOf(metaWin);
if (index != -1) {
metaWin.disconnect(this._minimizedChangedIds[index]);
this._allWindows.splice(index, 1);
this._minimizedChangedIds.splice(index, 1);
}
this._doRemoveWindow(metaWin); this._doRemoveWindow(metaWin);
}, },
@ -352,36 +345,27 @@ const WorkspaceThumbnail = new Lang.Class({
this.actor.destroy(); this.actor.destroy();
}, },
workspaceRemoved : function() { _onDestroy: function(actor) {
if (this._removed)
return;
this._removed = true;
this.metaWorkspace.disconnect(this._windowAddedId); this.metaWorkspace.disconnect(this._windowAddedId);
this.metaWorkspace.disconnect(this._windowRemovedId); this.metaWorkspace.disconnect(this._windowRemovedId);
global.screen.disconnect(this._windowEnteredMonitorId); global.screen.disconnect(this._windowEnteredMonitorId);
global.screen.disconnect(this._windowLeftMonitorId); global.screen.disconnect(this._windowLeftMonitorId);
for (let i = 0; i < this._allWindows.length; i++) for (let i = 0; i < this._windows.length; i++) {
this._allWindows[i].disconnect(this._minimizedChangedIds[i]); let metaWin = this._windows[i].metaWindow;
}, if (metaWin._minimizedChangedId) {
metaWin.disconnect(metaWin._minimizedChangedId);
_onDestroy: function(actor) { delete metaWin._minimizedChangedId;
this.workspaceRemoved(); }
}
this._windows = []; this._windows = [];
this.actor = null; this.actor = null;
}, },
// Tests if @win belongs to this workspace
_isWorkspaceWindow : function (win) {
return Main.isWindowActorDisplayedOnWorkspace(win, this.metaWorkspace.index());
},
// Tests if @win belongs to this workspace and monitor // Tests if @win belongs to this workspace and monitor
_isMyWindow : function (win) { _isMyWindow : function (win) {
return this._isWorkspaceWindow(win) && return Main.isWindowActorDisplayedOnWorkspace(win, this.metaWorkspace.index()) &&
(!win.get_meta_window() || win.get_meta_window().get_monitor() == this.monitorIndex); (!win.get_meta_window() || win.get_meta_window().get_monitor() == this.monitorIndex);
}, },
@ -397,17 +381,11 @@ const WorkspaceThumbnail = new Lang.Class({
let clone = new WindowClone(win); let clone = new WindowClone(win);
clone.connect('selected', clone.connect('selected',
Lang.bind(this, function(clone, time) { Lang.bind(this, this._activate));
this.activate(time);
}));
clone.connect('drag-begin', clone.connect('drag-begin',
Lang.bind(this, function(clone) { Lang.bind(this, function(clone) {
Main.overview.beginWindowDrag(); Main.overview.beginWindowDrag();
})); }));
clone.connect('drag-cancelled',
Lang.bind(this, function(clone) {
Main.overview.cancelledWindowDrag();
}));
clone.connect('drag-end', clone.connect('drag-end',
Lang.bind(this, function(clone) { Lang.bind(this, function(clone) {
Main.overview.endWindowDrag(); Main.overview.endWindowDrag();
@ -424,7 +402,7 @@ const WorkspaceThumbnail = new Lang.Class({
return clone; return clone;
}, },
activate : function (time) { _activate : function (clone, time) {
if (this.state > ThumbnailState.NORMAL) if (this.state > ThumbnailState.NORMAL)
return; return;
@ -435,8 +413,8 @@ const WorkspaceThumbnail = new Lang.Class({
this.metaWorkspace.activate(time); this.metaWorkspace.activate(time);
}, },
// Draggable target interface used only by ThumbnailsBox // Draggable target interface
handleDragOverInternal : function(source, time) { handleDragOver : function(source, actor, x, y, time) {
if (source == Main.xdndHandler) { if (source == Main.xdndHandler) {
this.metaWorkspace.activate(time); this.metaWorkspace.activate(time);
return DND.DragMotionResult.CONTINUE; return DND.DragMotionResult.CONTINUE;
@ -445,6 +423,11 @@ const WorkspaceThumbnail = new Lang.Class({
if (this.state > ThumbnailState.NORMAL) if (this.state > ThumbnailState.NORMAL)
return DND.DragMotionResult.CONTINUE; return DND.DragMotionResult.CONTINUE;
let [w, h] = this.actor.get_transformed_size();
// Bubble up if we're in the "workspace cut".
if (y < WORKSPACE_CUT_SIZE || y > h - WORKSPACE_CUT_SIZE)
return DND.DragMotionResult.CONTINUE;
if (source.realWindow && !this._isMyWindow(source.realWindow)) if (source.realWindow && !this._isMyWindow(source.realWindow))
return DND.DragMotionResult.MOVE_DROP; return DND.DragMotionResult.MOVE_DROP;
if (source.shellWorkspaceLaunch) if (source.shellWorkspaceLaunch)
@ -453,7 +436,7 @@ const WorkspaceThumbnail = new Lang.Class({
return DND.DragMotionResult.CONTINUE; return DND.DragMotionResult.CONTINUE;
}, },
acceptDropInternal : function(source, time) { acceptDrop : function(source, actor, x, y, time) {
if (this.state > ThumbnailState.NORMAL) if (this.state > ThumbnailState.NORMAL)
return false; return false;
@ -491,8 +474,7 @@ const ThumbnailsBox = new Lang.Class({
Name: 'ThumbnailsBox', Name: 'ThumbnailsBox',
_init: function() { _init: function() {
this.actor = new Shell.GenericContainer({ reactive: true, this.actor = new Shell.GenericContainer({ style_class: 'workspace-thumbnails',
style_class: 'workspace-thumbnails',
request_mode: Clutter.RequestMode.WIDTH_FOR_HEIGHT }); request_mode: Clutter.RequestMode.WIDTH_FOR_HEIGHT });
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));
@ -521,7 +503,6 @@ const ThumbnailsBox = new Lang.Class({
this._indicator = indicator; this._indicator = indicator;
this.actor.add_actor(indicator); this.actor.add_actor(indicator);
this._dropWorkspace = -1;
this._dropPlaceholderPos = -1; this._dropPlaceholderPos = -1;
this._dropPlaceholder = new St.Bin({ style_class: 'placeholder' }); this._dropPlaceholder = new St.Bin({ style_class: 'placeholder' });
this.actor.add_actor(this._dropPlaceholder); this.actor.add_actor(this._dropPlaceholder);
@ -538,187 +519,83 @@ const ThumbnailsBox = new Lang.Class({
this._stateCounts[ThumbnailState[key]] = 0; this._stateCounts[ThumbnailState[key]] = 0;
this._thumbnails = []; this._thumbnails = [];
this.actor.connect('button-press-event', function() { return true; });
this.actor.connect('button-release-event', Lang.bind(this, this._onButtonRelease));
Main.overview.connect('item-drag-begin',
Lang.bind(this, this._onDragBegin));
Main.overview.connect('item-drag-end',
Lang.bind(this, this._onDragEnd));
Main.overview.connect('item-drag-cancelled',
Lang.bind(this, this._onDragCancelled));
Main.overview.connect('window-drag-begin',
Lang.bind(this, this._onDragBegin));
Main.overview.connect('window-drag-end',
Lang.bind(this, this._onDragEnd));
Main.overview.connect('window-drag-cancelled',
Lang.bind(this, this._onDragCancelled));
},
_onButtonRelease: function(actor, event) {
let [stageX, stageY] = event.get_coords();
let [r, x, y] = this.actor.transform_stage_point(stageX, stageY);
for (let i = 0; i < this._thumbnails.length; i++) {
let thumbnail = this._thumbnails[i]
let [w, h] = thumbnail.actor.get_transformed_size();
if (y >= thumbnail.actor.y && y <= thumbnail.actor.y + h) {
thumbnail.activate(event.time);
break;
}
}
return true;
},
_onDragBegin: function() {
this._dragCancelled = false;
this._dragMonitor = {
dragMotion: Lang.bind(this, this._onDragMotion)
};
DND.addDragMonitor(this._dragMonitor);
},
_onDragEnd: function() {
if (this._dragCancelled)
return;
this._endDrag();
},
_onDragCancelled: function() {
this._dragCancelled = true;
this._endDrag();
},
_endDrag: function() {
this._clearDragPlaceholder();
DND.removeDragMonitor(this._dragMonitor);
},
_onDragMotion: function(dragEvent) {
if (!this.actor.contains(dragEvent.targetActor))
this._onLeave();
return DND.DragMotionResult.CONTINUE;
},
_onLeave: function() {
this._clearDragPlaceholder();
},
_clearDragPlaceholder: function() {
if (this._dropPlaceholderPos == -1)
return;
this._dropPlaceholderPos = -1;
this.actor.queue_relayout();
}, },
// Draggable target interface // Draggable target interface
handleDragOver : function(source, actor, x, y, time) { handleDragOver : function(source, actor, x, y, time) {
if (!source.realWindow && !source.shellWorkspaceLaunch && source != Main.xdndHandler) if (!source.realWindow && !source.shellWorkspaceLaunch)
return DND.DragMotionResult.CONTINUE;
if (!Meta.prefs_get_dynamic_workspaces())
return DND.DragMotionResult.CONTINUE; return DND.DragMotionResult.CONTINUE;
let spacing = this.actor.get_theme_node().get_length('spacing'); let spacing = this.actor.get_theme_node().get_length('spacing');
let thumbHeight = this._porthole.height * this._scale;
let workspace = -1;
let firstThumbY = this._thumbnails[0].actor.y;
for (let i = 0; i < this._thumbnails.length; i ++) {
let targetBase = firstThumbY + (thumbHeight + spacing) * i;
this._dropWorkspace = -1;
let placeholderPos = -1;
let targetBase;
if (this._dropPlaceholderPos == 0)
targetBase = this._dropPlaceholder.y;
else
targetBase = this._thumbnails[0].actor.y;
let targetTop = targetBase - spacing - WORKSPACE_CUT_SIZE;
let length = this._thumbnails.length;
for (let i = 0; i < length; i ++) {
// Allow the reorder target to have a 10px "cut" into // Allow the reorder target to have a 10px "cut" into
// each side of the thumbnail, to make dragging onto the // each side of the thumbnail, to make dragging onto the
// placeholder easier // placeholder easier
let [w, h] = this._thumbnails[i].actor.get_transformed_size(); let targetTop = targetBase - spacing - WORKSPACE_CUT_SIZE;
let targetBottom = targetBase + WORKSPACE_CUT_SIZE; let targetBottom = targetBase + WORKSPACE_CUT_SIZE;
let nextTargetBase = targetBase + h + spacing;
let nextTargetTop = nextTargetBase - spacing - ((i == length - 1) ? 0: WORKSPACE_CUT_SIZE);
// Expand the target to include the placeholder, if it exists. // Expand the target to include the placeholder, if it exists.
if (i == this._dropPlaceholderPos) if (i == this._dropPlaceholderPos)
targetBottom += this._dropPlaceholder.get_height(); targetBottom += this._dropPlaceholder.get_height();
if (y > targetTop && y <= targetBottom && source != Main.xdndHandler) { if (y > targetTop && y <= targetBottom) {
placeholderPos = i; workspace = i;
break; break;
} else if (y > targetBottom && y <= nextTargetTop) {
this._dropWorkspace = i;
break
} }
targetBase = nextTargetBase;
targetTop = nextTargetTop;
} }
if (this._dropPlaceholderPos != placeholderPos) { this._dropPlaceholderPos = workspace;
this._dropPlaceholderPos = placeholderPos; this.actor.queue_relayout();
this.actor.queue_relayout();
}
if (this._dropWorkspace != -1) if (workspace == -1)
return this._thumbnails[this._dropWorkspace].handleDragOverInternal(source, time);
else if (this._dropPlaceholderPos != -1)
return source.realWindow ? DND.DragMotionResult.MOVE_DROP : DND.DragMotionResult.COPY_DROP;
else
return DND.DragMotionResult.CONTINUE; return DND.DragMotionResult.CONTINUE;
return DND.DragMotionResult.MOVE_DROP;
}, },
acceptDrop: function(source, actor, x, y, time) { acceptDrop: function(source, actor, x, y, time) {
if (this._dropWorkspace != -1) { if (this._dropPlaceholderPos == -1)
return this._thumbnails[this._dropWorkspace].acceptDropInternal(source, time);
} else if (this._dropPlaceholderPos != -1) {
if (!source.realWindow && !source.shellWorkspaceLaunch)
return false;
let isWindow = !!source.realWindow;
// To create a new workspace, we first slide all the windows on workspaces
// below us to the next workspace, leaving a blank workspace for us to recycle.
let newWorkspaceIndex;
[newWorkspaceIndex, this._dropPlaceholderPos] = [this._dropPlaceholderPos, -1];
// Nab all the windows below us.
let windows = global.get_window_actors().filter(function(win) {
if (isWindow)
return win.get_workspace() >= newWorkspaceIndex && win != source;
else
return win.get_workspace() >= newWorkspaceIndex;
});
// ... move them down one.
windows.forEach(function(win) {
win.meta_window.change_workspace_by_index(win.get_workspace() + 1,
true, time);
});
if (isWindow)
// ... and bam, a workspace, good as new.
source.metaWindow.change_workspace_by_index(newWorkspaceIndex,
true, time);
else if (source.shellWorkspaceLaunch) {
source.shellWorkspaceLaunch({ workspace: newWorkspaceIndex,
timestamp: time });
// This new workspace will be automatically removed if the application fails
// to open its first window within some time, as tracked by Shell.WindowTracker.
// Here, we only add a very brief timeout to avoid the _immediate_ removal of the
// workspace while we wait for the startup sequence to load.
Main.keepWorkspaceAlive(global.screen.get_workspace_by_index(newWorkspaceIndex),
WORKSPACE_KEEP_ALIVE_TIME);
}
return true;
} else {
return false; return false;
}
if (!source.realWindow && !source.shellWorkspaceLaunch)
return false;
let isWindow = !!source.realWindow;
// To create a new workspace, we first slide all the windows on workspaces
// below us to the next workspace, leaving a blank workspace for us to recycle.
let newWorkspaceIndex;
[newWorkspaceIndex, this._dropPlaceholderPos] = [this._dropPlaceholderPos, -1];
// Nab all the windows below us.
let windows = global.get_window_actors().filter(function(win) {
if (isWindow)
return win.get_workspace() >= newWorkspaceIndex && win != source;
else
return win.get_workspace() >= newWorkspaceIndex;
});
// ... move them down one.
windows.forEach(function(win) {
win.meta_window.change_workspace_by_index(win.get_workspace() + 1,
true, time);
});
if (isWindow)
// ... and bam, a workspace, good as new.
source.metaWindow.change_workspace_by_index(newWorkspaceIndex,
true, time);
else if (source.shellWorkspaceLaunch)
source.shellWorkspaceLaunch({ workspace: newWorkspaceIndex,
timestamp: time });
return true;
}, },
show: function() { show: function() {
@ -793,10 +670,8 @@ const ThumbnailsBox = new Lang.Class({
if (thumbnail.state > ThumbnailState.NORMAL) if (thumbnail.state > ThumbnailState.NORMAL)
continue; continue;
if (currentPos >= start && currentPos < start + count) { if (currentPos >= start && currentPos < start + count)
thumbnail.workspaceRemoved();
this._setThumbnailState(thumbnail, ThumbnailState.REMOVING); this._setThumbnailState(thumbnail, ThumbnailState.REMOVING);
}
currentPos++; currentPos++;
} }
@ -985,7 +860,7 @@ const ThumbnailsBox = new Lang.Class({
}, },
_allocate: function(actor, box, flags) { _allocate: function(actor, box, flags) {
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL); let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
// See comment about this._background in _init() // See comment about this._background in _init()
let themeNode = this._background.get_theme_node(); let themeNode = this._background.get_theme_node();

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 Gio = imports.gi.Gio;
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;
@ -20,7 +19,6 @@ const WORKSPACE_SWITCH_TIME = 0.25;
// Note that mutter has a compile-time limit of 36 // Note that mutter has a compile-time limit of 36
const MAX_WORKSPACES = 16; const MAX_WORKSPACES = 16;
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
const CONTROLS_POP_IN_TIME = 0.1; const CONTROLS_POP_IN_TIME = 0.1;
@ -29,7 +27,7 @@ const WorkspacesView = new Lang.Class({
Name: 'WorkspacesView', Name: 'WorkspacesView',
_init: function(workspaces) { _init: function(workspaces) {
this.actor = new St.Widget({ style_class: 'workspaces-view' }); this.actor = new St.Group({ style_class: 'workspaces-view' });
// The actor itself isn't a drop target, so we don't want to pick on its area // The actor itself isn't a drop target, so we don't want to pick on its area
this.actor.set_size(0, 0); this.actor.set_size(0, 0);
@ -42,6 +40,8 @@ const WorkspacesView = new Lang.Class({
this._spacing = node.get_length('spacing'); this._spacing = node.get_length('spacing');
this._updateWorkspaceActors(false); this._updateWorkspaceActors(false);
})); }));
this.actor.connect('notify::mapped',
Lang.bind(this, this._onMappedChanged));
this._width = 0; this._width = 0;
this._height = 0; this._height = 0;
@ -59,11 +59,6 @@ const WorkspacesView = new Lang.Class({
this._zoomOut = false; // zoom to a larger area this._zoomOut = false; // zoom to a larger area
this._inDrag = false; // dragging a window this._inDrag = false; // dragging a window
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
this._updateExtraWorkspacesId =
this._settings.connect('changed::workspaces-only-on-primary',
Lang.bind(this, this._updateExtraWorkspaces));
let activeWorkspaceIndex = global.screen.get_active_workspace_index(); let activeWorkspaceIndex = global.screen.get_active_workspace_index();
this._workspaces = workspaces; this._workspaces = workspaces;
@ -72,7 +67,17 @@ const WorkspacesView = new Lang.Class({
this._workspaces[w].actor.reparent(this.actor); this._workspaces[w].actor.reparent(this.actor);
this._workspaces[activeWorkspaceIndex].actor.raise_top(); this._workspaces[activeWorkspaceIndex].actor.raise_top();
this._updateExtraWorkspaces(); this._extraWorkspaces = [];
let monitors = Main.layoutManager.monitors;
let m = 0;
for (let i = 0; i < monitors.length; i++) {
if (i == Main.layoutManager.primaryIndex)
continue;
let ws = new Workspace.Workspace(null, i);
this._extraWorkspaces[m++] = ws;
ws.setGeometry(monitors[i].x, monitors[i].y, monitors[i].width, monitors[i].height);
global.overlay_group.add_actor(ws.actor);
}
// Position/scale the desktop windows and their children after the // Position/scale the desktop windows and their children after the
// workspaces have been created. This cannot be done first because // workspaces have been created. This cannot be done first because
@ -83,8 +88,6 @@ const WorkspacesView = new Lang.Class({
Lang.bind(this, function() { Lang.bind(this, function() {
for (let w = 0; w < this._workspaces.length; w++) for (let w = 0; w < this._workspaces.length; w++)
this._workspaces[w].zoomToOverview(); this._workspaces[w].zoomToOverview();
if (!this._extraWorkspaces)
return;
for (let w = 0; w < this._extraWorkspaces.length; w++) for (let w = 0; w < this._extraWorkspaces.length; w++)
this._extraWorkspaces[w].zoomToOverview(); this._extraWorkspaces[w].zoomToOverview();
})); }));
@ -95,14 +98,14 @@ const WorkspacesView = new Lang.Class({
this._clipWidth, this._clipHeight); this._clipWidth, this._clipHeight);
})); }));
this.scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex, this._scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
lower: 0, lower: 0,
page_increment: 1, page_increment: 1,
page_size: 1, page_size: 1,
step_increment: 0, step_increment: 0,
upper: this._workspaces.length }); upper: this._workspaces.length });
this.scrollAdjustment.connect('notify::value', this._scrollAdjustment.connect('notify::value',
Lang.bind(this, this._onScroll)); Lang.bind(this, this._onScroll));
this._switchWorkspaceNotifyId = this._switchWorkspaceNotifyId =
global.window_manager.connect('switch-workspace', global.window_manager.connect('switch-workspace',
@ -116,35 +119,8 @@ const WorkspacesView = new Lang.Class({
Lang.bind(this, this._dragBegin)); Lang.bind(this, this._dragBegin));
this._windowDragEndId = Main.overview.connect('window-drag-end', this._windowDragEndId = Main.overview.connect('window-drag-end',
Lang.bind(this, this._dragEnd)); Lang.bind(this, this._dragEnd));
}, this._swipeScrollBeginId = 0;
this._swipeScrollEndId = 0;
_updateExtraWorkspaces: function() {
this._destroyExtraWorkspaces();
if (!this._settings.get_boolean('workspaces-only-on-primary'))
return;
this._extraWorkspaces = [];
let monitors = Main.layoutManager.monitors;
for (let i = 0; i < monitors.length; i++) {
if (i == Main.layoutManager.primaryIndex)
continue;
let ws = new Workspace.Workspace(null, i);
ws.setGeometry(monitors[i].x, monitors[i].y,
monitors[i].width, monitors[i].height);
global.overlay_group.add_actor(ws.actor);
this._extraWorkspaces.push(ws);
}
},
_destroyExtraWorkspaces: function() {
if (!this._extraWorkspaces)
return;
for (let m = 0; m < this._extraWorkspaces.length; m++)
this._extraWorkspaces[m].destroy();
this._extraWorkspaces = null;
}, },
setGeometry: function(x, y, width, height, spacing) { setGeometry: function(x, y, width, height, spacing) {
@ -181,6 +157,10 @@ const WorkspacesView = new Lang.Class({
return this._workspaces[active]; return this._workspaces[active];
}, },
getWorkspaceByIndex: function(index) {
return this._workspaces[index];
},
hide: function() { hide: function() {
let activeWorkspaceIndex = global.screen.get_active_workspace_index(); let activeWorkspaceIndex = global.screen.get_active_workspace_index();
let activeWorkspace = this._workspaces[activeWorkspaceIndex]; let activeWorkspace = this._workspaces[activeWorkspaceIndex];
@ -191,8 +171,6 @@ const WorkspacesView = new Lang.Class({
for (let w = 0; w < this._workspaces.length; w++) for (let w = 0; w < this._workspaces.length; w++)
this._workspaces[w].zoomFromOverview(); this._workspaces[w].zoomFromOverview();
if (!this._extraWorkspaces)
return;
for (let w = 0; w < this._extraWorkspaces.length; w++) for (let w = 0; w < this._extraWorkspaces.length; w++)
this._extraWorkspaces[w].zoomFromOverview(); this._extraWorkspaces[w].zoomFromOverview();
}, },
@ -204,8 +182,6 @@ const WorkspacesView = new Lang.Class({
syncStacking: function(stackIndices) { syncStacking: function(stackIndices) {
for (let i = 0; i < this._workspaces.length; i++) for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].syncStacking(stackIndices); this._workspaces[i].syncStacking(stackIndices);
if (!this._extraWorkspaces)
return;
for (let i = 0; i < this._extraWorkspaces.length; i++) for (let i = 0; i < this._extraWorkspaces.length; i++)
this._extraWorkspaces[i].syncStacking(stackIndices); this._extraWorkspaces[i].syncStacking(stackIndices);
}, },
@ -267,8 +243,10 @@ const WorkspacesView = new Lang.Class({
for (let w = 0; w < this._workspaces.length; w++) { for (let w = 0; w < this._workspaces.length; w++) {
let workspace = this._workspaces[w]; let workspace = this._workspaces[w];
if (this._animating || this._scrolling) { if (this._animating || this._scrolling) {
workspace.hideWindowsOverlays();
workspace.actor.show(); workspace.actor.show();
} else { } else {
workspace.showWindowsOverlays();
if (this._inDrag) if (this._inDrag)
workspace.actor.visible = (Math.abs(w - active) <= 1); workspace.actor.visible = (Math.abs(w - active) <= 1);
else else
@ -284,7 +262,7 @@ const WorkspacesView = new Lang.Class({
this._animatingScroll = true; this._animatingScroll = true;
if (showAnimation) { if (showAnimation) {
Tweener.addTween(this.scrollAdjustment, { Tweener.addTween(this._scrollAdjustment, {
value: index, value: index,
time: WORKSPACE_SWITCH_TIME, time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad', transition: 'easeOutQuad',
@ -294,7 +272,7 @@ const WorkspacesView = new Lang.Class({
}) })
}); });
} else { } else {
this.scrollAdjustment.value = index; this._scrollAdjustment.value = index;
this._animatingScroll = false; this._animatingScroll = false;
} }
}, },
@ -302,7 +280,7 @@ const WorkspacesView = new Lang.Class({
updateWorkspaces: function(oldNumWorkspaces, newNumWorkspaces) { updateWorkspaces: function(oldNumWorkspaces, newNumWorkspaces) {
let active = global.screen.get_active_workspace_index(); let active = global.screen.get_active_workspace_index();
Tweener.addTween(this.scrollAdjustment, Tweener.addTween(this._scrollAdjustment,
{ upper: newNumWorkspaces, { upper: newNumWorkspaces,
time: WORKSPACE_SWITCH_TIME, time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad' transition: 'easeOutQuad'
@ -329,12 +307,12 @@ const WorkspacesView = new Lang.Class({
}, },
_onDestroy: function() { _onDestroy: function() {
this._destroyExtraWorkspaces(); for (let i = 0; i < this._extraWorkspaces.length; i++)
this.scrollAdjustment.run_dispose(); this._extraWorkspaces[i].destroy();
this._scrollAdjustment.run_dispose();
Main.overview.disconnect(this._overviewShowingId); Main.overview.disconnect(this._overviewShowingId);
Main.overview.disconnect(this._overviewShownId); Main.overview.disconnect(this._overviewShownId);
global.window_manager.disconnect(this._switchWorkspaceNotifyId); global.window_manager.disconnect(this._switchWorkspaceNotifyId);
this._settings.disconnect(this._updateExtraWorkspacesId);
if (this._inDrag) if (this._inDrag)
this._dragEnd(); this._dragEnd();
@ -357,6 +335,21 @@ const WorkspacesView = new Lang.Class({
} }
}, },
_onMappedChanged: function() {
if (this.actor.mapped) {
let direction = Overview.SwipeScrollDirection.VERTICAL;
Main.overview.setScrollAdjustment(this._scrollAdjustment,
direction);
this._swipeScrollBeginId = Main.overview.connect('swipe-scroll-begin',
Lang.bind(this, this._swipeScrollBegin));
this._swipeScrollEndId = Main.overview.connect('swipe-scroll-end',
Lang.bind(this, this._swipeScrollEnd));
} else {
Main.overview.disconnect(this._swipeScrollBeginId);
Main.overview.disconnect(this._swipeScrollEndId);
}
},
_dragBegin: function() { _dragBegin: function() {
if (this._scrolling) if (this._scrolling)
return; return;
@ -378,9 +371,6 @@ const WorkspacesView = new Lang.Class({
this._firstDragMotion = false; this._firstDragMotion = false;
for (let i = 0; i < this._workspaces.length; i++) for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setReservedSlot(dragEvent.dragActor._delegate); this._workspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
if (!this._extraWorkspaces)
return DND.DragMotionResult.CONTINUE;
for (let i = 0; i < this._extraWorkspaces.length; i++) for (let i = 0; i < this._extraWorkspaces.length; i++)
this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate); this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
} }
@ -394,18 +384,15 @@ const WorkspacesView = new Lang.Class({
for (let i = 0; i < this._workspaces.length; i++) for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setReservedSlot(null); this._workspaces[i].setReservedSlot(null);
if (!this._extraWorkspaces)
return;
for (let i = 0; i < this._extraWorkspaces.length; i++) for (let i = 0; i < this._extraWorkspaces.length; i++)
this._extraWorkspaces[i].setReservedSlot(null); this._extraWorkspaces[i].setReservedSlot(null);
}, },
startSwipeScroll: function() { _swipeScrollBegin: function() {
this._scrolling = true; this._scrolling = true;
}, },
endSwipeScroll: function(result) { _swipeScrollEnd: function(overview, result) {
this._scrolling = false; this._scrolling = false;
if (result == Overview.SwipeScrollResult.CLICK) { if (result == Overview.SwipeScrollResult.CLICK) {
@ -454,6 +441,7 @@ const WorkspacesView = new Lang.Class({
let dy = newY - currentY; let dy = newY - currentY;
for (let i = 0; i < this._workspaces.length; i++) { for (let i = 0; i < this._workspaces.length; i++) {
this._workspaces[i].hideWindowsOverlays();
this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1; this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
this._workspaces[i].actor.y += dy; this._workspaces[i].actor.y += dy;
} }
@ -474,8 +462,6 @@ const WorkspacesDisplay = 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('notify::mapped', Lang.bind(this, this._setupSwipeScrolling));
this.actor.connect('parent-set', Lang.bind(this, this._parentSet));
this.actor.set_clip_to_allocation(true); this.actor.set_clip_to_allocation(true);
let controls = new St.Bin({ style_class: 'workspace-controls', let controls = new St.Bin({ style_class: 'workspace-controls',
@ -492,32 +478,22 @@ const WorkspacesDisplay = new Lang.Class({
controls.connect('scroll-event', controls.connect('scroll-event',
Lang.bind(this, this._onScrollEvent)); Lang.bind(this, this._onScrollEvent));
this._primaryIndex = Main.layoutManager.primaryIndex; this._monitorIndex = Main.layoutManager.primaryIndex;
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox(); this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
controls.add_actor(this._thumbnailsBox.actor); controls.add_actor(this._thumbnailsBox.actor);
this._workspacesViews = null; this.workspacesView = null;
this._primaryScrollAdjustment = null;
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
this._settings.connect('changed::workspaces-only-on-primary',
Lang.bind(this,
this._workspacesOnlyOnPrimaryChanged));
this._workspacesOnlyOnPrimaryChanged();
this._inDrag = false; this._inDrag = false;
this._cancelledDrag = false; this._cancelledDrag = false;
this._controlsInitiallyHovered = false;
this._alwaysZoomOut = false; this._alwaysZoomOut = false;
this._zoomOut = false; this._zoomOut = false;
this._zoomFraction = 0; this._zoomFraction = 0;
this._updateAlwaysZoom(); this._updateAlwaysZoom();
// If we stop hiding the overview on layout changes, we will need to
// update the _workspacesViews here
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom)); Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom));
Main.xdndHandler.connect('drag-begin', Lang.bind(this, function(){ Main.xdndHandler.connect('drag-begin', Lang.bind(this, function(){
@ -538,25 +514,9 @@ const WorkspacesDisplay = new Lang.Class({
this._windowDragBeginId = 0; this._windowDragBeginId = 0;
this._windowDragCancelledId = 0; this._windowDragCancelledId = 0;
this._windowDragEndId = 0; this._windowDragEndId = 0;
this._notifyOpacityId = 0;
this._swipeScrollBeginId = 0;
this._swipeScrollEndId = 0;
}, },
show: function() { show: function() {
if(!this._alwaysZoomOut) {
let [mouseX, mouseY] = global.get_pointer();
let [x, y] = this._controls.get_transformed_position();
let [width, height] = this._controls.get_transformed_size();
let visibleWidth = this._controls.get_theme_node().get_length('visible-width');
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
if(rtl)
x = x + width - visibleWidth;
if(mouseX > x - 0.5 && mouseX < x + visibleWidth + 0.5 &&
mouseY > y - 0.5 && mouseY < y + height + 0.5)
this._controlsInitiallyHovered = true;
}
this._zoomOut = this._alwaysZoomOut; this._zoomOut = this._alwaysZoomOut;
this._zoomFraction = this._alwaysZoomOut ? 1 : 0; this._zoomFraction = this._alwaysZoomOut ? 1 : 0;
this._updateZoom(); this._updateZoom();
@ -564,7 +524,16 @@ const WorkspacesDisplay = new Lang.Class({
this._controls.show(); this._controls.show();
this._thumbnailsBox.show(); this._thumbnailsBox.show();
this._updateWorkspacesViews(); this._workspaces = [];
for (let i = 0; i < global.screen.n_workspaces; i++) {
let metaWorkspace = global.screen.get_workspace_by_index(i);
this._workspaces[i] = new Workspace.Workspace(metaWorkspace, this._monitorIndex);
}
if (this.workspacesView)
this.workspacesView.destroy();
this.workspacesView = new WorkspacesView(this._workspaces);
this._updateWorkspacesGeometry();
this._restackedNotifyId = this._restackedNotifyId =
global.screen.connect('restacked', global.screen.connect('restacked',
@ -595,19 +564,10 @@ const WorkspacesDisplay = new Lang.Class({
this._onRestacked(); this._onRestacked();
}, },
zoomFromOverview: function() {
for (let i = 0; i < this._workspacesViews.length; i++) {
this._workspacesViews[i].hide();
}
},
hide: function() { hide: function() {
this._controls.hide(); this._controls.hide();
this._thumbnailsBox.hide(); this._thumbnailsBox.hide();
if (!this._alwaysZoomOut)
this.zoomFraction = 0;
if (this._restackedNotifyId > 0){ if (this._restackedNotifyId > 0){
global.screen.disconnect(this._restackedNotifyId); global.screen.disconnect(this._restackedNotifyId);
this._restackedNotifyId = 0; this._restackedNotifyId = 0;
@ -637,120 +597,12 @@ const WorkspacesDisplay = new Lang.Class({
this._windowDragEndId = 0; this._windowDragEndId = 0;
} }
for (let i = 0; i < this._workspacesViews.length; i++) this.workspacesView.destroy();
this._workspacesViews[i].destroy(); this.workspacesView = null;
this._workspacesViews = null; for (let w = 0; w < this._workspaces.length; w++) {
this._workspaces[w].disconnectAll();
for (let i = 0; i < this._workspaces.length; i++) this._workspaces[w].destroy();
for (let w = 0; w < this._workspaces[i].length; w++) {
this._workspaces[i][w].disconnectAll();
this._workspaces[i][w].destroy();
}
},
_setupSwipeScrolling: function() {
if (this._swipeScrollBeginId)
Main.overview.disconnect(this._swipeScrollBeginId);
this._swipeScrollBeginId = 0;
if (this._swipeScrollEndId)
Main.overview.disconnect(this._swipeScrollEndId);
this._swipeScrollEndId = 0;
if (!this.actor.mapped)
return;
let direction = Overview.SwipeScrollDirection.VERTICAL;
Main.overview.setScrollAdjustment(this._scrollAdjustment,
direction);
this._swipeScrollBeginId = Main.overview.connect('swipe-scroll-begin',
Lang.bind(this, function() {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].startSwipeScroll();
}));
this._swipeScrollEndId = Main.overview.connect('swipe-scroll-end',
Lang.bind(this, function(overview, result) {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].endSwipeScroll(result);
}));
},
_workspacesOnlyOnPrimaryChanged: function() {
this._workspacesOnlyOnPrimary = this._settings.get_boolean('workspaces-only-on-primary');
if (!Main.overview.visible)
return;
this._updateWorkspacesViews();
},
_updateWorkspacesViews: function() {
if (this._workspacesViews)
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].destroy();
if (this._workspaces)
for (let i = 0; i < this._workspaces.length; i++)
for (let w = 0; w < this._workspaces[i].length; w++)
this._workspaces[i][w].destroy();
this._workspacesViews = [];
this._workspaces = [];
let monitors = Main.layoutManager.monitors;
for (let i = 0; i < monitors.length; i++) {
if (this._workspacesOnlyOnPrimary && i != this._primaryIndex)
continue; // we are only interested in the primary monitor
let monitorWorkspaces = [];
for (let w = 0; w < global.screen.n_workspaces; w++) {
let metaWorkspace = global.screen.get_workspace_by_index(w);
monitorWorkspaces.push(new Workspace.Workspace(metaWorkspace, i));
}
this._workspaces.push(monitorWorkspaces);
let view = new WorkspacesView(monitorWorkspaces);
if (this._workspacesOnlyOnPrimary || i == this._primaryIndex) {
this._scrollAdjustment = view.scrollAdjustment;
this._scrollAdjustment.connect('notify::value',
Lang.bind(this, this._scrollValueChanged));
this._setupSwipeScrolling();
}
this._workspacesViews.push(view);
} }
this._updateWorkspacesGeometry();
for (let i = 0; i < this._workspacesViews.length; i++)
global.overlay_group.add_actor(this._workspacesViews[i].actor);
},
_scrollValueChanged: function() {
if (this._workspacesOnlyOnPrimary)
return;
for (let i = 0; i < this._workspacesViews.length; i++) {
if (i == this._primaryIndex)
continue;
let adjustment = this._workspacesViews[i].scrollAdjustment;
// the adjustments work in terms of workspaces, so the
// values map directly
adjustment.value = this._scrollAdjustment.value;
}
},
_getPrimaryView: function() {
if (!this._workspacesViews)
return null;
if (this._workspacesOnlyOnPrimary)
return this._workspacesViews[0];
else
return this._workspacesViews[this._primaryIndex];
},
activeWorkspaceHasMaximizedWindows: function() {
return this._getPrimaryView().getActiveWorkspace().hasMaximizedWindows();
}, },
// zoomFraction property allows us to tween the controls sliding in and out // zoomFraction property allows us to tween the controls sliding in and out
@ -807,7 +659,7 @@ const WorkspacesDisplay = new Lang.Class({
let controlsVisible = this._controls.get_theme_node().get_length('visible-width'); let controlsVisible = this._controls.get_theme_node().get_length('visible-width');
let controlsReserved = controlsVisible * (1 - this._zoomFraction) + controlsNatural * this._zoomFraction; let controlsReserved = controlsVisible * (1 - this._zoomFraction) + controlsNatural * this._zoomFraction;
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL); let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
if (rtl) { if (rtl) {
childBox.x2 = controlsReserved; childBox.x2 = controlsReserved;
childBox.x1 = childBox.x2 - controlsNatural; childBox.x1 = childBox.x2 - controlsNatural;
@ -823,34 +675,8 @@ const WorkspacesDisplay = new Lang.Class({
this._updateWorkspacesGeometry(); this._updateWorkspacesGeometry();
}, },
_parentSet: function(actor, oldParent) {
if (oldParent && this._notifyOpacityId)
oldParent.disconnect(this._notifyOpacityId);
this._notifyOpacityId = 0;
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
function() {
let newParent = this.actor.get_parent();
if (!newParent)
return;
// This is kinda hackish - we want the primary view to
// appear as parent of this.actor, though in reality it
// is added directly to overlay_group
this._notifyOpacityId = newParent.connect('notify::opacity',
Lang.bind(this, function() {
let opacity = this.actor.get_parent().opacity;
let primaryView = this._getPrimaryView();
if (!primaryView)
return;
primaryView.actor.opacity = opacity;
primaryView.actor.visible = opacity != 0;
}));
}));
},
_updateWorkspacesGeometry: function() { _updateWorkspacesGeometry: function() {
if (!this._workspacesViews) if (!this.workspacesView)
return; return;
let fullWidth = this.actor.allocation.x2 - this.actor.allocation.x1; let fullWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
@ -864,13 +690,15 @@ const WorkspacesDisplay = new Lang.Class({
let [x, y] = this.actor.get_transformed_position(); let [x, y] = this.actor.get_transformed_position();
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL); let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
let clipWidth = width - controlsVisible; let clipWidth = width - controlsVisible;
let clipHeight = (fullHeight / fullWidth) * clipWidth; let clipHeight = (fullHeight / fullWidth) * clipWidth;
let clipX = rtl ? x + controlsVisible : x; let clipX = rtl ? x + controlsVisible : x;
let clipY = y + (fullHeight - clipHeight) / 2; let clipY = y + (fullHeight - clipHeight) / 2;
this.workspacesView.setClipRect(clipX, clipY, clipWidth, clipHeight);
if (this._zoomOut) { if (this._zoomOut) {
width -= controlsNatural; width -= controlsNatural;
if (rtl) if (rtl)
@ -885,28 +713,7 @@ const WorkspacesDisplay = new Lang.Class({
let difference = fullHeight - height; let difference = fullHeight - height;
y += difference / 2; y += difference / 2;
this.workspacesView.setGeometry(x, y, width, height, difference);
let monitors = Main.layoutManager.monitors;
let m = 0;
for (let i = 0; i < monitors.length; i++) {
if (i == this._primaryIndex) {
this._workspacesViews[m].setClipRect(clipX, clipY,
clipWidth, clipHeight);
this._workspacesViews[m].setGeometry(x, y, width, height,
difference);
m++;
} else if (!this._workspacesOnlyOnPrimary) {
this._workspacesViews[m].setClipRect(monitors[i].x,
monitors[i].y,
monitors[i].width,
monitors[i].height);
this._workspacesViews[m].setGeometry(monitors[i].x,
monitors[i].y,
monitors[i].width,
monitors[i].height, 0);
m++;
}
}
}, },
_onRestacked: function() { _onRestacked: function() {
@ -918,14 +725,12 @@ const WorkspacesDisplay = new Lang.Class({
stackIndices[stack[i].get_meta_window().get_stable_sequence()] = i; stackIndices[stack[i].get_meta_window().get_stable_sequence()] = i;
} }
for (let i = 0; i < this._workspacesViews.length; i++) this.workspacesView.syncStacking(stackIndices);
this._workspacesViews[i].syncStacking(stackIndices);
this._thumbnailsBox.syncStacking(stackIndices); this._thumbnailsBox.syncStacking(stackIndices);
}, },
_workspacesChanged: function() { _workspacesChanged: function() {
let oldNumWorkspaces = this._workspaces[0].length; let oldNumWorkspaces = this._workspaces.length;
let newNumWorkspaces = global.screen.n_workspaces; let newNumWorkspaces = global.screen.n_workspaces;
let active = global.screen.get_active_workspace_index(); let active = global.screen.get_active_workspace_index();
@ -935,24 +740,15 @@ const WorkspacesDisplay = new Lang.Class({
this._updateAlwaysZoom(); this._updateAlwaysZoom();
this._updateZoom(); this._updateZoom();
if (this._workspacesViews == null) if (this.workspacesView == null)
return; return;
let lostWorkspaces = []; let lostWorkspaces = [];
if (newNumWorkspaces > oldNumWorkspaces) { if (newNumWorkspaces > oldNumWorkspaces) {
let monitors = Main.layoutManager.monitors; // Assume workspaces are only added at the end
let m = 0; for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
for (let i = 0; i < monitors.length; i++) { let metaWorkspace = global.screen.get_workspace_by_index(w);
if (this._workspacesOnlyOnPrimaryChanged && this._workspaces[w] = new Workspace.Workspace(metaWorkspace, this._monitorIndex);
i != this._primaryIndex)
continue;
// Assume workspaces are only added at the end
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
let metaWorkspace = global.screen.get_workspace_by_index(w);
this._workspaces[m++][w] =
new Workspace.Workspace(metaWorkspace, i);
}
} }
this._thumbnailsBox.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces); this._thumbnailsBox.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces);
@ -963,28 +759,25 @@ const WorkspacesDisplay = new Lang.Class({
let removedNum = oldNumWorkspaces - newNumWorkspaces; let removedNum = oldNumWorkspaces - newNumWorkspaces;
for (let w = 0; w < oldNumWorkspaces; w++) { for (let w = 0; w < oldNumWorkspaces; w++) {
let metaWorkspace = global.screen.get_workspace_by_index(w); let metaWorkspace = global.screen.get_workspace_by_index(w);
if (this._workspaces[0][w].metaWorkspace != metaWorkspace) { if (this._workspaces[w].metaWorkspace != metaWorkspace) {
removedIndex = w; removedIndex = w;
break; break;
} }
} }
for (let i = 0; i < this._workspaces.length; i++) { lostWorkspaces = this._workspaces.splice(removedIndex,
lostWorkspaces = this._workspaces[i].splice(removedIndex, removedNum);
removedNum);
for (let l = 0; l < lostWorkspaces.length; l++) { for (let l = 0; l < lostWorkspaces.length; l++) {
lostWorkspaces[l].disconnectAll(); lostWorkspaces[l].disconnectAll();
lostWorkspaces[l].destroy(); lostWorkspaces[l].destroy();
}
} }
this._thumbnailsBox.removeThumbmails(removedIndex, removedNum); this._thumbnailsBox.removeThumbmails(removedIndex, removedNum);
} }
for (let i = 0; i < this._workspacesViews.length; i++) this.workspacesView.updateWorkspaces(oldNumWorkspaces,
this._workspacesViews[i].updateWorkspaces(oldNumWorkspaces, newNumWorkspaces);
newNumWorkspaces);
}, },
_updateZoom : function() { _updateZoom : function() {
@ -996,7 +789,7 @@ const WorkspacesDisplay = new Lang.Class({
this._zoomOut = shouldZoom; this._zoomOut = shouldZoom;
this._updateWorkspacesGeometry(); this._updateWorkspacesGeometry();
if (!this._workspacesViews) if (!this.workspacesView)
return; return;
Tweener.addTween(this, Tweener.addTween(this,
@ -1004,16 +797,12 @@ const WorkspacesDisplay = new Lang.Class({
time: WORKSPACE_SWITCH_TIME, time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad' }); transition: 'easeOutQuad' });
for (let i = 0; i < this._workspacesViews.length; i++) this.workspacesView.updateWindowPositions();
this._workspacesViews[i].updateWindowPositions();
} }
}, },
_onControlsHoverChanged: function() { _onControlsHoverChanged: function() {
if(!this._controls.hover) this._updateZoom();
this._controlsInitiallyHovered = false;
if(!this._controlsInitiallyHovered)
this._updateZoom();
}, },
_dragBegin: function() { _dragBegin: function() {

View File

@ -17,7 +17,6 @@ const XdndHandler = new Lang.Class({
// Used as a drag actor in case we don't have a cursor window clone // Used as a drag actor in case we don't have a cursor window clone
this._dummy = new Clutter.Rectangle({ width: 1, height: 1, opacity: 0 }); this._dummy = new Clutter.Rectangle({ width: 1, height: 1, opacity: 0 });
global.stage.add_actor(this._dummy); global.stage.add_actor(this._dummy);
Shell.util_set_hidden_from_pick(this._dummy, true);
this._dummy.hide(); this._dummy.hide();
// Mutter delays the creation of the output window as long // Mutter delays the creation of the output window as long
@ -113,11 +112,10 @@ const XdndHandler = new Lang.Class({
while (pickedActor) { while (pickedActor) {
if (pickedActor._delegate && pickedActor._delegate.handleDragOver) { if (pickedActor._delegate && pickedActor._delegate.handleDragOver) {
let [r, targX, targY] = pickedActor.transform_stage_point(x, y);
let result = pickedActor._delegate.handleDragOver(this, let result = pickedActor._delegate.handleDragOver(this,
dragEvent.dragActor, dragEvent.dragActor,
targX, x,
targY, y,
global.get_current_time()); global.get_current_time());
if (result != DND.DragMotionResult.CONTINUE) if (result != DND.DragMotionResult.CONTINUE)
return; return;

View File

@ -30,14 +30,11 @@ hu
id id
it it
ja ja
kk
kn
ko ko
kn
ku ku
lt lt
lv lv
ml
mk
mr mr
ms ms
nb nb
@ -50,7 +47,6 @@ pt
pt_BR pt_BR
ro ro
ru ru
si
sk sk
sl sl
sr sr

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