Compare commits

..

34 Commits
3.1.4 ... 3.0.2

Author SHA1 Message Date
73f7991264 Bump version to 3.0.2
Update NEWS
2011-05-25 15:26:34 -04:00
976f26cb26 StTextureCache: Fix leak of key string
Also micro-optimize by avoiding another strdup(), instead pass
ownership of the string when we can.

https://bugzilla.gnome.org/show_bug.cgi?id=649508
2011-05-25 14:17:07 -04:00
1278e31b65 StTextureCache: plug leak in not-found icon case
Need to free the key too.

https://bugzilla.gnome.org/show_bug.cgi?id=649508
2011-05-25 14:16:29 -04:00
92f27a3c00 st-scroll-view: remove spurious assignment of uninitialized data
https://bugzilla.gnome.org/show_bug.cgi?id=649596
2011-05-25 14:12:25 -04:00
28667a686d workspace: Use Main.uiGroup instead of global.stage
The mouse-wheel zoom "easter egg" broke when using the magnifier
because it was using global.stage. Fix it to use Main.uiGroup instead.

https://bugzilla.gnome.org/show_bug.cgi?id=649632
2011-05-25 14:12:19 -04:00
783683a12c workspacesView: Don't change opacity during dnd
We used used to indicate to the user the ability to move to another workspace
during dnd by highligthing the adjacent workspaces on hover.

This was done by changing the workspace's opacity to 200 and set it to
255 for the highlighted adjacent ones.

This is now no longer needed as the design was completely changed since
then (overview relayout; we no longer represent workspaces in the way
we did before) and introduces a bug where we don't properly reset the
opacity after the drag action, so just remove that code.

https://bugzilla.gnome.org/show_bug.cgi?id=648983
2011-05-25 14:12:11 -04:00
fc70446050 history: Fix navigation when entering a repeat
If the user typed "a", hit up, and pressed enter again, we wouldn't re-set the
history pointer to the end, so the broken navigation would instead go to the
entry before that.

https://bugzilla.gnome.org/show_bug.cgi?id=648765
2011-05-25 14:12:01 -04:00
70ab08aefd workspace: End zooming when starting a window drag
The mouse-wheel zooming "easter egg" breaks horribly when you
drag a window, due to ugly lightbox reparenting tricks it uses.

For now, just end any zoom before we drag the window around.

https://bugzilla.gnome.org/show_bug.cgi?id=649632
2011-05-25 14:11:52 -04:00
ca6308ae64 shell-app: Fix a case where last_user_time isn't updated.
When activating an uninteresting window, the last_user_time isn't updated,
because we aren't tracking the window that the user_time gets updated on.
Hack around this by setting the last_user_time in shell_app_activate when
activating an uninteresting window.

https://bugzilla.gnome.org/show_bug.cgi?id=643302
2011-05-25 14:11:46 -04:00
4dcbb84f06 network: fix modem connected state check
There is no CONNECTED state for devices, it's ACTIVATED.

https://bugzilla.gnome.org/show_bug.cgi?id=650124
2011-05-25 14:11:40 -04:00
f4e6f7074e panel: Don't propagate button-release-event in _onCornerClicked()
Since both the hot corner's ClutterGroup and the hot corner's
ClutterRectangle button-release-event is connected to
_onCornerClicked() we must handle it there by returning 'true' to
Clutter or else _onCornerClicked() is called twice which defeats the
HOT_CORNER_ACTIVATION_TIMEOUT logic.

https://bugzilla.gnome.org/show_bug.cgi?id=649427
2011-05-25 14:11:17 -04:00
0d92f2b0c5 telepathyClient: don't update notifications for outgoing messages
If you receive a message, a notification will appear. If you reply in
Empathy's chat window before the notification disappears, the
notification is updated with the contents of the message you *just*
sent! We should only update notifications if they're incoming.

https://bugzilla.gnome.org/show_bug.cgi?id=650219

Signed-off-by: Jonny Lamb <jonnylamb@gnome.org>
2011-05-25 14:11:13 -04:00
2afb4cc124 PopupSliderMenuItem: intercept clicks outside the slider
Connect to button-press-event on the menu item actor, not on the
slider, so any part that is highlighted is also clicked. This means
that click on the left of the volume slider is a rapid way to mute.

https://bugzilla.gnome.org/show_bug.cgi?id=646660
2011-05-25 14:11:09 -04:00
762b0e45e0 network: request that nm-applet show the mobile broadband wizard
Use nm-applet 0.8.999 API to call the mobile broadband wizard and
activate the new connection.

Fixes https://bugzilla.gnome.org/show_bug.cgi?id=649318
2011-05-25 14:10:45 -04:00
a7acd3b535 network: fix initial connections to WPA[2] Enterprise APs
Call out to nm-applet to do the dirty work since the dialog of
doom is pretty complicated and we don't have a JS equivalent
of it for now.

Fixes https://bugzilla.gnome.org/show_bug.cgi?id=648171
2011-05-25 14:10:24 -04:00
ccc4b20e83 network: fix handling of AP flags and enhance for 802.1x
All WPA APs were getting set as WPA2 due to the check for privacy;
WPA/WPA2 APs *must* set the Privacy bit according to the standard,
so we'd never end up in the case for NMAccessPointSecurity.WPA.

Fix that, and also add flags for WPA[2] Enterprise which we'll
use a bit later for the first-time connect case for 802.1x enabled
access points.
2011-05-25 14:08:22 -04:00
8dd45bea1c network: simplify connection sorting by using libnm-glib functions
Instead of rolling our own code, use new libnm-glib functions to do
the same thing.  Requires libnm-glib as of
779215c742bbe29a2c66202ec7e2e6d43edeb8ff (which will be part of 0.9).

Fixes https://bugzilla.gnome.org/show_bug.cgi?id=648648
2011-05-25 14:08:19 -04:00
0c80f8cec4 Updated Irish translation. 2011-05-23 02:09:38 -06:00
27508864bf vi.po: new translation for "dash" 2011-05-22 21:50:39 +07:00
117be3b14d Updated Irish translation. 2011-05-22 04:35:00 -06:00
4bc2f9b5e6 Updated Persian translation 2011-05-17 00:54:40 +04:30
ba5c45deaf st-private: Correct fix for memory leak
The previous fix in 72f9f482d was wrong; we need to keep around
the buffer until cairo is done with the pattern.

https://bugzilla.gnome.org/show_bug.cgi?id=649497
2011-05-12 14:44:10 -04:00
941246a4f0 st-private: Fix memory leak
==13810== 11,360 bytes in 1 blocks are definitely lost in loss record 18,574 of 18,765
==13810==    at 0x4005447: calloc (vg_replace_malloc.c:467)
==13810==    by 0x5191882: standard_calloc (gmem.c:107)
==13810==    by 0x51920A7: g_malloc0 (gmem.c:196)
==13810==    by 0x4056201: blur_pixels (st-private.c:466)
==13810==    by 0x40573B4: _st_create_shadow_cairo_pattern (st-private.c:710)
==13810==    by 0x4070746: st_theme_node_paint (st-theme-node-drawing.c:856)
==13810==    by 0x3FEFFFFF: ???

https://bugzilla.gnome.org/show_bug.cgi?id=649497
2011-05-12 14:44:07 -04:00
7feef56656 shell-xfixes-cursor: missing XFree
memory returned by XFixesGetCursorImage should be freed after usage.
https://bugzilla.gnome.org/show_bug.cgi?id=642652
2011-05-12 14:24:34 -04:00
9a2a07f32a Updated Norwegian bokmål translation from Sigurd Gartmann 2011-05-11 22:49:11 +02:00
af9594c902 Finnish date/time fixes from Marko Myllynen. Full usage however depends on getting bugs #647320 / #648678 in g_date_time_format fixed. 2011-05-05 18:04:51 +03:00
569008b084 appDisplay: Fix off-by-one when incrementally adding application icons
A "cosmetic" code arrangement I requested in code review resulted
in one too few items being removed from the queue for each incremental
chunk of icons added. Fix.

https://bugzilla.gnome.org/show_bug.cgi?id=648739
2011-05-03 08:53:08 -04:00
0e086563bc Added UG translation 2011-05-02 18:45:55 +02:00
91d4a832ad Added UG translation 2011-05-02 18:44:55 +02:00
832ce362f0 Added UG translation 2011-05-02 18:40:46 +02:00
aa04e453b8 Added UG translation 2011-05-02 18:40:09 +02:00
b0a75aed95 Added UG translation 2011-05-02 07:27:26 +02:00
dba97f36c0 Added Slovak translation 2011-04-27 09:01:55 +02:00
2560b37819 Updated Swedish translation 2011-04-26 23:10:51 +02:00
149 changed files with 7732 additions and 18860 deletions

8
.gitignore vendored
View File

@ -3,7 +3,6 @@
*.o
.deps
.libs
ABOUT-NLS
ChangeLog
INSTALL
Makefile
@ -30,13 +29,8 @@ m4/
omf.make
po/*.gmo
po/gnome-shell.pot
po/*.header
po/*.sed
po/*.sin
po/Makefile.in.in
po/Makevars.template
po/POTFILES
po/Rules-quot
po/stamp-it
scripts/launcher.pyc
src/*.gir
@ -49,11 +43,9 @@ src/calendar-server/org.gnome.Shell.CalendarServer.service
src/gnome-shell
src/gnome-shell-calendar-server
src/gnome-shell-extension-tool
src/gnome-shell-hotplug-sniffer
src/gnome-shell-jhbuild
src/gnome-shell-perf-helper
src/gnome-shell-real
src/hotplug-sniffer/org.gnome.Shell.HotplugSniffer.service
src/run-js-test
src/test-recorder
src/test-recorder.ogg

View File

@ -3,5 +3,5 @@ E-mail: otaylor@redhat.com
Userid: otaylor
Colin Walters
E-mail: walters@verbum.org
E-mail: walters@redhat.com
Userid: walters

130
NEWS
View File

@ -1,132 +1,6 @@
3.1.4
=====
* Take over inserted media handling and autorun from gnome-session [Cosimo]
* Message Tray
- Display a count of unread notifications on icons
[Jasper, Guillaume; #649356, #654139]
- Only remove icons when the sender quits from D-Bus, not when it
closes its last window [Neha, Marina; #645764]
- Solve problems switching chats between shell and Empathy
[Guillaume; #654237]
- Fix handling of bad GMarkup in messages [Dan; #650298]
- Never show notifications when the screensaver is active [Dan; #654550]
* Telepathy integrationpp
- Implement Telepathy Debug interface to enable empathy-debugger
[Guillaume; #652816]
- Allow approving room invitations, and audio/video calls
[Guillaume; #653740 #653939]
- Send typing notifications [Jonny; #650196]
* Fix selection highlighting for light-on-dark entries [Jasper; #643768]
* Make control-Return in the overview open a new window [Maxim]
* Delay showing the alt-Tab switcher to reduce visual noise when
flipping betweeen windows [Dan; #652346]
* When we have vertically stacked monitors, put the message tray
on the bottom one [Dan; #636963]
* Fix various problems with keynav and the Activities button
[Dan; #641253 #645759]
* Ensure screensaver is locked when switching users [Colin; #654565]
* Improve extension creation tool [Jasper; #653206]
* Fix compatibility with latest GJS [Giovanni; #654349]
* Code cleanups [Adel, Dan, Jasper; #645759 #654577 #654791 #654987]
* Misc bug fixes [Richard, Dan, Florian, Giovanni, Jasper, Marc-Antoine, Rui;
#647175 #649513 #650452 #651082 #653700 #653989 #654105 #654791 #654267
#654269 #654527 #655446]
* Build fixes [Florian, Siegfried; #654300]
Contributors:
Giovanni Campagna, Cosimo Cecchi, Guillaume Desmottes, Neha Doijode,
Maxim Ermilov, Adel Gadllah, Siegfried-Angel Gevatter Pujals, Richard Hughes,
Jonny Lamb, Rui Matos, Florian Müllner, Marc-Antoine Perennou, Colin Walters,
Dan Winship, Marina Zhurakhinskaya
Translations:
Mario Blättermann, Paul Seyfert [de], Jorge González, Daniel Mustieles [es],
Fran Dieguez [gl], Yaron Shahrabani [he], Luca Ferretti [it],
Rudolfs Mazurs [lv], Kjartan Maraas [nb], A S Alam [pa], Yuri Kozlov [ru],
Michal Štrba, Matej Urbančič [sl]
3.1.3
=====
* Fix problem with "user theme extension" breaking the CSS for other
extensions [Giovanni; #650971]
* Telepathy IM framework integration
- Switch to using telepathy-glib rather than talking to
Telepathy via D-Bus [Guillaume, Jasper; #645585, #649633, #651138, #651227]
- Acknowledge messages when the user clicks on them [Guillaume, #647893]
- Fix problem with telepathy icon blinking for incoming messages
even though the user has been notified of them [Guillaume; #643594]
* Networking
- keep wirelesss networks in predictable order [Giovanni; #646580, #652313]
- Show unmanaged devices in the menu [Giovanni; #646946]
- Fix overflow when too many VPN connections [Giovanni; #651602]
* Bluetooth
- Show "hardware disabled" when disabled by rfkill [Giovanni; #648048]
- Fix bug updating status of devices [Giovanni; #647565]
* LookingGlass console:
- Add a "Memory" tab [Colin; #650692]
- Make escape work from any page [Dan Winship; #647303]
- Provide a way to refer to panel items as, e.g.,
Main.panel._activities [Dan Winship; #646915]
* User menu
- Fix problem with suspend menu option locking the screen even when the user
disabled that. [Florian; #652327]
- Hide "power off..." option if shutdown is disabled via PolicyKit
[Florian; #652038]
* Track changes to WM_CLASS (fixes problems with LibreOffice tracking)
[Colin; #649315]
* Remove app tracking workarounds for Firefox and LibreOffice [Colin; #651015]
* Use upstream gettext autoconfigury rather than glib version [Javier; #631576]
* Show messages in the message tray when an application is fullscreen
[Dan Winship; #608667]
* Don't autohide the workspace pager if there is more than one workspace
[Florian; #652714, #653078, #653142]
* Don't always slide out the workspace pager at drag begin [Florian; #652730]
* Only offer to remove a favorite app when dragging it's icon [Owen; #642895]
* Allow dropping an icon anywhere on a workspace [Adel; #652079]
* st-scroll-view: Make the fade effect and offset themable [Jasper; #651813]
* Obey the user's preference when running an application in a terminal
from the run dialog [Florian; #648422]
* Consistently exit overview when launching external applications
[Colin; #653095]
* Adapt to changes in GJS for how GObject APIs are bound
[Alex, Colin, Florian, Jasper, Marc-Antoine; #649981, #652597]
* Fix problems with scrolling in overflow for alt-Tab switcher
[Dan Winship, Adel; #647807]
* Mark relationships between labels and actors for accessibility [Alejandro]
* Add org.gnome.shell.enabled-extensions complementing disabled-extensions
GSetting [Tassilo; #651088]
* Visual tweaks [Jakub, Jasper; #646261, #652715]
* Switch to building against clutter-1.7 with independent Cogl [Adel; #653397]
* Code cleanups [Colin, Dan Winship, Florian; #633620, #645031, #648755, #648758,
#648760, #649203, #649517, #650317, #652730]
* Memory leak fixes [Colin, Maxim; #649508, #650934]
* Build Fixes [Colin, Dan Winship, Florian, Ionut, Morten, Owen, Sean; #647395,
#648006, #650869, #653199, #653275
* Miscellaneous bug fixes [Adam, Adel, Dan Williams, Dan Winship, Florian,
Ionut, Jasper, Maxim, Ray; #620105, #639459, #641570, #642793, #643513,
#645848, #646919, #647186, #648305, #648410, #648562, #648894, #649001,
#645990, #647893, #647907, #651012, #651086, #651606, #651569, #651866,
#652388, #653511]
Contributors:
Ionut Biru, Giovanni Campagna, Guillaume Desmottes, Adam Dingle,
Maxim Ermilov, Adel Gadllah, Tassilo Horn, Javier Jardón, Jonny Lamb,
Alexander Larsson, Rui Matos, Morten Mjelva, Florian Müllner,
Marc-Antoine Perennou, Alejandro Piñeiro, Jasper St. Pierre, Jakub Steiner,
Ray Strode, Owen Taylor, Colin Walters, Dan Williams, Sean Wilson, Dan Winship
Translations:
Daniel Martinez Cucalon [ar], Ihar Hrachyshka [be], Carles Ferrando,
Gil Forcada, Sílvia Miranda [ca], Kristjan Schmidt [eo], Jorge González,
Daniel Mustieles [es], Seán de Búrca [ga], Fran Diéguez [gl],
Yaron Shahrabani [he], Kjartan Maraas [nb], Misha Shnurapet,
Yuri Myasoedov [ru], Daniel Nylander [se], Peter Mráz [sk],
Matej Urbančič [sl], Krishnababu Krothapalli [te], Daniel Korostil [uk],
Aron Xu [zh_CN]
3.0.2
=====
* Network Menu [Dan Williams]
* Network Menu [Dan Williams
- Fix connecting to WPA2 Enterprise access points
Fixes https://bugzilla.gnome.org/show_bug.cgi?id=648171
- Show the mobile broadband wizard when selecting 3G network
@ -149,7 +23,7 @@ Translations:
* Memory leak fixes [Colin, Maxim]
642652, 649508, 649497
* Miscellaneous minor bug fixes [Adel, Christopher, Jasper]
649596, 648765, 648983, 649632
649596,648765, 648983, 649632
Contributors:
Christopher Aillon, Giovanni Campagna, Maxim Ermilov,

View File

@ -1,5 +1,5 @@
AC_PREREQ(2.63)
AC_INIT([gnome-shell],[3.1.4],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[3.0.2],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([src/shell-global.c])
@ -23,16 +23,12 @@ AM_PROG_CC_C_O
LT_PREREQ([2.2.6])
LT_INIT([disable-static])
# i18n
IT_PROG_INTLTOOL([0.40])
AM_GNU_GETTEXT([external])
AM_GNU_GETTEXT_VERSION([0.17])
GETTEXT_PACKAGE=gnome-shell
AC_SUBST(GETTEXT_PACKAGE)
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",
[The prefix for our gettext translation domains.])
IT_PROG_INTLTOOL(0.26)
AM_GLIB_GNU_GETTEXT
PKG_PROG_PKG_CONFIG([0.22])
@ -64,19 +60,19 @@ fi
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
CLUTTER_MIN_VERSION=1.7.5
CLUTTER_MIN_VERSION=1.5.15
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
GJS_MIN_VERSION=1.29.15
GJS_MIN_VERSION=0.7.11
MUTTER_MIN_VERSION=3.0.0
GTK_MIN_VERSION=3.0.0
GIO_MIN_VERSION=2.25.9
LIBECAL_MIN_VERSION=2.32.0
LIBEDATASERVER_MIN_VERSION=1.2.0
LIBEDATASERVERUI_MIN_VERSION=2.91.6
TELEPATHY_GLIB_MIN_VERSION=0.15.3
LIBEDATASERVERUI2_MIN_VERSION=1.2.0
LIBEDATASERVERUI3_MIN_VERSION=2.91.6
TELEPATHY_GLIB_MIN_VERSION=0.13.12
TELEPATHY_LOGGER_MIN_VERSION=0.2.4
POLKIT_MIN_VERSION=0.100
STARTUP_NOTIFICATION_MIN_VERSION=0.11
# Collect more than 20 libraries for a prize!
PKG_CHECK_MODULES(GNOME_SHELL, gio-2.0 >= $GIO_MIN_VERSION
@ -85,10 +81,10 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-2.0 >= $GIO_MIN_VERSION
libmutter >= $MUTTER_MIN_VERSION
gjs-internals-1.0 >= $GJS_MIN_VERSION
libgnome-menu $recorder_modules gconf-2.0
gdk-x11-3.0 libsoup-2.4
gdk-x11-3.0
clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION
libstartup-notification-1.0
gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION
libcanberra
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
@ -97,8 +93,6 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-2.0 >= $GIO_MIN_VERSION
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
PKG_CHECK_MODULES(SHELL_HOTPLUG_SNIFFER, gio-2.0 gdk-pixbuf-2.0)
GJS_VERSION=`$PKG_CONFIG --modversion gjs-internals-1.0`
AC_DEFINE_UNQUOTED([GJS_VERSION], ["$GJS_VERSION"], [The version of GJS we're linking to])
AC_SUBST([GJS_VERSION], ["$GJS_VERSION"])
@ -117,20 +111,22 @@ saved_CFLAGS=$CFLAGS
saved_LIBS=$LIBS
CFLAGS=$GNOME_SHELL_CFLAGS
LIBS=$GNOME_SHELL_LIBS
AC_CHECK_FUNCS(JS_NewGlobalObject XFixesCreatePointerBarrier)
# sn_startup_sequence_get_application_id, we can replace with a version check later
AC_CHECK_FUNCS(JS_NewGlobalObject sn_startup_sequence_get_application_id XFixesCreatePointerBarrier)
CFLAGS=$saved_CFLAGS
LIBS=$saved_LIBS
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.2 gnome-desktop-3.0 >= 2.90.0 x11)
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 gnome-desktop-3.0 >= 2.90.0 x11)
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-3.0)
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
PKG_CHECK_MODULES(JS_TEST, clutter-x11-1.0 gjs-1.0 gobject-introspection-1.0 gtk+-3.0)
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 0.1.7)
AC_MSG_CHECKING([for bluetooth support])
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0],
[BLUETOOTH_DIR=`$PKG_CONFIG --variable=applet_libdir gnome-bluetooth-1.0`
BLUETOOTH_LIBS=`$PKG_CONFIG --variable=applet_libs gnome-bluetooth-1.0`
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 2.90.0],
[BLUETOOTH_DIR=`$PKG_CONFIG --variable=libdir gnome-bluetooth-1.0`/gnome-bluetooth
BLUETOOTH_LIBS="-L'$BLUETOOTH_DIR' -lgnome-bluetooth-applet"
AC_SUBST([BLUETOOTH_LIBS],["$BLUETOOTH_LIBS"])
AC_DEFINE_UNQUOTED([BLUETOOTH_DIR],["$BLUETOOTH_DIR"],[Path to installed GnomeBluetooth typelib and library])
AC_DEFINE([HAVE_BLUETOOTH],[1],[Define if you have libgnome-bluetooth-applet])
@ -140,7 +136,13 @@ PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0],
AC_SUBST([HAVE_BLUETOOTH],[0])
AC_MSG_RESULT([no])])
PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION libedataserverui-3.0 >= $LIBEDATASERVERUI_MIN_VERSION gio-2.0)
# Default to libedataserverui-3.0, but allow falling back to 1.2
PKG_CHECK_EXISTS(libedataserverui-3.0,
[EDS_API=3.0
LIBEDATASERVERUI_MIN_VERSION=$LIBEDATASERVERUI3_MIN_VERSION],
[EDS_API=1.2
LIBEDATASERVERUI_MIN_VERSION=$LIBEDATASERVERUI2_MIN_VERSION])
PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION libedataserverui-$EDS_API >= $LIBEDATASERVERUI_MIN_VERSION gio-2.0)
AC_SUBST(CALENDAR_SERVER_CFLAGS)
AC_SUBST(CALENDAR_SERVER_LIBS)

View File

@ -30,14 +30,26 @@ dist_theme_DATA = \
theme/filter-selected-ltr.svg \
theme/filter-selected-rtl.svg \
theme/gnome-shell.css \
theme/mosaic-view-active.svg \
theme/mosaic-view.svg \
theme/move-window-on-new.svg \
theme/panel-border.svg \
theme/panel-button-border.svg \
theme/panel-button-highlight-narrow.svg \
theme/panel-button-highlight-wide.svg \
theme/process-working.svg \
theme/running-indicator.svg \
theme/scroll-button-down-hover.png \
theme/scroll-button-down.png \
theme/scroll-button-up-hover.png \
theme/scroll-button-up.png \
theme/scroll-hhandle.svg \
theme/scroll-vhandle.svg \
theme/section-more.svg \
theme/section-more-open.svg \
theme/separator-white.png \
theme/single-view-active.svg \
theme/single-view.svg \
theme/source-button-border.svg \
theme/toggle-off-us.svg \
theme/toggle-off-intl.svg \

View File

@ -15,18 +15,8 @@
<default>[]</default>
<_summary>Uuids of extensions to disable</_summary>
<_description>
GNOME Shell extensions have a uuid property; this key lists extensions
which should not be loaded. This setting overrides enabled-extensions
for extensions that appear in both lists.
</_description>
</key>
<key name="enabled-extensions" type="as">
<default>[]</default>
<_summary>Uuids of extensions to enable</_summary>
<_description>
GNOME Shell extensions have a uuid property; this key lists extensions
which should be loaded. disabled-extensions overrides this setting for
extensions that appear in both lists.
GNOME Shell extensions have a uuid property;
this key lists extensions which should not be loaded.
</_description>
</key>
<key name="enable-app-monitoring" type="b">

View File

@ -39,11 +39,6 @@ StScrollBar
padding: 0px;
}
StScrollView.vfade
{
-st-vfade-offset: 68px;
}
StScrollView StScrollBar
{
min-width: 16px;
@ -187,7 +182,6 @@ StTooltip StLabel {
}
.popup-inactive-menu-item {
font-weight: normal;
color: #999;
}
@ -264,7 +258,7 @@ StTooltip StLabel {
}
.panel-corner:active,
.panel-corner:overview,
.panel-corner:checked,
.panel-corner:focus {
-panel-corner-inner-border-color: rgba(255,255,255,0.8);
}
@ -301,7 +295,7 @@ StTooltip StLabel {
}
.panel-button:active,
.panel-button:overview,
.panel-button:checked,
.panel-button:focus {
border-image: url("panel-button-border.svg") 10 10 0 2;
background-image: url("panel-button-highlight-wide.svg");
@ -464,7 +458,6 @@ StTooltip StLabel {
background-gradient-start: rgba(5,5,6,0.1);
background-gradient-end: rgba(254,254,254,0.1);
background-gradient-direction: vertical;
selected-color: black;
caret-color: rgb(128, 128, 128);
caret-size: 1px;
width: 250px;
@ -725,8 +718,6 @@ StTooltip StLabel {
.lg-dialog StEntry
{
color: #88ff66;
selection-background-color: #88ff66;
selected-color: black;
}
.lg-obj-inspector-title
@ -1139,83 +1130,6 @@ StTooltip StLabel {
icon-size: 36px;
}
.hotplug-transient-box {
spacing: 6px;
padding: 2px 72px 2px 12px;
}
.hotplug-notification-item {
background-color: #3c3c3c;
padding: 0px 10px;
border-radius: 8px;
border: 1px solid #181818;
}
.hotplug-notification-item:hover {
border: 1px solid #a1a1a1;
}
.hotplug-notification-item:focus {
background-color: #666666;
}
.hotplug-notification-item:active {
border: 1px solid #a1a1a1;
background-color: #2b2b2b;
}
.hotplug-notification-item-icon {
icon-size: 24px;
padding: 2px 5px;
}
.hotplug-resident-box {
spacing: 8px;
}
.hotplug-resident-mount {
spacing: 8px;
border-radius: 4px;
color: #ccc;
}
.hotplug-resident-mount:hover {
background-gradient-direction: horizontal;
background-gradient-start: rgba(255, 255, 255, 0.1);
background-gradient-end: rgba(255, 255, 255, 0);
color: #fff;
}
.hotplug-resident-mount-label {
color: inherit;
padding-left: 6px;
}
.hotplug-resident-mount-icon {
icon-size: 24px;
padding-left: 6px;
}
.hotplug-resident-eject-icon {
icon-size: 16px;
}
.hotplug-resident-eject-button {
padding: 2px;
border: 1px solid #2b2b2b;
border-radius: 5px;
color: #ccc;
}
.hotplug-resident-eject-button:hover {
color: #fff;
background-color: #2b2b2b;
border: 1px solid #a1a1a1;
}
.chat-log-message {
color: #888888;
}
@ -1275,8 +1189,6 @@ StTooltip StLabel {
color: #545454;
background-color: #e8e8e8;
caret-color: #545454;
selection-background-color: #bcbcbc;
selected-color: #323232;
box-shadow: 0px 0px 6px 2px rgba(255,255,255,0.9);
}
@ -1343,16 +1255,6 @@ StTooltip StLabel {
padding-left: 4px;
}
.summary-source-counter {
color: white;
background-color: #3465A4;
text-shadow: black 1px 1px 0;
font-size: 9pt;
border-radius: 1em;
min-height: 1em;
min-width: 1em;
}
.source-title {
font-size: 9pt;
font-weight: bold;
@ -1568,8 +1470,6 @@ StTooltip StLabel {
font-weight: bold;
width: 23em;
color: white;
selection-background-color: white;
selected-color: black;
}
.run-dialog {
@ -1673,90 +1573,6 @@ StTooltip StLabel {
color: #444444;
}
/* ShellMountOperation Dialogs */
.shell-mount-operation-icon {
icon-size: 48px;
}
.mount-password-reask {
color: red;
}
.show-processes-dialog,
.mount-question-dialog {
spacing: 24px;
}
.show-processes-dialog-subject,
.mount-question-dialog-subject {
font-size: 12pt;
font-weight: bold;
color: #666666;
padding-top: 10px;
padding-left: 17px;
padding-bottom: 6px;
}
.show-processes-dialog-subject:rtl,
.mount-question-dialog-subject:rtl {
padding-left: 0px;
padding-right: 17px;
}
.show-processes-dialog-description,
.mount-question-dialog-description {
font-size: 10pt;
color: white;
padding-left: 17px;
width: 28em;
}
.show-processes-dialog-description:rtl,
.mount-question-dialog-description:rtl {
padding-right: 17px;
}
.show-processes-dialog-app-list {
font-size: 10pt;
max-height: 200px;
padding-top: 24px;
padding-left: 49px;
padding-right: 32px;
}
.show-processes-dialog-app-list:rtl {
padding-right: 49px;
padding-left: 32px;
}
.show-processes-dialog-app-list-item {
color: #ccc;
}
.show-processes-dialog-app-list-item:hover {
color: white;
}
.show-processes-dialog-app-list-item:ltr {
padding-right: 1em;
}
.show-processes-dialog-app-list-item:rtl {
padding-left: 1em;
}
.show-processes-dialog-app-list-item-icon:ltr {
padding-right: 17px;
}
.show-processes-dialog-app-list-item-icon:rtl {
padding-left: 17px;
}
.show-processes-dialog-app-list-item-name {
font-size: 10pt;
}
/* PolicyKit Authentication Dialog */
.polkit-dialog {
/* this is the width of the entire modal popup */

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="16"
id="svg6503"
version="1.1"
inkscape:version="0.47pre4 r22446"
sodipodi:docname="mosaic-view-active.svg">
<defs
id="defs6505">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 16 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="32 : 16 : 1"
inkscape:persp3d-origin="16 : 10.666667 : 1"
id="perspective6511" />
<inkscape:perspective
id="perspective6494"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.197802"
inkscape:cx="-15.97056"
inkscape:cy="16"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1680"
inkscape:window-height="997"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="1" />
<metadata
id="metadata6508">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,-16)">
<g
style="display:inline;fill:#cbcbcb;fill-opacity:1"
transform="translate(-449.85476,-685.85869)"
id="g5306">
<rect
style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none"
id="rect5308"
width="11"
height="7"
x="450.5"
y="710.5"
rx="0.99999958"
ry="1" />
<rect
style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline"
id="rect5310"
width="11"
height="7"
x="462.5"
y="702.5"
rx="0.99999958"
ry="1" />
<rect
style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999976000000002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline"
id="rect5312"
width="11"
height="7"
x="450.5"
y="702.5"
rx="0.99999958"
ry="1" />
<rect
style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline"
id="rect5314"
width="11"
height="7"
x="462.5"
y="710.5"
rx="0.99999958"
ry="1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

113
data/theme/mosaic-view.svg Normal file
View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="16"
id="svg6503"
version="1.1"
inkscape:version="0.47pre4 r22446"
sodipodi:docname="New document 19">
<defs
id="defs6505">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 16 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="32 : 16 : 1"
inkscape:persp3d-origin="16 : 10.666667 : 1"
id="perspective6511" />
<inkscape:perspective
id="perspective6494"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.197802"
inkscape:cx="16"
inkscape:cy="16"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1680"
inkscape:window-height="997"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="1" />
<metadata
id="metadata6508">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,-16)">
<g
style="display:inline"
transform="translate(-449.85476,-685.85869)"
id="g5306">
<rect
style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none"
id="rect5308"
width="11"
height="7"
x="450.5"
y="710.5"
rx="0.99999958"
ry="1" />
<rect
style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline"
id="rect5310"
width="11"
height="7"
x="462.5"
y="702.5"
rx="0.99999958"
ry="1" />
<rect
style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline"
id="rect5312"
width="11"
height="7"
x="450.5"
y="702.5"
rx="0.99999958"
ry="1" />
<rect
style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline"
id="rect5314"
width="11"
height="7"
x="462.5"
y="710.5"
rx="0.99999958"
ry="1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="98"
height="98"
id="svg6375"
version="1.1"
inkscape:version="0.47 r22583"
sodipodi:docname="add-workspace.svg">
<defs
id="defs6377">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 16 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="32 : 16 : 1"
inkscape:persp3d-origin="16 : 10.666667 : 1"
id="perspective6383" />
<inkscape:perspective
id="perspective6366"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.9590209"
inkscape:cx="56.650687"
inkscape:cy="20.635343"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1680"
inkscape:window-height="997"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="1" />
<metadata
id="metadata6380">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,66)">
<g
id="g2824"
transform="matrix(11.568551,0,0,11.698271,-78.828159,-304.81518)">
<path
style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 11.07363,21.36834 0,6.43903"
id="path5322" />
<path
style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
d="m 14.29314,24.58786 -6.43902,0"
id="path5324" />
</g>
<path
style="fill:#000000;fill-opacity:0.98823529"
d="m 48.239516,97.908047 c -0.41677,-0.05102 -1.269253,-0.222408 -1.894408,-0.380859 -4.088493,-1.036262 -7.520781,-4.753234 -8.330163,-9.021094 -0.154947,-0.817026 -0.257819,-6.68112 -0.257819,-14.696556 l 0,-13.337088 -13.829177,-0.08909 C 10.802042,60.298796 10.026884,60.268266 8.6851548,59.783022 3.6288503,57.954375 0.62673331,53.828648 0.62673331,48.708554 c 0,-5.625522 4.25936019,-10.425065 9.97721469,-11.242548 0.987903,-0.141242 7.368912,-0.254994 14.460646,-0.257791 l 12.692532,-0.005 0,-13.586668 c 0,-14.6441583 0.03287,-15.0698926 1.364686,-17.6753047 2.185477,-4.2754229 6.938193,-6.75739913 11.687647,-6.10355607 3.382776,0.46569661 6.737962,2.72496967 8.414081,5.66577137 1.480816,2.5981315 1.519067,3.0522448 1.519067,18.0333334 l 0,13.666424 12.692533,0.005 c 7.091733,0.0028 13.472742,0.116549 14.460646,0.257791 6.395303,0.914337 10.804785,6.623716 9.941157,12.871766 -0.698243,5.051565 -4.792685,9.104635 -9.941157,9.840713 -0.987904,0.141242 -7.368913,0.254995 -14.460646,0.257791 l -12.692533,0.005 0,13.801945 c 0,13.031417 -0.02798,13.895893 -0.501177,15.484801 -1.526902,5.127058 -6.919246,8.802262 -12.001914,8.18002 z"
id="path2828"
transform="translate(0,-66)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -2,62 +2,24 @@
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="119.97824"
height="119.97824"
id="svg7355"
version="1.1"
inkscape:version="0.48.1 r9760"
sodipodi:docname="running-indicator.svg">
<metadata
id="metadata4175">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#2c1cff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1141"
id="namedview4173"
showgrid="false"
inkscape:zoom="8.1348081"
inkscape:cx="81.120662"
inkscape:cy="58.117986"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="1"
inkscape:current-layer="g30864" />
version="1.1">
<defs
id="defs7357">
<radialGradient
xlink:href="#linearGradient36429"
id="radialGradient7461"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.011539,0,0,0.57582113,-0.39262194,71.83807)"
cx="47.428951"
cy="167.16817"
fx="47.428951"
fy="167.16817"
gradientTransform="matrix(1.0525552,0,0,1.0525552,-2.5162753,-9.0000838)"
cx="47.878681"
cy="171.25"
fx="47.878681"
fy="171.25"
r="37" />
<linearGradient
id="linearGradient36429">
@ -97,7 +59,7 @@
fx="49.067139"
cy="242.50381"
cx="49.067139"
gradientTransform="matrix(1.1891549,0,0,0.15252127,-9.281289,132.52772)"
gradientTransform="matrix(1.1891549,0,0,0.55513246,-9.281289,36.12653)"
gradientUnits="userSpaceOnUse"
id="radialGradient7488"
xlink:href="#linearGradient36471" />
@ -110,21 +72,19 @@
id="g30864"
transform="translate(255.223,70.118091)">
<rect
ry="3.4593496"
rx="3.4593496"
y="99.596962"
x="12.596948"
height="71.116341"
width="71.116341"
ry="3.5996203"
rx="3.5996203"
y="98"
x="11"
height="74"
width="74"
id="rect14000"
style="opacity:0.37187500000000001;fill:url(#radialGradient7461);fill-opacity:1;stroke:none" />
style="opacity:0.371875;fill:url(#radialGradient7461);fill-opacity:1;stroke:none" />
<path
id="rect34520"
d="m 83.273151,166.72152 c 0,1.96759 -1.584022,3.55163 -3.551629,3.55163 l -63.443032,0 c -1.967608,0 -3.551648,-1.58402 -3.551643,-3.55164 0,-5.85318 0,-5.85318 0,0"
style="opacity:0.35;fill:none;stroke:url(#radialGradient7488);stroke-width:1;stroke-opacity:1"
connector-curvature="0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccscc" />
d="m 84.506708,167.95508 c 6e-6,1.96759 -1.584022,3.55162 -3.551629,3.55163 l -65.910146,0 c -1.967608,-1e-5 -3.551648,-1.58402 -3.551643,-3.55164"
style="opacity:0.2;fill:none;stroke:url(#radialGradient7488);stroke-width:1;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="5.8600588"
height="9"
id="svg3647"
version="1.1"
inkscape:version="0.47 r22583"
sodipodi:docname="section-more.svg">
<defs
id="defs3649">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective3655" />
<inkscape:perspective
id="perspective3603"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="82.777778"
inkscape:cx="2.9300294"
inkscape:cy="5.466443"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1680"
inkscape:window-height="997"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="1" />
<metadata
id="metadata3652">
<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(-262.78425,-490.71933)">
<path
transform="matrix(0,-0.98149546,0.71467449,0,25.404986,578.15569)"
d="M 88.830127,340 80.169873,340 84.5,332.5 88.830127,340 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="true"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="2.5"
sodipodi:r1="5"
sodipodi:cy="337.5"
sodipodi:cx="84.5"
sodipodi:sides="3"
id="path5497-5"
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.59699643;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
sodipodi:type="star" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

87
data/theme/section-more.svg Executable file
View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="5.8600588"
height="9"
id="svg3647"
version="1.1"
inkscape:version="0.46+devel"
sodipodi:docname="New document 6">
<defs
id="defs3649">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective3655" />
<inkscape:perspective
id="perspective3603"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="112.21575"
inkscape:cy="-32.642856"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="609"
inkscape:window-height="501"
inkscape:window-x="164"
inkscape:window-y="26"
inkscape:window-maximized="0" />
<metadata
id="metadata3652">
<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(-262.78425,-490.71933)">
<path
transform="matrix(0,0.98149546,-0.71467449,0,506.02358,412.28296)"
d="M 88.830127,340 80.169873,340 84.5,332.5 88.830127,340 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="true"
sodipodi:arg2="1.5707963"
sodipodi:arg1="0.52359878"
sodipodi:r2="2.5"
sodipodi:r1="5"
sodipodi:cy="337.5"
sodipodi:cx="84.5"
sodipodi:sides="3"
id="path5497-5"
style="fill:#5f5f5f;fill-opacity:1;stroke:#5f5f5f;stroke-width:0.59699643;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
sodipodi:type="star" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 B

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="16"
id="svg6446"
version="1.1"
inkscape:version="0.47pre4 r22446"
sodipodi:docname="single-view-active.svg">
<defs
id="defs6448">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 16 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="32 : 16 : 1"
inkscape:persp3d-origin="16 : 10.666667 : 1"
id="perspective6454" />
<inkscape:perspective
id="perspective6441"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.197802"
inkscape:cx="0.014720032"
inkscape:cy="16"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1680"
inkscape:window-height="997"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="1" />
<metadata
id="metadata6451">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,-17)">
<rect
ry="0.5"
rx="0.49999979"
y="17.483809"
x="0.53483802"
height="15"
width="23"
id="rect5304"
style="fill:#cccccc;fill-opacity:1;stroke:#cccccc;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="16"
id="svg6446"
version="1.1"
inkscape:version="0.47pre4 r22446"
sodipodi:docname="single-view.svg">
<defs
id="defs6448">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 16 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="32 : 16 : 1"
inkscape:persp3d-origin="16 : 10.666667 : 1"
id="perspective6454" />
<inkscape:perspective
id="perspective6441"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.197802"
inkscape:cx="0.014720032"
inkscape:cy="16"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1680"
inkscape:window-height="997"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="1" />
<metadata
id="metadata6451">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,-17)">
<rect
ry="0.5"
rx="0.49999979"
y="17.483809"
x="0.53483802"
height="15"
width="23"
id="rect5304"
style="fill:#626262;fill-opacity:1;stroke:#cccccc;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -13,8 +13,8 @@
height="22"
id="svg3199"
version="1.1"
inkscape:version="0.48.1 r9760"
sodipodi:docname="toggle-on-intl.svg">
inkscape:version="0.47 r22583"
sodipodi:docname="New document 11">
<defs
id="defs3201">
<inkscape:perspective
@ -39,14 +39,14 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="49.147112"
inkscape:cy="17.532036"
inkscape:zoom="0.35"
inkscape:cx="32.500004"
inkscape:cy="10.999997"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1412"
inkscape:window-height="1067"
inkscape:window-width="609"
inkscape:window-height="501"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="0" />
@ -58,7 +58,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
@ -72,7 +72,7 @@
transform="translate(-453.5,448.36218)"
id="g16453">
<rect
style="color:#000000;fill:#4a90d9;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994000000003;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
style="color:#000000;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect16256-9-4"
width="63.000004"
height="19"

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -13,8 +13,8 @@
height="22"
id="svg2857"
version="1.1"
inkscape:version="0.48.1 r9760"
sodipodi:docname="toggle-on-us.svg">
inkscape:version="0.47 r22583"
sodipodi:docname="New document 2">
<defs
id="defs2859">
<inkscape:perspective
@ -40,18 +40,16 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="19.689855"
inkscape:cy="2.0517979"
inkscape:cx="-69.642856"
inkscape:cy="42.428569"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="941"
inkscape:window-height="751"
inkscape:window-x="2577"
inkscape:window-y="206"
inkscape:window-maximized="0"
borderlayer="true"
inkscape:showpageshadow="false" />
inkscape:window-width="609"
inkscape:window-height="501"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="0" />
<metadata
id="metadata2862">
<rdf:RDF>
@ -60,7 +58,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
@ -74,7 +72,7 @@
transform="translate(-351.35714,708.36218)"
id="g16453">
<rect
style="color:#000000;fill:#4a90d9;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994000000003;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
style="color:#000000;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect16256-9-4"
width="63.000004"
height="19"

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -10,14 +10,11 @@ nobase_dist_js_DATA = \
misc/history.js \
misc/modemManager.js \
misc/params.js \
misc/screenSaver.js \
misc/util.js \
perf/core.js \
ui/altTab.js \
ui/appDisplay.js \
ui/appFavorites.js \
ui/automountManager.js \
ui/autorunManager.js \
ui/boxpointer.js \
ui/calendar.js \
ui/chrome.js \
@ -30,7 +27,6 @@ nobase_dist_js_DATA = \
ui/environment.js \
ui/extensionSystem.js \
ui/iconGrid.js \
ui/layout.js \
ui/lightbox.js \
ui/link.js \
ui/lookingGlass.js \
@ -39,7 +35,6 @@ nobase_dist_js_DATA = \
ui/main.js \
ui/messageTray.js \
ui/modalDialog.js \
ui/shellMountOperation.js \
ui/notificationDaemon.js \
ui/overview.js \
ui/panel.js \

View File

@ -109,8 +109,7 @@ const SessionManagerIface = {
name: 'org.gnome.SessionManager',
methods: [
{ name: 'Logout', inSignature: 'u', outSignature: '' },
{ name: 'Shutdown', inSignature: '', outSignature: '' },
{ name: 'CanShutdown', inSignature: '', outSignature: 'b' }
{ name: 'Shutdown', inSignature: '', outSignature: '' }
]
};

View File

@ -1,53 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const DBus = imports.dbus;
const Lang = imports.lang;
const ScreenSaverIface = {
name: 'org.gnome.ScreenSaver',
methods: [{ name: 'GetActive',
inSignature: '',
outSignature: 'b' },
{ name: 'Lock',
inSignature: '' },
{ name: 'SetActive',
inSignature: 'b' }],
signals: [{ name: 'ActiveChanged',
inSignature: 'b' }]
};
function ScreenSaverProxy() {
this._init();
}
ScreenSaverProxy.prototype = {
_init: function() {
DBus.session.proxifyObject(this,
'org.gnome.ScreenSaver',
'/org/gnome/ScreenSaver');
DBus.session.watch_name('org.gnome.ScreenSaver',
false, // do not launch a name-owner if none exists
Lang.bind(this, this._onSSAppeared),
Lang.bind(this, this._onSSVanished));
this.screenSaverActive = false;
this.connect('ActiveChanged',
Lang.bind(this, this._onActiveChanged));
},
_onSSAppeared: function(owner) {
this.GetActiveRemote(Lang.bind(this, function(isActive) {
this.screenSaverActive = isActive;
}))
},
_onSSVanished: function(oldOwner) {
this.screenSaverActive = false;
},
_onActiveChanged: function(object, isActive) {
this.screenSaverActive = isActive;
}
};
DBus.proxifyPrototype(ScreenSaverProxy.prototype, ScreenSaverIface);

View File

@ -7,6 +7,9 @@ const Shell = imports.gi.Shell;
const Main = imports.ui.main;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
/* http://daringfireball.net/2010/07/improved_regex_for_matching_urls */
const _urlRegexp = new RegExp('\\b(([a-z][\\w-]+:(/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)([^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:\'\\".,<>?«»“”‘’]))', 'gi');
@ -45,7 +48,7 @@ function spawn(argv) {
// occur when trying to parse or start the program.
function spawnCommandLine(command_line) {
try {
let [success, argv] = GLib.shell_parse_argv(command_line);
let [success, argc, argv] = GLib.shell_parse_argv(command_line);
trySpawn(argv);
} catch (err) {
_handleSpawnError(command_line, err);
@ -85,10 +88,10 @@ function trySpawn(argv)
// Runs @command_line in the background. If launching @command_line
// fails, this will throw an error.
function trySpawnCommandLine(command_line) {
let success, argv;
let success, argc, argv;
try {
[success, argv] = GLib.shell_parse_argv(command_line);
[success, argc, argv] = GLib.shell_parse_argv(command_line);
} catch (err) {
// Replace "Error invoking GLib.shell_parse_argv: " with
// something nicer

View File

@ -14,8 +14,7 @@ const Tweener = imports.ui.tweener;
const POPUP_APPICON_SIZE = 96;
const POPUP_SCROLL_TIME = 0.10; // seconds
const POPUP_FADE_IN_TIME = 0.4; // seconds
const POPUP_FADE_OUT_TIME = 0.1; // seconds
const POPUP_FADE_TIME = 0.1; // seconds
const APP_ICON_HOVER_TIMEOUT = 200; // milliseconds
@ -75,7 +74,7 @@ AltTabPopup.prototype = {
_allocate: function (actor, box, flags) {
let childBox = new Clutter.ActorBox();
let primary = Main.layoutManager.primaryMonitor;
let primary = global.get_primary_monitor();
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
let rightPadding = this.actor.get_theme_node().get_padding(St.Side.RIGHT);
@ -88,7 +87,7 @@ AltTabPopup.prototype = {
let [childMinHeight, childNaturalHeight] = this._appSwitcher.actor.get_preferred_height(primary.width - hPadding);
let [childMinWidth, childNaturalWidth] = this._appSwitcher.actor.get_preferred_width(childNaturalHeight);
childBox.x1 = Math.max(primary.x + leftPadding, primary.x + Math.floor((primary.width - childNaturalWidth) / 2));
childBox.x2 = Math.min(primary.x + primary.width - rightPadding, childBox.x1 + childNaturalWidth);
childBox.x2 = Math.min(primary.x + primary.width - hPadding, childBox.x1 + childNaturalWidth);
childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
childBox.y2 = childBox.y1 + childNaturalHeight;
this._appSwitcher.actor.allocate(childBox, flags);
@ -98,6 +97,8 @@ AltTabPopup.prototype = {
// those calculations
if (this._thumbnails) {
let icon = this._appIcons[this._currentApp].actor;
// Force a stage relayout to make sure we get the correct position
global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, 0, 0);
let [posX, posY] = icon.get_transformed_position();
let thumbnailCenter = posX + icon.width / 2;
let [childMinWidth, childNaturalWidth] = this._thumbnails.actor.get_preferred_width(-1);
@ -120,7 +121,7 @@ AltTabPopup.prototype = {
}
},
show : function(backward, binding) {
show : function(backward, switch_group) {
let tracker = Shell.WindowTracker.get_default();
let apps = tracker.get_running_apps ('');
@ -144,14 +145,8 @@ AltTabPopup.prototype = {
this._appIcons = this._appSwitcher.icons;
// Need to force an allocation so we can figure out whether we
// need to scroll when selecting
this.actor.opacity = 0;
this.actor.show();
this.actor.get_allocation_box();
// Make the initial selection
if (binding == 'switch_group') {
if (switch_group) {
if (backward) {
this._select(0, this._appIcons[0].cachedWindows.length - 1);
} else {
@ -160,10 +155,6 @@ AltTabPopup.prototype = {
else
this._select(0, 0);
}
} else if (binding == 'switch_group_backward') {
this._select(0, this._appIcons[0].cachedWindows.length - 1);
} else if (binding == 'switch_windows_backward') {
this._select(this._appIcons.length - 1);
} else if (this._appIcons.length == 1) {
this._select(0);
} else if (backward) {
@ -183,15 +174,12 @@ AltTabPopup.prototype = {
return false;
}
// Using easeInOutExpo over 400ms gives us 150ms of "nearly
// invisible" (less than 10% opacity), followed by a 100ms
// tween in (to 90% opacity, with the last 10% coming over the
// next 150ms). So if the user releases Alt quickly after we
// start tweening, they'll never see the switcher.
this.actor.opacity = 0;
this.actor.show();
Tweener.addTween(this.actor,
{ opacity: 255,
time: POPUP_FADE_IN_TIME,
transition: 'easeInOutExpo'
time: POPUP_FADE_TIME,
transition: 'easeOutQuad'
});
return true;
@ -227,25 +215,33 @@ AltTabPopup.prototype = {
this._disableHover();
if (keysym == Clutter.Escape) {
this.destroy();
} else if (action == Meta.KeyBindingAction.SWITCH_GROUP) {
if (action == Meta.KeyBindingAction.SWITCH_GROUP)
this._select(this._currentApp, backwards ? this._previousWindow() : this._nextWindow());
} else if (action == Meta.KeyBindingAction.SWITCH_GROUP_BACKWARD) {
this._select(this._currentApp, this._previousWindow());
} else if (action == Meta.KeyBindingAction.SWITCH_WINDOWS) {
this._select(backwards ? this._previousApp() : this._nextApp());
} else if (action == Meta.KeyBindingAction.SWITCH_WINDOWS_BACKWARD) {
this._select(this._previousApp());
} else if (this._thumbnailsFocused) {
if (keysym == Clutter.Left)
else if (keysym == Clutter.Escape)
this.destroy();
else if (this._thumbnailsFocused) {
if (action == Meta.KeyBindingAction.SWITCH_WINDOWS)
if (backwards) {
if (this._currentWindow == 0 || this._currentWindow == -1)
this._select(this._previousApp());
else
this._select(this._currentApp, this._previousWindow());
} else {
if (this._currentWindow == this._appIcons[this._currentApp].cachedWindows.length - 1)
this._select(this._nextApp());
else
this._select(this._currentApp, this._nextWindow());
}
else if (keysym == Clutter.Left)
this._select(this._currentApp, this._previousWindow());
else if (keysym == Clutter.Right)
this._select(this._currentApp, this._nextWindow());
else if (keysym == Clutter.Up)
this._select(this._currentApp, null, true);
} else {
if (keysym == Clutter.Left)
if (action == Meta.KeyBindingAction.SWITCH_WINDOWS)
this._select(backwards ? this._previousApp() : this._nextApp());
else if (keysym == Clutter.Left)
this._select(this._previousApp());
else if (keysym == Clutter.Right)
this._select(this._nextApp());
@ -374,7 +370,7 @@ AltTabPopup.prototype = {
if (this.actor.visible) {
Tweener.addTween(this.actor,
{ opacity: 0,
time: POPUP_FADE_OUT_TIME,
time: POPUP_FADE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
@ -587,7 +583,7 @@ SwitcherList.prototype = {
this._rightArrow.opacity = this._rightGradient.opacity;
},
addItem : function(item, label) {
addItem : function(item) {
let bbox = new St.Button({ style_class: 'item-box',
reactive: true });
@ -598,8 +594,6 @@ SwitcherList.prototype = {
bbox.connect('clicked', Lang.bind(this, function() { this._onItemClicked(n); }));
bbox.connect('enter-event', Lang.bind(this, function() { this._onItemEnter(n); }));
bbox.label_actor = label;
this._items.push(bbox);
},
@ -632,7 +626,7 @@ SwitcherList.prototype = {
this._items[this._highlighted].add_style_pseudo_class('selected');
}
let monitor = Main.layoutManager.primaryMonitor;
let monitor = global.get_primary_monitor();
let itemSize = this._items[index].allocation.x2 - this._items[index].allocation.x1;
let [posX, posY] = this._items[index].get_transformed_position();
posX += this.actor.x;
@ -660,7 +654,7 @@ SwitcherList.prototype = {
_scrollToRight : function() {
this._scrollableLeft = true;
let monitor = Main.layoutManager.primaryMonitor;
let monitor = global.get_primary_monitor();
let padding = this.actor.get_theme_node().get_horizontal_padding();
let parentPadding = this.actor.get_parent().get_theme_node().get_horizontal_padding();
let x = this._items[this._highlighted].allocation.x2 - monitor.width + padding + parentPadding;
@ -757,7 +751,7 @@ SwitcherList.prototype = {
let children = this._list.get_children();
let childBox = new Clutter.ActorBox();
let primary = Main.layoutManager.primaryMonitor;
let primary = global.get_primary_monitor();
let parentRightPadding = this.actor.get_parent().get_theme_node().get_padding(St.Side.RIGHT);
if (this.actor.allocation.x2 == primary.x + primary.width - parentRightPadding) {
if (this._squareItems)
@ -887,7 +881,7 @@ AppSwitcher.prototype = {
totalSpacing += this._separator.width + this._list.spacing;
// We just assume the whole screen here due to weirdness happing with the passed width
let primary = Main.layoutManager.primaryMonitor;
let primary = global.get_primary_monitor();
let parentPadding = this.actor.get_parent().get_theme_node().get_horizontal_padding();
let availWidth = primary.width - parentPadding - this.actor.get_theme_node().get_horizontal_padding();
let height = 0;
@ -985,7 +979,7 @@ AppSwitcher.prototype = {
_addIcon : function(appIcon) {
this.icons.push(appIcon);
this.addItem(appIcon.actor, appIcon.label);
this.addItem(appIcon.actor);
let n = this._arrows.length;
let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' });
@ -1055,12 +1049,9 @@ ThumbnailList.prototype = {
this._labels.push(bin);
bin.add_actor(name);
box.add_actor(bin);
this.addItem(box, name);
} else {
this.addItem(box, null);
}
this.addItem(box);
}
},

View File

@ -9,6 +9,8 @@ const Signals = imports.signals;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
const Mainloop = imports.mainloop;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const AppFavorites = imports.ui.appFavorites;
const DND = imports.ui.dnd;
@ -44,7 +46,7 @@ AlphabeticalView.prototype = {
this.actor = new St.ScrollView({ x_fill: true,
y_fill: false,
y_align: St.Align.START,
style_class: 'vfade' });
vfade: true });
this.actor.add_actor(box);
this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
this.actor.connect('notify::mapped', Lang.bind(this,
@ -172,12 +174,10 @@ ViewByCategories.prototype = {
// (used only before the actor is mapped the first time)
this._currentCategory = -2;
this._filters = new St.BoxLayout({ vertical: true, reactive: true });
this._filtersBox = new St.ScrollView({ x_fill: false,
y_fill: false,
style_class: 'vfade' });
this._filtersBox.add_actor(this._filters);
this._filters.connect('scroll-event', Lang.bind(this, this._scrollFilter));
this.actor.add(this._view.actor, { expand: true, x_fill: true, y_fill: true });
this.actor.add(this._filtersBox, { expand: false, y_fill: false, y_align: St.Align.START });
this.actor.add(this._filters, { expand: false, y_fill: false, y_align: St.Align.START });
// Always select the "All" filter when switching to the app view
this.actor.connect('notify::mapped', Lang.bind(this,
@ -195,6 +195,14 @@ ViewByCategories.prototype = {
this.actor.add(this._focusDummy);
},
_scrollFilter: function(actor, event) {
let direction = event.get_scroll_direction();
if (direction == Clutter.ScrollDirection.UP)
this._selectCategory(Math.max(this._currentCategory - 1, -1))
else if (direction == Clutter.ScrollDirection.DOWN)
this._selectCategory(Math.min(this._currentCategory + 1, this._sections.length - 1));
},
_selectCategory: function(num) {
if (this._currentCategory == num) // nothing to do
return;
@ -327,16 +335,8 @@ BaseAppSearchProvider.prototype = {
params = Params.parse(params, { workspace: null,
timestamp: null });
let workspace = params.workspace ? params.workspace.index() : -1;
let event = Clutter.get_current_event();
let modifiers = event ? Shell.get_event_state(event) : 0;
let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK;
let app = this._appSys.get_app(id);
if (openNewWindow)
app.open_new_window(workspace);
else
app.activate(workspace);
app.activate(params.workspace ? params.workspace.index() : -1);
},
dragActivateResult: function(id, params) {
@ -434,8 +434,6 @@ AppWellIcon.prototype = {
this.icon = new AppIcon(app, iconParams);
this.actor.set_child(this.icon.actor);
this.actor.label_actor = this.icon.label;
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
this.actor.connect('popup-menu', Lang.bind(this, this._onKeyboardPopupMenu));

View File

@ -3,6 +3,8 @@
const Shell = imports.gi.Shell;
const Lang = imports.lang;
const Signals = imports.signals;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Main = imports.ui.main;

View File

@ -1,278 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Lang = imports.lang;
const DBus = imports.dbus;
const Mainloop = imports.mainloop;
const Gio = imports.gi.Gio;
const Params = imports.misc.params;
const Main = imports.ui.main;
const ShellMountOperation = imports.ui.shellMountOperation;
const ScreenSaver = imports.misc.screenSaver;
// GSettings keys
const SETTINGS_SCHEMA = 'org.gnome.desktop.media-handling';
const SETTING_ENABLE_AUTOMOUNT = 'automount';
const AUTORUN_EXPIRE_TIMEOUT_SECS = 10;
const ConsoleKitSessionIface = {
name: 'org.freedesktop.ConsoleKit.Session',
methods: [{ name: 'IsActive',
inSignature: '',
outSignature: 'b' }],
signals: [{ name: 'ActiveChanged',
inSignature: 'b' }]
};
const ConsoleKitSessionProxy = DBus.makeProxyClass(ConsoleKitSessionIface);
const ConsoleKitManagerIface = {
name: 'org.freedesktop.ConsoleKit.Manager',
methods: [{ name: 'GetCurrentSession',
inSignature: '',
outSignature: 'o' }]
};
function ConsoleKitManager() {
this._init();
};
ConsoleKitManager.prototype = {
_init: function() {
this.sessionActive = true;
DBus.system.proxifyObject(this,
'org.freedesktop.ConsoleKit',
'/org/freedesktop/ConsoleKit/Manager');
DBus.system.watch_name('org.freedesktop.ConsoleKit',
false, // do not launch a name-owner if none exists
Lang.bind(this, this._onManagerAppeared),
Lang.bind(this, this._onManagerVanished));
},
_onManagerAppeared: function(owner) {
this.GetCurrentSessionRemote(Lang.bind(this, this._onCurrentSession));
},
_onManagerVanished: function(oldOwner) {
this.sessionActive = true;
},
_onCurrentSession: function(session) {
this._ckSession = new ConsoleKitSessionProxy(DBus.system, 'org.freedesktop.ConsoleKit', session);
this._ckSession.connect
('ActiveChanged', Lang.bind(this, function(object, isActive) {
this.sessionActive = isActive;
}));
this._ckSession.IsActiveRemote(Lang.bind(this, function(isActive) {
this.sessionActive = isActive;
}));
}
};
DBus.proxifyPrototype(ConsoleKitManager.prototype, ConsoleKitManagerIface);
function AutomountManager() {
this._init();
}
AutomountManager.prototype = {
_init: function() {
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
this._volumeQueue = [];
this.ckListener = new ConsoleKitManager();
this._ssProxy = new ScreenSaver.ScreenSaverProxy();
this._ssProxy.connect('ActiveChanged',
Lang.bind(this,
this._screenSaverActiveChanged));
this._volumeMonitor = Gio.VolumeMonitor.get();
this._volumeMonitor.connect('volume-added',
Lang.bind(this,
this._onVolumeAdded));
this._volumeMonitor.connect('volume-removed',
Lang.bind(this,
this._onVolumeRemoved));
this._volumeMonitor.connect('drive-connected',
Lang.bind(this,
this._onDriveConnected));
this._volumeMonitor.connect('drive-disconnected',
Lang.bind(this,
this._onDriveDisconnected));
this._volumeMonitor.connect('drive-eject-button',
Lang.bind(this,
this._onDriveEjectButton));
Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
},
_screenSaverActiveChanged: function(object, isActive) {
if (!isActive) {
this._volumeQueue.forEach(Lang.bind(this, function(volume) {
this._checkAndMountVolume(volume);
}));
}
// clear the queue anyway
this._volumeQueue = [];
},
_startupMountAll: function() {
let volumes = this._volumeMonitor.get_volumes();
volumes.forEach(Lang.bind(this, function(volume) {
this._checkAndMountVolume(volume, { checkSession: false,
useMountOp: false });
}));
return false;
},
_onDriveConnected: function() {
// if we're not in the current ConsoleKit session,
// or screensaver is active, don't play sounds
if (!this.ckListener.sessionActive)
return;
if (this._ssProxy.screenSaverActive)
return;
global.play_theme_sound(0, 'device-added-media');
},
_onDriveDisconnected: function() {
// if we're not in the current ConsoleKit session,
// or screensaver is active, don't play sounds
if (!this.ckListener.sessionActive)
return;
if (this._ssProxy.screenSaverActive)
return;
global.play_theme_sound(0, 'device-removed-media');
},
_onDriveEjectButton: function(monitor, drive) {
// TODO: this code path is not tested, as the GVfs volume monitor
// doesn't emit this signal just yet.
if (!this.ckListener.sessionActive)
return;
// we force stop/eject in this case, so we don't have to pass a
// mount operation object
if (drive.can_stop()) {
drive.stop
(Gio.MountUnmountFlags.FORCE, null, null,
Lang.bind(this, function(drive, res) {
try {
drive.stop_finish(res);
} catch (e) {
log("Unable to stop the drive after drive-eject-button " + e.toString());
}
}));
} else if (drive.can_eject()) {
drive.eject_with_operation
(Gio.MountUnmountFlags.FORCE, null, null,
Lang.bind(this, function(drive, res) {
try {
drive.eject_with_operation_finish(res);
} catch (e) {
log("Unable to eject the drive after drive-eject-button " + e.toString());
}
}));
}
},
_onVolumeAdded: function(monitor, volume) {
this._checkAndMountVolume(volume);
},
_checkAndMountVolume: function(volume, params) {
params = Params.parse(params, { checkSession: true,
useMountOp: true });
if (params.checkSession) {
// if we're not in the current ConsoleKit session,
// don't attempt automount
if (!this.ckListener.sessionActive)
return;
if (this._ssProxy.screenSaverActive) {
if (this._volumeQueue.indexOf(volume) == -1)
this._volumeQueue.push(volume);
return;
}
}
if (!this._settings.get_boolean(SETTING_ENABLE_AUTOMOUNT) ||
!volume.should_automount() ||
!volume.can_mount()) {
// allow the autorun to run anyway; this can happen if the
// mount gets added programmatically later, even if
// should_automount() or can_mount() are false, like for
// blank optical media.
this._allowAutorun(volume);
this._allowAutorunExpire(volume);
return;
}
if (params.useMountOp) {
let operation = new ShellMountOperation.ShellMountOperation(volume);
this._mountVolume(volume, operation.mountOp);
} else {
this._mountVolume(volume, null);
}
},
_mountVolume: function(volume, operation) {
this._allowAutorun(volume);
volume.mount(0, operation, null,
Lang.bind(this, this._onVolumeMounted));
},
_onVolumeMounted: function(volume, res) {
this._allowAutorunExpire(volume);
try {
volume.mount_finish(res);
} catch (e) {
let string = e.toString();
// FIXME: needs proper error code handling instead of this
// See https://bugzilla.gnome.org/show_bug.cgi?id=591480
if (string.indexOf('No key available with this passphrase') != -1)
this._reaskPassword(volume);
else
log('Unable to mount volume ' + volume.get_name() + ': ' + string);
}
},
_onVolumeRemoved: function(monitor, volume) {
this._volumeQueue =
this._volumeQueue.filter(function(element) {
return (element != volume);
});
},
_reaskPassword: function(volume) {
let operation = new ShellMountOperation.ShellMountOperation(volume, { reaskPassword: true });
this._mountVolume(volume, operation.mountOp);
},
_allowAutorun: function(volume) {
volume.allowAutorun = true;
},
_allowAutorunExpire: function(volume) {
Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, function() {
volume.allowAutorun = false;
return false;
});
}
}

View File

@ -1,634 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Lang = imports.lang;
const DBus = imports.dbus;
const Gio = imports.gi.Gio;
const St = imports.gi.St;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const ShellMountOperation = imports.ui.shellMountOperation;
// GSettings keys
const SETTINGS_SCHEMA = 'org.gnome.desktop.media-handling';
const SETTING_DISABLE_AUTORUN = 'autorun-never';
const SETTING_START_APP = 'autorun-x-content-start-app';
const SETTING_IGNORE = 'autorun-x-content-ignore';
const SETTING_OPEN_FOLDER = 'autorun-x-content-open-folder';
const AutorunSetting = {
RUN: 0,
IGNORE: 1,
FILES: 2,
ASK: 3
};
const HOTPLUG_ICON_SIZE = 16;
// misc utils
function ignoreAutorunForMount(mount) {
let root = mount.get_root();
let volume = mount.get_volume();
if ((root.is_native() && !isMountRootHidden(root)) ||
(volume && volume.allowAutorun && volume.should_automount()))
return false;
return true;
}
function isMountRootHidden(root) {
let path = root.get_path();
// skip any mounts in hidden directory hierarchies
return (path.indexOf('/.') != -1);
}
function startAppForMount(app, mount) {
let files = [];
let root = mount.get_root();
let retval = false;
files.push(root);
try {
retval = app.launch(files,
global.create_app_launch_context())
} catch (e) {
log('Unable to launch the application ' + app.get_name()
+ ': ' + e.toString());
}
return retval;
}
/******************************************/
const HotplugSnifferIface = {
name: 'org.gnome.Shell.HotplugSniffer',
methods: [{ name: 'SniffURI',
inSignature: 's',
outSignature: 'as' }]
};
const HotplugSniffer = function() {
this._init();
};
HotplugSniffer.prototype = {
_init: function() {
DBus.session.proxifyObject(this,
'org.gnome.Shell.HotplugSniffer',
'/org/gnome/Shell/HotplugSniffer');
},
};
DBus.proxifyPrototype(HotplugSniffer.prototype, HotplugSnifferIface);
function ContentTypeDiscoverer(callback) {
this._init(callback);
}
ContentTypeDiscoverer.prototype = {
_init: function(callback) {
this._callback = callback;
},
guessContentTypes: function(mount) {
// guess mount's content types using GIO
mount.guess_content_type(false, null,
Lang.bind(this,
this._onContentTypeGuessed));
},
_onContentTypeGuessed: function(mount, res) {
let contentTypes = [];
try {
contentTypes = mount.guess_content_type_finish(res);
} catch (e) {
log('Unable to guess content types on added mount ' + mount.get_name()
+ ': ' + e.toString());
}
if (contentTypes.length) {
this._emitCallback(mount, contentTypes);
} else {
let root = mount.get_root();
let hotplugSniffer = new HotplugSniffer();
hotplugSniffer.SniffURIRemote
(root.get_uri(), DBus.CALL_FLAG_START,
Lang.bind(this, function(contentTypes) {
this._emitCallback(mount, contentTypes);
}));
}
},
_emitCallback: function(mount, contentTypes) {
if (!contentTypes)
contentTypes = [];
// we're not interested in win32 software content types here
contentTypes = contentTypes.filter(function(type) {
return (type != 'x-content/win32-software');
});
let apps = [];
contentTypes.forEach(function(type) {
let app = Gio.app_info_get_default_for_type(type, false);
if (app)
apps.push(app);
});
if (apps.length == 0)
apps.push(Gio.app_info_get_default_for_type('inode/directory', false));
this._callback(mount, apps, contentTypes);
}
}
function AutorunManager() {
this._init();
}
AutorunManager.prototype = {
_init: function() {
this._volumeMonitor = Gio.VolumeMonitor.get();
this._volumeMonitor.connect('mount-added',
Lang.bind(this,
this._onMountAdded));
this._volumeMonitor.connect('mount-removed',
Lang.bind(this,
this._onMountRemoved));
this._transDispatcher = new AutorunTransientDispatcher();
this._createResidentSource();
let mounts = this._volumeMonitor.get_mounts();
mounts.forEach(Lang.bind(this, function (mount) {
let discoverer = new ContentTypeDiscoverer(Lang.bind (this,
function (mount, apps) {
this._residentSource.addMount(mount, apps);
}));
discoverer.guessContentTypes(mount);
}));
},
_createResidentSource: function() {
this._residentSource = new AutorunResidentSource();
this._residentSource.connect('destroy',
Lang.bind(this,
this._createResidentSource));
},
_onMountAdded: function(monitor, mount) {
// don't do anything if our session is not the currently
// active one
if (!Main.automountManager.ckListener.sessionActive)
return;
let discoverer = new ContentTypeDiscoverer(Lang.bind (this,
function (mount, apps, contentTypes) {
this._transDispatcher.addMount(mount, apps, contentTypes);
this._residentSource.addMount(mount, apps);
}));
discoverer.guessContentTypes(mount);
},
_onMountRemoved: function(monitor, mount) {
this._transDispatcher.removeMount(mount);
this._residentSource.removeMount(mount);
},
ejectMount: function(mount) {
let mountOp = new ShellMountOperation.ShellMountOperation(mount);
// first, see if we have a drive
let drive = mount.get_drive();
let volume = mount.get_volume();
if (drive &&
drive.get_start_stop_type() == Gio.DriveStartStopType.SHUTDOWN &&
drive.can_stop()) {
drive.stop(0, mountOp.mountOp, null,
Lang.bind(this, this._onStop));
} else {
if (mount.can_eject()) {
mount.eject_with_operation(0, mountOp.mountOp, null,
Lang.bind(this, this._onEject));
} else if (volume && volume.can_eject()) {
volume.eject_with_operation(0, mountOp.mountOp, null,
Lang.bind(this, this._onEject));
} else if (drive && drive.can_eject()) {
drive.eject_with_operation(0, mountOp.mountOp, null,
Lang.bind(this, this._onEject));
} else if (mount.can_unmount()) {
mount.unmount_with_operation(0, mountOp.mountOp, null,
Lang.bind(this, this._onUnmount));
}
}
},
_onUnmount: function(mount, res) {
try {
mount.unmount_with_operation_finish(res);
} catch (e) {
// FIXME: we need to ignore G_IO_ERROR_FAILED_HANDLED errors here
// but we can't access the error code from JS.
// See https://bugzilla.gnome.org/show_bug.cgi?id=591480
log('Unable to eject the mount ' + mount.get_name()
+ ': ' + e.toString());
}
},
_onEject: function(source, res) {
try {
source.eject_with_operation_finish(res);
} catch (e) {
// FIXME: we need to ignore G_IO_ERROR_FAILED_HANDLED errors here
// but we can't access the error code from JS.
// See https://bugzilla.gnome.org/show_bug.cgi?id=591480
log('Unable to eject the drive ' + source.get_name()
+ ': ' + e.toString());
}
},
_onStop: function(drive, res) {
try {
drive.stop_finish(res);
} catch (e) {
// FIXME: we need to ignore G_IO_ERROR_FAILED_HANDLED errors here
// but we can't access the error code from JS.
// See https://bugzilla.gnome.org/show_bug.cgi?id=591480
log('Unable to stop the drive ' + drive.get_name()
+ ': ' + e.toString());
}
},
}
function AutorunResidentSource() {
this._init();
}
AutorunResidentSource.prototype = {
__proto__: MessageTray.Source.prototype,
_init: function() {
MessageTray.Source.prototype._init.call(this, _('Removable Devices'));
this._mounts = [];
this._notification = new AutorunResidentNotification(this);
this._setSummaryIcon(this.createNotificationIcon(HOTPLUG_ICON_SIZE));
},
addMount: function(mount, apps) {
if (ignoreAutorunForMount(mount))
return;
let filtered = this._mounts.filter(function (element) {
return (element.mount == mount);
});
if (filtered.length != 0)
return;
let element = { mount: mount, apps: apps };
this._mounts.push(element);
this._redisplay();
},
removeMount: function(mount) {
this._mounts =
this._mounts.filter(function (element) {
return (element.mount != mount);
});
this._redisplay();
},
_redisplay: function() {
if (this._mounts.length == 0) {
this._notification.destroy();
this.destroy();
return;
}
this._notification.updateForMounts(this._mounts);
// add ourselves as a source, and push the notification
if (!Main.messageTray.contains(this)) {
Main.messageTray.add(this);
this.pushNotification(this._notification);
}
},
createNotificationIcon: function(iconSize) {
return new St.Icon ({ icon_name: 'drive-harddisk',
icon_size: iconSize ? iconSize : this.ICON_SIZE });
}
}
function AutorunResidentNotification(source) {
this._init(source);
}
AutorunResidentNotification.prototype = {
__proto__: MessageTray.Notification.prototype,
_init: function(source) {
MessageTray.Notification.prototype._init.call(this, source,
source.title, null,
{ customContent: true });
// set the notification as resident
this.setResident(true);
this._layout = new St.BoxLayout ({ style_class: 'hotplug-resident-box',
vertical: true });
this.addActor(this._layout,
{ x_expand: true,
x_fill: true });
},
updateForMounts: function(mounts) {
// remove all the layout content
this._layout.destroy_children();
for (let idx = 0; idx < mounts.length; idx++) {
let element = mounts[idx];
let actor = this._itemForMount(element.mount, element.apps);
this._layout.add(actor, { x_fill: true,
expand: true });
}
},
_itemForMount: function(mount, apps) {
let item = new St.BoxLayout();
// prepare the mount button content
let mountLayout = new St.BoxLayout();
let mountIcon = new St.Icon({ gicon: mount.get_icon(),
style_class: 'hotplug-resident-mount-icon' });
mountLayout.add_actor(mountIcon);
let labelBin = new St.Bin({ y_align: St.Align.MIDDLE });
let mountLabel =
new St.Label({ text: mount.get_name(),
style_class: 'hotplug-resident-mount-label',
track_hover: true,
reactive: true });
labelBin.add_actor(mountLabel);
mountLayout.add_actor(labelBin);
let mountButton = new St.Button({ child: mountLayout,
x_align: St.Align.START,
x_fill: true,
style_class: 'hotplug-resident-mount',
button_mask: St.ButtonMask.ONE });
item.add(mountButton, { x_align: St.Align.START,
expand: true });
let ejectIcon =
new St.Icon({ icon_name: 'media-eject',
style_class: 'hotplug-resident-eject-icon' });
let ejectButton =
new St.Button({ style_class: 'hotplug-resident-eject-button',
button_mask: St.ButtonMask.ONE,
child: ejectIcon });
item.add(ejectButton, { x_align: St.Align.END });
// now connect signals
mountButton.connect('clicked', Lang.bind(this, function(actor, event) {
startAppForMount(apps[0], mount);
}));
ejectButton.connect('clicked', Lang.bind(this, function() {
Main.autorunManager.ejectMount(mount);
}));
return item;
},
}
function AutorunTransientDispatcher() {
this._init();
}
AutorunTransientDispatcher.prototype = {
_init: function() {
this._sources = [];
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
},
_getAutorunSettingForType: function(contentType) {
let runApp = this._settings.get_strv(SETTING_START_APP);
if (runApp.indexOf(contentType) != -1)
return AutorunSetting.RUN;
let ignore = this._settings.get_strv(SETTING_IGNORE);
if (ignore.indexOf(contentType) != -1)
return AutorunSetting.IGNORE;
let openFiles = this._settings.get_strv(SETTING_OPEN_FOLDER);
if (openFiles.indexOf(contentType) != -1)
return AutorunSetting.FILES;
return AutorunSetting.ASK;
},
_getSourceForMount: function(mount) {
let filtered =
this._sources.filter(function (source) {
return (source.mount == mount);
});
// we always make sure not to add two sources for the same
// mount in addMount(), so it's safe to assume filtered.length
// is always either 1 or 0.
if (filtered.length == 1)
return filtered[0];
return null;
},
_addSource: function(mount, apps) {
// if we already have a source showing for this
// mount, return
if (this._getSourceForMount(mount))
return;
// add a new source
this._sources.push(new AutorunTransientSource(mount, apps));
},
addMount: function(mount, apps, contentTypes) {
// if autorun is disabled globally, return
if (this._settings.get_boolean(SETTING_DISABLE_AUTORUN))
return;
// if the mount doesn't want to be autorun, return
if (ignoreAutorunForMount(mount))
return;
let setting = this._getAutorunSettingForType(contentTypes[0]);
// check at the settings for the first content type
// to see whether we should ask
if (setting == AutorunSetting.IGNORE)
return; // return right away
let success = false;
let app = null;
if (setting == AutorunSetting.RUN) {
app = Gio.app_info_get_default_for_type(type, false);
} else if (setting == AutorunSetting.FILES) {
app = Gio.app_info_get_default_for_type('inode/directory', false);
}
if (app)
success = startAppForMount(app, mount);
// we fallback here also in case the settings did not specify 'ask',
// but we failed launching the default app or the default file manager
if (!success)
this._addSource(mount, apps);
},
removeMount: function(mount) {
let source = this._getSourceForMount(mount);
// if we aren't tracking this mount, don't do anything
if (!source)
return;
// destroy the notification source
source.destroy();
}
}
function AutorunTransientSource(mount, apps) {
this._init(mount, apps);
}
AutorunTransientSource.prototype = {
__proto__: MessageTray.Source.prototype,
_init: function(mount, apps) {
MessageTray.Source.prototype._init.call(this, mount.get_name());
this.mount = mount;
this.apps = apps;
this._notification = new AutorunTransientNotification(this);
this._setSummaryIcon(this.createNotificationIcon(this.ICON_SIZE));
// add ourselves as a source, and popup the notification
Main.messageTray.add(this);
this.notify(this._notification);
},
createNotificationIcon: function(iconSize) {
return new St.Icon({ gicon: this.mount.get_icon(),
icon_size: iconSize ? iconSize : this.ICON_SIZE });
}
}
function AutorunTransientNotification(source) {
this._init(source);
}
AutorunTransientNotification.prototype = {
__proto__: MessageTray.Notification.prototype,
_init: function(source) {
MessageTray.Notification.prototype._init.call(this, source,
source.title, null,
{ customContent: true });
this._box = new St.BoxLayout({ style_class: 'hotplug-transient-box',
vertical: true });
this.addActor(this._box);
this._mount = source.mount;
source.apps.forEach(Lang.bind(this, function (app) {
let actor = this._buttonForApp(app);
if (actor)
this._box.add(actor, { x_fill: true,
x_align: St.Align.START });
}));
this._box.add(this._buttonForEject(), { x_fill: true,
x_align: St.Align.START });
// set the notification to transient and urgent, so that it
// expands out
this.setTransient(true);
this.setUrgency(MessageTray.Urgency.CRITICAL);
},
_buttonForApp: function(app) {
let box = new St.BoxLayout();
let icon = new St.Icon({ gicon: app.get_icon(),
style_class: 'hotplug-notification-item-icon' });
box.add(icon);
let label = new St.Bin({ y_align: St.Align.MIDDLE,
child: new St.Label
({ text: _("Open with %s").format(app.get_display_name()) })
});
box.add(label);
let button = new St.Button({ child: box,
x_fill: true,
x_align: St.Align.START,
button_mask: St.ButtonMask.ONE,
style_class: 'hotplug-notification-item' });
button.connect('clicked', Lang.bind(this, function() {
startAppForMount(app, this._mount);
this.destroy();
}));
return button;
},
_buttonForEject: function() {
let box = new St.BoxLayout();
let icon = new St.Icon({ icon_name: 'media-eject',
style_class: 'hotplug-notification-item-icon' });
box.add(icon);
let label = new St.Bin({ y_align: St.Align.MIDDLE,
child: new St.Label
({ text: _("Eject") })
});
box.add(label);
let button = new St.Button({ child: box,
x_fill: true,
x_align: St.Align.START,
button_mask: St.ButtonMask.ONE,
style_class: 'hotplug-notification-item' });
button.connect('clicked', Lang.bind(this, function() {
Main.autorunManager.ejectMount(this._mount);
}));
return button;
}
}

View File

@ -6,7 +6,6 @@ const Meta = imports.gi.Meta;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const POPUP_ANIMATION_TIME = 0.15;
@ -330,7 +329,7 @@ BoxPointer.prototype = {
// We also want to keep it onscreen, and separated from the
// edge by the same distance as the main part of the box is
// separated from its sourceActor
let primary = Main.layoutManager.primaryMonitor;
let primary = global.get_primary_monitor();
let themeNode = this.actor.get_theme_node();
let borderWidth = themeNode.get_length('-arrow-border-width');
let arrowBase = themeNode.get_length('-arrow-base');

View File

@ -8,6 +8,9 @@ const St = imports.gi.St;
const Signals = imports.signals;
const Pango = imports.gi.Pango;
const Gettext_gtk30 = imports.gettext.domain('gtk30');
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const C_ = Gettext.pgettext;
const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;

View File

@ -8,13 +8,13 @@ const Signals = imports.signals;
const Main = imports.ui.main;
const Params = imports.misc.params;
const ScreenSaver = imports.misc.screenSaver;
// This manages the shell "chrome"; the UI that's visible in the
// normal mode (ie, outside the Overview), that surrounds the main
// workspace content.
const defaultParams = {
visibleInOverview: false,
visibleInFullscreen: false,
affectsStruts: true,
affectsInputRegion: true
@ -36,8 +36,8 @@ Chrome.prototype = {
this._trackedActors = [];
Main.layoutManager.connect('monitors-changed',
Lang.bind(this, this._relayout));
global.screen.connect('monitors-changed',
Lang.bind(this, this._monitorsChanged));
global.screen.connect('restacked',
Lang.bind(this, this._windowsRestacked));
@ -50,15 +50,9 @@ Chrome.prototype = {
Main.overview.connect('hidden',
Lang.bind(this, this._overviewHidden));
this._screenSaverProxy = new ScreenSaver.ScreenSaverProxy();
this._screenSaverProxy.connect('ActiveChanged', Lang.bind(this, this._onScreenSaverActiveChanged));
this._screenSaverProxy.GetActiveRemote(Lang.bind(this,
function(result, err) {
if (!err)
this._onScreenSaverActiveChanged(this._screenSaverProxy, result);
}));
this._relayout();
this._updateMonitors();
this._updateFullscreen();
this._queueUpdateRegions();
},
_allocated: function(actor, box, flags) {
@ -79,8 +73,11 @@ Chrome.prototype = {
// in its visibility will affect the input region, but NOT the
// struts.
//
// If %visibleInFullscreen is %true, the actor will be visible
// even when a fullscreen window should be covering it.
// If %visibleInOverview is %true in @params, @actor will remain
// visible when the overview is brought up. Otherwise it will
// automatically be hidden. Likewise, if %visibleInFullscreen is
// %true, the actor will be visible even when a fullscreen window
// should be covering it.
//
// If %affectsStruts or %affectsInputRegion is %false, the actor
// will not have the indicated effect.
@ -99,7 +96,7 @@ Chrome.prototype = {
//
// @params can have any of the same values as in addActor(), though
// some possibilities don't make sense (eg, trying to have a
// %visibleInFullscreen child of a non-%visibleInFullscreen parent).
// %visibleInOverview child of a non-%visibleInOverview parent).
// By default, @actor has the same params as its chrome ancestor.
trackActor: function(actor, params) {
let ancestor = actor.get_parent();
@ -192,8 +189,10 @@ Chrome.prototype = {
_updateVisibility: function() {
for (let i = 0; i < this._trackedActors.length; i++) {
let actorData = this._trackedActors[i];
if (!this._inOverview && !actorData.visibleInFullscreen &&
this._findMonitorForActor(actorData.actor).inFullscreen)
if (this._inOverview && !actorData.visibleInOverview)
this.actor.set_skip_paint(actorData.actor, true);
else if (!this._inOverview && !actorData.visibleInFullscreen &&
this._findMonitorForActor(actorData.actor).inFullscreen)
this.actor.set_skip_paint(actorData.actor, true);
else
this.actor.set_skip_paint(actorData.actor, false);
@ -212,18 +211,18 @@ Chrome.prototype = {
this._queueUpdateRegions();
},
_relayout: function() {
this._monitors = Main.layoutManager.monitors;
this._primaryMonitor = Main.layoutManager.primaryMonitor;
this._updateFullscreen();
this._updateVisibility();
this._queueUpdateRegions();
},
_onScreenSaverActiveChanged: function(proxy, screenSaverActive) {
this.actor.visible = !screenSaverActive;
this._queueUpdateRegions();
_updateMonitors: function() {
let monitors = global.get_monitors();
let primary = global.get_primary_monitor();
this._monitors = monitors;
for (let i = 0; i < monitors.length; i++) {
let monitor = monitors[i];
if (monitor.x == primary.x &&
monitor.y == primary.y &&
monitor.width == primary.width &&
monitor.height == primary.height)
this._primaryMonitor = monitor;
}
},
_findMonitorForRect: function(x, y, w, h) {
@ -262,6 +261,15 @@ Chrome.prototype = {
return this._primaryMonitor; // Not on any monitor, pretend its on the primary
},
_monitorsChanged: function() {
this._updateMonitors();
// Update everything that depends on monitor positions
this._updateFullscreen();
this._updateVisibility();
this._queueUpdateRegions();
},
_queueUpdateRegions: function() {
if (!this._updateRegionIdle)
this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this._updateRegions),
@ -289,11 +297,6 @@ Chrome.prototype = {
for (let i = windows.length - 1; i > -1; i--) {
let window = windows[i];
// Skip minimized windows
if (!window.showing_on_its_workspace())
continue;
let layer = window.get_meta_window().get_layer();
if (layer == Meta.StackLayer.FULLSCREEN) {
@ -332,6 +335,11 @@ Chrome.prototype = {
this._updateVisibility();
this._queueUpdateRegions();
}
// Figure out where the pointer is in case we lost track of
// it during a grab. (In particular, if a trayicon popup menu
// is dismissed, see if we need to close the message tray.)
global.sync_pointer();
},
_updateRegions: function() {

View File

@ -153,14 +153,14 @@ CtrlAltTabPopup.prototype = {
},
_getPreferredWidth: function (actor, forHeight, alloc) {
let primary = Main.layoutManager.primaryMonitor;
let primary = global.get_primary_monitor();
alloc.min_size = primary.width;
alloc.natural_size = primary.width;
},
_getPreferredHeight: function (actor, forWidth, alloc) {
let primary = Main.layoutManager.primaryMonitor;
let primary = global.get_primary_monitor();
alloc.min_size = primary.height;
alloc.natural_size = primary.height;
@ -168,7 +168,7 @@ CtrlAltTabPopup.prototype = {
_allocate: function (actor, box, flags) {
let childBox = new Clutter.ActorBox();
let primary = Main.layoutManager.primaryMonitor;
let primary = global.get_primary_monitor();
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
let vPadding = this.actor.get_theme_node().get_vertical_padding();
@ -323,6 +323,6 @@ CtrlAltTabSwitcher.prototype = {
let text = new St.Label({ text: item.name });
box.add(text, { x_fill: false });
this.addItem(box, text);
this.addItem(box);
}
};

View File

@ -6,6 +6,8 @@ const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const AppDisplay = imports.ui.appDisplay;
const AppFavorites = imports.ui.appFavorites;
@ -324,7 +326,7 @@ Dash.prototype = {
this._favRemoveTarget = null;
}));
}
DND.removeDragMonitor(this._dragMonitor);
DND.removeMonitor(this._dragMonitor);
},
_onDragMotion: function(dragEvent) {
@ -342,10 +344,7 @@ Dash.prototype = {
let srcIsFavorite = (id in favorites);
if (srcIsFavorite &&
dragEvent.source.actor &&
this.actor.contains (dragEvent.source.actor) &&
this._favRemoveTarget == null) {
if (srcIsFavorite && this._favRemoveTarget == null) {
this._favRemoveTarget = new RemoveFavoriteIcon();
this._favRemoveTarget.icon.setIconSize(this.iconSize);
this._box.add(this._favRemoveTarget.actor);

View File

@ -8,6 +8,8 @@ const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Util = imports.misc.util;
const Main = imports.ui.main;
@ -198,7 +200,6 @@ DateMenuButton.prototype = {
_onPreferencesActivate: function() {
this.menu.close();
Main.overview.hide();
let app = Shell.AppSystem.get_default().get_app('gnome-datetime-panel.desktop');
app.activate(-1);
},

View File

@ -61,7 +61,7 @@ function addDragMonitor(monitor) {
dragMonitors.push(monitor);
}
function removeDragMonitor(monitor) {
function removeMonitor(monitor) {
for (let i = 0; i < dragMonitors.length; i++)
if (dragMonitors[i] == monitor) {
dragMonitors.splice(i, 1);
@ -284,13 +284,13 @@ _Draggable.prototype = {
this._dragOffsetY = actorStageY - this._dragStartY;
// Set the actor's scale such that it will keep the same
// transformed size when it's reparented to the uiGroup
// transformed size when it's reparented to the stage
let [scaledWidth, scaledHeight] = this.actor.get_transformed_size();
this.actor.set_scale(scaledWidth / this.actor.width,
scaledHeight / this.actor.height);
}
this._dragActor.reparent(Main.uiGroup);
this._dragActor.reparent(this.actor.get_stage());
this._dragActor.raise_top();
Shell.util_set_hidden_from_pick(this._dragActor, true);
@ -442,7 +442,7 @@ _Draggable.prototype = {
return true;
// If it accepted the drop without taking the actor,
// handle it ourselves.
if (this._dragActor.get_parent() == Main.uiGroup) {
if (this._dragActor.get_parent() == this._dragActor.get_stage()) {
if (this._restoreOnSuccess) {
this._restoreDragActor(event.get_time());
return true;

View File

@ -1,5 +1,8 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const DocInfo = imports.misc.docInfo;
const Params = imports.misc.params;
const Search = imports.ui.search;

View File

@ -22,6 +22,9 @@ const DBus = imports.dbus;
const Lang = imports.lang;
const Signals = imports.signals;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Clutter = imports.gi.Clutter;
const Gdm = imports.gi.Gdm;
const GLib = imports.gi.GLib;

View File

@ -1,22 +1,14 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
imports.gi.versions.Clutter = '1.0';
imports.gi.versions.Gio = '2.0';
imports.gi.versions.Gdk = '3.0';
imports.gi.versions.GdkPixbuf = '2.0';
imports.gi.versions.Gtk = '3.0';
const Clutter = imports.gi.Clutter;;
const Gettext = imports.gettext;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Gettext_gtk30 = imports.gettext.domain('gtk30');
// We can't import shell JS modules yet, because they may have
// variable initializations, etc, that depend on init() already having
// been run.
const Tweener = imports.ui.tweener;
const Format = imports.misc.format;
// "monkey patch" in some varargs ClutterContainer methods; we need
// to do this per-container class since there is no representation
@ -39,42 +31,49 @@ function _patchContainerClass(containerClass) {
};
}
// Replace @method with something that throws an error instead
function _blockMethod(method, replacement, reason) {
let match = method.match(/^(.+)\.([^.]+)$/);
if (!match)
throw new Error('Bad method name "' + method + '"');
let proto = 'imports.gi.' + match[1] + '.prototype';
let property = match[2];
if (!global.set_property_mutable(proto, property, true))
throw new Error('Bad method name "' + method + '"');
// eval() is evil in general, but we know it's safe here since
// set_property_mutable() would have failed if proto was
// malformed.
let node = eval(proto);
let msg = 'Do not use "' + method + '".';
if (replacement)
msg += ' Use "' + replacement + '" instead.';
if (reason)
msg += ' (' + reason + ')';
node[property] = function() {
throw new Error(msg);
};
global.set_property_mutable(proto, property, false);
}
function init() {
// Add some bindings to the global JS namespace; (gjs keeps the web
// browser convention of having that namespace be called 'window'.)
window.global = Shell.Global.get();
window._ = Gettext.gettext;
window.C_ = Gettext.pgettext;
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
_patchContainerClass(St.BoxLayout);
_patchContainerClass(St.Table);
Clutter.Actor.prototype.toString = function() {
return St.describe_actor(this);
};
let origToString = Object.prototype.toString;
Object.prototype.toString = function() {
let base = origToString.call(this);
if ('actor' in this && this.actor instanceof Clutter.Actor)
return base.replace(/\]$/, ' delegate for ' + this.actor.toString().substring(1));
else
return base;
};
Tweener.init();
String.prototype.format = Format.format;
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=508783
Date.prototype.toLocaleFormat = function(format) {
return Shell.util_format_date(format, this.getTime());
};
// Set the default direction for St widgets (this needs to be done before any use of St)
if (Gettext_gtk30.gettext('default:LTR') == 'default:RTL') {
St.Widget.set_default_direction(St.TextDirection.RTL);
}
let slowdownEnv = GLib.getenv('GNOME_SHELL_SLOWDOWN_FACTOR');
if (slowdownEnv) {
let factor = parseFloat(slowdownEnv);
@ -82,10 +81,24 @@ function init() {
St.set_slow_down_factor(factor);
}
// OK, now things are initialized enough that we can import shell JS
const Format = imports.misc.format;
const Tweener = imports.ui.tweener;
_patchContainerClass(St.BoxLayout);
_patchContainerClass(St.Table);
Tweener.init();
String.prototype.format = Format.format;
Clutter.Actor.prototype.toString = function() {
return St.describe_actor(this);
};
if (window.global === undefined) // test environment
return;
_blockMethod('Clutter.Event.get_state', 'Shell.get_event_state',
'gjs\'s handling of Clutter.ModifierType is broken. See bug 597292.');
_blockMethod('Gdk.Window.get_device_position', 'global.get_pointer',
'gjs\'s handling of Gdk.ModifierType is broken. See bug 597292.');
// Now close the back door to prevent extensions from trying to
// abuse it. We can't actually delete it since
// Shell.Global.prototype itself is read-only.
global.set_property_mutable('imports.gi.Shell.Global.prototype', 'set_property_mutable', true);
Shell.Global.prototype.set_property_mutable = undefined;
}

View File

@ -23,9 +23,8 @@ const ExtensionType = {
const extensionMeta = {};
// Maps uuid -> importer object (extension directory tree)
const extensions = {};
// Arrays of uuids
// Array of uuids
var disabledExtensions;
var enabledExtensions;
// GFile for user extensions
var userExtensionsDir = null;
@ -179,7 +178,6 @@ function init() {
}
disabledExtensions = global.settings.get_strv('disabled-extensions', -1);
enabledExtensions = global.settings.get_strv('enabled-extensions', -1);
}
function _loadExtensionsIn(dir, type) {
@ -197,10 +195,7 @@ function _loadExtensionsIn(dir, type) {
if (fileType != Gio.FileType.DIRECTORY)
continue;
let name = info.get_name();
// Enable all but disabled extensions if enabledExtensions is not set.
// If it is set, enable one those, except they are disabled as well.
let enabled = (enabledExtensions.length == 0 || enabledExtensions.indexOf(name) >= 0)
&& disabledExtensions.indexOf(name) < 0;
let enabled = disabledExtensions.indexOf(name) < 0;
let child = dir.get_child(name);
loadExtension(child, enabled, type);
}

View File

@ -42,10 +42,10 @@ BaseIcon.prototype = {
box.add_actor(this._iconBin);
if (params.showLabel) {
this.label = new St.Label({ text: label });
box.add_actor(this.label);
this._name = new St.Label({ text: label });
box.add_actor(this._name);
} else {
this.label = null;
this._name = null;
}
if (params.createIcon)
@ -67,8 +67,8 @@ BaseIcon.prototype = {
let childBox = new Clutter.ActorBox();
if (this.label) {
let [labelMinHeight, labelNatHeight] = this.label.get_preferred_height(-1);
if (this._name) {
let [labelMinHeight, labelNatHeight] = this._name.get_preferred_height(-1);
preferredHeight += this._spacing + labelNatHeight;
let labelHeight = availHeight >= preferredHeight ? labelNatHeight
@ -79,7 +79,7 @@ BaseIcon.prototype = {
childBox.x2 = availWidth;
childBox.y1 = iconSize + this._spacing;
childBox.y2 = childBox.y1 + labelHeight;
this.label.allocate(childBox, flags);
this._name.allocate(childBox, flags);
}
childBox.x1 = Math.floor((availWidth - iconNatWidth) / 2);
@ -98,8 +98,8 @@ BaseIcon.prototype = {
alloc.min_size = iconMinHeight;
alloc.natural_size = iconNatHeight;
if (this.label) {
let [labelMinHeight, labelNatHeight] = this.label.get_preferred_height(forWidth);
if (this._name) {
let [labelMinHeight, labelNatHeight] = this._name.get_preferred_height(forWidth);
alloc.min_size += this._spacing + labelMinHeight;
alloc.natural_size += this._spacing + labelNatHeight;
}

View File

@ -1,323 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Signals = imports.signals;
const St = imports.gi.St;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
function LayoutManager() {
this._init.apply(this, arguments);
}
LayoutManager.prototype = {
_init: function () {
this._rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL);
this.monitors = [];
this.primaryMonitor = null;
this.primaryIndex = -1;
this._hotCorners = [];
this._updateMonitors();
},
// This is called by Main after everything else is constructed;
// _updateHotCorners needs access to Main.panel, which didn't exist
// yet when the LayoutManager was constructed.
init: function() {
global.screen.connect('monitors-changed', Lang.bind(this, this._monitorsChanged));
this._updateHotCorners();
},
_updateMonitors: function() {
let screen = global.screen;
this.monitors = [];
let nMonitors = screen.get_n_monitors();
for (let i = 0; i < nMonitors; i++)
this.monitors.push(screen.get_monitor_geometry(i));
if (nMonitors == 1) {
this.primaryIndex = this.bottomIndex = 0;
} else {
// If there are monitors below the primary, then we need
// to split primary from bottom.
this.primaryIndex = this.bottomIndex = screen.get_primary_monitor();
for (let i = 0; i < this.monitors.length; i++) {
let monitor = this.monitors[i];
if (this._isAboveOrBelowPrimary(monitor)) {
if (monitor.y > this.monitors[this.bottomIndex].y)
this.bottomIndex = i;
}
}
}
this.primaryMonitor = this.monitors[this.primaryIndex];
this.bottomMonitor = this.monitors[this.bottomIndex];
},
_updateHotCorners: function() {
// destroy old hot corners
for (let i = 0; i < this._hotCorners.length; i++)
this._hotCorners[i].destroy();
this._hotCorners = [];
// build new hot corners
for (let i = 0; i < this.monitors.length; i++) {
if (i == this.primaryIndex)
continue;
let monitor = this.monitors[i];
let cornerX = this._rtl ? monitor.x + monitor.width : monitor.x;
let cornerY = monitor.y;
let haveTopLeftCorner = true;
// Check if we have a top left (right for RTL) corner.
// I.e. if there is no monitor directly above or to the left(right)
let besideX = this._rtl ? monitor.x + 1 : cornerX - 1;
let besideY = cornerY;
let aboveX = cornerX;
let aboveY = cornerY - 1;
for (let j = 0; j < this.monitors.length; j++) {
if (i == j)
continue;
let otherMonitor = this.monitors[j];
if (besideX >= otherMonitor.x &&
besideX < otherMonitor.x + otherMonitor.width &&
besideY >= otherMonitor.y &&
besideY < otherMonitor.y + otherMonitor.height) {
haveTopLeftCorner = false;
break;
}
if (aboveX >= otherMonitor.x &&
aboveX < otherMonitor.x + otherMonitor.width &&
aboveY >= otherMonitor.y &&
aboveY < otherMonitor.y + otherMonitor.height) {
haveTopLeftCorner = false;
break;
}
}
if (!haveTopLeftCorner)
continue;
let corner = new HotCorner();
this._hotCorners.push(corner);
corner.actor.set_position(cornerX, cornerY);
Main.chrome.addActor(corner.actor, { affectsStruts: false });
}
},
_monitorsChanged: function() {
this._updateMonitors();
this._updateHotCorners();
this.emit('monitors-changed');
},
_isAboveOrBelowPrimary: function(monitor) {
let primary = this.monitors[this.primaryIndex];
let monitorLeft = monitor.x, monitorRight = monitor.x + monitor.width;
let primaryLeft = primary.x, primaryRight = primary.x + primary.width;
if ((monitorLeft >= primaryLeft && monitorLeft <= primaryRight) ||
(monitorRight >= primaryLeft && monitorRight <= primaryRight) ||
(primaryLeft >= monitorLeft && primaryLeft <= monitorRight) ||
(primaryRight >= monitorLeft && primaryRight <= monitorRight))
return true;
return false;
},
get focusIndex() {
let screen = global.screen;
let display = screen.get_display();
let focusWindow = display.focus_window;
if (focusWindow) {
let wrect = focusWindow.get_outer_rect();
for (let i = 0; i < this.monitors.length; i++) {
let monitor = this.monitors[i];
if (monitor.x <= wrect.x && monitor.y <= wrect.y &&
monitor.x + monitor.width > wrect.x &&
monitor.y + monitor.height > wrect.y)
return i;
}
}
return this.primaryIndex;
},
get focusMonitor() {
return this.monitors[this.focusIndex];
}
};
Signals.addSignalMethods(LayoutManager.prototype);
// HotCorner:
//
// This class manages a "hot corner" that can toggle switching to
// overview.
function HotCorner() {
this._init();
}
HotCorner.prototype = {
_init : function() {
// We use this flag to mark the case where the user has entered the
// hot corner and has not left both the hot corner and a surrounding
// guard area (the "environs"). This avoids triggering the hot corner
// multiple times due to an accidental jitter.
this._entered = false;
this.actor = new Clutter.Group({ name: 'hot-corner-environs',
width: 3,
height: 3,
reactive: true });
this._corner = new Clutter.Rectangle({ name: 'hot-corner',
width: 1,
height: 1,
opacity: 0,
reactive: true });
this._corner._delegate = this;
this.actor.add_actor(this._corner);
if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
this._corner.set_position(this.actor.width - this._corner.width, 0);
this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
} else {
this._corner.set_position(0, 0);
}
this._activationTime = 0;
this.actor.connect('leave-event',
Lang.bind(this, this._onEnvironsLeft));
// Clicking on the hot corner environs should result in the
// same behavior as clicking on the hot corner.
this.actor.connect('button-release-event',
Lang.bind(this, this._onCornerClicked));
// In addition to being triggered by the mouse enter event,
// the hot corner can be triggered by clicking on it. This is
// useful if the user wants to undo the effect of triggering
// the hot corner once in the hot corner.
this._corner.connect('enter-event',
Lang.bind(this, this._onCornerEntered));
this._corner.connect('button-release-event',
Lang.bind(this, this._onCornerClicked));
this._corner.connect('leave-event',
Lang.bind(this, this._onCornerLeft));
},
destroy: function() {
this.actor.destroy();
},
_addRipple : function(delay, time, startScale, startOpacity, finalScale, finalOpacity) {
// We draw a ripple by using a source image and animating it scaling
// outwards and fading away. We want the ripples to move linearly
// or it looks unrealistic, but if the opacity of the ripple goes
// linearly to zero it fades away too quickly, so we use Tweener's
// 'onUpdate' to give a non-linear curve to the fade-away and make
// it more visible in the middle section.
let [x, y] = this._corner.get_transformed_position();
let ripple = new St.BoxLayout({ style_class: 'ripple-box',
opacity: 255 * Math.sqrt(startOpacity),
scale_x: startScale,
scale_y: startScale,
x: x,
y: y });
ripple._opacity = startOpacity;
if (ripple.get_direction() == St.TextDirection.RTL)
ripple.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
Tweener.addTween(ripple, { _opacity: finalOpacity,
scale_x: finalScale,
scale_y: finalScale,
delay: delay,
time: time,
transition: 'linear',
onUpdate: function() { ripple.opacity = 255 * Math.sqrt(ripple._opacity); },
onComplete: function() { ripple.destroy(); } });
Main.uiGroup.add_actor(ripple);
},
rippleAnimation: function() {
// Show three concentric ripples expanding outwards; the exact
// parameters were found by trial and error, so don't look
// for them to make perfect sense mathematically
// delay time scale opacity => scale opacity
this._addRipple(0.0, 0.83, 0.25, 1.0, 1.5, 0.0);
this._addRipple(0.05, 1.0, 0.0, 0.7, 1.25, 0.0);
this._addRipple(0.35, 1.0, 0.0, 0.3, 1, 0.0);
},
handleDragOver: function(source, actor, x, y, time) {
if (source != Main.xdndHandler)
return;
if (!Main.overview.visible && !Main.overview.animationInProgress) {
this.rippleAnimation();
Main.overview.showTemporarily();
Main.overview.beginItemDrag(actor);
}
},
_onCornerEntered : function() {
if (!this._entered) {
this._entered = true;
if (!Main.overview.animationInProgress) {
this._activationTime = Date.now() / 1000;
this.rippleAnimation();
Main.overview.toggle();
}
}
return false;
},
_onCornerClicked : function() {
if (this.shouldToggleOverviewOnClick())
Main.overview.toggle();
return true;
},
_onCornerLeft : function(actor, event) {
if (event.get_related() != this.actor)
this._entered = false;
// Consume event, otherwise this will confuse onEnvironsLeft
return true;
},
_onEnvironsLeft : function(actor, event) {
if (event.get_related() != this._corner)
this._entered = false;
return false;
},
// Checks if the Activities button is currently sensitive to
// clicks. The first call to this function within the
// HOT_CORNER_ACTIVATION_TIMEOUT time of the hot corner being
// triggered will return false. This avoids opening and closing
// the overview if the user both triggered the hot corner and
// clicked the Activities button.
shouldToggleOverviewOnClick: function() {
if (Main.overview.animationInProgress)
return false;
if (this._activationTime == 0 || Date.now() / 1000 - this._activationTime > HOT_CORNER_ACTIVATION_TIMEOUT)
return true;
return false;
}
};

View File

@ -5,13 +5,14 @@ const Cogl = imports.gi.Cogl;
const GConf = imports.gi.GConf;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Pango = imports.gi.Pango;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const History = imports.misc.history;
const ExtensionSystem = imports.ui.extensionSystem;
@ -99,19 +100,12 @@ Notebook.prototype = {
selectIndex: function(index) {
if (index == this._selectedIndex)
return;
this._unselect();
if (index < 0) {
this._unselect();
this.emit('selection', null);
return;
}
// Focus the new tab before unmapping the old one
let tabData = this._tabs[index];
if (!tabData.scrollView.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false))
this.actor.grab_key_focus();
this._unselect();
tabData.labelBox.add_style_pseudo_class('selected');
tabData.scrollView.show();
this._selectedIndex = index;
@ -436,7 +430,7 @@ Inspector.prototype = {
if (!this._eventHandler)
return;
let primary = Main.layoutManager.primaryMonitor;
let primary = global.get_primary_monitor();
let [minWidth, minHeight, natWidth, natHeight] =
this._eventHandler.get_preferred_size();
@ -582,53 +576,6 @@ ErrorLog.prototype = {
}
};
function Memory() {
this._init();
}
Memory.prototype = {
_init: function() {
this.actor = new St.BoxLayout({ vertical: true });
this._glibc_uordblks = new St.Label();
this.actor.add(this._glibc_uordblks);
this._js_bytes = new St.Label();
this.actor.add(this._js_bytes);
this._gjs_boxed = new St.Label();
this.actor.add(this._gjs_boxed);
this._gjs_gobject = new St.Label();
this.actor.add(this._gjs_gobject);
this._gjs_function = new St.Label();
this.actor.add(this._gjs_function);
this._gjs_closure = new St.Label();
this.actor.add(this._gjs_closure);
this._gcbutton = new St.Button({ label: 'Full GC',
style_class: 'lg-obj-inspector-button' });
this._gcbutton.connect('clicked', Lang.bind(this, function () { global.gc(); this._renderText(); }));
this.actor.add(this._gcbutton, { x_align: St.Align.START,
x_fill: false });
this.actor.connect('notify::mapped', Lang.bind(this, this._renderText));
},
_renderText: function() {
if (!this.actor.mapped)
return;
let memInfo = global.get_memory_info();
this._glibc_uordblks.text = 'glibc_uordblks: ' + memInfo.glibc_uordblks;
this._js_bytes.text = 'js bytes: ' + memInfo.js_bytes;
this._gjs_boxed.text = 'gjs_boxed: ' + memInfo.gjs_boxed;
this._gjs_gobject.text = 'gjs_gobject: ' + memInfo.gjs_gobject;
this._gjs_function.text = 'gjs_function: ' + memInfo.gjs_function;
this._gjs_closure.text = 'gjs_closure: ' + memInfo.gjs_closure;
}
};
function Extensions() {
this._init();
}
@ -798,7 +745,12 @@ LookingGlass.prototype = {
let label = new St.Label({ text: 'js>>> ' });
entryArea.add(label);
this._entry = new St.Entry({ can_focus: true });
this._entry = new St.Entry();
/* unmapping the edit box will un-focus it, undo that */
notebook.connect('selection', Lang.bind(this, function (nb, child) {
if (child == this._evalBox)
global.stage.set_key_focus(this._entry);
}));
entryArea.add(this._entry, { expand: true });
this._windowList = new WindowList();
@ -811,9 +763,6 @@ LookingGlass.prototype = {
this._errorLog = new ErrorLog();
notebook.appendPage('Errors', this._errorLog.actor);
this._memory = new Memory();
notebook.appendPage('Memory', this._memory.actor);
this._extensions = new Extensions();
notebook.appendPage('Extensions', this._extensions.actor);
@ -907,7 +856,7 @@ LookingGlass.prototype = {
},
_resizeTo: function(actor) {
let primary = Main.layoutManager.primaryMonitor;
let primary = global.get_primary_monitor();
let myWidth = primary.width * 0.7;
let myHeight = primary.height * 0.7;
let [srcX, srcY] = actor.get_transformed_position();
@ -960,7 +909,6 @@ LookingGlass.prototype = {
if (!Main.pushModal(this._entry))
return;
this._notebook.selectIndex(0);
this.actor.show();
this.actor.lower(Main.chrome.actor);
this._open = true;

View File

@ -1,5 +1,11 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
imports.gi.versions.Clutter = '1.0';
imports.gi.versions.Gio = '2.0';
imports.gi.versions.Gdk = '3.0';
imports.gi.versions.GdkPixbuf = '2.0';
imports.gi.versions.Gtk = '3.0';
const Clutter = imports.gi.Clutter;
const DBus = imports.dbus;
const Gdk = imports.gi.Gdk;
@ -11,9 +17,9 @@ const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const AutomountManager = imports.ui.automountManager;
const AutorunManager = imports.ui.autorunManager;
const Chrome = imports.ui.chrome;
const CtrlAltTab = imports.ui.ctrlAltTab;
const EndSessionDialog = imports.ui.endSessionDialog;
@ -25,7 +31,6 @@ const Overview = imports.ui.overview;
const Panel = imports.ui.panel;
const PlaceDisplay = imports.ui.placeDisplay;
const RunDialog = imports.ui.runDialog;
const Layout = imports.ui.layout;
const LookingGlass = imports.ui.lookingGlass;
const NotificationDaemon = imports.ui.notificationDaemon;
const WindowAttentionHandler = imports.ui.windowAttentionHandler;
@ -41,8 +46,6 @@ const Util = imports.misc.util;
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
let automountManager = null;
let autorunManager = null;
let chrome = null;
let panel = null;
let hotCorners = [];
@ -64,7 +67,6 @@ let uiGroup = null;
let magnifier = null;
let xdndHandler = null;
let statusIconDispatcher = null;
let layoutManager = null;
let _errorLogStack = [];
let _startDate;
let _defaultCssStylesheet = null;
@ -73,7 +75,12 @@ let _cssStylesheet = null;
let background = null;
function start() {
// Monkey patch utility functions into the global proxy;
// Add a binding for 'global' in the global JS namespace; (gjs
// keeps the web browser convention of having that namespace be
// called 'window'.)
window.global = Shell.Global.get();
// Now monkey patch utility functions into the global proxy;
// This is easier and faster than indirecting down into global
// if we want to call back up into JS.
global.logError = _logError;
@ -95,6 +102,8 @@ function start() {
// not loading any events until the user presses the clock
global.launch_calendar_server();
Environment.init();
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
// also initialize ShellAppSystem first. ShellAppSystem
// needs to load all the .desktop files, and ShellWindowTracker
@ -132,7 +141,6 @@ function start() {
global.overlay_group.reparent(uiGroup);
global.stage.add_actor(uiGroup);
layoutManager = new Layout.LayoutManager();
placesManager = new PlaceDisplay.PlacesManager();
xdndHandler = new XdndHandler.XdndHandler();
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
@ -146,10 +154,7 @@ function start() {
notificationDaemon = new NotificationDaemon.NotificationDaemon();
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
telepathyClient = new TelepathyClient.Client();
automountManager = new AutomountManager.AutomountManager();
autorunManager = new AutorunManager.AutorunManager();
layoutManager.init();
overview.init();
statusIconDispatcher.start(messageTray.actor);
@ -188,9 +193,14 @@ function start() {
// Attempt to become a PolicyKit authentication agent
PolkitAuthenticationAgent.init()
global.screen.connect('monitors-changed', _relayout);
ExtensionSystem.init();
ExtensionSystem.loadExtensions();
// Perform initial relayout here
_relayout();
panel.startStatusArea();
panel.startupAnimation();
@ -213,7 +223,6 @@ function start() {
global.screen.connect('window-entered-monitor', _windowEnteredMonitor);
global.screen.connect('window-left-monitor', _windowLeftMonitor);
global.screen.connect('restacked', _windowsRestacked);
_nWorkspacesChanged();
}
@ -305,24 +314,17 @@ function _windowRemoved(workspace, window) {
function _windowLeftMonitor(metaScreen, monitorIndex, metaWin) {
// If the window left the primary monitor, that
// might make that workspace empty
if (monitorIndex == layoutManager.primaryIndex)
if (monitorIndex == global.get_primary_monitor_index())
_queueCheckWorkspaces();
}
function _windowEnteredMonitor(metaScreen, monitorIndex, metaWin) {
// If the window entered the primary monitor, that
// might make that workspace non-empty
if (monitorIndex == layoutManager.primaryIndex)
if (monitorIndex == global.get_primary_monitor_index())
_queueCheckWorkspaces();
}
function _windowsRestacked() {
// Figure out where the pointer is in case we lost track of
// it during a grab. (In particular, if a trayicon popup menu
// is dismissed, see if we need to close the message tray.)
global.sync_pointer();
}
function _queueCheckWorkspaces() {
if (_checkWorkspacesId == 0)
_checkWorkspacesId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, _checkWorkspaces);
@ -406,21 +408,12 @@ function setThemeStylesheet(cssStylesheet)
*/
function loadTheme() {
let themeContext = St.ThemeContext.get_for_stage (global.stage);
let previousTheme = themeContext.get_theme();
let cssStylesheet = _defaultCssStylesheet;
if (_cssStylesheet != null)
cssStylesheet = _cssStylesheet;
let theme = new St.Theme ({ application_stylesheet: cssStylesheet });
if (previousTheme) {
let customStylesheets = previousTheme.get_custom_stylesheets();
for (let i = 0; i < customStylesheets.length; i++)
theme.load_stylesheet(customStylesheets[i]);
}
themeContext.set_theme (theme);
}
@ -486,16 +479,80 @@ function _getAndClearErrorStack() {
return errors;
}
function logStackTrace(msg) {
try {
throw new Error();
} catch (e) {
// e.stack must have at least two lines, with the first being
// logStackTrace() (which we strip off), and the second being
// our caller.
let trace = e.stack.substr(e.stack.indexOf('\n') + 1);
log(msg ? (msg + '\n' + trace) : trace);
function _relayout() {
let monitors = global.get_monitors();
// destroy old corners
for (let i = 0; i < hotCorners.length; i++)
hotCorners[i].destroy();
hotCorners = [];
let primary = global.get_primary_monitor();
for (let i = 0; i < monitors.length; i++) {
let monitor = monitors[i];
let isPrimary = (monitor.x == primary.x &&
monitor.y == primary.y &&
monitor.width == primary.width &&
monitor.height == primary.height);
let cornerX = monitor.x;
let cornerY = monitor.y;
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
cornerX += monitor.width;
let haveTopLeftCorner = true;
/* Check if we have a top left (right for RTL) corner.
* I.e. if there is no monitor directly above or to the left(right) */
let besideX;
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
besideX = monitor.x + 1;
else
besideX = cornerX - 1;
let besideY = cornerY;
let aboveX = cornerX;
let aboveY = cornerY - 1;
for (let j = 0; j < monitors.length; j++) {
if (i == j)
continue;
let otherMonitor = monitors[j];
if (besideX >= otherMonitor.x &&
besideX < otherMonitor.x + otherMonitor.width &&
besideY >= otherMonitor.y &&
besideY < otherMonitor.y + otherMonitor.height) {
haveTopLeftCorner = false;
break;
}
if (aboveX >= otherMonitor.x &&
aboveX < otherMonitor.x + otherMonitor.width &&
aboveY >= otherMonitor.y &&
aboveY < otherMonitor.y + otherMonitor.height) {
haveTopLeftCorner = false;
break;
}
}
/* We only want hot corners where there is a natural top-left
* corner, and on the primary monitor */
if (!isPrimary && !haveTopLeftCorner)
continue;
let corner = new Panel.HotCorner(isPrimary ? panel.button : null);
hotCorners.push(corner);
corner.actor.set_position(cornerX, cornerY);
if (isPrimary)
panel.setHotCorner(corner);
}
panel.relayout();
overview.relayout();
// To avoid updating the position and size of the workspaces
// in the overview, we just hide the overview. The positions
// will be updated when it is next shown.
overview.hide();
}
function isWindowActorDisplayedOnWorkspace(win, workspaceIndex) {

View File

@ -20,6 +20,9 @@ const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const Util = imports.misc.util;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const ANIMATION_TIME = 0.2;
const NOTIFICATION_TIMEOUT = 4;
const SUMMARY_TIMEOUT = 1;
@ -68,19 +71,14 @@ function _fixMarkup(text, allowMarkup) {
// Support &amp;, &quot;, &apos;, &lt; and &gt;, escape all other
// occurrences of '&'.
let _text = text.replace(/&(?!amp;|quot;|apos;|lt;|gt;)/g, '&amp;');
// Support <b>, <i>, and <u>, escape anything else
// so it displays as raw markup.
_text = _text.replace(/<(?!\/?[biu]>)/g, '&lt;');
try {
Pango.parse_markup(_text, -1, '');
return _text;
} catch (e) {}
return _text.replace(/<(\/?[^biu]>|[^>\/][^>])/g, '&lt;$1');
} else {
// Escape everything
let _text = text.replace(/&/g, '&amp;');
return _text.replace(/</g, '&lt;');
}
// !allowMarkup, or invalid markup
return GLib.markup_escape_text(text, -1);
}
function URLHighlighter(text, lineWrap, allowMarkup) {
@ -562,7 +560,7 @@ Notification.prototype = {
this._scrollArea = new St.ScrollView({ name: 'notification-scrollview',
vscrollbar_policy: this._scrollPolicy,
hscrollbar_policy: Gtk.PolicyType.NEVER,
style_class: 'vfade' });
vfade: true });
this._table.add(this._scrollArea, { row: 1, col: 1 });
this._contentArea = new St.BoxLayout({ name: 'notification-body',
vertical: true });
@ -834,7 +832,6 @@ Notification.prototype = {
// Restore banner opacity in case the notification is shown in the
// banner mode again on update.
this._bannerLabel.opacity = 255;
this.emit('collapsed');
},
_onActionInvoked: function(actor, mouseButtonClicked, id) {
@ -885,96 +882,20 @@ Source.prototype = {
_init: function(title) {
this.title = title;
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('destroy', Lang.bind(this,
function() {
this._actorDestroyed = true;
}));
this._actorDestroyed = false;
this._counterLabel = new St.Label();
this._counterBin = new St.Bin({ style_class: 'summary-source-counter',
child: this._counterLabel });
this._counterBin.hide();
this._iconBin = new St.Bin({ width: this.ICON_SIZE,
height: this.ICON_SIZE,
x_fill: true,
y_fill: true });
this.actor.add_actor(this._iconBin);
this.actor.add_actor(this._counterBin);
this.isTransient = false;
this.isChat = false;
this.notifications = [];
},
_getPreferredWidth: function (actor, forHeight, alloc) {
let [min, nat] = this._iconBin.get_preferred_width(forHeight);
alloc.min_size = min; alloc.nat_size = nat;
},
_getPreferredHeight: function (actor, forWidth, alloc) {
let [min, nat] = this._iconBin.get_preferred_height(forWidth);
alloc.min_size = min; alloc.nat_size = nat;
},
_allocate: function(actor, box, flags) {
// the iconBin should fill our entire box
this._iconBin.allocate(box, flags);
let childBox = new Clutter.ActorBox();
let [minWidth, minHeight, naturalWidth, naturalHeight] = this._counterBin.get_preferred_size();
let direction = this.actor.get_direction();
if (direction == St.TextDirection.LTR) {
// allocate on the right in LTR
childBox.x1 = box.x2 - naturalWidth;
childBox.x2 = box.x2;
} else {
// allocate on the left in RTL
childBox.x1 = 0;
childBox.x2 = naturalWidth;
}
childBox.y1 = box.y2 - naturalHeight;
childBox.y2 = box.y2;
this._counterBin.allocate(childBox, flags);
},
_setCount: function(count, visible) {
if (isNaN(parseInt(count)))
throw new Error("Invalid notification count: " + count);
if (this._actorDestroyed)
return;
this._counterBin.visible = visible;
this._counterLabel.set_text(count.toString());
},
_updateCount: function() {
let count = this.notifications.length;
this._setCount(count, count > 1);
},
setTransient: function(isTransient) {
this.isTransient = isTransient;
},
setTitle: function(newTitle) {
this.title = newTitle;
this.emit('title-changed');
},
// Called to create a new icon actor (of size this.ICON_SIZE).
// Must be overridden by the subclass if you do not pass icons
// explicitly to the Notification() constructor.
@ -985,7 +906,7 @@ Source.prototype = {
// Unlike createNotificationIcon, this always returns the same actor;
// there is only one summary icon actor for a Source.
getSummaryIcon: function() {
return this.actor;
return this._iconBin;
},
pushNotification: function(notification) {
@ -1004,11 +925,7 @@ Source.prototype = {
this.notifications.splice(index, 1);
if (this.notifications.length == 0)
this._lastNotificationRemoved();
this._updateCount();
}));
this._updateCount();
},
notify: function(notification) {
@ -1045,8 +962,6 @@ Source.prototype = {
for (let i = this.notifications.length - 1; i >= 0; i--)
if (!this.notifications[i].resident)
this.notifications[i].destroy();
this._updateCount();
},
// Default implementation is to destroy this source, but subclasses can override
@ -1083,11 +998,6 @@ SummaryItem.prototype = {
this._sourceTitleBin.child = this._sourceTitle;
this._sourceTitleBin.width = 0;
this.source.connect('title-changed',
Lang.bind(this, function() {
this._sourceTitle.text = source.title;
}));
this._sourceBox.add(this._sourceIcon, { y_fill: false });
this._sourceBox.add(this._sourceTitleBin, { expand: true, y_fill: false });
this.actor.child = this._sourceBox;
@ -1095,7 +1005,7 @@ SummaryItem.prototype = {
this.notificationStackView = new St.ScrollView({ name: source.isChat ? '' : 'summary-notification-stack-scrollview',
vscrollbar_policy: source.isChat ? Gtk.PolicyType.NEVER : Gtk.PolicyType.AUTOMATIC,
hscrollbar_policy: Gtk.PolicyType.NEVER,
style_class: 'vfade' });
vfade: true });
this.notificationStack = new St.BoxLayout({ name: 'summary-notification-stack',
vertical: true });
this.notificationStackView.add_actor(this.notificationStack);
@ -1335,11 +1245,11 @@ MessageTray.prototype = {
this._reNotifyAfterHideNotification = null;
Main.chrome.addActor(this.actor, { affectsStruts: false,
visibleInFullscreen: true });
visibleInOverview: true });
Main.chrome.trackActor(this._notificationBin);
Main.chrome.trackActor(this._summaryBoxPointer.actor);
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._setSizePosition));
global.screen.connect('monitors-changed', Lang.bind(this, this._setSizePosition));
this._setSizePosition();
@ -1375,20 +1285,20 @@ MessageTray.prototype = {
},
_setSizePosition: function() {
let monitor = Main.layoutManager.bottomMonitor;
this.actor.x = monitor.x;
this.actor.y = monitor.y + monitor.height - 1;
this.actor.width = monitor.width;
let primary = global.get_primary_monitor();
this.actor.x = primary.x;
this.actor.y = primary.y + primary.height - 1;
this.actor.width = primary.width;
this._notificationBin.x = 0;
this._notificationBin.width = monitor.width;
this._notificationBin.width = primary.width;
this._summaryBin.x = 0;
this._summaryBin.width = monitor.width;
this._summaryBin.width = primary.width;
if (this._pointerBarrier)
global.destroy_pointer_barrier(this._pointerBarrier);
this._pointerBarrier =
global.create_pointer_barrier(monitor.x + monitor.width, monitor.y + monitor.height - this.actor.height,
monitor.x + monitor.width, monitor.y + monitor.height,
global.create_pointer_barrier(primary.x + primary.width, primary.y + primary.height - this.actor.height,
primary.x + primary.width, primary.y + primary.height,
4 /* BarrierNegativeX */);
@ -1698,8 +1608,6 @@ MessageTray.prototype = {
this._clickedSummaryItemMouseButton != button) {
this._clickedSummaryItem = summaryItem;
this._clickedSummaryItemMouseButton = button;
summaryItem.source.emit('summary-item-clicked', button);
} else {
this._unsetClickedSummaryItem();
}
@ -1949,18 +1857,18 @@ MessageTray.prototype = {
},
_showTray: function() {
let monitor = Main.layoutManager.bottomMonitor;
let primary = global.get_primary_monitor();
this._tween(this.actor, '_trayState', State.SHOWN,
{ y: monitor.y + monitor.height - this.actor.height,
{ y: primary.y + primary.height - this.actor.height,
time: ANIMATION_TIME,
transition: 'easeOutQuad'
});
},
_hideTray: function() {
let monitor = Main.layoutManager.bottomMonitor;
let primary = global.get_primary_monitor();
this._tween(this.actor, '_trayState', State.HIDDEN,
{ y: monitor.y + monitor.height - 1,
{ y: primary.y + primary.height - 1,
time: ANIMATION_TIME,
transition: 'easeOutQuad'
});
@ -2106,15 +2014,9 @@ MessageTray.prototype = {
this._notification.expand(!autoExpanding);
},
_onNotificationExpanded: function() {
_onNotificationExpanded: function() {
let expandedY = this.actor.height - this._notificationBin.height;
// Don't animate the notification to its new position if it has shrunk:
// there will be a very visible "gap" that breaks the illusion.
if (this._notificationBin.y < expandedY)
this._notificationBin.y = expandedY;
else if (this._notification.y != expandedY)
if (this._notificationBin.y != expandedY)
this._tween(this._notificationBin, '_notificationState', State.SHOWN,
{ y: expandedY,
time: ANIMATION_TIME,
@ -2129,6 +2031,7 @@ MessageTray.prototype = {
},
_showSummary: function(timeout) {
let primary = global.get_primary_monitor();
this._summaryBin.opacity = 0;
this._summaryBin.y = this.actor.height;
this._tween(this._summaryBin, '_summaryState', State.SHOWN,

View File

@ -10,6 +10,8 @@ const Pango = imports.gi.Pango;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Params = imports.misc.params;
@ -149,7 +151,7 @@ ModalDialog.prototype = {
},
_fadeOpen: function() {
let monitor = Main.layoutManager.focusMonitor;
let monitor = global.get_focus_monitor();
this._backgroundBin.set_position(monitor.x, monitor.y);
this._backgroundBin.set_size(monitor.width, monitor.height);

View File

@ -7,6 +7,8 @@ const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Mainloop = imports.mainloop;
const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Config = imports.misc.config;
const Main = imports.ui.main;
@ -122,7 +124,7 @@ NotificationDaemon.prototype = {
} else if (hints['image-data']) {
let [width, height, rowStride, hasAlpha,
bitsPerSample, nChannels, data] = hints['image-data'];
return textureCache.load_from_raw(data, hasAlpha,
return textureCache.load_from_raw(data, data.length, hasAlpha,
width, height, rowStride, size);
} else {
let stockIcon;
@ -148,7 +150,7 @@ NotificationDaemon.prototype = {
//
// Either a pid or ndata.notification is needed to retrieve or
// create a source.
_getSource: function(title, pid, ndata, sender) {
_getSource: function(title, pid, ndata) {
if (!pid && !(ndata && ndata.notification))
return null;
@ -165,13 +167,10 @@ NotificationDaemon.prototype = {
// with a transient one from the same sender, so we
// always create a new source object for new transient notifications
// and never add it to this._sources .
if (!isForTransientNotification && this._sources[pid]) {
let source = this._sources[pid];
source.setTitle(title);
return source;
}
if (!isForTransientNotification && this._sources[pid])
return this._sources[pid];
let source = new Source(title, pid, sender);
let source = new Source(title, pid);
source.setTransient(isForTransientNotification);
if (!isForTransientNotification) {
@ -190,11 +189,9 @@ NotificationDaemon.prototype = {
actions, hints, timeout) {
let id;
// Filter out chat, presence, calls and invitation notifications from
// Empathy, since we handle that information from telepathyClient.js
// Filter out chat and presence notifications from Empathy, since we
// handle that information from telepathyClient.js
if (appName == 'Empathy' && (hints['category'] == 'im.received' ||
hints['category'] == 'x-empathy.im.room-invitation' ||
hints['category'] == 'x-empathy.call.incoming' ||
hints['category'] == 'presence.online' ||
hints['category'] == 'presence.offline')) {
// Ignore replacesId since we already sent back a
@ -246,7 +243,7 @@ NotificationDaemon.prototype = {
let sender = DBus.getCurrentMessageContext().sender;
let pid = this._senderToPid[sender];
let source = this._getSource(appName, pid, ndata, sender);
let source = this._getSource(appName, pid, ndata);
if (source) {
this._notifyForSource(source, ndata);
@ -267,7 +264,7 @@ NotificationDaemon.prototype = {
if (!ndata)
return;
source = this._getSource(appName, pid, ndata, sender);
source = this._getSource(appName, pid, ndata);
// We only store sender-pid entries for persistent sources.
// Removing the entries once the source is destroyed
@ -416,7 +413,7 @@ NotificationDaemon.prototype = {
},
_onTrayIconAdded: function(o, icon) {
let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null, null);
let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null);
source.setTrayIcon(icon);
},
@ -429,28 +426,18 @@ NotificationDaemon.prototype = {
DBus.conformExport(NotificationDaemon.prototype, NotificationDaemonIface);
function Source(title, pid, sender) {
this._init(title, pid, sender);
function Source(title, pid) {
this._init(title, pid);
}
Source.prototype = {
__proto__: MessageTray.Source.prototype,
_init: function(title, pid, sender) {
_init: function(title, pid) {
MessageTray.Source.prototype._init.call(this, title);
this._pid = pid;
if (sender)
// TODO: dbus-glib implementation of watch_name() doesnt return an id to be used for
// unwatch_name() or implement unwatch_name(), however when we move to using GDBus implementation,
// we should save the id here and call unwatch_name() with it in destroy().
// Moving to GDBus is the work in progress: https://bugzilla.gnome.org/show_bug.cgi?id=648651
// and https://bugzilla.gnome.org/show_bug.cgi?id=622921 .
DBus.session.watch_name(sender,
false,
null,
Lang.bind(this, this._onNameVanished));
this._appStateChangedId = 0;
this._setApp();
if (this.app)
this.title = this.app.get_name();
@ -459,16 +446,6 @@ Source.prototype = {
this._trayIcon = null;
},
_onNameVanished: function() {
// Destroy the notification source when its sender is removed from DBus.
// Only do so if this.app is set to avoid removing "notify-send" sources, senders
// of which аre removed from DBus immediately.
// Sender being removed from DBus would normally result in a tray icon being removed,
// so allow the code path that handles the tray icon being removed to handle that case.
if (!this.trayIcon && this.app)
this.destroy();
},
processNotification: function(notification, icon) {
if (!this.app)
this._setApp();
@ -521,6 +498,10 @@ Source.prototype = {
if (!this.app)
return;
// We only update the app if this.app is null, so we can't disconnect the old this._appStateChangedId
// even if it were non-zero for some reason.
this._appStateChangedId = this.app.connect('notify::state', Lang.bind(this, this._appStateChanged));
// Only override the icon if we were previously using
// notification-based icons (ie, not a trayicon) or if it was unset before
if (!this._trayIcon) {
@ -545,6 +526,19 @@ Source.prototype = {
this.destroy();
},
_appStateChanged: function() {
// Destroy notification sources when their apps exit.
// The app exiting would normally result in a tray icon being removed,
// so the associated source would be destroyed through the code path
// that handles the tray icon being removed. We should not destroy
// the source associated with a tray icon when the application state
// is Shell.AppState.STOPPED because running applications that have
// no open windows would also have that state. This is often the case
// for applications that use tray icons.
if (!this._trayIcon && this.app.get_state() == Shell.AppState.STOPPED)
this.destroy();
},
openApp: function() {
if (this.app == null)
return;
@ -557,6 +551,10 @@ Source.prototype = {
},
destroy: function() {
if (this.app && this._appStateChangedId) {
this.app.disconnect(this._appStateChangedId);
this._appStateChangedId = 0;
}
MessageTray.Source.prototype.destroy.call(this);
}
};

View File

@ -8,6 +8,8 @@ const Signals = imports.signals;
const Lang = imports.lang;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Gdk = imports.gi.Gdk;
const AppDisplay = imports.ui.appDisplay;
@ -121,7 +123,7 @@ Overview.prototype = {
let spacing = node.get_length('spacing');
if (spacing != this._spacing) {
this._spacing = spacing;
this._relayout();
this.relayout();
}
}));
@ -202,8 +204,6 @@ Overview.prototype = {
// the left of the overview
Main.ctrlAltTabManager.addGroup(this.dash.actor, _("Dash"), 'user-bookmarks');
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._relayout));
this._relayout();
},
_onDragBegin: function() {
@ -222,7 +222,7 @@ Overview.prototype = {
}
this._resetWindowSwitchTimeout();
this._lastHoveredWindow = null;
DND.removeDragMonitor(this._dragMonitor);
DND.removeMonitor(this._dragMonitor);
this.endItemDrag();
},
@ -283,8 +283,7 @@ Overview.prototype = {
},
_onButtonPress: function(actor, event) {
if (this._scrollDirection == SwipeScrollDirection.NONE
|| event.get_button() != 1)
if (this._scrollDirection == SwipeScrollDirection.NONE)
return;
let [stageX, stageY] = event.get_coords();
@ -393,7 +392,7 @@ Overview.prototype = {
[stageX, stageY] = event.get_coords();
let dx = this._dragX - stageX;
let dy = this._dragY - stageY;
let primary = Main.layoutManager.primaryMonitor;
let primary = global.get_primary_monitor();
this._dragX = stageX;
this._dragY = stageY;
@ -440,13 +439,8 @@ Overview.prototype = {
return clone;
},
_relayout: function () {
// To avoid updating the position and size of the workspaces
// we just hide the overview. The positions will be updated
// when it is next shown.
this.hide();
let primary = Main.layoutManager.primaryMonitor;
relayout: function () {
let primary = global.get_primary_monitor();
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
let contentY = Main.panel.actor.height;

View File

@ -9,10 +9,11 @@ const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Signals = imports.signals;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Config = imports.misc.config;
const CtrlAltTab = imports.ui.ctrlAltTab;
const Layout = imports.ui.layout;
const Overview = imports.ui.overview;
const PopupMenu = imports.ui.popupMenu;
const PanelMenu = imports.ui.panelMenu;
@ -25,6 +26,8 @@ const PANEL_ICON_SIZE = 24;
const STARTUP_ANIMATION_TIME = 0.2;
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
const BUTTON_DND_ACTIVATION_TIMEOUT = 250;
const ANIMATED_ICON_UPDATE_TIMEOUT = 100;
@ -301,7 +304,6 @@ AppMenuButton.prototype = {
this._visible = true;
this.actor.show();
this.actor.reactive = true;
if (!this._targetIsCurrent)
return;
@ -318,7 +320,6 @@ AppMenuButton.prototype = {
return;
this._visible = false;
this.actor.reactive = false;
if (!this._targetIsCurrent) {
this.actor.hide();
return;
@ -543,163 +544,13 @@ AppMenuButton.prototype = {
Signals.addSignalMethods(AppMenuButton.prototype);
// Activities button. Because everything else in the top bar is a
// PanelMenu.Button, it simplifies some things to make this be one too.
// We just hack it up to not actually have a menu attached to it.
function ActivitiesButton() {
this._init.apply(this, arguments);
}
ActivitiesButton.prototype = {
__proto__: PanelMenu.Button.prototype,
_init: function() {
PanelMenu.Button.prototype._init.call(this, 0.0);
let container = new Shell.GenericContainer();
container.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
container.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
container.connect('allocate', Lang.bind(this, this._allocate));
this.actor.child = container;
this.actor.name = 'panelActivities';
/* Translators: If there is no suitable word for "Activities"
in your language, you can use the word for "Overview". */
this._label = new St.Label({ text: _("Activities") });
container.add_actor(this._label);
this._hotCorner = new Layout.HotCorner();
container.add_actor(this._hotCorner.actor);
// Hack up our menu...
this.menu.open = Lang.bind(this, this._onMenuOpenRequest);
this.menu.close = Lang.bind(this, this._onMenuCloseRequest);
this.menu.toggle = Lang.bind(this, this._onMenuToggleRequest);
this.actor.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
this.actor.connect_after('button-release-event', Lang.bind(this, this._onButtonRelease));
this.actor.connect_after('key-release-event', Lang.bind(this, this._onKeyRelease));
Main.overview.connect('showing', Lang.bind(this, function() {
this.actor.add_style_pseudo_class('overview');
this._escapeMenuGrab();
}));
Main.overview.connect('hiding', Lang.bind(this, function() {
this.actor.remove_style_pseudo_class('overview');
this._escapeMenuGrab();
}));
this._xdndTimeOut = 0;
},
_getPreferredWidth: function(actor, forHeight, alloc) {
[alloc.min_size, alloc.natural_size] = this._label.get_preferred_width(forHeight);
},
_getPreferredHeight: function(actor, forWidth, alloc) {
[alloc.min_size, alloc.natural_size] = this._label.get_preferred_height(forWidth);
},
_allocate: function(actor, box, flags) {
this._label.allocate(box, flags);
// The hot corner needs to be outside any padding/alignment
// that has been imposed on us
let primary = Main.layoutManager.primaryMonitor;
let hotBox = new Clutter.ActorBox();
let ok, x, y;
if (actor.get_direction() == St.TextDirection.LTR) {
[ok, x, y] = actor.transform_stage_point(primary.x, primary.y)
} else {
[ok, x, y] = actor.transform_stage_point(primary.x + primary.width, primary.y);
// hotCorner.actor has northeast gravity, so we don't need
// to adjust x for its width
}
hotBox.x1 = Math.round(x);
hotBox.x2 = hotBox.x1 + this._hotCorner.actor.width;
hotBox.y1 = Math.round(y);
hotBox.y2 = hotBox.y1 + this._hotCorner.actor.height;
this._hotCorner.actor.allocate(hotBox, flags);
},
handleDragOver: function(source, actor, x, y, time) {
if (source != Main.xdndHandler)
return;
if (this._xdndTimeOut != 0)
Mainloop.source_remove(this._xdndTimeOut);
this._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT,
Lang.bind(this, this._xdndShowOverview, actor));
},
_escapeMenuGrab: function() {
if (this.menu.isOpen)
this.menu.close();
},
_onCapturedEvent: function(actor, event) {
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
if (!this._hotCorner.shouldToggleOverviewOnClick())
return true;
}
return false;
},
_onMenuOpenRequest: function() {
this.menu.isOpen = true;
this.menu.emit('open-state-changed', true);
},
_onMenuCloseRequest: function() {
this.menu.isOpen = false;
this.menu.emit('open-state-changed', false);
},
_onMenuToggleRequest: function() {
this.menu.isOpen = !this.menu.isOpen;
this.menu.emit('open-state-changed', this.menu.isOpen);
},
_onButtonRelease: function() {
if (this.menu.isOpen) {
this.menu.close();
Main.overview.toggle();
}
},
_onKeyRelease: function(actor, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_space) {
if (this.menu.isOpen)
this.menu.close();
Main.overview.toggle();
}
},
_xdndShowOverview: function(actor) {
let [x, y, mask] = global.get_pointer();
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
if (pickedActor == this.actor) {
if (!Main.overview.visible && !Main.overview.animationInProgress) {
Main.overview.showTemporarily();
Main.overview.beginItemDrag(actor);
}
}
Mainloop.source_remove(this._xdndTimeOut);
this._xdndTimeOut = 0;
}
};
function PanelCorner(panel, side) {
this._init(panel, side);
function PanelCorner(side) {
this._init(side);
}
PanelCorner.prototype = {
_init: function(panel, side) {
this._panel = panel;
_init: function(side) {
this._side = side;
this.actor = new St.DrawingArea({ style_class: 'panel-corner' });
this.actor.connect('repaint', Lang.bind(this, this._repaint));
@ -775,14 +626,185 @@ PanelCorner.prototype = {
this.actor.set_size(cornerRadius,
innerBorderWidth + cornerRadius);
if (this._side == St.Side.LEFT)
this.actor.set_position(this._panel.actor.x,
this._panel.actor.y + this._panel.actor.height - innerBorderWidth);
this.actor.set_position(Main.panel.actor.x,
Main.panel.actor.y + Main.panel.actor.height - innerBorderWidth);
else
this.actor.set_position(this._panel.actor.x + this._panel.actor.width - cornerRadius,
this._panel.actor.y + this._panel.actor.height - innerBorderWidth);
this.actor.set_position(Main.panel.actor.x + Main.panel.actor.width - cornerRadius,
Main.panel.actor.y + Main.panel.actor.height - innerBorderWidth);
}
};
/**
* HotCorner:
*
* This class manages the "hot corner" that can toggle switching to
* overview.
*/
function HotCorner(button) {
this._init(button);
}
HotCorner.prototype = {
_init : function(button) {
// This is the activities button associated with this hot corner,
// if this is on the primary monitor (or null with the corner is
// on a different monitor)
this._button = button;
// We use this flag to mark the case where the user has entered the
// hot corner and has not left both the hot corner and a surrounding
// guard area (the "environs"). This avoids triggering the hot corner
// multiple times due to an accidental jitter.
this._entered = false;
this.actor = new Clutter.Group({ width: 3,
height: 3,
reactive: true });
this._corner = new Clutter.Rectangle({ width: 1,
height: 1,
opacity: 0,
reactive: true });
this.actor.add_actor(this._corner);
if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
this._corner.set_position(this.actor.width - this._corner.width, 0);
this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
} else {
this._corner.set_position(0, 0);
}
this._activationTime = 0;
this.actor.connect('enter-event',
Lang.bind(this, this._onEnvironsEntered));
this.actor.connect('leave-event',
Lang.bind(this, this._onEnvironsLeft));
// Clicking on the hot corner environs should result in the same bahavior
// as clicking on the hot corner.
this.actor.connect('button-release-event',
Lang.bind(this, this._onCornerClicked));
// In addition to being triggered by the mouse enter event, the hot corner
// can be triggered by clicking on it. This is useful if the user wants to
// undo the effect of triggering the hot corner once in the hot corner.
this._corner.connect('enter-event',
Lang.bind(this, this._onCornerEntered));
this._corner.connect('button-release-event',
Lang.bind(this, this._onCornerClicked));
this._corner.connect('leave-event',
Lang.bind(this, this._onCornerLeft));
this._corner._delegate = this._corner;
this._corner.handleDragOver = Lang.bind(this,
function(source, actor, x, y, time) {
if (source == Main.xdndHandler) {
if(!Main.overview.visible && !Main.overview.animationInProgress) {
this.rippleAnimation();
Main.overview.showTemporarily();
Main.overview.beginItemDrag(actor);
}
}
});
Main.chrome.addActor(this.actor, { visibleInOverview: true, affectsStruts: false });
},
destroy: function() {
this.actor.destroy();
},
_addRipple : function(delay, time, startScale, startOpacity, finalScale, finalOpacity) {
// We draw a ripple by using a source image and animating it scaling
// outwards and fading away. We want the ripples to move linearly
// or it looks unrealistic, but if the opacity of the ripple goes
// linearly to zero it fades away too quickly, so we use Tweener's
// 'onUpdate' to give a non-linear curve to the fade-away and make
// it more visible in the middle section.
let [x, y] = this._corner.get_transformed_position();
let ripple = new St.BoxLayout({ style_class: 'ripple-box',
opacity: 255 * Math.sqrt(startOpacity),
scale_x: startScale,
scale_y: startScale,
x: x,
y: y });
ripple._opacity = startOpacity;
if (ripple.get_direction() == St.TextDirection.RTL)
ripple.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
Tweener.addTween(ripple, { _opacity: finalOpacity,
scale_x: finalScale,
scale_y: finalScale,
delay: delay,
time: time,
transition: 'linear',
onUpdate: function() { ripple.opacity = 255 * Math.sqrt(ripple._opacity); },
onComplete: function() { ripple.destroy(); } });
Main.uiGroup.add_actor(ripple);
},
rippleAnimation: function() {
// Show three concentric ripples expanding outwards; the exact
// parameters were found by trial and error, so don't look
// for them to make perfect sense mathematically
// delay time scale opacity => scale opacity
this._addRipple(0.0, 0.83, 0.25, 1.0, 1.5, 0.0);
this._addRipple(0.05, 1.0, 0.0, 0.7, 1.25, 0.0);
this._addRipple(0.35, 1.0, 0.0, 0.3, 1, 0.0);
},
_onEnvironsEntered : function() {
if (this._button)
this._button.hover = true;
},
_onCornerEntered : function() {
if (!this._entered) {
this._entered = true;
if (!Main.overview.animationInProgress) {
this._activationTime = Date.now() / 1000;
this.rippleAnimation();
Main.overview.toggle();
}
}
return false;
},
_onCornerClicked : function() {
if (!Main.overview.animationInProgress)
this.maybeToggleOverviewOnClick();
return true;
},
_onCornerLeft : function(actor, event) {
if (event.get_related() != this.actor)
this._entered = false;
// Consume event, otherwise this will confuse onEnvironsLeft
return true;
},
_onEnvironsLeft : function(actor, event) {
if (this._button)
this._button.hover = false;
if (event.get_related() != this._corner)
this._entered = false;
return false;
},
// Toggles the overview unless this is the first click on the Activities button within the HOT_CORNER_ACTIVATION_TIMEOUT time
// of the hot corner being triggered. This check avoids opening and closing the overview if the user both triggered the hot corner
// and clicked the Activities button.
maybeToggleOverviewOnClick: function() {
if (this._activationTime == 0 || Date.now() / 1000 - this._activationTime > HOT_CORNER_ACTIVATION_TIMEOUT)
Main.overview.toggle();
this._activationTime = 0;
}
}
function Panel() {
this._init();
@ -795,8 +817,6 @@ Panel.prototype = {
reactive: true });
this.actor._delegate = this;
this._statusArea = {};
Main.overview.connect('shown', Lang.bind(this, function () {
this.actor.add_style_class_name('in-overview');
}));
@ -812,8 +832,8 @@ Panel.prototype = {
this._centerBox = new St.BoxLayout({ name: 'panelCenter' });
this._rightBox = new St.BoxLayout({ name: 'panelRight' });
this._leftCorner = new PanelCorner(this, St.Side.LEFT);
this._rightCorner = new PanelCorner(this, St.Side.RIGHT);
this._leftCorner = new PanelCorner(St.Side.LEFT);
this._rightCorner = new PanelCorner(St.Side.RIGHT);
/* This box container ensures that the centerBox is positioned in the *absolute*
* center, but can be pushed aside if necessary. */
@ -887,16 +907,31 @@ Panel.prototype = {
}));
/* Button on the left side of the panel. */
this._activitiesButton = new ActivitiesButton();
this._activities = this._activitiesButton.actor;
this._leftBox.add(this._activities);
/* Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview". */
let label = new St.Label({ text: _("Activities") });
this.button = new St.Button({ name: 'panelActivities',
style_class: 'panel-button',
reactive: true,
can_focus: true });
this.button.set_child(label);
this.button._delegate = this.button;
this.button._xdndTimeOut = 0;
this.button.handleDragOver = Lang.bind(this,
function(source, actor, x, y, time) {
if (source == Main.xdndHandler) {
if (this.button._xdndTimeOut != 0)
Mainloop.source_remove(this.button._xdndTimeOut);
this.button._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT,
Lang.bind(this,
function() {
this._xdndShowOverview(actor);
}));
}
});
this._leftBox.add(this.button);
// The activities button has a pretend menu, so as to integrate
// more cleanly with the rest of the panel
this._menus.addMenu(this._activitiesButton.menu);
// Synchronize the button's pseudo classes with its corner
this._activities.connect('style-changed', Lang.bind(this,
// Synchronize the buttons pseudo classes with its corner
this.button.connect('style-changed', Lang.bind(this,
function(actor) {
let rtl = actor.get_direction() == St.TextDirection.RTL;
let corner = rtl ? this._rightCorner : this._leftCorner;
@ -904,10 +939,12 @@ Panel.prototype = {
corner.actor.set_style_pseudo_class(pseudoClass);
}));
this._appMenu = new AppMenuButton();
this._leftBox.add(this._appMenu.actor);
this._hotCorner = null;
this._menus.addMenu(this._appMenu.menu);
let appMenuButton = new AppMenuButton();
this._leftBox.add(appMenuButton.actor);
this._menus.addMenu(appMenuButton.menu);
/* center */
this._dateMenu = new DateMenu.DateMenuButton();
@ -926,12 +963,12 @@ Panel.prototype = {
this._rightBox.add(this._trayBox);
this._rightBox.add(this._statusBox);
this._userMenu = new StatusMenu.StatusMenuButton();
this._userMenu.actor.name = 'panelStatus';
this._rightBox.add(this._userMenu.actor);
this._statusmenu = new StatusMenu.StatusMenuButton();
this._statusmenu.actor.name = 'panelStatus';
this._rightBox.add(this._statusmenu.actor);
// Synchronize the buttons pseudo classes with its corner
this._userMenu.actor.connect('style-changed', Lang.bind(this,
this._statusmenu.actor.connect('style-changed', Lang.bind(this,
function(actor) {
let rtl = actor.get_direction() == St.TextDirection.RTL;
let corner = rtl ? this._leftCorner : this._rightCorner;
@ -942,17 +979,65 @@ Panel.prototype = {
Main.statusIconDispatcher.connect('status-icon-added', Lang.bind(this, this._onTrayIconAdded));
Main.statusIconDispatcher.connect('status-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
Main.chrome.addActor(this.actor);
Main.chrome.addActor(this._leftCorner.actor, { affectsStruts: false,
affectsInputRegion: false });
Main.chrome.addActor(this._rightCorner.actor, { affectsStruts: false,
affectsInputRegion: false });
// TODO: decide what to do with the rest of the panel in the Overview mode (make it fade-out, become non-reactive, etc.)
// We get into the Overview mode on button-press-event as opposed to button-release-event because eventually we'll probably
// have the Overview act like a menu that allows the user to release the mouse on the activity the user wants
// to switch to.
this.button.connect('clicked', Lang.bind(this, function(b) {
if (!Main.overview.animationInProgress) {
this._hotCorner.maybeToggleOverviewOnClick();
return true;
} else {
return false;
}
}));
// In addition to pressing the button, the Overview can be entered and exited by other means, such as
// pressing the System key, Alt+F1 or Esc. We want the button to be pressed in when the Overview is entered
// and to be released when it is exited regardless of how it was triggered.
Main.overview.connect('showing', Lang.bind(this, function() {
this.button.checked = true;
}));
Main.overview.connect('hiding', Lang.bind(this, function() {
this.button.checked = false;
}));
Main.chrome.addActor(this.actor, { visibleInOverview: true });
Main.chrome.addActor(this._leftCorner.actor, { visibleInOverview: true,
affectsStruts: false,
affectsInputRegion: false });
Main.chrome.addActor(this._rightCorner.actor, { visibleInOverview: true,
affectsStruts: false,
affectsInputRegion: false });
Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'start-here',
{ sortGroup: CtrlAltTab.SortGroup.TOP });
},
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._relayout));
this._relayout();
_xdndShowOverview: function (actor) {
let [x, y, mask] = global.get_pointer();
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
if (pickedActor != this.button) {
Mainloop.source_remove(this.button._xdndTimeOut);
this.button._xdndTimeOut = 0;
return;
}
if(!Main.overview.visible && !Main.overview.animationInProgress) {
Main.overview.showTemporarily();
Main.overview.beginItemDrag(actor);
}
Mainloop.source_remove(this.button._xdndTimeOut);
this.button._xdndTimeOut = 0;
},
// While there can be multiple hotcorners (one per monitor), the hot corner
// that is on top of the Activities button is special since it needs special
// coordination with clicking on that button
setHotCorner: function(corner) {
this._hotCorner = corner;
},
startStatusArea: function() {
@ -966,13 +1051,11 @@ Panel.prototype = {
let indicator = new constructor();
this._statusBox.add(indicator.actor);
this._menus.addMenu(indicator.menu);
this._statusArea[role] = indicator;
}
// PopupMenuManager depends on menus being added in order for
// keyboard navigation
this._menus.addMenu(this._userMenu.menu);
this._menus.addMenu(this._statusmenu.menu);
},
startupAnimation: function() {
@ -999,8 +1082,8 @@ Panel.prototype = {
});
},
_relayout: function() {
let primary = Main.layoutManager.primaryMonitor;
relayout: function() {
let primary = global.get_primary_monitor();
this.actor.set_position(primary.x, primary.y);
this.actor.set_size(primary.width, -1);

View File

@ -26,7 +26,8 @@ Button.prototype = {
this.menu = new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP, 0);
this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
this.menu.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress));
Main.chrome.addActor(this.menu.actor, { affectsStruts: false });
Main.chrome.addActor(this.menu.actor, { visibleInOverview: true,
affectsStruts: false });
this.menu.actor.hide();
},
@ -35,7 +36,7 @@ Button.prototype = {
// 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;
let monitor = global.get_primary_monitor();
this.menu.actor.style = ('max-height: ' +
Math.round(monitor.height - Main.panel.actor.height) +
'px;');

View File

@ -7,6 +7,8 @@ const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
@ -268,7 +270,10 @@ PlacesManager.prototype = {
if (!GLib.file_test(this._bookmarksPath, GLib.FileTest.EXISTS))
return;
let bookmarksContent = Shell.get_file_contents_utf8_sync(this._bookmarksPath);
let [success, bookmarksContent, len] = GLib.file_get_contents(this._bookmarksPath);
if (!success)
return;
let bookmarks = bookmarksContent.split('\n');

View File

@ -22,6 +22,8 @@
const Lang = imports.lang;
const Signals = imports.signals;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Shell = imports.gi.Shell;
const Clutter = imports.gi.Clutter;
const St = imports.gi.St;

View File

@ -13,6 +13,9 @@ const Main = imports.ui.main;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const SLIDER_SCROLL_STEP = 0.05; /* Slider scrolling step in % */
function PopupBaseMenuItem(params) {
@ -704,35 +707,11 @@ PopupSwitchMenuItem.prototype = {
this._switch = new Switch(active);
this.addActor(this.label);
this.addActor(this._switch.actor, { align: St.Align.END });
this._statusBin = new St.Bin({ x_align: St.Align.END });
this.addActor(this._statusBin, { align: St.Align.END });
this._statusLabel = new St.Label({ text: '',
style_class: 'popup-inactive-menu-item'
});
this._statusBin.child = this._switch.actor;
},
setStatus: function(text) {
if (text != null) {
this._statusLabel.text = text;
this._statusBin.child = this._statusLabel;
this.actor.reactive = false;
this.actor.can_focus = false;
} else {
this._statusBin.child = this._switch.actor;
this.actor.reactive = true;
this.actor.can_focus = true;
}
},
activate: function(event) {
if (this._switch.actor.mapped) {
this.connect('activate', Lang.bind(this,function(from) {
this.toggle();
}
PopupBaseMenuItem.prototype.activate.call(this, event);
}));
},
toggle: function() {
@ -946,14 +925,6 @@ PopupMenuBase.prototype = {
});
},
get firstMenuItem() {
let items = this._getMenuItems();
if (items.length)
return items[0];
else
return null;
},
removeAll: function() {
let children = this._getMenuItems();
for (let i = 0; i < children.length; i++) {

View File

@ -8,6 +8,8 @@ const Meta = imports.gi.Meta;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const FileUtils = imports.misc.fileUtils;
const Main = imports.ui.main;
@ -23,10 +25,6 @@ const HISTORY_KEY = 'command-history';
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
const DISABLE_COMMAND_LINE_KEY = 'disable-command-line';
const TERMINAL_SCHEMA = 'org.gnome.desktop.default-applications.terminal';
const EXEC_KEY = 'exec';
const EXEC_ARG_KEY = 'exec-arg';
const DIALOG_GROW_TIME = 0.1;
function CommandCompleter() {
@ -173,7 +171,6 @@ __proto__: ModalDialog.ModalDialog.prototype,
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'run-dialog' });
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
this._terminalSettings = new Gio.Settings({ schema: TERMINAL_SCHEMA });
global.settings.connect('changed::development-tools', Lang.bind(this, function () {
this._enableInternalCommands = global.settings.get_boolean('development-tools');
}));
@ -194,7 +191,7 @@ __proto__: ModalDialog.ModalDialog.prototype,
}),
'debugexit': Lang.bind(this, function() {
Meta.quit(Meta.ExitCode.ERROR);
Meta.exit(Meta.ExitCode.ERROR);
}),
// rt is short for "reload theme"
@ -314,11 +311,8 @@ __proto__: ModalDialog.ModalDialog.prototype,
f();
} else if (input) {
try {
if (inTerminal) {
let exec = this._terminalSettings.get_string(EXEC_KEY);
let exec_arg = this._terminalSettings.get_string(EXEC_ARG_KEY);
command = exec + ' ' + exec_arg + ' ' + input;
}
if (inTerminal)
command = 'gnome-terminal -x ' + input;
Util.trySpawnCommandLine(command);
} catch (e) {
// Mmmh, that failed - see if @input matches an existing file
@ -333,46 +327,33 @@ __proto__: ModalDialog.ModalDialog.prototype,
if (GLib.file_test(path, GLib.FileTest.EXISTS)) {
let file = Gio.file_new_for_path(path);
try {
Gio.app_info_launch_default_for_uri(file.get_uri(),
global.create_app_launch_context());
} catch (e) {
// The exception from gjs contains an error string like:
// Error invoking Gio.app_info_launch_default_for_uri: No application
// is registered as handling this file
// We are only interested in the part after the first colon.
let message = e.message.replace(/[^:]*: *(.+)/, '$1');
this._showError(message);
}
Gio.app_info_launch_default_for_uri(file.get_uri(),
global.create_app_launch_context());
} else {
this._showError(e.message);
this._commandError = true;
this._errorMessage.set_text(e.message);
if (!this._errorBox.visible) {
let [errorBoxMinHeight, errorBoxNaturalHeight] = this._errorBox.get_preferred_height(-1);
let parentActor = this._errorBox.get_parent();
Tweener.addTween(parentActor,
{ height: parentActor.height + errorBoxNaturalHeight,
time: DIALOG_GROW_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
parentActor.set_height(-1);
this._errorBox.show();
})
});
}
}
}
}
},
_showError : function(message) {
this._commandError = true;
this._errorMessage.set_text(message);
if (!this._errorBox.visible) {
let [errorBoxMinHeight, errorBoxNaturalHeight] = this._errorBox.get_preferred_height(-1);
let parentActor = this._errorBox.get_parent();
Tweener.addTween(parentActor,
{ height: parentActor.height + errorBoxNaturalHeight,
time: DIALOG_GROW_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
parentActor.set_height(-1);
this._errorBox.show();
})
});
}
},
open: function() {
this._history.lastItem();
this._errorBox.hide();

View File

@ -3,11 +3,10 @@
const DBus = imports.dbus;
const Gio = imports.gi.Gio;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Main = imports.ui.main;
// This module provides functionality for driving the shell user interface
// in an automated fashion. The primary current use case for this is
// automated performance testing (see runPerfScript()), but it could
@ -247,14 +246,18 @@ function _collect(scriptModule, outputFile) {
Shell.write_string_to_stream(out, '"events":\n');
Shell.PerfLog.get_default().dump_events(out);
let monitors = Main.layoutManager.monitors;
let primary = Main.layoutManager.primaryIndex;
let monitors = global.get_monitors();
let primary = global.get_primary_monitor();
Shell.write_string_to_stream(out, ',\n"monitors":\n[');
for (let i = 0; i < monitors.length; i++) {
let monitor = monitors[i];
let is_primary = (monitor.x == primary.x &&
monitor.y == primary.y &&
monitor.width == primary.width &&
monitor.height == primary.height);
if (i != 0)
Shell.write_string_to_stream(out, ', ');
Shell.write_string_to_stream(out, '"%s%dx%d+%d+%d"'.format(i == primary ? "*" : "",
Shell.write_string_to_stream(out, '"%s%dx%d+%d+%d"'.format(is_primary ? "*" : "",
monitor.width, monitor.height,
monitor.x, monitor.y));
}

View File

@ -7,6 +7,9 @@ const Signals = imports.signals;
const Shell = imports.gi.Shell;
const Util = imports.misc.util;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const FileUtils = imports.misc.fileUtils;
const Main = imports.ui.main;
@ -157,7 +160,7 @@ SearchProvider.prototype = {
},
/**
* getResultMeta:
* getResultInfo:
* @id: Result identifier string
*
* Return an object with 'id', 'name', (both strings) and 'createIcon'
@ -273,7 +276,7 @@ OpenSearchSystem.prototype = {
_addProvider: function(fileName) {
let path = global.datadir + '/search_providers/' + fileName;
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] = global.parse_search_provider(source);
let provider ={ name: name,
url: url,
id: this._providers.length,

View File

@ -2,6 +2,8 @@
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Gtk = imports.gi.Gtk;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
@ -28,7 +30,6 @@ SearchResult.prototype = {
x_align: St.Align.START,
y_fill: true });
this.actor._delegate = this;
this._dragActorSource = null;
let content = provider.createResultActor(metaInfo, terms);
if (content == null) {
@ -38,11 +39,6 @@ SearchResult.prototype = {
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
{ createIcon: this.metaInfo['createIcon'] });
content.set_child(icon.actor);
this._dragActorSource = icon.icon;
this.actor.label_actor = icon.label;
} else {
if (content._delegate && content._delegate.getDragActorSource)
this._dragActorSource = content._delegate.getDragActorSource();
}
this._content = content;
this.actor.set_child(content);
@ -81,8 +77,6 @@ SearchResult.prototype = {
},
getDragActorSource: function() {
if (this._dragActorSource)
return this._dragActorSource;
// not exactly right, but alignment problems are hard to notice
return this._content;
},
@ -199,7 +193,7 @@ SearchResults.prototype = {
let scrollView = new St.ScrollView({ x_fill: true,
y_fill: false,
style_class: 'vfade' });
vfade: true });
scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
scrollView.add_actor(this._content);
@ -265,7 +259,6 @@ SearchResults.prototype = {
let title = new St.Label({ text: provider.name,
style_class: 'dash-search-button-label' });
button.label_actor = title;
bin.set_child(title);
button.set_child(bin);
provider.actor = button;

View File

@ -1,405 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Lang = imports.lang;
const Signals = imports.signals;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Pango = imports.gi.Pango;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const ModalDialog = imports.ui.modalDialog;
const Params = imports.misc.params;
const LIST_ITEM_ICON_SIZE = 48;
/* ------ Common Utils ------- */
function _setLabelText(label, text) {
if (text) {
label.set_text(text);
label.show();
} else {
label.set_text('');
label.hide();
}
}
function _setButtonsForChoices(dialog, choices) {
let buttons = [];
for (let idx = 0; idx < choices.length; idx++) {
let button = idx;
buttons.unshift({ label: choices[idx],
action: Lang.bind(dialog, function() {
dialog.emit('response', button);
})});
}
dialog.setButtons(buttons);
}
function _setLabelsForMessage(dialog, message) {
let labels = message.split('\n');
_setLabelText(dialog.subjectLabel, labels[0]);
if (labels.length > 1)
_setLabelText(dialog.descriptionLabel, labels[1]);
}
/* -------------------------------------------------------- */
function ListItem(app) {
this._init(app);
}
ListItem.prototype = {
_init: function(app) {
this._app = app;
let layout = new St.BoxLayout({ vertical: false});
this.actor = new St.Button({ style_class: 'show-processes-dialog-app-list-item',
can_focus: true,
child: layout,
reactive: true,
x_align: St.Align.START,
x_fill: true });
this._icon = this._app.create_icon_texture(LIST_ITEM_ICON_SIZE);
let iconBin = new St.Bin({ style_class: 'show-processes-dialog-app-list-item-icon',
child: this._icon });
layout.add(iconBin);
this._nameLabel = new St.Label({ text: this._app.get_name(),
style_class: 'show-processes-dialog-app-list-item-name' });
let labelBin = new St.Bin({ y_align: St.Align.MIDDLE,
child: this._nameLabel });
layout.add(labelBin);
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
},
_onClicked: function() {
this.emit('activate');
this._app.activate(-1);
}
};
Signals.addSignalMethods(ListItem.prototype);
function ShellMountOperation(source, params) {
this._init(source, params);
}
ShellMountOperation.prototype = {
_init: function(source, params) {
params = Params.parse(params, { reaskPassword: false });
this._reaskPassword = params.reaskPassword;
this._dialog = null;
this._processesDialog = null;
this.mountOp = new Shell.MountOperation();
this.mountOp.connect('ask-question',
Lang.bind(this, this._onAskQuestion));
this.mountOp.connect('ask-password',
Lang.bind(this, this._onAskPassword));
this.mountOp.connect('show-processes-2',
Lang.bind(this, this._onShowProcesses2));
this.mountOp.connect('aborted',
Lang.bind(this, this._onAborted));
this._icon = new St.Icon({ gicon: source.get_icon(),
style_class: 'shell-mount-operation-icon' });
},
_onAskQuestion: function(op, message, choices) {
this._dialog = new ShellMountQuestionDialog(this._icon);
this._dialog.connect('response',
Lang.bind(this, function(object, choice) {
this.mountOp.set_choice(choice);
this.mountOp.reply(Gio.MountOperationResult.HANDLED);
this._dialog.close(global.get_current_time());
this._dialog = null;
}));
this._dialog.update(message, choices);
this._dialog.open(global.get_current_time());
},
_onAskPassword: function(op, message) {
this._notificationShowing = true;
this._source = new ShellMountPasswordSource(message, this._icon, this._reaskPassword);
this._source.connect('password-ready',
Lang.bind(this, function(source, password) {
this.mountOp.set_password(password);
this.mountOp.reply(Gio.MountOperationResult.HANDLED);
this._notificationShowing = false;
this._source.destroy();
}));
this._source.connect('destroy',
Lang.bind(this, function() {
if (!this._notificationShowing)
return;
this._notificationShowing = false;
this.mountOp.reply(Gio.MountOperationResult.ABORTED);
}));
},
_onAborted: function(op) {
if (!this._dialog)
return;
this._dialog.close(global.get_current_time());
this._dialog = null;
},
_onShowProcesses2: function(op) {
let processes = op.get_show_processes_pids();
let choices = op.get_show_processes_choices();
let message = op.get_show_processes_message();
if (!this._processesDialog) {
this._processesDialog = new ShellProcessesDialog(this._icon);
this._dialog = this._processesDialog;
this._processesDialog.connect('response',
Lang.bind(this, function(object, choice) {
if (choice == -1) {
this.mountOp.reply(Gio.MountOperationResult.ABORTED);
} else {
this.mountOp.set_choice(choice);
this.mountOp.reply(Gio.MountOperationResult.HANDLED);
}
this._processesDialog.close(global.get_current_time());
this._dialog = null;
}));
this._processesDialog.open(global.get_current_time());
}
this._processesDialog.update(message, processes, choices);
},
}
function ShellMountQuestionDialog(icon) {
this._init(icon);
}
ShellMountQuestionDialog.prototype = {
__proto__: ModalDialog.ModalDialog.prototype,
_init: function(icon) {
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'mount-question-dialog' });
let mainContentLayout = new St.BoxLayout();
this.contentLayout.add(mainContentLayout, { x_fill: true,
y_fill: false });
this._iconBin = new St.Bin({ child: icon });
mainContentLayout.add(this._iconBin,
{ x_fill: true,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
let messageLayout = new St.BoxLayout({ vertical: true });
mainContentLayout.add(messageLayout,
{ y_align: St.Align.START });
this.subjectLabel = new St.Label({ style_class: 'mount-question-dialog-subject' });
messageLayout.add(this.subjectLabel,
{ y_fill: false,
y_align: St.Align.START });
this.descriptionLabel = new St.Label({ style_class: 'mount-question-dialog-description' });
this.descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this.descriptionLabel.clutter_text.line_wrap = true;
messageLayout.add(this.descriptionLabel,
{ y_fill: true,
y_align: St.Align.START });
},
update: function(message, choices) {
_setLabelsForMessage(this, message);
_setButtonsForChoices(this, choices);
}
}
Signals.addSignalMethods(ShellMountQuestionDialog.prototype);
function ShellMountPasswordSource(message, icon, reaskPassword) {
this._init(message, icon, reaskPassword);
}
ShellMountPasswordSource.prototype = {
__proto__: MessageTray.Source.prototype,
_init: function(message, icon, reaskPassword) {
let strings = message.split('\n');
MessageTray.Source.prototype._init.call(this, strings[0]);
this._notification = new ShellMountPasswordNotification(this, strings, icon, reaskPassword);
// add ourselves as a source, and popup the notification
Main.messageTray.add(this);
this.notify(this._notification);
},
}
Signals.addSignalMethods(ShellMountPasswordSource.prototype);
function ShellMountPasswordNotification(source, strings, icon, reaskPassword) {
this._init(source, strings, icon, reaskPassword);
}
ShellMountPasswordNotification.prototype = {
__proto__: MessageTray.Notification.prototype,
_init: function(source, strings, icon, reaskPassword) {
MessageTray.Notification.prototype._init.call(this, source,
strings[0], null,
{ customContent: true,
icon: icon });
// set the notification to transient and urgent, so that it
// expands out
this.setTransient(true);
this.setUrgency(MessageTray.Urgency.CRITICAL);
if (strings[1])
this.addBody(strings[1]);
if (reaskPassword) {
let label = new St.Label({ style_class: 'mount-password-reask',
text: _("Wrong password, please try again") });
this.addActor(label);
}
this._responseEntry = new St.Entry({ style_class: 'mount-password-entry',
can_focus: true });
this.setActionArea(this._responseEntry);
this._responseEntry.clutter_text.connect('activate',
Lang.bind(this, this._onEntryActivated));
this._responseEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
this._responseEntry.grab_key_focus();
},
_onEntryActivated: function() {
let text = this._responseEntry.get_text();
if (text == '')
return;
this.source.emit('password-ready', text);
}
}
function ShellProcessesDialog(icon) {
this._init(icon);
}
ShellProcessesDialog.prototype = {
__proto__: ModalDialog.ModalDialog.prototype,
_init: function(icon) {
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'show-processes-dialog' });
let mainContentLayout = new St.BoxLayout();
this.contentLayout.add(mainContentLayout, { x_fill: true,
y_fill: false });
this._iconBin = new St.Bin({ child: icon });
mainContentLayout.add(this._iconBin,
{ x_fill: true,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
let messageLayout = new St.BoxLayout({ vertical: true });
mainContentLayout.add(messageLayout,
{ y_align: St.Align.START });
this.subjectLabel = new St.Label({ style_class: 'show-processes-dialog-subject' });
messageLayout.add(this.subjectLabel,
{ y_fill: false,
y_align: St.Align.START });
this.descriptionLabel = new St.Label({ style_class: 'show-processes-dialog-description' });
this.descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this.descriptionLabel.clutter_text.line_wrap = true;
messageLayout.add(this.descriptionLabel,
{ y_fill: true,
y_align: St.Align.START });
let scrollView = new St.ScrollView({ style_class: 'show-processes-dialog-app-list'});
scrollView.set_policy(Gtk.PolicyType.NEVER,
Gtk.PolicyType.AUTOMATIC);
this.contentLayout.add(scrollView,
{ x_fill: true,
y_fill: true });
scrollView.hide();
this._applicationList = new St.BoxLayout({ vertical: true });
scrollView.add_actor(this._applicationList,
{ x_fill: true,
y_fill: true,
x_align: St.Align.START,
y_align: St.Align.MIDDLE });
this._applicationList.connect('actor-added',
Lang.bind(this, function() {
if (this._applicationList.get_children().length == 1)
scrollView.show();
}));
this._applicationList.connect('actor-removed',
Lang.bind(this, function() {
if (this._applicationList.get_children().length == 0)
scrollView.hide();
}));
},
_setAppsForPids: function(pids) {
// remove all the items
this._applicationList.destroy_children();
pids.forEach(Lang.bind(this, function(pid) {
let tracker = Shell.WindowTracker.get_default();
let app = tracker.get_app_from_pid(pid);
if (!app)
return;
let item = new ListItem(app);
this._applicationList.add(item.actor, { x_fill: true });
item.connect('activate',
Lang.bind(this, function() {
// use -1 to indicate Cancel
this.emit('response', -1);
}));
}));
},
update: function(message, processes, choices) {
this._setAppsForPids(processes);
_setLabelsForMessage(this, message);
_setButtonsForChoices(this, choices);
}
}
Signals.addSignalMethods(ShellProcessesDialog.prototype);

View File

@ -10,11 +10,13 @@ const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
const KEY_STICKY_KEYS_ENABLED = 'stickykeys-enable';
const KEY_BOUNCE_KEYS_ENABLED = 'bouncekeys-enable';
@ -89,7 +91,6 @@ ATIndicator.prototype = {
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Universal Access Settings"), function() {
Main.overview.hide();
let app = Shell.AppSystem.get_default().get_app('gnome-universal-access-panel.desktop');
app.activate(-1);
});

View File

@ -16,6 +16,9 @@ const MessageTray = imports.ui.messageTray;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const ConnectionState = {
DISCONNECTED: 0,
CONNECTED: 1,
@ -64,7 +67,7 @@ Indicator.prototype = {
this._fullMenuItems = [new PopupMenu.PopupSeparatorMenuItem(),
new PopupMenu.PopupMenuItem(_("Send Files to Device...")),
new PopupMenu.PopupMenuItem(_("Set up a New Device...")),
new PopupMenu.PopupMenuItem(_("Setup a New Device...")),
new PopupMenu.PopupSeparatorMenuItem()];
this._hasDevices = false;
this._deviceSep = this._fullMenuItems[0]; // hidden if no device exists
@ -90,7 +93,6 @@ Indicator.prototype = {
this._updateFullMenu();
this.menu.addAction(_("Bluetooth Settings"), function() {
Main.overview.hide()
let app = Shell.AppSystem.get_default().get_app('bluetooth-properties.desktop');
app.activate(-1);
});
@ -109,11 +111,7 @@ Indicator.prototype = {
current_state != GnomeBluetoothApplet.KillswitchState.HARD_BLOCKED;
this._killswitch.setToggleState(on);
if (can_toggle)
this._killswitch.setStatus(null);
else
/* TRANSLATORS: this means that bluetooth was disabled by hardware rfkill */
this._killswitch.setStatus(_("hardware disabled"));
this._killswitch.actor.reactive = can_toggle;
if (has_adapter)
this.actor.show();
@ -129,6 +127,13 @@ Indicator.prototype = {
}
},
_deviceCompare: function(d1, d2) {
return d1.device_path == d2.device_path &&
d1.bdaddr == d2.bdaddr &&
d1.can_connect == d2.can_connect &&
d1.capabilities == d2.capabilities;
},
_updateDevices: function() {
let devices = this._applet.get_devices();
@ -137,8 +142,12 @@ Indicator.prototype = {
let item = this._deviceItems[i];
let destroy = true;
for (let j = 0; j < devices.length; j++) {
if (item._device.device_path == devices[j].device_path) {
this._updateDeviceItem(item, devices[j]);
// we need to deep compare because BluetoothSimpleDevice is a boxed type
// (but we take advantage of that, because _skip will disappear the next
// time get_devices() is called)
if (this._deviceCompare(item._device, devices[j])) {
item.label.text = devices[j].alias;
devices[j]._skip = true;
destroy = false;
break;
}
@ -153,7 +162,7 @@ Indicator.prototype = {
this._hasDevices = newlist.length > 0;
for (let i = 0; i < devices.length; i++) {
let d = devices[i];
if (d._item)
if (d._skip)
continue;
let item = this._createDeviceItem(d);
if (item) {
@ -168,62 +177,23 @@ Indicator.prototype = {
this._deviceSep.actor.hide();
},
_updateDeviceItem: function(item, device) {
if (!device.can_connect && device.capabilities == GnomeBluetoothApplet.Capabilities.NONE) {
item.destroy();
return;
}
let prevDevice = item._device;
let prevCapabilities = prevDevice.capabilities;
let prevCanConnect = prevDevice.can_connect;
// adopt the new device object
item._device = device;
device._item = item;
// update properties
item.label.text = device.alias;
if (prevCapabilities != device.capabilities ||
prevCanConnect != device.can_connect) {
// need to rebuild the submenu
item.menu.removeAll();
this._buildDeviceSubMenu(item, device);
}
// update connected property
if (device.can_connect)
item._connectedMenuitem.setToggleState(device.connected);
},
_createDeviceItem: function(device) {
if (!device.can_connect && device.capabilities == GnomeBluetoothApplet.Capabilities.NONE)
return null;
let item = new PopupMenu.PopupSubMenuMenuItem(device.alias);
// adopt the device object, and add a back link
item._device = device;
device._item = item;
this._buildDeviceSubMenu(item, device);
return item;
},
_buildDeviceSubMenu: function(item, device) {
if (device.can_connect) {
item._connected = device.connected;
item._connectedMenuitem = new PopupMenu.PopupSwitchMenuItem(_("Connection"), device.connected);
item._connectedMenuitem.connect('toggled', Lang.bind(this, function() {
let menuitem = new PopupMenu.PopupSwitchMenuItem(_("Connection"), device.connected);
menuitem.connect('toggled', Lang.bind(this, function() {
if (item._connected > ConnectionState.CONNECTED) {
// operation already in progress, revert
// (should not happen anyway)
menuitem.setToggleState(menuitem.state);
}
if (item._connected) {
item._connected = ConnectionState.DISCONNECTING;
menuitem.setStatus(_("disconnecting..."));
this._applet.disconnect_device(item._device.device_path, function(applet, success) {
if (success) { // apply
item._connected = ConnectionState.DISCONNECTED;
@ -232,11 +202,9 @@ Indicator.prototype = {
item._connected = ConnectionState.CONNECTED;
menuitem.setToggleState(true);
}
menuitem.setStatus(null);
});
} else {
item._connected = ConnectionState.CONNECTING;
menuitem.setStatus(_("connecting..."));
this._applet.connect_device(item._device.device_path, function(applet, success) {
if (success) { // apply
item._connected = ConnectionState.CONNECTED;
@ -245,12 +213,11 @@ Indicator.prototype = {
item._connected = ConnectionState.DISCONNECTED;
menuitem.setToggleState(false);
}
menuitem.setStatus(null);
});
}
}));
item.menu.addMenuItem(item._connectedMenuitem);
item.menu.addMenuItem(menuitem);
}
if (device.capabilities & GnomeBluetoothApplet.Capabilities.OBEX_PUSH) {
@ -296,6 +263,8 @@ Indicator.prototype = {
default:
break;
}
return item;
},
_updateFullMenu: function() {

View File

@ -9,11 +9,13 @@ const Lang = imports.lang;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Main = imports.ui.main;
const PopupMenu = imports.ui.popupMenu;
const PanelMenu = imports.ui.panelMenu;
const Util = imports.misc.util;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
function LayoutMenuItem() {
this._init.apply(this, arguments);
}
@ -69,11 +71,9 @@ XKBIndicator.prototype = {
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Show Keyboard Layout..."), Lang.bind(this, function() {
Main.overview.hide();
Util.spawn(['gkbd-keyboard-display', '-g', String(this._config.get_current_group() + 1)]);
}));
this.menu.addAction(_("Localization Settings"), function() {
Main.overview.hide();
let app = Shell.AppSystem.get_default().get_app('gnome-region-panel.desktop');
app.activate(-1);
});

View File

@ -18,6 +18,9 @@ const MessageTray = imports.ui.messageTray;
const ModemManager = imports.misc.modemManager;
const Util = imports.misc.util;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const NMConnectionCategory = {
INVALID: 'invalid',
WIRED: 'wired',
@ -41,10 +44,6 @@ const NM80211Mode = NetworkManager['80211Mode'];
const NM80211ApFlags = NetworkManager['80211ApFlags'];
const NM80211ApSecurityFlags = NetworkManager['80211ApSecurityFlags'];
// number of wireless networks that should be visible
// (the remaining are placed into More...)
const NUM_VISIBLE_NETWORKS = 5;
const NMAppletHelperInterface = {
name: 'org.gnome.network_manager_applet',
methods: [
@ -192,7 +191,63 @@ NMNetworkMenuItem.prototype = {
apObj.updateId = 0;
}
PopupMenu.PopupBaseMenuItem.prototype.destroy.call(this);
PopupMenu.PopupImageMenuItem.prototype.destroy.call(this);
}
};
function NMDeviceTitleMenuItem() {
this._init.apply(this, arguments);
}
NMDeviceTitleMenuItem.prototype = {
__proto__: PopupMenu.PopupBaseMenuItem.prototype,
_init: function(description, params) {
PopupMenu.PopupBaseMenuItem.prototype._init.call(this, params);
this._descriptionLabel = new St.Label({ text: description,
style_class: 'popup-subtitle-menu-item'
});
this.addActor(this._descriptionLabel);
this._statusBin = new St.Bin({ x_align: St.Align.END });
this.addActor(this._statusBin, { align: St.Align.END });
this._statusLabel = new St.Label({ text: '',
style_class: 'popup-inactive-menu-item'
});
this._switch = new PopupMenu.Switch(false);
this._statusBin.child = this._switch.actor;
},
setStatus: function(text) {
if (text != null) {
this._statusLabel.text = text;
this._statusBin.child = this._statusLabel;
this.actor.reactive = false;
this.actor.can_focus = false;
} else {
this._statusBin.child = this._switch.actor;
this.actor.reactive = true;
this.actor.can_focus = true;
}
},
activate: function(event) {
if (this._switch.actor.mapped) {
this._switch.toggle();
this.emit('toggled', this._switch.state);
}
PopupMenu.PopupBaseMenuItem.prototype.activate.call(this, event);
},
get state() {
return this._switch.state;
},
setToggleState: function(newval) {
this._switch.setToggleState(newval);
}
};
@ -201,13 +256,7 @@ function NMWiredSectionTitleMenuItem() {
}
NMWiredSectionTitleMenuItem.prototype = {
__proto__: PopupMenu.PopupSwitchMenuItem.prototype,
_init: function(label, params) {
params = params || { };
params.style_class = 'popup-subtitle-menu-item';
PopupMenu.PopupSwitchMenuItem.prototype._init.call(this, label, false, params);
},
__proto__: NMDeviceTitleMenuItem.prototype,
updateForDevice: function(device) {
if (device) {
@ -219,7 +268,7 @@ NMWiredSectionTitleMenuItem.prototype = {
},
activate: function(event) {
PopupMenu.PopupSwitchMenuItem.prototype.activate.call(this, event);
NMDeviceTitleMenuItem.prototype.activate.call(this, event);
if (!this._device) {
log('Section title activated when there is more than one device, should be non reactive');
@ -245,12 +294,10 @@ function NMWirelessSectionTitleMenuItem() {
}
NMWirelessSectionTitleMenuItem.prototype = {
__proto__: PopupMenu.PopupSwitchMenuItem.prototype,
__proto__: NMDeviceTitleMenuItem.prototype,
_init: function(client, property, title, params) {
params = params || { };
params.style_class = 'popup-subtitle-menu-item';
PopupMenu.PopupSwitchMenuItem.prototype._init.call(this, title, false, params);
NMDeviceTitleMenuItem.prototype._init.call(this, title, params);
this._client = client;
this._property = property + '_enabled';
@ -276,7 +323,7 @@ NMWirelessSectionTitleMenuItem.prototype = {
},
activate: function(event) {
PopupMenu.PopupSwitchMenuItem.prototype.activate.call(this, event);
NMDeviceTitleMenuItem.prototype.activate.call(this, event);
this._client[this._setEnabledFunc](this._switch.state);
},
@ -325,14 +372,15 @@ NMDevice.prototype = {
};
this._connections.push(obj);
}
this._connections.sort(this._connectionSortFunction);
this._connections.sort(function(one, two) {
return two.timestamp - one.timestamp;
});
this._activeConnection = null;
this._activeConnectionItem = null;
this._autoConnectionItem = null;
this._overflowItem = null;
if (this.device) {
this.statusItem = new PopupMenu.PopupSwitchMenuItem(this._getDescription(), this.connected, { style_class: 'popup-subtitle-menu-item' });
this.statusItem = new NMDeviceTitleMenuItem(this._getDescription());
this._statusChanged = this.statusItem.connect('toggled', Lang.bind(this, function(item, state) {
if (state)
this.activate();
@ -433,7 +481,9 @@ NMDevice.prototype = {
timestamp: connection._timestamp,
};
this._connections.push(obj);
this._connections.sort(this._connectionSortFunction);
this._connections.sort(function(one, two) {
return two.timestamp - one.timestamp;
});
this._clearSection();
this._createSection();
@ -468,13 +518,6 @@ NMDevice.prototype = {
return this.device.connection_valid(connection);
},
_connectionSortFunction: function(one, two) {
if (one.timestamp == two.timestamp)
return GLib.utf8_collate(one.name, two.name);
return two.timestamp - one.timestamp;
},
setEnabled: function(enabled) {
// do nothing by default, we want to keep the conneciton list visible
// in the majority of cases (wired, wwan, vpn)
@ -482,15 +525,11 @@ NMDevice.prototype = {
getStatusLabel: function() {
switch(this.device.state) {
case NetworkManager.DeviceState.UNMANAGED:
case NetworkManager.DeviceState.DISCONNECTED:
case NetworkManager.DeviceState.DEACTIVATING:
case NetworkManager.DeviceState.ACTIVATED:
return null;
case NetworkManager.DeviceState.UNMANAGED:
/* Translators: this is for network devices that are physically present but are not
under NetworkManager's control (and thus cannot be used in the menu) */
return _("unmanaged");
case NetworkManager.DeviceState.DEACTIVATING:
return _("disconnecting...");
case NetworkManager.DeviceState.PREPARE:
case NetworkManager.DeviceState.CONFIG:
case NetworkManager.DeviceState.IP_CONFIG:
@ -549,7 +588,6 @@ NMDevice.prototype = {
this.section.removeAll();
this._autoConnectionItem = null;
this._activeConnectionItem = null;
this._overflowItem = null;
for (let i = 0; i < this._connections.length; i++) {
this._connections[i].item = null;
}
@ -568,23 +606,13 @@ NMDevice.prototype = {
this.section.addMenuItem(this._activeConnectionItem);
}
if (this._connections.length > 0) {
let activeOffset = this._activeConnectionItem ? 1 : 0;
for(let j = 0; j < this._connections.length; ++j) {
let obj = this._connections[j];
if (this._activeConnection &&
obj.connection == this._activeConnection._connection)
continue;
obj.item = this._createConnectionItem(obj);
if (j + activeOffset >= NUM_VISIBLE_NETWORKS) {
if (!this._overflowItem) {
this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More..."));
this.section.addMenuItem(this._overflowItem);
}
this._overflowItem.menu.addMenuItem(obj.item);
} else
this.section.addMenuItem(obj.item);
this.section.addMenuItem(obj.item);
}
} else if (this._autoConnectionName) {
this._autoConnectionItem = new PopupMenu.PopupMenuItem(this._autoConnectionName);
@ -792,7 +820,7 @@ NMDeviceModem.prototype = {
}));
}
NMDevice.prototype._init.call(this, client, device, connections);
NMDevice.prototype._init.call(this, client, device, connections, 1);
},
setEnabled: function(enabled) {
@ -998,7 +1026,6 @@ NMDeviceWireless.prototype = {
item: null,
accessPoints: [ ap ]
};
obj.ssidText = NetworkManager.utils_ssid_to_utf8(obj.ssid);
this._networks.push(obj);
}
@ -1011,14 +1038,6 @@ NMDeviceWireless.prototype = {
}
}
}
if (this.device.active_access_point) {
this._activeNetwork = this._networks[this._findNetwork(this.device.active_access_point)];
} else {
this._activeNetwork = null;
}
this._networks.sort(this._networkSortFunction);
this._apChangedId = device.connect('notify::active-access-point', Lang.bind(this, this._activeApChanged));
this._apAddedId = device.connect('access-point-added', Lang.bind(this, this._accessPointAdded));
this._apRemovedId = device.connect('access-point-removed', Lang.bind(this, this._accessPointRemoved));
@ -1026,13 +1045,8 @@ NMDeviceWireless.prototype = {
},
destroy: function() {
if (this._apChangedId) {
// see above for this HACK
GObject.Object.prototype.disconnect.call(this.device, this._apChangedId);
this._apChangedId = 0;
}
if (this._apAddedId) {
// see above for this HACK
GObject.Object.prototype.disconnect.call(this.device, this._apAddedId);
this._apAddedId = 0;
}
@ -1098,19 +1112,6 @@ NMDeviceWireless.prototype = {
}
},
_activeApChanged: function() {
this._activeNetwork = null;
let activeAp = this.device.active_access_point;
if (activeAp) {
let pos = this._findNetwork(activeAp);
this._activeNetwork = this._networks[pos];
}
// we don't refresh the view here, setActiveConnection will
},
_getApSecurityType: function(accessPoint) {
if (accessPoint._secType)
return accessPoint._secType;
@ -1142,32 +1143,6 @@ NMDeviceWireless.prototype = {
return type;
},
_networkSortFunction: function(one, two) {
let oneHasConnection = one.connections.length != 0;
let twoHasConnection = two.connections.length != 0;
// place known connections first
// (-1 = good order, 1 = wrong order)
if (oneHasConnection && !twoHasConnection)
return -1;
else if (!oneHasConnection && twoHasConnection)
return 1;
let oneHasSecurity = one.security != NMAccessPointSecurity.NONE;
let twoHasSecurity = two.security != NMAccessPointSecurity.NONE;
// place secure connections first
// (we treat WEP/WPA/WPA2 the same as there is no way to
// take them apart from the UI)
if (oneHasSecurity && !twoHasSecurity)
return -1;
else if (!oneHasSecurity && twoHasSecurity)
return 1;
// sort alphabetically
return GLib.utf8_collate(one.ssidText, two.ssidText);
},
_networkCompare: function(network, accessPoint) {
if (!ssidCompare(network.ssid, accessPoint.get_ssid()))
return false;
@ -1190,8 +1165,6 @@ NMDeviceWireless.prototype = {
_accessPointAdded: function(device, accessPoint) {
let pos = this._findNetwork(accessPoint);
let apObj;
let needsupdate = false;
if (pos != -1) {
apObj = this._networks[pos];
if (apObj.accessPoints.indexOf(accessPoint) != -1) {
@ -1200,8 +1173,6 @@ NMDeviceWireless.prototype = {
}
apObj.accessPoints.push(accessPoint);
if (apObj.item)
apObj.item.updateAccessPoints(apObj.accessPoints);
} else {
apObj = { ssid: accessPoint.get_ssid(),
mode: accessPoint.mode,
@ -1210,8 +1181,7 @@ NMDeviceWireless.prototype = {
item: null,
accessPoints: [ accessPoint ]
};
apObj.ssidText = NetworkManager.utils_ssid_to_utf8(apObj.ssid);
needsupdate = true;
this._networks.push(apObj);
}
// check if this enables new connections for this group
@ -1220,44 +1190,12 @@ NMDeviceWireless.prototype = {
if (accessPoint.connection_valid(connection) &&
apObj.connections.indexOf(connection) == -1) {
apObj.connections.push(connection);
// this potentially changes the order
needsupdate = true;
}
}
if (needsupdate) {
if (apObj.item)
apObj.item.destroy();
if (pos != -1)
this._networks.splice(pos, 1);
if (this._networks.length == 0) {
// 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);
}
}
// update everything
this._clearSection();
this._createSection();
},
_accessPointRemoved: function(device, accessPoint) {
@ -1281,29 +1219,12 @@ NMDeviceWireless.prototype = {
if (apObj.accessPoints.length == 0) {
if (apObj.item)
apObj.item.destroy();
if (this._overflowItem) {
if (!apObj.isMore) {
// we removed an item in the main menu, and we have a more submenu
// we need to extract the first item in more and move it to the submenu
let apObj = this._overflowItem.menu.firstMenuItem;
if (apObj.item) {
apObj.item.destroy();
this._createNetworkItem(apObj, NUM_VISIBLE_NETWORKS-1);
}
}
// This can happen if the removed connection is from the overflow
// menu, or if we just moved the last connection out from the menu
if (this._overflowItem.menu.length == 0) {
this._overflowItem.destroy();
this._overflowItem = null;
}
}
this._networks.splice(pos, 1);
if (this._overflowItem &&
this._overflowItem.menu.length == 0) {
this._overflowItem.destroy();
this._overflowItem = null;
}
} else if (apObj.item)
apObj.item.updateAccessPoints(apObj.accessPoints);
},
@ -1352,12 +1273,6 @@ NMDeviceWireless.prototype = {
// remove the connection from the access point group
connections.splice(k);
anyauto = connections.length == 0;
if (anyauto) {
// this potentially changes the sorting order
forceupdate = true;
break;
}
if (apObj.item) {
if (apObj.item instanceof PopupMenu.PopupSubMenuMenuItem) {
let items = apObj.item.menu.getMenuItems();
@ -1383,7 +1298,6 @@ NMDeviceWireless.prototype = {
}
if (forceupdate || anyauto) {
this._networks.sort(this._networkSortFunction);
this._clearSection();
this._createSection();
}
@ -1399,24 +1313,42 @@ NMDeviceWireless.prototype = {
this._connections.push(obj);
// find an appropriate access point
let forceupdate = false;
let any = false, forceupdate = false;
for (let i = 0; i < this._networks.length; i++) {
let apObj = this._networks[i];
// Check if connection is valid for any of these access points
let any = false;
for (let k = 0; k < apObj.accessPoints.length; k++) {
let ap = apObj.accessPoints[k];
if (ap.connection_valid(connection)) {
apObj.connections.push(connection);
// this potentially changes the sorting order
forceupdate = true;
any = true;
break;
}
}
if (any && this._shouldShowConnectionList()) {
// we need to show this connection
if (apObj.item && apObj.item.menu) {
// We're already showing the submenu for this access point
apObj.item.menu.addMenuItem(this._createAPItem(connection, apObj, true));
} else {
if (apObj.item)
apObj.item.destroy();
if (apObj.connections.length == 1) {
apObj.item = this._createAPItem(connection, apObj, false);
this.section.addMenuItem(apObj.item);
} else {
apObj.item = null;
// we need to force an update to create the submenu
forceupdate = true;
}
}
}
}
if (forceupdate) {
this._networks.sort(this._networkSortFunction);
this._clearSection();
this._createSection();
}
@ -1468,50 +1400,6 @@ NMDeviceWireless.prototype = {
return connection;
},
_createNetworkItem: function(apObj, position) {
if(apObj.connections.length > 0) {
if (apObj.connections.length == 1)
apObj.item = this._createAPItem(apObj.connections[0], apObj, false);
else {
let title = apObj.ssidText;
apObj.item = new PopupMenu.PopupSubMenuMenuItem(title);
apObj.item._apObj = apObj;
for (let i = 0; i < apObj.connections.length; i++)
apObj.item.menu.addMenuItem(this._createAPItem(apObj.connections[i], apObj, true));
}
} else {
apObj.item = new NMNetworkMenuItem(apObj.accessPoints);
apObj.item._apObj = apObj;
apObj.item.connect('activate', Lang.bind(this, function() {
let accessPoints = sortAccessPoints(apObj.accessPoints);
if ( (accessPoints[0]._secType == NMAccessPointSecurity.WPA2_ENT)
|| (accessPoints[0]._secType == NMAccessPointSecurity.WPA_ENT)) {
// 802.1x-enabled APs get handled by nm-applet for now...
this._applet_proxy.ConnectTo8021xNetworkRemote(this.device.get_path(),
accessPoints[0].dbus_path,
Lang.bind(this, function(results, err) {
if (err)
log(err);
}));
} else {
let connection = this._createAutomaticConnection(apObj);
this._client.add_and_activate_connection(connection, this.device, accessPoints[0].dbus_path, null)
}
}));
}
if (position < NUM_VISIBLE_NETWORKS) {
apObj.isMore = false;
this.section.addMenuItem(apObj.item, position);
} else {
if (!this._overflowItem) {
this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More..."));
this.section.addMenuItem(this._overflowItem);
}
this._overflowItem.menu.addMenuItem(apObj.item, position - NUM_VISIBLE_NETWORKS);
apObj.isMore = true;
}
},
_createSection: function() {
if (!this._shouldShowConnectionList())
return;
@ -1521,14 +1409,58 @@ NMDeviceWireless.prototype = {
this.section.addMenuItem(this._activeConnectionItem);
}
let activeOffset = this._activeConnectionItem ? 1 : 0;
let activeAp = this.device.active_access_point;
let activeApSsid = activeAp ? activeAp.get_ssid() : null;
// we want five access points in the menu, including the active one
let numItems = this._activeConnection ? 4 : 5;
for(let j = 0; j < this._networks.length; j++) {
let apObj = this._networks[j];
if (apObj == this._activeNetwork)
if(activeAp && ssidCompare(apObj.ssid, activeApSsid))
continue;
this._createNetworkItem(apObj, j + activeOffset);
let menuItem;
if(apObj.connections.length > 0) {
if (apObj.connections.length == 1)
apObj.item = this._createAPItem(apObj.connections[0], apObj, false);
else {
let title = NetworkManager.utils_ssid_to_utf8(apObj.ssid) || _("<unknown>");
apObj.item = new PopupMenu.PopupSubMenuMenuItem(title);
apObj.item._apObj = apObj;
for (let i = 0; i < apObj.connections.length; i++)
apObj.item.menu.addMenuItem(this._createAPItem(apObj.connections[i], apObj, true));
}
} else {
apObj.item = new NMNetworkMenuItem(apObj.accessPoints);
apObj.item._apObj = apObj;
apObj.item.connect('activate', Lang.bind(this, function() {
let accessPoints = sortAccessPoints(apObj.accessPoints);
if ( (accessPoints[0]._secType == NMAccessPointSecurity.WPA2_ENT)
|| (accessPoints[0]._secType == NMAccessPointSecurity.WPA_ENT)) {
// 802.1x-enabled APs get handled by nm-applet for now...
this._applet_proxy.ConnectTo8021xNetworkRemote(this.device.get_path(),
accessPoints[0].dbus_path,
Lang.bind(this, function(results, err) {
if (err)
log(err);
}));
} else {
let connection = this._createAutomaticConnection(apObj);
this._client.add_and_activate_connection(connection, this.device, accessPoints[0].dbus_path, null)
}
}));
}
if (j < numItems)
this.section.addMenuItem(apObj.item);
else {
if (!this._overflowItem) {
this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More..."));
this.section.addMenuItem(this._overflowItem);
}
this._overflowItem.menu.addMenuItem(apObj.item);
}
}
},
};
@ -1603,7 +1535,6 @@ NMApplet.prototype = {
this.menu.addMenuItem(this._devices.vpn.section);
this.menu.addAction(_("Network Settings"), function() {
Main.overview.hide();
let app = Shell.AppSystem.get_default().get_app('gnome-network-panel.desktop');
app.activate(-1);
});
@ -1682,18 +1613,21 @@ NMApplet.prototype = {
_syncSectionTitle: function(category) {
let devices = this._devices[category].devices;
let managedDevices = devices.filter(function(dev) {
return dev.device.state != NetworkManager.DeviceState.UNMANAGED;
});
let item = this._devices[category].item;
let section = this._devices[category].section;
if (devices.length == 0)
if (managedDevices.length == 0)
section.actor.hide();
else {
section.actor.show();
if (devices.length == 1) {
let dev = devices[0];
if (managedDevices.length == 1) {
let dev = managedDevices[0];
dev.statusItem.actor.hide();
item.updateForDevice(dev);
} else {
devices.forEach(function(dev) {
managedDevices.forEach(function(dev) {
dev.statusItem.actor.show();
});
// remove status text from the section title item

View File

@ -7,13 +7,15 @@ const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const BUS_NAME = 'org.gnome.SettingsDaemon';
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Power';
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const BUS_NAME = 'org.gnome.PowerManager';
const OBJECT_PATH = '/org/gnome/PowerManager';
const UPDeviceType = {
UNKNOWN: 0,
@ -41,7 +43,7 @@ const UPDeviceState = {
};
const PowerManagerInterface = {
name: 'org.gnome.SettingsDaemon.Power',
name: 'org.gnome.PowerManager',
methods: [
{ name: 'GetDevices', inSignature: '', outSignature: 'a(susbut)' },
{ name: 'GetPrimaryDevice', inSignature: '', outSignature: '(susbut)' },
@ -81,7 +83,6 @@ Indicator.prototype = {
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Power Settings"),function() {
Main.overview.hide();
let app = Shell.AppSystem.get_default().get_app('gnome-power-panel.desktop');
app.activate(-1);
});
@ -93,6 +94,7 @@ Indicator.prototype = {
_readPrimaryDevice: function() {
this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(device, error) {
if (error) {
this._checkError(error);
this._hasPrimary = false;
this._primaryDeviceId = null;
this._batteryItem.actor.hide();
@ -113,15 +115,15 @@ Indicator.prototype = {
let timestring;
if (time > 60) {
if (minutes == 0) {
timestring = ngettext("%d hour remaining", "%d hours remaining", hours).format(hours);
timestring = Gettext.ngettext("%d hour remaining", "%d hours remaining", hours).format(hours);
} else {
/* TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining" */
let template = _("%d %s %d %s remaining");
timestring = template.format (hours, ngettext("hour", "hours", hours), minutes, ngettext("minute", "minutes", minutes));
timestring = template.format (hours, Gettext.ngettext("hour", "hours", hours), minutes, Gettext.ngettext("minute", "minutes", minutes));
}
} else
timestring = ngettext("%d minute remaining", "%d minutes remaining", minutes).format(minutes);
timestring = Gettext.ngettext("%d minute remaining", "%d minutes remaining", minutes).format(minutes);
this._batteryItem.label.text = timestring;
}
this._primaryPercentage.text = Math.round(percentage) + '%';
@ -144,6 +146,7 @@ Indicator.prototype = {
this._deviceItems = [];
if (error) {
this._checkError(error);
this._deviceSep.actor.hide();
return;
}
@ -174,12 +177,21 @@ Indicator.prototype = {
this.setGIcon(gicon);
this.actor.show();
} else {
this._checkError(error);
this.menu.close();
this.actor.hide();
}
}));
this._readPrimaryDevice();
this._readOtherDevices();
},
_checkError: function(error) {
if (!this._restarted && error && error.message.match(/org\.freedesktop\.DBus\.Error\.(UnknownMethod|InvalidArgs)/)) {
Util.killall('gnome-power-manager');
Util.spawn(['gnome-power-manager']);
this._restarted = true;
}
}
};

View File

@ -9,11 +9,13 @@ const Gvc = imports.gi.Gvc;
const Signals = imports.signals;
const St = imports.gi.St;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const VOLUME_ADJUSTMENT_STEP = 0.05; /* Volume adjustment step in % */
const VOLUME_NOTIFY_ID = 1;
@ -62,7 +64,6 @@ Indicator.prototype = {
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Sound Settings"), function() {
Main.overview.hide();
let app = Shell.AppSystem.get_default().get_app('gnome-sound-panel.desktop');
app.activate(-1);
});

View File

@ -9,19 +9,30 @@ const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Tp = imports.gi.TelepathyGLib;
const UPowerGlib = imports.gi.UPowerGlib;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const GnomeSession = imports.misc.gnomeSession;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const ScreenSaver = imports.misc.screenSaver;
const Util = imports.misc.util;
const BUS_NAME = 'org.gnome.ScreenSaver';
const OBJECT_PATH = '/org/gnome/ScreenSaver';
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
const DISABLE_USER_SWITCH_KEY = 'disable-user-switching';
const DISABLE_LOCK_SCREEN_KEY = 'disable-lock-screen';
const DISABLE_LOG_OUT_KEY = 'disable-log-out';
const ScreenSaverInterface = {
name: BUS_NAME,
methods: [ { name: 'Lock', inSignature: '' } ]
};
let ScreenSaverProxy = DBus.makeProxyClass(ScreenSaverInterface);
// Adapted from gdm/gui/user-switch-applet/applet.c
//
// Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
@ -48,12 +59,11 @@ StatusMenuButton.prototype = {
this._presence = new GnomeSession.Presence();
this._presenceItems = {};
this._session = new GnomeSession.SessionManager();
this._haveShutdown = true;
this._account_mgr = Tp.AccountManager.dup()
this._upClient = new UPowerGlib.Client();
this._screenSaverProxy = new ScreenSaver.ScreenSaverProxy();
this._screenSaverProxy = new ScreenSaverProxy(DBus.session, BUS_NAME, OBJECT_PATH);
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._iconBox = new St.Bin();
@ -81,25 +91,12 @@ StatusMenuButton.prototype = {
Lang.bind(this, this._updateSwitchUser));
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
Lang.bind(this, this._updateLogout));
this._lockdownSettings.connect('changed::' + DISABLE_LOCK_SCREEN_KEY,
Lang.bind(this, this._updateLockScreen));
this._updateSwitchUser();
this._updateLogout();
this._updateLockScreen();
// Whether shutdown is available or not depends on both lockdown
// settings (disable-log-out) and Polkit policy - the latter doesn't
// notify, so we update the menu item each time the menu opens or
// the lockdown setting changes, which should be close enough.
this.menu.connect('open-state-changed', Lang.bind(this,
function(menu, open) {
if (open)
this._updateHaveShutdown();
}));
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
Lang.bind(this, this._updateHaveShutdown));
this._upClient.connect('notify::can-suspend', Lang.bind(this, this._updateSuspendOrPowerOff));
},
@ -116,25 +113,13 @@ StatusMenuButton.prototype = {
},
_updateSessionSeparator: function() {
let sessionItemsVisible = this._loginScreenItem.actor.visible ||
this._logoutItem.actor.visible ||
this._lockScreenItem.actor.visible;
let showSessionSeparator = sessionItemsVisible &&
this._suspendOrPowerOffItem.actor.visible;
let showSettingsSeparator = sessionItemsVisible ||
this._suspendOrPowerOffItem.actor.visible;
if (showSessionSeparator)
let showSeparator = this._loginScreenItem.actor.visible ||
this._logoutItem.actor.visible ||
this._lockScreenItem.actor.visible;
if (showSeparator)
this._sessionSeparator.actor.show();
else
this._sessionSeparator.actor.hide();
if (showSettingsSeparator)
this._settingsSeparator.actor.show();
else
this._settingsSeparator.actor.hide();
},
_updateSwitchUser: function() {
@ -164,34 +149,16 @@ StatusMenuButton.prototype = {
this._updateSessionSeparator();
},
_updateHaveShutdown: function() {
this._session.CanShutdownRemote(Lang.bind(this,
function(result, error) {
if (!error) {
this._haveShutdown = result;
this._updateSuspendOrPowerOff();
}
}));
},
_updateSuspendOrPowerOff: function() {
this._haveSuspend = this._upClient.get_can_suspend();
if (!this._suspendOrPowerOffItem)
return;
if (!this._haveShutdown && !this._haveSuspend)
this._suspendOrPowerOffItem.actor.hide();
else
this._suspendOrPowerOffItem.actor.show();
this._updateSessionSeparator();
// If we can't suspend show Power Off... instead
// and disable the alt key
if (!this._haveSuspend) {
this._suspendOrPowerOffItem.updateText(_("Power Off..."), null);
} else if (!this._haveShutdown) {
this._suspendOrPowerOffItem.updateText(_("Suspend"), null);
} else {
this._suspendOrPowerOffItem.updateText(_("Suspend"), _("Power Off..."));
}
@ -237,7 +204,6 @@ StatusMenuButton.prototype = {
item = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(item);
this._settingsSeparator = item;
item = new PopupMenu.PopupMenuItem(_("Lock Screen"));
item.connect('activate', Lang.bind(this, this._onLockScreenActivate));
@ -291,11 +257,8 @@ StatusMenuButton.prototype = {
_onLoginScreenActivate: function() {
Main.overview.hide();
// Ensure we only move to GDM after the screensaver has activated; in some
// OS configurations, the X server may block event processing on VT switch
this._screenSaverProxy.SetActiveRemote(true, Lang.bind(this, function() {
this._gdm.goto_login_session();
}));
this._gdm.goto_login_session();
this._onLockScreenActivate();
},
_onQuitSessionActivate: function() {
@ -308,8 +271,7 @@ StatusMenuButton.prototype = {
if (this._haveSuspend &&
this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
// Ensure we only suspend after the screensaver has activated
this._screenSaverProxy.SetActiveRemote(true, Lang.bind(this, function() {
this._screenSaverProxy.LockRemote(Lang.bind(this, function() {
this._upClient.suspend_sync(null);
}));
} else {

View File

@ -9,6 +9,9 @@ const Signals = imports.signals;
const St = imports.gi.St;
const Tpl = imports.gi.TelepathyLogger;
const Tp = imports.gi.TelepathyGLib;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const C_ = Gettext.pgettext;
const History = imports.misc.history;
const Main = imports.ui.main;
@ -24,9 +27,6 @@ const SCROLLBACK_IDLE_LENGTH = 5;
// See Source._displayPendingMessages
const SCROLLBACK_HISTORY_LINES = 10;
// See Notification._onEntryChanged
const COMPOSING_STOP_TIMEOUT = 5;
const NotificationDirection = {
SENT: 'chat-sent',
RECEIVED: 'chat-received'
@ -72,34 +72,27 @@ function Client() {
Client.prototype = {
_init : function() {
// channel path -> ChatSource
this._chatSources = {};
this._chatState = Tp.ChannelChatState.ACTIVE;
// channel path -> Source
this._sources = {};
// Set up a SimpleObserver, which will call _observeChannels whenever a
// channel matching its filters is detected.
// The second argument, recover, means _observeChannels will be run
// for any existing channel as well.
let dbus = Tp.DBusDaemon.dup();
this._tpClient = new Shell.TpClient({ 'dbus_daemon': dbus,
'name': 'GnomeShell',
'uniquify-name': true })
this._tpClient.set_observe_channels_func(
Lang.bind(this, this._observeChannels));
this._tpClient.set_approve_channels_func(
Lang.bind(this, this._approveChannels));
this._tpClient.set_handle_channels_func(
Lang.bind(this, this._handleChannels));
this._observer = Tp.SimpleObserver.new(dbus, true, 'GnomeShell', true,
Lang.bind(this, this._observeChannels));
// Allow other clients (such as Empathy) to pre-empt our channels if
// needed
this._tpClient.set_delegated_channels_callback(
Lang.bind(this, this._delegatedChannelsCb));
// We only care about single-user text-based chats
let props = {};
props[Tp.PROP_CHANNEL_CHANNEL_TYPE] = Tp.IFACE_CHANNEL_TYPE_TEXT;
props[Tp.PROP_CHANNEL_TARGET_HANDLE_TYPE] = Tp.HandleType.CONTACT;
this._observer.add_observer_filter(props);
try {
this._tpClient.register();
this._observer.register();
} catch (e) {
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
throw new Error('Couldn\'t register SimpleObserver. Error: \n' + e);
}
},
@ -112,7 +105,7 @@ Client.prototype = {
this._finishObserveChannels(account, conn, channels, context);
} else {
Shell.get_self_contact_features(conn,
contactFeatures,
contactFeatures.length, contactFeatures,
Lang.bind(this, function() {
this._finishObserveChannels(account, conn, channels, context);
}));
@ -132,216 +125,60 @@ Client.prototype = {
continue;
/* Request a TpContact */
Shell.get_tp_contacts(conn, [targetHandle],
contactFeatures,
Shell.get_tp_contacts(conn, 1, [targetHandle],
contactFeatures.length, contactFeatures,
Lang.bind(this, function (connection, contacts, failed) {
if (contacts.length < 1)
return;
/* We got the TpContact */
this._createChatSource(account, conn, channel, contacts[0]);
this._createSource(account, conn, channel, contacts[0]);
}), null);
}
context.accept();
},
_createChatSource: function(account, conn, channel, contact) {
if (this._chatSources[channel.get_object_path()])
_createSource: function(account, conn, channel, contact) {
if (this._sources[channel.get_object_path()])
return;
let source = new ChatSource(account, conn, channel, contact, this._tpClient);
let source = new Source(account, conn, channel, contact);
this._chatSources[channel.get_object_path()] = source;
this._sources[channel.get_object_path()] = source;
source.connect('destroy', Lang.bind(this,
function() {
if (this._tpClient.is_handling_channel(channel)) {
// The chat box has been destroyed so it can't
// handle the channel any more.
channel.close_async(function(src, result) {
channel.close_finish(result);
});
}
delete this._chatSources[channel.get_object_path()];
delete this._sources[channel.get_object_path()];
}));
},
_handleChannels: function(handler, account, conn, channels,
requests, user_action_time, context) {
this._handlingChannels(account, conn, channels);
context.accept();
},
_handlingChannels: function(account, conn, channels) {
let len = channels.length;
for (let i = 0; i < len; i++) {
let channel = channels[i];
// We can only handle text channel, so close any other channel
if (!(channel instanceof Tp.TextChannel)) {
channel.close_async(null);
continue;
}
if (this._tpClient.is_handling_channel(channel)) {
// We are already handling the channel, display the source
let source = this._chatSources[channel.get_object_path()];
if (source)
source.notify();
}
}
},
_displayRoomInvitation: function(conn, channel, dispatchOp, context) {
// We can only approve the rooms if we have been invited to it
let selfHandle = channel.group_get_self_handle();
if (selfHandle == 0) {
Shell.decline_dispatch_op(context, 'Not invited to the room');
return;
}
let [invited, inviter, reason, msg] = channel.group_get_local_pending_info(selfHandle);
if (!invited) {
Shell.decline_dispatch_op(context, 'Not invited to the room');
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
// system-users for now as Empathy does.
let source = new ApproverSource(dispatchOp, _("Invitation"), 'system-users');
Main.messageTray.add(source);
let notif = new RoomInviteNotification(source, dispatchOp, channel, contacts[0]);
source.notify(notif);
context.accept();
},
_approveChannels: function(approver, account, conn, channels,
dispatchOp, context) {
let channel = channels[0];
let chanType = channel.get_channel_type();
if (chanType == Tp.IFACE_CHANNEL_TYPE_TEXT)
this._approveTextChannel(account, conn, channel, dispatchOp, context);
else if (chanType == Tp.IFACE_CHANNEL_TYPE_STREAMED_MEDIA ||
chanType == 'org.freedesktop.Telepathy.Channel.Type.Call.DRAFT')
this._approveCall(account, conn, channel, dispatchOp, context);
},
_approveTextChannel: function(account, conn, channel, dispatchOp, context) {
let [targetHandle, targetHandleType] = channel.get_handle();
if (targetHandleType == Tp.HandleType.CONTACT) {
// Approve private text channels right away as we are going to handle it
dispatchOp.claim_with_async(this._tpClient,
Lang.bind(this, function(dispatchOp, result) {
try {
dispatchOp.claim_with_finish(result);
this._handlingChannels(account, conn, [channel]);
} catch (err) {
throw new Error('Failed to Claim channel: ' + err);
}}));
context.accept();
} else {
this._displayRoomInvitation(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));
},
_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 props = channel.borrow_immutable_properties();
if (props['org.freedesktop.Telepathy.Channel.Type.Call.DRAFT.InitialVideo'] ||
props[Tp.PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_VIDEO])
isVideo = true;
// We got the TpContact
let source = new ApproverSource(dispatchOp, _("Call"), isVideo ? 'camera-web' : 'audio-input-microphone');
Main.messageTray.add(source);
let notif = new AudioVideoNotification(source, dispatchOp, channel, contacts[0], isVideo);
source.notify(notif);
context.accept();
},
_delegatedChannelsCb: function(client, channels) {
// Nothing to do as we don't make a distinction between observed and
// handled channels.
}
};
function ChatSource(account, conn, channel, contact, client) {
this._init(account, conn, channel, contact, client);
function Source(account, conn, channel, contact) {
this._init(account, conn, channel, contact);
}
ChatSource.prototype = {
Source.prototype = {
__proto__: MessageTray.Source.prototype,
_init: function(account, conn, channel, contact, client) {
_init: function(account, conn, channel, contact) {
MessageTray.Source.prototype._init.call(this, contact.get_alias());
this.isChat = true;
this._account = account;
this._contact = contact;
this._client = client;
this._pendingMessages = [];
this._conn = conn;
this._channel = channel;
this._closedId = this._channel.connect('invalidated', Lang.bind(this, this._channelClosed));
this._notification = new ChatNotification(this);
this._notification = new Notification(this);
this._notification.setUrgency(MessageTray.Urgency.HIGH);
// We ack messages when the message box is collapsed if user has
// interacted with it before and so read the messages:
// - 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._sentId = this._channel.connect('message-sent', Lang.bind(this, this._messageSent));
this._receivedId = this._channel.connect('message-received', Lang.bind(this, this._messageReceived));
this._pendingId = this._channel.connect('pending-message-removed', Lang.bind(this, this._pendingRemoved));
this._setSummaryIcon(this.createNotificationIcon());
@ -358,7 +195,7 @@ ChatSource.prototype = {
_updateAlias: function() {
let oldAlias = this.title;
this.setTitle(this._contact.get_alias());
this.title = this._contact.get_alias();
this._notification.appendAliasChange(oldAlias, this.title);
this.pushNotification(this._notification);
},
@ -387,17 +224,13 @@ ChatSource.prototype = {
},
open: function(notification) {
if (this._client.is_handling_channel(this._channel)) {
// We are handling the channel, try to pass it to Empathy
this._client.delegate_channels_async([this._channel], global.get_current_time(), "", null);
}
else {
// We are not the handler, just ask to present the channel
let dbus = Tp.DBusDaemon.dup();
let cd = Tp.ChannelDispatcher.new(dbus);
let props = {};
props[Tp.PROP_CHANNEL_CHANNEL_TYPE] = Tp.IFACE_CHANNEL_TYPE_TEXT;
[props[Tp.PROP_CHANNEL_TARGET_HANDLE], props[Tp.PROP_CHANNEL_TARGET_HANDLE_TYPE]] = this._channel.get_handle();
cd.present_channel_async(this._channel, global.get_current_time(), null);
}
let req = Tp.AccountChannelRequest.new(this._account, props, global.get_current_time());
req.ensure_channel_async('', null, null);
},
_getLogMessages: function() {
@ -415,20 +248,7 @@ ChatSource.prototype = {
let logMessages = events.map(makeMessageFromTplEvent);
let pendingTpMessages = this._channel.get_pending_messages();
let pendingMessages = [];
for (let i = 0; i < pendingTpMessages.length; i++) {
let message = pendingTpMessages[i];
if (message.get_message_type() == Tp.ChannelTextMessageType.DELIVERY_REPORT)
continue;
pendingMessages.push(makeMessageFromTpMessage(message, NotificationDirection.RECEIVED));
this._pendingMessages.push(message);
}
this._updateCount();
let pendingMessages = pendingTpMessages.map(function (tpMessage) { return makeMessageFromTpMessage(tpMessage, NotificationDirection.RECEIVED); });
let showTimestamp = false;
@ -464,7 +284,6 @@ ChatSource.prototype = {
_channelClosed: function() {
this._channel.disconnect(this._closedId);
this._channel.disconnect(this._receivedId);
this._channel.disconnect(this._pendingId);
this._channel.disconnect(this._sentId);
this._contact.disconnect(this._notifyAliasId);
@ -474,17 +293,7 @@ ChatSource.prototype = {
this.destroy();
},
_updateCount: function() {
this._setCount(this._pendingMessages.length, this._pendingMessages.length > 0);
},
_messageReceived: function(channel, message) {
if (message.get_message_type() == Tp.ChannelTextMessageType.DELIVERY_REPORT)
return;
this._pendingMessages.push(message);
this._updateCount();
message = makeMessageFromTpMessage(message, NotificationDirection.RECEIVED);
this._notification.appendMessage(message);
this.notify();
@ -511,25 +320,10 @@ ChatSource.prototype = {
}
let msg = Tp.ClientMessage.new_text(type, text);
this._channel.send_message_async(msg, 0, Lang.bind(this, function (src, result) {
this._channel.send_message_finish(result);
}));
this._channel.send_message_async(msg, 0, null);
},
setChatState: function(state) {
// We don't want to send COMPOSING every time a letter is typed into
// the entry. We send the state only when it changes. Telepathy/Empathy
// might change it behind our back if the user is using both
// gnome-shell's entry and the Empathy conversation window. We could
// keep track of it with the ChatStateChanged signal but it is good
// enough right now.
if (state != this._chatState) {
this._chatState = state;
this._channel.set_chat_state_async(state, null);
}
},
_presenceChanged: function (contact, presence, status, message) {
_presenceChanged: function (contact, presence, type, status, message) {
let msg, shouldNotify, title;
if (this._presence == presence)
@ -562,53 +356,14 @@ ChatSource.prototype = {
this._notification.appendPresence(msg, shouldNotify);
if (shouldNotify)
this.notify();
},
_pendingRemoved: function(channel, message) {
let idx = this._pendingMessages.indexOf(message);
if (idx >= 0) {
this._pendingMessages.splice(idx, 1);
this._updateCount();
}
else
throw new Error('Message not in our pending list: ' + message);
},
_ackMessages: function() {
if (this._pendingMessages.length == 0)
return;
// Don't clear our messages here, tp-glib will send a
// 'pending-message-removed' for each one.
this._channel.ack_messages_async(this._pendingMessages, Lang.bind(this, function(src, result) {
this._channel.ack_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;
}
};
function ChatNotification(source) {
function Notification(source) {
this._init(source);
}
ChatNotification.prototype = {
Notification.prototype = {
__proto__: MessageTray.Notification.prototype,
_init: function(source) {
@ -618,7 +373,6 @@ ChatNotification.prototype = {
this._responseEntry = new St.Entry({ style_class: 'chat-response',
can_focus: true });
this._responseEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivated));
this._responseEntry.clutter_text.connect('text-changed', Lang.bind(this, this._onEntryChanged));
this.setActionArea(this._responseEntry);
this._oldMaxScrollAdjustment = 0;
@ -635,7 +389,6 @@ ChatNotification.prototype = {
this._history = [];
this._timestampTimeoutId = 0;
this._composingTimeoutId = 0;
},
/**
@ -671,35 +424,13 @@ ChatNotification.prototype = {
this._append(messageBody, styles, message.timestamp, noTimestamp);
},
_filterMessages: function() {
if (this._history.length < 1)
return;
let lastMessageTime = this._history[0].time;
let currentTime = (Date.now() / 1000);
// Keep the scrollback from growing too long. If the most
// recent message (before the one we just added) is within
// SCROLLBACK_RECENT_TIME, we will keep
// SCROLLBACK_RECENT_LENGTH previous messages. Otherwise
// we'll keep SCROLLBACK_IDLE_LENGTH messages.
let maxLength = (lastMessageTime < currentTime - SCROLLBACK_RECENT_TIME) ?
SCROLLBACK_IDLE_LENGTH : SCROLLBACK_RECENT_LENGTH;
let filteredHistory = this._history.filter(function(item) { return item.realMessage });
if (filteredHistory.length > maxLength) {
let lastMessageToKeep = filteredHistory[maxLength];
let expired = this._history.splice(this._history.indexOf(lastMessageToKeep));
for (let i = 0; i < expired.length; i++)
expired[i].actor.destroy();
}
},
_append: function(text, styles, timestamp, noTimestamp) {
let currentTime = (Date.now() / 1000);
if (!timestamp)
timestamp = currentTime;
let lastMessageTime = -1;
if (this._history.length > 0)
lastMessageTime = this._history[0].time;
// Reset the old message timeout
if (this._timestampTimeoutId)
@ -722,7 +453,23 @@ ChatNotification.prototype = {
Lang.bind(this, this.appendTimestamp));
}
this._filterMessages();
if (this._history.length > 1) {
// Keep the scrollback from growing too long. If the most
// recent message (before the one we just added) is within
// SCROLLBACK_RECENT_TIME, we will keep
// SCROLLBACK_RECENT_LENGTH previous messages. Otherwise
// we'll keep SCROLLBACK_IDLE_LENGTH messages.
let maxLength = (lastMessageTime < currentTime - SCROLLBACK_RECENT_TIME) ?
SCROLLBACK_IDLE_LENGTH : SCROLLBACK_RECENT_LENGTH;
let filteredHistory = this._history.filter(function(item) { return item.realMessage });
if (filteredHistory.length > maxLength) {
let lastMessageToKeep = filteredHistory[maxLength];
let expired = this._history.splice(this._history.indexOf(lastMessageToKeep));
for (let i = 0; i < expired.length; i++)
expired[i].actor.destroy();
}
}
},
_formatTimestamp: function(date) {
@ -764,9 +511,6 @@ ChatNotification.prototype = {
this._history.unshift({ actor: timeLabel, time: lastMessageTime, realMessage: false });
this._timestampTimeoutId = 0;
this._filterMessages();
return false;
},
@ -778,23 +522,21 @@ ChatNotification.prototype = {
let label = this.addBody(text, true);
label.add_style_class_name('chat-meta-message');
this._history.unshift({ actor: label, time: (Date.now() / 1000), realMessage: false});
this._filterMessages();
},
appendAliasChange: function(oldAlias, newAlias) {
oldAlias = GLib.markup_escape_text(oldAlias, -1);
newAlias = GLib.markup_escape_text(newAlias, -1);
// FIXME: uncomment this after 3.0 string freeze ends
/* Translators: this is the other person changing their old IM name to their new
IM name. */
let message = '<i>' + _("%s is now known as %s").format(oldAlias, newAlias) + '</i>';
let label = this.addBody(message, true);
label.add_style_class_name('chat-meta-message');
this._history.unshift({ actor: label, time: (Date.now() / 1000), realMessage: false });
this.update(newAlias, null, { customContent: true });
// oldAlias = GLib.markup_escape_text(oldAlias, -1);
// newAlias = GLib.markup_escape_text(newAlias, -1);
this._filterMessages();
// /* Translators: this is the other person changing their old IM name to their new
// IM name. */
// let message = '<i>' + _("%s is now known as %s").format(oldAlias, newAlias) + '</i>';
// let label = this.addBody(message, true);
// label.add_style_class_name('chat-meta-message');
// this._history.unshift({ actor: label, time: (Date.now() / 1000), realMessage: false });
// this.update(newAlias, null, { customContent: true });
},
_onEntryActivated: function() {
@ -808,166 +550,5 @@ ChatNotification.prototype = {
// see Source._messageSent
this._responseEntry.set_text('');
this.source.respond(text);
},
_composingStopTimeout: function() {
this._composingTimeoutId = 0;
this.source.setChatState(Tp.ChannelChatState.PAUSED);
return false;
},
_onEntryChanged: function() {
let text = this._responseEntry.get_text();
// If we're typing, we want to send COMPOSING.
// If we empty the entry, we want to send ACTIVE.
// If we've stopped typing for COMPOSING_STOP_TIMEOUT
// seconds, we want to send PAUSED.
// Remove composing timeout.
if (this._composingTimeoutId > 0) {
Mainloop.source_remove(this._composingTimeoutId);
this._composingTimeoutId = 0;
}
if (text != '') {
this.source.setChatState(Tp.ChannelChatState.COMPOSING);
this._composingTimeoutId = Mainloop.timeout_add_seconds(
COMPOSING_STOP_TIMEOUT,
Lang.bind(this, this._composingStopTimeout));
} else {
this.source.setChatState(Tp.ChannelChatState.ACTIVE);
}
}
};
function ApproverSource(dispatchOp, text, icon) {
this._init(dispatchOp, text, icon);
}
ApproverSource.prototype = {
__proto__: MessageTray.Source.prototype,
_init: function(dispatchOp, text, icon) {
MessageTray.Source.prototype._init.call(this, text);
this._icon = icon;
this._setSummaryIcon(this.createNotificationIcon());
this._dispatchOp = dispatchOp;
// Destroy the source if the channel dispatch operation is invalidated
// as we can't approve any more.
this._invalidId = dispatchOp.connect('invalidated',
Lang.bind(this, function(domain, code, msg) {
this.destroy();
}));
},
destroy: function() {
if (this._invalidId != 0) {
this._dispatchOp.disconnect(this._invalidId);
this._invalidId = 0;
}
MessageTray.Source.prototype.destroy.call(this);
},
createNotificationIcon: function() {
return new St.Icon({ icon_name: this._icon,
icon_type: St.IconType.FULLCOLOR,
icon_size: this.ICON_SIZE });
}
}
function RoomInviteNotification(source, dispatchOp, channel, inviter) {
this._init(source, dispatchOp, channel, inviter);
}
RoomInviteNotification.prototype = {
__proto__: MessageTray.Notification.prototype,
_init: function(source, dispatchOp, channel, inviter) {
MessageTray.Notification.prototype._init.call(this,
source,
/* translators: argument is a room name like
* room@jabber.org for example. */
_("Invitation to %s").format(channel.get_identifier()),
null,
{ customContent: true });
this.setResident(true);
/* translators: first argument is the name of a contact and the second
* one the name of a room. "Alice is inviting you to join room@jabber.org
* for example. */
this.addBody(_("%s is inviting you to join %s").format(inviter.get_alias(), channel.get_identifier()));
this.addButton('decline', _("Decline"));
this.addButton('accept', _("Accept"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
switch (action) {
case 'decline':
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE,
'', function(src, result) {
src.leave_channels_finish(result)});
break;
case 'accept':
dispatchOp.handle_with_time_async('', global.get_current_time(),
function(src, result) {
src.handle_with_time_finish(result)});
break;
}
this.destroy();
}));
}
};
// Audio Video
function AudioVideoNotification(source, dispatchOp, channel, contact, isVideo) {
this._init(source, dispatchOp, channel, contact, isVideo);
}
AudioVideoNotification.prototype = {
__proto__: MessageTray.Notification.prototype,
_init: function(source, dispatchOp, channel, contact, isVideo) {
let title = '';
if (isVideo)
/* translators: argument is a contact name like Alice for example. */
title = _("Video call from %s").format(contact.get_alias());
else
/* translators: argument is a contact name like Alice for example. */
title = _("Call from %s").format(contact.get_alias());
MessageTray.Notification.prototype._init.call(this,
source,
title,
null,
{ customContent: true });
this.setResident(true);
this.addButton('reject', _("Reject"));
this.addButton('answer', _("Answer"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
switch (action) {
case 'reject':
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE,
'', function(src, result) {
src.leave_channels_finish(result)});
break;
case 'answer':
dispatchOp.handle_with_time_async('', global.get_current_time(),
function(src, result) {
src.handle_with_time_finish(result)});
break;
}
this.destroy();
}));
}
};

View File

@ -8,6 +8,8 @@ const Signals = imports.signals;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Main = imports.ui.main;
const Search = imports.ui.search;
@ -141,19 +143,13 @@ SearchTab.prototype = {
'edit-find');
this._text.connect('text-changed', Lang.bind(this, this._onTextChanged));
this._text.connect('key-press-event', Lang.bind(this, function (o, e) {
// We can't connect to 'activate' here because search providers
// might want to do something with the modifiers in activateSelected.
let symbol = e.get_key_symbol();
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
if (this._searchTimeoutId > 0) {
Mainloop.source_remove(this._searchTimeoutId);
this._doSearch();
}
this._searchResults.activateSelected();
return true;
this._text.connect('activate', Lang.bind(this, function (se) {
if (this._searchTimeoutId > 0) {
Mainloop.source_remove(this._searchTimeoutId);
this._doSearch();
}
return false;
this._searchResults.activateSelected();
return true;
}));
this._entry.connect('notify::mapped', Lang.bind(this, this._onMapped));

View File

@ -2,6 +2,8 @@
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;

View File

@ -6,7 +6,6 @@ const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const AltTab = imports.ui.altTab;
const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup;
@ -23,7 +22,8 @@ function getDimShader() {
if (dimShader === null)
return null;
if (!dimShader) {
let source = Shell.get_file_contents_utf8_sync(global.datadir + '/shaders/dim-window.glsl');
let [success, source, length] = GLib.file_get_contents(global.datadir +
'/shaders/dim-window.glsl');
try {
let shader = new Clutter.Shader();
shader.set_fragment_source(source, -1);
@ -119,8 +119,6 @@ WindowManager.prototype = {
this.setKeybindingHandler('switch_to_workspace_down', Lang.bind(this, this._showWorkspaceSwitcher));
this.setKeybindingHandler('switch_windows', Lang.bind(this, this._startAppSwitcher));
this.setKeybindingHandler('switch_group', Lang.bind(this, this._startAppSwitcher));
this.setKeybindingHandler('switch_windows_backward', Lang.bind(this, this._startAppSwitcher));
this.setKeybindingHandler('switch_group_backward', Lang.bind(this, this._startAppSwitcher));
this.setKeybindingHandler('switch_panels', Lang.bind(this, this._startA11ySwitcher));
Main.overview.connect('showing', Lang.bind(this, function() {
@ -182,7 +180,7 @@ WindowManager.prototype = {
*/
this._minimizing.push(actor);
let primary = Main.layoutManager.primaryMonitor;
let primary = global.get_primary_monitor();
let xDest = primary.x;
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
xDest += primary.width;
@ -536,7 +534,7 @@ WindowManager.prototype = {
let tabPopup = new AltTab.AltTabPopup();
if (!tabPopup.show(backwards, binding))
if (!tabPopup.show(backwards, binding == 'switch_group'))
tabPopup.destroy();
},

View File

@ -1,7 +1,6 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const GConf = imports.gi.GConf;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
@ -28,8 +27,6 @@ const CLOSE_BUTTON_FADE_TIME = 0.1;
const DRAGGING_WINDOW_OPACITY = 100;
const BUTTON_LAYOUT_KEY = '/desktop/gnome/shell/windows/button_layout';
// Define a layout scheme for small window counts. For larger
// counts we fall back to an algorithm. We need more schemes here
// unless we have a really good algorithm.
@ -225,12 +222,8 @@ WindowClone.prototype = {
let [width, height] = this.actor.get_transformed_size();
let monitorIndex = this.metaWindow.get_monitor();
let monitor = Main.layoutManager.monitors[monitorIndex];
let availArea = new Meta.Rectangle({ x: monitor.x,
y: monitor.y,
width: monitor.width,
height: monitor.height });
if (monitorIndex == Main.layoutManager.primaryIndex) {
let availArea = global.get_monitors()[monitorIndex];
if (monitorIndex == global.get_primary_monitor_index()) {
availArea.y += Main.panel.actor.height;
availArea.height -= Main.panel.actor.height;
}
@ -312,21 +305,6 @@ WindowClone.prototype = {
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) {
let workspace = this._getWorkspaceActor();
return workspace.handleDragOver(source, actor, x, y, time);
},
acceptDrop : function(source, actor, x, y, time) {
let workspace = this._getWorkspaceActor();
workspace.acceptDrop(source, actor, x, y, time);
},
_onDragCancelled : function (draggable, time) {
this.emit('drag-cancelled');
},
@ -419,8 +397,6 @@ WindowOverlay.prototype = {
show: function() {
this._hidden = false;
if (this._windowClone.actor.has_pointer)
this.closeButton.show();
this.title.show();
},
@ -457,20 +433,9 @@ WindowOverlay.prototype = {
let button = this.closeButton;
let title = this.title;
let gconf = GConf.Client.get_default();
let layout = gconf.get_string(BUTTON_LAYOUT_KEY);
let rtl = St.Widget.get_default_direction() == St.TextDirection.RTL;
let split = layout.split(":");
let side;
if (split[0].indexOf("close") > -1)
side = rtl ? St.Side.RIGHT : St.Side.LEFT;
else
side = rtl ? St.Side.LEFT : St.Side.RIGHT;
let buttonX;
let buttonY = cloneY - (button.height - button._overlap);
if (side == St.Side.LEFT)
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
buttonX = cloneX - (button.width - button._overlap);
else
buttonX = cloneX + (cloneWidth - button._overlap);
@ -597,7 +562,7 @@ Workspace.prototype = {
this._height = 0;
this.monitorIndex = monitorIndex;
this._monitor = Main.layoutManager.monitors[this.monitorIndex];
this._monitor = global.get_monitors()[this.monitorIndex];
this._windowOverlaysGroup = new Clutter.Group();
// Without this the drop area will be overlapped.
this._windowOverlaysGroup.set_size(0, 0);
@ -652,7 +617,6 @@ Workspace.prototype = {
function () {
this._dropRect.set_position(x, y);
this._dropRect.set_size(width, height);
this.positionWindows(WindowPositionFlags.ANIMATE);
return false;
}));
@ -675,6 +639,16 @@ Workspace.prototype = {
return this._windows.length == 0;
},
/**
* setReactive:
* @reactive: %true iff the workspace should be reactive
*
* Set the workspace (desktop) reactive
**/
setReactive: function(reactive) {
this.actor.reactive = reactive;
},
// Only use this for n <= 20 say
_factorial: function(n) {
let result = 1;

View File

@ -56,7 +56,7 @@ WorkspaceSwitcherPopup.prototype = {
_getPreferredHeight : function (actor, forWidth, alloc) {
let children = this._list.get_children();
let primary = Main.layoutManager.primaryMonitor;
let primary = global.get_primary_monitor();
let availHeight = primary.height;
availHeight -= Main.panel.actor.height;
@ -82,7 +82,7 @@ WorkspaceSwitcherPopup.prototype = {
},
_getPreferredWidth : function (actor, forHeight, alloc) {
let primary = Main.layoutManager.primaryMonitor;
let primary = global.get_primary_monitor();
this._childWidth = Math.round(this._childHeight * primary.width / primary.height);
alloc.min_size = this._childWidth;
@ -125,7 +125,7 @@ WorkspaceSwitcherPopup.prototype = {
},
_position: function() {
let primary = Main.layoutManager.primaryMonitor;
let primary = global.get_primary_monitor();
this._container.x = primary.x + Math.floor((primary.width - this._container.width) / 2);
this._container.y = primary.y + Main.panel.actor.height +
Math.floor(((primary.height - Main.panel.actor.height) - this._container.height) / 2);

View File

@ -146,7 +146,7 @@ function WorkspaceThumbnail(metaWorkspace) {
WorkspaceThumbnail.prototype = {
_init : function(metaWorkspace) {
this.metaWorkspace = metaWorkspace;
this.monitorIndex = Main.layoutManager.primaryIndex;
this.monitorIndex = global.get_primary_monitor_index();
this.actor = new St.Group({ reactive: true,
clip_to_allocation: true,
@ -170,7 +170,7 @@ WorkspaceThumbnail.prototype = {
this._background = new Clutter.Clone({ source: global.background_actor });
this._contents.add_actor(this._background);
let monitor = Main.layoutManager.primaryMonitor;
let monitor = global.get_primary_monitor();
this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height);
let windows = global.get_window_actors().filter(this._isMyWindow, this);
@ -178,11 +178,6 @@ WorkspaceThumbnail.prototype = {
// Create clones for windows that should be visible in the Overview
this._windows = [];
for (let i = 0; i < windows.length; i++) {
windows[i].meta_window._minimizedChangedId =
windows[i].meta_window.connect('notify::minimized',
Lang.bind(this,
this._updateMinimized));
if (this._isOverviewWindow(windows[i])) {
this._addWindowClone(windows[i]);
}
@ -262,18 +257,11 @@ WorkspaceThumbnail.prototype = {
return;
// Check if window still should be here
if (win && this._isMyWindow(win) && this._isOverviewWindow(win))
if (win && this._isMyWindow(win))
return;
let clone = this._windows[index];
this._windows.splice(index, 1);
if (win && this._isOverviewWindow(win)) {
if (metaWin._minimizedChangedId) {
metaWin.disconnect(metaWin._minimizedChangedId);
delete metaWin._minimizedChangedId;
}
}
clone.destroy();
},
@ -302,11 +290,6 @@ WorkspaceThumbnail.prototype = {
if (this._lookupIndex (metaWin) != -1)
return;
if (!metaWin._minimizedChangedId)
metaWin._minimizedChangedId = metaWin.connect('notify::minimized',
Lang.bind(this,
this._updateMinimized));
if (!this._isMyWindow(win) || !this._isOverviewWindow(win))
return;
@ -333,13 +316,6 @@ WorkspaceThumbnail.prototype = {
}
},
_updateMinimized: function(metaWin) {
if (metaWin.minimized)
this._doRemoveWindow(metaWin);
else
this._doAddWindow(metaWin);
},
destroy : function() {
this.actor.destroy();
},
@ -350,14 +326,6 @@ WorkspaceThumbnail.prototype = {
global.screen.disconnect(this._windowEnteredMonitorId);
global.screen.disconnect(this._windowLeftMonitorId);
for (let i = 0; i < this._windows.length; i++) {
let metaWin = this._windows[i].metaWindow;
if (metaWin._minimizedChangedId) {
metaWin.disconnect(metaWin._minimizedChangedId);
delete metaWin._minimizedChangedId;
}
}
this._windows = [];
this.actor = null;
},
@ -371,8 +339,7 @@ WorkspaceThumbnail.prototype = {
// Tests if @win should be shown in the Overview
_isOverviewWindow : function (win) {
let tracker = Shell.WindowTracker.get_default();
return tracker.is_window_interesting(win.get_meta_window()) &&
win.get_meta_window().showing_on_its_workspace();
return tracker.is_window_interesting(win.get_meta_window());
},
// Create a clone of a (non-desktop) window and add it to the window list
@ -528,7 +495,7 @@ ThumbnailsBox.prototype = {
// The "porthole" is the portion of the screen that we show in the workspaces
let panelHeight = Main.panel.actor.height;
let monitor = Main.layoutManager.primaryMonitor;
let monitor = global.get_primary_monitor();
this._porthole = {
x: monitor.x,
y: monitor.y + panelHeight,

View File

@ -7,6 +7,8 @@ const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Signals = imports.signals;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
@ -49,12 +51,9 @@ WorkspacesView.prototype = {
this._height = 0;
this._x = 0;
this._y = 0;
this._clipX = 0;
this._clipY = 0;
this._clipWidth = 0;
this._clipHeight = 0;
this._workspaceRatioSpacing = 0;
this._spacing = 0;
this._lostWorkspaces = [];
this._animating = false; // tweening
this._scrolling = false; // swipe-scrolling
this._animatingScroll = false; // programatically updating the adjustment
@ -70,10 +69,10 @@ WorkspacesView.prototype = {
this._workspaces[activeWorkspaceIndex].actor.raise_top();
this._extraWorkspaces = [];
let monitors = Main.layoutManager.monitors;
let monitors = global.get_monitors();
let m = 0;
for (let i = 0; i < monitors.length; i++) {
if (i == Main.layoutManager.primaryIndex)
if (i == global.get_primary_monitor_index())
continue;
let ws = new Workspace.Workspace(null, i);
this._extraWorkspaces[m++] = ws;
@ -96,8 +95,7 @@ WorkspacesView.prototype = {
this._overviewShownId =
Main.overview.connect('shown',
Lang.bind(this, function() {
this.actor.set_clip(this._clipX, this._clipY,
this._clipWidth, this._clipHeight);
this.actor.set_clip(this._x, this._y, this._width, this._height);
}));
this._scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
@ -141,13 +139,6 @@ WorkspacesView.prototype = {
this._workspaces[i].setGeometry(x, y, width, height);
},
setClipRect: function(x, y, width, height) {
this._clipX = x;
this._clipY = y;
this._clipWidth = width;
this._clipHeight = height;
},
_lookupWorkspaceForMetaWindow: function (metaWindow) {
for (let i = 0; i < this._workspaces.length; i++) {
if (this._workspaces[i].containsMetaWindow(metaWindow))
@ -161,10 +152,6 @@ WorkspacesView.prototype = {
return this._workspaces[active];
},
getWorkspaceByIndex: function(index) {
return this._workspaces[index];
},
hide: function() {
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
let activeWorkspace = this._workspaces[activeWorkspaceIndex];
@ -239,6 +226,27 @@ WorkspacesView.prototype = {
this._updateVisibility();
}
}
for (let l = 0; l < this._lostWorkspaces.length; l++) {
let workspace = this._lostWorkspaces[l];
Tweener.removeTweens(workspace.actor);
workspace.actor.show();
workspace.hideWindowsOverlays();
if (showAnimation) {
Tweener.addTween(workspace.actor,
{ y: workspace.x,
time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
this._cleanWorkspaces)
});
} else {
this._cleanWorkspaces();
}
}
},
_updateVisibility: function() {
@ -259,6 +267,17 @@ WorkspacesView.prototype = {
}
},
_cleanWorkspaces: function() {
if (this._lostWorkspaces.length == 0)
return;
for (let l = 0; l < this._lostWorkspaces.length; l++)
this._lostWorkspaces[l].destroy();
this._lostWorkspaces = [];
this._updateWorkspaceActors(false);
},
_updateScrollAdjustment: function(index, showAnimation) {
if (this._scrolling)
return;
@ -281,9 +300,12 @@ WorkspacesView.prototype = {
}
},
updateWorkspaces: function(oldNumWorkspaces, newNumWorkspaces) {
updateWorkspaces: function(oldNumWorkspaces, newNumWorkspaces, lostWorkspaces) {
let active = global.screen.get_active_workspace_index();
for (let l = 0; l < lostWorkspaces.length; l++)
lostWorkspaces[l].disconnectAll();
Tweener.addTween(this._scrollAdjustment,
{ upper: newNumWorkspaces,
time: WORKSPACE_SWITCH_TIME,
@ -291,13 +313,12 @@ WorkspacesView.prototype = {
});
if (newNumWorkspaces > oldNumWorkspaces) {
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
this._workspaces[w].setGeometry(this._x, this._y,
this._width, this._height);
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++)
this.actor.add_actor(this._workspaces[w].actor);
}
this._updateWorkspaceActors(false);
} else {
this._lostWorkspaces = lostWorkspaces;
}
this._scrollToActive(true);
@ -383,7 +404,7 @@ WorkspacesView.prototype = {
this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
}
let primary = Main.layoutManager.primaryMonitor;
let primary = global.get_primary_monitor();
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
let topWorkspace, bottomWorkspace;
@ -449,7 +470,7 @@ WorkspacesView.prototype = {
Mainloop.source_remove(this._timeoutId);
this._timeoutId = 0;
}
DND.removeDragMonitor(this._dragMonitor);
DND.removeMonitor(this._dragMonitor);
this._inDrag = false;
for (let i = 0; i < this._workspaces.length; i++)
@ -550,8 +571,8 @@ WorkspacesDisplay.prototype = {
controls.connect('scroll-event',
Lang.bind(this, this._onScrollEvent));
this._monitorIndex = Main.layoutManager.primaryIndex;
this._monitor = Main.layoutManager.monitors[this._monitorIndex];
this._monitorIndex = global.get_primary_monitor_index();
this._monitor = global.get_monitors()[this._monitorIndex];
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
controls.add_actor(this._thumbnailsBox.actor);
@ -567,10 +588,7 @@ WorkspacesDisplay.prototype = {
this._updateAlwaysZoom();
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom));
global.screen.connect('notify::n-workspaces',
Lang.bind(this, this._workspacesChanged));
global.screen.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom));
Main.xdndHandler.connect('drag-begin', Lang.bind(this, function(){
this._alwaysZoomOut = true;
}));
@ -580,6 +598,7 @@ WorkspacesDisplay.prototype = {
this._updateAlwaysZoom();
}));
this._nWorkspacesNotifyId = 0;
this._switchWorkspaceNotifyId = 0;
this._itemDragBeginId = 0;
@ -609,6 +628,10 @@ WorkspacesDisplay.prototype = {
this.workspacesView = new WorkspacesView(this._workspaces);
this._updateWorkspacesGeometry();
this._nWorkspacesNotifyId =
global.screen.connect('notify::n-workspaces',
Lang.bind(this, this._workspacesChanged));
this._restackedNotifyId =
global.screen.connect('restacked',
Lang.bind(this, this._onRestacked));
@ -639,6 +662,10 @@ WorkspacesDisplay.prototype = {
this._controls.hide();
this._thumbnailsBox.hide();
if (this._nWorkspacesNotifyId > 0) {
global.screen.disconnect(this._nWorkspacesNotifyId);
this._nWorkspacesNotifyId = 0;
}
if (this._restackedNotifyId > 0){
global.screen.disconnect(this._restackedNotifyId);
this._restackedNotifyId = 0;
@ -687,15 +714,10 @@ WorkspacesDisplay.prototype = {
},
_updateAlwaysZoom: function() {
// Always show the pager if workspaces are actually used,
// e.g. there are windows on more than one
this._alwaysZoomOut = global.screen.n_workspaces > 2;
this._alwaysZoomOut = false;
if (this._alwaysZoomOut)
return;
let monitors = Main.layoutManager.monitors;
let primary = Main.layoutManager.primaryMonitor;
let monitors = global.get_monitors();
let primary = global.get_primary_monitor();
/* Look for any monitor to the right of the primary, if there is
* one, we always keep zoom out, otherwise its hard to reach
@ -763,13 +785,6 @@ WorkspacesDisplay.prototype = {
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
let clipWidth = width - controlsVisible;
let clipHeight = (fullHeight / fullWidth) * clipWidth;
let clipX = rtl ? x + controlsVisible : x;
let clipY = y + (fullHeight - clipHeight) / 2;
this.workspacesView.setClipRect(clipX, clipY, clipWidth, clipHeight);
if (this._zoomOut) {
width -= controlsNatural;
if (rtl)
@ -808,12 +823,6 @@ WorkspacesDisplay.prototype = {
if (oldNumWorkspaces == newNumWorkspaces)
return;
this._updateAlwaysZoom();
this._updateZoom();
if (this.workspacesView == null)
return;
let lostWorkspaces = [];
if (newNumWorkspaces > oldNumWorkspaces) {
// Assume workspaces are only added at the end
@ -839,23 +848,24 @@ WorkspacesDisplay.prototype = {
lostWorkspaces = this._workspaces.splice(removedIndex,
removedNum);
for (let l = 0; l < lostWorkspaces.length; l++) {
lostWorkspaces[l].disconnectAll();
lostWorkspaces[l].destroy();
}
// Don't let the user try to select this workspace as it's
// making its exit.
for (let l = 0; l < lostWorkspaces.length; l++)
lostWorkspaces[l].setReactive(false);
this._thumbnailsBox.removeThumbmails(removedIndex, removedNum);
}
this.workspacesView.updateWorkspaces(oldNumWorkspaces,
newNumWorkspaces);
newNumWorkspaces,
lostWorkspaces);
},
_updateZoom : function() {
if (Main.overview.animationInProgress)
return;
let shouldZoom = this._alwaysZoomOut || this._controls.hover;
let shouldZoom = this._alwaysZoomOut || this._controls.hover || (this._inDrag && !this._cancelledDrag);
if (shouldZoom != this._zoomOut) {
this._zoomOut = shouldZoom;
this._updateWorkspacesGeometry();
@ -879,22 +889,12 @@ WorkspacesDisplay.prototype = {
_dragBegin: function() {
this._inDrag = true;
this._cancelledDrag = false;
this._dragMonitor = {
dragMotion: Lang.bind(this, this._onDragMotion)
};
DND.addDragMonitor(this._dragMonitor);
this._updateZoom();
},
_dragCancelled: function() {
this._cancelledDrag = true;
DND.removeDragMonitor(this._dragMonitor);
},
_onDragMotion: function(dragEvent) {
let controlsHovered = this._controls.contains(dragEvent.targetActor);
this._controls.set_hover(controlsHovered);
return DND.DragMotionResult.CONTINUE;
this._updateZoom();
},
_dragEnd: function() {

View File

@ -36,48 +36,53 @@ visually attractive and easy to use experience.
.SH OPTIONS
.TP
.B \-\-replace
Replace the running window manager
.B \-r, \-\-replace
Replace the running metacity/gnome-panel
.br
.TP
.B \-\-sm-disable
Disable connection to the session manager
.B \-v, \-\-verbose
Shows details about the results of running `gnome-shell'.
.br
.TP
.B \-\-sm-client-id=ID
Specify session management ID
.B \-g, \-\-debug
Run under a debugger
.br
.TP
.B \-\-sm-save-file=FILE
Initialize session from savefile
.br
.TP
.B \-\-screen=SCREEN
X screen to use
.br
.TP
.B \-d, \-\-display=DISPLAY
X display to use
.B \-\-debug\-command
Command to use for debugging (defaults to 'gdb \-\-args')
.br
.TP
.B \-\-sync
Make X calls synchronous
.br
Make X calls synchronously, useful when debugging down X errors
.br
.TP
.B \-\-version
Print version and exit
.B \-\-xephyr
Run a debugging instance inside Xephyr
.br
.TP
.B \-\-help
Display help and exit
.B \-\-geometry
Specify Xephyr screen geometry
.br
.TP
.B \-w, \-\-wide
Use widescreen (1280x800) with Xephyr
.br
.TP
.B \-\-create\-extension
Create a new GNOME Shell extension
.TP
.B \-\-eval\-file
Evaluate the contents of the given JavaScript file
.br
.SH BUGS

View File

@ -1,18 +1,14 @@
af
an
ar
be
bg
bn
bn_IN
ca
ca@valencia
cs
da
de
el
en_GB
eo
es
et
eu
@ -48,7 +44,6 @@ sr
sr@latin
sv
ta
te
th
tr
ug

1161
po/an.po

File diff suppressed because it is too large Load Diff

1217
po/be.po

File diff suppressed because it is too large Load Diff

553
po/ca.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

622
po/de.po

File diff suppressed because it is too large Load Diff

1222
po/eo.po

File diff suppressed because it is too large Load Diff

635
po/es.po

File diff suppressed because it is too large Load Diff

174
po/fa.po
View File

@ -7,10 +7,9 @@
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&keywords=I18N+L10N&component=general\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2011-04-15 18:20+0000\n"
"PO-Revision-Date: 2011-04-06 23:37+0330\n"
"PO-Revision-Date: 2011-05-17 00:53+0330\n"
"Last-Translator: Arash Mousavi <mousavi.arash@gmail.com>\n"
"Language-Team: Persian <translate@ifsug.org>\n"
"Language: fa\n"
@ -31,18 +30,12 @@ msgid "Window management and application launching"
msgstr "مدیریت پنجره‌ها و اجرا کننده‌ی برنامه‌ها"
#: ../data/org.gnome.shell.gschema.xml.in.h:1
msgid ""
"Allows access to internal debugging and monitoring tools using the Alt-F2 "
"dialog."
msgstr ""
"اجازه دسترسی به ابزارهای اشکال‌زدا و پایشگر داخلی با استفاده از محاوره‌ی Alt-"
"F2."
msgid "Allows access to internal debugging and monitoring tools using the Alt-F2 dialog."
msgstr "اجازه دسترسی به ابزارهای اشکال‌زدا و پایشگر داخلی با استفاده از محاوره‌ی Alt-F2."
#: ../data/org.gnome.shell.gschema.xml.in.h:2
msgid "Enable internal tools useful for developers and testers from Alt-F2"
msgstr ""
"فعال کردن ابزارهای داخلی مفید برای توسعه دهندگان و آزمایش کنندگان از طریق "
"Alt-F2"
msgstr "فعال کردن ابزارهای داخلی مفید برای توسعه دهندگان و آزمایش کنندگان از طریق Alt-F2"
#: ../data/org.gnome.shell.gschema.xml.in.h:3
msgid "File extension used for storing the screencast"
@ -53,12 +46,8 @@ msgid "Framerate used for recording screencasts."
msgstr "سرعت فریم استفاده شده در تصویربرداری از صفحه‌نمایش."
#: ../data/org.gnome.shell.gschema.xml.in.h:5
msgid ""
"GNOME Shell extensions have a uuid property; this key lists extensions which "
"should not be loaded."
msgstr ""
"افزونه‌های پوسته‌ی گنوم مشخصه‌ی uuid دارند؛ این کلید افزونه‌هایی که نباید بار "
"شوند را فهرست می‌کند."
msgid "GNOME Shell extensions have a uuid property; this key lists extensions which should not be loaded."
msgstr "افزونه‌های پوسته‌ی گنوم مشخصه‌ی uuid دارند؛ این کلید افزونه‌هایی که نباید بار شوند را فهرست می‌کند."
#: ../data/org.gnome.shell.gschema.xml.in.h:6
msgid "History for command (Alt-F2) dialog"
@ -86,17 +75,7 @@ msgstr "فهرست شناسه‌های پرونده‌ی رومیزی برای
#: ../data/org.gnome.shell.gschema.xml.in.h:13
#, no-c-format
msgid ""
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
"used for gst-launch. The pipeline should have an unconnected sink pad where "
"the recorded video is recorded. It will normally have a unconnected source "
"pad; output from that pad will be written into the output file. However the "
"pipeline can also take care of its own output - this might be used to send "
"the output to an icecast server via shout2send or similar. When unset or set "
"to an empty value, the default pipeline will be used. This is currently "
"'videorate ! vp8enc quality=10 speed=2 threads=%T ! queue ! webmmux' and "
"records to WEBM using the VP8 codec. %T is used as a placeholder for a guess "
"at the optimal thread count on the system."
msgid "Sets the GStreamer pipeline used to encode recordings. It follows the syntax used for gst-launch. The pipeline should have an unconnected sink pad where the recorded video is recorded. It will normally have a unconnected source pad; output from that pad will be written into the output file. However the pipeline can also take care of its own output - this might be used to send the output to an icecast server via shout2send or similar. When unset or set to an empty value, the default pipeline will be used. This is currently 'videorate ! vp8enc quality=10 speed=2 threads=%T ! queue ! webmmux' and records to WEBM using the VP8 codec. %T is used as a placeholder for a guess at the optimal thread count on the system."
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:14
@ -112,45 +91,24 @@ msgid "Show time with seconds"
msgstr "نمایش ساعت همراه با ثانیه"
#: ../data/org.gnome.shell.gschema.xml.in.h:17
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
msgid "The applications corresponding to these identifiers will be displayed in the favorites area."
msgstr "برنامه‌های مشابه این شناسه‌ها در قسمت مورد پسندها نمایش داده می‌شود."
#: ../data/org.gnome.shell.gschema.xml.in.h:18
msgid ""
"The filename for recorded screencasts will be a unique filename based on the "
"current date, and use this extension. It should be changed when recording to "
"a different container format."
msgstr ""
"نام پرونده‌ی ضبط شده برای تصویربرداری از صفحه‌نمایش یکتا و براساس تاریخ جاری "
"خواهد بود و از این افزونه استفاده خواهد کرد. اگر در زمان ضبط از قالب دیگری "
"استفاده کنید باید تغییر کند."
msgid "The filename for recorded screencasts will be a unique filename based on the current date, and use this extension. It should be changed when recording to a different container format."
msgstr "نام پرونده‌ی ضبط شده برای تصویربرداری از صفحه‌نمایش یکتا و براساس تاریخ جاری خواهد بود و از این افزونه استفاده خواهد کرد. اگر در زمان ضبط از قالب دیگری استفاده کنید باید تغییر کند."
#: ../data/org.gnome.shell.gschema.xml.in.h:19
msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames-per-second."
msgstr ""
"سرعت فریم حاصل از تصویربرداری از صفحه نمایش با استفاده از ضبط کننده نمایشگر "
"پوسته‌ی گنوم بر اساس فریم بر ثانیه"
msgid "The framerate of the resulting screencast recordered by GNOME Shell's screencast recorder in frames-per-second."
msgstr "سرعت فریم حاصل از تصویربرداری از صفحه نمایش با استفاده از ضبط کننده نمایشگر پوسته‌ی گنوم بر اساس فریم بر ثانیه"
#: ../data/org.gnome.shell.gschema.xml.in.h:20
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "مجرای ارتباطی gstreamer برای کدگذاری تصویربرداری از صفحه نمایش"
#: ../data/org.gnome.shell.gschema.xml.in.h:21
msgid ""
"The shell normally monitors active applications in order to present the most "
"used ones (e.g. in launchers). While this data will be kept private, you may "
"want to disable this for privacy reasons. Please note that doing so won't "
"remove already saved data."
msgstr ""
"پوسته گنوم در حالت عادی برنامه‌های فعال را جهت ارائه برنامه‌های بیشتر استفاده "
"شده پایش می کند. (برای مثال در اجرا کننده‌ها). با اینکه که این اطلاعات به "
"صورت خصوصی نگاه‌داری می‌شود، ممکن است شما بخواهید این امکان را به دلایل امنیتی "
"غیرفعال کنید. لطفا توجه کنید این کار باعث پاک شدن اطلاعاتی که تاکنون ذخیره "
"شده‌اند نمی‌شود."
msgid "The shell normally monitors active applications in order to present the most used ones (e.g. in launchers). While this data will be kept private, you may want to disable this for privacy reasons. Please note that doing so won't remove already saved data."
msgstr "پوسته گنوم در حالت عادی برنامه‌های فعال را جهت ارائه برنامه‌های بیشتر استفاده شده پایش می کند. (برای مثال در اجرا کننده‌ها). با اینکه که این اطلاعات به صورت خصوصی نگاه‌داری می‌شود، ممکن است شما بخواهید این امکان را به دلایل امنیتی غیرفعال کنید. لطفا توجه کنید این کار باعث پاک شدن اطلاعاتی که تاکنون ذخیره شده‌اند نمی‌شود."
#: ../data/org.gnome.shell.gschema.xml.in.h:22
msgid "Uuids of extensions to disable"
@ -158,8 +116,7 @@ msgstr "شناسه‌های Uuid مربوط به افزونه‌ها که غیر
#: ../data/org.gnome.shell.gschema.xml.in.h:23
msgid "Whether to collect stats about applications usage"
msgstr ""
"اینکه اطلاعات برنامه‌ها درباره‌ی میزان استفاده از منابع جمع‌آوری شود یا خیر"
msgstr "اینکه اطلاعات برنامه‌ها درباره‌ی میزان استفاده از منابع جمع‌آوری شود یا خیر"
#: ../data/org.gnome.shell.gschema.xml.in.h:24
msgid "disabled OpenSearch providers"
@ -227,13 +184,13 @@ msgstr "تمام روز"
#: ../js/ui/calendar.js:71
msgctxt "event list time"
msgid "%H:%M"
msgstr "%OH:%OM"
msgstr "%H:%M"
#. Transators: Shown in calendar event list, if 12h format
#: ../js/ui/calendar.js:78
msgctxt "event list time"
msgid "%l:%M %p"
msgstr "%OI:%OM"
msgstr "%l:%M %p"
#. Translators: Calendar grid abbreviation for Sunday.
#. *
@ -334,16 +291,18 @@ msgid "Nothing Scheduled"
msgstr "بدون برنامه‌ریزی"
#. Translators: Shown on calendar heading when selected day occurs on current year
#: ../js/ui/calendar.js:720 ../js/ui/telepathyClient.js:492
#: ../js/ui/calendar.js:720
#: ../js/ui/telepathyClient.js:492
msgctxt "calendar heading"
msgid "%A, %B %d"
msgstr "%A %Od %B "
msgstr "%A, %B %d"
#. Translators: Shown on calendar heading when selected day occurs on different year
#: ../js/ui/calendar.js:723 ../js/ui/telepathyClient.js:495
#: ../js/ui/calendar.js:723
#: ../js/ui/telepathyClient.js:495
msgctxt "calendar heading"
msgid "%A, %B %d, %Y"
msgstr "%A %Od %B %Oy"
msgstr "%A, %B %d, %Y"
#: ../js/ui/calendar.js:733
msgid "Today"
@ -361,7 +320,8 @@ msgstr "این هفته"
msgid "Next week"
msgstr "هفته آینده"
#: ../js/ui/dash.js:174 ../js/ui/messageTray.js:1037
#: ../js/ui/dash.js:174
#: ../js/ui/messageTray.js:1037
msgid "Remove"
msgstr "حذف"
@ -377,48 +337,48 @@ msgstr "بازکردن تقویم"
#. in 24-hour mode.
#: ../js/ui/dateMenu.js:164
msgid "%a %b %e, %R:%S"
msgstr "%a %Od %b %OH:%OM:%OS"
msgstr "%a %b %e, %R:%S"
#: ../js/ui/dateMenu.js:165
msgid "%a %b %e, %R"
msgstr "%a %Od %b %OH:%OM"
msgstr "%a %b %e, %R"
#. Translators: This is the time format without date used
#. in 24-hour mode.
#: ../js/ui/dateMenu.js:169
msgid "%a %R:%S"
msgstr "%a %OH:%OM:%OS"
msgstr "%a %R:%S"
#: ../js/ui/dateMenu.js:170
msgid "%a %R"
msgstr "%a %OH:%OM"
msgstr "%a %R"
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/dateMenu.js:177
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a Od% %b %OH:%OM:%OS"
msgstr "%a %b %e, %l:%M:%S %p"
#: ../js/ui/dateMenu.js:178
msgid "%a %b %e, %l:%M %p"
msgstr "%a %Od %b %OH:%OM"
msgstr "%a %b %e, %l:%M %p"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/dateMenu.js:182
msgid "%a %l:%M:%S %p"
msgstr "%a %OH:%OM:%OS"
msgstr "%a %l:%M:%S %p"
#: ../js/ui/dateMenu.js:183
msgid "%a %l:%M %p"
msgstr "%a %OH:%OM"
msgstr "%a %l:%M %p"
#. Translators: This is the date format to use when the calendar popup is
#. * shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
#.
#: ../js/ui/dateMenu.js:194
msgid "%A %B %e, %Y"
msgstr "%A %Od %B"
msgstr "%A %B %e, %Y"
#: ../js/ui/docDisplay.js:19
msgid "RECENT ITEMS"
@ -429,14 +389,14 @@ msgstr "موارد اخیر"
msgid "Log Out %s"
msgstr "خروج از %s"
#: ../js/ui/endSessionDialog.js:64 ../js/ui/endSessionDialog.js:70
#: ../js/ui/endSessionDialog.js:64
#: ../js/ui/endSessionDialog.js:70
msgid "Log Out"
msgstr "خروج از سیستم"
#: ../js/ui/endSessionDialog.js:65
msgid "Click Log Out to quit these applications and log out of the system."
msgstr ""
"بر روی خروج از سیستم کلیک کنید تا از این برنامه‌ها خارج و از سیستم خارج شوید."
msgstr "بر روی خروج از سیستم کلیک کنید تا از این برنامه‌ها خارج و از سیستم خارج شوید."
#: ../js/ui/endSessionDialog.js:66
#, c-format
@ -452,7 +412,8 @@ msgstr "شما در مدت %Id ثانیه به طور خودکار از سیست
msgid "Logging out of the system."
msgstr "درحال خروج از سیستم."
#: ../js/ui/endSessionDialog.js:75 ../js/ui/endSessionDialog.js:82
#: ../js/ui/endSessionDialog.js:75
#: ../js/ui/endSessionDialog.js:82
msgid "Power Off"
msgstr "خاموش کردن"
@ -469,16 +430,15 @@ msgstr "سیستم در مدت %Id ثانیه به طور خودکار خامو
msgid "Powering off the system."
msgstr "درحال خاموش کردن سیستم."
#: ../js/ui/endSessionDialog.js:80 ../js/ui/endSessionDialog.js:88
#: ../js/ui/endSessionDialog.js:80
#: ../js/ui/endSessionDialog.js:88
#: ../js/ui/endSessionDialog.js:93
msgid "Restart"
msgstr "راه‌اندازی مجدد"
#: ../js/ui/endSessionDialog.js:89
msgid "Click Restart to quit these applications and restart the system."
msgstr ""
"بر روی راه‌اندازی مجدد کلیک کنید تا از این برنامه‌ها خارج و سیستم مجددا "
"راه‌اندازی گردد."
msgstr "بر روی راه‌اندازی مجدد کلیک کنید تا از این برنامه‌ها خارج و سیستم مجددا راه‌اندازی گردد."
#: ../js/ui/endSessionDialog.js:90
#, c-format
@ -489,7 +449,8 @@ msgstr "سیستم در مدت %Id ثانیه به طور خودکار مجدد
msgid "Restarting the system."
msgstr "درحال راه‌اندازی مجدد سیستم."
#: ../js/ui/endSessionDialog.js:413 ../js/ui/polkitAuthenticationAgent.js:172
#: ../js/ui/endSessionDialog.js:413
#: ../js/ui/polkitAuthenticationAgent.js:172
#: ../js/ui/status/bluetooth.js:466
msgid "Cancel"
msgstr "لغو"
@ -504,7 +465,8 @@ msgstr "به کار انداختن"
#. translators:
#. * The device has been disabled
#: ../js/ui/lookingGlass.js:627 ../src/gvc/gvc-mixer-control.c:1091
#: ../js/ui/lookingGlass.js:627
#: ../src/gvc/gvc-mixer-control.c:1091
msgid "Disabled"
msgstr "از کار انداختن"
@ -628,12 +590,14 @@ msgstr "درحال حستجو..."
msgid "No matching results."
msgstr "نتیجه‌ی منطبقی پیدا نشد."
#: ../js/ui/statusMenu.js:161 ../js/ui/statusMenu.js:163
#: ../js/ui/statusMenu.js:161
#: ../js/ui/statusMenu.js:163
#: ../js/ui/statusMenu.js:228
msgid "Power Off..."
msgstr "خاموش کردن..."
#: ../js/ui/statusMenu.js:163 ../js/ui/statusMenu.js:227
#: ../js/ui/statusMenu.js:163
#: ../js/ui/statusMenu.js:227
msgid "Suspend"
msgstr "تعلیق"
@ -707,9 +671,12 @@ msgstr "کنتراست بالا"
msgid "Large Text"
msgstr "متن درشت"
#: ../js/ui/status/bluetooth.js:42 ../js/ui/status/bluetooth.js:237
#: ../js/ui/status/bluetooth.js:333 ../js/ui/status/bluetooth.js:367
#: ../js/ui/status/bluetooth.js:407 ../js/ui/status/bluetooth.js:440
#: ../js/ui/status/bluetooth.js:42
#: ../js/ui/status/bluetooth.js:237
#: ../js/ui/status/bluetooth.js:333
#: ../js/ui/status/bluetooth.js:367
#: ../js/ui/status/bluetooth.js:407
#: ../js/ui/status/bluetooth.js:440
msgid "Bluetooth"
msgstr "بلوتوث"
@ -758,7 +725,8 @@ msgstr "تنظیمات صفحه‌کلید"
msgid "Mouse Settings"
msgstr "تنظیمات موشی"
#: ../js/ui/status/bluetooth.js:259 ../js/ui/status/volume.js:66
#: ../js/ui/status/bluetooth.js:259
#: ../js/ui/status/volume.js:66
msgid "Sound Settings"
msgstr "تنظیمات صدا"
@ -789,7 +757,8 @@ msgstr "رد کردن"
msgid "Pairing confirmation for %s"
msgstr "تایید جهت جفت‌شدن با %s"
#: ../js/ui/status/bluetooth.js:414 ../js/ui/status/bluetooth.js:448
#: ../js/ui/status/bluetooth.js:414
#: ../js/ui/status/bluetooth.js:448
#, c-format
msgid "Device %s wants to pair with this computer"
msgstr "دستگاه %s می‌خواهد با این رایانه جفت شود"
@ -797,9 +766,7 @@ msgstr "دستگاه %s می‌خواهد با این رایانه جفت شود
#: ../js/ui/status/bluetooth.js:415
#, c-format
msgid "Please confirm whether the PIN '%s' matches the one on the device."
msgstr ""
"لطفا تایید کنید که آیا PIN مربوط به «%s» با همتای آن در دستگاه مطابقت دارد "
"یا خیر."
msgstr "لطفا تایید کنید که آیا PIN مربوط به «%s» با همتای آن در دستگاه مطابقت دارد یا خیر."
#: ../js/ui/status/bluetooth.js:417
msgid "Matches"
@ -830,7 +797,8 @@ msgstr "نمایش چیدمان صفحه‌کلید..."
msgid "Localization Settings"
msgstr "تنظیمات محلی‌سازی"
#: ../js/ui/status/network.js:109 ../js/ui/status/network.js:1498
#: ../js/ui/status/network.js:109
#: ../js/ui/status/network.js:1498
msgid "<unknown>"
msgstr "<ناشناخته>"
@ -852,7 +820,7 @@ msgstr "تصدیق هویت لازم است"
#. module, which is missing
#: ../js/ui/status/network.js:534
msgid "firmware missing"
msgstr ""
msgstr "میان‌افزار پیدا نشد"
#. Translators: this is for wired network devices that are physically disconnected
#: ../js/ui/status/network.js:541
@ -871,7 +839,8 @@ msgstr "اتصال شکست خورد"
#. TRANSLATORS: this is the indication that a connection for another logged in user is active,
#. and we cannot access its settings (including the name)
#: ../js/ui/status/network.js:628 ../js/ui/status/network.js:1446
#: ../js/ui/status/network.js:628
#: ../js/ui/status/network.js:1446
msgid "Connected (private)"
msgstr "متصل شد (خصوصی)"
@ -888,7 +857,8 @@ msgid "Auto dial-up"
msgstr "دایال‌آپ خودکار"
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
#: ../js/ui/status/network.js:937 ../js/ui/status/network.js:1458
#: ../js/ui/status/network.js:937
#: ../js/ui/status/network.js:1458
#, c-format
msgid "Auto %s"
msgstr "اتصال بیسیم %s خودکار"
@ -1048,7 +1018,8 @@ msgstr "لوح‌رایانه"
msgid "Computer"
msgstr "رایانه"
#: ../js/ui/status/power.js:250 ../src/shell-app-system.c:1088
#: ../js/ui/status/power.js:250
#: ../src/shell-app-system.c:1088
msgid "Unknown"
msgstr "ناشناخته"
@ -1096,7 +1067,8 @@ msgstr "ارسال در %X بر روی %A"
msgid "Type to search..."
msgstr "برای جستجو تایپ کنید..."
#: ../js/ui/viewSelector.js:142 ../src/shell-util.c:250
#: ../js/ui/viewSelector.js:142
#: ../src/shell-util.c:250
msgid "Search"
msgstr "جستجو"

581
po/ga.po

File diff suppressed because it is too large Load Diff

569
po/gl.po

File diff suppressed because it is too large Load Diff

676
po/he.po

File diff suppressed because it is too large Load Diff

619
po/it.po

File diff suppressed because it is too large Load Diff

609
po/lv.po

File diff suppressed because it is too large Load Diff

599
po/nb.po

File diff suppressed because it is too large Load Diff

662
po/pa.po

File diff suppressed because it is too large Load Diff

735
po/ru.po

File diff suppressed because it is too large Load Diff

647
po/sk.po

File diff suppressed because it is too large Load Diff

745
po/sl.po

File diff suppressed because it is too large Load Diff

612
po/sv.po

File diff suppressed because it is too large Load Diff

1254
po/te.po

File diff suppressed because it is too large Load Diff

234
po/uk.po
View File

@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-05-02 02:44+0300\n"
"PO-Revision-Date: 2011-05-02 02:46+0300\n"
"POT-Creation-Date: 2011-03-27 18:25+0300\n"
"PO-Revision-Date: 2011-03-27 18:27+0300\n"
"Last-Translator: Korostil Daniel <ted.korostiled@gmail.com>\n"
"Language-Team: translation@linux.org.ua\n"
"Language: uk\n"
@ -98,7 +98,7 @@ msgstr ""
"Вказує канал даних GStreamer для кодування запису. Звідси відповідний "
"синтаксис для gst-launch. Канал даних повинен мати нез'єднаний приймальний "
"буфер, де відео записано. Зазвичай воно має нез'єднане джерело буфера; вивід "
"з цього буфера буде записано в вихідний файл. Однак канал даних також "
"з цього буфера буде записано в вихідний файл. Однак канал даних також "
"відповідати за власний вивід — це може бути використано для відправлення "
"виводу до сервера через протокол shout2send чи будь-який інший. Коли не "
"вказано або вказано порожнє значення, буде використано типовий канал даних. "
@ -189,27 +189,27 @@ msgid "Execution of '%s' failed:"
msgstr "Не вдалось виконати «%s»:"
#. Translators: Filter to display all applications
#: ../js/ui/appDisplay.js:260
#: ../js/ui/appDisplay.js:230
msgid "All"
msgstr "Всі"
#: ../js/ui/appDisplay.js:359
#: ../js/ui/appDisplay.js:328
msgid "APPLICATIONS"
msgstr "ПРОГРАМИ"
#: ../js/ui/appDisplay.js:385
#: ../js/ui/appDisplay.js:354
msgid "SETTINGS"
msgstr "ПАРАМЕТРИ"
#: ../js/ui/appDisplay.js:658
#: ../js/ui/appDisplay.js:625
msgid "New Window"
msgstr "Нове вікно"
#: ../js/ui/appDisplay.js:661
#: ../js/ui/appDisplay.js:628
msgid "Remove from Favorites"
msgstr "Вилучити з улюбленого"
#: ../js/ui/appDisplay.js:662
#: ../js/ui/appDisplay.js:629
msgid "Add to Favorites"
msgstr "Додати до улюбленого"
@ -342,13 +342,13 @@ msgid "Nothing Scheduled"
msgstr "Нічого не заплановано"
#. Translators: Shown on calendar heading when selected day occurs on current year
#: ../js/ui/calendar.js:720 ../js/ui/telepathyClient.js:487
#: ../js/ui/calendar.js:720
msgctxt "calendar heading"
msgid "%A, %B %d"
msgstr "%A, %B %d"
#. Translators: Shown on calendar heading when selected day occurs on different year
#: ../js/ui/calendar.js:723 ../js/ui/telepathyClient.js:490
#: ../js/ui/calendar.js:723
msgctxt "calendar heading"
msgid "%A, %B %d, %Y"
msgstr "%A, %B %d, %Y"
@ -369,7 +369,7 @@ msgstr "Цей тиждень"
msgid "Next week"
msgstr "Наступний тиждень"
#: ../js/ui/dash.js:174 ../js/ui/messageTray.js:1037
#: ../js/ui/dash.js:174 ../js/ui/messageTray.js:1000
msgid "Remove"
msgstr "Вилучити"
@ -495,8 +495,8 @@ msgstr "Система автоматично перезапуститься ч
msgid "Restarting the system."
msgstr "Перезапуск системи."
#: ../js/ui/endSessionDialog.js:413 ../js/ui/polkitAuthenticationAgent.js:172
#: ../js/ui/status/bluetooth.js:491
#: ../js/ui/endSessionDialog.js:415 ../js/ui/polkitAuthenticationAgent.js:172
#: ../js/ui/status/bluetooth.js:466
msgid "Cancel"
msgstr "Скасувати"
@ -530,11 +530,11 @@ msgstr "Переглянути джерело"
msgid "Web Page"
msgstr "Веб-сторінка"
#: ../js/ui/messageTray.js:1030
#: ../js/ui/messageTray.js:993
msgid "Open"
msgstr "Відкрити"
#: ../js/ui/messageTray.js:2194
#: ../js/ui/messageTray.js:2151
msgid "System Information"
msgstr "Інформація про систему"
@ -557,18 +557,18 @@ msgid "Dash"
msgstr "Риска"
#. TODO - _quit() doesn't really work on apps in state STARTING yet
#: ../js/ui/panel.js:533
#: ../js/ui/panel.js:515
#, c-format
msgid "Quit %s"
msgstr "Вийти з %s"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:913
#: ../js/ui/panel.js:878
msgid "Activities"
msgstr "Діяльність"
#: ../js/ui/panel.js:1015
#: ../js/ui/panel.js:979
msgid "Top Bar"
msgstr "Верхня панель"
@ -626,11 +626,11 @@ msgstr "toggle-switch-intl"
msgid "Please enter a command:"
msgstr "Будь ласка, введіть команду:"
#: ../js/ui/searchDisplay.js:313
#: ../js/ui/searchDisplay.js:310
msgid "Searching..."
msgstr "Пошук…"
#: ../js/ui/searchDisplay.js:327
#: ../js/ui/searchDisplay.js:324
msgid "No matching results."
msgstr "Нема збігів."
@ -713,9 +713,9 @@ msgstr "Висока контрастність"
msgid "Large Text"
msgstr "Більший текст"
#: ../js/ui/status/bluetooth.js:42 ../js/ui/status/bluetooth.js:264
#: ../js/ui/status/bluetooth.js:358 ../js/ui/status/bluetooth.js:392
#: ../js/ui/status/bluetooth.js:432 ../js/ui/status/bluetooth.js:465
#: ../js/ui/status/bluetooth.js:42 ../js/ui/status/bluetooth.js:237
#: ../js/ui/status/bluetooth.js:333 ../js/ui/status/bluetooth.js:367
#: ../js/ui/status/bluetooth.js:407 ../js/ui/status/bluetooth.js:440
msgid "Bluetooth"
msgstr "Bluetooth"
@ -728,101 +728,101 @@ msgid "Send Files to Device..."
msgstr "Відправити файли до пристрою…"
#: ../js/ui/status/bluetooth.js:70
msgid "Set up a New Device..."
msgid "Setup a New Device..."
msgstr "Встановити новий пристрій…"
#: ../js/ui/status/bluetooth.js:95
msgid "Bluetooth Settings"
msgstr "Параметри Bluetooth"
#: ../js/ui/status/bluetooth.js:215
#: ../js/ui/status/bluetooth.js:188
msgid "Connection"
msgstr "З'єднання"
#: ../js/ui/status/bluetooth.js:251
#: ../js/ui/status/bluetooth.js:224
msgid "Send Files..."
msgstr "Відправити файли…"
#: ../js/ui/status/bluetooth.js:256
#: ../js/ui/status/bluetooth.js:229
msgid "Browse Files..."
msgstr "Огляд файлів…"
#: ../js/ui/status/bluetooth.js:265
#: ../js/ui/status/bluetooth.js:238
msgid "Error browsing device"
msgstr "Помилка перегляду пристрою…"
#: ../js/ui/status/bluetooth.js:266
#: ../js/ui/status/bluetooth.js:239
#, c-format
msgid "The requested device cannot be browsed, error is '%s'"
msgstr "Потрібний пристрій неможливо переглянути, помилка — «%s»"
#: ../js/ui/status/bluetooth.js:274
#: ../js/ui/status/bluetooth.js:247
msgid "Keyboard Settings"
msgstr "Параметри клавіатури"
#: ../js/ui/status/bluetooth.js:279
#: ../js/ui/status/bluetooth.js:252
msgid "Mouse Settings"
msgstr "Параметри миші"
#: ../js/ui/status/bluetooth.js:286 ../js/ui/status/volume.js:66
#: ../js/ui/status/bluetooth.js:259 ../js/ui/status/volume.js:66
msgid "Sound Settings"
msgstr "Параметри звуку"
#: ../js/ui/status/bluetooth.js:393
#: ../js/ui/status/bluetooth.js:368
#, c-format
msgid "Authorization request from %s"
msgstr "Запит про авторизацію від %s"
#: ../js/ui/status/bluetooth.js:399
#: ../js/ui/status/bluetooth.js:374
#, c-format
msgid "Device %s wants access to the service '%s'"
msgstr "Пристрій %s потребує доступ до служби «%s»"
#: ../js/ui/status/bluetooth.js:401
#: ../js/ui/status/bluetooth.js:376
msgid "Always grant access"
msgstr "Завжди надавати доступ"
#: ../js/ui/status/bluetooth.js:402
#: ../js/ui/status/bluetooth.js:377
msgid "Grant this time only"
msgstr "Надати лише цього разу"
#: ../js/ui/status/bluetooth.js:403
#: ../js/ui/status/bluetooth.js:378
msgid "Reject"
msgstr "Відмовити"
#: ../js/ui/status/bluetooth.js:433
#: ../js/ui/status/bluetooth.js:408
#, c-format
msgid "Pairing confirmation for %s"
msgstr "Сполучення підтвердження для %s"
#: ../js/ui/status/bluetooth.js:439 ../js/ui/status/bluetooth.js:473
#: ../js/ui/status/bluetooth.js:414 ../js/ui/status/bluetooth.js:448
#, c-format
msgid "Device %s wants to pair with this computer"
msgstr "Пристрій %s потребує прив'язання до цього комп'ютера"
#: ../js/ui/status/bluetooth.js:440
#: ../js/ui/status/bluetooth.js:415
#, c-format
msgid "Please confirm whether the PIN '%s' matches the one on the device."
msgstr "Будь ласка, підвердьте, чи «%s» збігається з PIN на пристрої."
#: ../js/ui/status/bluetooth.js:442
#: ../js/ui/status/bluetooth.js:417
msgid "Matches"
msgstr "Збігається"
#: ../js/ui/status/bluetooth.js:443
#: ../js/ui/status/bluetooth.js:418
msgid "Does not match"
msgstr "Не збігається"
#: ../js/ui/status/bluetooth.js:466
#: ../js/ui/status/bluetooth.js:441
#, c-format
msgid "Pairing request for %s"
msgstr "Запит на сполучення для %s"
#: ../js/ui/status/bluetooth.js:474
#: ../js/ui/status/bluetooth.js:449
msgid "Please enter the PIN mentioned on the device."
msgstr "Будь ласка, введіть PIN, згаданий на пристрої."
#: ../js/ui/status/bluetooth.js:490
#: ../js/ui/status/bluetooth.js:465
msgid "OK"
msgstr "Гаразд"
@ -834,139 +834,139 @@ msgstr "Показувати розкладку клавіатури…"
msgid "Localization Settings"
msgstr "Параметри локалізації"
#: ../js/ui/status/network.js:113
#: ../js/ui/status/network.js:104 ../js/ui/status/network.js:1454
msgid "<unknown>"
msgstr "<невідомо>"
#. Translators: this indicates that wireless or wwan is disabled by hardware killswitch
#: ../js/ui/status/network.js:330
#: ../js/ui/status/network.js:311
msgid "disabled"
msgstr "вимкнено"
#: ../js/ui/status/network.js:528
#: ../js/ui/status/network.js:494
msgid "connecting..."
msgstr "з'єднання…"
#. Translators: this is for network connections that require some kind of key or password
#: ../js/ui/status/network.js:531
#: ../js/ui/status/network.js:497
msgid "authentication required"
msgstr "Потрібна аутентифікація"
#. Translators: this is for devices that require some kind of firmware or kernel
#. module, which is missing
#: ../js/ui/status/network.js:541
#: ../js/ui/status/network.js:507
msgid "firmware missing"
msgstr "Бракує мікропрограми"
#. Translators: this is for wired network devices that are physically disconnected
#: ../js/ui/status/network.js:548
#: ../js/ui/status/network.js:514
msgid "cable unplugged"
msgstr "кабель від'єднано"
#. Translators: this is for a network device that cannot be activated (for example it
#. is disabled by rfkill, or it has no coverage
#: ../js/ui/status/network.js:553
#: ../js/ui/status/network.js:519
msgid "unavailable"
msgstr "недоступний"
#: ../js/ui/status/network.js:555
#: ../js/ui/status/network.js:521
msgid "connection failed"
msgstr "не вдалось з'єднатись"
#. TRANSLATORS: this is the indication that a connection for another logged in user is active,
#. and we cannot access its settings (including the name)
#: ../js/ui/status/network.js:635 ../js/ui/status/network.js:1532
#: ../js/ui/status/network.js:602 ../js/ui/status/network.js:1402
msgid "Connected (private)"
msgstr "З'єднано (приватно)"
#: ../js/ui/status/network.js:720
#: ../js/ui/status/network.js:683
msgid "Auto Ethernet"
msgstr "Автоматично Ethernet"
#: ../js/ui/status/network.js:795
#: ../js/ui/status/network.js:758
msgid "Auto broadband"
msgstr "Автоматично радіомережа"
#: ../js/ui/status/network.js:798
#: ../js/ui/status/network.js:761
msgid "Auto dial-up"
msgstr "Автоматично додзвін"
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
#: ../js/ui/status/network.js:944 ../js/ui/status/network.js:1544
#: ../js/ui/status/network.js:904 ../js/ui/status/network.js:1414
#, c-format
msgid "Auto %s"
msgstr "Автоматично %s"
#: ../js/ui/status/network.js:946
#: ../js/ui/status/network.js:906
msgid "Auto bluetooth"
msgstr "Автоматично Bluetooth"
#: ../js/ui/status/network.js:1546
#: ../js/ui/status/network.js:1416
msgid "Auto wireless"
msgstr "Автоматично бездротова мережа"
#: ../js/ui/status/network.js:1583
#: ../js/ui/status/network.js:1474
msgid "More..."
msgstr "Більше…"
#: ../js/ui/status/network.js:1625
#: ../js/ui/status/network.js:1497
msgid "Enable networking"
msgstr "Увімкнути мережу"
#: ../js/ui/status/network.js:1637
#: ../js/ui/status/network.js:1509
msgid "Wired"
msgstr "Дротова"
#: ../js/ui/status/network.js:1648
#: ../js/ui/status/network.js:1520
msgid "Wireless"
msgstr "Бездротова"
#: ../js/ui/status/network.js:1658
#: ../js/ui/status/network.js:1530
msgid "Mobile broadband"
msgstr "Мобільна радіомережа"
#: ../js/ui/status/network.js:1668
#: ../js/ui/status/network.js:1540
msgid "VPN Connections"
msgstr "З'єднання VPN"
#: ../js/ui/status/network.js:1680
#: ../js/ui/status/network.js:1549
msgid "Network Settings"
msgstr "Налаштування мережі"
#: ../js/ui/status/network.js:1974
#: ../js/ui/status/network.js:1844
#, c-format
msgid "You're now connected to mobile broadband connection '%s'"
msgstr "Зараз ви з'єднані через мобільну радіомережу «%s»"
#: ../js/ui/status/network.js:1978
#: ../js/ui/status/network.js:1848
#, c-format
msgid "You're now connected to wireless network '%s'"
msgstr "Зараз ви з'єднані через бездротову мережу «%s»"
#: ../js/ui/status/network.js:1982
#: ../js/ui/status/network.js:1852
#, c-format
msgid "You're now connected to wired network '%s'"
msgstr "Зараз ви з'єднані через дротову мережу «%s»"
#: ../js/ui/status/network.js:1986
#: ../js/ui/status/network.js:1856
#, c-format
msgid "You're now connected to VPN network '%s'"
msgstr "Зараз ви з'єднані через мережу VPN «%s»"
#: ../js/ui/status/network.js:1991
#: ../js/ui/status/network.js:1861
#, c-format
msgid "You're now connected to '%s'"
msgstr "Зараз ви з'єднані через «%s»"
#: ../js/ui/status/network.js:1999
#: ../js/ui/status/network.js:1869
msgid "Connection established"
msgstr "З'єднання встановлено"
#: ../js/ui/status/network.js:2125
#: ../js/ui/status/network.js:1991
msgid "Networking is disabled"
msgstr "Мережу вимкнено"
#: ../js/ui/status/network.js:2250
#: ../js/ui/status/network.js:2116
msgid "Network Manager"
msgstr "Керування мережею"
@ -1072,22 +1072,22 @@ msgstr "Гучність"
msgid "Microphone"
msgstr "Мікрофон"
#: ../js/ui/telepathyClient.js:330
#: ../js/ui/telepathyClient.js:331
#, c-format
msgid "%s is online."
msgstr "%s в мережі."
#: ../js/ui/telepathyClient.js:335
#: ../js/ui/telepathyClient.js:336
#, c-format
msgid "%s is offline."
msgstr "%s поза мережею."
#: ../js/ui/telepathyClient.js:338
#: ../js/ui/telepathyClient.js:339
#, c-format
msgid "%s is away."
msgstr "%s відійшов."
#: ../js/ui/telepathyClient.js:341
#: ../js/ui/telepathyClient.js:342
#, c-format
msgid "%s is busy."
msgstr "%s зайнятий."
@ -1095,18 +1095,11 @@ msgstr "%s зайнятий."
#. Translators: this is a time format string followed by a date.
#. If applicable, replace %X with a strftime format valid for your
#. locale, without seconds.
#: ../js/ui/telepathyClient.js:479
#: ../js/ui/telepathyClient.js:473
#, no-c-format
msgid "Sent at %X on %A"
msgstr "Відправити на %X в %A"
#. Translators: this is the other person changing their old IM name to their new
#. IM name.
#: ../js/ui/telepathyClient.js:524
#, c-format
msgid "%s is now known as %s"
msgstr "%s тепер відомий як %s"
#. Translators: this is the text displayed
#. in the search entry when no search is
#. active; it should not exceed ~30
@ -1153,7 +1146,7 @@ msgstr[2] "%u входів"
msgid "System Sounds"
msgstr "Системні звуки"
#: ../src/main.c:445
#: ../src/main.c:446
msgid "Print version"
msgstr "Показати версію"
@ -1162,6 +1155,42 @@ msgstr "Показати версію"
msgid "Failed to launch '%s'"
msgstr "Не вдалось запустити «%s»"
#: ../src/shell-global.c:1395
msgid "Less than a minute ago"
msgstr "Менше хвилини тому"
#: ../src/shell-global.c:1399
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d хвилина тому"
msgstr[1] "%d хвилини тому"
msgstr[2] "%d хвилин тому"
#: ../src/shell-global.c:1404
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d година тому"
msgstr[1] "%d години тому"
msgstr[2] "%d годин тому"
#: ../src/shell-global.c:1409
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d день тому"
msgstr[1] "%d дні тому"
msgstr[2] "%d днів тому"
#: ../src/shell-global.c:1414
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d тиждень тому"
msgstr[1] "%d тижні тому"
msgstr[2] "%d тижнів тому"
#: ../src/shell-mobile-providers.c:80
msgid "United Kingdom"
msgstr "Великобританія"
@ -1194,33 +1223,6 @@ msgstr "Файлова система"
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Less than a minute ago"
#~ msgstr "Менше хвилини тому"
#~ msgid "%d minute ago"
#~ msgid_plural "%d minutes ago"
#~ msgstr[0] "%d хвилина тому"
#~ msgstr[1] "%d хвилини тому"
#~ msgstr[2] "%d хвилин тому"
#~ msgid "%d hour ago"
#~ msgid_plural "%d hours ago"
#~ msgstr[0] "%d година тому"
#~ msgstr[1] "%d години тому"
#~ msgstr[2] "%d годин тому"
#~ msgid "%d day ago"
#~ msgid_plural "%d days ago"
#~ msgstr[0] "%d день тому"
#~ msgstr[1] "%d дні тому"
#~ msgstr[2] "%d днів тому"
#~ msgid "%d week ago"
#~ msgid_plural "%d weeks ago"
#~ msgstr[0] "%d тиждень тому"
#~ msgstr[1] "%d тижні тому"
#~ msgstr[2] "%d тижнів тому"
#~ msgid "Shut Down"
#~ msgstr "Вимкнути"

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,13 @@
service_in_files += calendar-server/org.gnome.Shell.CalendarServer.service.in
servicedir = $(datadir)/dbus-1/services
service_in_files = calendar-server/org.gnome.Shell.CalendarServer.service.in
service_DATA = $(service_in_files:.service.in=.service)
$(service_DATA): $(service_in_files) Makefile
$(AM_V_GEN) \
[ -d $(@D) ] || $(mkdir_p) $(@D) ; \
sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@.tmp && mv $@.tmp $@
CLEANFILES += $(service_DATA)
libexec_PROGRAMS += gnome-shell-calendar-server

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